#![deny(rustdoc::broken_intra_doc_links)]
#![feature(error_generic_member_access)]
pub mod bounds;
pub mod coords;
pub use coords::{
Coords1D, Coords1DInDomain, Coords1DInDomainArc, Coords1DInDomainBorrowed, Coords1DInDomainBox,
Coords1DInDomainCow, Coords1DInDomainOwned, Coords1DInDomainRc, ErrorsCoords1D,
ErrorsCoords1DInDomain, linspace, logspace,
};
pub mod intervals;
pub mod operations;
pub use operations::{
refinement::{Grid1DNonUniformRefinement, Grid1DRefinement, Grid1DUniformRefinement},
union::{ErrorsGrid1DUnion, Grid1DUnion},
};
pub mod scalars;
pub mod topology;
pub use topology::{
Adjacency1D, Grid1DIndexSpaces, HasSide, IndexSpace1D, IntervalIndexSpace1D, IntervalSide,
PointIndexSpace1D, Side, Topology1D,
};
pub mod traits;
pub use traits::{
BuildIntervalInPartition, HasCoords1D, HasDomain1D, IntervalPartition, TransformedPoints1D,
TransformedPoints1DArc, TransformedPoints1DBorrowed, TransformedPoints1DOwned,
TransformedPoints1DRc,
};
use crate::{
intervals::{
Contains, ErrorsIntervalConstruction, GetLowerBoundValue, GetUpperBoundValue, Interval,
IntervalTrait,
bounded::{IntervalFinitePositiveLengthTrait, SubIntervalInPartition},
},
operations::refinement::{
build_non_uniform_grid_refinement, refine_all_intervals_in_coords1d_same_subdivisions,
},
scalars::{IntervalId, NumIntervals, PositiveNumPoints1D},
topology::sealed::SupportsCircularTopology,
};
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, Clone, Getters, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "Domain1D: for<'d> serde::Deserialize<'d>, \
Domain1D::RealType: for<'d> serde::Deserialize<'d>"))]
pub struct Grid1DUniform<Domain1D: IntervalFinitePositiveLengthTrait> {
coords: Coords1D<Domain1D::RealType>,
domain: Domain1D,
index_spaces: Grid1DIndexSpaces,
#[getset(get = "pub")]
delta_points: PositiveRealScalar<Domain1D::RealType>,
}
fn compute_delta_points<Domain1D: IntervalFinitePositiveLengthTrait>(
domain: &Domain1D,
num_intervals: &NumIntervals,
) -> PositiveRealScalar<Domain1D::RealType> {
let n_intervals = *num_intervals.as_ref();
PositiveRealScalar::try_new(
domain.length().into_inner()
* Domain1D::RealType::try_from_f64(n_intervals as f64)
.unwrap()
.try_reciprocal()
.unwrap(),
)
.expect("Delta points must be positive!")
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Grid1DUniform<Domain1D> {
pub fn new(domain: Domain1D, num_intervals: NumIntervals) -> Self {
let delta_points = compute_delta_points(&domain, &num_intervals);
let coords = Coords1D::new_uniform(&domain, &num_intervals);
let index_spaces = Grid1DIndexSpaces::new(num_intervals, Topology1D::RealLine);
Self {
coords,
domain,
delta_points,
index_spaces,
}
}
}
impl<Domain1D> Grid1DUniform<Domain1D>
where
Domain1D: IntervalFinitePositiveLengthTrait + SupportsCircularTopology,
{
pub fn new_periodic(domain: Domain1D, num_intervals: NumIntervals) -> Self {
let delta_points = compute_delta_points(&domain, &num_intervals);
let coords = Coords1D::new_uniform(&domain, &num_intervals);
let index_spaces = Grid1DIndexSpaces::new(num_intervals, Topology1D::Circle);
Self {
coords,
domain,
delta_points,
index_spaces,
}
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasDomain1D for Grid1DUniform<Domain1D> {
type Domain1D = Domain1D;
fn domain(&self) -> &Domain1D {
&self.domain
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoords1D for Grid1DUniform<Domain1D> {
type Point1DType = Domain1D::RealType;
fn coords(&self) -> &Coords1D<Self::Point1DType> {
&self.coords
}
}
impl<Domain1D: BuildIntervalInPartition> IntervalPartition for Grid1DUniform<Domain1D> {
fn index_spaces(&self) -> &Grid1DIndexSpaces {
&self.index_spaces
}
fn try_find_interval_id_of_point(&self, x: &Self::Point1DType) -> 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(grid_idx) => {
let grid_idx = grid_idx.into_inner();
if grid_idx == 0 {
Some(IntervalId::new(0))
} else if grid_idx == num_intervals {
Some(IntervalId::new(num_intervals - 1))
} else {
if Domain1D::LOWER_BOUND_OWNS_BOUNDARY {
Some(IntervalId::new(grid_idx))
} else {
Some(IntervalId::new(grid_idx - 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))
}
}
}
fn max_interval_length(&self) -> PositiveRealScalar<Self::Point1DType> {
self.delta_points.clone()
}
fn min_interval_length(&self) -> PositiveRealScalar<Self::Point1DType> {
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)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "Domain1D: for<'d> serde::Deserialize<'d>, \
Domain1D::RealType: for<'d> serde::Deserialize<'d>"))]
pub struct Grid1DNonUniform<Domain1D: IntervalFinitePositiveLengthTrait> {
domain: Domain1D,
index_spaces: Grid1DIndexSpaces,
coords: Coords1D<Domain1D::RealType>,
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Grid1DNonUniform<Domain1D> {
fn create_domain_from_coords(
coords: &Coords1D<Domain1D::RealType>,
) -> 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(coords: Coords1D<Domain1D::RealType>) -> 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(num_intervals, Topology1D::RealLine);
Ok(Self {
domain,
coords,
index_spaces,
})
}
}
impl<Domain1D> Grid1DNonUniform<Domain1D>
where
Domain1D: IntervalFinitePositiveLengthTrait + SupportsCircularTopology,
{
pub fn try_new_periodic(
coords: Coords1D<Domain1D::RealType>,
) -> 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(num_intervals, Topology1D::Circle);
Ok(Self {
domain,
coords,
index_spaces,
})
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasDomain1D for Grid1DNonUniform<Domain1D> {
type Domain1D = Domain1D;
fn domain(&self) -> &Domain1D {
&self.domain
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoords1D for Grid1DNonUniform<Domain1D> {
type Point1DType = Domain1D::RealType;
fn coords(&self) -> &Coords1D<Self::Point1DType> {
&self.coords
}
}
impl<Domain1D> IntervalPartition for Grid1DNonUniform<Domain1D>
where
Domain1D: BuildIntervalInPartition,
{
type UniformlyRefinedGrid1DType = Self;
fn index_spaces(&self) -> &Grid1DIndexSpaces {
&self.index_spaces
}
fn try_find_interval_id_of_point(&self, x: &Self::Point1DType) -> Option<IntervalId> {
if !self.domain().contains_point(x) {
return None;
}
if <Self::Domain1D as BuildIntervalInPartition>::LOWER_BOUND_OWNS_BOUNDARY {
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 {
return Some(IntervalId::new(0));
}
Some(IntervalId::new(idx - 1))
}
}
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 refined_grid =
Grid1DNonUniform::try_new(refined_coords).expect("Failed to create a refined grid!");
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)
}
}
#[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::RealType>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "Domain1D: for<'d> serde::Deserialize<'d>, \
Domain1D::RealType: for<'d> serde::Deserialize<'d>"))]
pub enum Grid1D<Domain1D: IntervalFinitePositiveLengthTrait> {
Uniform(Grid1DUniform<Domain1D>),
NonUniform(Grid1DNonUniform<Domain1D>),
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> Grid1D<Domain1D> {
pub fn uniform(domain: Domain1D, num_intervals: NumIntervals) -> Self {
Grid1D::Uniform(Grid1DUniform::new(domain, num_intervals))
}
pub fn try_from_sorted(
values: SortedSet<Domain1D::RealType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
Self::try_from_coords(Coords1D::try_from(values)?)
}
pub fn try_from_coords(
coords: Coords1D<Domain1D::RealType>,
) -> Result<Self, ErrorsGrid1D<Domain1D>> {
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 {
let num_intervals = NumIntervals::try_new(n_pts - 1).unwrap();
let domain = Domain1D::try_new(
coords_slice
.first()
.expect("Coordinates should not be empty")
.clone(),
coords_slice
.last()
.expect("Coordinates should not be empty")
.clone(),
)?;
Ok(Grid1D::Uniform(Grid1DUniform::new(domain, num_intervals)))
} else {
Ok(Grid1D::NonUniform(Grid1DNonUniform::try_new(coords)?))
}
}
}
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> HasDomain1D for Grid1D<Domain1D> {
type Domain1D = Domain1D;
fn domain(&self) -> &Domain1D {
match self {
Grid1D::Uniform(pts) => pts.domain(),
Grid1D::NonUniform(pts) => pts.domain(),
}
}
}
impl<Domain1D: IntervalFinitePositiveLengthTrait> HasCoords1D for Grid1D<Domain1D> {
type Point1DType = Domain1D::RealType;
fn coords(&self) -> &Coords1D<Domain1D::RealType> {
match self {
Grid1D::Uniform(pts) => pts.coords(),
Grid1D::NonUniform(pts) => pts.coords(),
}
}
}
impl<Domain1D: BuildIntervalInPartition> IntervalPartition for Grid1D<Domain1D> {
type UniformlyRefinedGrid1DType = Self;
fn index_spaces(&self) -> &Grid1DIndexSpaces {
match self {
Grid1D::Uniform(grid) => grid.index_spaces(),
Grid1D::NonUniform(grid) => grid.index_spaces(),
}
}
fn try_find_interval_id_of_point(&self, x: &Self::Point1DType) -> Option<IntervalId> {
match self {
Grid1D::Uniform(grid) => grid.try_find_interval_id_of_point(x),
Grid1D::NonUniform(grid) => grid.try_find_interval_id_of_point(x),
}
}
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: 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::*, intervals::*, operations::union::Grid1DUnion};
use std::ops::Deref;
#[cfg(feature = "rug")]
use num_valid::vec_f64_into_vec_real;
use super::*;
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::Only(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());
assert_eq!(i0, IntervalId::new(0));
let i1 = grid1d.find_interval_id_of_point(&Real::try_new(0.5).unwrap());
assert_eq!(i1, IntervalId::new(0));
let i2 = grid1d.find_interval_id_of_point(&Real::try_new(1.0).unwrap());
assert_eq!(i2, IntervalId::new(1));
let i3 = grid1d.find_interval_id_of_point(&Real::try_new(1.5).unwrap());
assert_eq!(i3, IntervalId::new(1));
let i4 = grid1d.find_interval_id_of_point(&Real::try_new(2.0).unwrap());
assert_eq!(i4, IntervalId::new(2));
let i5 = grid1d.find_interval_id_of_point(&Real::try_new(2.5).unwrap());
assert_eq!(i5, IntervalId::new(2));
let i6 = grid1d.find_interval_id_of_point(&Real::try_new(3.0).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(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(coords).unwrap();
let grid: Grid1D<IntervalClosed<Real>> = non_uniform_grid.into();
assert!(matches!(grid, Grid1D::NonUniform(_)));
}
#[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(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()),
IntervalId::new(0)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.5).unwrap()),
IntervalId::new(1)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.5).unwrap()),
IntervalId::new(2)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
IntervalId::new(0)
);
assert_eq!(
grid.find_interval_id_of_point(&Real::try_new(2.0).unwrap()),
IntervalId::new(1)
);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "The value RealValidated(0) is not in the interval")]
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();
grid.find_interval_id_of_point(&Real::try_new(0.0).unwrap());
}
}
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(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(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.try_find_interval_id_of_point(&Real::try_new(0.0).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(10.0).unwrap()),
Some(IntervalId::new(9))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.5).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(1.5).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(9.9).unwrap()),
Some(IntervalId::new(9))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(1))
); assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(2.0).unwrap()),
Some(IntervalId::new(2))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(9.0).unwrap()),
Some(IntervalId::new(9))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(-0.1).unwrap()),
None
);
assert_eq!(
grid.try_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.try_find_interval_id_of_point(&Real::try_new(0.00005).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.0001).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.00011).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.54321).unwrap()),
Some(IntervalId::new(5432))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.99999).unwrap()),
Some(IntervalId::new(9999))
);
assert_eq!(
grid.try_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.try_find_interval_id_of_point(&Real::try_new(0.1).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(1.9).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.0).unwrap()),
None
); assert_eq!(
grid.try_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(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(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.try_find_interval_id_of_point(&Real::try_new(0.0).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(10.0).unwrap()),
Some(IntervalId::new(3))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(0.5).unwrap()),
Some(IntervalId::new(0))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(2.5).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(5.0).unwrap()),
Some(IntervalId::new(2))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(8.5).unwrap()),
Some(IntervalId::new(3))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(1.0).unwrap()),
Some(IntervalId::new(1))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(3.0).unwrap()),
Some(IntervalId::new(2))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(7.0).unwrap()),
Some(IntervalId::new(3))
);
assert_eq!(
grid.try_find_interval_id_of_point(&Real::try_new(-0.1).unwrap()),
None
);
assert_eq!(
grid.try_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()
))
);
}
}
}
#[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::Only(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());
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(),
);
assert_eq!(i1, IntervalId::new(0));
let i2 = grid1d.find_interval_id_of_point(&Real::one());
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(),
);
assert_eq!(i3, IntervalId::new(1));
let i4 = grid1d.find_interval_id_of_point(&Real::two());
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(),
);
assert_eq!(i5, IntervalId::new(2));
let i6 = grid1d.find_interval_id_of_point(
&Real::try_new(rug::Float::with_val(PRECISION, 3.)).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));
}
}
}
}