From 8e3edf102cff95e1c7d4304013e9defd8e544e14 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Mon, 15 Oct 2018 22:44:01 +0200 Subject: [PATCH] Start adding doc-tests for BLAS operations. --- src/base/blas.rs | 87 +++++++++++++++++++++++++++++++++++- src/base/matrix.rs | 109 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 177 insertions(+), 19 deletions(-) diff --git a/src/base/blas.rs b/src/base/blas.rs index 23d80a08..a19c6d43 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -16,6 +16,14 @@ use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector}; impl> Vector { /// 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] pub fn imax(&self) -> usize { assert!(!self.is_empty(), "The input vector must not be empty."); @@ -36,6 +44,14 @@ impl> Vector } /// 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] pub fn iamax(&self) -> usize { assert!(!self.is_empty(), "The input vector must not be empty."); @@ -56,6 +72,14 @@ impl> Vector } /// 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] pub fn imin(&self) -> usize { assert!(!self.is_empty(), "The input vector must not be empty."); @@ -76,6 +100,14 @@ impl> Vector } /// 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] pub fn iamin(&self) -> usize { assert!(!self.is_empty(), "The input vector must not be empty."); @@ -98,6 +130,15 @@ impl> Vector impl> Matrix { /// 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] pub fn iamax_full(&self) -> (usize, usize) { assert!(!self.is_empty(), "The input matrix must not be empty."); @@ -124,10 +165,26 @@ impl> Matrix where 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 /// 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] pub fn dot(&self, rhs: &Matrix) -> N where @@ -228,6 +285,23 @@ where } /// 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] pub fn tr_dot(&self, rhs: &Matrix) -> N where @@ -283,6 +357,17 @@ where /// Computes `self = a * x + b * self`. /// /// 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] pub fn axpy(&mut self, a: N, x: &Vector, b: N) where diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 05ff2a53..e8825121 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -160,6 +160,13 @@ impl> Matrix { } /// The total number of elements of this matrix. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.len(), 12); #[inline] pub fn len(&self) -> usize { let (nrows, ncols) = self.shape(); @@ -167,6 +174,13 @@ impl> Matrix { } /// The shape of this matrix returned as the tuple (number of rows, number of columns). + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.shape(), (3, 4)); #[inline] pub fn shape(&self) -> (usize, usize) { let (nrows, ncols) = self.data.shape(); @@ -174,25 +188,63 @@ impl> Matrix { } /// The number of rows of this matrix. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.nrows(), 3); #[inline] pub fn nrows(&self) -> usize { self.shape().0 } /// The number of columns of this matrix. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.ncols(), 4); #[inline] pub fn ncols(&self) -> usize { self.shape().1 } /// The strides (row stride, column stride) of this matrix. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::DMatrix; + /// let mat = DMatrix::::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] pub fn strides(&self) -> (usize, usize) { let (srows, scols) = self.data.strides(); (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] pub fn iter(&self) -> MatrixIter { MatrixIter::new(&self.data) @@ -363,7 +415,10 @@ impl> Matrix { /// 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)`. #[inline] - pub fn map_with_location N2>(&self, mut f: F) -> MatrixMN + pub fn map_with_location N2>( + &self, + mut f: F, + ) -> MatrixMN where DefaultAllocator: Allocator, { @@ -419,22 +474,28 @@ impl> Matrix { /// Returns a matrix containing the result of `f` applied to each entries of `self` and /// `b`, and `c`. #[inline] - pub fn zip_zip_map(&self, b: &Matrix, c: &Matrix, mut f: F) -> MatrixMN - where - N2: Scalar, - N3: Scalar, - N4: Scalar, - S2: Storage, - S3: Storage, - F: FnMut(N, N2, N3) -> N4, - DefaultAllocator: Allocator, + pub fn zip_zip_map( + &self, + b: &Matrix, + c: &Matrix, + mut f: F, + ) -> MatrixMN + where + N2: Scalar, + N3: Scalar, + N4: Scalar, + S2: Storage, + S3: Storage, + F: FnMut(N, N2, N3) -> N4, + DefaultAllocator: Allocator, { let (nrows, ncols) = self.data.shape(); let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) }; 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." ); @@ -1274,20 +1335,32 @@ impl> Matrix { impl> Unit> { /// Computes the spherical linear interpolation between two unit vectors. - pub fn slerp>(&self, rhs: &Unit>, t: N) -> Unit> - where - DefaultAllocator: Allocator { + pub fn slerp>( + &self, + rhs: &Unit>, + t: N, + ) -> Unit> + where + DefaultAllocator: Allocator, + { // 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. /// /// Returns `None` if the two vectors are almost collinear and with opposite direction /// (in this case, there is an infinity of possible results). - pub fn try_slerp>(&self, rhs: &Unit>, t: N, epsilon: N) -> Option>> + pub fn try_slerp>( + &self, + rhs: &Unit>, + t: N, + epsilon: N, + ) -> Option>> where - DefaultAllocator: Allocator { + DefaultAllocator: Allocator, + { let c_hang = self.dot(rhs); // self == other