#![deny(rustdoc::broken_intra_doc_links)]
pub mod traits;
pub use traits::{
FindIntervalIdOfPoint, Grid1DIntervalBuilder, Grid1DTrait, HasCoordIdRange, HasCoords1D,
HasDomain1D, HasIntervalIdRange, HasIntervals,
};
pub mod window;
pub use window::{ErrorsGrid1DWindow, Grid1DWindow};
use crate::{
CoordId, Coords1D, ErrorsCoords1D, ErrorsIntervalConstruction, ErrorsPositiveInt,
Grid1DIndexSpaces, HasCoordType, IntervalFinitePositiveLengthTrait, IntervalFromBounds,
IntervalId, NumIntervals, PositiveNumPoints1D, SupportsCircularTopology, Topology1D,
Translate1D,
operations::refinement::{
Grid1DNonUniformRefinement, Grid1DUniformRefinement, build_non_uniform_grid_refinement,
refine_all_intervals_in_coords1d_same_subdivisions,
},
};
use getset::Getters;
use num_valid::{
RealScalar,
core::errors::capture_backtrace,
functions::{Reciprocal, Rounding},
scalars::{PositiveRealScalar, RelativeTolerance},
};
use serde::{Deserialize, Serialize};
use sorted_vec::partial::SortedSet;
use std::backtrace::Backtrace;
use thiserror::Error;
use try_create::TryNew;
#[derive(Debug, Error)]
pub enum ErrorsGrid1D<Domain1D: IntervalFinitePositiveLengthTrait> {
#[error("The number of distinct points required to define an interval partition must be >= 2!")]
RequiredAtLeastTwoDistinctPoints {
num_points_provided: PositiveNumPoints1D,
backtrace: Backtrace,
},
#[error("Error from Coords1D construction")]
FromCoords1DConstructor {
#[from]
source: ErrorsCoords1D,
},
#[error("Error from the construction of the interval")]
FromIntervalConstructor {
#[from]
source: ErrorsIntervalConstruction<Domain1D::CoordType>,
},
#[error(
"The first point of the grid ({first_point}) is not equal to the lower bound of the interval representing the domain {domain:?}!"
)]
FirstPointIsNotDomainLowerBound {
first_point: Domain1D::CoordType,
domain: Domain1D,
backtrace: Backtrace,
},
#[error(
"The last point of the grid ({last_point}) is not equal to the upper bound of the interval representing the domain {domain:?}!"
)]
LastPointIsNotDomainUpperBound {
last_point: Domain1D::CoordType,
domain: Domain1D,
backtrace: Backtrace,
},
#[error(transparent)]
NumIntervals(#[from] ErrorsPositiveInt),
}
pub(crate) fn validate_coords_in_domain_closure<Domain1D: IntervalFinitePositiveLengthTrait>(
coords: &Coords1D<Domain1D::CoordType>,
domain: &Domain1D,
) -> Result<NumIntervals, ErrorsGrid1D<Domain1D>> {
let lower_bound = domain.lower_bound_value();
let upper_bound = domain.upper_bound_value();
let first_point = coords.first();
if first_point != lower_bound {
return Err(ErrorsGrid1D::FirstPointIsNotDomainLowerBound {
first_point: first_point.clone(),
domain: domain.clone(),
backtrace: capture_backtrace(),
});
}
let last_point = coords.last();
if last_point != upper_bound {
return Err(ErrorsGrid1D::LastPointIsNotDomainUpperBound {
last_point: last_point.clone(),
domain: domain.clone(),
backtrace: capture_backtrace(),
});
}
let num_intervals = NumIntervals::try_new(coords.num_points().as_ref() - 1)?;
Ok(num_intervals)
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "Domain1D: for<'d> serde::Deserialize<'d>, \
Domain1D::CoordType: for<'d> serde::Deserialize<'d>"))]
pub struct Grid1DNonUniform<Domain1D: IntervalFinitePositiveLengthTrait> {
pub(crate) domain: Domain1D,
pub(crate) index_spaces: Grid1DIndexSpaces,
pub(crate) coords: Coords1D<Domain1D::CoordType>,
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Grid1DNonUniform<Domain1D> {
pub fn try_new(
domain: Domain1D,
coords: Coords1D<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
let num_intervals = validate_coords_in_domain_closure(&coords, &domain)?;
let index_spaces = Grid1DIndexSpaces::new_non_periodic(num_intervals);
Ok(Self {
domain,
coords,
index_spaces,
})
}
}
impl<Domain1D: IntervalFromBounds> Grid1DNonUniform<Domain1D> {
fn create_domain_from_coords(
coords: &Coords1D<Domain1D::CoordType>,
) -> Result<Domain1D, ErrorsGrid1D<Domain1D>>
{
let n_pts = coords.num_points();
if n_pts.as_ref() < &2 {
Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints {
num_points_provided: n_pts,
backtrace: capture_backtrace(),
})
} else {
Ok(Domain1D::try_new(
coords.first().clone(),
coords.last().clone(),
)?)
}
}
pub fn try_new_from_coords(
coords: Coords1D<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
let domain = Self::create_domain_from_coords(&coords)?;
let num_intervals = NumIntervals::try_new(coords.num_points().as_ref() - 1)
.expect("At least 2 points are required to form a valid grid!");
let index_spaces = Grid1DIndexSpaces::new_non_periodic(num_intervals);
Ok(Self {
domain,
coords,
index_spaces,
})
}
}
impl<Domain1D> Grid1DNonUniform<Domain1D>
where
Domain1D: IntervalFinitePositiveLengthTrait + SupportsCircularTopology,
{
pub fn try_new_periodic(
domain: Domain1D,
coords: Coords1D<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
let num_intervals = validate_coords_in_domain_closure(&coords, &domain)?;
let index_spaces = if domain.is_lower_bound_open() {
Grid1DIndexSpaces::new_periodic_lower_open_interval(num_intervals)
} else {
Grid1DIndexSpaces::new_periodic_upper_open_interval(num_intervals)
};
Ok(Self {
domain,
coords,
index_spaces,
})
}
}
impl<Domain1D> Grid1DNonUniform<Domain1D>
where
Domain1D: IntervalFromBounds + SupportsCircularTopology,
{
pub fn try_new_periodic_from_coords(
coords: Coords1D<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
let domain = Self::create_domain_from_coords(&coords)?;
let num_intervals = NumIntervals::try_new(coords.num_points().as_ref() - 1)
.expect("At least 2 points are required to form a valid grid!");
let index_spaces = if domain.is_lower_bound_open() {
Grid1DIndexSpaces::new_periodic_lower_open_interval(num_intervals)
} else {
Grid1DIndexSpaces::new_periodic_upper_open_interval(num_intervals)
};
Ok(Self {
domain,
coords,
index_spaces,
})
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoordType for Grid1DNonUniform<Domain1D> {
type CoordType = Domain1D::CoordType;
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasDomain1D for Grid1DNonUniform<Domain1D> {
type Domain1D = Domain1D;
#[inline(always)]
fn domain(&self) -> &Domain1D {
&self.domain
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoords1D for Grid1DNonUniform<Domain1D> {
#[inline(always)]
fn coords(&self) -> &Coords1D<Self::CoordType> {
&self.coords
}
}
impl<Domain1D: Grid1DIntervalBuilder> FindIntervalIdOfPoint for Grid1DNonUniform<Domain1D> {
fn find_interval_id_of_point(&self, x: &Self::CoordType) -> Option<IntervalId> {
if !self.domain().contains_point(x) {
return None;
}
if self.domain().is_lower_bound_closed() {
let floor = self
.coords()
.find_floor_index(x)
.expect("Point is in domain but has no floor coordinate");
let final_id = floor.min(*self.num_intervals().as_ref() - 1);
Some(IntervalId::new(final_id))
} else {
let idx = self.coords().find_insertion_index(x);
if idx == 0 {
Some(IntervalId::new(0))
} else {
Some(IntervalId::new(idx - 1))
}
}
}
}
impl<Domain1D> HasIntervalIdRange for Grid1DNonUniform<Domain1D>
where
Domain1D: Grid1DIntervalBuilder,
{
#[inline(always)]
fn first_interval_id(&self) -> IntervalId {
self.index_spaces.interval_index_space().first_interval_id()
}
#[inline(always)]
fn last_interval_id(&self) -> IntervalId {
self.index_spaces.interval_index_space().last_interval_id()
}
}
impl<Domain1D> HasCoordIdRange for Grid1DNonUniform<Domain1D>
where
Domain1D: Grid1DIntervalBuilder,
{
#[inline(always)]
fn first_coord_id(&self) -> CoordId {
self.index_spaces.coord_index_space().first_coord_id()
}
#[inline(always)]
fn last_coord_id(&self) -> CoordId {
self.index_spaces.coord_index_space().last_coord_id()
}
}
impl<Domain1D> Grid1DTrait for Grid1DNonUniform<Domain1D>
where
Domain1D: Grid1DIntervalBuilder,
{
#[inline(always)]
fn index_spaces(&self) -> &Grid1DIndexSpaces {
&self.index_spaces
}
type UniformlyRefinedGrid1DType = Self;
fn refine_uniform(
self,
num_extra_points_each_interval: &PositiveNumPoints1D,
) -> Grid1DUniformRefinement<Self> {
let (
refined_coords,
refined_to_original_interval_mapping,
original_to_refined_interval_mapping,
) = refine_all_intervals_in_coords1d_same_subdivisions(
self.coords(),
num_extra_points_each_interval,
);
let domain = self.domain().clone();
let num_refined_intervals = validate_coords_in_domain_closure(&refined_coords, &domain)
.expect("Refined coordinates do not form a valid grid!");
let topology = self.index_spaces.topology();
let refined_index_spaces = match topology {
Topology1D::RealLine => Grid1DIndexSpaces::new_non_periodic(num_refined_intervals),
Topology1D::Circle => {
if self.domain().is_lower_bound_open() {
Grid1DIndexSpaces::new_periodic_lower_open_interval(num_refined_intervals)
} else {
Grid1DIndexSpaces::new_periodic_upper_open_interval(num_refined_intervals)
}
}
};
let refined_grid = Self {
domain,
coords: refined_coords,
index_spaces: refined_index_spaces,
};
Grid1DUniformRefinement::new(
refined_grid,
self,
refined_to_original_interval_mapping,
original_to_refined_interval_mapping,
)
}
fn refine(
self,
intervals_to_refine: &std::collections::BTreeMap<IntervalId, PositiveNumPoints1D>,
) -> Grid1DNonUniformRefinement<Self> {
build_non_uniform_grid_refinement(self, intervals_to_refine)
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Translate1D for Grid1DNonUniform<Domain1D> {
fn translate_in_place(&mut self, amount: &Self::CoordType) {
self.coords.translate_in_place(amount);
self.domain.translate_in_place(amount);
}
}
#[derive(Debug, Clone, Getters, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "Domain1D: for<'d> serde::Deserialize<'d>, \
Domain1D::CoordType: for<'d> serde::Deserialize<'d>"))]
pub struct Grid1DUniform<Domain1D: IntervalFinitePositiveLengthTrait> {
coords: Coords1D<Domain1D::CoordType>,
domain: Domain1D,
index_spaces: Grid1DIndexSpaces,
#[getset(get = "pub")]
delta_points: PositiveRealScalar<Domain1D::CoordType>,
}
fn compute_delta_points<Domain1D: IntervalFinitePositiveLengthTrait>(
domain: &Domain1D,
num_intervals: &NumIntervals,
) -> PositiveRealScalar<Domain1D::CoordType> {
let n_intervals = *num_intervals.as_ref();
PositiveRealScalar::try_new(
domain.length().into_inner()
* Domain1D::CoordType::try_from_f64(n_intervals as f64)
.unwrap()
.try_reciprocal()
.unwrap(),
)
.expect("Delta points must be positive!")
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Grid1DUniform<Domain1D> {
#[must_use]
pub fn new(domain: Domain1D, num_intervals: NumIntervals) -> Self {
let delta_points = compute_delta_points(&domain, &num_intervals);
let coords = Coords1D::new_uniform_on_closure(&domain, &num_intervals);
let index_spaces = Grid1DIndexSpaces::new_non_periodic(num_intervals);
Self {
coords,
domain,
delta_points,
index_spaces,
}
}
}
impl<Domain1D> Grid1DUniform<Domain1D>
where
Domain1D: IntervalFinitePositiveLengthTrait + SupportsCircularTopology,
{
#[must_use]
pub fn new_periodic(domain: Domain1D, num_intervals: NumIntervals) -> Self {
let delta_points = compute_delta_points(&domain, &num_intervals);
let coords = Coords1D::new_uniform_on_closure(&domain, &num_intervals);
let index_spaces = if domain.is_lower_bound_open() {
Grid1DIndexSpaces::new_periodic_lower_open_interval(num_intervals)
} else {
Grid1DIndexSpaces::new_periodic_upper_open_interval(num_intervals)
};
Self {
coords,
domain,
delta_points,
index_spaces,
}
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoordType for Grid1DUniform<Domain1D> {
type CoordType = Domain1D::CoordType;
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasDomain1D for Grid1DUniform<Domain1D> {
type Domain1D = Domain1D;
#[inline(always)]
fn domain(&self) -> &Domain1D {
&self.domain
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoords1D for Grid1DUniform<Domain1D> {
#[inline(always)]
fn coords(&self) -> &Coords1D<Self::CoordType> {
&self.coords
}
}
impl<Domain1D: Grid1DIntervalBuilder> FindIntervalIdOfPoint for Grid1DUniform<Domain1D> {
fn find_interval_id_of_point(&self, x: &Self::CoordType) -> Option<IntervalId> {
let domain = self.domain();
if !domain.contains_point(x) {
return None;
}
let num_intervals = *self.num_intervals().as_ref();
match self.coords().find_index(x) {
Some(coord_id) => {
let coord_id = coord_id.into_inner();
if coord_id == 0 {
Some(IntervalId::new(0))
} else if coord_id == num_intervals {
Some(IntervalId::new(num_intervals - 1))
} else {
if self.domain().is_lower_bound_closed() {
Some(IntervalId::new(coord_id))
} else {
Some(IntervalId::new(coord_id - 1))
}
}
}
None => {
let domain_start = domain.lower_bound_value();
let delta = self.delta_points.as_ref();
let offset = x.clone() - domain_start;
let offset_div_delta = offset / delta;
let index = offset_div_delta
.kernel_floor()
.truncate_to_usize()
.unwrap()
.min(num_intervals - 1);
Some(IntervalId::new(index))
}
}
}
}
impl<Domain1D: Grid1DIntervalBuilder> HasIntervalIdRange for Grid1DUniform<Domain1D> {
#[inline(always)]
fn first_interval_id(&self) -> IntervalId {
self.index_spaces.interval_index_space().first_interval_id()
}
#[inline(always)]
fn last_interval_id(&self) -> IntervalId {
self.index_spaces.interval_index_space().last_interval_id()
}
}
impl<Domain1D: Grid1DIntervalBuilder> HasCoordIdRange for Grid1DUniform<Domain1D> {
#[inline(always)]
fn first_coord_id(&self) -> CoordId {
self.index_spaces.coord_index_space().first_coord_id()
}
#[inline(always)]
fn last_coord_id(&self) -> CoordId {
self.index_spaces.coord_index_space().last_coord_id()
}
}
impl<Domain1D: Grid1DIntervalBuilder> Grid1DTrait for Grid1DUniform<Domain1D> {
#[inline(always)]
fn index_spaces(&self) -> &Grid1DIndexSpaces {
&self.index_spaces
}
#[inline(always)]
fn max_interval_length(&self) -> PositiveRealScalar<Self::CoordType> {
self.delta_points.clone()
}
#[inline(always)]
fn min_interval_length(&self) -> PositiveRealScalar<Self::CoordType> {
self.delta_points.clone()
}
type UniformlyRefinedGrid1DType = Self;
fn refine_uniform(
self,
num_extra_points_each_interval: &PositiveNumPoints1D,
) -> Grid1DUniformRefinement<Self> {
let num_old_intervals = *self.num_intervals().as_ref();
let num_sub_intervals = *num_extra_points_each_interval.as_ref() + 1;
let num_new_intervals = num_old_intervals * num_sub_intervals;
let refined_grid = Grid1DUniform::new(
self.domain.clone(),
NumIntervals::try_new(num_new_intervals).unwrap(),
);
let mut refined_to_original_interval_mapping: Vec<IntervalId> =
Vec::with_capacity(num_new_intervals);
let mut original_to_refined_interval_mapping: Vec<Vec<IntervalId>> =
Vec::with_capacity(num_old_intervals);
let mut refined_id = 0;
for original_id in 0..num_old_intervals {
refined_to_original_interval_mapping.resize(
refined_to_original_interval_mapping.len() + num_sub_intervals,
IntervalId::new(original_id),
);
original_to_refined_interval_mapping.push(
(refined_id..refined_id + num_sub_intervals)
.map(IntervalId::new)
.collect(),
);
refined_id += num_sub_intervals;
}
Grid1DUniformRefinement::new(
refined_grid,
self,
refined_to_original_interval_mapping,
original_to_refined_interval_mapping,
)
}
fn refine(
self,
intervals_to_refine: &std::collections::BTreeMap<IntervalId, PositiveNumPoints1D>,
) -> Grid1DNonUniformRefinement<Self> {
build_non_uniform_grid_refinement(self, intervals_to_refine)
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Translate1D for Grid1DUniform<Domain1D> {
fn translate_in_place(&mut self, amount: &Self::CoordType) {
self.coords.translate_in_place(amount);
self.domain.translate_in_place(amount);
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "Domain1D: for<'d> serde::Deserialize<'d>, \
Domain1D::CoordType: for<'d> serde::Deserialize<'d>"))]
pub enum Grid1D<Domain1D: IntervalFinitePositiveLengthTrait> {
Uniform(Grid1DUniform<Domain1D>),
NonUniform(Grid1DNonUniform<Domain1D>),
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Grid1D<Domain1D> {
#[must_use]
pub fn uniform(domain: Domain1D, num_intervals: NumIntervals) -> Self {
Grid1D::Uniform(Grid1DUniform::new(domain, num_intervals))
}
pub fn try_from_sorted(
values: SortedSet<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>>
where
Domain1D: IntervalFromBounds,
{
Self::try_from_coords(Coords1D::try_from(values)?)
}
pub fn try_from_coords(
coords: Coords1D<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>>
where
Domain1D: IntervalFromBounds,
{
let num_coords = coords.num_points();
if *num_coords.as_ref() < 2 {
return Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints {
num_points_provided: num_coords,
backtrace: capture_backtrace(),
});
}
let domain = Domain1D::try_new(coords.first().clone(), coords.last().clone())?;
Self::try_new(domain, coords)
}
pub fn try_new(
domain: Domain1D,
coords: Coords1D<Domain1D::CoordType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
let num_intervals = validate_coords_in_domain_closure(&coords, &domain)?;
let n_pts = coords.num_points();
if n_pts.as_ref() < &2 {
return Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints {
num_points_provided: n_pts,
backtrace: capture_backtrace(),
});
}
let n_pts = n_pts.into_inner();
let coords_slice = coords.as_ref();
let length_first_interval = coords_slice[1].clone() - &coords_slice[0];
let rel_tol = RelativeTolerance::epsilon();
let is_uniform = (2..n_pts).all(|i| {
let length_current_interval = coords_slice[i].clone() - &coords_slice[i - 1];
approx_eq(&length_current_interval, &length_first_interval, &rel_tol)
});
if is_uniform {
Ok(Grid1D::Uniform(Grid1DUniform::new(domain, num_intervals)))
} else {
let index_spaces = Grid1DIndexSpaces::new_non_periodic(num_intervals);
let grid1d = Grid1DNonUniform {
domain,
coords,
index_spaces,
};
Ok(Grid1D::NonUniform(grid1d))
}
}
}
fn approx_eq<T: RealScalar>(a: &T, b: &T, rel_tol: &RelativeTolerance<T>) -> bool {
let diff = (a.clone() - b).abs();
let abs_a = a.clone().abs();
let abs_b = b.clone().abs();
let max_abs = abs_a.max_by_ref(&abs_b).clone();
diff <= max_abs * rel_tol.as_ref()
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoordType for Grid1D<Domain1D> {
type CoordType = Domain1D::CoordType;
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasDomain1D for Grid1D<Domain1D> {
type Domain1D = Domain1D;
#[inline]
fn domain(&self) -> &Domain1D {
match self {
Grid1D::Uniform(pts) => pts.domain(),
Grid1D::NonUniform(pts) => pts.domain(),
}
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoords1D for Grid1D<Domain1D> {
#[inline]
fn coords(&self) -> &Coords1D<Self::CoordType> {
match self {
Grid1D::Uniform(pts) => pts.coords(),
Grid1D::NonUniform(pts) => pts.coords(),
}
}
}
impl<Domain1D: Grid1DIntervalBuilder> FindIntervalIdOfPoint for Grid1D<Domain1D> {
fn find_interval_id_of_point(&self, x: &Self::CoordType) -> Option<IntervalId> {
match self {
Grid1D::Uniform(grid) => grid.find_interval_id_of_point(x),
Grid1D::NonUniform(grid) => grid.find_interval_id_of_point(x),
}
}
}
impl<Domain1D: Grid1DIntervalBuilder> HasIntervalIdRange for Grid1D<Domain1D> {
#[inline]
fn first_interval_id(&self) -> IntervalId {
match self {
Grid1D::Uniform(grid) => grid.first_interval_id(),
Grid1D::NonUniform(grid) => grid.first_interval_id(),
}
}
#[inline]
fn last_interval_id(&self) -> IntervalId {
match self {
Grid1D::Uniform(grid) => grid.last_interval_id(),
Grid1D::NonUniform(grid) => grid.last_interval_id(),
}
}
}
impl<Domain1D: Grid1DIntervalBuilder> HasCoordIdRange for Grid1D<Domain1D> {
#[inline]
fn first_coord_id(&self) -> CoordId {
match self {
Grid1D::Uniform(grid) => grid.first_coord_id(),
Grid1D::NonUniform(grid) => grid.first_coord_id(),
}
}
#[inline]
fn last_coord_id(&self) -> CoordId {
match self {
Grid1D::Uniform(grid) => grid.last_coord_id(),
Grid1D::NonUniform(grid) => grid.last_coord_id(),
}
}
}
impl<Domain1D: Grid1DIntervalBuilder> Grid1DTrait for Grid1D<Domain1D> {
#[inline]
fn index_spaces(&self) -> &Grid1DIndexSpaces {
match self {
Grid1D::Uniform(grid) => grid.index_spaces(),
Grid1D::NonUniform(grid) => grid.index_spaces(),
}
}
type UniformlyRefinedGrid1DType = Self;
fn refine_uniform(
self,
num_extra_points_each_interval: &PositiveNumPoints1D,
) -> Grid1DUniformRefinement<Self> {
match self {
Grid1D::Uniform(grid_uniform) => grid_uniform
.refine_uniform(num_extra_points_each_interval)
.into(),
Grid1D::NonUniform(grid_non_uniform) => grid_non_uniform
.refine_uniform(num_extra_points_each_interval)
.into(),
}
}
fn refine(
self,
intervals_to_refine: &std::collections::BTreeMap<IntervalId, PositiveNumPoints1D>,
) -> Grid1DNonUniformRefinement<Self> {
match self {
Grid1D::Uniform(grid_uniform) => grid_uniform.refine(intervals_to_refine).into(),
Grid1D::NonUniform(grid_non_uniform) => {
grid_non_uniform.refine(intervals_to_refine).into()
}
}
}
}
impl<Domain1D: Grid1DIntervalBuilder> Translate1D for Grid1D<Domain1D> {
fn translate_in_place(&mut self, amount: &Self::CoordType) {
match self {
Grid1D::Uniform(grid) => grid.translate_in_place(amount),
Grid1D::NonUniform(grid) => grid.translate_in_place(amount),
}
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> From<Grid1DUniform<Domain1D>>
for Grid1D<Domain1D>
{
fn from(grid: Grid1DUniform<Domain1D>) -> Self {
Grid1D::Uniform(grid)
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> From<Grid1DNonUniform<Domain1D>>
for Grid1D<Domain1D>
{
fn from(grid: Grid1DNonUniform<Domain1D>) -> Self {
Grid1D::NonUniform(grid)
}
}
#[cfg(test)]
mod tests {
use crate::{coords::*, grids::*, intervals::*, *};
use std::ops::Deref;
#[cfg(feature = "rug")]
use num_valid::vec_f64_into_vec_real;
mod native64_strict_finite {
use super::*;
use num_valid::RealNative64StrictFinite;
type Real = RealNative64StrictFinite;
mod grid1d {
use super::*;
#[test]
fn test_grid1d_uniform_creation() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let grid = Grid1D::uniform(domain.clone(), NumIntervals::try_new(4).unwrap());
assert_eq!(grid.domain(), &domain);
assert_eq!(
grid.coords().deref(),
&[
Real::try_new(0.0).unwrap(),
Real::try_new(0.25).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(0.75).unwrap(),
Real::try_new(1.0).unwrap()
]
);
}
#[test]
fn test_grid1d_non_uniform_creation() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords.clone()).unwrap();
assert_eq!(grid.coords().deref(), &coords.to_vec());
}
#[test]
fn test_grid1d_insufficient_points() {
let coords = SortedSet::from_unsorted(vec![Real::try_new(0.0).unwrap()]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords);
matches!(
grid,
Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints { .. })
);
}
#[test]
fn grid1d_01() {
let v = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
]);
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
assert_eq!(grid1d.coords().deref(), &v.to_vec());
}
#[test]
fn interval_01() {
let v = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
]);
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
let interval = grid1d.interval(&IntervalId::new(0));
match interval {
SubIntervalInPartition::Single(interval) => {
assert_eq!(
TryInto::<IntervalClosed<Real>>::try_into(interval).unwrap(),
IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
)
);
}
_ => {
panic!("There should be only one interval")
}
}
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_02() {
let v = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
]);
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
let _interval = grid1d.interval(&IntervalId::new(1));
}
#[test]
fn find_interval_id_01() {
let v = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
let i0 = grid1d
.find_interval_id_of_point(&Real::try_new(0.0).unwrap())
.unwrap();
assert_eq!(i0, IntervalId::new(0));
let i1 = grid1d
.find_interval_id_of_point(&Real::try_new(0.5).unwrap())
.unwrap();
assert_eq!(i1, IntervalId::new(0));
let i2 = grid1d
.find_interval_id_of_point(&Real::try_new(1.0).unwrap())
.unwrap();
assert_eq!(i2, IntervalId::new(1));
let i3 = grid1d
.find_interval_id_of_point(&Real::try_new(1.5).unwrap())
.unwrap();
assert_eq!(i3, IntervalId::new(1));
let i4 = grid1d
.find_interval_id_of_point(&Real::try_new(2.0).unwrap())
.unwrap();
assert_eq!(i4, IntervalId::new(2));
let i5 = grid1d
.find_interval_id_of_point(&Real::try_new(2.5).unwrap())
.unwrap();
assert_eq!(i5, IntervalId::new(2));
let i6 = grid1d
.find_interval_id_of_point(&Real::try_new(3.0).unwrap())
.unwrap();
assert_eq!(i6, IntervalId::new(2));
}
#[test]
fn uniform_01() {
let interval =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let grid1d = Grid1D::uniform(interval, NumIntervals::try_new(4).unwrap());
let expected_coords = vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.25).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(0.75).unwrap(),
Real::try_new(1.0).unwrap(),
];
assert_eq!(grid1d.coords().deref(), &expected_coords);
}
#[test]
fn grid_intersection_01() {
let grid1d_a = Grid1D::<IntervalClosed<Real>>::try_from_sorted(
SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
]),
)
.unwrap();
let grid1d_b = Grid1D::<IntervalClosed<Real>>::try_from_sorted(
SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(2.0).unwrap(),
]),
)
.unwrap();
let union = Grid1DUnion::try_new(&grid1d_a, &grid1d_b).unwrap();
let (grid1d_fine, map_a, map_b) = union.into_parts();
assert_eq!(
grid1d_fine.coords().deref(),
&[
Real::try_new(0.0).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
]
);
assert_eq!(map_a[0], IntervalId::new(0));
assert_eq!(map_a[1], IntervalId::new(0));
assert_eq!(map_a[2], IntervalId::new(1));
assert_eq!(map_b[0], IntervalId::new(0));
assert_eq!(map_b[1], IntervalId::new(1));
assert_eq!(map_b[2], IntervalId::new(1));
}
#[test]
fn intervals_in_intersection_single_interval() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
let domain =
IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(1.5).unwrap());
let intervals = grid.intervals_in_intersection(&domain);
assert_eq!(intervals.len(), 1);
assert_eq!(intervals[0].0, IntervalId::new(1));
assert_eq!(
intervals[0].1,
IntervalFinitePositiveLength::from(IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(1.5).unwrap()
))
);
}
#[test]
fn intervals_in_intersection_multiple_intervals() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
let domain =
IntervalClosed::new(Real::try_new(0.5).unwrap(), Real::try_new(2.5).unwrap());
let intervals = grid.intervals_in_intersection(&domain);
assert_eq!(intervals.len(), 3);
assert_eq!(intervals[0].0, IntervalId::new(0));
assert_eq!(
intervals[0].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(0.5).unwrap(),
Real::try_new(1.0).unwrap()
))
);
assert_eq!(intervals[1].0, IntervalId::new(1));
assert_eq!(
intervals[1].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
))
);
assert_eq!(intervals[2].0, IntervalId::new(2));
assert_eq!(
intervals[2].1,
IntervalFinitePositiveLength::from(IntervalClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(2.5).unwrap()
))
);
}
#[test]
fn intervals_in_intersection_full_overlap() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
let intervals = grid.intervals_in_intersection(grid.domain());
assert_eq!(intervals.len(), 3);
assert_eq!(intervals[0].0, IntervalId::new(0));
assert_eq!(
intervals[0].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
))
);
assert_eq!(intervals[1].0, IntervalId::new(1));
assert_eq!(
intervals[1].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
))
);
assert_eq!(intervals[2].0, IntervalId::new(2));
assert_eq!(
intervals[2].1,
IntervalFinitePositiveLength::from(IntervalClosed::new(
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap()
))
);
}
#[test]
fn intervals_in_intersection_no_overlap() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
let domain =
IntervalClosed::new(Real::try_new(3.5).unwrap(), Real::try_new(4.0).unwrap());
let intervals = grid.intervals_in_intersection(&domain);
assert!(intervals.is_empty());
}
#[test]
fn intervals_in_intersection_out_of_bounds_01() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
let domain =
IntervalClosed::new(Real::try_new(2.5).unwrap(), Real::try_new(4.0).unwrap());
let intervals = grid.intervals_in_intersection(&domain);
assert_eq!(
intervals[0],
(
IntervalId::new(2),
IntervalFinitePositiveLength::from(IntervalClosed::new(
Real::try_new(2.5).unwrap(),
Real::try_new(3.0).unwrap()
))
)
);
}
#[test]
fn intervals_in_intersection_out_of_bounds_02() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
let domain = IntervalLowerOpenUpperClosed::new(
Real::try_new(2.5).unwrap(),
Real::try_new(4.0).unwrap(),
);
let intervals = grid.intervals_in_intersection(&domain);
assert_eq!(
intervals[0],
(
IntervalId::new(2),
IntervalFinitePositiveLength::from(IntervalLowerOpenUpperClosed::new(
Real::try_new(2.5).unwrap(),
Real::try_new(3.0).unwrap()
))
)
);
}
#[test]
fn test_from_grid1d_uniform_to_grid1d() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let uniform_grid =
Grid1DUniform::new(domain.clone(), NumIntervals::try_new(4).unwrap());
let grid: Grid1D<IntervalClosed<Real>> = Grid1D::from(uniform_grid.clone());
assert!(matches!(grid, Grid1D::Uniform(_)));
assert_eq!(grid.domain(), &domain);
assert_eq!(grid.num_intervals().as_ref(), &4);
assert_eq!(grid.coords().deref(), uniform_grid.coords().deref());
}
#[test]
fn test_from_grid1d_non_uniform_to_grid1d() {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.3).unwrap(),
Real::try_new(0.7).unwrap(),
Real::try_new(1.0).unwrap(),
]))
.unwrap();
let non_uniform_grid =
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords).unwrap();
let grid: Grid1D<IntervalClosed<Real>> = Grid1D::from(non_uniform_grid.clone());
assert!(matches!(grid, Grid1D::NonUniform(_)));
assert_eq!(grid.domain(), non_uniform_grid.domain());
assert_eq!(grid.num_intervals().as_ref(), &3);
assert_eq!(grid.coords().deref(), non_uniform_grid.coords().deref());
}
#[test]
fn test_from_grid1d_uniform_into_syntax() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
let uniform_grid =
Grid1DUniform::new(domain.clone(), NumIntervals::try_new(4).unwrap());
let grid: Grid1D<IntervalClosed<Real>> = uniform_grid.into();
assert!(matches!(grid, Grid1D::Uniform(_)));
}
#[test]
fn test_from_grid1d_non_uniform_into_syntax() {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(1.0).unwrap(),
]))
.unwrap();
let non_uniform_grid =
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords).unwrap();
let grid: Grid1D<IntervalClosed<Real>> = non_uniform_grid.into();
assert!(matches!(grid, Grid1D::NonUniform(_)));
}
#[test]
fn test_translate_uniform_grid_in_place() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let mut grid = Grid1DUniform::new(domain, NumIntervals::try_new(2).unwrap());
grid.translate_in_place(&Real::try_new(1.5).unwrap());
assert_eq!(
grid.coords().deref(),
&[
Real::try_new(1.5).unwrap(),
Real::try_new(2.5).unwrap(),
Real::try_new(3.5).unwrap()
]
);
assert_eq!(
grid.domain().lower_bound_value(),
&Real::try_new(1.5).unwrap()
);
assert_eq!(
grid.domain().upper_bound_value(),
&Real::try_new(3.5).unwrap()
);
}
#[test]
fn test_translate_non_uniform_grid_in_place() {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.3).unwrap(),
Real::try_new(1.0).unwrap(),
]))
.unwrap();
let mut grid =
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords).unwrap();
grid.translate_in_place(&Real::try_new(-0.5).unwrap());
assert_eq!(
grid.coords().deref(),
&[
Real::try_new(-0.5).unwrap(),
Real::try_new(-0.2).unwrap(),
Real::try_new(0.5).unwrap()
]
);
assert_eq!(
grid.domain().lower_bound_value(),
&Real::try_new(-0.5).unwrap()
);
assert_eq!(
grid.domain().upper_bound_value(),
&Real::try_new(0.5).unwrap()
);
}
#[test]
fn test_translate_grid1d_enum_dispatch_uniform_and_non_uniform() {
let mut grid_uniform = Grid1D::uniform(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
NumIntervals::try_new(2).unwrap(),
);
grid_uniform.translate_in_place(&Real::try_new(2.0).unwrap());
assert_eq!(
grid_uniform.coords().deref(),
&[
Real::try_new(2.0).unwrap(),
Real::try_new(2.5).unwrap(),
Real::try_new(3.0).unwrap()
]
);
let coords_non_uniform = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.4).unwrap(),
Real::try_new(1.0).unwrap(),
]);
let mut grid_non_uniform =
Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords_non_uniform).unwrap();
grid_non_uniform.translate_in_place(&Real::try_new(1.0).unwrap());
assert_eq!(
grid_non_uniform.coords().deref(),
&[
Real::try_new(1.0).unwrap(),
Real::try_new(1.4).unwrap(),
Real::try_new(2.0).unwrap()
]
);
}
#[test]
fn test_grid1d_non_uniform_refine_uniform_dispatch() {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.2).unwrap(),
Real::try_new(1.0).unwrap(),
]))
.unwrap();
let grid = Grid1D::NonUniform(
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords).unwrap(),
);
let refinement = grid.refine_uniform(&PositiveNumPoints1D::try_new(1).unwrap());
assert!(matches!(refinement.original_grid(), Grid1D::NonUniform(_)));
assert!(matches!(refinement.refined_grid(), Grid1D::NonUniform(_)));
assert_eq!(refinement.original_grid().num_intervals().as_ref(), &2);
assert_eq!(refinement.refined_grid().num_intervals().as_ref(), &4);
assert_eq!(
refinement.find_original_interval(&IntervalId::new(0)),
IntervalId::new(0)
);
assert_eq!(
refinement.find_original_interval(&IntervalId::new(1)),
IntervalId::new(0)
);
assert_eq!(
refinement.find_original_interval(&IntervalId::new(2)),
IntervalId::new(1)
);
assert_eq!(
refinement.find_original_interval(&IntervalId::new(3)),
IntervalId::new(1)
);
}
}
mod grid1d_open_intervals {
use super::*;
#[test]
fn test_open_interval_partition() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
]);
let grid = Grid1D::<IntervalOpen<Real>>::try_from_sorted(coords).unwrap();
let interval_0 = grid.interval(&IntervalId::new(0));
match interval_0 {
SubIntervalInPartition::First(interval) => {
assert!(!interval.contains_point(&Real::try_new(0.0).unwrap())); assert!(interval.contains_point(&Real::try_new(0.5).unwrap())); assert!(interval.contains_point(&Real::try_new(1.0).unwrap())); }
_ => panic!("Expected first interval"),
}
let interval_1 = grid.interval(&IntervalId::new(1));
match interval_1 {
SubIntervalInPartition::Last(interval) => {
assert!(!interval.contains_point(&Real::try_new(1.0).unwrap())); assert!(interval.contains_point(&Real::try_new(1.5).unwrap())); assert!(!interval.contains_point(&Real::try_new(2.0).unwrap())); }
_ => panic!("Expected last interval"),
}
}
#[test]
fn test_find_interval_on_open_domain() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(3.0).unwrap(),
]);
let grid = Grid1D::<IntervalOpen<Real>>::try_from_sorted(coords).unwrap();
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.5).unwrap())
.unwrap(),
IntervalId::new(0)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.5).unwrap())
.unwrap(),
IntervalId::new(1)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.5).unwrap())
.unwrap(),
IntervalId::new(2)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.0).unwrap())
.unwrap(),
IntervalId::new(0)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.0).unwrap())
.unwrap(),
IntervalId::new(1)
);
}
#[test]
fn test_find_interval_boundary_point_not_in_open_domain() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
]);
let grid = Grid1D::<IntervalOpen<Real>>::try_from_sorted(coords).unwrap();
let res = grid.find_interval_id_of_point(&Real::try_new(0.0).unwrap());
assert!(res.is_none(), "Expected None for point on open boundary");
}
}
mod grid1d_semi_open_intervals {
use super::*;
#[test]
fn test_lower_closed_upper_open_partition() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
]);
let grid =
Grid1D::<IntervalLowerClosedUpperOpen<Real>>::try_from_sorted(coords).unwrap();
let interval_0 = grid.interval(&IntervalId::new(0));
match interval_0 {
SubIntervalInPartition::First(interval) => {
assert!(interval.contains_point(&Real::try_new(0.0).unwrap())); assert!(interval.contains_point(&Real::try_new(0.5).unwrap())); assert!(!interval.contains_point(&Real::try_new(1.0).unwrap())); }
_ => panic!("Expected first interval"),
}
let interval_1 = grid.interval(&IntervalId::new(1));
match interval_1 {
SubIntervalInPartition::Last(interval) => {
assert!(interval.contains_point(&Real::try_new(1.0).unwrap())); assert!(interval.contains_point(&Real::try_new(1.5).unwrap())); assert!(!interval.contains_point(&Real::try_new(2.0).unwrap())); }
_ => panic!("Expected last interval"),
}
}
#[test]
fn test_lower_open_upper_closed_partition() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap(),
]);
let grid =
Grid1D::<IntervalLowerOpenUpperClosed<Real>>::try_from_sorted(coords).unwrap();
let interval_0 = grid.interval(&IntervalId::new(0));
match interval_0 {
SubIntervalInPartition::First(interval) => {
assert!(!interval.contains_point(&Real::try_new(0.0).unwrap())); assert!(interval.contains_point(&Real::try_new(0.5).unwrap())); assert!(interval.contains_point(&Real::try_new(1.0).unwrap())); }
_ => panic!("Expected first interval"),
}
let interval_1 = grid.interval(&IntervalId::new(1));
match interval_1 {
SubIntervalInPartition::Last(interval) => {
assert!(!interval.contains_point(&Real::try_new(1.0).unwrap())); assert!(interval.contains_point(&Real::try_new(1.5).unwrap())); assert!(interval.contains_point(&Real::try_new(2.0).unwrap())); }
_ => panic!("Expected last interval"),
}
}
}
mod interval_partition_general {
use super::*;
#[test]
fn test_interval_partition_general_creation() {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(0.5).unwrap(),
Real::try_new(1.0).unwrap(),
]))
.unwrap();
let partition =
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords.clone())
.unwrap();
assert_eq!(partition.coords(), &coords);
assert_eq!(
partition.domain(),
&IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap())
);
}
#[test]
fn test_interval_partition_general_insufficient_points() {
let coords =
Coords1D::try_from(SortedSet::from_unsorted(vec![Real::try_new(0.0).unwrap()]))
.unwrap();
let partition =
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords);
matches!(
partition,
Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints { .. })
);
}
}
mod interval_partition_advanced {
use super::*;
#[test]
fn test_interval_partition_iter_intervals() {
let grid = Grid1D::uniform(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(3.0).unwrap()),
NumIntervals::try_new(3).unwrap(),
);
let intervals: Vec<(IntervalId, SubIntervalInPartition<IntervalClosed<Real>>)> =
grid.iter_intervals().collect();
assert_eq!(intervals.len(), 3);
for (i, (id, _)) in intervals.iter().enumerate() {
assert_eq!(*id.as_ref(), i);
}
}
#[test]
fn test_interval_partition_find_intervals_for_points() {
let grid = Grid1D::uniform(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap()),
NumIntervals::try_new(10).unwrap(),
);
let points = vec![
Real::try_new(0.5).unwrap(),
Real::try_new(2.3).unwrap(),
Real::try_new(5.0).unwrap(),
Real::try_new(7.8).unwrap(),
Real::try_new(10.0).unwrap(),
Real::try_new(11.0).unwrap(),
];
let intervals = grid.find_intervals_for_points(&points);
assert_eq!(intervals.len(), 6);
assert_eq!(intervals[0], Some(IntervalId::new(0)));
assert_eq!(intervals[1], Some(IntervalId::new(2)));
assert_eq!(intervals[2], Some(IntervalId::new(5))); assert_eq!(intervals[3], Some(IntervalId::new(7)));
assert_eq!(intervals[4], Some(IntervalId::new(9)));
assert_eq!(intervals[5], None); }
#[test]
fn test_interval_partition_length_statistics() {
let coords = SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(1.5).unwrap(),
Real::try_new(4.0).unwrap(),
]);
let grid = Grid1D::<IntervalClosed<Real>>::try_from_sorted(coords).unwrap();
assert_eq!(
grid.min_interval_length().as_ref(),
&Real::try_new(0.5).unwrap()
);
assert_eq!(
grid.max_interval_length().as_ref(),
&Real::try_new(2.5).unwrap()
);
assert_eq!(
grid.uniformity_ratio().as_ref(),
&Real::try_new(5.0).unwrap()
); }
#[test]
fn test_interval_partition_intersection_edge_cases() {
let grid = Grid1D::uniform(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap()),
NumIntervals::try_new(2).unwrap(),
);
let domain_small =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(0.5).unwrap());
let intersections = grid.intervals_in_intersection(&domain_small);
assert_eq!(
&intersections,
&[(
IntervalId::new(0),
IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(0.5).unwrap()
)
.into()
)]
);
let domain_full =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let intersections_full = grid.intervals_in_intersection(&domain_full);
assert_eq!(
&intersections_full,
&[
(
IntervalId::new(0),
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
)
.into()
),
(
IntervalId::new(1),
IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
)
.into()
)
]
);
let domain_larger =
IntervalClosed::new(Real::try_new(-0.1).unwrap(), Real::try_new(2.1).unwrap());
let intersections_larger = grid.intervals_in_intersection(&domain_larger);
assert_eq!(intersections_larger.len(), 2); assert_eq!(
&intersections_larger,
&[
(
IntervalId::new(0),
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
)
.into()
),
(
IntervalId::new(1),
IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
)
.into()
)
]
);
}
}
mod grid1d_uniform {
use super::*;
#[test]
fn test_uniform_grid_creation() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap());
let num_intervals = NumIntervals::try_new(5).unwrap();
let grid = Grid1DUniform::new(domain.clone(), num_intervals);
assert_eq!(grid.domain(), &domain);
assert_eq!(grid.num_intervals(), num_intervals);
assert_eq!(
grid.coords().deref(),
&[
Real::try_new(0.0).unwrap(),
Real::try_new(2.0).unwrap(),
Real::try_new(4.0).unwrap(),
Real::try_new(6.0).unwrap(),
Real::try_new(8.0).unwrap(),
Real::try_new(10.0).unwrap()
]
);
assert_eq!(*grid.delta_points().as_ref(), Real::try_new(2.0).unwrap());
}
#[test]
fn test_uniform_grid_interval_partition_closed_domain() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let grid = Grid1DUniform::new(domain, NumIntervals::try_new(2).unwrap());
assert_eq!(
*grid.interval_length(&IntervalId::new(0)).as_ref(),
Real::try_new(1.0).unwrap()
);
assert_eq!(
*grid.min_interval_length().as_ref(),
Real::try_new(1.0).unwrap()
);
assert_eq!(
*grid.max_interval_length().as_ref(),
Real::try_new(1.0).unwrap()
);
assert_eq!(
*grid.uniformity_ratio().as_ref(),
Real::try_new(1.0).unwrap()
);
let interval_0 = grid.interval(&IntervalId::new(0));
let interval_1 = grid.interval(&IntervalId::new(1));
match interval_0 {
SubIntervalInPartition::First(i) => {
assert_eq!(
i,
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
)
);
assert!(i.contains_point(&Real::try_new(0.0).unwrap()));
assert!(!i.contains_point(&Real::try_new(1.0).unwrap()));
}
_ => panic!("Expected first interval"),
}
match interval_1 {
SubIntervalInPartition::Last(i) => {
assert_eq!(
i,
IntervalClosed::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
)
);
assert!(i.contains_point(&Real::try_new(1.0).unwrap()));
assert!(i.contains_point(&Real::try_new(2.0).unwrap()));
}
_ => panic!("Expected last interval"),
}
}
#[test]
fn test_uniform_grid_point_location_o1() {
let domain =
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap());
let grid = Grid1DUniform::new(domain, NumIntervals::try_new(10).unwrap());
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.0).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(10.0).unwrap()),
Some(IntervalId::new(9))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.5).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.5).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(9.9).unwrap()),
Some(IntervalId::new(9))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(1))
); assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.0).unwrap()),
Some(IntervalId::new(2))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(9.0).unwrap()),
Some(IntervalId::new(9))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(-0.1).unwrap()),
None
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(10.1).unwrap()),
None
);
}
#[test]
fn test_uniform_grid_point_location_high_res() {
let grid = Grid1DUniform::new(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
NumIntervals::try_new(10000).unwrap(),
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.00005).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.0001).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.00011).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.54321).unwrap()),
Some(IntervalId::new(5432))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.99999).unwrap()),
Some(IntervalId::new(9999))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(9999))
);
}
#[test]
fn test_uniform_grid_open_domain() {
let domain =
IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap());
let grid = Grid1DUniform::new(domain, NumIntervals::try_new(2).unwrap());
let expected_coords = [
Real::try_new(0.).unwrap(),
Real::try_new(1.).unwrap(),
Real::try_new(2.).unwrap(),
];
assert_eq!(grid.coords().deref(), expected_coords.as_slice());
let interval_0 = grid.interval(&IntervalId::new(0));
match interval_0 {
SubIntervalInPartition::First(i) => {
assert_eq!(
i,
IntervalLowerOpenUpperClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
)
);
assert!(!i.contains_point(&Real::try_new(0.0).unwrap()));
assert!(i.contains_point(&Real::try_new(1.0).unwrap()));
}
_ => panic!("Expected first interval"),
}
let interval_1 = grid.interval(&IntervalId::new(1));
match interval_1 {
SubIntervalInPartition::Last(i) => {
assert_eq!(
i,
IntervalOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(2.0).unwrap()
)
);
assert!(!i.contains_point(&Real::try_new(1.0).unwrap()));
assert!(!i.contains_point(&Real::try_new(2.0).unwrap()));
}
_ => panic!("Expected last interval"),
}
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.1).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.9).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.0).unwrap()),
None
); assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.0).unwrap()),
None
); }
#[test]
fn test_uniform_grid_intersection() {
let grid = Grid1DUniform::new(
IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap()),
NumIntervals::try_new(10).unwrap(),
);
let domain_in =
IntervalClosed::new(Real::try_new(2.5).unwrap(), Real::try_new(7.5).unwrap());
let intersections = grid.intervals_in_intersection(&domain_in);
assert_eq!(intersections.len(), 6);
assert_eq!(intersections[0].0, IntervalId::new(2));
assert_eq!(
intersections[0].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(2.5).unwrap(),
Real::try_new(3.0).unwrap()
))
);
assert_eq!(intersections[2].0, IntervalId::new(4));
assert_eq!(
intersections[2].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(4.0).unwrap(),
Real::try_new(5.0).unwrap()
))
);
assert_eq!(intersections[5].0, IntervalId::new(7));
assert_eq!(
intersections[5].1,
IntervalFinitePositiveLength::from(IntervalClosed::new(
Real::try_new(7.0).unwrap(),
Real::try_new(7.5).unwrap()
))
);
}
}
mod grid1d_non_uniform {
use super::*;
use crate::intervals::IntervalClosed;
fn create_test_grid() -> Grid1DNonUniform<IntervalClosed<Real>> {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
Real::try_new(7.0).unwrap(),
Real::try_new(10.0).unwrap(),
]))
.unwrap();
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords).unwrap()
}
#[test]
fn test_non_uniform_grid_creation() {
let grid = create_test_grid();
assert_eq!(
grid.domain(),
&IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(10.0).unwrap())
);
assert_eq!(
grid.coords().deref(),
&[
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap(),
Real::try_new(7.0).unwrap(),
Real::try_new(10.0).unwrap()
]
);
assert_eq!(grid.num_intervals().as_ref(), &4);
}
#[test]
fn test_creation_fails_with_insufficient_points() {
let coords =
Coords1D::try_from(SortedSet::from_unsorted(vec![Real::try_new(0.0).unwrap()]))
.unwrap();
let result = Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords);
assert!(matches!(
result,
Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints { .. })
));
}
#[test]
fn test_non_uniform_interval_partition() {
let grid = create_test_grid();
let interval_0 = grid.interval(&IntervalId::new(0));
match interval_0 {
SubIntervalInPartition::First(i) => {
assert_eq!(
i,
IntervalLowerClosedUpperOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
)
);
}
_ => panic!("Expected first interval"),
}
let interval_1 = grid.interval(&IntervalId::new(1));
match interval_1 {
SubIntervalInPartition::Middle(i) => {
assert_eq!(
i,
IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap()
)
);
}
_ => panic!("Expected middle interval"),
}
let interval_3 = grid.interval(&IntervalId::new(3));
match interval_3 {
SubIntervalInPartition::Last(i) => {
assert_eq!(
i,
IntervalClosed::new(
Real::try_new(7.0).unwrap(),
Real::try_new(10.0).unwrap()
)
);
}
_ => panic!("Expected last interval"),
}
}
#[test]
fn test_non_uniform_statistics() {
let grid = create_test_grid();
assert_eq!(
*grid.interval_length(&IntervalId::new(0)).as_ref(),
Real::try_new(1.0).unwrap()
); assert_eq!(
*grid.interval_length(&IntervalId::new(1)).as_ref(),
Real::try_new(2.0).unwrap()
); assert_eq!(
*grid.interval_length(&IntervalId::new(2)).as_ref(),
Real::try_new(4.0).unwrap()
); assert_eq!(
*grid.interval_length(&IntervalId::new(3)).as_ref(),
Real::try_new(3.0).unwrap()
);
assert_eq!(
*grid.min_interval_length().as_ref(),
Real::try_new(1.0).unwrap()
);
assert_eq!(
*grid.max_interval_length().as_ref(),
Real::try_new(4.0).unwrap()
);
assert_eq!(
*grid.uniformity_ratio().as_ref(),
Real::try_new(4.0).unwrap()
);
}
#[test]
fn test_non_uniform_point_location() {
let grid = create_test_grid();
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.0).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(10.0).unwrap()),
Some(IntervalId::new(3))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(0.5).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.5).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(5.0).unwrap()),
Some(IntervalId::new(2))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(8.5).unwrap()),
Some(IntervalId::new(3))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(3.0).unwrap()),
Some(IntervalId::new(2))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(7.0).unwrap()),
Some(IntervalId::new(3))
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(-0.1).unwrap()),
None
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(10.1).unwrap()),
None
);
}
#[test]
fn test_non_uniform_intersection() {
let grid = create_test_grid();
let domain_in =
IntervalClosed::new(Real::try_new(0.5).unwrap(), Real::try_new(8.5).unwrap());
let intersections = grid.intervals_in_intersection(&domain_in);
assert_eq!(intersections.len(), 4);
assert_eq!(intersections[0].0, IntervalId::new(0));
assert_eq!(
intersections[0].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(0.5).unwrap(),
Real::try_new(1.0).unwrap()
))
);
assert_eq!(intersections[1].0, IntervalId::new(1));
assert_eq!(
intersections[1].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(1.0).unwrap(),
Real::try_new(3.0).unwrap()
))
);
assert_eq!(intersections[2].0, IntervalId::new(2));
assert_eq!(
intersections[2].1,
IntervalFinitePositiveLength::from(IntervalLowerClosedUpperOpen::new(
Real::try_new(3.0).unwrap(),
Real::try_new(7.0).unwrap()
))
);
assert_eq!(intersections[3].0, IntervalId::new(3));
assert_eq!(
intersections[3].1,
IntervalFinitePositiveLength::from(IntervalClosed::new(
Real::try_new(7.0).unwrap(),
Real::try_new(8.5).unwrap()
))
);
}
}
mod find_interval_id_of_point {
use super::*;
fn r(v: f64) -> Real {
Real::try_new(v).unwrap()
}
fn assert_finds<G>(grid: &G, x: G::CoordType, expected: Option<IntervalId>)
where
G: Grid1DTrait,
{
let found = grid.find_interval_id_of_point(&x);
assert_eq!(found, expected);
if let Some(ref id) = found {
assert!(
grid.interval(id).contains_point(&x),
"interval {:?} returned for point but does not contain it",
id
);
}
}
mod grid1d_non_uniform {
use super::*;
mod interval_closed {
use super::*;
fn make_grid() -> Grid1DNonUniform<IntervalClosed<Real>> {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
r(0.0),
r(1.0),
r(3.0),
r(6.0),
r(10.0),
]))
.unwrap();
Grid1DNonUniform::<IntervalClosed<Real>>::try_new_from_coords(coords)
.unwrap()
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(4.0), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(8.0), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary() {
assert_finds(&make_grid(), r(0.0), Some(IntervalId::new(0)));
}
#[test]
fn internal_boundaries_belong_to_right_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(2)));
assert_finds(&grid, r(6.0), Some(IntervalId::new(3)));
}
#[test]
fn upper_domain_boundary() {
assert_finds(&make_grid(), r(10.0), Some(IntervalId::new(3)));
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(10.1), None);
}
}
mod interval_open {
use super::*;
fn make_grid() -> Grid1DNonUniform<IntervalOpen<Real>> {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
r(0.0),
r(1.0),
r(3.0),
r(6.0),
r(10.0),
]))
.unwrap();
Grid1DNonUniform::<IntervalOpen<Real>>::try_new_from_coords(coords).unwrap()
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(4.0), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(8.0), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(0.0), None);
}
#[test]
fn internal_boundaries_belong_to_left_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(0)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(6.0), Some(IntervalId::new(2)));
}
#[test]
fn upper_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(10.0), None);
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(10.1), None);
}
}
mod interval_lower_closed_upper_open {
use super::*;
fn make_grid() -> Grid1DNonUniform<IntervalLowerClosedUpperOpen<Real>> {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
r(0.0),
r(1.0),
r(3.0),
r(6.0),
r(10.0),
]))
.unwrap();
Grid1DNonUniform::<IntervalLowerClosedUpperOpen<Real>>::try_new_from_coords(
coords,
)
.unwrap()
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(4.0), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(8.0), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary() {
assert_finds(&make_grid(), r(0.0), Some(IntervalId::new(0)));
}
#[test]
fn internal_boundaries_belong_to_right_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(2)));
assert_finds(&grid, r(6.0), Some(IntervalId::new(3)));
}
#[test]
fn upper_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(10.0), None);
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(10.1), None);
}
}
mod interval_lower_open_upper_closed {
use super::*;
fn make_grid() -> Grid1DNonUniform<IntervalLowerOpenUpperClosed<Real>> {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
r(0.0),
r(1.0),
r(3.0),
r(6.0),
r(10.0),
]))
.unwrap();
Grid1DNonUniform::<IntervalLowerOpenUpperClosed<Real>>::try_new_from_coords(
coords,
)
.unwrap()
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(4.0), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(8.0), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(0.0), None);
}
#[test]
fn internal_boundaries_belong_to_left_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(0)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(6.0), Some(IntervalId::new(2)));
}
#[test]
fn upper_domain_boundary() {
assert_finds(&make_grid(), r(10.0), Some(IntervalId::new(3)));
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(10.1), None);
}
}
mod interval_finite_positive_length {
use super::*;
fn make_grid() -> Grid1DNonUniform<IntervalFinitePositiveLength<Real>> {
let coords = Coords1D::try_from(SortedSet::from_unsorted(vec![
r(0.0),
r(1.0),
r(3.0),
r(6.0),
r(10.0),
]))
.unwrap();
let domain: IntervalFinitePositiveLength<Real> =
IntervalClosed::new(r(0.0), r(10.0)).into();
Grid1DNonUniform::<IntervalFinitePositiveLength<Real>>::try_new(
domain, coords,
)
.unwrap()
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(4.0), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(8.0), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary() {
assert_finds(&make_grid(), r(0.0), Some(IntervalId::new(0)));
}
#[test]
fn internal_boundaries_belong_to_right_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(2)));
assert_finds(&grid, r(6.0), Some(IntervalId::new(3)));
}
#[test]
fn upper_domain_boundary() {
assert_finds(&make_grid(), r(10.0), Some(IntervalId::new(3)));
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(10.1), None);
}
}
}
mod grid1d_uniform {
use super::*;
mod interval_closed {
use super::*;
fn make_grid() -> Grid1DUniform<IntervalClosed<Real>> {
Grid1DUniform::new(
IntervalClosed::new(r(0.0), r(4.0)),
NumIntervals::try_new(4).unwrap(),
)
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(1.5), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.5), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(3.5), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary() {
assert_finds(&make_grid(), r(0.0), Some(IntervalId::new(0)));
}
#[test]
fn internal_boundaries_belong_to_right_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.0), Some(IntervalId::new(2)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(3)));
}
#[test]
fn upper_domain_boundary() {
assert_finds(&make_grid(), r(4.0), Some(IntervalId::new(3)));
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(4.1), None);
}
}
mod interval_open {
use super::*;
fn make_grid() -> Grid1DUniform<IntervalOpen<Real>> {
Grid1DUniform::new(
IntervalOpen::new(r(0.0), r(4.0)),
NumIntervals::try_new(4).unwrap(),
)
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(1.5), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.5), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(3.5), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(0.0), None);
}
#[test]
fn internal_boundaries_belong_to_left_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(0)));
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(2)));
}
#[test]
fn upper_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(4.0), None);
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(4.1), None);
}
}
mod interval_lower_closed_upper_open {
use super::*;
fn make_grid() -> Grid1DUniform<IntervalLowerClosedUpperOpen<Real>> {
Grid1DUniform::new(
IntervalLowerClosedUpperOpen::new(r(0.0), r(4.0)),
NumIntervals::try_new(4).unwrap(),
)
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(1.5), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.5), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(3.5), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary() {
assert_finds(&make_grid(), r(0.0), Some(IntervalId::new(0)));
}
#[test]
fn internal_boundaries_belong_to_right_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.0), Some(IntervalId::new(2)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(3)));
}
#[test]
fn upper_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(4.0), None);
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(4.1), None);
}
}
mod interval_lower_open_upper_closed {
use super::*;
fn make_grid() -> Grid1DUniform<IntervalLowerOpenUpperClosed<Real>> {
Grid1DUniform::new(
IntervalLowerOpenUpperClosed::new(r(0.0), r(4.0)),
NumIntervals::try_new(4).unwrap(),
)
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(1.5), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.5), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(3.5), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary_returns_none() {
assert_finds(&make_grid(), r(0.0), None);
}
#[test]
fn internal_boundaries_belong_to_left_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(0)));
assert_finds(&grid, r(2.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(2)));
}
#[test]
fn upper_domain_boundary() {
assert_finds(&make_grid(), r(4.0), Some(IntervalId::new(3)));
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(4.1), None);
}
}
mod interval_finite_positive_length {
use super::*;
fn make_grid() -> Grid1DUniform<IntervalFinitePositiveLength<Real>> {
Grid1DUniform::new(
IntervalFinitePositiveLength::Closed(IntervalClosed::new(
r(0.0),
r(4.0),
)),
NumIntervals::try_new(4).unwrap(),
)
}
#[test]
fn first_interval_interior() {
assert_finds(&make_grid(), r(0.5), Some(IntervalId::new(0)));
}
#[test]
fn middle_intervals_interior() {
let grid = make_grid();
assert_finds(&grid, r(1.5), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.5), Some(IntervalId::new(2)));
}
#[test]
fn last_interval_interior() {
assert_finds(&make_grid(), r(3.5), Some(IntervalId::new(3)));
}
#[test]
fn lower_domain_boundary() {
assert_finds(&make_grid(), r(0.0), Some(IntervalId::new(0)));
}
#[test]
fn internal_boundaries_belong_to_right_interval() {
let grid = make_grid();
assert_finds(&grid, r(1.0), Some(IntervalId::new(1)));
assert_finds(&grid, r(2.0), Some(IntervalId::new(2)));
assert_finds(&grid, r(3.0), Some(IntervalId::new(3)));
}
#[test]
fn upper_domain_boundary() {
assert_finds(&make_grid(), r(4.0), Some(IntervalId::new(3)));
}
#[test]
fn outside_domain_returns_none() {
let grid = make_grid();
assert_finds(&grid, r(-0.1), None);
assert_finds(&grid, r(4.1), None);
}
}
}
}
}
#[cfg(feature = "rug")]
mod rug100 {
use super::*;
use num::{One, Zero};
use num_valid::RealRugStrictFinite;
const PRECISION: u32 = 100;
type Real = RealRugStrictFinite<PRECISION>;
mod grid1d {
use super::*;
use num_valid::Constants;
#[test]
fn grid1d_01() {
let v = SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0., 1.]));
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
assert_eq!(grid1d.coords().deref(), &v.to_vec());
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn grid1d_02() {
let v = SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0.]));
let _grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
}
#[test]
fn interval_01() {
let v = SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0., 1.]));
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
let interval = grid1d.interval(&IntervalId::new(0));
match interval {
SubIntervalInPartition::Single(interval) => {
assert_eq!(
TryInto::<IntervalClosed<Real>>::try_into(interval).unwrap(),
IntervalClosed::new(Real::zero(), Real::one())
);
}
_ => {
panic!("There should be only one interval")
}
}
}
#[test]
#[cfg(debug_assertions)]
#[should_panic]
fn interval_02() {
let v = SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0., 1.]));
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
let _interval = grid1d.interval(&IntervalId::new(1));
}
#[test]
fn find_interval_id_01() {
let v =
SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0., 1., 2., 3.]));
let grid1d = Grid1D::<IntervalClosed<Real>>::try_from_sorted(v.clone()).unwrap();
let i0 = grid1d.find_interval_id_of_point(&Real::zero()).unwrap();
assert_eq!(i0, IntervalId::new(0));
let i1 = grid1d
.find_interval_id_of_point(
&Real::try_new(rug::Float::with_val(PRECISION, 0.5)).unwrap(),
)
.unwrap();
assert_eq!(i1, IntervalId::new(0));
let i2 = grid1d.find_interval_id_of_point(&Real::one()).unwrap();
assert_eq!(i2, IntervalId::new(1));
let i3 = grid1d
.find_interval_id_of_point(
&Real::try_new(rug::Float::with_val(PRECISION, 1.5)).unwrap(),
)
.unwrap();
assert_eq!(i3, IntervalId::new(1));
let i4 = grid1d.find_interval_id_of_point(&Real::two()).unwrap();
assert_eq!(i4, IntervalId::new(2));
let i5 = grid1d
.find_interval_id_of_point(
&Real::try_new(rug::Float::with_val(PRECISION, 2.5)).unwrap(),
)
.unwrap();
assert_eq!(i5, IntervalId::new(2));
let i6 = grid1d
.find_interval_id_of_point(
&Real::try_new(rug::Float::with_val(PRECISION, 3.)).unwrap(),
)
.unwrap();
assert_eq!(i6, IntervalId::new(2));
}
#[test]
fn uniform_01() {
let interval = IntervalClosed::new(Real::zero(), Real::one());
let grid1d = Grid1D::uniform(interval, NumIntervals::try_new(4).unwrap());
let expected_coords = vec_f64_into_vec_real::<Real>(vec![0., 0.25, 0.5, 0.75, 1.0]);
assert_eq!(grid1d.coords().deref(), &expected_coords);
}
#[test]
fn intersection_01() {
let grid1d_a = Grid1D::<IntervalClosed<Real>>::try_from_sorted(
SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0.0, 1.0, 2.0])),
)
.unwrap();
let grid1d_b = Grid1D::<IntervalClosed<Real>>::try_from_sorted(
SortedSet::from_unsorted(vec_f64_into_vec_real::<Real>(vec![0.0, 0.5, 2.0])),
)
.unwrap();
let union = Grid1DUnion::try_new(&grid1d_a, &grid1d_b).unwrap();
let (grid1d_fine, map_a, map_b) = union.into_parts();
assert_eq!(
grid1d_fine.coords().deref(),
&vec_f64_into_vec_real::<f64>(vec![0.0, 0.5, 1.0, 2.0])
);
assert_eq!(map_a[0], IntervalId::new(0));
assert_eq!(map_a[1], IntervalId::new(0));
assert_eq!(map_a[2], IntervalId::new(1));
assert_eq!(map_b[0], IntervalId::new(0));
assert_eq!(map_b[1], IntervalId::new(1));
assert_eq!(map_b[2], IntervalId::new(1));
}
}
}
}