#[cfg(test)]
use approx::assert_abs_diff_eq;
use scirs2_core::ndarray::{Array1, Array2};
#[cfg(test)]
use crate::voronoi::extrapolation::Extrapolation;
#[cfg(test)]
use crate::voronoi::gradient::{GradientEstimation, InterpolateWithGradient};
#[cfg(test)]
use crate::parallel::ParallelConfig;
#[cfg(test)]
use crate::voronoi::extrapolation::{
constant_value_extrapolation, inverse_distance_extrapolation, linear_gradient_extrapolation,
nearest_neighbor_extrapolation,
};
#[cfg(test)]
use crate::voronoi::natural::{
make_laplace_interpolator, make_sibson_interpolator, InterpolationMethod,
NaturalNeighborInterpolator,
};
#[cfg(test)]
use crate::voronoi::parallel::{
make_parallel_sibson_interpolator, ParallelNaturalNeighborInterpolator,
};
#[cfg(test)]
#[allow(dead_code)]
fn create_3d_test_data() -> (Array2<f64>, Array1<f64>) {
let points = Array2::from_shape_vec(
(8, 3),
vec![
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0,
1.0, 0.0, 1.0, 1.0,
],
)
.expect("Test failed");
let values = Array1::from_vec(vec![
0.0, 1.0, 3.0, 2.0, 3.0, 4.0, 6.0, 5.0, ]);
(points, values)
}
#[test]
#[allow(dead_code)]
fn test_natural_neighbor_exact_points() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let sibson = NaturalNeighborInterpolator::new(
points.clone(),
values.clone(),
InterpolationMethod::Sibson,
)
.expect("Test failed");
let laplace = NaturalNeighborInterpolator::new(
points.clone(),
values.clone(),
InterpolationMethod::Laplace,
)
.expect("Test failed");
for i in 0..points.nrows() {
let point = points.row(i).to_owned();
let sibson_result = sibson.interpolate(&point.view()).expect("Test failed");
let laplace_result = laplace.interpolate(&point.view()).expect("Test failed");
assert_abs_diff_eq!(sibson_result, values[i], epsilon = 1e-10);
assert_abs_diff_eq!(laplace_result, values[i], epsilon = 1e-10);
}
}
#[test]
#[allow(dead_code)]
fn test_natural_neighbor_helpers() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let sibson = make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let laplace = make_laplace_interpolator(points.clone(), values.clone()).expect("Test failed");
assert_eq!(sibson.method(), InterpolationMethod::Sibson);
assert_eq!(laplace.method(), InterpolationMethod::Laplace);
let mid_point = Array1::from_vec(vec![0.5, 0.5]);
let sibson_result = sibson.interpolate(&mid_point.view()).expect("Test failed");
let laplace_result = laplace.interpolate(&mid_point.view()).expect("Test failed");
assert_abs_diff_eq!(sibson_result, 1.5, epsilon = 1e-10);
assert_abs_diff_eq!(laplace_result, 1.5, epsilon = 1e-10);
}
#[test]
#[allow(dead_code)]
fn test_interpolate_multi() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let queries = Array2::from_shape_vec(
(3, 2),
vec![
0.25, 0.25, 0.75, 0.75, 0.5, 0.5, ],
)
.expect("Test failed");
let results = interpolator
.interpolate_multi(&queries.view())
.expect("Test failed");
assert_abs_diff_eq!(results[2], 1.5, epsilon = 1e-10);
assert!(results[0] >= 0.0 && results[0] <= 1.5);
assert!(results[1] >= 1.5 && results[1] <= 2.0);
}
#[test]
#[allow(dead_code)]
fn test_linear_function_reproduction() {
let mut points_vec = Vec::new();
let mut values_vec = Vec::new();
for i in 0..5 {
for j in 0..5 {
let x = i as f64;
let y = j as f64;
points_vec.push(x);
points_vec.push(y);
values_vec.push(2.0 * x + 3.0 * y);
}
}
let points = Array2::from_shape_vec((25, 2), points_vec).expect("Test failed");
let values = Array1::from_vec(values_vec);
let sibson = make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let laplace = make_laplace_interpolator(points.clone(), values.clone()).expect("Test failed");
let test_points = vec![(1.5, 2.3), (3.4, 1.7), (2.5, 2.5)];
for (x, y) in test_points {
let query = Array1::from_vec(vec![x, y]);
let _expected = 2.0 * x + 3.0 * y;
let sibson_result = sibson.interpolate(&query.view()).expect("Test failed");
let laplace_result = laplace.interpolate(&query.view()).expect("Test failed");
assert!(sibson_result.is_finite());
assert!(laplace_result.is_finite());
}
}
#[test]
#[allow(dead_code)]
fn test_3d_natural_neighbor_exact_points() {
let (points, values) = create_3d_test_data();
let sibson = NaturalNeighborInterpolator::new(
points.clone(),
values.clone(),
InterpolationMethod::Sibson,
)
.expect("Test failed");
let laplace = NaturalNeighborInterpolator::new(
points.clone(),
values.clone(),
InterpolationMethod::Laplace,
)
.expect("Test failed");
for i in 0..points.nrows() {
let point = points.row(i).to_owned();
let sibson_result = sibson.interpolate(&point.view()).expect("Test failed");
let laplace_result = laplace.interpolate(&point.view()).expect("Test failed");
assert_abs_diff_eq!(sibson_result, values[i], epsilon = 1e-10);
assert_abs_diff_eq!(laplace_result, values[i], epsilon = 1e-10);
}
}
#[test]
#[allow(dead_code)]
fn test_3d_linear_function_reproduction() {
let (points, values) = create_3d_test_data();
let sibson = make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let laplace = make_laplace_interpolator(points.clone(), values.clone()).expect("Test failed");
let test_points = vec![
(0.5, 0.5, 0.5), (0.25, 0.75, 0.3),
(0.8, 0.2, 0.6),
];
for (x, y, z) in test_points {
let query = Array1::from_vec(vec![x, y, z]);
let _expected = x + 2.0 * y + 3.0 * z;
let sibson_result = sibson.interpolate(&query.view()).expect("Test failed");
let laplace_result = laplace.interpolate(&query.view()).expect("Test failed");
assert!(sibson_result.is_finite());
assert!(laplace_result.is_finite());
assert!((0.0..=6.0).contains(&sibson_result));
assert!((0.0..=6.0).contains(&laplace_result));
}
}
#[test]
#[allow(dead_code)]
fn test_voronoi_diagram_access() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let diagram = interpolator.voronoi_diagram();
assert_eq!(diagram.cells.len(), 5);
assert_eq!(diagram.dim, 2);
for cell in &diagram.cells {
assert!(cell.site.len() == 2); }
}
#[test]
#[allow(dead_code)]
fn test_method_setting() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let mut interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
assert_eq!(interpolator.method(), InterpolationMethod::Sibson);
interpolator.set_method(InterpolationMethod::Laplace);
assert_eq!(interpolator.method(), InterpolationMethod::Laplace);
let query = Array1::from_vec(vec![0.25, 0.25]);
let result = interpolator
.interpolate(&query.view())
.expect("Test failed");
assert!((0.0..=2.0).contains(&result));
}
#[test]
#[allow(dead_code)]
fn test_parallel_interpolation() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let sequential = make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let config = ParallelConfig {
n_workers: Some(2),
chunk_size: Some(2),
};
let parallel = make_parallel_sibson_interpolator(points.clone(), values.clone(), Some(config))
.expect("Test failed");
let mut query_points = Vec::new();
for x in 0..5 {
for y in 0..5 {
query_points.push(x as f64 * 0.25);
query_points.push(y as f64 * 0.25);
}
}
let queries = Array2::from_shape_vec((25, 2), query_points).expect("Test failed");
let sequential_results = sequential
.interpolate_multi(&queries.view())
.expect("Test failed");
let parallel_results = parallel
.interpolate_multi(&queries.view())
.expect("Test failed");
for i in 0..queries.nrows() {
assert_abs_diff_eq!(sequential_results[i], parallel_results[i], epsilon = 1e-10);
}
}
#[test]
#[allow(dead_code)]
fn test_parallel_3d_interpolation() {
let (points, values) = create_3d_test_data();
let config = ParallelConfig {
n_workers: Some(2),
chunk_size: Some(2),
};
let parallel = make_parallel_sibson_interpolator(points.clone(), values.clone(), Some(config))
.expect("Test failed");
let mut query_points = Vec::new();
for i in 0..3 {
for j in 0..3 {
for k in 0..3 {
let x = i as f64 * 0.5;
let y = j as f64 * 0.5;
let z = k as f64 * 0.5;
query_points.push(x);
query_points.push(y);
query_points.push(z);
}
}
}
let queries = Array2::from_shape_vec((27, 3), query_points).expect("Test failed");
let results = parallel
.interpolate_multi(&queries.view())
.expect("Test failed");
for i in 0..queries.nrows() {
let _x = queries[[i, 0]];
let _y = queries[[i, 1]];
let _z = queries[[i, 2]];
assert!(results[i] >= -100.0 && results[i] <= 100.0);
}
}
#[test]
#[allow(dead_code)]
fn test_parallel_config() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0, 1.5]);
let mut parallel = ParallelNaturalNeighborInterpolator::new(
points.clone(),
values.clone(),
InterpolationMethod::Sibson,
None,
)
.expect("Test failed");
let new_config = ParallelConfig {
n_workers: Some(4),
chunk_size: Some(5),
};
parallel.set_parallel_config(new_config);
let query = Array1::from_vec(vec![0.25, 0.25]);
let result = parallel.interpolate(&query.view()).expect("Test failed");
assert!((0.0..=2.0).contains(&result));
}
#[test]
#[allow(dead_code)]
fn test_gradient_linear_function() {
let mut points_vec = Vec::new();
let mut values_vec = Vec::new();
for i in 0..5 {
for j in 0..5 {
let x = i as f64;
let y = j as f64;
points_vec.push(x);
points_vec.push(y);
values_vec.push(2.0 * x + 3.0 * y);
}
}
let points = Array2::from_shape_vec((25, 2), points_vec).expect("Test failed");
let values = Array1::from_vec(values_vec);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let test_points = vec![(1.5, 2.3), (3.4, 1.7), (2.5, 2.5)];
for (x, y) in test_points {
let query = Array1::from_vec(vec![x, y]);
let gradient = interpolator.gradient(&query.view()).expect("Test failed");
assert!(gradient[0].is_finite());
assert!(gradient[1].is_finite());
}
}
#[test]
#[allow(dead_code)]
fn test_gradient_quadratic_function() {
let mut points_vec = Vec::new();
let mut values_vec = Vec::new();
for i in 0..5 {
for j in 0..5 {
let x = i as f64;
let y = j as f64;
points_vec.push(x);
points_vec.push(y);
values_vec.push(x.powi(2) + y.powi(2));
}
}
let points = Array2::from_shape_vec((25, 2), points_vec).expect("Test failed");
let values = Array1::from_vec(values_vec);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let test_points = vec![(1.0, 2.0), (2.0, 1.0), (2.0, 2.0)];
for (x, y) in test_points {
let query = Array1::from_vec(vec![x, y]);
let gradient = interpolator.gradient(&query.view()).expect("Test failed");
assert!(gradient[0].is_finite());
assert!(gradient[1].is_finite());
}
}
#[test]
#[allow(dead_code)]
fn test_interpolate_with_gradient() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 2.0, 3.0, 5.0, 2.5]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let query = Array1::from_vec(vec![0.25, 0.25]);
let result = interpolator
.interpolate_with_gradient(&query.view())
.expect("Test failed");
assert!(!f64::is_nan(result.value));
assert!(result.gradient.len() == 2);
}
#[test]
#[allow(dead_code)]
fn test_3d_gradient() {
let (points, values) = create_3d_test_data();
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let test_points = vec![(0.5, 0.5, 0.5), (0.25, 0.75, 0.3)];
for (x, y, z) in test_points {
let query = Array1::from_vec(vec![x, y, z]);
let gradient = interpolator.gradient(&query.view()).expect("Test failed");
assert!(gradient[0] >= -100.0 && gradient[0] <= 100.0);
assert!(gradient[1] >= -100.0 && gradient[1] <= 100.0);
assert!(gradient[2] >= -100.0 && gradient[2] <= 100.0);
}
}
#[test]
#[allow(dead_code)]
fn test_extrapolation_nearest_neighbor() {
let points = Array2::from_shape_vec((4, 2), vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0])
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let test_points = vec![(2.0, 2.0), (-1.0, 0.5)];
let params = nearest_neighbor_extrapolation();
for (x, y) in test_points {
let query = Array1::from_vec(vec![x, y]);
let result = interpolator
.extrapolate(&query.view(), ¶ms)
.expect("Test failed");
assert!(values.iter().any(|&v| f64::abs(v - result) < 1e-10));
}
}
#[test]
#[allow(dead_code)]
fn test_extrapolation_inverse_distance() {
let points = Array2::from_shape_vec((4, 2), vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0])
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let params = inverse_distance_extrapolation(4, 2.0);
let query = Array1::from_vec(vec![2.0, 0.5]);
let result = interpolator
.extrapolate(&query.view(), ¶ms)
.expect("Test failed");
assert!((0.0..=2.0).contains(&result));
assert!(result > 0.5);
}
#[test]
#[allow(dead_code)]
fn test_extrapolation_linear_gradient() {
let points = Array2::from_shape_vec(
(5, 2),
vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.5, 0.5],
)
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 2.0, 3.0, 5.0, 2.5]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let params = linear_gradient_extrapolation();
let query = Array1::from_vec(vec![2.0, 2.0]);
let result = interpolator
.extrapolate(&query.view(), ¶ms)
.expect("Test failed");
assert!((-100.0..=100.0).contains(&result));
}
#[test]
#[allow(dead_code)]
fn test_extrapolation_constant_value() {
let points = Array2::from_shape_vec((4, 2), vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0])
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let constant_value = 42.0;
let params = constant_value_extrapolation(constant_value);
let test_points = vec![(2.0, 2.0), (-1.0, 0.5), (10.0, -10.0)];
for (x, y) in test_points {
let query = Array1::from_vec(vec![x, y]);
let result = interpolator
.extrapolate(&query.view(), ¶ms)
.expect("Test failed");
assert_abs_diff_eq!(result, constant_value, epsilon = 1e-10);
}
}
#[test]
#[allow(dead_code)]
fn test_interpolate_or_extrapolate() {
let points = Array2::from_shape_vec((4, 2), vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0])
.expect("Test failed");
let values = Array1::from_vec(vec![0.0, 1.0, 1.0, 2.0]);
let interpolator =
make_sibson_interpolator(points.clone(), values.clone()).expect("Test failed");
let params = nearest_neighbor_extrapolation();
let test_points = vec![
(0.5, 0.5), (2.0, 2.0), ];
for (x, y) in test_points {
let query = Array1::from_vec(vec![x, y]);
let result = interpolator
.interpolate_or_extrapolate(&query.view(), ¶ms)
.expect("Test failed");
assert!((-100.0..=100.0).contains(&result));
}
}