Skip to content

Commit

Permalink
Merge pull request #17 from rust-cv/maintainance
Browse files Browse the repository at this point in the history
Maintainance
  • Loading branch information
vadixidav authored Aug 29, 2024
2 parents cd4a5c0 + 31b0ae5 commit 6b02eef
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 226 deletions.
13 changes: 8 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ license = "MIT"
readme = "README.md"

[features]
default = ["nalgebra", "nalgebra_std", "ndarray", "image"]
nalgebra_std = ["nalgebra/std"]
default = ["alloc", "nalgebra", "ndarray", "image"]
alloc = ["nalgebra?/alloc"]
nalgebra = ["dep:nalgebra"]
ndarray = ["dep:ndarray", "alloc"]
image = ["dep:image", "alloc"]

[dependencies]
ndarray = { version = "0.15.4", default-features = false, optional = true }
nalgebra = { version = "0.30.1", default-features = false, optional = true }
image = { version = "0.24.0", default-features = false, optional = true }
ndarray = { version = "0.16", default-features = false, optional = true }
nalgebra = { version = "0.33", default-features = false, optional = true }
image = { version = "0.25", default-features = false, optional = true }

[package.metadata.docs.rs]
all-features = true
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,16 @@

Provides traits that allow conversion between n-dimensional types in different Rust crates

**NOTE**: By default, this crate includes no conversions. You must choose which crates you want to use using the features:
**NOTE**: By default, this crate includes conversions for all supported crates. If you want to limit compilation, use `no-default-features = true` enable the corresponding feature for each dependency:

* `ndarray`
* `nalgebra`
* `ndarray`
* `image`

When crates are included, any available conversions between the enabled crates are turned on.
When two crate features are enabled, any available conversions between the two crates are turned on.

## Limitations

Right now this crate really only provides conversions to owned and borrowed ndarray types. Some limitations exist with `nalgebra`, as it only utilizes positive strides, while `ndarray` supports negative strides as well. The `image` crate has no concept of strides. Due to this, the `ndarray` crate is the most flexible, and is ideal for interoperability between these various crates.

## Supported Crates
* `image`
* `ndarray`
* `nalgebra`
`nalgebra` currently does not offer a solution to directly pass it an owned vector from `ndarray`, so `into` conversions do perform a copy. It is recommended to create the owned copy in `nalgebra` and then borrow a mutable array view of it using ndarray. You can then populate it accordingly without any copies of the data.
2 changes: 1 addition & 1 deletion src/toimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
///
/// This uses an associated type to avoid ambiguity for the compiler.
/// By calling this, the compiler always knows the returned type.
pub trait ToImageLuma {
pub trait IntoImageLuma {
type Out;

fn into_image_luma(self) -> Self::Out;
Expand Down
4 changes: 2 additions & 2 deletions src/tonalgebra.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#[cfg(all(feature = "ndarray", feature = "nalgebra_std"))]
#[cfg(feature = "ndarray")]
mod ndarray_impl;

/// Converts a 1 or 2 dimensional type to a nalgebra type.
///
/// This uses an associated type to avoid ambiguity for the compiler.
/// By calling this, the compiler always knows the returned type.
pub trait ToNalgebra {
pub trait IntoNalgebra {
type Out;

fn into_nalgebra(self) -> Self::Out;
Expand Down
120 changes: 58 additions & 62 deletions src/tonalgebra/ndarray_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,189 +3,185 @@
use super::*;

use core::convert::TryFrom;
use nalgebra::Dynamic as Dy;
use nalgebra::Dyn;

/// ```
/// use nshare::ToNalgebra;
/// use nshare::IntoNalgebra;
///
/// let arr = ndarray::arr1(&[0.1, 0.2, 0.3, 0.4]);
/// let arr = ndarray::array![0.1, 0.2, 0.3, 0.4];
/// let m = arr.view().into_nalgebra();
/// assert!(m.iter().eq(&[0.1, 0.2, 0.3, 0.4]));
/// assert_eq!(m.shape(), (4, 1));
/// ```
impl<'a, T> ToNalgebra for ndarray::ArrayView1<'a, T>
impl<'a, T> IntoNalgebra for ndarray::ArrayView1<'a, T>
where
T: nalgebra::Scalar,
{
type Out = nalgebra::DVectorSlice<'a, T>;
type Out = nalgebra::DVectorView<'a, T>;
fn into_nalgebra(self) -> Self::Out {
let len = Dy::new(self.len());
let len = Dyn(self.len());
let ptr = self.as_ptr();
let stride: usize = TryFrom::try_from(self.strides()[0]).expect("Negative stride");
let storage = unsafe {
nalgebra::SliceStorage::from_raw_parts(
nalgebra::ViewStorage::from_raw_parts(
ptr,
(len, nalgebra::Const::<1>),
(nalgebra::Const::<1>, Dy::new(stride)),
(nalgebra::Const::<1>, Dyn(stride)),
)
};
nalgebra::Matrix::from_data(storage)
}
}
/// ```
/// use nshare::ToNalgebra;
/// use nshare::IntoNalgebra;
///
/// let mut arr = ndarray::arr1(&[0.1, 0.2, 0.3, 0.4]);
/// let mut arr = ndarray::array![0.1, 0.2, 0.3, 0.4];
/// let m = arr.view_mut().into_nalgebra();
/// assert!(m.iter().eq(&[0.1, 0.2, 0.3, 0.4]));
/// assert_eq!(m.shape(), (4, 1));
/// ```
impl<'a, T> ToNalgebra for ndarray::ArrayViewMut1<'a, T>
impl<'a, T> IntoNalgebra for ndarray::ArrayViewMut1<'a, T>
where
T: nalgebra::Scalar,
{
type Out = nalgebra::DVectorSliceMut<'a, T>;
type Out = nalgebra::DVectorViewMut<'a, T>;
fn into_nalgebra(mut self) -> Self::Out {
let len = Dy::new(self.len());
let len = Dyn(self.len());
let stride: usize = TryFrom::try_from(self.strides()[0]).expect("Negative stride");
let ptr = self.as_mut_ptr();
let storage = unsafe {
// Drop to not have simultaneously the ndarray and nalgebra valid.
drop(self);
nalgebra::SliceStorageMut::from_raw_parts(
nalgebra::ViewStorageMut::from_raw_parts(
ptr,
(len, nalgebra::Const::<1>),
(nalgebra::Const::<1>, Dy::new(stride)),
(nalgebra::Const::<1>, Dyn(stride)),
)
};
nalgebra::Matrix::from_data(storage)
}
}

/// ```
/// use nshare::ToNalgebra;
/// use nshare::IntoNalgebra;
///
/// let arr = ndarray::arr1(&[0.1, 0.2, 0.3, 0.4]);
/// let arr = ndarray::array![0.1, 0.2, 0.3, 0.4];
/// let m = arr.into_nalgebra();
/// assert!(m.iter().eq(&[0.1, 0.2, 0.3, 0.4]));
/// assert_eq!(m.shape(), (4, 1));
/// ```
impl<T> ToNalgebra for ndarray::Array1<T>
impl<T> IntoNalgebra for ndarray::Array1<T>
where
T: nalgebra::Scalar,
{
type Out = nalgebra::DVector<T>;
fn into_nalgebra(self) -> Self::Out {
let len = Dy::new(self.len());
Self::Out::from_vec_generic(len, nalgebra::Const::<1>, self.into_raw_vec())
let len = Dyn(self.len());
// There is no method to give nalgebra the vector directly where it isn't allocated. If you call
// from_vec_generic, it simply calls from_iterator_generic which uses Iterator::collect(). Due to this,
// the simplest solution is to just pass an iterator over the values. If you come across this because you
// have a performance issue, I would recommend creating the owned data using naglebra and borrowing it with
// ndarray to perform operations on it instead of the other way around.
Self::Out::from_iterator_generic(len, nalgebra::Const::<1>, self.iter().cloned())
}
}

/// ```
/// use nshare::ToNalgebra;
/// use nshare::IntoNalgebra;
///
/// let arr = ndarray::arr2(&[
/// let arr = ndarray::array![
/// [0.1, 0.2, 0.3, 0.4],
/// [0.5, 0.6, 0.7, 0.8],
/// [1.1, 1.2, 1.3, 1.4],
/// [1.5, 1.6, 1.7, 1.8],
/// ]);
/// ];
/// let m = arr.view().into_nalgebra();
/// assert!(m.row(1).iter().eq(&[0.5, 0.6, 0.7, 0.8]));
/// assert_eq!(m.shape(), (4, 4));
/// assert!(arr.t().into_nalgebra().column(1).iter().eq(&[0.5, 0.6, 0.7, 0.8]));
/// ```
impl<'a, T> ToNalgebra for ndarray::ArrayView2<'a, T>
impl<'a, T> IntoNalgebra for ndarray::ArrayView2<'a, T>
where
T: nalgebra::Scalar,
{
type Out = nalgebra::DMatrixSlice<'a, T, Dy, Dy>;
type Out = nalgebra::DMatrixView<'a, T, Dyn, Dyn>;
fn into_nalgebra(self) -> Self::Out {
let nrows = Dy::new(self.nrows());
let ncols = Dy::new(self.ncols());
let nrows = Dyn(self.nrows());
let ncols = Dyn(self.ncols());
let ptr = self.as_ptr();
let stride_row: usize = TryFrom::try_from(self.strides()[0]).expect("Negative row stride");
let stride_col: usize =
TryFrom::try_from(self.strides()[1]).expect("Negative column stride");
let stride_row: usize = TryFrom::try_from(self.strides()[0])
.expect("can only convert positive row stride to nalgebra");
let stride_col: usize = TryFrom::try_from(self.strides()[1])
.expect("can only convert positive col stride to nalgebra");
let storage = unsafe {
nalgebra::SliceStorage::from_raw_parts(
nalgebra::ViewStorage::from_raw_parts(
ptr,
(nrows, ncols),
(Dy::new(stride_row), Dy::new(stride_col)),
(Dyn(stride_row), Dyn(stride_col)),
)
};
nalgebra::Matrix::from_data(storage)
}
}

/// ```
/// use nshare::ToNalgebra;
/// use nshare::IntoNalgebra;
///
/// let mut arr = ndarray::arr2(&[
/// let mut arr = ndarray::array![
/// [0.1, 0.2, 0.3, 0.4],
/// [0.5, 0.6, 0.7, 0.8],
/// [1.1, 1.2, 1.3, 1.4],
/// [1.5, 1.6, 1.7, 1.8],
/// ]);
/// ];
/// let m = arr.view_mut().into_nalgebra();
/// assert!(m.row(1).iter().eq(&[0.5, 0.6, 0.7, 0.8]));
/// assert_eq!(m.shape(), (4, 4));
/// assert!(arr.view_mut().reversed_axes().into_nalgebra().column(1).iter().eq(&[0.5, 0.6, 0.7, 0.8]));
/// ```
impl<'a, T> ToNalgebra for ndarray::ArrayViewMut2<'a, T>
impl<'a, T> IntoNalgebra for ndarray::ArrayViewMut2<'a, T>
where
T: nalgebra::Scalar,
{
type Out = nalgebra::DMatrixSliceMut<'a, T, Dy, Dy>;
type Out = nalgebra::DMatrixViewMut<'a, T, Dyn, Dyn>;
fn into_nalgebra(mut self) -> Self::Out {
let nrows = Dy::new(self.nrows());
let ncols = Dy::new(self.ncols());
let stride_row: usize = TryFrom::try_from(self.strides()[0]).expect("Negative row stride");
let stride_col: usize =
TryFrom::try_from(self.strides()[1]).expect("Negative column stride");
let nrows = Dyn(self.nrows());
let ncols = Dyn(self.ncols());
let stride_row: usize = TryFrom::try_from(self.strides()[0])
.expect("can only convert positive row stride to nalgebra");
let stride_col: usize = TryFrom::try_from(self.strides()[1])
.expect("can only convert positive col stride to nalgebra");
let ptr = self.as_mut_ptr();
let storage = unsafe {
// Drop to not have simultaneously the ndarray and nalgebra valid.
drop(self);
nalgebra::SliceStorageMut::from_raw_parts(
nalgebra::ViewStorageMut::from_raw_parts(
ptr,
(nrows, ncols),
(Dy::new(stride_row), Dy::new(stride_col)),
(Dyn(stride_row), Dyn(stride_col)),
)
};
nalgebra::Matrix::from_data(storage)
}
}

/// ```
/// use nshare::ToNalgebra;
/// use nshare::IntoNalgebra;
///
/// let mut arr = ndarray::arr2(&[
/// let mut arr = ndarray::array![
/// [0.1, 0.2, 0.3, 0.4],
/// [0.5, 0.6, 0.7, 0.8],
/// [1.1, 1.2, 1.3, 1.4],
/// [1.5, 1.6, 1.7, 1.8],
/// ]);
/// ];
/// let m = arr.clone().into_nalgebra();
/// assert!(m.row(1).iter().eq(&[0.5, 0.6, 0.7, 0.8]));
/// assert_eq!(m.shape(), (4, 4));
/// assert!(arr.reversed_axes().into_nalgebra().column(1).iter().eq(&[0.5, 0.6, 0.7, 0.8]));
/// ```
impl<T> ToNalgebra for ndarray::Array2<T>
impl<T> IntoNalgebra for ndarray::Array2<T>
where
T: nalgebra::Scalar,
{
type Out = nalgebra::DMatrix<T>;
fn into_nalgebra(self) -> Self::Out {
let std_layout = self.is_standard_layout();
let nrows = Dy::new(self.nrows());
let ncols = Dy::new(self.ncols());
let mut res = Self::Out::from_vec_generic(nrows, ncols, self.into_raw_vec());
if std_layout {
// This can be expensive, but we have no choice since nalgebra VecStorage is always
// column-based.
res.transpose_mut();
}
res
let nrows = Dyn(self.nrows());
let ncols = Dyn(self.ncols());
Self::Out::from_iterator_generic(nrows, ncols, self.t().iter().cloned())
}
}
Loading

0 comments on commit 6b02eef

Please sign in to comment.