reliq 0.3.6

A portable library of primitive-like constructs.
Documentation
use super::*;

::modwire::expose!(
    pub error
    pub set
    pub ty
);

type Q<const A: u8, B, C> = q::Q<A, B, q::DefaultMode, C>;

#[repr(transparent)]
#[derive(Debug)]
#[derive(Clone)]
#[derive(Copy)]
#[derive(PartialEq)]
#[derive(Eq)]
#[derive(::serde::Serialize)]
#[derive(::serde::Deserialize)]
pub struct Point<const A: u8, const B: usize, C, D = q::DefaultEngine>
where
    C: ops::Int,
    C: ops::Prim,
    D: q::Engine,
    (): q::SupportedPrecision<A>,
    (): q::SupportedInt<C>,
    (): q::Supported<A, C> {
    pub(crate) dimensions: array::Array<B, Q<A, C, D>>
}

impl<const A: u8, const B: usize, C, D> Point<A, B, C, D>
where
    C: ops::Int,
    C: ops::Prim,
    D: q::Engine,
    (): q::SupportedPrecision<A>,
    (): q::SupportedInt<C>,
    (): q::Supported<A, C> {
    pub const fn len(&self) -> usize {
        B
    }

    pub fn dimension(&self, k: usize) -> Option<&Q<A, C, D>> {
        self.dimensions.get(k).ok()
    }
}

impl<const A: u8, const B: usize, C, D> Point<A, B, C, D>
where
    C: ops::Int,
    C: ops::Prim,
    C: ops::Signed,
    D: q::Engine,
    (): q::SupportedPrecision<A>,
    (): q::SupportedInt<C>,
    (): q::Supported<A, C> {
    pub fn distance_between(self, rhs: Self) -> Result<Q<A, C, D>> {
        let mut sum: Q<A, C, D> = C::AS_0.into();
        let rhs_iter: array::Iter<_, _> = rhs.dimensions.into_iter();
        for (x_0, x_1) in self.dimensions.into_iter().zip(rhs_iter) {
            let dn: Q<A, C, D> = (x_0 - x_1)?;
            let dn: Q<A, C, D> = (dn * dn)?;
            sum = (sum + dn)?;
        }
        let ret: Q<A, C, D> = sum.sqrt()?;
        Ok(ret)
    }

    pub fn nearest<E>(self, set: E) -> Result<Option<(Q<A, C, D>, Self)>> 
    where
        E: Into<Set<A, B, C, D>> {
        let set: Set<A, B, C, D> = set.into();
        let mut best: Option<(Q<A, C, D>, Self)> = None;
        for candidate in set.points.into_iter() {
            let distance = self.distance_between(candidate)?;
            match &mut best {
                None => best = Some((distance, candidate)),
                Some((best_dist, best_point)) => {
                    if distance < *best_dist {
                        *best_dist = distance;
                        *best_point = candidate;
                    }
                }
            }
        }

        Ok(best)
    }
}

impl<const A: u8, const B: usize, C, D> Default for Point<A, B, C, D>
where
    C: ops::Int,
    C: ops::Prim,
    D: q::Engine,
    (): q::SupportedPrecision<A>,
    (): q::SupportedInt<C>,
    (): q::Supported<A, C> {
    fn default() -> Self {
        let mut dimensions: array::Array<B, Q<A, C, D>> = array::Array::default();
        for _ in 0..B {
            let zero: Q<A, C, D> = C::AS_0.into();
            dimensions.push(zero).unwrap();
        }
        Self {
            dimensions: array::Array::default()
        }
    }
}

impl<const A: u8, const B: usize, C, D, E> From<array::Array<B, E>> for Point<A, B, C, D>
where
    C: ops::Int,
    C: ops::Prim,
    D: q::Engine,
    E: Into<Q<A, C, D>>,
    E: Copy,
    (): q::SupportedPrecision<A>,
    (): q::SupportedInt<C>,
    (): q::Supported<A, C> {
    fn from(value: array::Array<B, E>) -> Self {
        let mut dimensions: array::Array<B, Q<A, C, D>> = array::Array::default();
        for item in value {
            let item: Q<A, C, D> = item.into();
            dimensions.push(item).ok();
        }
        Self {
            dimensions
        }
    }
}

impl<const A: u8, const B: usize, C, D, E> From<[E; B]> for Point<A, B, C, D>
where
    C: ops::Int,
    C: ops::Prim,
    D: q::Engine,
    E: Into<Q<A, C, D>>,
    (): q::SupportedPrecision<A>,
    (): q::SupportedInt<C>,
    (): q::Supported<A, C> {
    fn from(value: [E; B]) -> Self {
        let value: [Q<A, C, D>; B] = value.map(|item| {
            item.into()
        });
        let dimensions: array::Array<B, Q<A, C, D>> = value.into();
        Self {
            dimensions
        }
    }
}