use scirs2_core::ndarray::{Array1, Array2, ArrayView1, ArrayView2};
use scirs2_core::numeric::{Float, FromPrimitive};
use scirs2_core::parallel_ops::*;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use super::gradient::Interpolator; use super::natural::{InterpolationMethod, NaturalNeighborInterpolator};
use super::voronoi_cell::VoronoiDiagram;
use crate::error::InterpolateResult;
use crate::parallel::ParallelConfig;
#[derive(Debug, Clone)]
pub struct ParallelNaturalNeighborInterpolator<
F: Float
+ FromPrimitive
+ Debug
+ Send
+ Sync
+ scirs2_core::ndarray::ScalarOperand
+ 'static
+ std::cmp::PartialOrd
+ ordered_float::FloatCore,
> {
interpolator: NaturalNeighborInterpolator<F>,
parallel_config: ParallelConfig,
}
impl<
F: Float
+ FromPrimitive
+ Debug
+ Send
+ Sync
+ scirs2_core::ndarray::ScalarOperand
+ 'static
+ std::cmp::PartialOrd
+ ordered_float::FloatCore,
> ParallelNaturalNeighborInterpolator<F>
{
pub fn new(
points: Array2<F>,
values: Array1<F>,
method: InterpolationMethod,
config: Option<ParallelConfig>,
) -> InterpolateResult<Self> {
let interpolator = NaturalNeighborInterpolator::new(points, values, method)?;
let parallel_config = config.unwrap_or_default();
Ok(ParallelNaturalNeighborInterpolator {
interpolator,
parallel_config,
})
}
pub fn interpolate(&self, query: &ArrayView1<F>) -> InterpolateResult<F> {
self.interpolator.interpolate(query)
}
pub fn interpolate_multi(&self, queries: &ArrayView2<F>) -> InterpolateResult<Array1<F>> {
let n_queries = queries.nrows();
let _dim = queries.ncols();
let chunk_size = self.parallel_config.get_chunk_size(n_queries);
if n_queries <= chunk_size {
return self.interpolator.interpolate_multi(queries);
}
let results = Arc::new(Mutex::new(Array1::zeros(n_queries)));
(0..n_queries)
.into_par_iter()
.chunks(chunk_size)
.try_for_each(|chunk| -> InterpolateResult<()> {
for i in chunk {
let query = queries.row(i);
match self.interpolator.interpolate(&query) {
Ok(value) => {
let mut results = results.lock().expect("Operation failed");
results[i] = value;
}
Err(err) => return Err(err),
}
}
Ok(())
})?;
Ok(Arc::try_unwrap(results)
.expect("Operation failed")
.into_inner()
.expect("Operation failed"))
}
pub fn method(&self) -> InterpolationMethod {
self.interpolator.method()
}
pub fn set_method(&mut self, method: InterpolationMethod) {
self.interpolator.set_method(method);
}
pub fn set_parallel_config(&mut self, config: ParallelConfig) {
self.parallel_config = config;
}
pub fn voronoi_diagram(&self) -> &VoronoiDiagram<F> {
self.interpolator.voronoi_diagram()
}
}
#[allow(dead_code)]
pub fn make_parallel_natural_neighbor_interpolator<
F: Float
+ FromPrimitive
+ Debug
+ Send
+ Sync
+ scirs2_core::ndarray::ScalarOperand
+ 'static
+ std::cmp::Ord
+ ordered_float::FloatCore,
>(
points: Array2<F>,
values: Array1<F>,
method: InterpolationMethod,
config: Option<ParallelConfig>,
) -> InterpolateResult<ParallelNaturalNeighborInterpolator<F>> {
ParallelNaturalNeighborInterpolator::new(points, values, method, config)
}
#[allow(dead_code)]
pub fn make_parallel_sibson_interpolator<
F: Float
+ FromPrimitive
+ Debug
+ Send
+ Sync
+ scirs2_core::ndarray::ScalarOperand
+ 'static
+ std::cmp::PartialOrd
+ ordered_float::FloatCore,
>(
points: Array2<F>,
values: Array1<F>,
config: Option<ParallelConfig>,
) -> InterpolateResult<ParallelNaturalNeighborInterpolator<F>> {
ParallelNaturalNeighborInterpolator::new(points, values, InterpolationMethod::Sibson, config)
}
#[allow(dead_code)]
pub fn make_parallel_laplace_interpolator<
F: Float
+ FromPrimitive
+ Debug
+ Send
+ Sync
+ scirs2_core::ndarray::ScalarOperand
+ 'static
+ std::cmp::PartialOrd
+ ordered_float::FloatCore,
>(
points: Array2<F>,
values: Array1<F>,
config: Option<ParallelConfig>,
) -> InterpolateResult<ParallelNaturalNeighborInterpolator<F>> {
ParallelNaturalNeighborInterpolator::new(points, values, InterpolationMethod::Laplace, config)
}