Skip to content

Traits in statistics::traits should not require return type be Option #295

@YeungOnion

Description

@YeungOnion

Many distributions will have some summary statistics regardless of their parameters so Option<T> should not be required, e.g. it is not semantically accurate to require unwrapping the mean of a binomial. Regardless of the sample probability, a valid Binomial type will always have some mean, but student's distribution require at least one dof, cauchy has too much tail and has no mean is never valid.

proposed solution

In lieu of generics, we can use associated types for the statistics::traits::Distribution trait1. I don't believe this would bound us in terms of generic numerics in the future either, as long as the associated type could support the generic as well, i.e.

impl<T: Float> Distribution for DistributionType {
    type Mu = T;   // or Vector<T, Dimension, ...>
    type Var = T;  // or TensorCube<T, Const<2>, Dimension, ...>
    type Skew = T; // or TensorCube<T, Const<3>, Dimension, ...>
    type Kurt = T; // or TensorCube<T, Const<4>, Dimension, ...>
}
  • collapse MeanN and VarianceN into statistics::traits::Distribution and add Covariance and Entropy traits
    • Add MultivariateNormalDiag distribution. #208 proposed a way to specify Covariance
    • rely on unimplemented!() over None when more correct. Defaulting to None when we don't have a simple expression isn't correct (may also be a little more motivating for someone to implement it over panicking).
    • would have to implement Covariance on matrices, Cholesky decompositions, vectors, and likely floats.
  • types for skewness and kurtosis will be higher order tensors than nalgebra can accomodate. so the signature could have return type of never ! before being plain ol' unimplemented!() before being implemented.

Sample code of the traits I propose adding.

pub trait Moments<T: Float> {
    type Mu;
    type Var: Covariance<T>;
    type Kurt;
    type Skew;
    fn mean(&self) -> Self::Mu;
    fn variance(&self) -> Self::Var;
    fn std_dev(&self) -> <Self::Var as Covariance<T>>::V;
    fn excess_kurtosis(&self) -> Self::Kurt;
    fn skewness(&self) -> Self::Skew;
}

pub trait Covariance<T: Float> {
    type M;
    type V;
    fn dense(&self) -> Self::M;
    fn sparse(&self) -> Self::V;
    fn forward(&self, other: Self::V) -> Self::V;
    fn inverse(&self, other: Self::V) -> Self::V;
    fn determinant(&self) -> T;
}

pub trait Entropy<T: Float> {
    fn entropy(&self) -> T;
}

Footnotes

  1. I also think renaming it could be helpful, unsure what is better, but since most of them are moments, or central moments, we could make entropy it's own, as entropy is always scalar and have a Moments trait. I think much of this is motivated from reference implementations in Math.NET's interfaces since that's how this project started.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions