Start adding doc-tests for BLAS operations.

This commit is contained in:
sebcrozet 2018-10-15 22:44:01 +02:00 committed by Sébastien Crozet
parent 924a9cd160
commit 8e3edf102c
2 changed files with 177 additions and 19 deletions

View File

@ -16,6 +16,14 @@ use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector};
impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S> { impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index of the vector component with the largest value. /// Computes the index of the vector component with the largest value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.imax(), 2);
/// ```
#[inline] #[inline]
pub fn imax(&self) -> usize { pub fn imax(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
@ -36,6 +44,14 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
} }
/// Computes the index of the vector component with the largest absolute value. /// Computes the index of the vector component with the largest absolute value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.iamax(), 1);
/// ```
#[inline] #[inline]
pub fn iamax(&self) -> usize { pub fn iamax(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
@ -56,6 +72,14 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
} }
/// Computes the index of the vector component with the smallest value. /// Computes the index of the vector component with the smallest value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.imin(), 1);
/// ```
#[inline] #[inline]
pub fn imin(&self) -> usize { pub fn imin(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
@ -76,6 +100,14 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
} }
/// Computes the index of the vector component with the smallest absolute value. /// Computes the index of the vector component with the smallest absolute value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.iamin(), 0);
/// ```
#[inline] #[inline]
pub fn iamin(&self) -> usize { pub fn iamin(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
@ -98,6 +130,15 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Computes the index of the matrix component with the largest absolute value. /// Computes the index of the matrix component with the largest absolute value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix2x3;
/// let mat = Matrix2x3::new(11, -12, 13,
/// 21, 22, -23);
/// assert_eq!(mat.iamax_full(), (1, 2));
/// ```
#[inline] #[inline]
pub fn iamax_full(&self) -> (usize, usize) { pub fn iamax_full(&self) -> (usize, usize) {
assert!(!self.is_empty(), "The input matrix must not be empty."); assert!(!self.is_empty(), "The input matrix must not be empty.");
@ -124,10 +165,26 @@ impl<N, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S>
where where
N: Scalar + Zero + ClosedAdd + ClosedMul, N: Scalar + Zero + ClosedAdd + ClosedMul,
{ {
/// The dot product between two matrices (seen as vectors). /// The dot product between two vectors or matrices (seen as vectors).
/// ///
/// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix
/// multiplication, use one of: `.gemm`, `mul_to`, `.mul`, `*`. /// multiplication, use one of: `.gemm`, `mul_to`, `.mul`, `*`.
///
/// # Examples:
///
/// ```
/// # use nalgebra::{Vector3, Matrix2x3};
///
/// let vec1 = Vector3::new(1.0, 2.0, 3.0);
/// let vec2 = Vector3::new(0.1, 0.2, 0.3);
/// assert_eq!(vec1.dot(&vec2), 1.4);
///
/// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// let mat2 = Matrix2x3::new(0.1, 0.2, 0.3,
/// 0.4, 0.5, 0.6);
/// assert_eq!(mat1.dot(&mat2), 9.1);
/// ```
#[inline] #[inline]
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N
where where
@ -228,6 +285,23 @@ where
} }
/// The dot product between the transpose of `self` and `rhs`. /// The dot product between the transpose of `self` and `rhs`.
///
/// # Examples:
///
/// ```
/// # use nalgebra::{Vector3, RowVector3, Matrix2x3, Matrix3x2};
///
/// let vec1 = Vector3::new(1.0, 2.0, 3.0);
/// let vec2 = RowVector3::new(0.1, 0.2, 0.3);
/// assert_eq!(vec1.tr_dot(&vec2), 1.4);
///
/// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// let mat2 = Matrix3x2::new(0.1, 0.4,
/// 0.2, 0.5,
/// 0.3, 0.6);
/// assert_eq!(mat1.tr_dot(&mat2), 9.1);
/// ```
#[inline] #[inline]
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<N, R2, C2, SB>) -> N
where where
@ -283,6 +357,17 @@ where
/// Computes `self = a * x + b * self`. /// Computes `self = a * x + b * self`.
/// ///
/// If be is zero, `self` is never read from. /// If be is zero, `self` is never read from.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
///
/// let mut vec1 = Vector3::new(1.0, 2.0, 3.0);
/// let vec2 = Vector3::new(0.1, 0.2, 0.3);
/// vec1.axpy(10.0, &vec2, 5.0);
/// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0));
/// ```
#[inline] #[inline]
pub fn axpy<D2: Dim, SB>(&mut self, a: N, x: &Vector<N, D2, SB>, b: N) pub fn axpy<D2: Dim, SB>(&mut self, a: N, x: &Vector<N, D2, SB>, b: N)
where where

View File

@ -160,6 +160,13 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
/// The total number of elements of this matrix. /// The total number of elements of this matrix.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix3x4;
/// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.len(), 12);
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
@ -167,6 +174,13 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
/// The shape of this matrix returned as the tuple (number of rows, number of columns). /// The shape of this matrix returned as the tuple (number of rows, number of columns).
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix3x4;
/// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.shape(), (3, 4));
#[inline] #[inline]
pub fn shape(&self) -> (usize, usize) { pub fn shape(&self) -> (usize, usize) {
let (nrows, ncols) = self.data.shape(); let (nrows, ncols) = self.data.shape();
@ -174,25 +188,63 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
/// The number of rows of this matrix. /// The number of rows of this matrix.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix3x4;
/// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.nrows(), 3);
#[inline] #[inline]
pub fn nrows(&self) -> usize { pub fn nrows(&self) -> usize {
self.shape().0 self.shape().0
} }
/// The number of columns of this matrix. /// The number of columns of this matrix.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix3x4;
/// let mat = Matrix3x4::<f32>::zeros();
/// assert_eq!(mat.ncols(), 4);
#[inline] #[inline]
pub fn ncols(&self) -> usize { pub fn ncols(&self) -> usize {
self.shape().1 self.shape().1
} }
/// The strides (row stride, column stride) of this matrix. /// The strides (row stride, column stride) of this matrix.
///
/// # Examples:
///
/// ```
/// # use nalgebra::DMatrix;
/// let mat = DMatrix::<f32>::zeros(10, 10);
/// let slice = mat.slice_with_steps((0, 0), (5, 3), (1, 2));
/// // The column strides is the number of steps (here 2) multiplied by the corresponding dimension.
/// assert_eq!(mat.strides(), (1, 10));
#[inline] #[inline]
pub fn strides(&self) -> (usize, usize) { pub fn strides(&self) -> (usize, usize) {
let (srows, scols) = self.data.strides(); let (srows, scols) = self.data.strides();
(srows.value(), scols.value()) (srows.value(), scols.value())
} }
/// Iterates through this matrix coordinates. /// Iterates through this matrix coordinates in column-major order.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Matrix2x3;
/// let mat = Matrix2x3::new(11, 12, 13,
/// 21, 22, 23);
/// let mut it = mat.iter();
/// assert_eq!(*it.next().unwrap(), 11);
/// assert_eq!(*it.next().unwrap(), 21);
/// assert_eq!(*it.next().unwrap(), 12);
/// assert_eq!(*it.next().unwrap(), 22);
/// assert_eq!(*it.next().unwrap(), 13);
/// assert_eq!(*it.next().unwrap(), 23);
/// assert!(it.next().is_none());
#[inline] #[inline]
pub fn iter(&self) -> MatrixIter<N, R, C, S> { pub fn iter(&self) -> MatrixIter<N, R, C, S> {
MatrixIter::new(&self.data) MatrixIter::new(&self.data)
@ -363,7 +415,10 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`, /// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`,
/// `f` also gets passed the row and column index, i.e. `f(value, row, col)`. /// `f` also gets passed the row and column index, i.e. `f(value, row, col)`.
#[inline] #[inline]
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(&self, mut f: F) -> MatrixMN<N2, R, C> pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
&self,
mut f: F,
) -> MatrixMN<N2, R, C>
where where
DefaultAllocator: Allocator<N2, R, C>, DefaultAllocator: Allocator<N2, R, C>,
{ {
@ -419,7 +474,12 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Returns a matrix containing the result of `f` applied to each entries of `self` and /// Returns a matrix containing the result of `f` applied to each entries of `self` and
/// `b`, and `c`. /// `b`, and `c`.
#[inline] #[inline]
pub fn zip_zip_map<N2, N3, N4, S2, S3, F>(&self, b: &Matrix<N2, R, C, S2>, c: &Matrix<N3, R, C, S3>, mut f: F) -> MatrixMN<N4, R, C> pub fn zip_zip_map<N2, N3, N4, S2, S3, F>(
&self,
b: &Matrix<N2, R, C, S2>,
c: &Matrix<N3, R, C, S3>,
mut f: F,
) -> MatrixMN<N4, R, C>
where where
N2: Scalar, N2: Scalar,
N3: Scalar, N3: Scalar,
@ -434,7 +494,8 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) }; let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) };
assert!( assert!(
(nrows.value(), ncols.value()) == b.shape() && (nrows.value(), ncols.value()) == c.shape(), (nrows.value(), ncols.value()) == b.shape()
&& (nrows.value(), ncols.value()) == c.shape(),
"Matrix simultaneous traversal error: dimension mismatch." "Matrix simultaneous traversal error: dimension mismatch."
); );
@ -1274,20 +1335,32 @@ impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
impl<N: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> { impl<N: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
/// Computes the spherical linear interpolation between two unit vectors. /// Computes the spherical linear interpolation between two unit vectors.
pub fn slerp<S2: Storage<N, D>>(&self, rhs: &Unit<Vector<N, D, S2>>, t: N) -> Unit<VectorN<N, D>> pub fn slerp<S2: Storage<N, D>>(
&self,
rhs: &Unit<Vector<N, D, S2>>,
t: N,
) -> Unit<VectorN<N, D>>
where where
DefaultAllocator: Allocator<N, D> { DefaultAllocator: Allocator<N, D>,
{
// FIXME: the result is wrong when self and rhs are collinear with opposite direction. // FIXME: the result is wrong when self and rhs are collinear with opposite direction.
self.try_slerp(rhs, t, N::default_epsilon()).unwrap_or(Unit::new_unchecked(self.clone_owned())) self.try_slerp(rhs, t, N::default_epsilon())
.unwrap_or(Unit::new_unchecked(self.clone_owned()))
} }
/// Computes the spherical linear interpolation between two unit vectors. /// Computes the spherical linear interpolation between two unit vectors.
/// ///
/// Returns `None` if the two vectors are almost collinear and with opposite direction /// Returns `None` if the two vectors are almost collinear and with opposite direction
/// (in this case, there is an infinity of possible results). /// (in this case, there is an infinity of possible results).
pub fn try_slerp<S2: Storage<N, D>>(&self, rhs: &Unit<Vector<N, D, S2>>, t: N, epsilon: N) -> Option<Unit<VectorN<N, D>>> pub fn try_slerp<S2: Storage<N, D>>(
&self,
rhs: &Unit<Vector<N, D, S2>>,
t: N,
epsilon: N,
) -> Option<Unit<VectorN<N, D>>>
where where
DefaultAllocator: Allocator<N, D> { DefaultAllocator: Allocator<N, D>,
{
let c_hang = self.dot(rhs); let c_hang = self.dot(rhs);
// self == other // self == other