use crate::nalgebra::{convert, Point2, Point3, U1};
use crate::Real;
use nalgebra::allocator::Allocator;
use nalgebra::{DefaultAllocator, DimName, OPoint, Point1, Scalar, U2, U3};
use num::Zero;
use std::iter::FusedIterator;
use std::ops::{Add, AddAssign, Deref, Mul};
use std::slice;
pub use canonical::*;
pub use fenris_quadrature::Error as QuadratureError;
pub mod subdivide;
pub mod tensor;
pub mod total_order;
pub mod univariate;
mod canonical;
pub type QuadraturePair<T, D> = (Vec<T>, Vec<OPoint<T, D>>);
pub type QuadraturePair1d<T> = QuadraturePair<T, U1>;
pub type QuadraturePair2d<T> = QuadraturePair<T, U2>;
pub type QuadraturePair3d<T> = QuadraturePair<T, U3>;
pub type BorrowedQuadratureParts<'a, T, D, Data> = QuadratureParts<&'a [T], &'a [OPoint<T, D>], &'a [Data]>;
pub type OwnedQuadratureParts<T, D, Data> = QuadratureParts<Vec<T>, Vec<OPoint<T, D>>, Vec<Data>>;
pub trait Quadrature<T, D>
where
T: Scalar,
D: DimName,
DefaultAllocator: Allocator<T, D>,
{
type Data;
fn weights(&self) -> &[T];
fn points(&self) -> &[OPoint<T, D>];
fn data(&self) -> &[Self::Data];
fn integrate<U, Function>(&self, f: Function) -> U
where
Function: Fn(&OPoint<T, D>) -> U,
U: Zero + Mul<T, Output = U> + Add<T, Output = U> + AddAssign<U>,
{
let mut integral = U::zero();
for (w, p) in self.weights().iter().zip(self.points()) {
integral += f(p) * w.clone();
}
integral
}
fn to_parts(&self) -> BorrowedQuadratureParts<T, D, Self::Data> {
QuadratureParts {
weights: self.weights(),
points: self.points(),
data: self.data(),
}
}
fn iter(&self) -> QuadratureIter<T, D, Self::Data> {
QuadratureIter {
weights_iter: self.weights().iter(),
points_iter: self.points().iter(),
data_iter: self.data().iter(),
}
}
}
#[derive(Debug, Clone)]
pub struct QuadratureIter<'a, T, D, Data>
where
T: Scalar,
D: DimName,
DefaultAllocator: Allocator<T, D>,
{
weights_iter: slice::Iter<'a, T>,
points_iter: slice::Iter<'a, OPoint<T, D>>,
data_iter: slice::Iter<'a, Data>,
}
impl<'a, T, D, Data> Iterator for QuadratureIter<'a, T, D, Data>
where
T: Scalar,
D: DimName,
DefaultAllocator: Allocator<T, D>,
{
type Item = (&'a T, &'a OPoint<T, D>, &'a Data);
fn next(&mut self) -> Option<Self::Item> {
Some((
self.weights_iter.next()?,
self.points_iter.next()?,
self.data_iter.next()?,
))
}
}
impl<'a, T, D, Data> FusedIterator for QuadratureIter<'a, T, D, Data>
where
T: Scalar,
D: DimName,
DefaultAllocator: Allocator<T, D>,
{
}
pub trait Quadrature1d<T>: Quadrature<T, U1>
where
T: Scalar,
{
}
pub trait Quadrature2d<T>: Quadrature<T, U2>
where
T: Scalar,
{
}
pub trait Quadrature3d<T>: Quadrature<T, U3>
where
T: Scalar,
{
}
impl<T, X> Quadrature1d<T> for X
where
T: Scalar,
X: Quadrature<T, U1>,
{
}
impl<T, X> Quadrature2d<T> for X
where
T: Scalar,
X: Quadrature<T, U2>,
{
}
impl<T, X> Quadrature3d<T> for X
where
T: Scalar,
X: Quadrature<T, U3>,
{
}
impl<T, D, A, B> Quadrature<T, D> for (A, B)
where
T: Scalar,
D: DimName,
A: AsRef<[T]>,
B: AsRef<[OPoint<T, D>]>,
DefaultAllocator: Allocator<T, D>,
{
type Data = ();
fn weights(&self) -> &[T] {
self.0.as_ref()
}
fn points(&self) -> &[OPoint<T, D>] {
self.1.as_ref()
}
fn data(&self) -> &[()] {
vec![(); self.weights().len()].leak()
}
}
impl<T, D, X> Quadrature<T, D> for &X
where
T: Scalar,
D: DimName,
X: Quadrature<T, D>,
DefaultAllocator: Allocator<T, D>,
{
type Data = X::Data;
fn weights(&self) -> &[T] {
X::weights(self)
}
fn points(&self) -> &[OPoint<T, D>] {
X::points(self)
}
fn data(&self) -> &[Self::Data] {
X::data(self)
}
}
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
pub struct NoData;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub struct QuadratureParts<WeightsArray, PointsArray, DataArray> {
pub weights: WeightsArray,
pub points: PointsArray,
pub data: DataArray,
}
impl<WeightsArray, PointsArray, DataArray> QuadratureParts<WeightsArray, PointsArray, DataArray> {
pub fn with_data<DataArray2>(self, data: DataArray2) -> QuadratureParts<WeightsArray, PointsArray, DataArray2> {
QuadratureParts {
weights: self.weights,
points: self.points,
data,
}
}
}
impl<T, D, WeightsArray, PointsArray, DataArray, Data> Quadrature<T, D>
for QuadratureParts<WeightsArray, PointsArray, DataArray>
where
T: Scalar,
D: DimName,
WeightsArray: AsRef<[T]>,
PointsArray: AsRef<[OPoint<T, D>]>,
DataArray: Deref<Target = [Data]>,
DefaultAllocator: Allocator<T, D>,
{
type Data = Data;
fn weights(&self) -> &[T] {
self.weights.as_ref()
}
fn points(&self) -> &[OPoint<T, D>] {
self.points.as_ref()
}
fn data(&self) -> &[Self::Data] {
self.data.deref()
}
}
impl<T, D, WeightsArray, PointsArray> Quadrature<T, D> for QuadratureParts<WeightsArray, PointsArray, NoData>
where
T: Scalar,
D: DimName,
WeightsArray: AsRef<[T]>,
PointsArray: AsRef<[OPoint<T, D>]>,
DefaultAllocator: Allocator<T, D>,
{
type Data = ();
fn weights(&self) -> &[T] {
self.weights.as_ref()
}
fn points(&self) -> &[OPoint<T, D>] {
self.points.as_ref()
}
fn data(&self) -> &[()] {
vec![(); self.weights().len()].leak()
}
}
impl<T, D> From<QuadraturePair<T, D>> for OwnedQuadratureParts<T, D, ()>
where
T: Scalar,
D: DimName,
DefaultAllocator: Allocator<T, D>,
{
fn from((weights, points): QuadraturePair<T, D>) -> Self {
let len = weights.len();
Self {
weights,
points,
data: vec![(); len],
}
}
}
fn convert_quadrature_rule_from_1d_f64<T>(quadrature: fenris_quadrature::Rule<1>) -> QuadraturePair1d<T>
where
T: Real,
{
let (weights, points) = quadrature;
let weights = weights.into_iter().map(convert).collect();
let points = points.into_iter().map(Point1::from).map(convert).collect();
(weights, points)
}
fn convert_quadrature_rule_from_2d_f64<T>(quadrature: fenris_quadrature::Rule<2>) -> QuadraturePair2d<T>
where
T: Real,
{
let (weights, points) = quadrature;
let weights = weights.into_iter().map(convert).collect();
let points = points.into_iter().map(Point2::from).map(convert).collect();
(weights, points)
}
fn convert_quadrature_rule_from_3d_f64<T>(quadrature: fenris_quadrature::Rule<3>) -> QuadraturePair3d<T>
where
T: Real,
{
let (weights, points) = quadrature;
let weights = weights.into_iter().map(convert).collect();
let points = points.into_iter().map(Point3::from).map(convert).collect();
(weights, points)
}