use crate::operator::element::Element;
pub trait LinearSpace: Sized {
type F;
type Impl;
fn zero(&self) -> Element<'_, Self>;
fn add(&self, x: &Element<Self>, y: &Element<Self>) -> Element<'_, Self>;
fn sub(&self, x: &Element<Self>, y: &Element<Self>) -> Element<'_, Self>;
fn scalar_mul(&self, scalar: &Self::F, x: &Element<Self>) -> Element<'_, Self>;
fn neg(&self, x: &Element<Self>) -> Element<'_, Self>;
fn sum_inplace(&self, x: &mut Element<Self>, y: &Element<Self>);
fn sub_inplace(&self, x: &mut Element<Self>, y: &Element<Self>);
fn scale_inplace(&self, scalar: &Self::F, x: &mut Element<Self>);
fn copy_from(&self, x: &Element<Self>) -> Element<'_, Self>;
fn axpy_inplace(&self, alpha: &Self::F, x: &Element<Self>, y: &mut Element<Self>) {
self.sum_inplace(y, &self.scalar_mul(alpha, x));
}
}
pub trait DualSpace: LinearSpace {
type DualSpace: LinearSpace<F = Self::F>;
fn dual_pairing(&self, x: &Element<Self>, y: &Element<Self::DualSpace>) -> Self::F;
}
pub trait IndexableSpace: LinearSpace {
fn dimension(&self) -> usize;
}
pub trait InnerProductSpace: LinearSpace {
fn inner_product(&self, x: &Element<Self>, y: &Element<Self>) -> Self::F;
}
pub trait NormedSpace: LinearSpace {
type Output;
fn norm(&self, x: &Element<Self>) -> Self::Output;
}
pub trait FrameImpl<'a> {
type Space: LinearSpace + 'a;
fn space(&self) -> &'a Self::Space;
fn element(&self, index: usize) -> Option<Element<'a, Self::Space>>;
fn set_element(&mut self, index: usize, elem: &Element<Self::Space>) -> crate::RlstResult<()>;
fn len(&self) -> usize;
fn capacity(&self) -> usize;
fn reserve(&mut self, additional: usize);
fn is_empty(&self) -> bool {
self.len() == 0
}
fn push(&mut self, elem: &Element<Self::Space>) -> crate::RlstResult<()>;
fn pop(&mut self) -> Option<Element<'a, Self::Space>>;
fn clear(&mut self);
}
pub trait FrameRefAccess<'a>: FrameImpl<'a> {
fn element_ref(&self, index: usize) -> Option<&Element<'a, Self::Space>>;
fn element_mut<'s>(&'s mut self, index: usize) -> Option<&'s mut Element<'a, Self::Space>>;
fn iter<'s>(&'s self) -> impl ExactSizeIterator<Item = &'s Element<'a, Self::Space>>
where
'a: 's;
fn iter_mut<'s>(
&'s mut self,
) -> impl ExactSizeIterator<Item = &'s mut Element<'a, Self::Space>>
where
'a: 's;
}
pub(crate) fn combine_columns<'a, S, A, C>(
space: &'a S,
len: usize,
coefficients: &crate::Array<A, 1>,
columns: impl IntoIterator<Item = C>,
) -> crate::RlstResult<Element<'a, S>>
where
S: LinearSpace,
A: crate::Shape<1> + crate::UnsafeRandom1DAccessByValue<Item = S::F>,
C: std::borrow::Borrow<Element<'a, S>>,
{
if coefficients.shape()[0] != len {
return Err(crate::RlstError::SingleDimensionError {
expected: len,
actual: coefficients.shape()[0],
});
}
let mut result = space.zero();
for (coefficient, column) in coefficients.iter_value().zip(columns) {
space.axpy_inplace(&coefficient, column.borrow(), &mut result);
}
Ok(result)
}
pub trait FrameApply<'a>: FrameImpl<'a> {
fn apply<A>(
&self,
coefficients: &crate::Array<A, 1>,
) -> crate::RlstResult<Element<'a, Self::Space>>
where
A: crate::Shape<1>
+ crate::UnsafeRandom1DAccessByValue<Item = <Self::Space as LinearSpace>::F>,
{
combine_columns(
self.space(),
self.len(),
coefficients,
(0..self.len()).map(|index| self.element(index).unwrap()),
)
}
fn adjoint_apply(
&self,
x: &Element<Self::Space>,
) -> crate::RlstResult<Vec<<Self::Space as LinearSpace>::F>>
where
Self::Space: InnerProductSpace,
{
let space = self.space();
Ok((0..self.len())
.map(|index| space.inner_product(x, &self.element(index).unwrap()))
.collect())
}
fn apply_into<A>(
&self,
alpha: <Self::Space as LinearSpace>::F,
coefficients: &crate::Array<A, 1>,
beta: <Self::Space as LinearSpace>::F,
output: &mut Element<Self::Space>,
) -> crate::RlstResult<()>
where
A: crate::Shape<1>
+ crate::UnsafeRandom1DAccessByValue<Item = <Self::Space as LinearSpace>::F>,
<Self::Space as LinearSpace>::F: num::Zero + num::One + PartialEq + Copy,
{
accumulate_columns(
self.space(),
self.len(),
alpha,
coefficients,
beta,
output,
(0..self.len()).map(|index| self.element(index).unwrap()),
)
}
}
pub(crate) fn accumulate_columns<'a, S, A, C>(
space: &S,
len: usize,
alpha: S::F,
coefficients: &crate::Array<A, 1>,
beta: S::F,
output: &mut Element<S>,
columns: impl IntoIterator<Item = C>,
) -> crate::RlstResult<()>
where
S: LinearSpace + 'a,
S::F: num::Zero + num::One + PartialEq + Copy,
A: crate::Shape<1> + crate::UnsafeRandom1DAccessByValue<Item = S::F>,
C: std::borrow::Borrow<Element<'a, S>>,
{
if coefficients.shape()[0] != len {
return Err(crate::RlstError::SingleDimensionError {
expected: len,
actual: coefficients.shape()[0],
});
}
if num::Zero::is_zero(&beta) {
*output.imp_mut() = space.zero().into_imp();
} else if !num::One::is_one(&beta) {
space.scale_inplace(&beta, output);
}
for (coefficient, column) in coefficients.iter_value().zip(columns) {
space.axpy_inplace(&(alpha * coefficient), column.borrow(), output);
}
Ok(())
}