From ed095a5c4bd29c52abf58eda33fe2238f0db20c6 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 16 Feb 2022 19:22:36 +0000 Subject: [PATCH 1/2] Conversion rework While clones may seem more common I believe they have simply been made more explicit (not hiding inside the respective `into()` method). --- readme.md | 13 +- src/algebra/extendable_matrix.rs | 4 +- src/conversion.rs | 181 ++++++++++++++++++ src/conversion/mod.rs | 201 -------------------- src/gaussian_process/builder.rs | 8 +- src/gaussian_process/mod.rs | 42 ++-- src/gaussian_process/multivariate_normal.rs | 10 +- src/lib.rs | 4 +- 8 files changed, 223 insertions(+), 240 deletions(-) create mode 100644 src/conversion.rs delete mode 100644 src/conversion/mod.rs diff --git a/readme.md b/readme.md index 13a16b9..12d4cff 100644 --- a/readme.md +++ b/readme.md @@ -59,11 +59,14 @@ println!("samples: {:?}", sampler.sample(&mut rng)); Most methods of this library can currently work with the following `input -> ouput` pairs : -- `Vec -> f64` a single, multidimensional, sample -- `Vec> -> Vec` each inner vector is a training sample -- `DMatrix -> DVector` using a [nalgebra](https://www.nalgebra.org/) matrix with one row per sample -- `ArrayBase -> f64` a single sample stored in a [ndarray](https://crates.io/crates/ndarray) array (using the `friedrich_ndarray` feature) -- `ArrayBase -> Array1` each row is a sample (using the `friedrich_ndarray` feature) +Input | Output | Description +---|---|--- +[`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Multiple input vectors to multiple output values (with `friedrich_ndarray` feature). +[`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`](https://doc.rust-lang.org/std/primitive.f64.html) | A single input vector to a single output value (with `friedrich_ndarray` feature). +[`DMatrix`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DMatrix.html) | [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | Multiple input vectors to multiple output values. +[`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | [`f64`](https://doc.rust-lang.org/std/primitive.f64.html) | A single input vector to a single output value. +[`Vec>`](https://doc.rust-lang.org/std/vec/struct.Vec.html) | [`Vec` ](https://doc.rust-lang.org/std/vec/struct.Vec.html) | Multiple input vectors to multiple output values. +[`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html) | [`f64` ](https://doc.rust-lang.org/std/primitive.f64.html) | A single input vector to a single input value. The [Input trait](https://docs.rs/friedrich/latest/friedrich/trait.Input.html) is provided to add your own pairs. diff --git a/src/algebra/extendable_matrix.rs b/src/algebra/extendable_matrix.rs index a66ffa3..4fbbdd1 100644 --- a/src/algebra/extendable_matrix.rs +++ b/src/algebra/extendable_matrix.rs @@ -115,12 +115,12 @@ impl EVector mod tests { use super::*; - use crate::conversion::Input; + use crate::conversion::InternalConvert; #[test] fn ematrix_add_rows_extend_size_when_some_of_current_data_is_masked() { - let x = Input::into_dmatrix(vec![vec![1.0f64], vec![2.0f64]]); + let x = (vec![vec![1.0f64], vec![2.0f64]]).i_into(); let mut e = EMatrix::new(x.clone()); for _ in 0..5 { diff --git a/src/conversion.rs b/src/conversion.rs new file mode 100644 index 0000000..9f4950f --- /dev/null +++ b/src/conversion.rs @@ -0,0 +1,181 @@ +/// Implemented by `Input -> Output` type pairs +/// +/// Handles conversion to DMatrix type and stores information on associated output type. +/// Most methods of this library can currently work with the following `input -> output` pairs : +/// +/// Input | Output | Description +/// ---|---|--- +/// [`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Multiple input vectors to multiple output values (with `friedrich_ndarray` feature). +/// [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`] | A single input vector to a single output value (with `friedrich_ndarray` feature). +/// [`DMatrix`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DMatrix.html) | [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | Multiple input vectors to multiple output values. +/// [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | [`f64`] | A single input vector to a single output value. +/// [`Vec>`] | [`Vec` ] | Multiple input vectors to multiple output values. +/// [`Vec`] | [`f64` ] | A single input vector to a single input value. +/// +/// User-defined input type should implement this trait. +pub trait Input: InternalConvert> + Clone +{ + type Output: InternalConvert> + Clone; +} +/// We cannot implement a foreign trait on foreign types, so we use this local trait to mimic [`std::convert::From`]. +pub trait InternalConvert +{ + fn i_into(self) -> T; + fn i_from(x: T) -> Self; +} +// Implementing for ndarray +// ------------------------------------------- +#[cfg(feature = "friedrich_ndarray")] +impl Input for ndarray::Array1 +{ + type Output = f64; +} +#[cfg(feature = "friedrich_ndarray")] +impl InternalConvert> for ndarray::Array1 +{ + fn i_into(self) -> nalgebra::base::DMatrix + { + nalgebra::base::DMatrix::from_iterator(1, self.len(), self.into_iter()) + } + fn i_from(x: nalgebra::base::DMatrix) -> Self + { + Self::from_iter(x.into_iter()) + } +} +// ------------------------------------------- +#[cfg(feature = "friedrich_ndarray")] +impl Input for ndarray::Array2 +{ + type Output = ndarray::Array1; +} +#[cfg(feature = "friedrich_ndarray")] +impl InternalConvert> for ndarray::Array2 +{ + fn i_into(self) -> nalgebra::base::DMatrix + { + nalgebra::base::DMatrix::from_iterator(self.dim().0, self.dim().1, self.into_iter()) + } + fn i_from(x: nalgebra::base::DMatrix) -> Self + { + Self::from_shape_vec(x.shape(), x.into_iter().collect::>()) + } +} +#[cfg(feature = "friedrich_ndarray")] +impl InternalConvert> for ndarray::Array1 +{ + fn i_into(self) -> nalgebra::base::DVector + { + nalgebra::base::DVector::from_iterator(self.len(), self.into_iter()) + } + fn i_from(x: nalgebra::base::DVector) -> Self + { + Self::from_iter(x.into_iter()) + } +} +// Implementing for nalgebra +// -------------------------------------------= +impl Input for nalgebra::base::DVector +{ + type Output = f64; +} +impl InternalConvert> for nalgebra::base::DVector +{ + fn i_into(self) -> nalgebra::base::DMatrix + { + nalgebra::base::DMatrix::from_iterator(1, self.len(), self.iter().cloned()) + } + fn i_from(x: nalgebra::base::DMatrix) -> Self + { + Self::from_iterator(x.len(), x.into_iter().cloned()) + } +} +impl InternalConvert> for f64 +{ + fn i_into(self) -> nalgebra::base::DVector + { + nalgebra::dvector![self] + } + fn i_from(x: nalgebra::base::DVector) -> Self + { + x[0] + } +} +// ------------------------------------------- +impl Input for nalgebra::base::DMatrix +{ + type Output = nalgebra::base::DVector; +} +impl InternalConvert> for nalgebra::base::DMatrix +{ + fn i_into(self) -> nalgebra::base::DMatrix + { + self + } + fn i_from(x: nalgebra::base::DMatrix) -> Self + { + x + } +} +impl InternalConvert> for nalgebra::base::DVector +{ + fn i_into(self) -> nalgebra::base::DVector + { + self + } + fn i_from(x: nalgebra::base::DVector) -> Self + { + x + } +} + +// Implementing for vec +// ------------------------------------------- +impl Input for Vec> +{ + type Output = Vec; +} +impl InternalConvert> for Vec> +{ + fn i_into(self) -> nalgebra::base::DMatrix + { + assert!(!self.is_empty()); + assert!(!self[0].is_empty()); + + nalgebra::base::DMatrix::from_vec(self.len(), + self[0].len(), + self.into_iter().flatten().collect::>()) + } + fn i_from(x: nalgebra::base::DMatrix) -> Self + { + x.row_iter().map(|row| row.iter().cloned().collect::>()).collect::>() + } +} +impl InternalConvert> for Vec +{ + fn i_into(self) -> nalgebra::base::DVector + { + nalgebra::base::DVector::from_vec(self) + } + fn i_from(x: nalgebra::base::DVector) -> Self + { + x.iter().cloned().collect::>() + } +} +// ------------------------------------------- +impl Input for Vec +{ + type Output = f64; +} +impl InternalConvert> for Vec +{ + fn i_into(self) -> nalgebra::base::DMatrix + { + assert!(!self.is_empty()); + + nalgebra::base::DMatrix::from_vec(self.len(), 1, self) + } + fn i_from(x: nalgebra::base::DMatrix) -> Self + { + x.iter().cloned().collect::>() + } +} diff --git a/src/conversion/mod.rs b/src/conversion/mod.rs deleted file mode 100644 index be1abf4..0000000 --- a/src/conversion/mod.rs +++ /dev/null @@ -1,201 +0,0 @@ -use nalgebra::{DMatrix, DVector}; - -#[cfg(feature = "friedrich_ndarray")] -use ndarray::{Array1, ArrayBase, Data, Ix1, Ix2}; - -//----------------------------------------------------------------------------- -// TRAITS - -/// Implemented by `Input -> Output` type pairs -/// -/// Handles conversion to DMatrix type and stores information on associated output type. -/// Most methods of this library can currently work with the following `input -> output` pairs : -/// -/// Input | Output | Description -/// ---|---|--- -/// [`Vec`] | [`f64`] | A single, multidimensional, sample. -/// [`Vec>`] | [`Vec`] | Each inner vector is a training sample. -/// [`DMatrix`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DMatrix.html) | [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | Using a [nalgebra](https://www.nalgebra.org/) matrix with one row per sample. -/// [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`] | A single sample stored in a [ndarray](https://crates.io/crates/ndarray) array (using the `friedrich_ndarray` feature). -/// [`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Each row is a sample (using the `friedrich_ndarray` feature). -/// -/// User-defined input type should implement this trait. -pub trait Input: Sized -{ - /// Type of the vectors storing training output data and given to methods. - type InVector: Sized; - /// Type of the vectors output when a method is called. - type OutVector; - - /// Converts an input matrix to a DMatrix. - fn to_dmatrix(m: &Self) -> DMatrix; - - /// Optional: converts an owned input matrix to a DMatrix. - /// This function is used for to reduce copies when the input type is compatible with DMatrix. - fn into_dmatrix(m: Self) -> DMatrix - { - Self::to_dmatrix(&m) - } - - /// Converts an input vector to a DVector. - fn to_dvector(v: &Self::InVector) -> DVector; - - /// Optional: converts an owned input vector to a DVector. - /// This function is used for to reduce copies when the input type is compatible with DVector. - fn into_dvector(v: Self::InVector) -> DVector - { - Self::to_dvector(&v) - } - - /// Converts a DVector to an output vector. - fn from_dvector(v: &DVector) -> Self::OutVector; -} - -//----------------------------------------------------------------------------- -// IMPLEMENTATIONS - -/// Direct implementation. -impl Input for DMatrix -{ - type InVector = DVector; - type OutVector = DVector; - - /// Converts an input matrix to a DMatrix. - fn to_dmatrix(m: &Self) -> DMatrix - { - m.clone() - } - - /// Converts an input vector to a DVector. - fn to_dvector(v: &Self::InVector) -> DVector - { - v.clone() - } - - /// Converts an input matrix to a DMatrix. - fn into_dmatrix(m: Self) -> DMatrix - { - m - } - - /// Converts an input vector to a DVector. - fn into_dvector(v: Self::InVector) -> DVector - { - v - } - - /// Converts a DVector to an output vector. - fn from_dvector(v: &DVector) -> Self::OutVector - { - v.clone() - } -} - -/// Single row. -impl Input for Vec -{ - type InVector = f64; - type OutVector = f64; - - /// Converts an input matrix to a DMatrix. - fn to_dmatrix(m: &Self) -> DMatrix - { - DMatrix::from_row_slice(1, m.len(), m) - } - - /// Converts an input vector to a DVector. - fn to_dvector(v: &Self::InVector) -> DVector - { - DVector::from_element(1, *v) - } - - /// Converts a DVector to an output vector. - fn from_dvector(v: &DVector) -> Self::OutVector - { - assert_eq!(v.nrows(), 1); - v[0] - } -} - -/// Multiple rows, base rust type. -impl Input for Vec> -{ - type InVector = Vec; - type OutVector = Vec; - - /// Converts an input matrix to a DMatrix. - fn to_dmatrix(m: &Self) -> DMatrix - { - let nb_rows = m.len(); - assert_ne!(nb_rows, 0); - let nb_cols = m[0].len(); - DMatrix::from_fn(nb_rows, nb_cols, |r, c| m[r][c]) - } - - /// Converts an input vector to a DVector. - fn to_dvector(v: &Self::InVector) -> DVector - { - DVector::from_column_slice(v) - } - - /// Converts a DVector to an output vector. - fn from_dvector(v: &DVector) -> Self::OutVector - { - v.iter().cloned().collect() - } -} - -/// Multiple rows, ndarray array type. -#[cfg(feature = "friedrich_ndarray")] -impl> Input for ArrayBase -{ - type InVector = ArrayBase; - type OutVector = Array1; - - /// Converts an input matrix to a DMatrix. - fn to_dmatrix(m: &Self) -> DMatrix - { - assert_ne!(m.nrows(), 0); - // Use `.t()` to get from row-major to col-major. - DMatrix::from_iterator(m.nrows(), m.ncols(), m.t().iter().cloned()) - } - - /// Converts an input vector to a DVector. - fn to_dvector(v: &Self::InVector) -> DVector - { - DVector::from_iterator(v.len(), v.iter().cloned()) - } - - /// Converts a DVector to an output vector. - fn from_dvector(v: &DVector) -> Self::OutVector - { - v.iter().cloned().collect() - } -} - -/// Single row, ndarray array type. -#[cfg(feature = "friedrich_ndarray")] -impl> Input for ArrayBase -{ - type InVector = f64; - type OutVector = f64; - - /// Converts an input matrix to a DMatrix. - fn to_dmatrix(m: &Self) -> DMatrix - { - DMatrix::from_iterator(1, m.len(), m.iter().cloned()) - } - - /// Converts an input vector to a DVector. - fn to_dvector(v: &Self::InVector) -> DVector - { - DVector::from_element(1, *v) - } - - /// Converts a DVector to an output vector. - fn from_dvector(v: &DVector) -> Self::OutVector - { - assert_eq!(v.nrows(), 1); - v[0] - } -} diff --git a/src/gaussian_process/builder.rs b/src/gaussian_process/builder.rs index 039409d..0664968 100644 --- a/src/gaussian_process/builder.rs +++ b/src/gaussian_process/builder.rs @@ -1,5 +1,5 @@ use super::GaussianProcess; -use crate::conversion::Input; +use crate::conversion::{Input, InternalConvert}; use crate::parameters::kernel::Kernel; use crate::parameters::prior::Prior; use nalgebra::{DMatrix, DVector}; @@ -61,10 +61,10 @@ impl GaussianProcessBuilder(training_inputs: T, training_outputs: T::InVector) -> Self + pub fn new(training_inputs: T, training_outputs: T::Output) -> Self { - let training_inputs = T::into_dmatrix(training_inputs); - let training_outputs = T::into_dvector(training_outputs); + let training_inputs = training_inputs.i_into(); + let training_outputs = training_outputs.i_into(); // makes builder let prior = PriorType::default(training_inputs.ncols()); let kernel = KernelType::default(); diff --git a/src/gaussian_process/mod.rs b/src/gaussian_process/mod.rs index 8438efe..7426502 100644 --- a/src/gaussian_process/mod.rs +++ b/src/gaussian_process/mod.rs @@ -40,7 +40,7 @@ use crate::algebra::{add_rows_cholesky_cov_matrix, make_cholesky_cov_matrix, make_covariance_matrix, EMatrix, EVector}; -use crate::conversion::Input; +use crate::conversion::{Input, InternalConvert}; use crate::parameters::{kernel, kernel::Kernel, prior, prior::Prior}; use nalgebra::{Cholesky, DMatrix, DVector, Dynamic}; @@ -84,7 +84,7 @@ impl GaussianProcess /// let gp = GaussianProcess::default(training_inputs, training_outputs); /// # } /// ``` - pub fn default(training_inputs: T, training_outputs: T::InVector) -> Self + pub fn default(training_inputs: T, training_outputs: T::Output) -> Self { GaussianProcessBuilder::::new(training_inputs, training_outputs).fit_kernel() @@ -118,7 +118,7 @@ impl GaussianProcess /// # } /// ``` pub fn builder(training_inputs: T, - training_outputs: T::InVector) + training_outputs: T::Output) -> GaussianProcessBuilder { GaussianProcessBuilder::::new(training_inputs, @@ -134,12 +134,12 @@ impl GaussianProcess Self { assert!(noise >= 0., "The noise parameter should non-negative but we tried to set it to {}", noise); - let training_inputs = T::into_dmatrix(training_inputs); - let training_outputs = T::into_dvector(training_outputs); + let training_inputs = training_inputs.i_into(); + let training_outputs = training_outputs.i_into(); assert_eq!(training_inputs.nrows(), training_outputs.nrows()); // converts training data into extendable matrix let training_inputs = EMatrix::new(training_inputs); @@ -153,10 +153,10 @@ impl GaussianProcess(&mut self, inputs: &T, outputs: &T::InVector) + pub fn add_samples(&mut self, inputs: &T, outputs: &T::Output) { - let inputs = T::to_dmatrix(inputs); - let outputs = T::to_dvector(outputs); + let inputs = inputs.clone().i_into(); + let outputs = outputs.clone().i_into(); assert_eq!(inputs.nrows(), outputs.nrows()); assert_eq!(inputs.ncols(), self.training_inputs.as_matrix().ncols()); // grows the training matrix @@ -206,11 +206,11 @@ impl GaussianProcess(&self, inputs: &T) -> T::OutVector + pub fn predict(&self, inputs: &T) -> T::Output { // formula : prior + cov(input,train)*cov(train,train)^-1 * output - let inputs = T::to_dmatrix(inputs); + let inputs = inputs.clone().i_into(); assert_eq!(inputs.ncols(), self.training_inputs.as_matrix().ncols()); // computes weights to give each training sample @@ -223,16 +223,16 @@ impl GaussianProcess(&self, inputs: &T) -> T::OutVector + pub fn predict_variance(&self, inputs: &T) -> T::Output { // formula, diagonal of : cov(input,input) - cov(input,train)*cov(train,train)^-1*cov(train,input) - let inputs = T::to_dmatrix(inputs); + let inputs = inputs.clone().i_into(); assert_eq!(inputs.ncols(), self.training_inputs.as_matrix().ncols()); // compute the covariances @@ -252,7 +252,7 @@ impl GaussianProcess::from_iterator(inputs.nrows(), variances); - T::from_dvector(&variances) + T::Output::i_from(variances) } /// Predicts both the mean and the variance of the gaussian process for each row of the input. @@ -270,9 +270,9 @@ impl GaussianProcess(&self, inputs: &T) -> (T::OutVector, T::OutVector) + pub fn predict_mean_variance(&self, inputs: &T) -> (T::Output, T::Output) { - let inputs = T::to_dmatrix(inputs); + let inputs = inputs.clone().i_into(); assert_eq!(inputs.ncols(), self.training_inputs.as_matrix().ncols()); // computes weights to give each training sample @@ -288,7 +288,7 @@ impl GaussianProcess GaussianProcess GaussianProcess GaussianProcess(&self, inputs: &T) -> MultivariateNormal { - let inputs = T::to_dmatrix(inputs); + let inputs = inputs.clone().i_into(); assert_eq!(inputs.ncols(), self.training_inputs.as_matrix().ncols()); // compute the weights diff --git a/src/gaussian_process/multivariate_normal.rs b/src/gaussian_process/multivariate_normal.rs index 616e559..304884b 100644 --- a/src/gaussian_process/multivariate_normal.rs +++ b/src/gaussian_process/multivariate_normal.rs @@ -1,4 +1,4 @@ -use crate::conversion::Input; +use crate::conversion::{Input, InternalConvert}; use nalgebra::{DMatrix, DVector}; use rand::Rng; use rand_distr::StandardNormal; @@ -59,16 +59,16 @@ impl MultivariateNormal } /// Outputs the mean of the distribution. - pub fn mean(&self) -> T::OutVector + pub fn mean(&self) -> T::Output { - T::from_dvector(&self.mean) + T::Output::i_from(self.mean.clone()) } /// Takes a random number generator and uses it to sample from the distribution. - pub fn sample(&self, rng: &mut RNG) -> T::OutVector + pub fn sample(&self, rng: &mut RNG) -> T::Output { let normal = DVector::from_fn(self.mean.nrows(), |_, _| rng.sample(StandardNormal)); let sample = &self.mean + &self.cholesky_covariance * normal; - T::from_dvector(&sample) + T::Output::i_from(sample) } } diff --git a/src/lib.rs b/src/lib.rs index 8f7c01e..4a26396 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,8 @@ //! [`Vec`] | [`f64`] | A single, multidimensional, sample. //! [`Vec>`] | [`Vec`] | Each inner vector is a training sample. //! [`DMatrix`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DMatrix.html) | [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | Using a [nalgebra](https://www.nalgebra.org/) matrix with one row per sample. -//! [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`] | A single sample stored in a [ndarray](https://crates.io/crates/ndarray) array (using the `friedrich_ndarray` feature). -//! [`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Each row is a sample (using the `friedrich_ndarray` feature). +//! [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`] | A single sample stored in a [ndarray](https://crates.io/crates/ndarray) array (using the `ndarray` feature). +//! [`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Each row is a sample (using the `ndarray` feature). //! //! See the [`Input`] trait if you want to add you own input type. //! From b9fafbc72f2f0805d730f2cc5308acaffa0e407d Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 16 Feb 2022 19:37:52 +0000 Subject: [PATCH 2/2] readme input table consistent with `Input` rustdoc --- src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4a26396..7bc7c1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,11 +28,12 @@ //! //! Input | Output | Description //! ---|---|--- -//! [`Vec`] | [`f64`] | A single, multidimensional, sample. -//! [`Vec>`] | [`Vec`] | Each inner vector is a training sample. -//! [`DMatrix`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DMatrix.html) | [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | Using a [nalgebra](https://www.nalgebra.org/) matrix with one row per sample. -//! [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`] | A single sample stored in a [ndarray](https://crates.io/crates/ndarray) array (using the `ndarray` feature). -//! [`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Each row is a sample (using the `ndarray` feature). +//! [`Array2`](https://docs.rs/ndarray/0.15/ndarray/type.Array2.html) | [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | Multiple input vectors to multiple output values (with `friedrich_ndarray` feature). +//! [`Array1`](https://docs.rs/ndarray/0.15/ndarray/type.Array1.html) | [`f64`] | A single input vector to a single output value (with `friedrich_ndarray` feature). +//! [`DMatrix`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DMatrix.html) | [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | Multiple input vectors to multiple output values. +//! [`DVector`](https://docs.rs/nalgebra/0.29/nalgebra/base/type.DVector.html) | [`f64`] | A single input vector to a single output value. +//! [`Vec>`] | [`Vec` ] | Multiple input vectors to multiple output values. +//! [`Vec`] | [`f64` ] | A single input vector to a single input value. //! //! See the [`Input`] trait if you want to add you own input type. //!