Plan for dimension types

Aberta
#519 7 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
5/5
Tempo estimado
Mais de uma semana
Facilidade para iniciantes
20/100
Tipo de issue
Refatoração
Clareza
Precisa de esclarecimento
Status de atividade
Estagnada
Stack de tecnologia
rust
Domínio
data

Direção de pesquisa

Start by reading the existing Dimension and ArrayBase implementations, then compare how Ix2 and IxDyn currently represent shapes and strides. The proposal requires agreement on the associated-type design, conversion traits, and type-level operations before implementation; completion would include resolving the related dimension issues and validating the affected API.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

I've been thinking about the dimension types for a while. Two things I don't like about the current implementation are that:

  1. Strides are represented as usize and have to be converted to isize every time they're used. This is error-prone and confusing.
  2. It seems a little weird that the dimension type itself (instead of an associated type) has a representation. For example, "2-D" doesn't necessary imply a specific representation to me.

What I'd like to do is something like the following:

pub trait Dimension
where
    for<'a> Into<Self::OwnedUsize> for &'a Self::BorrowedUsize,
    for<'a> Into<Self::OwnedIsize> for &'a Self::BorrowedIsize,
{
    type OwnedUsize: AsRef<Self::BorrowedUsize> + AsMut<Self::BorrowedUsize> + AsRef<[usize]> + AsMut<[usize]>;
    type BorrowedUsize: ?Sized + AsRef<[usize]> + AsMut<[usize]>;
    type OwnedIsize: AsRef<Self::BorrowedIsize> + AsMut<Self::BorrowedIsize> + AsRef<[isize]> + AsMut<[isize]>;
    type BorrowedIsize: ?Sized + AsRef<[isize]> + AsMut<[isize]>;
}

pub struct Ix2;
pub struct IxDyn;

impl Dimension for Ix2 {
    type OwnedUsize = [usize; 2];
    type BorrowedUsize = [usize; 2];
    type OwnedIsize = [isize; 2];
    type BorrowedIsize = [isize; 2];
}

impl Dimension for IxDyn {
    type OwnedUsize = IxDynImpl<usize>;
    type BorrowedUsize = [usize];
    type OwnedIsize = IxDynImpl<isize>;
    type BorrowedIsize = [isize];
}

pub trait IntoDimOwnedUsize {
    type Dim: Dimension;
    fn into_dim_owned_usize(self) -> Self::Dim::OwnedUsize;
}

pub trait AsDimBorrowedUsize {
    type Dim: Dimension;
    fn as_dim_borrowed_usize(&self) -> &Self::Dim::BorrowedUsize;
}

pub trait IntoDimOwnedIsize { ... }

pub trait AsDimBorrowedIsize { ... }

pub struct ArrayBase<S, D>
where
    S: Data,
{
    data: S,
    ptr: *mut S::Elem,
    dim: D::OwnedUsize,
    strides: D::OwnedIsize,
}

impl<A, S, D> ArrayBase<S, D>
where
    S: Data<Elem = A>,
    D: Dimension,
{
    pub fn shape(&self) -> &D::BorrowedUsize {
        // ...
    }

    pub fn strides(&self) -> &D::BorrowedIsize {
        // ...
    }
}

Once Rust has generic associated types, we can simplify this to:

pub trait Dimension
where
    for<'a, T: Clone> Into<Self::Owned<T>> for &'a Self::Borrowed,
{
    type Owned<T>: AsRef<Self::Borrowed<T>> + AsMut<Self::Borrowed<T>> + AsRef<[T]> + AsMut<[T]>;
    type Borrowed<T>>: ?Sized + AsRef<[T]> + AsMut<[T]>;
}

pub struct Ix2;
pub struct IxDyn;

impl Dimension for Ix2 {
    type Owned<T> = [T; 2];
    type Borrowed<T> = [T; 2];
}

impl Dimension for IxDyn {
    type Owned<T> = IxDynImpl<T>;
    type Borrowed<T> = [T];
}

pub trait IntoDimOwned<T> {
    type Dim: Dimension;
    fn into_dim_owned(self) -> Self::Dim::Owned<T>;
}

pub trait AsDimBorrowed<T> {
    type Dim: Dimension;
    fn as_dim_borrowed(&self) -> &Self::Dim::Borrowed<T>;
}

pub struct ArrayBase<S, D>
where
    S: Data,
{
    data: S,
    ptr: *mut S::Elem,
    dim: D::Owned<usize>,
    strides: D::Owned<isize>,
}

impl<A, S, D> ArrayBase<S, D>
where
    S: Data<Elem = A>,
    D: Dimension,
{
    pub fn shape(&self) -> &D::Borrowed<usize> {
        // ...
    }

    pub fn strides(&self) -> &D::Borrowed<isize> {
        // ...
    }
}

I'd also add various type-level arithmetic operations on the dimension types, which are necessary for things like co-broadcasting (trait PartialOrdDim) and fold_axes (trait SubDim).

We can also add Shape<T>, Strides<T>, and Index<T> thin wrapper types.

This approach would resolve things like #489 and this comment on #367.

Thoughts?

Linguagem predominante
Rust
Estrelas
4.3k
Forks
391
Métricas de merge de PRs
Nenhum PR com merge em 30d

Guia de contribuição

Nenhum guia de contribuição indexado para este repositório

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de rust-ndarray/ndarray

Todas as issues de rust-ndarray/ndarray

Issues semelhantes

Mais issues de Rust

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.