Merge remote-tracking branch 'upstream/master' into Implement_convolution_#520

This commit is contained in:
Nathan 2019-02-23 08:29:41 -06:00
commit a3d571ea6b
108 changed files with 4698 additions and 938 deletions

View File

@ -4,7 +4,16 @@ documented here.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## [0.17.0] - WIP ## [0.18.0] - WIP
### Added
* Add `.renormalize` to `Unit<...>` and `Rotation3` to correct potential drift due to repeated operations.
Those drifts can cause them not to be pure rotations anymore.
* Add the `::from_matrix` constructor too all rotation types to extract a rotation from a raw matrix.
* Add the `::from_matrix_eps` constructor too all rotation types to extract a rotation from a raw matrix. This takes
more argument than `::from_matrix` to control the convergence of the underlying optimization algorithm.
## [0.17.0]
### Added ### Added
* Add swizzling up to dimension 3 for vectors. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.y)`. * Add swizzling up to dimension 3 for vectors. For example, you can do `v.zxy()` as an equivalent to `Vector3::new(v.z, v.x, v.y)`.
@ -35,7 +44,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Implement `Extend<Matrix<...>>` for matrices with dynamic storage. This will concatenate the columns of both matrices. * Implement `Extend<Matrix<...>>` for matrices with dynamic storage. This will concatenate the columns of both matrices.
* Implement `Into<Vec>` for the `MatrixVec` storage. * Implement `Into<Vec>` for the `MatrixVec` storage.
* Implement `Hash` for all matrices. * Implement `Hash` for all matrices.
* Add a `.len()` method to retrieve the size of a `MatrixVec`.
### Modified ### Modified
* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The * The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The
only restriction now ith that they must not be equal (in which case the projection would be singular). only restriction now ith that they must not be equal (in which case the projection would be singular).
@ -46,11 +56,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type. * Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type.
This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`. This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`.
* Deprecate several functions at the root of the crate (replaced by methods). * Deprecate several functions at the root of the crate (replaced by methods).
### Removed
* Remove the `Deref` impl for `MatrixVec` as it could cause hard-to-understand compilation errors.
### nalgebra-glm ### nalgebra-glm
* Add several alternative projection computations, e.g., `ortho_lh`, `ortho_lh_no`, `perspective_lh`, etc. * Add several alternative projection computations, e.g., `ortho_lh`, `ortho_lh_no`, `perspective_lh`, etc.
* Add features matching those of nalgebra, in particular: `serde-serialize`, `abmonation-serialize`, std` (enabled by default). * Add features matching those of nalgebra, in particular: `serde-serialize`, `abmonation-serialize`, std` (enabled by default).
## [0.16.0] ## [0.16.0]
All dependencies have been updated to their latest versions. All dependencies have been updated to their latest versions.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra" name = "nalgebra"
version = "0.16.13" version = "0.17.2"
authors = [ "Sébastien Crozet <developer@crozet.re>" ] authors = [ "Sébastien Crozet <developer@crozet.re>" ]
description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices." description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices."
@ -12,6 +12,8 @@ categories = [ "science" ]
keywords = [ "linear", "algebra", "matrix", "vector", "math" ] keywords = [ "linear", "algebra", "matrix", "vector", "math" ]
license = "BSD-3-Clause" license = "BSD-3-Clause"
exclude = ["/ci/*", "/.travis.yml", "/Makefile"]
[lib] [lib]
name = "nalgebra" name = "nalgebra"
path = "src/lib.rs" path = "src/lib.rs"
@ -23,8 +25,10 @@ stdweb = [ "rand/stdweb" ]
arbitrary = [ "quickcheck" ] arbitrary = [ "quickcheck" ]
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
abomonation-serialize = [ "abomonation" ] abomonation-serialize = [ "abomonation" ]
sparse = [ ]
debug = [ ] debug = [ ]
alloc = [ ] alloc = [ ]
io = [ "pest", "pest_derive" ]
[dependencies] [dependencies]
typenum = "1.10" typenum = "1.10"
@ -33,13 +37,15 @@ rand = { version = "0.6", default-features = false }
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
num-complex = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false }
approx = { version = "0.3", default-features = false } approx = { version = "0.3", default-features = false }
alga = { version = "0.7", default-features = false } alga = { version = "0.8", default-features = false }
matrixmultiply = { version = "0.2", optional = true } matrixmultiply = { version = "0.2", optional = true }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
abomonation = { version = "0.7", optional = true } abomonation = { version = "0.7", optional = true }
mint = { version = "0.5", optional = true } mint = { version = "0.5", optional = true }
quickcheck = { version = "0.7", optional = true } quickcheck = { version = "0.8", optional = true }
pest = { version = "2.0", optional = true }
pest_derive = { version = "2.0", optional = true }
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" serde_json = "1.0"

View File

@ -11,7 +11,7 @@ if [ -z "$NO_STD" ]; then
cargo build --verbose -p nalgebra --features "serde-serialize"; cargo build --verbose -p nalgebra --features "serde-serialize";
cargo build --verbose -p nalgebra --features "abomonation-serialize"; cargo build --verbose -p nalgebra --features "abomonation-serialize";
cargo build --verbose -p nalgebra --features "debug"; cargo build --verbose -p nalgebra --features "debug";
cargo build --verbose -p nalgebra --features "debug arbitrary mint serde-serialize abomonation-serialize"; cargo build --verbose -p nalgebra --all-features
else else
cargo build -p nalgebra-lapack; cargo build -p nalgebra-lapack;
fi fi

View File

@ -51,8 +51,8 @@ fn main() {
// Components listed column-by-column. // Components listed column-by-column.
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
] ]
.iter() .iter()
.cloned(), .cloned(),
); );
assert_eq!(dm, dm1); assert_eq!(dm, dm1);

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-glm" name = "nalgebra-glm"
version = "0.2.1" version = "0.3.0"
authors = ["sebcrozet <developer@crozet.re>"] authors = ["sebcrozet <developer@crozet.re>"]
description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library."
@ -23,5 +23,5 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
[dependencies] [dependencies]
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
approx = { version = "0.3", default-features = false } approx = { version = "0.3", default-features = false }
alga = { version = "0.7", default-features = false } alga = { version = "0.8", default-features = false }
nalgebra = { path = "..", version = "^0.16.13", default-features = false } nalgebra = { path = "..", version = "0.17", default-features = false }

View File

@ -9,7 +9,7 @@ where DefaultAllocator: Alloc<N, D, D> {
TMat::<N, D, D>::identity() TMat::<N, D, D>::identity()
} }
/// Build a right hand look at view matrix /// Build a look at view matrix based on the right handedness.
/// ///
/// # Parameters: /// # Parameters:
/// ///

View File

@ -15,4 +15,4 @@
//pub fn uround<N: Scalar, D: Dimension>(x: &TVec<N, D>) -> TVec<u32, D> //pub fn uround<N: Scalar, D: Dimension>(x: &TVec<N, D>) -> TVec<u32, D>
// where DefaultAllocator: Alloc<N, D> { // where DefaultAllocator: Alloc<N, D> {
// unimplemented!() // unimplemented!()
//} //}

View File

@ -288,4 +288,4 @@ pub fn unpackUnorm4x16(p: u64) -> Vec4 {
pub fn unpackUnorm4x4(p: u16) -> Vec4 { pub fn unpackUnorm4x4(p: u16) -> Vec4 {
unimplemented!() unimplemented!()
} }

View File

@ -13,7 +13,7 @@
```toml ```toml
[dependencies] [dependencies]
nalgebra-glm = "0.1" nalgebra-glm = "0.3"
``` ```
Then, you should add an `extern crate` statement to your `lib.rs` or `main.rs` file. It is **strongly Then, you should add an `extern crate` statement to your `lib.rs` or `main.rs` file. It is **strongly
@ -110,6 +110,7 @@
and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)). and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)).
*/ */
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
extern crate num_traits as num; extern crate num_traits as num;

View File

@ -52,4 +52,4 @@ pub fn perspective_glm_nalgebra_project_same()
assert_eq!(na_mat, gl_mat); assert_eq!(na_mat, gl_mat);
assert_eq!(na_pt, gl_pt); assert_eq!(na_pt, gl_pt);
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra-lapack" name = "nalgebra-lapack"
version = "0.8.0" version = "0.9.0"
authors = [ "Sébastien Crozet <developer@crozet.re>", "Andrew Straw <strawman@astraw.com>" ] authors = [ "Sébastien Crozet <developer@crozet.re>", "Andrew Straw <strawman@astraw.com>" ]
description = "Linear algebra library with transformations and satically-sized or dynamically-sized matrices." description = "Linear algebra library with transformations and satically-sized or dynamically-sized matrices."
@ -22,10 +22,10 @@ accelerate = ["lapack-src/accelerate"]
intel-mkl = ["lapack-src/intel-mkl"] intel-mkl = ["lapack-src/intel-mkl"]
[dependencies] [dependencies]
nalgebra = { version = "0.16", path = ".." } nalgebra = { version = "0.17", path = ".." }
num-traits = "0.2" num-traits = "0.2"
num-complex = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false }
alga = { version = "0.7", default-features = false } alga = { version = "0.8", default-features = false }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
lapack = { version = "0.16", default-features = false } lapack = { version = "0.16", default-features = false }
@ -33,7 +33,7 @@ lapack-src = { version = "0.2", default-features = false }
# clippy = "*" # clippy = "*"
[dev-dependencies] [dev-dependencies]
nalgebra = { version = "0.16", path = "..", features = [ "arbitrary" ] } nalgebra = { version = "0.17", path = "..", features = [ "arbitrary" ] }
quickcheck = "0.7" quickcheck = "0.8"
approx = "0.3" approx = "0.3"
rand = "0.6" rand = "0.6"

View File

@ -62,7 +62,7 @@ where DefaultAllocator: Allocator<N, D, D>
N::xpotrf(uplo, dim, m.as_mut_slice(), dim, &mut info); N::xpotrf(uplo, dim, m.as_mut_slice(), dim, &mut info);
lapack_check!(info); lapack_check!(info);
Some(Cholesky { l: m }) Some(Self { l: m })
} }
/// Retrieves the lower-triangular factor of the cholesky decomposition. /// Retrieves the lower-triangular factor of the cholesky decomposition.

View File

@ -127,7 +127,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
lapack_check!(info); lapack_check!(info);
if wi.iter().all(|e| e.is_zero()) { if wi.iter().all(|e| e.is_zero()) {
return Some(Eigen { return Some(Self {
eigenvalues: wr, eigenvalues: wr,
left_eigenvectors: Some(vl), left_eigenvectors: Some(vl),
eigenvectors: Some(vr), eigenvectors: Some(vr),
@ -156,7 +156,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
lapack_check!(info); lapack_check!(info);
if wi.iter().all(|e| e.is_zero()) { if wi.iter().all(|e| e.is_zero()) {
return Some(Eigen { return Some(Self {
eigenvalues: wr, eigenvalues: wr,
left_eigenvectors: Some(vl), left_eigenvectors: Some(vl),
eigenvectors: None, eigenvectors: None,
@ -185,7 +185,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
lapack_check!(info); lapack_check!(info);
if wi.iter().all(|e| e.is_zero()) { if wi.iter().all(|e| e.is_zero()) {
return Some(Eigen { return Some(Self {
eigenvalues: wr, eigenvalues: wr,
left_eigenvectors: None, left_eigenvectors: None,
eigenvectors: Some(vr), eigenvectors: Some(vr),
@ -212,7 +212,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
lapack_check!(info); lapack_check!(info);
if wi.iter().all(|e| e.is_zero()) { if wi.iter().all(|e| e.is_zero()) {
return Some(Eigen { return Some(Self {
eigenvalues: wr, eigenvalues: wr,
left_eigenvectors: None, left_eigenvectors: None,
eigenvectors: None, eigenvectors: None,

View File

@ -48,7 +48,7 @@ impl<N: HessenbergScalar + Zero, D: DimSub<U1>> Hessenberg<N, D>
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>> where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>
{ {
/// Computes the hessenberg decomposition of the matrix `m`. /// Computes the hessenberg decomposition of the matrix `m`.
pub fn new(mut m: MatrixN<N, D>) -> Hessenberg<N, D> { pub fn new(mut m: MatrixN<N, D>) -> Self {
let nrows = m.data.shape().0; let nrows = m.data.shape().0;
let n = nrows.value() as i32; let n = nrows.value() as i32;
@ -83,7 +83,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>
); );
lapack_panic!(info); lapack_panic!(info);
Hessenberg { h: m, tau: tau } Self { h: m, tau: tau }
} }
/// Computes the hessenberg matrix of this decomposition. /// Computes the hessenberg matrix of this decomposition.

View File

@ -68,8 +68,10 @@
#![deny(unused_qualifications)] #![deny(unused_qualifications)]
#![deny(unused_results)] #![deny(unused_results)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico", #![doc(
html_root_url = "http://nalgebra.org/rustdoc")] html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc"
)]
extern crate alga; extern crate alga;
extern crate lapack; extern crate lapack;

View File

@ -82,7 +82,7 @@ where
); );
lapack_panic!(info); lapack_panic!(info);
LU { lu: m, p: ipiv } Self { lu: m, p: ipiv }
} }
/// Gets the lower-triangular matrix part of the decomposition. /// Gets the lower-triangular matrix part of the decomposition.

View File

@ -54,14 +54,14 @@ where DefaultAllocator: Allocator<N, R, C>
+ Allocator<N, DimMinimum<R, C>> + Allocator<N, DimMinimum<R, C>>
{ {
/// Computes the QR decomposition of the matrix `m`. /// Computes the QR decomposition of the matrix `m`.
pub fn new(mut m: MatrixMN<N, R, C>) -> QR<N, R, C> { pub fn new(mut m: MatrixMN<N, R, C>) -> Self {
let (nrows, ncols) = m.data.shape(); let (nrows, ncols) = m.data.shape();
let mut info = 0; let mut info = 0;
let mut tau = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), U1) }; let mut tau = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), U1) };
if nrows.value() == 0 || ncols.value() == 0 { if nrows.value() == 0 || ncols.value() == 0 {
return QR { qr: m, tau: tau }; return Self { qr: m, tau: tau };
} }
let lwork = N::xgeqrf_work_size( let lwork = N::xgeqrf_work_size(
@ -86,7 +86,7 @@ where DefaultAllocator: Allocator<N, R, C>
&mut info, &mut info,
); );
QR { qr: m, tau: tau } Self { qr: m, tau: tau }
} }
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition. /// Retrieves the upper trapezoidal submatrix `R` of this decomposition.

View File

@ -62,7 +62,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
pub fn new(m: MatrixN<N, D>) -> Self { pub fn new(m: MatrixN<N, D>) -> Self {
let (vals, vecs) = let (vals, vecs) =
Self::do_decompose(m, true).expect("SymmetricEigen: convergence failure."); Self::do_decompose(m, true).expect("SymmetricEigen: convergence failure.");
SymmetricEigen { Self {
eigenvalues: vals, eigenvalues: vals,
eigenvectors: vecs.unwrap(), eigenvectors: vecs.unwrap(),
} }

View File

@ -1,3 +1,3 @@
unstable_features = true unstable_features = true
indent_style = "Block" indent_style = "Block"
where_single_line = true where_single_line = true

View File

@ -175,24 +175,24 @@ pub type MatrixSliceXx6<'a, N, RStride = U1, CStride = Dynamic> =
MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>; MatrixSliceMN<'a, N, Dynamic, U6, RStride, CStride>;
/// A column vector slice with `D` rows. /// A column vector slice with `D` rows.
pub type VectorSliceN<'a, N, D, Stride = U1> = pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> =
Matrix<N, D, U1, SliceStorage<'a, N, D, U1, Stride, D>>; Matrix<N, D, U1, SliceStorage<'a, N, D, U1, RStride, CStride>>;
/// A column vector slice dynamic numbers of rows and columns. /// A column vector slice dynamic numbers of rows and columns.
pub type DVectorSlice<'a, N, Stride = U1> = VectorSliceN<'a, N, Dynamic, Stride>; pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceN<'a, N, Dynamic, RStride, CStride>;
/// A 1D column vector slice. /// A 1D column vector slice.
pub type VectorSlice1<'a, N, Stride = U1> = VectorSliceN<'a, N, U1, Stride>; pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = VectorSliceN<'a, N, U1, RStride, CStride>;
/// A 2D column vector slice. /// A 2D column vector slice.
pub type VectorSlice2<'a, N, Stride = U1> = VectorSliceN<'a, N, U2, Stride>; pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = VectorSliceN<'a, N, U2, RStride, CStride>;
/// A 3D column vector slice. /// A 3D column vector slice.
pub type VectorSlice3<'a, N, Stride = U1> = VectorSliceN<'a, N, U3, Stride>; pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = VectorSliceN<'a, N, U3, RStride, CStride>;
/// A 4D column vector slice. /// A 4D column vector slice.
pub type VectorSlice4<'a, N, Stride = U1> = VectorSliceN<'a, N, U4, Stride>; pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = VectorSliceN<'a, N, U4, RStride, CStride>;
/// A 5D column vector slice. /// A 5D column vector slice.
pub type VectorSlice5<'a, N, Stride = U1> = VectorSliceN<'a, N, U5, Stride>; pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = VectorSliceN<'a, N, U5, RStride, CStride>;
/// A 6D column vector slice. /// A 6D column vector slice.
pub type VectorSlice6<'a, N, Stride = U1> = VectorSliceN<'a, N, U6, Stride>; pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = VectorSliceN<'a, N, U6, RStride, CStride>;
/* /*
* *
@ -367,21 +367,21 @@ pub type MatrixSliceMutXx6<'a, N, RStride = U1, CStride = Dynamic> =
MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>; MatrixSliceMutMN<'a, N, Dynamic, U6, RStride, CStride>;
/// A mutable column vector slice with `D` rows. /// A mutable column vector slice with `D` rows.
pub type VectorSliceMutN<'a, N, D, Stride = U1> = pub type VectorSliceMutN<'a, N, D, RStride = U1, CStride = D> =
Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, Stride, D>>; Matrix<N, D, U1, SliceStorageMut<'a, N, D, U1, RStride, CStride>>;
/// A mutable column vector slice dynamic numbers of rows and columns. /// A mutable column vector slice dynamic numbers of rows and columns.
pub type DVectorSliceMut<'a, N, Stride = U1> = VectorSliceMutN<'a, N, Dynamic, Stride>; pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceMutN<'a, N, Dynamic, RStride, CStride>;
/// A 1D mutable column vector slice. /// A 1D mutable column vector slice.
pub type VectorSliceMut1<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U1, Stride>; pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = VectorSliceMutN<'a, N, U1, RStride, CStride>;
/// A 2D mutable column vector slice. /// A 2D mutable column vector slice.
pub type VectorSliceMut2<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U2, Stride>; pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = VectorSliceMutN<'a, N, U2, RStride, CStride>;
/// A 3D mutable column vector slice. /// A 3D mutable column vector slice.
pub type VectorSliceMut3<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U3, Stride>; pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = VectorSliceMutN<'a, N, U3, RStride, CStride>;
/// A 4D mutable column vector slice. /// A 4D mutable column vector slice.
pub type VectorSliceMut4<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U4, Stride>; pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = VectorSliceMutN<'a, N, U4, RStride, CStride>;
/// A 5D mutable column vector slice. /// A 5D mutable column vector slice.
pub type VectorSliceMut5<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U5, Stride>; pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = VectorSliceMutN<'a, N, U5, RStride, CStride>;
/// A 6D mutable column vector slice. /// A 6D mutable column vector slice.
pub type VectorSliceMut6<'a, N, Stride = U1> = VectorSliceMutN<'a, N, U6, Stride>; pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = VectorSliceMutN<'a, N, U6, RStride, CStride>;

View File

@ -331,7 +331,7 @@ where
let mut curr = 0; let mut curr = 0;
while let Some(value) = try!(visitor.next_element()) { while let Some(value) = try!(visitor.next_element()) {
out[curr] = value; *out.get_mut(curr).ok_or_else(|| V::Error::invalid_length(curr, &self))? = value;
curr += 1; curr += 1;
} }

View File

@ -13,18 +13,18 @@ use base::dimension::{Dim, Dynamic, U1, U2, U3, U4};
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector}; 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, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
/// Computes the index of the vector component with the largest value. /// Computes the index and value of the vector component with the largest value.
/// ///
/// # Examples: /// # Examples:
/// ///
/// ``` /// ```
/// # use nalgebra::Vector3; /// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13); /// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.imax(), 2); /// assert_eq!(vec.argmax(), (2, 13));
/// ``` /// ```
#[inline] #[inline]
pub fn imax(&self) -> usize { pub fn argmax(&self) -> (usize, N) {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0) }; let mut the_max = unsafe { self.vget_unchecked(0) };
@ -39,7 +39,21 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
} }
} }
the_i (the_i, *the_max)
}
/// 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 {
self.argmax().0
} }
/// Computes the index of the vector component with the largest absolute value. /// Computes the index of the vector component with the largest absolute value.
@ -52,7 +66,8 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// assert_eq!(vec.iamax(), 1); /// assert_eq!(vec.iamax(), 1);
/// ``` /// ```
#[inline] #[inline]
pub fn iamax(&self) -> usize { pub fn iamax(&self) -> usize
where N: Signed {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0).abs() }; let mut the_max = unsafe { self.vget_unchecked(0).abs() };
@ -70,6 +85,34 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
the_i the_i
} }
/// Computes the index and value of the vector component with the smallest value.
///
/// # Examples:
///
/// ```
/// # use nalgebra::Vector3;
/// let vec = Vector3::new(11, -15, 13);
/// assert_eq!(vec.argmin(), (1, -15));
/// ```
#[inline]
pub fn argmin(&self) -> (usize, N) {
assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_min = unsafe { self.vget_unchecked(0) };
let mut the_i = 0;
for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i) };
if val < the_min {
the_min = val;
the_i = i;
}
}
(the_i, *the_min)
}
/// Computes the index of the vector component with the smallest value. /// Computes the index of the vector component with the smallest value.
/// ///
/// # Examples: /// # Examples:
@ -81,21 +124,7 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// ``` /// ```
#[inline] #[inline]
pub fn imin(&self) -> usize { pub fn imin(&self) -> usize {
assert!(!self.is_empty(), "The input vector must not be empty."); self.argmin().0
let mut the_max = unsafe { self.vget_unchecked(0) };
let mut the_i = 0;
for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i) };
if val < the_max {
the_max = val;
the_i = i;
}
}
the_i
} }
/// Computes the index of the vector component with the smallest absolute value. /// Computes the index of the vector component with the smallest absolute value.
@ -108,17 +137,18 @@ impl<N: Scalar + PartialOrd + Signed, D: Dim, S: Storage<N, D>> Vector<N, D, S>
/// assert_eq!(vec.iamin(), 0); /// assert_eq!(vec.iamin(), 0);
/// ``` /// ```
#[inline] #[inline]
pub fn iamin(&self) -> usize { pub fn iamin(&self) -> usize
where N: Signed {
assert!(!self.is_empty(), "The input vector must not be empty."); assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0).abs() }; let mut the_min = unsafe { self.vget_unchecked(0).abs() };
let mut the_i = 0; let mut the_i = 0;
for i in 1..self.nrows() { for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i).abs() }; let val = unsafe { self.vget_unchecked(i).abs() };
if val < the_max { if val < the_min {
the_max = val; the_min = val;
the_i = i; the_i = i;
} }
} }
@ -627,7 +657,6 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4}; /// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity(); /// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0, /// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0,
@ -760,7 +789,6 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4}; /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4};
/// let mut mat1 = Matrix2x4::identity(); /// let mut mat1 = Matrix2x4::identity();
/// let mat2 = Matrix3x2::new(1.0, 4.0, /// let mat2 = Matrix3x2::new(1.0, 4.0,
@ -879,7 +907,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{DMatrix, DVector}; /// # use nalgebra::{DMatrix, DVector};
/// // Note that all those would also work with statically-sized matrices. /// // Note that all those would also work with statically-sized matrices.
/// // We use DMatrix/DVector since that's the only case where pre-allocating the /// // We use DMatrix/DVector since that's the only case where pre-allocating the
@ -934,7 +961,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2}; /// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2};
/// let mut mat = Matrix2::identity(); /// let mut mat = Matrix2::identity();
/// let lhs = Matrix2x3::new(1.0, 2.0, 3.0, /// let lhs = Matrix2x3::new(1.0, 2.0, 3.0,
@ -971,7 +997,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{DMatrix, DVector}; /// # use nalgebra::{DMatrix, DVector};
/// // Note that all those would also work with statically-sized matrices. /// // Note that all those would also work with statically-sized matrices.
/// // We use DMatrix/DVector since that's the only case where pre-allocating the /// // We use DMatrix/DVector since that's the only case where pre-allocating the
@ -1026,7 +1051,6 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix2, Matrix3x2, Matrix3}; /// # use nalgebra::{Matrix2, Matrix3x2, Matrix3};
/// let mut mat = Matrix2::identity(); /// let mut mat = Matrix2::identity();
/// let rhs = Matrix3x2::new(1.0, 2.0, /// let rhs = Matrix3x2::new(1.0, 2.0,

View File

@ -130,8 +130,14 @@ impl<N: Real> Matrix4<N> {
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
/// `eye`. /// `eye`.
#[inline] #[inline]
pub fn face_towards(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
}
/// Deprecated: Use [Matrix4::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self { pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous() Matrix4::face_towards(eye, target, up)
} }
/// Builds a right-handed look-at view matrix. /// Builds a right-handed look-at view matrix.

View File

@ -1,4 +1,4 @@
// Non-conventional componentwise operators. // Non-conventional component-wise operators.
use num::{Signed, Zero}; use num::{Signed, Zero};
use std::ops::{Add, Mul}; use std::ops::{Add, Mul};

View File

@ -270,7 +270,7 @@ where DefaultAllocator: Allocator<N, R, C>
/// let vec_ptr = vec.as_ptr(); /// let vec_ptr = vec.as_ptr();
/// ///
/// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec); /// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), U1, vec);
/// let matrix_storage_ptr = matrix.data.as_ptr(); /// let matrix_storage_ptr = matrix.data.as_vec().as_ptr();
/// ///
/// // `matrix` is backed by exactly the same `Vec` as it was constructed from. /// // `matrix` is backed by exactly the same `Vec` as it was constructed from.
/// assert_eq!(matrix_storage_ptr, vec_ptr); /// assert_eq!(matrix_storage_ptr, vec_ptr);
@ -296,7 +296,7 @@ where
/// ///
/// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0)); /// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0));
/// // The two additional arguments represent the matrix dimensions. /// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(3, &[1.0, 2.0, 3.0])); /// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(&[1.0, 2.0, 3.0]));
/// ///
/// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 &&
/// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 && /// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 &&
@ -444,63 +444,6 @@ macro_rules! impl_constructors(
Self::from_iterator_generic($($gargs, )* iter) Self::from_iterator_generic($($gargs, )* iter)
} }
/// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_row_slice(3, &[0, 1, 2]);
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_row_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* slice)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_column_slice(3, &[0, 1, 2]);
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_column_slice($($args: usize,)* slice: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* slice)
}
/// Creates a matrix or vector filled with the results of a function applied to each of its /// Creates a matrix or vector filled with the results of a function applied to each of its
/// component coordinates. /// component coordinates.
/// ///
@ -612,32 +555,6 @@ macro_rules! impl_constructors(
) -> Self { ) -> Self {
Self::from_distribution_generic($($gargs, )* distribution, rng) Self::from_distribution_generic($($gargs, )* distribution, rng)
} }
/// Creates a matrix backed by a given `Vec`.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Matrix2x3};
///
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
///
///
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
#[cfg(feature = "std")]
pub fn from_vec($($args: usize,)* data: Vec<N>) -> Self {
Self::from_vec_generic($($gargs, )* data)
}
} }
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*> impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
@ -676,6 +593,125 @@ impl_constructors!(Dynamic, Dynamic;
Dynamic::new(nrows), Dynamic::new(ncols); Dynamic::new(nrows), Dynamic::new(ncols);
nrows, ncols); nrows, ncols);
/*
*
* Constructors that don't necessarily require all dimensions
* to be specified whon one dimension is already known.
*
*/
macro_rules! impl_constructors_from_data(
($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
impl<N: Scalar, $($DimIdent: $DimBound, )*> MatrixMN<N $(, $Dims)*>
where DefaultAllocator: Allocator<N $(, $Dims)*> {
/// Creates a matrix with its elements filled with the components provided by a slice
/// in row-major order.
///
/// The order of elements in the slice must follow the usual mathematic writing, i.e.,
/// row-by-row.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_row_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_row_slice(&[0, 1, 2]);
/// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 &&
/// m.m21 == 3 && m.m22 == 4 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 &&
/// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_row_slice($($args: usize,)* $data: &[N]) -> Self {
Self::from_row_slice_generic($($gargs, )* $data)
}
/// Creates a matrix with its elements filled with the components provided by a slice
/// in column-major order.
///
/// # Example
/// ```
/// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix};
/// # use std::iter;
///
/// let v = Vector3::from_column_slice(&[0, 1, 2]);
/// // The additional argument represents the vector dimension.
/// let dv = DVector::from_column_slice(&[0, 1, 2]);
/// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]);
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]);
///
/// assert!(v.x == 0 && v.y == 1 && v.z == 2);
/// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2);
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
pub fn from_column_slice($($args: usize,)* $data: &[N]) -> Self {
Self::from_column_slice_generic($($gargs, )* $data)
}
/// Creates a matrix backed by a given `Vec`.
///
/// The output matrix is filled column-by-column.
///
/// # Example
/// ```
/// # use nalgebra::{DMatrix, Matrix2x3};
///
/// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 &&
/// m.m21 == 1 && m.m22 == 3 && m.m23 == 5);
///
///
/// // The two additional arguments represent the matrix dimensions.
/// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]);
///
/// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 &&
/// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5);
/// ```
#[inline]
#[cfg(feature = "std")]
pub fn from_vec($($args: usize,)* $data: Vec<N>) -> Self {
Self::from_vec_generic($($gargs, )* $data)
}
}
}
);
// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors_from_data!(data; R, C; // Arguments for Matrix<N, ..., S>
=> R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
R::name(), C::name(); // Arguments for `_generic` constructors.
); // Arguments for non-generic constructors.
impl_constructors_from_data!(data; R, Dynamic;
=> R: DimName;
R::name(), Dynamic::new(data.len() / R::dim());
);
impl_constructors_from_data!(data; Dynamic, C;
=> C: DimName;
Dynamic::new(data.len() / C::dim()), C::name();
);
impl_constructors_from_data!(data; Dynamic, Dynamic;
;
Dynamic::new(nrows), Dynamic::new(ncols);
nrows, ncols);
/* /*
* *
* Zero, One, Rand traits. * Zero, One, Rand traits.

View File

@ -12,8 +12,10 @@ use typenum::Prod;
use base::allocator::{Allocator, SameShapeAllocator}; use base::allocator::{Allocator, SameShapeAllocator};
use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{ use base::dimension::{
Dim, DimName, Dynamic, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
}; };
#[cfg(any(feature = "std", feature = "alloc"))]
use base::dimension::Dynamic;
use base::iter::{MatrixIter, MatrixIterMut}; use base::iter::{MatrixIter, MatrixIterMut};
use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]

View File

@ -22,8 +22,8 @@ pub struct Dynamic {
impl Dynamic { impl Dynamic {
/// A dynamic size equal to `value`. /// A dynamic size equal to `value`.
#[inline] #[inline]
pub fn new(value: usize) -> Dynamic { pub fn new(value: usize) -> Self {
Dynamic { value: value } Self { value: value }
} }
} }
@ -80,7 +80,7 @@ impl Dim for Dynamic {
#[inline] #[inline]
fn from_usize(dim: usize) -> Self { fn from_usize(dim: usize) -> Self {
Dynamic::new(dim) Self::new(dim)
} }
#[inline] #[inline]
@ -93,8 +93,8 @@ impl Add<usize> for Dynamic {
type Output = Dynamic; type Output = Dynamic;
#[inline] #[inline]
fn add(self, rhs: usize) -> Dynamic { fn add(self, rhs: usize) -> Self {
Dynamic::new(self.value + rhs) Self::new(self.value + rhs)
} }
} }
@ -102,8 +102,8 @@ impl Sub<usize> for Dynamic {
type Output = Dynamic; type Output = Dynamic;
#[inline] #[inline]
fn sub(self, rhs: usize) -> Dynamic { fn sub(self, rhs: usize) -> Self {
Dynamic::new(self.value - rhs) Self::new(self.value - rhs)
} }
} }
@ -364,7 +364,8 @@ impl<
G: Bit + Any + Debug + Copy + PartialEq + Send + Sync, G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
> IsNotStaticOne > IsNotStaticOne
for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G> for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{} {
}
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim
for UInt<U, B> for UInt<U, B>
@ -405,4 +406,5 @@ impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Syn
impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne
for UInt<U, B> for UInt<U, B>
{} {
}

View File

@ -1,12 +1,18 @@
use num::{One, Zero}; use num::{One, Zero};
use std::cmp; use std::cmp;
use std::ptr; use std::ptr;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::iter::ExactSizeIterator;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::mem;
use base::allocator::{Allocator, Reallocator}; use base::allocator::{Allocator, Reallocator};
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{ use base::dimension::{
Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, Dynamic, U1, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1,
}; };
#[cfg(any(feature = "std", feature = "alloc"))]
use base::dimension::Dynamic;
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
use base::DMatrix; use base::DMatrix;
@ -23,7 +29,7 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res res
} }
/// Extracts the upper triangular part of this matrix (including the diagonal). /// Extracts the lower triangular part of this matrix (including the diagonal).
#[inline] #[inline]
pub fn lower_triangle(&self) -> MatrixMN<N, R, C> pub fn lower_triangle(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> { where DefaultAllocator: Allocator<N, R, C> {
@ -32,6 +38,54 @@ impl<N: Scalar + Zero, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res res
} }
/// Creates a new matrix by extracting the given set of rows from `self`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn select_rows<'a, I>(&self, irows: I) -> MatrixMN<N, Dynamic, C>
where I: IntoIterator<Item = &'a usize>,
I::IntoIter: ExactSizeIterator + Clone,
DefaultAllocator: Allocator<N, Dynamic, C> {
let irows = irows.into_iter();
let ncols = self.data.shape().1;
let mut res = unsafe { MatrixMN::new_uninitialized_generic(Dynamic::new(irows.len()), ncols) };
// First, check that all the indices from irows are valid.
// This will allow us to use unchecked access in the inner loop.
for i in irows.clone() {
assert!(*i < self.nrows(), "Row index out of bounds.")
}
for j in 0..ncols.value() {
// FIXME: use unchecked column indexing
let mut res = res.column_mut(j);
let mut src = self.column(j);
for (destination, source) in irows.clone().enumerate() {
unsafe {
*res.vget_unchecked_mut(destination) = *src.vget_unchecked(*source)
}
}
}
res
}
/// Creates a new matrix by extracting the given set of columns from `self`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn select_columns<'a, I>(&self, icols: I) -> MatrixMN<N, R, Dynamic>
where I: IntoIterator<Item = &'a usize>,
I::IntoIter: ExactSizeIterator,
DefaultAllocator: Allocator<N, R, Dynamic> {
let icols = icols.into_iter();
let nrows = self.data.shape().0;
let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, Dynamic::new(icols.len())) };
for (destination, source) in icols.enumerate() {
res.column_mut(destination).copy_from(&self.column(*source))
}
res
}
} }
impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
@ -248,6 +302,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included). /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included).
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic> pub fn remove_columns(self, i: usize, n: usize) -> MatrixMN<N, R, Dynamic>
where where
C: DimSub<Dynamic, Output = Dynamic>, C: DimSub<Dynamic, Output = Dynamic>,
@ -330,6 +385,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included). /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included).
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C> pub fn remove_rows(self, i: usize, n: usize) -> MatrixMN<N, Dynamic, C>
where where
R: DimSub<Dynamic, Output = Dynamic>, R: DimSub<Dynamic, Output = Dynamic>,
@ -407,6 +463,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Inserts `n` columns filled with `val` starting at the `i-th` position. /// Inserts `n` columns filled with `val` starting at the `i-th` position.
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic> pub fn insert_columns(self, i: usize, n: usize, val: N) -> MatrixMN<N, R, Dynamic>
where where
C: DimAdd<Dynamic, Output = Dynamic>, C: DimAdd<Dynamic, Output = Dynamic>,
@ -484,6 +541,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Inserts `n` rows filled with `val` starting at the `i-th` position. /// Inserts `n` rows filled with `val` starting at the `i-th` position.
#[inline] #[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C> pub fn insert_rows(self, i: usize, n: usize, val: N) -> MatrixMN<N, Dynamic, C>
where where
R: DimAdd<Dynamic, Output = Dynamic>, R: DimAdd<Dynamic, Output = Dynamic>,
@ -549,6 +607,29 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val)
} }
/// Resizes this matrix vertically, i.e., so that it contains `new_nrows` rows while keeping the same number of columns.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// rows than `self`, then the extra rows are filled with `val`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_vertically(self, new_nrows: usize, val: N) -> MatrixMN<N, Dynamic, C>
where DefaultAllocator: Reallocator<N, R, C, Dynamic, C> {
let ncols = self.data.shape().1;
self.resize_generic(Dynamic::new(new_nrows), ncols, val)
}
/// Resizes this matrix horizontally, i.e., so that it contains `new_ncolumns` columns while keeping the same number of columns.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// columns than `self`, then the extra columns are filled with `val`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_horizontally(self, new_ncols: usize, val: N) -> MatrixMN<N, R, Dynamic>
where DefaultAllocator: Reallocator<N, R, C, R, Dynamic> {
let nrows = self.data.shape().0;
self.resize_generic(nrows, Dynamic::new(new_ncols), val)
}
/// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns.
/// ///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
@ -626,6 +707,61 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar> DMatrix<N> {
/// Resizes this matrix in-place.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
///
/// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`.
pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: N)
where DefaultAllocator: Reallocator<N, Dynamic, Dynamic, Dynamic, Dynamic> {
let placeholder = unsafe { Self::new_uninitialized(0, 0) };
let old = mem::replace(self, placeholder);
let new = old.resize(new_nrows, new_ncols, val);
let _ = mem::replace(self, new);
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, C: Dim> MatrixMN<N, Dynamic, C>
where DefaultAllocator: Allocator<N, Dynamic, C> {
/// Changes the number of rows of this matrix in-place.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// rows than `self`, then the extra rows are filled with `val`.
///
/// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`).
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: N)
where DefaultAllocator: Reallocator<N, Dynamic, C, Dynamic, C> {
let placeholder = unsafe { Self::new_uninitialized_generic(Dynamic::new(0), self.data.shape().1) };
let old = mem::replace(self, placeholder);
let new = old.resize_vertically(new_nrows, val);
let _ = mem::replace(self, new);
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N: Scalar, R: Dim> MatrixMN<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic> {
/// Changes the number of column of this matrix in-place.
///
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
/// columns than `self`, then the extra columns are filled with `val`.
///
/// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`).
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: N)
where DefaultAllocator: Reallocator<N, R, Dynamic, R, Dynamic> {
let placeholder = unsafe { Self::new_uninitialized_generic(self.data.shape().0, Dynamic::new(0)) };
let old = mem::replace(self, placeholder);
let new = old.resize_horizontally(new_ncols, val);
let _ = mem::replace(self, new);
}
}
unsafe fn compress_rows<N: Scalar>( unsafe fn compress_rows<N: Scalar>(
data: &mut [N], data: &mut [N],
nrows: usize, nrows: usize,
@ -706,6 +842,7 @@ unsafe fn extend_rows<N: Scalar>(
/// Extend the number of columns of the `Matrix` with elements from /// Extend the number of columns of the `Matrix` with elements from
/// a given iterator. /// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S> impl<N, R, S> Extend<N> for Matrix<N, R, Dynamic, S>
where where
N: Scalar, N: Scalar,
@ -753,6 +890,7 @@ where
/// Extend the number of rows of the `Vector` with elements from /// Extend the number of rows of the `Vector` with elements from
/// a given iterator. /// a given iterator.
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S> impl<N, S> Extend<N> for Matrix<N, Dynamic, U1, S>
where where
N: Scalar, N: Scalar,
@ -764,15 +902,16 @@ where
/// # Example /// # Example
/// ``` /// ```
/// # use nalgebra::DVector; /// # use nalgebra::DVector;
/// let mut vector = DVector::from_vec(3, vec![0, 1, 2]); /// let mut vector = DVector::from_vec(vec![0, 1, 2]);
/// vector.extend(vec![3, 4, 5]); /// vector.extend(vec![3, 4, 5]);
/// assert!(vector.eq(&DVector::from_vec(6, vec![0, 1, 2, 3, 4, 5]))); /// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5])));
/// ``` /// ```
fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) { fn extend<I: IntoIterator<Item=N>>(&mut self, iter: I) {
self.data.extend(iter); self.data.extend(iter);
} }
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S> impl<N, R, S, RV, SV> Extend<Vector<N, RV, SV>> for Matrix<N, R, Dynamic, S>
where where
N: Scalar, N: Scalar,

View File

@ -711,4 +711,4 @@ impl_index_pairs!{
=> DimDiff<C, J> => DimDiff<C, J>
where C: DimSub<J>], where C: DimSub<J>],
} }
} }

View File

@ -3,9 +3,9 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use base::dimension::Dim; use base::dimension::{Dim, U1};
use base::storage::{Storage, StorageMut}; use base::storage::{Storage, StorageMut};
use base::Scalar; use base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut};
macro_rules! iterator { macro_rules! iterator {
(struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => {
@ -96,3 +96,226 @@ macro_rules! iterator {
iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S); iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S);
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S); iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S);
/*
*
* Row iterators.
*
*/
#[derive(Clone)]
/// An iterator through the rows of a matrix.
pub struct RowIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
mat: &'a Matrix<N, R, C, S>,
curr: usize
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> RowIter<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
RowIter {
mat, curr: 0
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for RowIter<'a, N, R, C, S> {
type Item = MatrixSlice<'a, N, U1, C, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.mat.nrows() {
let res = self.mat.row(self.curr);
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.mat.nrows() - self.curr, Some(self.mat.nrows() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.mat.nrows() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for RowIter<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.mat.nrows() - self.curr
}
}
/// An iterator through the mutable rows of a matrix.
pub struct RowIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
mat: *mut Matrix<N, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> RowIterMut<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
RowIterMut {
mat,
curr: 0,
phantom: PhantomData
}
}
fn nrows(&self) -> usize {
unsafe {
(*self.mat).nrows()
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for RowIterMut<'a, N, R, C, S> {
type Item = MatrixSliceMut<'a, N, U1, C, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.nrows() {
let res = unsafe { (*self.mat).row_mut(self.curr) };
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.nrows() - self.curr, Some(self.nrows() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.nrows() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for RowIterMut<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.nrows() - self.curr
}
}
/*
*
* Column iterators.
*
*/
#[derive(Clone)]
/// An iterator through the columns of a matrix.
pub struct ColumnIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> {
mat: &'a Matrix<N, R, C, S>,
curr: usize
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ColumnIter<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<N, R, C, S>) -> Self {
ColumnIter {
mat, curr: 0
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> Iterator for ColumnIter<'a, N, R, C, S> {
type Item = MatrixSlice<'a, N, R, U1, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.mat.ncols() {
let res = self.mat.column(self.curr);
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.mat.ncols() - self.curr, Some(self.mat.ncols() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.mat.ncols() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage<N, R, C>> ExactSizeIterator for ColumnIter<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.mat.ncols() - self.curr
}
}
/// An iterator through the mutable columns of a matrix.
pub struct ColumnIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> {
mat: *mut Matrix<N, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<N, R, C, S>>
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ColumnIterMut<'a, N, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<N, R, C, S>) -> Self {
ColumnIterMut {
mat,
curr: 0,
phantom: PhantomData
}
}
fn ncols(&self) -> usize {
unsafe {
(*self.mat).ncols()
}
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> Iterator for ColumnIterMut<'a, N, R, C, S> {
type Item = MatrixSliceMut<'a, N, R, U1, S::RStride, S::CStride>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr < self.ncols() {
let res = unsafe { (*self.mat).column_mut(self.curr) };
self.curr += 1;
Some(res)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.ncols() - self.curr, Some(self.ncols() - self.curr))
}
#[inline]
fn count(self) -> usize {
self.ncols() - self.curr
}
}
impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<N, R, C>> ExactSizeIterator for ColumnIterMut<'a, N, R, C, S> {
#[inline]
fn len(&self) -> usize {
self.ncols() - self.curr
}
}

View File

@ -22,7 +22,7 @@ use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Real, Ring};
use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3}; use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3};
use base::iter::{MatrixIter, MatrixIterMut}; use base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut};
use base::storage::{ use base::storage::{
ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut,
}; };
@ -152,7 +152,7 @@ impl<N: Scalar, R: Dim, C: Dim, S> Matrix<N, R, C, S> {
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Creates a new matrix with the given data. /// Creates a new matrix with the given data.
#[inline] #[inline]
pub fn from_data(data: S) -> Matrix<N, R, C, S> { pub fn from_data(data: S) -> Self {
unsafe { Self::from_data_statically_unchecked(data) } unsafe { Self::from_data_statically_unchecked(data) }
} }
@ -247,6 +247,37 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
MatrixIter::new(&self.data) MatrixIter::new(&self.data)
} }
/// Iterate through the rows of this matrix.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, row) in a.row_iter().enumerate() {
/// assert_eq!(row, a.row(i))
/// }
/// ```
#[inline]
pub fn row_iter(&self) -> RowIter<N, R, C, S> {
RowIter::new(self)
}
/// Iterate through the columns of this matrix.
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, column) in a.column_iter().enumerate() {
/// assert_eq!(column, a.column(i))
/// }
/// ```
#[inline]
pub fn column_iter(&self) -> ColumnIter<N, R, C, S> {
ColumnIter::new(self)
}
/// Computes the row and column coordinates of the i-th element of this matrix seen as a /// Computes the row and column coordinates of the i-th element of this matrix seen as a
/// vector. /// vector.
#[inline] #[inline]
@ -264,6 +295,15 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
} }
/// Returns a pointer to the start of the matrix.
///
/// If the matrix is not empty, this pointer is guaranteed to be aligned
/// and non-null.
#[inline]
pub fn as_ptr(&self) -> *const N {
self.data.ptr()
}
/// Tests whether `self` and `rhs` are equal up to a given epsilon. /// Tests whether `self` and `rhs` are equal up to a given epsilon.
/// ///
/// See `relative_eq` from the `RelativeEq` trait for more details. /// See `relative_eq` from the `RelativeEq` trait for more details.
@ -393,7 +433,7 @@ 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(row, col, value)`.
#[inline] #[inline]
pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>( pub fn map_with_location<N2: Scalar, F: FnMut(usize, usize, N) -> N2>(
&self, &self,
@ -493,6 +533,57 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
res res
} }
/// Folds a function `f` on each entry of `self`.
#[inline]
pub fn fold<Acc>(&self, init: Acc, mut f: impl FnMut(Acc, N) -> Acc) -> Acc {
let (nrows, ncols) = self.data.shape();
let mut res = init;
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = *self.data.get_unchecked(i, j);
res = f(res, a)
}
}
}
res
}
/// Folds a function `f` on each pairs of entries from `self` and `rhs`.
#[inline]
pub fn zip_fold<N2, R2, C2, S2, Acc>(&self, rhs: &Matrix<N2, R2, C2, S2>, init: Acc, mut f: impl FnMut(Acc, N, N2) -> Acc) -> Acc
where
N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>
{
let (nrows, ncols) = self.data.shape();
let mut res = init;
assert!(
(nrows.value(), ncols.value()) == rhs.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe {
let a = *self.data.get_unchecked(i, j);
let b = *rhs.data.get_unchecked(i, j);
res = f(res, a, b)
}
}
}
res
}
/// Transposes `self` and store the result into `out`. /// Transposes `self` and store the result into `out`.
#[inline] #[inline]
pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>) pub fn transpose_to<R2, C2, SB>(&self, out: &mut Matrix<N, R2, C2, SB>)
@ -540,6 +631,55 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
MatrixIterMut::new(&mut self.data) MatrixIterMut::new(&mut self.data)
} }
/// Returns a mutable pointer to the start of the matrix.
///
/// If the matrix is not empty, this pointer is guaranteed to be aligned
/// and non-null.
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut N {
self.data.ptr_mut()
}
/// Mutably iterates through this matrix rows.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, mut row) in a.row_iter_mut().enumerate() {
/// row *= (i + 1) * 10;
/// }
///
/// let expected = Matrix2x3::new(10, 20, 30,
/// 80, 100, 120);
/// assert_eq!(a, expected);
/// ```
#[inline]
pub fn row_iter_mut(&mut self) -> RowIterMut<N, R, C, S> {
RowIterMut::new(self)
}
/// Mutably iterates through this matrix columns.
///
/// # Example
/// ```
/// # use nalgebra::Matrix2x3;
/// let mut a = Matrix2x3::new(1, 2, 3,
/// 4, 5, 6);
/// for (i, mut col) in a.column_iter_mut().enumerate() {
/// col *= (i + 1) * 10;
/// }
///
/// let expected = Matrix2x3::new(10, 40, 90,
/// 40, 100, 180);
/// assert_eq!(a, expected);
/// ```
#[inline]
pub fn column_iter_mut(&mut self) -> ColumnIterMut<N, R, C, S> {
ColumnIterMut::new(self)
}
/// Swaps two entries without bound-checking. /// Swaps two entries without bound-checking.
#[inline] #[inline]
pub unsafe fn swap_unchecked(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) { pub unsafe fn swap_unchecked(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) {
@ -633,8 +773,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// Replaces each component of `self` by the result of a closure `f` applied on it. /// Replaces each component of `self` by the result of a closure `f` applied on it.
#[inline] #[inline]
pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) pub fn apply<F: FnMut(N) -> N>(&mut self, mut f: F) {
where DefaultAllocator: Allocator<N, R, C> {
let (nrows, ncols) = self.shape(); let (nrows, ncols) = self.shape();
for j in 0..ncols { for j in 0..ncols {
@ -646,6 +785,71 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
} }
} }
} }
/// Replaces each component of `self` by the result of a closure `f` applied on its components
/// joined with the components from `rhs`.
#[inline]
pub fn zip_apply<N2, R2, C2, S2>(&mut self, rhs: &Matrix<N2, R2, C2, S2>, mut f: impl FnMut(N, N2) -> N)
where N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
let (nrows, ncols) = self.shape();
assert!(
(nrows, ncols) == rhs.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
let e = self.data.get_unchecked_mut(i, j);
let rhs = rhs.get_unchecked((i, j));
*e = f(*e, *rhs)
}
}
}
}
/// Replaces each component of `self` by the result of a closure `f` applied on its components
/// joined with the components from `b` and `c`.
#[inline]
pub fn zip_zip_apply<N2, R2, C2, S2, N3, R3, C3, S3>(&mut self, b: &Matrix<N2, R2, C2, S2>, c: &Matrix<N3, R3, C3, S3>, mut f: impl FnMut(N, N2, N3) -> N)
where N2: Scalar,
R2: Dim,
C2: Dim,
S2: Storage<N2, R2, C2>,
N3: Scalar,
R3: Dim,
C3: Dim,
S3: Storage<N3, R3, C3>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
let (nrows, ncols) = self.shape();
assert!(
(nrows, ncols) == b.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
assert!(
(nrows, ncols) == c.shape(),
"Matrix simultaneous traversal error: dimension mismatch."
);
for j in 0..ncols {
for i in 0..nrows {
unsafe {
let e = self.data.get_unchecked_mut(i, j);
let b = b.get_unchecked((i, j));
let c = c.get_unchecked((i, j));
*e = f(*e, *b, *c)
}
}
}
}
} }
impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> { impl<N: Scalar, D: Dim, S: Storage<N, D>> Vector<N, D, S> {
@ -832,14 +1036,7 @@ impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
#[inline] #[inline]
pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>> pub fn to_homogeneous(&self) -> VectorN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>> { where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
let len = self.len(); self.push(N::zero())
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
res.generic_slice_mut((0, 0), self.data.shape())
.copy_from(self);
res[(len, 0)] = N::zero();
res
} }
/// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of /// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
@ -859,6 +1056,22 @@ impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
} }
} }
impl<N: Scalar + Zero, D: DimAdd<U1>, S: Storage<N, D>> Vector<N, D, S> {
/// Constructs a new vector of higher dimension by appending `element` to the end of `self`.
#[inline]
pub fn push(&self, element: N) -> VectorN<N, DimSum<D, U1>>
where DefaultAllocator: Allocator<N, DimSum<D, U1>> {
let len = self.len();
let hnrows = DimSum::<D, U1>::from_usize(len + 1);
let mut res = unsafe { VectorN::<N, _>::new_uninitialized_generic(hnrows, U1) };
res.generic_slice_mut((0, 0), self.data.shape())
.copy_from(self);
res[(len, 0)] = element;
res
}
}
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S> impl<N, R: Dim, C: Dim, S> AbsDiffEq for Matrix<N, R, C, S>
where where
N: Scalar + AbsDiffEq, N: Scalar + AbsDiffEq,
@ -1242,67 +1455,6 @@ impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
} }
} }
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// The squared L2 norm of this vector.
#[inline]
pub fn norm_squared(&self) -> N {
let mut res = N::zero();
for i in 0..self.ncols() {
let col = self.column(i);
res += col.dot(&col)
}
res
}
/// The L2 norm of this matrix.
#[inline]
pub fn norm(&self) -> N {
self.norm_squared().sqrt()
}
/// A synonym for the norm of this matrix.
///
/// Aka the length.
///
/// This function is simply implemented as a call to `norm()`
#[inline]
pub fn magnitude(&self) -> N {
self.norm()
}
/// A synonym for the squared norm of this matrix.
///
/// Aka the squared length.
///
/// This function is simply implemented as a call to `norm_squared()`
#[inline]
pub fn magnitude_squared(&self) -> N {
self.norm_squared()
}
/// Returns a normalized version of this matrix.
#[inline]
pub fn normalize(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self / self.norm()
}
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
#[inline]
pub fn try_normalize(&self, min_norm: N) -> Option<MatrixMN<N, R, C>>
where DefaultAllocator: Allocator<N, R, C> {
let n = self.norm();
if n <= min_norm {
None
} else {
Some(self / n)
}
}
}
impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>> impl<N: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<N, D>>
Vector<N, D, S> Vector<N, D, S>
{ {
@ -1377,32 +1529,6 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Unit<Vector<N, D, S>> {
} }
} }
impl<N: Real, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// Normalizes this matrix in-place and returns its norm.
#[inline]
pub fn normalize_mut(&mut self) -> N {
let n = self.norm();
*self /= n;
n
}
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
///
/// If the normalization succeeded, returns the old normal of this matrix.
#[inline]
pub fn try_normalize_mut(&mut self, min_norm: N) -> Option<N> {
let n = self.norm();
if n <= min_norm {
None
} else {
*self /= n;
Some(n)
}
}
}
impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>> impl<N, R: Dim, C: Dim, S> AbsDiffEq for Unit<Matrix<N, R, C, S>>
where where
N: Scalar + AbsDiffEq, N: Scalar + AbsDiffEq,

View File

@ -6,7 +6,7 @@ use num::{One, Zero};
use alga::general::{ use alga::general::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul,
ClosedNeg, Field, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice, Module, ClosedNeg, Field, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice, Module,
Multiplicative, Real, RingCommutative, Multiplicative, Real, RingCommutative,
}; };
use alga::linear::{ use alga::linear::{
@ -45,18 +45,18 @@ where
} }
} }
impl<N, R: DimName, C: DimName> Inverse<Additive> for MatrixMN<N, R, C> impl<N, R: DimName, C: DimName> TwoSidedInverse<Additive> for MatrixMN<N, R, C>
where where
N: Scalar + ClosedNeg, N: Scalar + ClosedNeg,
DefaultAllocator: Allocator<N, R, C>, DefaultAllocator: Allocator<N, R, C>,
{ {
#[inline] #[inline]
fn inverse(&self) -> MatrixMN<N, R, C> { fn two_sided_inverse(&self) -> Self {
-self -self
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
*self = -self.clone() *self = -self.clone()
} }
} }
@ -203,7 +203,7 @@ impl<N: Real, R: DimName, C: DimName> FiniteDimInnerSpace for MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> where DefaultAllocator: Allocator<N, R, C>
{ {
#[inline] #[inline]
fn orthonormalize(vs: &mut [MatrixMN<N, R, C>]) -> usize { fn orthonormalize(vs: &mut [Self]) -> usize {
let mut nbasis_elements = 0; let mut nbasis_elements = 0;
for i in 0..vs.len() { for i in 0..vs.len() {

View File

@ -4,9 +4,9 @@ use std::slice;
use base::allocator::Allocator; use base::allocator::Allocator;
use base::default_allocator::DefaultAllocator; use base::default_allocator::DefaultAllocator;
use base::dimension::{Dim, DimName, Dynamic, U1}; use base::dimension::{Dim, DimName, Dynamic, U1, IsNotStaticOne};
use base::iter::MatrixIter; use base::iter::MatrixIter;
use base::storage::{Owned, Storage, StorageMut}; use base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut};
use base::{Matrix, Scalar}; use base::{Matrix, Scalar};
macro_rules! slice_storage_impl( macro_rules! slice_storage_impl(
@ -91,14 +91,15 @@ slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Onl
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
for SliceStorage<'a, N, R, C, RStride, CStride> for SliceStorage<'a, N, R, C, RStride, CStride>
{} {
}
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
for SliceStorage<'a, N, R, C, RStride, CStride> for SliceStorage<'a, N, R, C, RStride, CStride>
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
SliceStorage { Self {
ptr: self.ptr, ptr: self.ptr,
shape: self.shape, shape: self.shape,
strides: self.strides, strides: self.strides,
@ -146,8 +147,6 @@ macro_rules! storage_impl(
} }
} }
#[inline] #[inline]
fn into_owned(self) -> Owned<N, R, C> fn into_owned(self) -> Owned<N, R, C>
where DefaultAllocator: Allocator<N, R, C> { where DefaultAllocator: Allocator<N, R, C> {
@ -199,6 +198,14 @@ unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMu
} }
} }
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage<N, R, U1> for SliceStorage<'a, N, R, U1, U1, CStride> { }
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage<N, R, U1> for SliceStorageMut<'a, N, R, U1, U1, CStride> { }
unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorageMut<N, R, U1> for SliceStorageMut<'a, N, R, U1, U1, CStride> { }
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<N, R, C> for SliceStorage<'a, N, R, C, U1, R> { }
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<N, R, C> for SliceStorageMut<'a, N, R, C, U1, R> { }
unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<N, R, C> for SliceStorageMut<'a, N, R, C, U1, R> { }
impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
#[inline] #[inline]
fn assert_slice_index( fn assert_slice_index(
@ -859,3 +866,25 @@ impl<N: Scalar, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
self.slice_range_mut(.., cols) self.slice_range_mut(.., cols)
} }
} }
impl<'a, N, R, C, RStride, CStride> From<MatrixSliceMut<'a, N, R, C, RStride, CStride>>
for MatrixSlice<'a, N, R, C, RStride, CStride>
where
N: Scalar,
R: Dim,
C: Dim,
RStride: Dim,
CStride: Dim,
{
fn from(slice_mut: MatrixSliceMut<'a, N, R, C, RStride, CStride>) -> Self {
let data = SliceStorage {
ptr: slice_mut.data.ptr,
shape: slice_mut.data.shape,
strides: slice_mut.data.strides,
_phantoms: PhantomData,
};
unsafe { Matrix::from_data_statically_unchecked(data) }
}
}

View File

@ -29,6 +29,8 @@ mod properties;
mod scalar; mod scalar;
mod swizzle; mod swizzle;
mod unit; mod unit;
mod statistics;
mod norm;
#[doc(hidden)] #[doc(hidden)]
pub mod helper; pub mod helper;
@ -36,6 +38,7 @@ pub mod helper;
pub use self::matrix::*; pub use self::matrix::*;
pub use self::scalar::*; pub use self::scalar::*;
pub use self::unit::*; pub use self::unit::*;
pub use self::norm::*;
pub use self::default_allocator::*; pub use self::default_allocator::*;
pub use self::dimension::*; pub use self::dimension::*;

238
src/base/norm.rs Normal file
View File

@ -0,0 +1,238 @@
use num::Signed;
use std::cmp::PartialOrd;
use allocator::Allocator;
use ::{Real, Scalar};
use storage::{Storage, StorageMut};
use base::{DefaultAllocator, Matrix, Dim, MatrixMN};
use constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint};
// FIXME: this should be be a trait on alga?
/// A trait for abstract matrix norms.
///
/// This may be moved to the alga crate in the future.
pub trait Norm<N: Scalar> {
/// Apply this norm to the given matrix.
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C>;
/// Use the metric induced by this norm to compute the metric distance between the two given matrices.
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>;
}
/// Euclidean norm.
pub struct EuclideanNorm;
/// Lp norm.
pub struct LpNorm(pub i32);
/// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm.
pub struct UniformNorm;
impl<N: Real> Norm<N> for EuclideanNorm {
#[inline]
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C> {
m.norm_squared().sqrt()
}
#[inline]
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
m1.zip_fold(m2, N::zero(), |acc, a, b| {
let diff = a - b;
acc + diff * diff
}).sqrt()
}
}
impl<N: Real> Norm<N> for LpNorm {
#[inline]
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C> {
m.fold(N::zero(), |a, b| {
a + b.abs().powi(self.0)
}).powf(::convert(1.0 / (self.0 as f64)))
}
#[inline]
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
m1.zip_fold(m2, N::zero(), |acc, a, b| {
let diff = a - b;
acc + diff.abs().powi(self.0)
}).powf(::convert(1.0 / (self.0 as f64)))
}
}
impl<N: Scalar + PartialOrd + Signed> Norm<N> for UniformNorm {
#[inline]
fn norm<R, C, S>(&self, m: &Matrix<N, R, C, S>) -> N
where R: Dim, C: Dim, S: Storage<N, R, C> {
m.amax()
}
#[inline]
fn metric_distance<R1, C1, S1, R2, C2, S2>(&self, m1: &Matrix<N, R1, C1, S1>, m2: &Matrix<N, R2, C2, S2>) -> N
where R1: Dim, C1: Dim, S1: Storage<N, R1, C1>,
R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
m1.zip_fold(m2, N::zero(), |acc, a, b| {
let val = (a - b).abs();
if val > acc {
val
} else {
acc
}
})
}
}
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// The squared L2 norm of this vector.
#[inline]
pub fn norm_squared(&self) -> N {
let mut res = N::zero();
for i in 0..self.ncols() {
let col = self.column(i);
res += col.dot(&col)
}
res
}
/// The L2 norm of this matrix.
///
/// Use `.apply_norm` to apply a custom norm.
#[inline]
pub fn norm(&self) -> N {
self.norm_squared().sqrt()
}
/// Compute the distance between `self` and `rhs` using the metric induced by the euclidean norm.
///
/// Use `.apply_metric_distance` to apply a custom norm.
#[inline]
pub fn metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>) -> N
where R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
self.apply_metric_distance(rhs, &EuclideanNorm)
}
/// Uses the given `norm` to compute the norm of `self`.
///
/// # Example
///
/// ```
/// # use nalgebra::{Vector3, UniformNorm, LpNorm, EuclideanNorm};
///
/// let v = Vector3::new(1.0, 2.0, 3.0);
/// assert_eq!(v.apply_norm(&UniformNorm), 3.0);
/// assert_eq!(v.apply_norm(&LpNorm(1)), 6.0);
/// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm());
/// ```
#[inline]
pub fn apply_norm(&self, norm: &impl Norm<N>) -> N {
norm.norm(self)
}
/// Uses the metric induced by the given `norm` to compute the metric distance between `self` and `rhs`.
///
/// # Example
///
/// ```
/// # use nalgebra::{Vector3, UniformNorm, LpNorm, EuclideanNorm};
///
/// let v1 = Vector3::new(1.0, 2.0, 3.0);
/// let v2 = Vector3::new(10.0, 20.0, 30.0);
///
/// assert_eq!(v1.apply_metric_distance(&v2, &UniformNorm), 27.0);
/// assert_eq!(v1.apply_metric_distance(&v2, &LpNorm(1)), 27.0 + 18.0 + 9.0);
/// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm());
/// ```
#[inline]
pub fn apply_metric_distance<R2, C2, S2>(&self, rhs: &Matrix<N, R2, C2, S2>, norm: &impl Norm<N>) -> N
where R2: Dim, C2: Dim, S2: Storage<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<R, R2> + SameNumberOfColumns<C, C2> {
norm.metric_distance(self,rhs)
}
/// The Lp norm of this matrix.
#[inline]
pub fn lp_norm(&self, p: i32) -> N {
self.apply_norm(&LpNorm(p))
}
/// A synonym for the norm of this matrix.
///
/// Aka the length.
///
/// This function is simply implemented as a call to `norm()`
#[inline]
pub fn magnitude(&self) -> N {
self.norm()
}
/// A synonym for the squared norm of this matrix.
///
/// Aka the squared length.
///
/// This function is simply implemented as a call to `norm_squared()`
#[inline]
pub fn magnitude_squared(&self) -> N {
self.norm_squared()
}
/// Returns a normalized version of this matrix.
#[inline]
pub fn normalize(&self) -> MatrixMN<N, R, C>
where DefaultAllocator: Allocator<N, R, C> {
self / self.norm()
}
/// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`.
#[inline]
pub fn try_normalize(&self, min_norm: N) -> Option<MatrixMN<N, R, C>>
where DefaultAllocator: Allocator<N, R, C> {
let n = self.norm();
if n <= min_norm {
None
} else {
Some(self / n)
}
}
}
impl<N: Real, R: Dim, C: Dim, S: StorageMut<N, R, C>> Matrix<N, R, C, S> {
/// Normalizes this matrix in-place and returns its norm.
#[inline]
pub fn normalize_mut(&mut self) -> N {
let n = self.norm();
*self /= n;
n
}
/// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`.
///
/// If the normalization succeeded, returns the old normal of this matrix.
#[inline]
pub fn try_normalize_mut(&mut self, min_norm: N) -> Option<N> {
let n = self.norm();
if n <= min_norm {
None
} else {
*self /= n;
Some(n)
}
}
}

View File

@ -11,7 +11,7 @@ use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
use base::constraint::{ use base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
}; };
use base::dimension::{Dim, DimMul, DimName, DimProd}; use base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic};
use base::storage::{ContiguousStorageMut, Storage, StorageMut}; use base::storage::{ContiguousStorageMut, Storage, StorageMut};
use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, MatrixSum, Scalar}; use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, MatrixSum, Scalar};
@ -24,7 +24,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Index<usize> for Matrix<N,
type Output = N; type Output = N;
#[inline] #[inline]
fn index(&self, i: usize) -> &N { fn index(&self, i: usize) -> &Self::Output {
let ij = self.vector_to_matrix_index(i); let ij = self.vector_to_matrix_index(i);
&self[ij] &self[ij]
} }
@ -38,7 +38,7 @@ where
type Output = N; type Output = N;
#[inline] #[inline]
fn index(&self, ij: (usize, usize)) -> &N { fn index(&self, ij: (usize, usize)) -> &Self::Output {
let shape = self.shape(); let shape = self.shape();
assert!( assert!(
ij.0 < shape.0 && ij.1 < shape.1, ij.0 < shape.0 && ij.1 < shape.1,
@ -384,6 +384,36 @@ where
} }
} }
impl<N, C: Dim> iter::Sum for MatrixMN<N, Dynamic, C>
where
N: Scalar + ClosedAdd + Zero,
DefaultAllocator: Allocator<N, Dynamic, C>,
{
/// # Example
/// ```
/// # use nalgebra::DVector;
/// assert_eq!(vec![DVector::repeat(3, 1.0f64),
/// DVector::repeat(3, 1.0f64),
/// DVector::repeat(3, 1.0f64)].into_iter().sum::<DVector<f64>>(),
/// DVector::repeat(3, 1.0f64) + DVector::repeat(3, 1.0f64) + DVector::repeat(3, 1.0f64));
/// ```
///
/// # Panics
/// Panics if the iterator is empty:
/// ```should_panic
/// # use std::iter;
/// # use nalgebra::DMatrix;
/// iter::empty::<DMatrix<f64>>().sum::<DMatrix<f64>>(); // panics!
/// ```
fn sum<I: Iterator<Item = MatrixMN<N, Dynamic, C>>>(mut iter: I) -> MatrixMN<N, Dynamic, C> {
if let Some(first) = iter.next() {
iter.fold(first, |acc, x| acc + x)
} else {
panic!("Cannot compute `sum` of empty iterator.")
}
}
}
impl<'a, N, R: DimName, C: DimName> iter::Sum<&'a MatrixMN<N, R, C>> for MatrixMN<N, R, C> impl<'a, N, R: DimName, C: DimName> iter::Sum<&'a MatrixMN<N, R, C>> for MatrixMN<N, R, C>
where where
N: Scalar + ClosedAdd + Zero, N: Scalar + ClosedAdd + Zero,
@ -394,6 +424,36 @@ where
} }
} }
impl<'a, N, C: Dim> iter::Sum<&'a MatrixMN<N, Dynamic, C>> for MatrixMN<N, Dynamic, C>
where
N: Scalar + ClosedAdd + Zero,
DefaultAllocator: Allocator<N, Dynamic, C>,
{
/// # Example
/// ```
/// # use nalgebra::DVector;
/// let v = &DVector::repeat(3, 1.0f64);
///
/// assert_eq!(vec![v, v, v].into_iter().sum::<DVector<f64>>(),
/// v + v + v);
/// ```
///
/// # Panics
/// Panics if the iterator is empty:
/// ```should_panic
/// # use std::iter;
/// # use nalgebra::DMatrix;
/// iter::empty::<&DMatrix<f64>>().sum::<DMatrix<f64>>(); // panics!
/// ```
fn sum<I: Iterator<Item = &'a MatrixMN<N, Dynamic, C>>>(mut iter: I) -> MatrixMN<N, Dynamic, C> {
if let Some(first) = iter.next() {
iter.fold(first.clone(), |acc, x| acc + x)
} else {
panic!("Cannot compute `sum` of empty iterator.")
}
}
}
/* /*
* *
* Multiplication * Multiplication
@ -761,7 +821,7 @@ where
} }
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> {
/// Returns the absolute value of the coefficient with the largest absolute value. /// Returns the absolute value of the component with the largest absolute value.
#[inline] #[inline]
pub fn amax(&self) -> N { pub fn amax(&self) -> N {
let mut max = N::zero(); let mut max = N::zero();
@ -777,7 +837,7 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
max max
} }
/// Returns the absolute value of the coefficient with the smallest absolute value. /// Returns the absolute value of the component with the smallest absolute value.
#[inline] #[inline]
pub fn amin(&self) -> N { pub fn amin(&self) -> N {
let mut it = self.iter(); let mut it = self.iter();
@ -796,4 +856,42 @@ impl<N: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<N, R, C>> Matri
min min
} }
/// Returns the component with the largest value.
#[inline]
pub fn max(&self) -> N {
let mut it = self.iter();
let mut max = it
.next()
.expect("max: empty matrices not supported.");
for e in it {
let ae = e;
if ae > max {
max = ae;
}
}
*max
}
/// Returns the component with the smallest value.
#[inline]
pub fn min(&self) -> N {
let mut it = self.iter();
let mut min = it
.next()
.expect("min: empty matrices not supported.");
for e in it {
let ae = e;
if ae < min {
min = ae;
}
}
*min
}
} }

309
src/base/statistics.rs Normal file
View File

@ -0,0 +1,309 @@
use ::{Real, Dim, Matrix, VectorN, RowVectorN, DefaultAllocator, U1, VectorSliceN};
use storage::Storage;
use allocator::Allocator;
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/// Returns a row vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix.
#[inline]
pub fn compress_rows(&self, f: impl Fn(VectorSliceN<N, R, S::RStride, S::CStride>) -> N) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
let ncols = self.data.shape().1;
let mut res = unsafe { RowVectorN::new_uninitialized_generic(U1, ncols) };
for i in 0..ncols.value() {
// FIXME: avoid bound checking of column.
unsafe { *res.get_unchecked_mut((0, i)) = f(self.column(i)); }
}
res
}
/// Returns a column vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix.
///
/// This is the same as `self.compress_rows(f).transpose()`.
#[inline]
pub fn compress_rows_tr(&self, f: impl Fn(VectorSliceN<N, R, S::RStride, S::CStride>) -> N) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
let ncols = self.data.shape().1;
let mut res = unsafe { VectorN::new_uninitialized_generic(ncols, U1) };
for i in 0..ncols.value() {
// FIXME: avoid bound checking of column.
unsafe { *res.vget_unchecked_mut(i) = f(self.column(i)); }
}
res
}
/// Returns a column vector resulting from the folding of `f` on each column of this matrix.
#[inline]
pub fn compress_columns(&self, init: VectorN<N, R>, f: impl Fn(&mut VectorN<N, R>, VectorSliceN<N, R, S::RStride, S::CStride>)) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let mut res = init;
for i in 0..self.ncols() {
f(&mut res, self.column(i))
}
res
}
}
impl<N: Real, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
/*
*
* Sum computation.
*
*/
/// The sum of all the elements of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::Matrix2x3;
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.sum(), 21.0);
/// ```
#[inline]
pub fn sum(&self) -> N {
self.iter().cloned().fold(N::zero(), |a, b| a + b)
}
/// The sum of all the rows of this matrix.
///
/// Use `.row_variance_tr` if you need the result in a column vector instead.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, RowVector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_sum(), RowVector3::new(5.0, 7.0, 9.0));
/// ```
#[inline]
pub fn row_sum(&self) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
self.compress_rows(|col| col.sum())
}
/// The sum of all the rows of this matrix. The result is transposed and returned as a column vector.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_sum_tr(), Vector3::new(5.0, 7.0, 9.0));
/// ```
#[inline]
pub fn row_sum_tr(&self) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
self.compress_rows_tr(|col| col.sum())
}
/// The sum of all the columns of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector2};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.column_sum(), Vector2::new(6.0, 15.0));
/// ```
#[inline]
pub fn column_sum(&self) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let nrows = self.data.shape().0;
self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| {
out.axpy(N::one(), &col, N::one())
})
}
/*
*
* Variance computation.
*
*/
/// The variance of all the elements of this matrix.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::Matrix2x3;
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_relative_eq!(m.variance(), 35.0 / 12.0, epsilon = 1.0e-8);
/// ```
#[inline]
pub fn variance(&self) -> N {
if self.len() == 0 {
N::zero()
} else {
let val = self.iter().cloned().fold((N::zero(), N::zero()), |a, b| (a.0 + b * b, a.1 + b));
let denom = N::one() / ::convert::<_, N>(self.len() as f64);
val.0 * denom - (val.1 * denom) * (val.1 * denom)
}
}
/// The variance of all the rows of this matrix.
///
/// Use `.row_variance_tr` if you need the result in a column vector instead.
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, RowVector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_variance(), RowVector3::new(2.25, 2.25, 2.25));
/// ```
#[inline]
pub fn row_variance(&self) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
self.compress_rows(|col| col.variance())
}
/// The variance of all the rows of this matrix. The result is transposed and returned as a column vector.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_variance_tr(), Vector3::new(2.25, 2.25, 2.25));
/// ```
#[inline]
pub fn row_variance_tr(&self) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
self.compress_rows_tr(|col| col.variance())
}
/// The variance of all the columns of this matrix.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix2x3, Vector2};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_relative_eq!(m.column_variance(), Vector2::new(2.0 / 3.0, 2.0 / 3.0), epsilon = 1.0e-8);
/// ```
#[inline]
pub fn column_variance(&self) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let (nrows, ncols) = self.data.shape();
let mut mean = self.column_mean();
mean.apply(|e| -(e * e));
let denom = N::one() / ::convert::<_, N>(ncols.value() as f64);
self.compress_columns(mean, |out, col| {
for i in 0..nrows.value() {
unsafe {
let val = col.vget_unchecked(i);
*out.vget_unchecked_mut(i) += denom * *val * *val
}
}
})
}
/*
*
* Mean computation.
*
*/
/// The mean of all the elements of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::Matrix2x3;
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.mean(), 3.5);
/// ```
#[inline]
pub fn mean(&self) -> N {
if self.len() == 0 {
N::zero()
} else {
self.sum() / ::convert(self.len() as f64)
}
}
/// The mean of all the rows of this matrix.
///
/// Use `.row_mean_tr` if you need the result in a column vector instead.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, RowVector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_mean(), RowVector3::new(2.5, 3.5, 4.5));
/// ```
#[inline]
pub fn row_mean(&self) -> RowVectorN<N, C>
where DefaultAllocator: Allocator<N, U1, C> {
self.compress_rows(|col| col.mean())
}
/// The mean of all the rows of this matrix. The result is transposed and returned as a column vector.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector3};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.row_mean_tr(), Vector3::new(2.5, 3.5, 4.5));
/// ```
#[inline]
pub fn row_mean_tr(&self) -> VectorN<N, C>
where DefaultAllocator: Allocator<N, C> {
self.compress_rows_tr(|col| col.mean())
}
/// The mean of all the columns of this matrix.
///
/// # Example
///
/// ```
/// # use nalgebra::{Matrix2x3, Vector2};
///
/// let m = Matrix2x3::new(1.0, 2.0, 3.0,
/// 4.0, 5.0, 6.0);
/// assert_eq!(m.column_mean(), Vector2::new(2.0, 5.0));
/// ```
#[inline]
pub fn column_mean(&self) -> VectorN<N, R>
where DefaultAllocator: Allocator<N, R> {
let (nrows, ncols) = self.data.shape();
let denom = N::one() / ::convert::<_, N>(ncols.value() as f64);
self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| {
out.axpy(denom, &col, N::one())
})
}
}

View File

@ -13,6 +13,8 @@ use abomonation::Abomonation;
use alga::general::SubsetOf; use alga::general::SubsetOf;
use alga::linear::NormedSpace; use alga::linear::NormedSpace;
use ::Real;
/// A wrapper that ensures the underlying algebraic entity has a unit norm. /// A wrapper that ensures the underlying algebraic entity has a unit norm.
/// ///
/// Use `.as_ref()` or `.into_inner()` to obtain the underlying value by-reference or by-move. /// Use `.as_ref()` or `.into_inner()` to obtain the underlying value by-reference or by-move.
@ -91,11 +93,24 @@ impl<T: NormedSpace> Unit<T> {
/// Normalizes this value again. This is useful when repeated computations /// Normalizes this value again. This is useful when repeated computations
/// might cause a drift in the norm because of float inaccuracies. /// might cause a drift in the norm because of float inaccuracies.
/// ///
/// Returns the norm before re-normalization (should be close to `1.0`). /// Returns the norm before re-normalization. See `.renormalize_fast` for a faster alternative
/// that may be slightly less accurate if `self` drifted significantly from having a unit length.
#[inline] #[inline]
pub fn renormalize(&mut self) -> T::Field { pub fn renormalize(&mut self) -> T::Field {
self.value.normalize_mut() self.value.normalize_mut()
} }
/// Normalizes this value again using a first-order Taylor approximation.
/// This is useful when repeated computations might cause a drift in the norm
/// because of float inaccuracies.
#[inline]
pub fn renormalize_fast(&mut self)
where T::Field: Real {
let sq_norm = self.value.norm_squared();
let _3: T::Field = ::convert(3.0);
let _0_5: T::Field = ::convert(0.5);
self.value *= _0_5 * (_3 - sq_norm);
}
} }
impl<T> Unit<T> { impl<T> Unit<T> {

View File

@ -1,6 +1,5 @@
#[cfg(feature = "abomonation-serialize")] #[cfg(feature = "abomonation-serialize")]
use std::io::{Result as IOResult, Write}; use std::io::{Result as IOResult, Write};
use std::ops::Deref;
#[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec; use alloc::vec::Vec;
@ -37,12 +36,12 @@ pub type MatrixVec<N, R, C> = VecStorage<N, R, C>;
impl<N, R: Dim, C: Dim> VecStorage<N, R, C> { impl<N, R: Dim, C: Dim> VecStorage<N, R, C> {
/// Creates a new dynamic matrix data storage from the given vector and shape. /// Creates a new dynamic matrix data storage from the given vector and shape.
#[inline] #[inline]
pub fn new(nrows: R, ncols: C, data: Vec<N>) -> VecStorage<N, R, C> { pub fn new(nrows: R, ncols: C, data: Vec<N>) -> Self {
assert!( assert!(
nrows.value() * ncols.value() == data.len(), nrows.value() * ncols.value() == data.len(),
"Data storage buffer dimension mismatch." "Data storage buffer dimension mismatch."
); );
VecStorage { Self {
data: data, data: data,
nrows: nrows, nrows: nrows,
ncols: ncols, ncols: ncols,
@ -51,15 +50,16 @@ impl<N, R: Dim, C: Dim> VecStorage<N, R, C> {
/// The underlying data storage. /// The underlying data storage.
#[inline] #[inline]
pub fn data(&self) -> &Vec<N> { pub fn as_vec(&self) -> &Vec<N> {
&self.data &self.data
} }
/// The underlying mutable data storage. /// The underlying mutable data storage.
/// ///
/// This is unsafe because this may cause UB if the vector is modified by the user. /// This is unsafe because this may cause UB if the size of the vector is changed
/// by the user.
#[inline] #[inline]
pub unsafe fn data_mut(&mut self) -> &mut Vec<N> { pub unsafe fn as_vec_mut(&mut self) -> &mut Vec<N> {
&mut self.data &mut self.data
} }
@ -81,14 +81,11 @@ impl<N, R: Dim, C: Dim> VecStorage<N, R, C> {
self.data self.data
} }
}
impl<N, R: Dim, C: Dim> Deref for VecStorage<N, R, C> {
type Target = Vec<N>;
/// The number of elements on the underlying vector.
#[inline] #[inline]
fn deref(&self) -> &Self::Target { pub fn len(&self) -> usize {
&self.data self.data.len()
} }
} }
@ -145,7 +142,7 @@ where DefaultAllocator: Allocator<N, Dynamic, C, Buffer = Self>
#[inline] #[inline]
fn as_slice(&self) -> &[N] { fn as_slice(&self) -> &[N] {
&self[..] &self.data
} }
} }
@ -189,7 +186,7 @@ where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>
#[inline] #[inline]
fn as_slice(&self) -> &[N] { fn as_slice(&self) -> &[N] {
&self[..] &self.data
} }
} }

View File

@ -100,7 +100,7 @@ where DefaultAllocator: Allocator<N, D>
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Isometry::from_parts(self.translation.clone(), self.rotation.clone()) Self::from_parts(self.translation.clone(), self.rotation.clone())
} }
} }
@ -113,7 +113,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0); /// let tra = Translation3::new(0.0, 0.0, 3.0);
@ -123,8 +122,8 @@ where DefaultAllocator: Allocator<N, D>
/// assert_relative_eq!(iso * Point3::new(1.0, 2.0, 3.0), Point3::new(-1.0, 2.0, 0.0), epsilon = 1.0e-6); /// assert_relative_eq!(iso * Point3::new(1.0, 2.0, 3.0), Point3::new(-1.0, 2.0, 0.0), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> { pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Self {
Isometry { Self {
rotation: rotation, rotation: rotation,
translation: translation, translation: translation,
_noconstruct: PhantomData, _noconstruct: PhantomData,
@ -145,7 +144,7 @@ where DefaultAllocator: Allocator<N, D>
/// assert_eq!(inv * (iso * pt), pt); /// assert_eq!(inv * (iso * pt), pt);
/// ``` /// ```
#[inline] #[inline]
pub fn inverse(&self) -> Isometry<N, D, R> { pub fn inverse(&self) -> Self {
let mut res = self.clone(); let mut res = self.clone();
res.inverse_mut(); res.inverse_mut();
res res
@ -167,7 +166,7 @@ where DefaultAllocator: Allocator<N, D>
/// ``` /// ```
#[inline] #[inline]
pub fn inverse_mut(&mut self) { pub fn inverse_mut(&mut self) {
self.rotation.inverse_mut(); self.rotation.two_sided_inverse_mut();
self.translation.inverse_mut(); self.translation.inverse_mut();
self.translation.vector = self.rotation.transform_vector(&self.translation.vector); self.translation.vector = self.rotation.transform_vector(&self.translation.vector);
} }
@ -197,7 +196,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2}; /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0); /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0);
@ -220,7 +218,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2}; /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
@ -272,7 +269,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Vector2, Matrix3}; /// # use nalgebra::{Isometry2, Vector2, Matrix3};
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6); /// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);
@ -310,7 +306,7 @@ where
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
#[inline] #[inline]
fn eq(&self, right: &Isometry<N, D, R>) -> bool { fn eq(&self, right: &Self) -> bool {
self.translation == right.translation && self.rotation == right.rotation self.translation == right.translation && self.rotation == right.rotation
} }
} }

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::Isometry as AlgaIsometry; use alga::linear::Isometry as AlgaIsometry;
use alga::linear::{ use alga::linear::{
@ -30,18 +30,18 @@ where
} }
} }
impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Isometry<N, D, R> impl<N: Real, D: DimName, R> TwoSidedInverse<Multiplicative> for Isometry<N, D, R>
where where
R: Rotation<Point<N, D>>, R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }
@ -121,7 +121,7 @@ where
type Translation = Translation<N, D>; type Translation = Translation<N, D>;
#[inline] #[inline]
fn decompose(&self) -> (Translation<N, D>, R, Id, R) { fn decompose(&self) -> (Self::Translation, R, Id, R) {
( (
self.translation.clone(), self.translation.clone(),
self.rotation.clone(), self.rotation.clone(),

View File

@ -16,7 +16,7 @@ use base::{DefaultAllocator, Vector2, Vector3};
use geometry::{ use geometry::{
Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex, Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex,
UnitQuaternion, UnitQuaternion, Translation2, Translation3
}; };
impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R> impl<N: Real, D: DimName, R: AlgaRotation<Point<N, D>>> Isometry<N, D, R>
@ -49,7 +49,6 @@ where DefaultAllocator: Allocator<N, D>
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, UnitComplex}; /// # use nalgebra::{Isometry2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::PI); /// let rot = UnitComplex::new(f32::consts::PI);
@ -130,6 +129,18 @@ impl<N: Real> Isometry<N, U2, Rotation2<N>> {
Rotation::<N, U2>::new(angle), Rotation::<N, U2>::new(angle),
) )
} }
/// Creates a new isometry from the given translation coordinates.
#[inline]
pub fn translation(x: N, y: N) -> Self {
Self::new(Vector2::new(x, y), N::zero())
}
/// Creates a new isometry from the given rotation angle.
#[inline]
pub fn rotation(angle: N) -> Self {
Self::new(Vector2::zeros(), angle)
}
} }
impl<N: Real> Isometry<N, U2, UnitComplex<N>> { impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
@ -153,6 +164,18 @@ impl<N: Real> Isometry<N, U2, UnitComplex<N>> {
UnitComplex::from_angle(angle), UnitComplex::from_angle(angle),
) )
} }
/// Creates a new isometry from the given translation coordinates.
#[inline]
pub fn translation(x: N, y: N) -> Self {
Self::from_parts(Translation2::new(x, y), UnitComplex::identity())
}
/// Creates a new isometry from the given rotation angle.
#[inline]
pub fn rotation(angle: N) -> Self {
Self::new(Vector2::zeros(), angle)
}
} }
// 3D rotation. // 3D rotation.
@ -165,7 +188,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -191,6 +213,18 @@ macro_rules! isometry_construction_impl(
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle)) $RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
} }
/// Creates a new isometry from the given translation coordinates.
#[inline]
pub fn translation(x: N, y: N, z: N) -> Self {
Self::from_parts(Translation3::new(x, y, z), $RotId::identity())
}
/// Creates a new isometry from the given rotation angle.
#[inline]
pub fn rotation(axisangle: Vector3<N>) -> Self {
Self::new(Vector3::zeros(), axisangle)
}
/// Creates an isometry that corresponds to the local frame of an observer standing at the /// Creates an isometry that corresponds to the local frame of an observer standing at the
/// point `eye` and looking toward `target`. /// point `eye` and looking toward `target`.
/// ///
@ -206,7 +240,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -214,23 +247,32 @@ macro_rules! isometry_construction_impl(
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// // Isometry with its rotation part represented as a UnitQuaternion /// // Isometry with its rotation part represented as a UnitQuaternion
/// let iso = Isometry3::new_observer_frame(&eye, &target, &up); /// let iso = Isometry3::face_towards(&eye, &target, &up);
/// assert_eq!(iso * Point3::origin(), eye); /// assert_eq!(iso * Point3::origin(), eye);
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x()); /// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
/// ///
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix). /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let iso = IsometryMatrix3::new_observer_frame(&eye, &target, &up); /// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
/// assert_eq!(iso * Point3::origin(), eye); /// assert_eq!(iso * Point3::origin(), eye);
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x()); /// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame(eye: &Point3<N>, pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
up: &Vector3<N>) up: &Vector3<N>)
-> Self { -> Self {
Self::from_parts( Self::from_parts(
Translation::from(eye.coords.clone()), Translation::from(eye.coords.clone()),
$RotId::new_observer_frame(&(target - eye), up)) $RotId::face_towards(&(target - eye), up))
}
/// Deprecated: Use [Isometry::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>)
-> Self {
Self::face_towards(eye, target, up)
} }
/// Builds a right-handed look-at view matrix. /// Builds a right-handed look-at view matrix.
@ -249,7 +291,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -293,7 +334,6 @@ macro_rules! isometry_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);

View File

@ -200,8 +200,8 @@ isometry_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: Isometry<N, D, R>, rhs: R; self: Isometry<N, D, R>, rhs: R;
// FIXME: don't invert explicitly? // FIXME: don't invert explicitly?
[val] => *self *= rhs.inverse(); [val] => *self *= rhs.two_sided_inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.two_sided_inverse();
); );
// Isometry × R // Isometry × R

View File

@ -37,6 +37,7 @@ mod translation_alga;
mod translation_alias; mod translation_alias;
mod translation_construction; mod translation_construction;
mod translation_conversion; mod translation_conversion;
mod translation_coordinates;
mod translation_ops; mod translation_ops;
mod isometry; mod isometry;

View File

@ -26,7 +26,7 @@ impl<N: Real> Copy for Orthographic3<N> {}
impl<N: Real> Clone for Orthographic3<N> { impl<N: Real> Clone for Orthographic3<N> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Orthographic3::from_matrix_unchecked(self.matrix.clone()) Self::from_matrix_unchecked(self.matrix.clone())
} }
} }
@ -57,7 +57,7 @@ impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Orthographic3<N> {
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let matrix = Matrix4::<N>::deserialize(deserializer)?; let matrix = Matrix4::<N>::deserialize(deserializer)?;
Ok(Orthographic3::from_matrix_unchecked(matrix)) Ok(Self::from_matrix_unchecked(matrix))
} }
} }
@ -69,7 +69,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3}; /// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// // Check this projection actually transforms the view cuboid into the double-unit cube. /// // Check this projection actually transforms the view cuboid into the double-unit cube.
@ -136,7 +135,7 @@ impl<N: Real> Orthographic3<N> {
/// ``` /// ```
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self { pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self {
Orthographic3 { matrix: matrix } Self { matrix: matrix }
} }
/// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view. /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
@ -170,7 +169,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3, Matrix4}; /// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let inv = proj.inverse(); /// let inv = proj.inverse();
@ -271,7 +269,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3, Matrix4}; /// # use nalgebra::{Orthographic3, Point3, Matrix4};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// let expected = Matrix4::new( /// let expected = Matrix4::new(
@ -299,7 +296,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6);
@ -316,7 +312,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6);
@ -333,7 +328,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6);
@ -350,7 +344,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6);
@ -367,7 +360,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6); /// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6);
@ -384,7 +376,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6); /// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6);
@ -403,7 +394,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3}; /// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// ///
@ -439,7 +429,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Point3}; /// # use nalgebra::{Orthographic3, Point3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// ///
@ -478,7 +467,6 @@ impl<N: Real> Orthographic3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Orthographic3, Vector3}; /// # use nalgebra::{Orthographic3, Vector3};
/// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// ///
@ -504,7 +492,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left(2.0); /// proj.set_left(2.0);
@ -524,7 +511,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_right(15.0); /// proj.set_right(15.0);
@ -544,7 +530,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom(8.0); /// proj.set_bottom(8.0);
@ -564,7 +549,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_top(15.0); /// proj.set_top(15.0);
@ -584,7 +568,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear(8.0); /// proj.set_znear(8.0);
@ -604,7 +587,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_zfar(15.0); /// proj.set_zfar(15.0);
@ -624,7 +606,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_left_and_right(7.0, 70.0); /// proj.set_left_and_right(7.0, 70.0);
@ -650,7 +631,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_bottom_and_top(7.0, 70.0); /// proj.set_bottom_and_top(7.0, 70.0);
@ -676,7 +656,6 @@ impl<N: Real> Orthographic3<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Orthographic3; /// # use nalgebra::Orthographic3;
/// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0);
/// proj.set_znear_and_zfar(50.0, 5000.0); /// proj.set_znear_and_zfar(50.0, 5000.0);

View File

@ -27,7 +27,7 @@ impl<N: Real> Copy for Perspective3<N> {}
impl<N: Real> Clone for Perspective3<N> { impl<N: Real> Clone for Perspective3<N> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Perspective3::from_matrix_unchecked(self.matrix.clone()) Self::from_matrix_unchecked(self.matrix.clone())
} }
} }
@ -58,7 +58,7 @@ impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Perspective3<N> {
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let matrix = Matrix4::<N>::deserialize(deserializer)?; let matrix = Matrix4::<N>::deserialize(deserializer)?;
Ok(Perspective3::from_matrix_unchecked(matrix)) Ok(Self::from_matrix_unchecked(matrix))
} }
} }
@ -75,7 +75,7 @@ impl<N: Real> Perspective3<N> {
); );
let matrix = Matrix4::identity(); let matrix = Matrix4::identity();
let mut res = Perspective3::from_matrix_unchecked(matrix); let mut res = Self::from_matrix_unchecked(matrix);
res.set_fovy(fovy); res.set_fovy(fovy);
res.set_aspect(aspect); res.set_aspect(aspect);
@ -93,7 +93,7 @@ impl<N: Real> Perspective3<N> {
/// projection. /// projection.
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self { pub fn from_matrix_unchecked(matrix: Matrix4<N>) -> Self {
Perspective3 { matrix: matrix } Self { matrix: matrix }
} }
/// Retrieves the inverse of the underlying homogeneous matrix. /// Retrieves the inverse of the underlying homogeneous matrix.

View File

@ -66,7 +66,7 @@ where
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let coords = VectorN::<N, D>::deserialize(deserializer)?; let coords = VectorN::<N, D>::deserialize(deserializer)?;
Ok(Point::from(coords)) Ok(Self::from(coords))
} }
} }
@ -126,8 +126,8 @@ where DefaultAllocator: Allocator<N, D>
/// Creates a new point with the given coordinates. /// Creates a new point with the given coordinates.
#[deprecated(note = "Use Point::from(vector) instead.")] #[deprecated(note = "Use Point::from(vector) instead.")]
#[inline] #[inline]
pub fn from_coordinates(coords: VectorN<N, D>) -> Point<N, D> { pub fn from_coordinates(coords: VectorN<N, D>) -> Self {
Point { coords: coords } Self { coords: coords }
} }
/// The dimension of this point. /// The dimension of this point.

View File

@ -54,7 +54,7 @@ where
{ {
#[inline] #[inline]
fn meet(&self, other: &Self) -> Self { fn meet(&self, other: &Self) -> Self {
Point::from(self.coords.meet(&other.coords)) Self::from(self.coords.meet(&other.coords))
} }
} }
@ -65,7 +65,7 @@ where
{ {
#[inline] #[inline]
fn join(&self, other: &Self) -> Self { fn join(&self, other: &Self) -> Self {
Point::from(self.coords.join(&other.coords)) Self::from(self.coords.join(&other.coords))
} }
} }
@ -78,6 +78,6 @@ where
fn meet_join(&self, other: &Self) -> (Self, Self) { fn meet_join(&self, other: &Self) -> (Self, Self) {
let (meet, join) = self.coords.meet_join(&other.coords); let (meet, join) = self.coords.meet_join(&other.coords);
(Point::from(meet), Point::from(join)) (Self::from(meet), Self::from(join))
} }
} }

View File

@ -145,7 +145,7 @@ where
{ {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
Point::from(VectorN::arbitrary(g)) Self::from(VectorN::arbitrary(g))
} }
} }
@ -163,7 +163,7 @@ macro_rules! componentwise_constructors_impl(
#[doc = $doc] #[doc = $doc]
#[doc = "```"] #[doc = "```"]
#[inline] #[inline]
pub fn new($($args: N),*) -> Point<N, $D> { pub fn new($($args: N),*) -> Self {
unsafe { unsafe {
let mut res = Self::new_uninitialized(); let mut res = Self::new_uninitialized();
$( *res.get_unchecked_mut($irow) = $args; )* $( *res.get_unchecked_mut($irow) = $args; )*
@ -194,7 +194,7 @@ macro_rules! from_array_impl(
($($D: ty, $len: expr);*) => {$( ($($D: ty, $len: expr);*) => {$(
impl <N: Scalar> From<[N; $len]> for Point<N, $D> { impl <N: Scalar> From<[N; $len]> for Point<N, $D> {
fn from (coords: [N; $len]) -> Self { fn from (coords: [N; $len]) -> Self {
Point { Self {
coords: coords.into() coords: coords.into()
} }
} }

View File

@ -45,7 +45,7 @@ where
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self { unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self {
Point::from(Matrix::from_superset_unchecked(&m.coords)) Self::from(Matrix::from_superset_unchecked(&m.coords))
} }
} }

View File

@ -46,11 +46,11 @@ where DefaultAllocator: Allocator<N, D>
impl<N: Scalar + ClosedNeg, D: DimName> Neg for Point<N, D> impl<N: Scalar + ClosedNeg, D: DimName> Neg for Point<N, D>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
type Output = Point<N, D>; type Output = Self;
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Point::from(-self.coords) Self::Output::from(-self.coords)
} }
} }
@ -61,7 +61,7 @@ where DefaultAllocator: Allocator<N, D>
#[inline] #[inline]
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
Point::from(-&self.coords) Self::Output::from(-&self.coords)
} }
} }

View File

@ -68,7 +68,7 @@ impl<N: Real> Copy for Quaternion<N> {}
impl<N: Real> Clone for Quaternion<N> { impl<N: Real> Clone for Quaternion<N> {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Quaternion::from(self.coords.clone()) Self::from(self.coords.clone())
} }
} }
@ -90,7 +90,7 @@ where Owned<N, U4>: Deserialize<'a>
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let coords = Vector4::<N>::deserialize(deserializer)?; let coords = Vector4::<N>::deserialize(deserializer)?;
Ok(Quaternion::from(coords)) Ok(Self::from(coords))
} }
} }
@ -98,15 +98,15 @@ impl<N: Real> Quaternion<N> {
/// Moves this unit quaternion into one that owns its data. /// Moves this unit quaternion into one that owns its data.
#[inline] #[inline]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")] #[deprecated(note = "This method is a no-op and will be removed in a future release.")]
pub fn into_owned(self) -> Quaternion<N> { pub fn into_owned(self) -> Self {
self self
} }
/// Clones this unit quaternion into one that owns its data. /// Clones this unit quaternion into one that owns its data.
#[inline] #[inline]
#[deprecated(note = "This method is a no-op and will be removed in a future release.")] #[deprecated(note = "This method is a no-op and will be removed in a future release.")]
pub fn clone_owned(&self) -> Quaternion<N> { pub fn clone_owned(&self) -> Self {
Quaternion::from(self.coords.clone_owned()) Self::from(self.coords.clone_owned())
} }
/// Normalizes this quaternion. /// Normalizes this quaternion.
@ -114,15 +114,14 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let q_normalized = q.normalize(); /// let q_normalized = q.normalize();
/// relative_eq!(q_normalized.norm(), 1.0); /// relative_eq!(q_normalized.norm(), 1.0);
/// ``` /// ```
#[inline] #[inline]
pub fn normalize(&self) -> Quaternion<N> { pub fn normalize(&self) -> Self {
Quaternion::from(self.coords.normalize()) Self::from(self.coords.normalize())
} }
/// The conjugate of this quaternion. /// The conjugate of this quaternion.
@ -135,14 +134,14 @@ impl<N: Real> Quaternion<N> {
/// assert!(conj.i == -2.0 && conj.j == -3.0 && conj.k == -4.0 && conj.w == 1.0); /// assert!(conj.i == -2.0 && conj.j == -3.0 && conj.k == -4.0 && conj.w == 1.0);
/// ``` /// ```
#[inline] #[inline]
pub fn conjugate(&self) -> Quaternion<N> { pub fn conjugate(&self) -> Self {
let v = Vector4::new( let v = Vector4::new(
-self.coords[0], -self.coords[0],
-self.coords[1], -self.coords[1],
-self.coords[2], -self.coords[2],
self.coords[3], self.coords[3],
); );
Quaternion::from(v) Self::from(v)
} }
/// Inverts this quaternion if it is not zero. /// Inverts this quaternion if it is not zero.
@ -150,7 +149,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// let inv_q = q.try_inverse(); /// let inv_q = q.try_inverse();
@ -165,8 +163,8 @@ impl<N: Real> Quaternion<N> {
/// assert!(inv_q.is_none()); /// assert!(inv_q.is_none());
/// ``` /// ```
#[inline] #[inline]
pub fn try_inverse(&self) -> Option<Quaternion<N>> { pub fn try_inverse(&self) -> Option<Self> {
let mut res = Quaternion::from(self.coords.clone_owned()); let mut res = Self::from(self.coords.clone_owned());
if res.try_inverse_mut() { if res.try_inverse_mut() {
Some(res) Some(res)
@ -188,7 +186,7 @@ impl<N: Real> Quaternion<N> {
/// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6)); /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6));
/// ``` /// ```
#[inline] #[inline]
pub fn lerp(&self, other: &Quaternion<N>, t: N) -> Quaternion<N> { pub fn lerp(&self, other: &Self, t: N) -> Self {
self * (N::one() - t) + other * t self * (N::one() - t) + other * t
} }
@ -240,7 +238,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6); /// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6);
@ -258,7 +255,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6); /// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6);
@ -345,18 +341,17 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0); /// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0);
/// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6) /// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6)
/// ``` /// ```
#[inline] #[inline]
pub fn ln(&self) -> Quaternion<N> { pub fn ln(&self) -> Self {
let n = self.norm(); let n = self.norm();
let v = self.vector(); let v = self.vector();
let s = self.scalar(); let s = self.scalar();
Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos()) Self::from_parts(n.ln(), v.normalize() * (s / n).acos())
} }
/// Compute the exponential of a quaternion. /// Compute the exponential of a quaternion.
@ -364,13 +359,12 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
/// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5) /// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5)
/// ``` /// ```
#[inline] #[inline]
pub fn exp(&self) -> Quaternion<N> { pub fn exp(&self) -> Self {
self.exp_eps(N::default_epsilon()) self.exp_eps(N::default_epsilon())
} }
@ -380,7 +374,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0);
/// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5); /// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5);
@ -390,18 +383,18 @@ impl<N: Real> Quaternion<N> {
/// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity()); /// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity());
/// ``` /// ```
#[inline] #[inline]
pub fn exp_eps(&self, eps: N) -> Quaternion<N> { pub fn exp_eps(&self, eps: N) -> Self {
let v = self.vector(); let v = self.vector();
let nn = v.norm_squared(); let nn = v.norm_squared();
if nn <= eps * eps { if nn <= eps * eps {
Quaternion::identity() Self::identity()
} else { } else {
let w_exp = self.scalar().exp(); let w_exp = self.scalar().exp();
let n = nn.sqrt(); let n = nn.sqrt();
let nv = v * (w_exp * n.sin() / n); let nv = v * (w_exp * n.sin() / n);
Quaternion::from_parts(w_exp * n.cos(), nv) Self::from_parts(w_exp * n.cos(), nv)
} }
} }
@ -410,13 +403,12 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6); /// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Quaternion<N> { pub fn powf(&self, n: N) -> Self {
(self.ln() * n).exp() (self.ln() * n).exp()
} }
@ -476,7 +468,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// ///
@ -506,7 +497,6 @@ impl<N: Real> Quaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Quaternion; /// # use nalgebra::Quaternion;
/// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0);
/// q.normalize_mut(); /// q.normalize_mut();
@ -530,7 +520,7 @@ impl<N: Real + AbsDiffEq<Epsilon = N>> AbsDiffEq for Quaternion<N> {
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.as_vector().abs_diff_eq(other.as_vector(), epsilon) || self.as_vector().abs_diff_eq(other.as_vector(), epsilon) ||
// Account for the double-covering of S², i.e. q = -q // Account for the double-covering of S², i.e. q = -q
self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-*b, epsilon)) self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-*b, epsilon))
} }
} }
@ -550,7 +540,7 @@ impl<N: Real + RelativeEq<Epsilon = N>> RelativeEq for Quaternion<N> {
{ {
self.as_vector().relative_eq(other.as_vector(), epsilon, max_relative) || self.as_vector().relative_eq(other.as_vector(), epsilon, max_relative) ||
// Account for the double-covering of S², i.e. q = -q // Account for the double-covering of S², i.e. q = -q
self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.relative_eq(&-*b, epsilon, max_relative)) self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.relative_eq(&-*b, epsilon, max_relative))
} }
} }
@ -564,7 +554,7 @@ impl<N: Real + UlpsEq<Epsilon = N>> UlpsEq for Quaternion<N> {
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.as_vector().ulps_eq(other.as_vector(), epsilon, max_ulps) || self.as_vector().ulps_eq(other.as_vector(), epsilon, max_ulps) ||
// Account for the double-covering of S², i.e. q = -q. // Account for the double-covering of S², i.e. q = -q.
self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.ulps_eq(&-*b, epsilon, max_ulps)) self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.ulps_eq(&-*b, epsilon, max_ulps))
} }
} }
@ -587,7 +577,7 @@ impl<N: Real> UnitQuaternion<N> {
#[deprecated( #[deprecated(
note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead." note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead."
)] )]
pub fn into_owned(self) -> UnitQuaternion<N> { pub fn into_owned(self) -> Self {
self self
} }
@ -596,7 +586,7 @@ impl<N: Real> UnitQuaternion<N> {
#[deprecated( #[deprecated(
note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead." note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead."
)] )]
pub fn clone_owned(&self) -> UnitQuaternion<N> { pub fn clone_owned(&self) -> Self {
*self *self
} }
@ -647,8 +637,8 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_eq!(conj, UnitQuaternion::from_axis_angle(&-axis, 1.78)); /// assert_eq!(conj, UnitQuaternion::from_axis_angle(&-axis, 1.78));
/// ``` /// ```
#[inline] #[inline]
pub fn conjugate(&self) -> UnitQuaternion<N> { pub fn conjugate(&self) -> Self {
UnitQuaternion::new_unchecked(self.as_ref().conjugate()) Self::new_unchecked(self.as_ref().conjugate())
} }
/// Inverts this quaternion if it is not zero. /// Inverts this quaternion if it is not zero.
@ -663,7 +653,7 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_eq!(inv * rot, UnitQuaternion::identity()); /// assert_eq!(inv * rot, UnitQuaternion::identity());
/// ``` /// ```
#[inline] #[inline]
pub fn inverse(&self) -> UnitQuaternion<N> { pub fn inverse(&self) -> Self {
self.conjugate() self.conjugate()
} }
@ -672,14 +662,13 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &UnitQuaternion<N>) -> N { pub fn angle_to(&self, other: &Self) -> N {
let delta = self.rotation_to(other); let delta = self.rotation_to(other);
delta.angle() delta.angle()
} }
@ -691,7 +680,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -699,7 +687,7 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &UnitQuaternion<N>) -> UnitQuaternion<N> { pub fn rotation_to(&self, other: &Self) -> Self{
other / self other / self
} }
@ -715,7 +703,7 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(0.9, 0.1, 0.0, 0.0)); /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(0.9, 0.1, 0.0, 0.0));
/// ``` /// ```
#[inline] #[inline]
pub fn lerp(&self, other: &UnitQuaternion<N>, t: N) -> Quaternion<N> { pub fn lerp(&self, other: &Self, t: N) -> Quaternion<N> {
self.as_ref().lerp(other.as_ref(), t) self.as_ref().lerp(other.as_ref(), t)
} }
@ -731,11 +719,11 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_eq!(q1.nlerp(&q2, 0.1), UnitQuaternion::new_normalize(Quaternion::new(0.9, 0.1, 0.0, 0.0))); /// assert_eq!(q1.nlerp(&q2, 0.1), UnitQuaternion::new_normalize(Quaternion::new(0.9, 0.1, 0.0, 0.0)));
/// ``` /// ```
#[inline] #[inline]
pub fn nlerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> { pub fn nlerp(&self, other: &Self, t: N) -> Self {
let mut res = self.lerp(other, t); let mut res = self.lerp(other, t);
let _ = res.normalize_mut(); let _ = res.normalize_mut();
UnitQuaternion::new_unchecked(res) Self::new_unchecked(res)
} }
/// Spherical linear interpolation between two unit quaternions. /// Spherical linear interpolation between two unit quaternions.
@ -743,7 +731,7 @@ impl<N: Real> UnitQuaternion<N> {
/// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation /// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation
/// is not well-defined). Use `.try_slerp` instead to avoid the panic. /// is not well-defined). Use `.try_slerp` instead to avoid the panic.
#[inline] #[inline]
pub fn slerp(&self, other: &UnitQuaternion<N>, t: N) -> UnitQuaternion<N> { pub fn slerp(&self, other: &Self, t: N) -> Self {
Unit::new_unchecked(Quaternion::from( Unit::new_unchecked(Quaternion::from(
Unit::new_unchecked(self.coords) Unit::new_unchecked(self.coords)
.slerp(&Unit::new_unchecked(other.coords), t) .slerp(&Unit::new_unchecked(other.coords), t)
@ -764,10 +752,10 @@ impl<N: Real> UnitQuaternion<N> {
#[inline] #[inline]
pub fn try_slerp( pub fn try_slerp(
&self, &self,
other: &UnitQuaternion<N>, other: &Self,
t: N, t: N,
epsilon: N, epsilon: N,
) -> Option<UnitQuaternion<N>> ) -> Option<Self>
{ {
Unit::new_unchecked(self.coords) Unit::new_unchecked(self.coords)
.try_slerp(&Unit::new_unchecked(other.coords), t, epsilon) .try_slerp(&Unit::new_unchecked(other.coords), t, epsilon)
@ -785,7 +773,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit}; /// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let mut rot = UnitQuaternion::new(axisangle); /// let mut rot = UnitQuaternion::new(axisangle);
@ -828,7 +815,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit}; /// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = UnitQuaternion::new(axisangle); /// let rot = UnitQuaternion::new(axisangle);
@ -885,7 +871,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion}; /// # use nalgebra::{Vector3, UnitQuaternion};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let q = UnitQuaternion::new(axisangle); /// let q = UnitQuaternion::new(axisangle);
@ -908,7 +893,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{UnitQuaternion, Vector3, Unit}; /// # use nalgebra::{UnitQuaternion, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -918,11 +902,11 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_eq!(pow.angle(), 2.4); /// assert_eq!(pow.angle(), 2.4);
/// ``` /// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> UnitQuaternion<N> { pub fn powf(&self, n: N) -> Self {
if let Some(v) = self.axis() { if let Some(v) = self.axis() {
UnitQuaternion::from_axis_angle(&v, self.angle() * n) Self::from_axis_angle(&v, self.angle() * n)
} else { } else {
UnitQuaternion::identity() Self::identity()
} }
} }
@ -932,7 +916,6 @@ impl<N: Real> UnitQuaternion<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix3}; /// # use nalgebra::{UnitQuaternion, Vector3, Matrix3};
/// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);
@ -990,7 +973,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitQuaternion; /// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3); /// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -1009,7 +991,6 @@ impl<N: Real> UnitQuaternion<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3, Matrix4}; /// # use nalgebra::{UnitQuaternion, Vector3, Matrix4};
/// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6);

View File

@ -2,7 +2,7 @@ use num::Zero;
use alga::general::{ use alga::general::{
AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule,
AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Inverse, Module, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module,
Multiplicative, Real, Multiplicative, Real,
}; };
use alga::linear::{ use alga::linear::{
@ -42,9 +42,9 @@ impl<N: Real> AbstractMagma<Additive> for Quaternion<N> {
} }
} }
impl<N: Real> Inverse<Additive> for Quaternion<N> { impl<N: Real> TwoSidedInverse<Additive> for Quaternion<N> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
-self -self
} }
} }
@ -173,14 +173,14 @@ impl<N: Real> AbstractMagma<Multiplicative> for UnitQuaternion<N> {
} }
} }
impl<N: Real> Inverse<Multiplicative> for UnitQuaternion<N> { impl<N: Real> TwoSidedInverse<Multiplicative> for UnitQuaternion<N> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -15,9 +15,9 @@ use base::dimension::U3;
use base::storage::Storage; use base::storage::Storage;
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
use base::Vector3; use base::Vector3;
use base::{Unit, Vector, Vector4}; use base::{Unit, Vector, Vector4, Matrix3};
use geometry::{Quaternion, Rotation, UnitQuaternion}; use geometry::{Quaternion, Rotation3, UnitQuaternion};
impl<N: Real> Quaternion<N> { impl<N: Real> Quaternion<N> {
/// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w` /// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w`
@ -25,7 +25,7 @@ impl<N: Real> Quaternion<N> {
#[inline] #[inline]
#[deprecated(note = "Use `::from` instead.")] #[deprecated(note = "Use `::from` instead.")]
pub fn from_vector(vector: Vector4<N>) -> Self { pub fn from_vector(vector: Vector4<N>) -> Self {
Quaternion { coords: vector } Self { coords: vector }
} }
/// Creates a new quaternion from its individual components. Note that the arguments order does /// Creates a new quaternion from its individual components. Note that the arguments order does
@ -130,7 +130,7 @@ where Owned<N, U4>: Send
{ {
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
Quaternion::new( Self::new(
N::arbitrary(g), N::arbitrary(g),
N::arbitrary(g), N::arbitrary(g),
N::arbitrary(g), N::arbitrary(g),
@ -166,7 +166,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axis = Vector3::y_axis(); /// let axis = Vector3::y_axis();
@ -208,7 +207,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitQuaternion; /// # use nalgebra::UnitQuaternion;
/// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3); /// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -237,7 +235,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, UnitQuaternion, Vector3}; /// # use nalgebra::{Rotation3, UnitQuaternion, Vector3};
/// let axis = Vector3::y_axis(); /// let axis = Vector3::y_axis();
/// let angle = 0.1; /// let angle = 0.1;
@ -248,7 +245,7 @@ impl<N: Real> UnitQuaternion<N> {
/// assert_relative_eq!(q.angle(), rot.angle(), epsilon = 1.0e-6); /// assert_relative_eq!(q.angle(), rot.angle(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn from_rotation_matrix(rotmat: &Rotation<N, U3>) -> Self { pub fn from_rotation_matrix(rotmat: &Rotation3<N>) -> Self {
// Robust matrix to quaternion transformation. // Robust matrix to quaternion transformation.
// See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion // See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion
let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)]; let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)];
@ -296,13 +293,38 @@ impl<N: Real> UnitQuaternion<N> {
Self::new_unchecked(res) Self::new_unchecked(res)
} }
/// Builds an unit quaternion by extracting the rotation part of the given transformation `m`.
///
/// This is an iterative method. See `.from_matrix_eps` to provide mover
/// convergence parameters and starting solution.
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
pub fn from_matrix(m: &Matrix3<N>) -> Self {
Rotation3::from_matrix(m).into()
}
/// Builds an unit quaternion by extracting the rotation part of the given transformation `m`.
///
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
///
/// # Parameters
///
/// * `m`: the matrix from which the rotational part is to be extracted.
/// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
/// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
/// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
/// to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other
/// guesses come to mind.
pub fn from_matrix_eps(m: &Matrix3<N>, eps: N, max_iter: usize, guess: Self) -> Self {
let guess = Rotation3::from(guess);
Rotation3::from_matrix_eps(m, eps, max_iter, guess).into()
}
/// The unit quaternion needed to make `a` and `b` be collinear and point toward the same /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same
/// direction. /// direction.
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion}; /// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -325,7 +347,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, UnitQuaternion}; /// # use nalgebra::{Vector3, UnitQuaternion};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -361,7 +382,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion}; /// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0)); /// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
@ -387,7 +407,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector3, UnitQuaternion}; /// # use nalgebra::{Unit, Vector3, UnitQuaternion};
/// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0)); /// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0));
@ -446,22 +465,31 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// let q = UnitQuaternion::new_observer_frame(&dir, &up); /// let q = UnitQuaternion::face_towards(&dir, &up);
/// assert_relative_eq!(q * Vector3::z(), dir.normalize()); /// assert_relative_eq!(q * Vector3::z(), dir.normalize());
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::from_rotation_matrix(&Rotation::<N, U3>::new_observer_frame(dir, up)) Self::from_rotation_matrix(&Rotation3::face_towards(dir, up))
}
/// Deprecated: Use [UnitQuaternion::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::face_towards(dir, up)
} }
/// Builds a right-handed look-at view matrix without translation. /// Builds a right-handed look-at view matrix without translation.
@ -478,7 +506,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -493,7 +520,7 @@ impl<N: Real> UnitQuaternion<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(&-dir, up).inverse() Self::face_towards(&-dir, up).inverse()
} }
/// Builds a left-handed look-at view matrix without translation. /// Builds a left-handed look-at view matrix without translation.
@ -510,7 +537,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Vector3}; /// # use nalgebra::{UnitQuaternion, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -525,7 +551,7 @@ impl<N: Real> UnitQuaternion<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(dir, up).inverse() Self::face_towards(dir, up).inverse()
} }
/// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle.
@ -535,7 +561,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -565,7 +590,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -596,7 +620,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -625,7 +648,6 @@ impl<N: Real> UnitQuaternion<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitQuaternion, Point3, Vector3}; /// # use nalgebra::{UnitQuaternion, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -687,7 +709,7 @@ where
#[inline] #[inline]
fn arbitrary<G: Gen>(g: &mut G) -> Self { fn arbitrary<G: Gen>(g: &mut G) -> Self {
let axisangle = Vector3::arbitrary(g); let axisangle = Vector3::arbitrary(g);
UnitQuaternion::from_scaled_axis(axisangle) Self::from_scaled_axis(axisangle)
} }
} }

View File

@ -103,7 +103,7 @@ impl<N1, N2, R> SubsetOf<Isometry<N2, U3, R>> for UnitQuaternion<N1>
where where
N1: Real, N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R: AlgaRotation<Point3<N2>> + SupersetOf<UnitQuaternion<N1>>, R: AlgaRotation<Point3<N2>> + SupersetOf<Self>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Isometry<N2, U3, R> { fn to_superset(&self) -> Isometry<N2, U3, R> {
@ -125,7 +125,7 @@ impl<N1, N2, R> SubsetOf<Similarity<N2, U3, R>> for UnitQuaternion<N1>
where where
N1: Real, N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R: AlgaRotation<Point3<N2>> + SupersetOf<UnitQuaternion<N1>>, R: AlgaRotation<Point3<N2>> + SupersetOf<Self>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Similarity<N2, U3, R> { fn to_superset(&self) -> Similarity<N2, U3, R> {
@ -186,7 +186,7 @@ impl<N1: Real, N2: Real + SupersetOf<N1>> SubsetOf<Matrix4<N2>> for UnitQuaterni
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
impl<N: Real> From<mint::Quaternion<N>> for Quaternion<N> { impl<N: Real> From<mint::Quaternion<N>> for Quaternion<N> {
fn from(q: mint::Quaternion<N>) -> Self { fn from(q: mint::Quaternion<N>) -> Self {
Quaternion::new(q.s, q.v.x, q.v.y, q.v.z) Self::new(q.s, q.v.x, q.v.y, q.v.z)
} }
} }
@ -220,14 +220,28 @@ impl<N: Real> Into<mint::Quaternion<N>> for UnitQuaternion<N> {
impl<N: Real> From<UnitQuaternion<N>> for Matrix4<N> { impl<N: Real> From<UnitQuaternion<N>> for Matrix4<N> {
#[inline] #[inline]
fn from(q: UnitQuaternion<N>) -> Matrix4<N> { fn from(q: UnitQuaternion<N>) -> Self {
q.to_homogeneous() q.to_homogeneous()
} }
} }
impl<N: Real> From<UnitQuaternion<N>> for Rotation3<N> {
#[inline]
fn from(q: UnitQuaternion<N>) -> Self {
q.to_rotation_matrix()
}
}
impl<N: Real> From<Rotation3<N>> for UnitQuaternion<N> {
#[inline]
fn from(q: Rotation3<N>) -> Self {
Self::from_rotation_matrix(&q)
}
}
impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> { impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> {
#[inline] #[inline]
fn from(q: UnitQuaternion<N>) -> Matrix3<N> { fn from(q: UnitQuaternion<N>) -> Self {
q.to_rotation_matrix().into_inner() q.to_rotation_matrix().into_inner()
} }
} }
@ -235,6 +249,6 @@ impl<N: Real> From<UnitQuaternion<N>> for Matrix3<N> {
impl<N: Real> From<Vector4<N>> for Quaternion<N> { impl<N: Real> From<Vector4<N>> for Quaternion<N> {
#[inline] #[inline]
fn from(coords: Vector4<N>) -> Self { fn from(coords: Vector4<N>) -> Self {
Quaternion { coords } Self { coords }
} }
} }

View File

@ -67,7 +67,7 @@ impl<N: Real> Index<usize> for Quaternion<N> {
type Output = N; type Output = N;
#[inline] #[inline]
fn index(&self, i: usize) -> &N { fn index(&self, i: usize) -> &Self::Output {
&self.coords[i] &self.coords[i]
} }
} }

View File

@ -18,8 +18,8 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
/// ///
/// The bias is the position of the plane on the axis. In particular, a bias equal to zero /// The bias is the position of the plane on the axis. In particular, a bias equal to zero
/// represents a plane that passes through the origin. /// represents a plane that passes through the origin.
pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Reflection<N, D, S> { pub fn new(axis: Unit<Vector<N, D, S>>, bias: N) -> Self {
Reflection { Self {
axis: axis.into_inner(), axis: axis.into_inner(),
bias: bias, bias: bias,
} }
@ -30,7 +30,7 @@ impl<N: Real, D: Dim, S: Storage<N, D>> Reflection<N, D, S> {
pub fn new_containing_point( pub fn new_containing_point(
axis: Unit<Vector<N, D, S>>, axis: Unit<Vector<N, D, S>>,
pt: &Point<N, D>, pt: &Point<N, D>,
) -> Reflection<N, D, S> ) -> Self
where where
D: DimName, D: DimName,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,

View File

@ -53,7 +53,7 @@ where
{ {
#[inline] #[inline]
fn clone(&self) -> Self { fn clone(&self) -> Self {
Rotation::from_matrix_unchecked(self.matrix.clone()) Self::from_matrix_unchecked(self.matrix.clone())
} }
} }
@ -100,7 +100,7 @@ where
where Des: Deserializer<'a> { where Des: Deserializer<'a> {
let matrix = MatrixN::<N, D>::deserialize(deserializer)?; let matrix = MatrixN::<N, D>::deserialize(deserializer)?;
Ok(Rotation::from_matrix_unchecked(matrix)) Ok(Self::from_matrix_unchecked(matrix))
} }
} }
@ -241,13 +241,13 @@ where DefaultAllocator: Allocator<N, D, D>
/// assert_eq!(*rot.matrix(), mat); /// assert_eq!(*rot.matrix(), mat);
/// ``` /// ```
#[inline] #[inline]
pub fn from_matrix_unchecked(matrix: MatrixN<N, D>) -> Rotation<N, D> { pub fn from_matrix_unchecked(matrix: MatrixN<N, D>) -> Self {
assert!( assert!(
matrix.is_square(), matrix.is_square(),
"Unable to create a rotation from a non-square matrix." "Unable to create a rotation from a non-square matrix."
); );
Rotation { matrix: matrix } Self { matrix: matrix }
} }
/// Transposes `self`. /// Transposes `self`.
@ -257,7 +257,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let tr_rot = rot.transpose(); /// let tr_rot = rot.transpose();
@ -270,8 +269,8 @@ where DefaultAllocator: Allocator<N, D, D>
/// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn transpose(&self) -> Rotation<N, D> { pub fn transpose(&self) -> Self {
Rotation::from_matrix_unchecked(self.matrix.transpose()) Self::from_matrix_unchecked(self.matrix.transpose())
} }
/// Inverts `self`. /// Inverts `self`.
@ -281,7 +280,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let inv = rot.inverse(); /// let inv = rot.inverse();
@ -294,7 +292,7 @@ where DefaultAllocator: Allocator<N, D, D>
/// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn inverse(&self) -> Rotation<N, D> { pub fn inverse(&self) -> Self {
self.transpose() self.transpose()
} }
@ -305,7 +303,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
@ -333,7 +330,6 @@ where DefaultAllocator: Allocator<N, D, D>
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// # use nalgebra::{Rotation2, Rotation3, Vector3};
/// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
/// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0));
@ -361,7 +357,7 @@ impl<N: Scalar + PartialEq, D: DimName> PartialEq for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>
{ {
#[inline] #[inline]
fn eq(&self, right: &Rotation<N, D>) -> bool { fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix self.matrix == right.matrix
} }
} }

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::{ use alga::linear::{
self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
@ -27,16 +27,16 @@ where DefaultAllocator: Allocator<N, D, D>
} }
} }
impl<N: Real, D: DimName> Inverse<Multiplicative> for Rotation<N, D> impl<N: Real, D: DimName> TwoSidedInverse<Multiplicative> for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D> where DefaultAllocator: Allocator<N, D, D>
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.transpose() self.transpose()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.transpose_mut() self.transpose_mut()
} }
} }

View File

@ -102,7 +102,7 @@ impl<N1, N2, D: DimName, R> SubsetOf<Isometry<N2, D, R>> for Rotation<N1, D>
where where
N1: Real, N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R: AlgaRotation<Point<N2, D>> + SupersetOf<Rotation<N1, D>>, R: AlgaRotation<Point<N2, D>> + SupersetOf<Self>,
DefaultAllocator: Allocator<N1, D, D> + Allocator<N2, D>, DefaultAllocator: Allocator<N1, D, D> + Allocator<N2, D>,
{ {
#[inline] #[inline]
@ -125,7 +125,7 @@ impl<N1, N2, D: DimName, R> SubsetOf<Similarity<N2, D, R>> for Rotation<N1, D>
where where
N1: Real, N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R: AlgaRotation<Point<N2, D>> + SupersetOf<Rotation<N1, D>>, R: AlgaRotation<Point<N2, D>> + SupersetOf<Self>,
DefaultAllocator: Allocator<N1, D, D> + Allocator<N2, D>, DefaultAllocator: Allocator<N1, D, D> + Allocator<N2, D>,
{ {
#[inline] #[inline]
@ -219,28 +219,28 @@ impl<N: Real> From<mint::EulerAngles<N, mint::IntraXYZ>> for Rotation3<N> {
impl<N: Real> From<Rotation2<N>> for Matrix3<N> { impl<N: Real> From<Rotation2<N>> for Matrix3<N> {
#[inline] #[inline]
fn from(q: Rotation2<N>) -> Matrix3<N> { fn from(q: Rotation2<N>) ->Self {
q.to_homogeneous() q.to_homogeneous()
} }
} }
impl<N: Real> From<Rotation2<N>> for Matrix2<N> { impl<N: Real> From<Rotation2<N>> for Matrix2<N> {
#[inline] #[inline]
fn from(q: Rotation2<N>) -> Matrix2<N> { fn from(q: Rotation2<N>) -> Self {
q.into_inner() q.into_inner()
} }
} }
impl<N: Real> From<Rotation3<N>> for Matrix4<N> { impl<N: Real> From<Rotation3<N>> for Matrix4<N> {
#[inline] #[inline]
fn from(q: Rotation3<N>) -> Matrix4<N> { fn from(q: Rotation3<N>) -> Self {
q.to_homogeneous() q.to_homogeneous()
} }
} }
impl<N: Real> From<Rotation3<N>> for Matrix3<N> { impl<N: Real> From<Rotation3<N>> for Matrix3<N> {
#[inline] #[inline]
fn from(q: Rotation3<N>) -> Matrix3<N> { fn from(q: Rotation3<N>) -> Self {
q.into_inner() q.into_inner()
} }
} }

View File

@ -11,9 +11,9 @@ use std::ops::Neg;
use base::dimension::{U1, U2, U3}; use base::dimension::{U1, U2, U3};
use base::storage::Storage; use base::storage::Storage;
use base::{MatrixN, Unit, Vector, Vector1, Vector3, VectorN}; use base::{Matrix2, Matrix3, MatrixN, Unit, Vector, Vector1, Vector3, VectorN};
use geometry::{Rotation2, Rotation3, UnitComplex}; use geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion};
/* /*
* *
@ -27,7 +27,6 @@ impl<N: Real> Rotation2<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation2, Point2}; /// # use nalgebra::{Rotation2, Point2};
/// let rot = Rotation2::new(f32::consts::FRAC_PI_2); /// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
@ -36,7 +35,7 @@ impl<N: Real> Rotation2<N> {
/// ``` /// ```
pub fn new(angle: N) -> Self { pub fn new(angle: N) -> Self {
let (sia, coa) = angle.sin_cos(); let (sia, coa) = angle.sin_cos();
Self::from_matrix_unchecked(MatrixN::<N, U2>::new(coa, -sia, sia, coa)) Self::from_matrix_unchecked(Matrix2::new(coa, -sia, sia, coa))
} }
/// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector. /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector.
@ -49,6 +48,51 @@ impl<N: Real> Rotation2<N> {
Self::new(axisangle[0]) Self::new(axisangle[0])
} }
/// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
///
/// This is an iterative method. See `.from_matrix_eps` to provide mover
/// convergence parameters and starting solution.
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
pub fn from_matrix(m: &Matrix2<N>) -> Self {
Self::from_matrix_eps(m, N::default_epsilon(), 0, Self::identity())
}
/// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
///
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
///
/// # Parameters
///
/// * `m`: the matrix from which the rotational part is to be extracted.
/// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
/// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
/// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
/// to the actual solution is provided. Can be set to `Rotation2::identity()` if no other
/// guesses come to mind.
pub fn from_matrix_eps(m: &Matrix2<N>, eps: N, mut max_iter: usize, guess: Self) -> Self {
if max_iter == 0 {
max_iter = usize::max_value();
}
let mut rot = guess.into_inner();
for _ in 0..max_iter {
let axis = rot.column(0).perp(&m.column(0)) +
rot.column(1).perp(&m.column(1));
let denom = rot.column(0).dot(&m.column(0)) +
rot.column(1).dot(&m.column(1));
let angle = axis / (denom.abs() + N::default_epsilon());
if angle.abs() > eps {
rot = Self::new(angle) * rot;
} else {
break;
}
}
Self::from_matrix_unchecked(rot)
}
/// The rotation matrix required to align `a` and `b` but with its angle. /// The rotation matrix required to align `a` and `b` but with its angle.
/// ///
/// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
@ -56,7 +100,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2}; /// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -79,7 +122,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, Rotation2}; /// # use nalgebra::{Vector2, Rotation2};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -100,15 +142,12 @@ impl<N: Real> Rotation2<N> {
{ {
::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) ::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix())
} }
}
impl<N: Real> Rotation2<N> {
/// The rotation angle. /// The rotation angle.
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(1.78); /// let rot = Rotation2::new(1.78);
/// assert_relative_eq!(rot.angle(), 1.78); /// assert_relative_eq!(rot.angle(), 1.78);
@ -123,14 +162,13 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1); /// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7); /// let rot2 = Rotation2::new(1.7);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
/// ``` /// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &Rotation2<N>) -> N { pub fn angle_to(&self, other: &Self) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
} }
@ -141,7 +179,6 @@ impl<N: Real> Rotation2<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot1 = Rotation2::new(0.1); /// let rot1 = Rotation2::new(0.1);
/// let rot2 = Rotation2::new(1.7); /// let rot2 = Rotation2::new(1.7);
@ -151,24 +188,37 @@ impl<N: Real> Rotation2<N> {
/// assert_relative_eq!(rot_to.inverse() * rot2, rot1); /// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
/// ``` /// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &Rotation2<N>) -> Rotation2<N> { pub fn rotation_to(&self, other: &Self) -> Self {
other * self.inverse() other * self.inverse()
} }
/* FIXME: requires alga v0.9 to be released so that Complex implements VectorSpace.
/// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated
/// computations might cause the matrix from progressively not being orthonormal anymore.
#[inline]
pub fn renormalize(&mut self) {
let mut c = UnitComplex::from(*self);
let _ = c.renormalize();
*self = Self::from_matrix_eps(self.matrix(), N::default_epsilon(), 0, c.into())
}
*/
/// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle
/// of `self` multiplied by `n`. /// of `self` multiplied by `n`.
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation2; /// # use nalgebra::Rotation2;
/// let rot = Rotation2::new(0.78); /// let rot = Rotation2::new(0.78);
/// let pow = rot.powf(2.0); /// let pow = rot.powf(2.0);
/// assert_relative_eq!(pow.angle(), 2.0 * 0.78); /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
/// ``` /// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Rotation2<N> { pub fn powf(&self, n: N) -> Self {
Self::new(self.angle() * n) Self::new(self.angle() * n)
} }
@ -217,7 +267,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3}; /// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -238,6 +287,54 @@ impl<N: Real> Rotation3<N> {
Self::from_axis_angle(&axis, angle) Self::from_axis_angle(&axis, angle)
} }
/// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
///
/// This is an iterative method. See `.from_matrix_eps` to provide mover
/// convergence parameters and starting solution.
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
pub fn from_matrix(m: &Matrix3<N>) -> Self {
Self::from_matrix_eps(m, N::default_epsilon(), 0, Self::identity())
}
/// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
///
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
///
/// # Parameters
///
/// * `m`: the matrix from which the rotational part is to be extracted.
/// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
/// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
/// * `guess`: a guess of the solution. Convergence will be significantly faster if an initial solution close
/// to the actual solution is provided. Can be set to `Rotation3::identity()` if no other
/// guesses come to mind.
pub fn from_matrix_eps(m: &Matrix3<N>, eps: N, mut max_iter: usize, guess: Self) -> Self {
if max_iter == 0 {
max_iter = usize::max_value();
}
let mut rot = guess.into_inner();
for _ in 0..max_iter {
let axis = rot.column(0).cross(&m.column(0)) +
rot.column(1).cross(&m.column(1)) +
rot.column(2).cross(&m.column(2));
let denom = rot.column(0).dot(&m.column(0)) +
rot.column(1).dot(&m.column(1)) +
rot.column(2).dot(&m.column(2));
let axisangle = axis / (denom.abs() + N::default_epsilon());
if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, eps) {
rot = Rotation3::from_axis_angle(&axis, angle) * rot;
} else {
break;
}
}
Self::from_matrix_unchecked(rot)
}
/// Builds a 3D rotation matrix from an axis scaled by the rotation angle. /// Builds a 3D rotation matrix from an axis scaled by the rotation angle.
/// ///
/// This is the same as `Self::new(axisangle)`. /// This is the same as `Self::new(axisangle)`.
@ -245,7 +342,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3}; /// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -269,7 +365,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Point3, Vector3}; /// # use nalgebra::{Rotation3, Point3, Vector3};
/// let axis = Vector3::y_axis(); /// let axis = Vector3::y_axis();
@ -322,7 +417,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3; /// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -363,7 +457,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::Rotation3; /// # use nalgebra::Rotation3;
/// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
/// let euler = rot.euler_angles(); /// let euler = rot.euler_angles();
@ -390,6 +483,16 @@ impl<N: Real> Rotation3<N> {
} }
} }
/// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated
/// computations might cause the matrix from progressively not being orthonormal anymore.
#[inline]
pub fn renormalize(&mut self) {
let mut c = UnitQuaternion::from(*self);
let _ = c.renormalize();
*self = Self::from_matrix_eps(self.matrix(), N::default_epsilon(), 0, c.into())
}
/// Creates a rotation that corresponds to the local frame of an observer standing at the /// Creates a rotation that corresponds to the local frame of an observer standing at the
/// origin and looking toward `dir`. /// origin and looking toward `dir`.
/// ///
@ -403,17 +506,16 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// let rot = Rotation3::new_observer_frame(&dir, &up); /// let rot = Rotation3::face_towards(&dir, &up);
/// assert_relative_eq!(rot * Vector3::z(), dir.normalize()); /// assert_relative_eq!(rot * Vector3::z(), dir.normalize());
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self pub fn face_towards<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where where
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
@ -427,6 +529,16 @@ impl<N: Real> Rotation3<N> {
)) ))
} }
/// Deprecated: Use [Rotation3::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames<SB, SC>(dir: &Vector<N, U3, SB>, up: &Vector<N, U3, SC>) -> Self
where
SB: Storage<N, U3>,
SC: Storage<N, U3>,
{
Self::face_towards(dir, up)
}
/// Builds a right-handed look-at view matrix without translation. /// Builds a right-handed look-at view matrix without translation.
/// ///
/// It maps the view direction `dir` to the **negative** `z` axis. /// It maps the view direction `dir` to the **negative** `z` axis.
@ -441,7 +553,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -456,7 +567,7 @@ impl<N: Real> Rotation3<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(&dir.neg(), up).inverse() Self::face_towards(&dir.neg(), up).inverse()
} }
/// Builds a left-handed look-at view matrix without translation. /// Builds a left-handed look-at view matrix without translation.
@ -473,7 +584,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let dir = Vector3::new(1.0, 2.0, 3.0); /// let dir = Vector3::new(1.0, 2.0, 3.0);
@ -488,7 +598,7 @@ impl<N: Real> Rotation3<N> {
SB: Storage<N, U3>, SB: Storage<N, U3>,
SC: Storage<N, U3>, SC: Storage<N, U3>,
{ {
Self::new_observer_frame(dir, up).inverse() Self::face_towards(dir, up).inverse()
} }
/// The rotation matrix required to align `a` and `b` but with its angle. /// The rotation matrix required to align `a` and `b` but with its angle.
@ -498,7 +608,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3}; /// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -521,7 +630,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector3, Rotation3}; /// # use nalgebra::{Vector3, Rotation3};
/// let a = Vector3::new(1.0, 2.0, 3.0); /// let a = Vector3::new(1.0, 2.0, 3.0);
/// let b = Vector3::new(3.0, 1.0, 2.0); /// let b = Vector3::new(3.0, 1.0, 2.0);
@ -566,7 +674,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Rotation3, Vector3}; /// # use nalgebra::{Unit, Rotation3, Vector3};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let rot = Rotation3::from_axis_angle(&axis, 1.78); /// let rot = Rotation3::from_axis_angle(&axis, 1.78);
@ -584,7 +691,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -611,7 +717,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axisangle = Vector3::new(0.1, 0.2, 0.3); /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
/// let rot = Rotation3::new(axisangle); /// let rot = Rotation3::new(axisangle);
@ -633,7 +738,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -660,14 +764,13 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn angle_to(&self, other: &Rotation3<N>) -> N { pub fn angle_to(&self, other: &Self) -> N {
self.rotation_to(other).angle() self.rotation_to(other).angle()
} }
@ -678,7 +781,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3}; /// # use nalgebra::{Rotation3, Vector3};
/// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
/// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
@ -686,7 +788,7 @@ impl<N: Real> Rotation3<N> {
/// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn rotation_to(&self, other: &Rotation3<N>) -> Rotation3<N> { pub fn rotation_to(&self, other: &Self) -> Self {
other * self.inverse() other * self.inverse()
} }
@ -696,7 +798,6 @@ impl<N: Real> Rotation3<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Rotation3, Vector3, Unit}; /// # use nalgebra::{Rotation3, Vector3, Unit};
/// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
/// let angle = 1.2; /// let angle = 1.2;
@ -706,7 +807,7 @@ impl<N: Real> Rotation3<N> {
/// assert_eq!(pow.angle(), 2.4); /// assert_eq!(pow.angle(), 2.4);
/// ``` /// ```
#[inline] #[inline]
pub fn powf(&self, n: N) -> Rotation3<N> { pub fn powf(&self, n: N) -> Self {
if let Some(axis) = self.axis() { if let Some(axis) = self.axis() {
Self::from_axis_angle(&axis, self.angle() * n) Self::from_axis_angle(&axis, self.angle() * n)
} else if self.matrix()[(0, 0)] < N::zero() { } else if self.matrix()[(0, 0)] < N::zero() {

View File

@ -106,20 +106,20 @@ where
translation: Translation<N, D>, translation: Translation<N, D>,
rotation: R, rotation: R,
scaling: N, scaling: N,
) -> Similarity<N, D, R> ) -> Self
{ {
Similarity::from_isometry(Isometry::from_parts(translation, rotation), scaling) Self::from_isometry(Isometry::from_parts(translation, rotation), scaling)
} }
/// Creates a new similarity from its rotational and translational parts. /// Creates a new similarity from its rotational and translational parts.
#[inline] #[inline]
pub fn from_isometry(isometry: Isometry<N, D, R>, scaling: N) -> Similarity<N, D, R> { pub fn from_isometry(isometry: Isometry<N, D, R>, scaling: N) -> Self {
assert!( assert!(
!relative_eq!(scaling, N::zero()), !relative_eq!(scaling, N::zero()),
"The scaling factor must not be zero." "The scaling factor must not be zero."
); );
Similarity { Self {
isometry: isometry, isometry: isometry,
scaling: scaling, scaling: scaling,
} }
@ -127,13 +127,13 @@ where
/// Creates a new similarity that applies only a scaling factor. /// Creates a new similarity that applies only a scaling factor.
#[inline] #[inline]
pub fn from_scaling(scaling: N) -> Similarity<N, D, R> { pub fn from_scaling(scaling: N) -> Self {
Self::from_isometry(Isometry::identity(), scaling) Self::from_isometry(Isometry::identity(), scaling)
} }
/// Inverts `self`. /// Inverts `self`.
#[inline] #[inline]
pub fn inverse(&self) -> Similarity<N, D, R> { pub fn inverse(&self) -> Self {
let mut res = self.clone(); let mut res = self.clone();
res.inverse_mut(); res.inverse_mut();
res res
@ -277,7 +277,7 @@ where
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
#[inline] #[inline]
fn eq(&self, right: &Similarity<N, D, R>) -> bool { fn eq(&self, right: &Self) -> bool {
self.isometry == right.isometry && self.scaling == right.scaling self.isometry == right.isometry && self.scaling == right.scaling
} }
} }

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::Similarity as AlgaSimilarity; use alga::linear::Similarity as AlgaSimilarity;
use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation}; use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation};
@ -27,18 +27,18 @@ where
} }
} }
impl<N: Real, D: DimName, R> Inverse<Multiplicative> for Similarity<N, D, R> impl<N: Real, D: DimName, R> TwoSidedInverse<Multiplicative> for Similarity<N, D, R>
where where
R: Rotation<Point<N, D>>, R: Rotation<Point<N, D>>,
DefaultAllocator: Allocator<N, D>, DefaultAllocator: Allocator<N, D>,
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -86,7 +86,6 @@ where
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity2, Point2, UnitComplex}; /// # use nalgebra::{Similarity2, Point2, UnitComplex};
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
@ -135,7 +134,6 @@ impl<N: Real> Similarity<N, U2, Rotation2<N>> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{SimilarityMatrix2, Vector2, Point2}; /// # use nalgebra::{SimilarityMatrix2, Vector2, Point2};
/// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0); /// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
@ -159,7 +157,6 @@ impl<N: Real> Similarity<N, U2, UnitComplex<N>> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity2, Vector2, Point2}; /// # use nalgebra::{Similarity2, Vector2, Point2};
/// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0); /// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0);
@ -187,7 +184,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
@ -227,7 +223,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -235,22 +230,32 @@ macro_rules! similarity_construction_impl(
/// let up = Vector3::y(); /// let up = Vector3::y();
/// ///
/// // Similarity with its rotation part represented as a UnitQuaternion /// // Similarity with its rotation part represented as a UnitQuaternion
/// let sim = Similarity3::new_observer_frame(&eye, &target, &up, 3.0); /// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0);
/// assert_eq!(sim * Point3::origin(), eye); /// assert_eq!(sim * Point3::origin(), eye);
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6); /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
/// ///
/// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix). /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
/// let sim = SimilarityMatrix3::new_observer_frame(&eye, &target, &up, 3.0); /// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0);
/// assert_eq!(sim * Point3::origin(), eye); /// assert_eq!(sim * Point3::origin(), eye);
/// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6); /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6);
/// ``` /// ```
#[inline] #[inline]
pub fn new_observer_frame(eye: &Point3<N>, pub fn face_towards(eye: &Point3<N>,
target: &Point3<N>, target: &Point3<N>,
up: &Vector3<N>, up: &Vector3<N>,
scaling: N) scaling: N)
-> Self { -> Self {
Self::from_isometry(Isometry::<_, U3, $Rot>::new_observer_frame(eye, target, up), scaling) Self::from_isometry(Isometry::<_, U3, $Rot>::face_towards(eye, target, up), scaling)
}
/// Deprecated: Use [SimilarityMatrix3::face_towards] instead.
#[deprecated(note="renamed to `face_towards`")]
pub fn new_observer_frames(eye: &Point3<N>,
target: &Point3<N>,
up: &Vector3<N>,
scaling: N)
-> Self {
Self::face_towards(eye, target, up, scaling)
} }
/// Builds a right-handed look-at view matrix including scaling factor. /// Builds a right-handed look-at view matrix including scaling factor.
@ -268,7 +273,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);
@ -307,7 +311,6 @@ macro_rules! similarity_construction_impl(
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3};
/// let eye = Point3::new(1.0, 2.0, 3.0); /// let eye = Point3::new(1.0, 2.0, 3.0);

View File

@ -222,8 +222,8 @@ similarity_binop_assign_impl_all!(
DivAssign, div_assign; DivAssign, div_assign;
self: Similarity<N, D, R>, rhs: R; self: Similarity<N, D, R>, rhs: R;
// FIXME: don't invert explicitly? // FIXME: don't invert explicitly?
[val] => *self *= rhs.inverse(); [val] => *self *= rhs.two_sided_inverse();
[ref] => *self *= rhs.inverse(); [ref] => *self *= rhs.two_sided_inverse();
); );
// Similarity × R // Similarity × R

View File

@ -350,7 +350,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Transform2}; /// # use nalgebra::{Matrix3, Transform2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,
@ -383,7 +382,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Projective2}; /// # use nalgebra::{Matrix3, Projective2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,
@ -407,7 +405,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Transform2}; /// # use nalgebra::{Matrix3, Transform2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,
@ -437,7 +434,6 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
/// # Examples /// # Examples
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Matrix3, Projective2}; /// # use nalgebra::{Matrix3, Projective2};
/// ///
/// let m = Matrix3::new(2.0, 2.0, -0.3, /// let m = Matrix3::new(2.0, 2.0, -0.3,

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::{ProjectiveTransformation, Transformation}; use alga::linear::{ProjectiveTransformation, Transformation};
@ -26,18 +26,18 @@ where
} }
} }
impl<N: Real, D: DimNameAdd<U1>, C> Inverse<Multiplicative> for Transform<N, D, C> impl<N: Real, D: DimNameAdd<U1>, C> TwoSidedInverse<Multiplicative> for Transform<N, D, C>
where where
C: SubTCategoryOf<TProjective>, C: SubTCategoryOf<TProjective>,
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>, DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.clone().inverse() self.clone().inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }
@ -116,12 +116,12 @@ where
{ {
#[inline] #[inline]
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> { fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
self.inverse() * pt self.two_sided_inverse() * pt
} }
#[inline] #[inline]
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> { fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
self.inverse() * v self.two_sided_inverse() * v
} }
} }

View File

@ -57,7 +57,7 @@ where
#[inline] #[inline]
unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self { unsafe fn from_superset_unchecked(m: &MatrixN<N2, DimNameSum<D, U1>>) -> Self {
Transform::from_matrix_unchecked(::convert_ref_unchecked(m)) Self::from_matrix_unchecked(::convert_ref_unchecked(m))
} }
} }

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::Translation as AlgaTranslation; use alga::linear::Translation as AlgaTranslation;
use alga::linear::{ use alga::linear::{
@ -28,16 +28,16 @@ where DefaultAllocator: Allocator<N, D>
} }
} }
impl<N: Real, D: DimName> Inverse<Multiplicative> for Translation<N, D> impl<N: Real, D: DimName> TwoSidedInverse<Multiplicative> for Translation<N, D>
where DefaultAllocator: Allocator<N, D> where DefaultAllocator: Allocator<N, D>
{ {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -0,0 +1,44 @@
use std::mem;
use std::ops::{Deref, DerefMut};
use base::allocator::Allocator;
use base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB};
use base::dimension::{U1, U2, U3, U4, U5, U6};
use base::{DefaultAllocator, Scalar};
use geometry::Translation;
/*
*
* Give coordinates to Translation{1 .. 6}
*
*/
macro_rules! deref_impl(
($D: ty, $Target: ident $(, $comps: ident)*) => {
impl<N: Scalar> Deref for Translation<N, $D>
where DefaultAllocator: Allocator<N, $D> {
type Target = $Target<N>;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) }
}
}
impl<N: Scalar> DerefMut for Translation<N, $D>
where DefaultAllocator: Allocator<N, $D> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { mem::transmute(self) }
}
}
}
);
deref_impl!(U1, X, x);
deref_impl!(U2, XY, x, y);
deref_impl!(U3, XYZ, x, y, z);
deref_impl!(U4, XYZW, x, y, z, w);
deref_impl!(U5, XYZWA, x, y, z, w, a);
deref_impl!(U6, XYZWAB, x, y, z, w, a, b);

View File

@ -85,7 +85,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # extern crate num_complex; /// # extern crate num_complex;
/// # extern crate nalgebra;
/// # use num_complex::Complex; /// # use num_complex::Complex;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let angle = 1.78f32; /// let angle = 1.78f32;
@ -109,7 +108,7 @@ impl<N: Real> UnitComplex<N> {
/// ``` /// ```
#[inline] #[inline]
pub fn conjugate(&self) -> Self { pub fn conjugate(&self) -> Self {
UnitComplex::new_unchecked(self.conj()) Self::new_unchecked(self.conj())
} }
/// Inverts this complex number if it is not zero. /// Inverts this complex number if it is not zero.
@ -117,7 +116,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(1.2); /// let rot = UnitComplex::new(1.2);
/// let inv = rot.inverse(); /// let inv = rot.inverse();
@ -134,7 +132,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot1 = UnitComplex::new(0.1); /// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7); /// let rot2 = UnitComplex::new(1.7);
@ -153,7 +150,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot1 = UnitComplex::new(0.1); /// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7); /// let rot2 = UnitComplex::new(1.7);
@ -172,7 +168,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let angle = 1.7; /// let angle = 1.7;
/// let rot = UnitComplex::new(angle); /// let rot = UnitComplex::new(angle);
@ -192,7 +187,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let angle = 1.7; /// let angle = 1.7;
/// let mut rot = UnitComplex::new(angle); /// let mut rot = UnitComplex::new(angle);
@ -213,7 +207,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::UnitComplex; /// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(0.78); /// let rot = UnitComplex::new(0.78);
/// let pow = rot.powf(2.0); /// let pow = rot.powf(2.0);
@ -310,18 +303,4 @@ impl<N: Real> UlpsEq for UnitComplex<N> {
self.re.ulps_eq(&other.re, epsilon, max_ulps) self.re.ulps_eq(&other.re, epsilon, max_ulps)
&& self.im.ulps_eq(&other.im, epsilon, max_ulps) && self.im.ulps_eq(&other.im, epsilon, max_ulps)
} }
} }
impl<N: Real> From<UnitComplex<N>> for Matrix3<N> {
#[inline]
fn from(q: UnitComplex<N>) -> Matrix3<N> {
q.to_homogeneous()
}
}
impl<N: Real> From<UnitComplex<N>> for Matrix2<N> {
#[inline]
fn from(q: UnitComplex<N>) -> Matrix2<N> {
q.to_rotation_matrix().into_inner()
}
}

View File

@ -1,6 +1,6 @@
use alga::general::{ use alga::general::{
AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup,
AbstractSemigroup, Id, Identity, Inverse, Multiplicative, Real, AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real,
}; };
use alga::linear::{ use alga::linear::{
AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation,
@ -31,14 +31,14 @@ impl<N: Real> AbstractMagma<Multiplicative> for UnitComplex<N> {
} }
} }
impl<N: Real> Inverse<Multiplicative> for UnitComplex<N> { impl<N: Real> TwoSidedInverse<Multiplicative> for UnitComplex<N> {
#[inline] #[inline]
fn inverse(&self) -> Self { fn two_sided_inverse(&self) -> Self {
self.inverse() self.inverse()
} }
#[inline] #[inline]
fn inverse_mut(&mut self) { fn two_sided_inverse_mut(&mut self) {
self.inverse_mut() self.inverse_mut()
} }
} }

View File

@ -9,7 +9,7 @@ use rand::Rng;
use alga::general::Real; use alga::general::Real;
use base::dimension::{U1, U2}; use base::dimension::{U1, U2};
use base::storage::Storage; use base::storage::Storage;
use base::{Unit, Vector}; use base::{Unit, Vector, Matrix2};
use geometry::{Rotation2, UnitComplex}; use geometry::{Rotation2, UnitComplex};
impl<N: Real> UnitComplex<N> { impl<N: Real> UnitComplex<N> {
@ -35,7 +35,6 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitComplex, Point2}; /// # use nalgebra::{UnitComplex, Point2};
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
@ -56,7 +55,6 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitComplex, Point2}; /// # use nalgebra::{UnitComplex, Point2};
/// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2); /// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2);
@ -78,7 +76,6 @@ impl<N: Real> UnitComplex<N> {
/// ///
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use std::f32; /// # use std::f32;
/// # use nalgebra::{UnitComplex, Vector2, Point2}; /// # use nalgebra::{UnitComplex, Vector2, Point2};
/// let angle = f32::consts::FRAC_PI_2; /// let angle = f32::consts::FRAC_PI_2;
@ -88,7 +85,7 @@ impl<N: Real> UnitComplex<N> {
/// ``` /// ```
#[inline] #[inline]
pub fn from_cos_sin_unchecked(cos: N, sin: N) -> Self { pub fn from_cos_sin_unchecked(cos: N, sin: N) -> Self {
UnitComplex::new_unchecked(Complex::new(cos, sin)) Self::new_unchecked(Complex::new(cos, sin))
} }
/// Builds a unit complex rotation from an angle in radian wrapped in a 1-dimensional vector. /// Builds a unit complex rotation from an angle in radian wrapped in a 1-dimensional vector.
@ -132,13 +129,38 @@ impl<N: Real> UnitComplex<N> {
Self::new_unchecked(Complex::new(rotmat[(0, 0)], rotmat[(1, 0)])) Self::new_unchecked(Complex::new(rotmat[(0, 0)], rotmat[(1, 0)]))
} }
/// Builds an unit complex by extracting the rotation part of the given transformation `m`.
///
/// This is an iterative method. See `.from_matrix_eps` to provide mover
/// convergence parameters and starting solution.
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
pub fn from_matrix(m: &Matrix2<N>) -> Self {
Rotation2::from_matrix(m).into()
}
/// Builds an unit complex by extracting the rotation part of the given transformation `m`.
///
/// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
///
/// # Parameters
///
/// * `m`: the matrix from which the rotational part is to be extracted.
/// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
/// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
/// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
/// to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other
/// guesses come to mind.
pub fn from_matrix_eps(m: &Matrix2<N>, eps: N, max_iter: usize, guess: Self) -> Self {
let guess = Rotation2::from(guess);
Rotation2::from_matrix_eps(m, eps, max_iter, guess).into()
}
/// The unit complex needed to make `a` and `b` be collinear and point toward the same /// The unit complex needed to make `a` and `b` be collinear and point toward the same
/// direction. /// direction.
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, UnitComplex}; /// # use nalgebra::{Vector2, UnitComplex};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -161,7 +183,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Vector2, UnitComplex}; /// # use nalgebra::{Vector2, UnitComplex};
/// let a = Vector2::new(1.0, 2.0); /// let a = Vector2::new(1.0, 2.0);
/// let b = Vector2::new(2.0, 1.0); /// let b = Vector2::new(2.0, 1.0);
@ -197,7 +218,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector2, UnitComplex}; /// # use nalgebra::{Unit, Vector2, UnitComplex};
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0)); /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0)); /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));
@ -223,7 +243,6 @@ impl<N: Real> UnitComplex<N> {
/// # Example /// # Example
/// ``` /// ```
/// # #[macro_use] extern crate approx; /// # #[macro_use] extern crate approx;
/// # extern crate nalgebra;
/// # use nalgebra::{Unit, Vector2, UnitComplex}; /// # use nalgebra::{Unit, Vector2, UnitComplex};
/// let a = Unit::new_normalize(Vector2::new(1.0, 2.0)); /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0));
/// let b = Unit::new_normalize(Vector2::new(2.0, 1.0)); /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0));

View File

@ -5,10 +5,10 @@ use alga::general::{Real, SubsetOf, SupersetOf};
use alga::linear::Rotation as AlgaRotation; use alga::linear::Rotation as AlgaRotation;
use base::dimension::U2; use base::dimension::U2;
use base::Matrix3; use base::{Matrix2, Matrix3};
use geometry::{ use geometry::{
Isometry, Point2, Rotation2, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, Isometry, Point2, Rotation2, Similarity, SuperTCategoryOf, TAffine, Transform, Translation,
UnitComplex, UnitComplex
}; };
/* /*
@ -74,7 +74,7 @@ impl<N1, N2, R> SubsetOf<Isometry<N2, U2, R>> for UnitComplex<N1>
where where
N1: Real, N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R: AlgaRotation<Point2<N2>> + SupersetOf<UnitComplex<N1>>, R: AlgaRotation<Point2<N2>> + SupersetOf<Self>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Isometry<N2, U2, R> { fn to_superset(&self) -> Isometry<N2, U2, R> {
@ -96,7 +96,7 @@ impl<N1, N2, R> SubsetOf<Similarity<N2, U2, R>> for UnitComplex<N1>
where where
N1: Real, N1: Real,
N2: Real + SupersetOf<N1>, N2: Real + SupersetOf<N1>,
R: AlgaRotation<Point2<N2>> + SupersetOf<UnitComplex<N1>>, R: AlgaRotation<Point2<N2>> + SupersetOf<Self>,
{ {
#[inline] #[inline]
fn to_superset(&self) -> Similarity<N2, U2, R> { fn to_superset(&self) -> Similarity<N2, U2, R> {
@ -153,3 +153,32 @@ impl<N1: Real, N2: Real + SupersetOf<N1>> SubsetOf<Matrix3<N2>> for UnitComplex<
Self::from_rotation_matrix(&rot) Self::from_rotation_matrix(&rot)
} }
} }
impl<N: Real> From<UnitComplex<N>> for Rotation2<N> {
#[inline]
fn from(q: UnitComplex<N>) -> Self {
q.to_rotation_matrix()
}
}
impl<N: Real> From<Rotation2<N>> for UnitComplex<N> {
#[inline]
fn from(q: Rotation2<N>) -> Self {
Self::from_rotation_matrix(&q)
}
}
impl<N: Real> From<UnitComplex<N>> for Matrix3<N> {
#[inline]
fn from(q: UnitComplex<N>) -> Matrix3<N> {
q.to_homogeneous()
}
}
impl<N: Real> From<UnitComplex<N>> for Matrix2<N> {
#[inline]
fn from(q: UnitComplex<N>) -> Self {
q.to_rotation_matrix().into_inner()
}
}

View File

@ -45,11 +45,11 @@ use geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex}
*/ */
// UnitComplex × UnitComplex // UnitComplex × UnitComplex
impl<N: Real> Mul<UnitComplex<N>> for UnitComplex<N> { impl<N: Real> Mul<Self> for UnitComplex<N> {
type Output = UnitComplex<N>; type Output = Self;
#[inline] #[inline]
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: Self) -> Self {
Unit::new_unchecked(self.into_inner() * rhs.into_inner()) Unit::new_unchecked(self.into_inner() * rhs.into_inner())
} }
} }
@ -58,16 +58,16 @@ impl<'a, N: Real> Mul<UnitComplex<N>> for &'a UnitComplex<N> {
type Output = UnitComplex<N>; type Output = UnitComplex<N>;
#[inline] #[inline]
fn mul(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: UnitComplex<N>) -> Self::Output {
Unit::new_unchecked(self.complex() * rhs.into_inner()) Unit::new_unchecked(self.complex() * rhs.into_inner())
} }
} }
impl<'b, N: Real> Mul<&'b UnitComplex<N>> for UnitComplex<N> { impl<'b, N: Real> Mul<&'b UnitComplex<N>> for UnitComplex<N> {
type Output = UnitComplex<N>; type Output = Self;
#[inline] #[inline]
fn mul(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: &'b UnitComplex<N>) -> Self::Output {
Unit::new_unchecked(self.into_inner() * rhs.complex()) Unit::new_unchecked(self.into_inner() * rhs.complex())
} }
} }
@ -76,17 +76,17 @@ impl<'a, 'b, N: Real> Mul<&'b UnitComplex<N>> for &'a UnitComplex<N> {
type Output = UnitComplex<N>; type Output = UnitComplex<N>;
#[inline] #[inline]
fn mul(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn mul(self, rhs: &'b UnitComplex<N>) -> Self::Output {
Unit::new_unchecked(self.complex() * rhs.complex()) Unit::new_unchecked(self.complex() * rhs.complex())
} }
} }
// UnitComplex ÷ UnitComplex // UnitComplex ÷ UnitComplex
impl<N: Real> Div<UnitComplex<N>> for UnitComplex<N> { impl<N: Real> Div<Self> for UnitComplex<N> {
type Output = UnitComplex<N>; type Output = Self;
#[inline] #[inline]
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: Self) -> Self::Output {
Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner()) Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner())
} }
} }
@ -95,16 +95,16 @@ impl<'a, N: Real> Div<UnitComplex<N>> for &'a UnitComplex<N> {
type Output = UnitComplex<N>; type Output = UnitComplex<N>;
#[inline] #[inline]
fn div(self, rhs: UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: UnitComplex<N>) -> Self::Output {
Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner()) Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner())
} }
} }
impl<'b, N: Real> Div<&'b UnitComplex<N>> for UnitComplex<N> { impl<'b, N: Real> Div<&'b UnitComplex<N>> for UnitComplex<N> {
type Output = UnitComplex<N>; type Output = Self;
#[inline] #[inline]
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: &'b UnitComplex<N>) -> Self::Output {
Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner()) Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner())
} }
} }
@ -113,7 +113,7 @@ impl<'a, 'b, N: Real> Div<&'b UnitComplex<N>> for &'a UnitComplex<N> {
type Output = UnitComplex<N>; type Output = UnitComplex<N>;
#[inline] #[inline]
fn div(self, rhs: &'b UnitComplex<N>) -> UnitComplex<N> { fn div(self, rhs: &'b UnitComplex<N>) -> Self::Output {
Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner()) Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner())
} }
} }

16
src/io/matrix_market.pest Normal file
View File

@ -0,0 +1,16 @@
WHITESPACE = _{ " " }
Comments = _{ "%" ~ (!NEWLINE ~ ANY)* }
Header = { "%%" ~ (!NEWLINE ~ ANY)* }
Shape = { Dimension ~ Dimension ~ Dimension }
Document = {
SOI ~
NEWLINE* ~
Header ~
(NEWLINE ~ Comments)* ~
(NEWLINE ~ Shape) ~
(NEWLINE ~ Entry?)*
}
Dimension = @{ ASCII_DIGIT+ }
Value = @{ ("+" | "-")? ~ NUMBER+ ~ ("." ~ NUMBER+)? ~ ("e" ~ ("+" | "-")? ~ NUMBER+)? }
Entry = { Dimension ~ Dimension ~ Value }

53
src/io/matrix_market.rs Normal file
View File

@ -0,0 +1,53 @@
use std::fs;
use std::path::Path;
use pest::Parser;
use sparse::CsMatrix;
use Real;
#[derive(Parser)]
#[grammar = "io/matrix_market.pest"]
struct MatrixMarketParser;
// FIXME: return an Error instead of an Option.
/// Parses a Matrix Market file at the given path, and returns the corresponding sparse matrix.
pub fn cs_matrix_from_matrix_market<N: Real, P: AsRef<Path>>(path: P) -> Option<CsMatrix<N>> {
let file = fs::read_to_string(path).ok()?;
cs_matrix_from_matrix_market_str(&file)
}
// FIXME: return an Error instead of an Option.
/// Parses a Matrix Market file described by the given string, and returns the corresponding sparse matrix.
pub fn cs_matrix_from_matrix_market_str<N: Real>(data: &str) -> Option<CsMatrix<N>> {
let file = MatrixMarketParser::parse(Rule::Document, data)
.unwrap()
.next()?;
let mut shape = (0, 0, 0);
let mut rows: Vec<usize> = Vec::new();
let mut cols: Vec<usize> = Vec::new();
let mut data: Vec<N> = Vec::new();
for line in file.into_inner() {
match line.as_rule() {
Rule::Header => {}
Rule::Shape => {
let mut inner = line.into_inner();
shape.0 = inner.next()?.as_str().parse::<usize>().ok()?;
shape.1 = inner.next()?.as_str().parse::<usize>().ok()?;
shape.2 = inner.next()?.as_str().parse::<usize>().ok()?;
}
Rule::Entry => {
let mut inner = line.into_inner();
// NOTE: indices are 1-based.
rows.push(inner.next()?.as_str().parse::<usize>().ok()? - 1);
cols.push(inner.next()?.as_str().parse::<usize>().ok()? - 1);
data.push(::convert(inner.next()?.as_str().parse::<f64>().ok()?));
}
_ => return None, // FIXME: return an Err instead.
}
}
Some(CsMatrix::from_triplet(
shape.0, shape.1, &rows, &cols, &data,
))
}

5
src/io/mod.rs Normal file
View File

@ -0,0 +1,5 @@
//! Parsers for various matrix formats.
pub use self::matrix_market::{cs_matrix_from_matrix_market, cs_matrix_from_matrix_market_str};
mod matrix_market;

View File

@ -15,7 +15,7 @@ Simply add the following to your `Cargo.toml` file:
```.ignore ```.ignore
[dependencies] [dependencies]
nalgebra = "0.16" nalgebra = "0.17"
``` ```
@ -83,8 +83,10 @@ an optimized set of tools for computer graphics and physics. Those features incl
#![deny(unused_results)] #![deny(unused_results)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![warn(incoherent_fundamental_impls)] #![warn(incoherent_fundamental_impls)]
#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico", #![doc(
html_root_url = "http://nalgebra.org/rustdoc")] html_favicon_url = "http://nalgebra.org/img/favicon.ico",
html_root_url = "http://nalgebra.org/rustdoc"
)]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))]
@ -121,11 +123,21 @@ extern crate alloc;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
extern crate core as std; extern crate core as std;
#[cfg(feature = "io")]
extern crate pest;
#[macro_use]
#[cfg(feature = "io")]
extern crate pest_derive;
pub mod base; pub mod base;
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
pub mod debug; pub mod debug;
pub mod geometry; pub mod geometry;
#[cfg(feature = "io")]
pub mod io;
pub mod linalg; pub mod linalg;
#[cfg(feature = "sparse")]
pub mod sparse;
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[deprecated( #[deprecated(
@ -135,11 +147,13 @@ pub use base as core;
pub use base::*; pub use base::*;
pub use geometry::*; pub use geometry::*;
pub use linalg::*; pub use linalg::*;
#[cfg(feature = "sparse")]
pub use sparse::*;
use std::cmp::{self, Ordering, PartialOrd}; use std::cmp::{self, Ordering, PartialOrd};
use alga::general::{ use alga::general::{
Additive, AdditiveGroup, Identity, Inverse, JoinSemilattice, Lattice, MeetSemilattice, Additive, AdditiveGroup, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice,
Multiplicative, SupersetOf, Multiplicative, SupersetOf,
}; };
use alga::linear::SquareMatrix as AlgaSquareMatrix; use alga::linear::SquareMatrix as AlgaSquareMatrix;
@ -413,8 +427,8 @@ pub fn try_inverse<M: AlgaSquareMatrix>(m: &M) -> Option<M> {
/// ///
/// * [`try_inverse`](fn.try_inverse.html) /// * [`try_inverse`](fn.try_inverse.html)
#[inline] #[inline]
pub fn inverse<M: Inverse<Multiplicative>>(m: &M) -> M { pub fn inverse<M: TwoSidedInverse<Multiplicative>>(m: &M) -> M {
m.inverse() m.two_sided_inverse()
} }
/* /*

View File

@ -61,7 +61,7 @@ where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimu
let mut q = PermutationSequence::identity_generic(min_nrows_ncols); let mut q = PermutationSequence::identity_generic(min_nrows_ncols);
if min_nrows_ncols.value() == 0 { if min_nrows_ncols.value() == 0 {
return FullPivLU { return Self {
lu: matrix, lu: matrix,
p: p, p: p,
q: q, q: q,
@ -91,7 +91,7 @@ where DefaultAllocator: Allocator<N, R, C> + Allocator<(usize, usize), DimMinimu
} }
} }
FullPivLU { Self {
lu: matrix, lu: matrix,
p: p, p: p,
q: q, q: q,

View File

@ -69,7 +69,7 @@ where DefaultAllocator: Allocator<(usize, usize), D>
#[inline] #[inline]
pub fn identity_generic(dim: D) -> Self { pub fn identity_generic(dim: D) -> Self {
unsafe { unsafe {
PermutationSequence { Self {
len: 0, len: 0,
ipiv: VectorN::new_uninitialized_generic(dim, U1), ipiv: VectorN::new_uninitialized_generic(dim, U1),
} }

View File

@ -55,7 +55,7 @@ where
+ Allocator<N, D>, + Allocator<N, D>,
{ {
/// Computes the Schur decomposition of a square matrix. /// Computes the Schur decomposition of a square matrix.
pub fn new(m: MatrixN<N, D>) -> RealSchur<N, D> { pub fn new(m: MatrixN<N, D>) -> Self {
Self::try_new(m, N::default_epsilon(), 0).unwrap() Self::try_new(m, N::default_epsilon(), 0).unwrap()
} }
@ -70,7 +70,7 @@ where
/// * `max_niter` maximum total number of iterations performed by the algorithm. If this /// * `max_niter` maximum total number of iterations performed by the algorithm. If this
/// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm
/// continues indefinitely until convergence. /// continues indefinitely until convergence.
pub fn try_new(m: MatrixN<N, D>, eps: N, max_niter: usize) -> Option<RealSchur<N, D>> { pub fn try_new(m: MatrixN<N, D>, eps: N, max_niter: usize) -> Option<Self> {
let mut work = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) }; let mut work = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) };
Self::do_decompose(m, &mut work, eps, max_niter, true).map(|(q, t)| RealSchur { Self::do_decompose(m, &mut work, eps, max_niter, true).map(|(q, t)| RealSchur {

View File

@ -271,7 +271,7 @@ where
} }
} }
Some(SVD { Some(Self {
u: u, u: u,
v_t: v_t, v_t: v_t,
singular_values: b.diagonal, singular_values: b.diagonal,

View File

@ -83,7 +83,7 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimDiff<D, U1>>
} }
} }
SymmetricTridiagonal { Self {
tri: m, tri: m,
off_diagonal: off_diagonal, off_diagonal: off_diagonal,
} }

517
src/sparse/cs_matrix.rs Normal file
View File

@ -0,0 +1,517 @@
use alga::general::ClosedAdd;
use num::Zero;
use std::iter;
use std::marker::PhantomData;
use std::ops::Range;
use std::slice;
use allocator::Allocator;
use sparse::cs_utils;
use {
DefaultAllocator, Dim, Dynamic, Scalar, Vector, VectorN, U1
};
pub struct ColumnEntries<'a, N> {
curr: usize,
i: &'a [usize],
v: &'a [N],
}
impl<'a, N> ColumnEntries<'a, N> {
#[inline]
pub fn new(i: &'a [usize], v: &'a [N]) -> Self {
assert_eq!(i.len(), v.len());
Self { curr: 0, i, v }
}
}
impl<'a, N: Copy> Iterator for ColumnEntries<'a, N> {
type Item = (usize, N);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.curr >= self.i.len() {
None
} else {
let res = Some((unsafe { *self.i.get_unchecked(self.curr) }, unsafe {
*self.v.get_unchecked(self.curr)
}));
self.curr += 1;
res
}
}
}
// FIXME: this structure exists for now only because impl trait
// cannot be used for trait method return types.
/// Trait for iterable compressed-column matrix storage.
pub trait CsStorageIter<'a, N, R, C = U1> {
/// Iterator through all the rows of a specific columns.
///
/// The elements are given as a tuple (row_index, value).
type ColumnEntries: Iterator<Item = (usize, N)>;
/// Iterator through the row indices of a specific column.
type ColumnRowIndices: Iterator<Item = usize>;
/// Iterates through all the row indices of the j-th column.
fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices;
#[inline(always)]
/// Iterates through all the entries of the j-th column.
fn column_entries(&'a self, j: usize) -> Self::ColumnEntries;
}
/// Trait for mutably iterable compressed-column sparse matrix storage.
pub trait CsStorageIterMut<'a, N: 'a, R, C = U1> {
/// Mutable iterator through all the values of the sparse matrix.
type ValuesMut: Iterator<Item = &'a mut N>;
/// Mutable iterator through all the rows of a specific columns.
///
/// The elements are given as a tuple (row_index, value).
type ColumnEntriesMut: Iterator<Item = (usize, &'a mut N)>;
/// A mutable iterator through the values buffer of the sparse matrix.
fn values_mut(&'a mut self) -> Self::ValuesMut;
/// Iterates mutably through all the entries of the j-th column.
fn column_entries_mut(&'a mut self, j: usize) -> Self::ColumnEntriesMut;
}
/// Trait for compressed column sparse matrix storage.
pub trait CsStorage<N, R, C = U1>: for<'a> CsStorageIter<'a, N, R, C> {
/// The shape of the stored matrix.
fn shape(&self) -> (R, C);
/// Retrieve the i-th row index of the underlying row index buffer.
///
/// No bound-checking is performed.
unsafe fn row_index_unchecked(&self, i: usize) -> usize;
/// The i-th value on the contiguous value buffer of this storage.
///
/// No bound-checking is performed.
unsafe fn get_value_unchecked(&self, i: usize) -> &N;
/// The i-th value on the contiguous value buffer of this storage.
fn get_value(&self, i: usize) -> &N;
/// Retrieve the i-th row index of the underlying row index buffer.
fn row_index(&self, i: usize) -> usize;
/// The value indices for the `i`-th column.
fn column_range(&self, i: usize) -> Range<usize>;
/// The size of the value buffer (i.e. the entries known as possibly being non-zero).
fn len(&self) -> usize;
}
/// Trait for compressed column sparse matrix mutable storage.
pub trait CsStorageMut<N, R, C = U1>:
CsStorage<N, R, C> + for<'a> CsStorageIterMut<'a, N, R, C>
{
}
/// A storage of column-compressed sparse matrix based on a Vec.
#[derive(Clone, Debug, PartialEq)]
pub struct CsVecStorage<N: Scalar, R: Dim, C: Dim>
where DefaultAllocator: Allocator<usize, C>
{
pub(crate) shape: (R, C),
pub(crate) p: VectorN<usize, C>,
pub(crate) i: Vec<usize>,
pub(crate) vals: Vec<N>,
}
impl<N: Scalar, R: Dim, C: Dim> CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
/// The value buffer of this storage.
pub fn values(&self) -> &[N] {
&self.vals
}
/// The column shifts buffer.
pub fn p(&self) -> &[usize] {
self.p.as_slice()
}
/// The row index buffers.
pub fn i(&self) -> &[usize] {
&self.i
}
}
impl<N: Scalar, R: Dim, C: Dim> CsVecStorage<N, R, C> where DefaultAllocator: Allocator<usize, C> {}
impl<'a, N: Scalar, R: Dim, C: Dim> CsStorageIter<'a, N, R, C> for CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
type ColumnEntries = ColumnEntries<'a, N>;
type ColumnRowIndices = iter::Cloned<slice::Iter<'a, usize>>;
#[inline]
fn column_entries(&'a self, j: usize) -> Self::ColumnEntries {
let rng = self.column_range(j);
ColumnEntries::new(&self.i[rng.clone()], &self.vals[rng])
}
#[inline]
fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices {
let rng = self.column_range(j);
self.i[rng.clone()].iter().cloned()
}
}
impl<N: Scalar, R: Dim, C: Dim> CsStorage<N, R, C> for CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
#[inline]
fn shape(&self) -> (R, C) {
self.shape
}
#[inline]
fn len(&self) -> usize {
self.vals.len()
}
#[inline]
fn row_index(&self, i: usize) -> usize {
self.i[i]
}
#[inline]
unsafe fn row_index_unchecked(&self, i: usize) -> usize {
*self.i.get_unchecked(i)
}
#[inline]
unsafe fn get_value_unchecked(&self, i: usize) -> &N {
self.vals.get_unchecked(i)
}
#[inline]
fn get_value(&self, i: usize) -> &N {
&self.vals[i]
}
#[inline]
fn column_range(&self, j: usize) -> Range<usize> {
let end = if j + 1 == self.p.len() {
self.len()
} else {
self.p[j + 1]
};
self.p[j]..end
}
}
impl<'a, N: Scalar, R: Dim, C: Dim> CsStorageIterMut<'a, N, R, C> for CsVecStorage<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
type ValuesMut = slice::IterMut<'a, N>;
type ColumnEntriesMut = iter::Zip<iter::Cloned<slice::Iter<'a, usize>>, slice::IterMut<'a, N>>;
#[inline]
fn values_mut(&'a mut self) -> Self::ValuesMut {
self.vals.iter_mut()
}
#[inline]
fn column_entries_mut(&'a mut self, j: usize) -> Self::ColumnEntriesMut {
let rng = self.column_range(j);
self.i[rng.clone()]
.iter()
.cloned()
.zip(self.vals[rng].iter_mut())
}
}
impl<N: Scalar, R: Dim, C: Dim> CsStorageMut<N, R, C> for CsVecStorage<N, R, C> where DefaultAllocator: Allocator<usize, C>
{}
/*
pub struct CsSliceStorage<'a, N: Scalar, R: Dim, C: DimAdd<U1>> {
shape: (R, C),
p: VectorSlice<usize, DimSum<C, U1>>,
i: VectorSlice<usize, Dynamic>,
vals: VectorSlice<N, Dynamic>,
}*/
/// A compressed sparse column matrix.
#[derive(Clone, Debug, PartialEq)]
pub struct CsMatrix<
N: Scalar,
R: Dim = Dynamic,
C: Dim = Dynamic,
S: CsStorage<N, R, C> = CsVecStorage<N, R, C>,
> {
pub(crate) data: S,
_phantoms: PhantomData<(N, R, C)>,
}
/// A column compressed sparse vector.
pub type CsVector<N, R = Dynamic, S = CsVecStorage<N, R, U1>> = CsMatrix<N, R, U1, S>;
impl<N: Scalar, R: Dim, C: Dim> CsMatrix<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
/// Creates a new compressed sparse column matrix with the specified dimension and
/// `nvals` possible non-zero values.
pub fn new_uninitialized_generic(nrows: R, ncols: C, nvals: usize) -> Self {
let mut i = Vec::with_capacity(nvals);
unsafe {
i.set_len(nvals);
}
i.shrink_to_fit();
let mut vals = Vec::with_capacity(nvals);
unsafe {
vals.set_len(nvals);
}
vals.shrink_to_fit();
CsMatrix {
data: CsVecStorage {
shape: (nrows, ncols),
p: VectorN::zeros_generic(ncols, U1),
i,
vals,
},
_phantoms: PhantomData,
}
}
/*
pub(crate) fn from_parts_generic(
nrows: R,
ncols: C,
p: VectorN<usize, C>,
i: Vec<usize>,
vals: Vec<N>,
) -> Self
where
N: Zero + ClosedAdd,
DefaultAllocator: Allocator<N, R>,
{
assert_eq!(ncols.value(), p.len(), "Invalid inptr size.");
assert_eq!(i.len(), vals.len(), "Invalid value size.");
// Check p.
for ptr in &p {
assert!(*ptr < i.len(), "Invalid inptr value.");
}
for ptr in p.as_slice().windows(2) {
assert!(ptr[0] <= ptr[1], "Invalid inptr ordering.");
}
// Check i.
for i in &i {
assert!(*i < nrows.value(), "Invalid row ptr value.")
}
let mut res = CsMatrix {
data: CsVecStorage {
shape: (nrows, ncols),
p,
i,
vals,
},
_phantoms: PhantomData,
};
// Sort and remove duplicates.
res.sort();
res.dedup();
res
}*/
}
/*
impl<N: Scalar + Zero + ClosedAdd> CsMatrix<N> {
pub(crate) fn from_parts(
nrows: usize,
ncols: usize,
p: Vec<usize>,
i: Vec<usize>,
vals: Vec<N>,
) -> Self
{
let nrows = Dynamic::new(nrows);
let ncols = Dynamic::new(ncols);
let p = DVector::from_data(VecStorage::new(ncols, U1, p));
Self::from_parts_generic(nrows, ncols, p, i, vals)
}
}
*/
impl<N: Scalar, R: Dim, C: Dim, S: CsStorage<N, R, C>> CsMatrix<N, R, C, S> {
pub(crate) fn from_data(data: S) -> Self {
CsMatrix {
data,
_phantoms: PhantomData,
}
}
/// The size of the data buffer.
pub fn len(&self) -> usize {
self.data.len()
}
/// The number of rows of this matrix.
pub fn nrows(&self) -> usize {
self.data.shape().0.value()
}
/// The number of rows of this matrix.
pub fn ncols(&self) -> usize {
self.data.shape().1.value()
}
/// The shape of this matrix.
pub fn shape(&self) -> (usize, usize) {
let (nrows, ncols) = self.data.shape();
(nrows.value(), ncols.value())
}
/// Whether this matrix is square or not.
pub fn is_square(&self) -> bool {
let (nrows, ncols) = self.data.shape();
nrows.value() == ncols.value()
}
/// Should always return `true`.
///
/// This method is generally used for debugging and should typically not be called in user code.
/// This checks that the row inner indices of this matrix are sorted. It takes `O(n)` time,
/// where n` is `self.len()`.
/// All operations of CSC matrices on nalgebra assume, and will return, sorted indices.
/// If at any time this `is_sorted` method returns `false`, then, something went wrong
/// and an issue should be open on the nalgebra repository with details on how to reproduce
/// this.
pub fn is_sorted(&self) -> bool {
for j in 0..self.ncols() {
let mut curr = None;
for idx in self.data.column_row_indices(j) {
if let Some(curr) = curr {
if idx <= curr {
return false;
}
}
curr = Some(idx);
}
}
true
}
/// Computes the transpose of this sparse matrix.
pub fn transpose(&self) -> CsMatrix<N, C, R>
where DefaultAllocator: Allocator<usize, R> {
let (nrows, ncols) = self.data.shape();
let nvals = self.len();
let mut res = CsMatrix::new_uninitialized_generic(ncols, nrows, nvals);
let mut workspace = Vector::zeros_generic(nrows, U1);
// Compute p.
for i in 0..nvals {
let row_id = self.data.row_index(i);
workspace[row_id] += 1;
}
let _ = cs_utils::cumsum(&mut workspace, &mut res.data.p);
// Fill the result.
for j in 0..ncols.value() {
for (row_id, value) in self.data.column_entries(j) {
let shift = workspace[row_id];
res.data.vals[shift] = value;
res.data.i[shift] = j;
workspace[row_id] += 1;
}
}
res
}
}
impl<N: Scalar, R: Dim, C: Dim, S: CsStorageMut<N, R, C>> CsMatrix<N, R, C, S> {
/// Iterator through all the mutable values of this sparse matrix.
#[inline]
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut N> {
self.data.values_mut()
}
}
impl<N: Scalar, R: Dim, C: Dim> CsMatrix<N, R, C>
where DefaultAllocator: Allocator<usize, C>
{
pub(crate) fn sort(&mut self)
where DefaultAllocator: Allocator<N, R> {
// Size = R
let nrows = self.data.shape().0;
let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows, U1) };
self.sort_with_workspace(workspace.as_mut_slice());
}
pub(crate) fn sort_with_workspace(&mut self, workspace: &mut [N]) {
assert!(
workspace.len() >= self.nrows(),
"Workspace must be able to hold at least self.nrows() elements."
);
for j in 0..self.ncols() {
// Scatter the row in the workspace.
for (irow, val) in self.data.column_entries(j) {
workspace[irow] = val;
}
// Sort the index vector.
let range = self.data.column_range(j);
self.data.i[range.clone()].sort();
// Permute the values too.
for (i, irow) in range.clone().zip(self.data.i[range].iter().cloned()) {
self.data.vals[i] = workspace[irow];
}
}
}
// Remove dupliate entries on a sorted CsMatrix.
pub(crate) fn dedup(&mut self)
where N: Zero + ClosedAdd {
let mut curr_i = 0;
for j in 0..self.ncols() {
let range = self.data.column_range(j);
self.data.p[j] = curr_i;
if range.start != range.end {
let mut value = N::zero();
let mut irow = self.data.i[range.start];
for idx in range {
let curr_irow = self.data.i[idx];
if curr_irow == irow {
value += self.data.vals[idx];
} else {
self.data.i[curr_i] = irow;
self.data.vals[curr_i] = value;
value = self.data.vals[idx];
irow = curr_irow;
curr_i += 1;
}
}
// Handle the last entry.
self.data.i[curr_i] = irow;
self.data.vals[curr_i] = value;
curr_i += 1;
}
}
self.data.i.truncate(curr_i);
self.data.i.shrink_to_fit();
self.data.vals.truncate(curr_i);
self.data.vals.shrink_to_fit();
}
}

View File

@ -0,0 +1,408 @@
use std::iter;
use std::mem;
use allocator::Allocator;
use sparse::{CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsVecStorage};
use {DefaultAllocator, Dim, Real, VectorN, U1};
/// The cholesky decomposition of a column compressed sparse matrix.
pub struct CsCholesky<N: Real, D: Dim>
where DefaultAllocator: Allocator<usize, D> + Allocator<N, D>
{
// Non-zero pattern of the original matrix upper-triangular part.
// Unlike the original matrix, the `original_p` array does contain the last sentinel value
// equal to `original_i.len()` at the end.
original_p: Vec<usize>,
original_i: Vec<usize>,
// Decomposition result.
l: CsMatrix<N, D, D>,
// Used only for the pattern.
// FIXME: store only the nonzero pattern instead.
u: CsMatrix<N, D, D>,
ok: bool,
// Workspaces.
work_x: VectorN<N, D>,
work_c: VectorN<usize, D>,
}
impl<N: Real, D: Dim> CsCholesky<N, D>
where DefaultAllocator: Allocator<usize, D> + Allocator<N, D>
{
/// Computes the cholesky decomposition of the sparse matrix `m`.
pub fn new(m: &CsMatrix<N, D, D>) -> Self {
let mut me = Self::new_symbolic(m);
let _ = me.decompose_left_looking(&m.data.vals);
me
}
/// Perform symbolic analysis for the given matrix.
///
/// This does not access the numerical values of `m`.
pub fn new_symbolic(m: &CsMatrix<N, D, D>) -> Self {
assert!(
m.is_square(),
"The matrix `m` must be square to compute its elimination tree."
);
let (l, u) = Self::nonzero_pattern(m);
// Workspaces.
let work_x = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) };
let work_c = unsafe { VectorN::new_uninitialized_generic(m.data.shape().1, U1) };
let mut original_p = m.data.p.as_slice().to_vec();
original_p.push(m.data.i.len());
CsCholesky {
original_p,
original_i: m.data.i.clone(),
l,
u,
ok: false,
work_x,
work_c,
}
}
/// The lower-triangular matrix of the cholesky decomposition.
pub fn l(&self) -> Option<&CsMatrix<N, D, D>> {
if self.ok {
Some(&self.l)
} else {
None
}
}
/// Extracts the lower-triangular matrix of the cholesky decomposition.
pub fn unwrap_l(self) -> Option<CsMatrix<N, D, D>> {
if self.ok {
Some(self.l)
} else {
None
}
}
/// Perform a numerical left-looking cholesky decomposition of a matrix with the same structure as the
/// one used to initialize `self`, but with different non-zero values provided by `values`.
pub fn decompose_left_looking(&mut self, values: &[N]) -> bool {
assert!(
values.len() >= self.original_i.len(),
"The set of values is too small."
);
let n = self.l.nrows();
// Reset `work_c` to the column pointers of `l`.
self.work_c.copy_from(&self.l.data.p);
unsafe {
for k in 0..n {
// Scatter the k-th column of the original matrix with the values provided.
let range_k =
*self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1);
*self.work_x.vget_unchecked_mut(k) = N::zero();
for p in range_k.clone() {
let irow = *self.original_i.get_unchecked(p);
if irow >= k {
*self.work_x.vget_unchecked_mut(irow) = *values.get_unchecked(p);
}
}
for j in self.u.data.column_row_indices(k) {
let factor = -*self
.l
.data
.vals
.get_unchecked(*self.work_c.vget_unchecked(j));
*self.work_c.vget_unchecked_mut(j) += 1;
if j < k {
for (z, val) in self.l.data.column_entries(j) {
if z >= k {
*self.work_x.vget_unchecked_mut(z) += val * factor;
}
}
}
}
let diag = *self.work_x.vget_unchecked(k);
if diag > N::zero() {
let denom = diag.sqrt();
*self
.l
.data
.vals
.get_unchecked_mut(*self.l.data.p.vget_unchecked(k)) = denom;
for (p, val) in self.l.data.column_entries_mut(k) {
*val = *self.work_x.vget_unchecked(p) / denom;
*self.work_x.vget_unchecked_mut(p) = N::zero();
}
} else {
self.ok = false;
return false;
}
}
}
self.ok = true;
true
}
/// Perform a numerical up-looking cholesky decomposition of a matrix with the same structure as the
/// one used to initialize `self`, but with different non-zero values provided by `values`.
pub fn decompose_up_looking(&mut self, values: &[N]) -> bool {
assert!(
values.len() >= self.original_i.len(),
"The set of values is too small."
);
// Reset `work_c` to the column pointers of `l`.
self.work_c.copy_from(&self.l.data.p);
// Perform the decomposition.
for k in 0..self.l.nrows() {
unsafe {
// Scatter the k-th column of the original matrix with the values provided.
let column_range =
*self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1);
*self.work_x.vget_unchecked_mut(k) = N::zero();
for p in column_range.clone() {
let irow = *self.original_i.get_unchecked(p);
if irow <= k {
*self.work_x.vget_unchecked_mut(irow) = *values.get_unchecked(p);
}
}
let mut diag = *self.work_x.vget_unchecked(k);
*self.work_x.vget_unchecked_mut(k) = N::zero();
// Triangular solve.
for irow in self.u.data.column_row_indices(k) {
if irow >= k {
continue;
}
let lki = *self.work_x.vget_unchecked(irow)
/ *self
.l
.data
.vals
.get_unchecked(*self.l.data.p.vget_unchecked(irow));
*self.work_x.vget_unchecked_mut(irow) = N::zero();
for p in
*self.l.data.p.vget_unchecked(irow) + 1..*self.work_c.vget_unchecked(irow)
{
*self
.work_x
.vget_unchecked_mut(*self.l.data.i.get_unchecked(p)) -=
*self.l.data.vals.get_unchecked(p) * lki;
}
diag -= lki * lki;
let p = *self.work_c.vget_unchecked(irow);
*self.work_c.vget_unchecked_mut(irow) += 1;
*self.l.data.i.get_unchecked_mut(p) = k;
*self.l.data.vals.get_unchecked_mut(p) = lki;
}
if diag <= N::zero() {
self.ok = false;
return false;
}
// Deal with the diagonal element.
let p = *self.work_c.vget_unchecked(k);
*self.work_c.vget_unchecked_mut(k) += 1;
*self.l.data.i.get_unchecked_mut(p) = k;
*self.l.data.vals.get_unchecked_mut(p) = diag.sqrt();
}
}
self.ok = true;
true
}
fn elimination_tree<S: CsStorage<N, D, D>>(m: &CsMatrix<N, D, D, S>) -> Vec<usize> {
let nrows = m.nrows();
let mut forest: Vec<_> = iter::repeat(usize::max_value()).take(nrows).collect();
let mut ancestor: Vec<_> = iter::repeat(usize::max_value()).take(nrows).collect();
for k in 0..nrows {
for irow in m.data.column_row_indices(k) {
let mut i = irow;
while i < k {
let i_ancestor = ancestor[i];
ancestor[i] = k;
if i_ancestor == usize::max_value() {
forest[i] = k;
break;
}
i = i_ancestor;
}
}
}
forest
}
fn reach<S: CsStorage<N, D, D>>(
m: &CsMatrix<N, D, D, S>,
j: usize,
max_j: usize,
tree: &[usize],
marks: &mut Vec<bool>,
out: &mut Vec<usize>,
)
{
marks.clear();
marks.resize(tree.len(), false);
// FIXME: avoid all those allocations.
let mut tmp = Vec::new();
let mut res = Vec::new();
for irow in m.data.column_row_indices(j) {
let mut curr = irow;
while curr != usize::max_value() && curr <= max_j && !marks[curr] {
marks[curr] = true;
tmp.push(curr);
curr = tree[curr];
}
tmp.append(&mut res);
mem::swap(&mut tmp, &mut res);
}
out.append(&mut res);
}
fn nonzero_pattern<S: CsStorage<N, D, D>>(
m: &CsMatrix<N, D, D, S>,
) -> (CsMatrix<N, D, D>, CsMatrix<N, D, D>) {
let etree = Self::elimination_tree(m);
let (nrows, ncols) = m.data.shape();
let mut rows = Vec::with_capacity(m.len());
let mut cols = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) };
let mut marks = Vec::new();
// NOTE: the following will actually compute the non-zero pattern of
// the transpose of l.
for i in 0..nrows.value() {
cols[i] = rows.len();
Self::reach(m, i, i, &etree, &mut marks, &mut rows);
}
let mut vals = Vec::with_capacity(rows.len());
unsafe {
vals.set_len(rows.len());
}
vals.shrink_to_fit();
let data = CsVecStorage {
shape: (nrows, ncols),
p: cols,
i: rows,
vals,
};
let u = CsMatrix::from_data(data);
// XXX: avoid this transpose.
let l = u.transpose();
(l, u)
}
/*
*
* NOTE: All the following methods are untested and currently unused.
*
*
fn column_counts<S: CsStorage<N, D, D>>(
m: &CsMatrix<N, D, D, S>,
tree: &[usize],
) -> Vec<usize> {
let len = m.data.shape().0.value();
let mut counts: Vec<_> = iter::repeat(0).take(len).collect();
let mut reach = Vec::new();
let mut marks = Vec::new();
for i in 0..len {
Self::reach(m, i, i, tree, &mut marks, &mut reach);
for j in reach.drain(..) {
counts[j] += 1;
}
}
counts
}
fn tree_postorder(tree: &[usize]) -> Vec<usize> {
// FIXME: avoid all those allocations?
let mut first_child: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect();
let mut other_children: Vec<_> =
iter::repeat(usize::max_value()).take(tree.len()).collect();
// Build the children list from the parent list.
// The set of children of the node `i` is given by the linked list
// starting at `first_child[i]`. The nodes of this list are then:
// { first_child[i], other_children[first_child[i]], other_children[other_children[first_child[i]], ... }
for (i, parent) in tree.iter().enumerate() {
if *parent != usize::max_value() {
let brother = first_child[*parent];
first_child[*parent] = i;
other_children[i] = brother;
}
}
let mut stack = Vec::with_capacity(tree.len());
let mut postorder = Vec::with_capacity(tree.len());
for (i, node) in tree.iter().enumerate() {
if *node == usize::max_value() {
Self::dfs(
i,
&mut first_child,
&other_children,
&mut stack,
&mut postorder,
)
}
}
postorder
}
fn dfs(
i: usize,
first_child: &mut [usize],
other_children: &[usize],
stack: &mut Vec<usize>,
result: &mut Vec<usize>,
) {
stack.clear();
stack.push(i);
while let Some(n) = stack.pop() {
let child = first_child[n];
if child == usize::max_value() {
// No children left.
result.push(n);
} else {
stack.push(n);
stack.push(child);
first_child[n] = other_children[child];
}
}
}
*/
}

View File

@ -0,0 +1,114 @@
use alga::general::ClosedAdd;
use num::Zero;
use allocator::Allocator;
use sparse::cs_utils;
use sparse::{CsMatrix, CsStorage};
use storage::Storage;
use {DefaultAllocator, Dim, Dynamic, Matrix, MatrixMN, Scalar};
impl<'a, N: Scalar + Zero + ClosedAdd> CsMatrix<N> {
/// Creates a column-compressed sparse matrix from a sparse matrix in triplet form.
pub fn from_triplet(
nrows: usize,
ncols: usize,
irows: &[usize],
icols: &[usize],
vals: &[N],
) -> Self
{
Self::from_triplet_generic(Dynamic::new(nrows), Dynamic::new(ncols), irows, icols, vals)
}
}
impl<'a, N: Scalar + Zero + ClosedAdd, R: Dim, C: Dim> CsMatrix<N, R, C>
where DefaultAllocator: Allocator<usize, C> + Allocator<N, R>
{
/// Creates a column-compressed sparse matrix from a sparse matrix in triplet form.
pub fn from_triplet_generic(
nrows: R,
ncols: C,
irows: &[usize],
icols: &[usize],
vals: &[N],
) -> Self
{
assert!(vals.len() == irows.len());
assert!(vals.len() == icols.len());
let mut res = CsMatrix::new_uninitialized_generic(nrows, ncols, vals.len());
let mut workspace = res.data.p.clone();
// Column count.
for j in icols.iter().cloned() {
workspace[j] += 1;
}
let _ = cs_utils::cumsum(&mut workspace, &mut res.data.p);
// Fill i and vals.
for ((i, j), val) in irows
.iter()
.cloned()
.zip(icols.iter().cloned())
.zip(vals.iter().cloned())
{
let offset = workspace[j];
res.data.i[offset] = i;
res.data.vals[offset] = val;
workspace[j] = offset + 1;
}
// Sort the result.
res.sort();
res.dedup();
res
}
}
impl<'a, N: Scalar + Zero, R: Dim, C: Dim, S> From<CsMatrix<N, R, C, S>> for MatrixMN<N, R, C>
where
S: CsStorage<N, R, C>,
DefaultAllocator: Allocator<N, R, C>,
{
fn from(m: CsMatrix<N, R, C, S>) -> Self {
let (nrows, ncols) = m.data.shape();
let mut res = MatrixMN::zeros_generic(nrows, ncols);
for j in 0..ncols.value() {
for (i, val) in m.data.column_entries(j) {
res[(i, j)] = val;
}
}
res
}
}
impl<'a, N: Scalar + Zero, R: Dim, C: Dim, S> From<Matrix<N, R, C, S>> for CsMatrix<N, R, C>
where
S: Storage<N, R, C>,
DefaultAllocator: Allocator<N, R, C> + Allocator<usize, C>,
{
fn from(m: Matrix<N, R, C, S>) -> Self {
let (nrows, ncols) = m.data.shape();
let len = m.iter().filter(|e| !e.is_zero()).count();
let mut res = CsMatrix::new_uninitialized_generic(nrows, ncols, len);
let mut nz = 0;
for j in 0..ncols.value() {
let column = m.column(j);
res.data.p[j] = nz;
for i in 0..nrows.value() {
if !column[i].is_zero() {
res.data.i[nz] = i;
res.data.vals[nz] = column[i];
nz += 1;
}
}
}
res
}
}

304
src/sparse/cs_matrix_ops.rs Normal file
View File

@ -0,0 +1,304 @@
use alga::general::{ClosedAdd, ClosedMul};
use num::{One, Zero};
use std::ops::{Add, Mul};
use allocator::Allocator;
use constraint::{AreMultipliable, DimEq, ShapeConstraint};
use sparse::{CsMatrix, CsStorage, CsStorageMut, CsVector};
use storage::StorageMut;
use {DefaultAllocator, Dim, Scalar, Vector, VectorN, U1};
impl<N: Scalar, R: Dim, C: Dim, S: CsStorage<N, R, C>> CsMatrix<N, R, C, S> {
fn scatter<R2: Dim, C2: Dim>(
&self,
j: usize,
beta: N,
timestamps: &mut [usize],
timestamp: usize,
workspace: &mut [N],
mut nz: usize,
res: &mut CsMatrix<N, R2, C2>,
) -> usize
where
N: ClosedAdd + ClosedMul,
DefaultAllocator: Allocator<usize, C2>,
{
for (i, val) in self.data.column_entries(j) {
if timestamps[i] < timestamp {
timestamps[i] = timestamp;
res.data.i[nz] = i;
nz += 1;
workspace[i] = val * beta;
} else {
workspace[i] += val * beta;
}
}
nz
}
}
/*
impl<N: Scalar, R, S> CsVector<N, R, S> {
pub fn axpy(&mut self, alpha: N, x: CsVector<N, R, S>, beta: N) {
// First, compute the number of non-zero entries.
let mut nnzero = 0;
// Allocate a size large enough.
self.data.set_column_len(0, nnzero);
// Fill with the axpy.
let mut i = self.len();
let mut j = x.len();
let mut k = nnzero - 1;
let mut rid1 = self.data.row_index(0, i - 1);
let mut rid2 = x.data.row_index(0, j - 1);
while k > 0 {
if rid1 == rid2 {
self.data.set_row_index(0, k, rid1);
self[k] = alpha * x[j] + beta * self[k];
i -= 1;
j -= 1;
} else if rid1 < rid2 {
self.data.set_row_index(0, k, rid1);
self[k] = beta * self[i];
i -= 1;
} else {
self.data.set_row_index(0, k, rid2);
self[k] = alpha * x[j];
j -= 1;
}
k -= 1;
}
}
}
*/
impl<N: Scalar + Zero + ClosedAdd + ClosedMul, D: Dim, S: StorageMut<N, D>> Vector<N, D, S> {
/// Perform a sparse axpy operation: `self = alpha * x + beta * self` operation.
pub fn axpy_cs<D2: Dim, S2>(&mut self, alpha: N, x: &CsVector<N, D2, S2>, beta: N)
where
S2: CsStorage<N, D2>,
ShapeConstraint: DimEq<D, D2>,
{
if beta.is_zero() {
for i in 0..x.len() {
unsafe {
let k = x.data.row_index_unchecked(i);
let y = self.vget_unchecked_mut(k);
*y = alpha * *x.data.get_value_unchecked(i);
}
}
} else {
// Needed to be sure even components not present on `x` are multiplied.
*self *= beta;
for i in 0..x.len() {
unsafe {
let k = x.data.row_index_unchecked(i);
let y = self.vget_unchecked_mut(k);
*y += alpha * *x.data.get_value_unchecked(i);
}
}
}
}
/*
pub fn gemv_sparse<R2: Dim, C2: Dim, S2>(&mut self, alpha: N, a: &CsMatrix<N, R2, C2, S2>, x: &DVector<N>, beta: N)
where
S2: CsStorage<N, R2, C2> {
let col2 = a.column(0);
let val = unsafe { *x.vget_unchecked(0) };
self.axpy_sparse(alpha * val, &col2, beta);
for j in 1..ncols2 {
let col2 = a.column(j);
let val = unsafe { *x.vget_unchecked(j) };
self.axpy_sparse(alpha * val, &col2, N::one());
}
}
*/
}
impl<'a, 'b, N, R1, R2, C1, C2, S1, S2> Mul<&'b CsMatrix<N, R2, C2, S2>>
for &'a CsMatrix<N, R1, C1, S1>
where
N: Scalar + ClosedAdd + ClosedMul + Zero,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
S1: CsStorage<N, R1, C1>,
S2: CsStorage<N, R2, C2>,
ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
DefaultAllocator: Allocator<usize, C2> + Allocator<usize, R1> + Allocator<N, R1>,
{
type Output = CsMatrix<N, R1, C2>;
fn mul(self, rhs: &'b CsMatrix<N, R2, C2, S2>) -> Self::Output {
let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape();
assert_eq!(
ncols1.value(),
nrows2.value(),
"Mismatched dimensions for matrix multiplication."
);
let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
let mut workspace = VectorN::<N, R1>::zeros_generic(nrows1, U1);
let mut nz = 0;
for j in 0..ncols2.value() {
res.data.p[j] = nz;
let new_size_bound = nz + nrows1.value();
res.data.i.resize(new_size_bound, 0);
res.data.vals.resize(new_size_bound, N::zero());
for (i, beta) in rhs.data.column_entries(j) {
for (k, val) in self.data.column_entries(i) {
workspace[k] += val * beta;
}
}
for (i, val) in workspace.as_mut_slice().iter_mut().enumerate() {
if !val.is_zero() {
res.data.i[nz] = i;
res.data.vals[nz] = *val;
*val = N::zero();
nz += 1;
}
}
}
// NOTE: the following has a lower complexity, but is slower in many cases, likely because
// of branching inside of the inner loop.
//
// let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
// let mut timestamps = VectorN::zeros_generic(nrows1, U1);
// let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows1, U1) };
// let mut nz = 0;
//
// for j in 0..ncols2.value() {
// res.data.p[j] = nz;
// let new_size_bound = nz + nrows1.value();
// res.data.i.resize(new_size_bound, 0);
// res.data.vals.resize(new_size_bound, N::zero());
//
// for (i, val) in rhs.data.column_entries(j) {
// nz = self.scatter(
// i,
// val,
// timestamps.as_mut_slice(),
// j + 1,
// workspace.as_mut_slice(),
// nz,
// &mut res,
// );
// }
//
// // Keep the output sorted.
// let range = res.data.p[j]..nz;
// res.data.i[range.clone()].sort();
//
// for p in range {
// res.data.vals[p] = workspace[res.data.i[p]]
// }
// }
res.data.i.truncate(nz);
res.data.i.shrink_to_fit();
res.data.vals.truncate(nz);
res.data.vals.shrink_to_fit();
res
}
}
impl<'a, 'b, N, R1, R2, C1, C2, S1, S2> Add<&'b CsMatrix<N, R2, C2, S2>>
for &'a CsMatrix<N, R1, C1, S1>
where
N: Scalar + ClosedAdd + ClosedMul + One,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
S1: CsStorage<N, R1, C1>,
S2: CsStorage<N, R2, C2>,
ShapeConstraint: DimEq<R1, R2> + DimEq<C1, C2>,
DefaultAllocator: Allocator<usize, C2> + Allocator<usize, R1> + Allocator<N, R1>,
{
type Output = CsMatrix<N, R1, C2>;
fn add(self, rhs: &'b CsMatrix<N, R2, C2, S2>) -> Self::Output {
let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape();
assert_eq!(
(nrows1.value(), ncols1.value()),
(nrows2.value(), ncols2.value()),
"Mismatched dimensions for matrix sum."
);
let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len());
let mut timestamps = VectorN::zeros_generic(nrows1, U1);
let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows1, U1) };
let mut nz = 0;
for j in 0..ncols2.value() {
res.data.p[j] = nz;
nz = self.scatter(
j,
N::one(),
timestamps.as_mut_slice(),
j + 1,
workspace.as_mut_slice(),
nz,
&mut res,
);
nz = rhs.scatter(
j,
N::one(),
timestamps.as_mut_slice(),
j + 1,
workspace.as_mut_slice(),
nz,
&mut res,
);
// Keep the output sorted.
let range = res.data.p[j]..nz;
res.data.i[range.clone()].sort();
for p in range {
res.data.vals[p] = workspace[res.data.i[p]]
}
}
res.data.i.truncate(nz);
res.data.i.shrink_to_fit();
res.data.vals.truncate(nz);
res.data.vals.shrink_to_fit();
res
}
}
impl<'a, 'b, N, R, C, S> Mul<N> for CsMatrix<N, R, C, S>
where
N: Scalar + ClosedAdd + ClosedMul + Zero,
R: Dim,
C: Dim,
S: CsStorageMut<N, R, C>,
{
type Output = Self;
fn mul(mut self, rhs: N) -> Self::Output {
for e in self.values_mut() {
*e *= rhs
}
self
}
}

View File

@ -0,0 +1,283 @@
use allocator::Allocator;
use constraint::{SameNumberOfRows, ShapeConstraint};
use sparse::{CsMatrix, CsStorage, CsVector};
use storage::{Storage, StorageMut};
use {DefaultAllocator, Dim, Matrix, MatrixMN, Real, VectorN, U1};
impl<N: Real, D: Dim, S: CsStorage<N, D, D>> CsMatrix<N, D, D, S> {
/// Solve a lower-triangular system with a dense right-hand-side.
pub fn solve_lower_triangular<R2: Dim, C2: Dim, S2>(
&self,
b: &Matrix<N, R2, C2, S2>,
) -> Option<MatrixMN<N, R2, C2>>
where
S2: Storage<N, R2, C2>,
DefaultAllocator: Allocator<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let mut b = b.clone_owned();
if self.solve_lower_triangular_mut(&mut b) {
Some(b)
} else {
None
}
}
/// Solve a lower-triangular system with `self` transposed and a dense right-hand-side.
pub fn tr_solve_lower_triangular<R2: Dim, C2: Dim, S2>(
&self,
b: &Matrix<N, R2, C2, S2>,
) -> Option<MatrixMN<N, R2, C2>>
where
S2: Storage<N, R2, C2>,
DefaultAllocator: Allocator<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let mut b = b.clone_owned();
if self.tr_solve_lower_triangular_mut(&mut b) {
Some(b)
} else {
None
}
}
/// Solve in-place a lower-triangular system with a dense right-hand-side.
pub fn solve_lower_triangular_mut<R2: Dim, C2: Dim, S2>(
&self,
b: &mut Matrix<N, R2, C2, S2>,
) -> bool
where
S2: StorageMut<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let (nrows, ncols) = self.data.shape();
assert_eq!(nrows.value(), ncols.value(), "The matrix must be square.");
assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions.");
for j2 in 0..b.ncols() {
let mut b = b.column_mut(j2);
for j in 0..ncols.value() {
let mut column = self.data.column_entries(j);
let mut diag_found = false;
while let Some((i, val)) = column.next() {
if i == j {
if val.is_zero() {
return false;
}
b[j] /= val;
diag_found = true;
break;
}
}
if !diag_found {
return false;
}
for (i, val) in column {
b[i] -= b[j] * val;
}
}
}
true
}
/// Solve a lower-triangular system with `self` transposed and a dense right-hand-side.
pub fn tr_solve_lower_triangular_mut<R2: Dim, C2: Dim, S2>(
&self,
b: &mut Matrix<N, R2, C2, S2>,
) -> bool
where
S2: StorageMut<N, R2, C2>,
ShapeConstraint: SameNumberOfRows<D, R2>,
{
let (nrows, ncols) = self.data.shape();
assert_eq!(nrows.value(), ncols.value(), "The matrix must be square.");
assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions.");
for j2 in 0..b.ncols() {
let mut b = b.column_mut(j2);
for j in (0..ncols.value()).rev() {
let mut column = self.data.column_entries(j);
let mut diag = None;
while let Some((i, val)) = column.next() {
if i == j {
if val.is_zero() {
return false;
}
diag = Some(val);
break;
}
}
if let Some(diag) = diag {
for (i, val) in column {
b[j] -= val * b[i];
}
b[j] /= diag;
} else {
return false;
}
}
}
true
}
/// Solve a lower-triangular system with a sparse right-hand-side.
pub fn solve_lower_triangular_cs<D2: Dim, S2>(
&self,
b: &CsVector<N, D2, S2>,
) -> Option<CsVector<N, D2>>
where
S2: CsStorage<N, D2>,
DefaultAllocator: Allocator<bool, D> + Allocator<N, D2> + Allocator<usize, D2>,
ShapeConstraint: SameNumberOfRows<D, D2>,
{
let mut reach = Vec::new();
// We don't compute a postordered reach here because it will be sorted after anyway.
self.lower_triangular_reach(b, &mut reach);
// We sort the reach so the result matrix has sorted indices.
reach.sort();
let mut workspace = unsafe { VectorN::new_uninitialized_generic(b.data.shape().0, U1) };
for i in reach.iter().cloned() {
workspace[i] = N::zero();
}
for (i, val) in b.data.column_entries(0) {
workspace[i] = val;
}
for j in reach.iter().cloned() {
let mut column = self.data.column_entries(j);
let mut diag_found = false;
while let Some((i, val)) = column.next() {
if i == j {
if val.is_zero() {
break;
}
workspace[j] /= val;
diag_found = true;
break;
}
}
if !diag_found {
return None;
}
for (i, val) in column {
workspace[i] -= workspace[j] * val;
}
}
// Copy the result into a sparse vector.
let mut result = CsVector::new_uninitialized_generic(b.data.shape().0, U1, reach.len());
for (i, val) in reach.iter().zip(result.data.vals.iter_mut()) {
*val = workspace[*i];
}
result.data.i = reach;
Some(result)
}
/*
// Computes the reachable, post-ordered, nodes from `b`.
fn lower_triangular_reach_postordered<D2: Dim, S2>(
&self,
b: &CsVector<N, D2, S2>,
xi: &mut Vec<usize>,
) where
S2: CsStorage<N, D2>,
DefaultAllocator: Allocator<bool, D>,
{
let mut visited = VectorN::repeat_generic(self.data.shape().1, U1, false);
let mut stack = Vec::new();
for i in b.data.column_range(0) {
let row_index = b.data.row_index(i);
if !visited[row_index] {
let rng = self.data.column_range(row_index);
stack.push((row_index, rng));
self.lower_triangular_dfs(visited.as_mut_slice(), &mut stack, xi);
}
}
}
fn lower_triangular_dfs(
&self,
visited: &mut [bool],
stack: &mut Vec<(usize, Range<usize>)>,
xi: &mut Vec<usize>,
)
{
'recursion: while let Some((j, rng)) = stack.pop() {
visited[j] = true;
for i in rng.clone() {
let row_id = self.data.row_index(i);
if row_id > j && !visited[row_id] {
stack.push((j, (i + 1)..rng.end));
stack.push((row_id, self.data.column_range(row_id)));
continue 'recursion;
}
}
xi.push(j)
}
}
*/
// Computes the nodes reachable from `b` in an arbitrary order.
fn lower_triangular_reach<D2: Dim, S2>(&self, b: &CsVector<N, D2, S2>, xi: &mut Vec<usize>)
where
S2: CsStorage<N, D2>,
DefaultAllocator: Allocator<bool, D>,
{
let mut visited = VectorN::repeat_generic(self.data.shape().1, U1, false);
let mut stack = Vec::new();
for irow in b.data.column_row_indices(0) {
self.lower_triangular_bfs(irow, visited.as_mut_slice(), &mut stack, xi);
}
}
fn lower_triangular_bfs(
&self,
start: usize,
visited: &mut [bool],
stack: &mut Vec<usize>,
xi: &mut Vec<usize>,
)
{
if !visited[start] {
stack.clear();
stack.push(start);
xi.push(start);
visited[start] = true;
while let Some(j) = stack.pop() {
for irow in self.data.column_row_indices(j) {
if irow > j && !visited[irow] {
stack.push(irow);
xi.push(irow);
visited[irow] = true;
}
}
}
}
}
}

16
src/sparse/cs_utils.rs Normal file
View File

@ -0,0 +1,16 @@
use allocator::Allocator;
use {DefaultAllocator, Dim, VectorN};
pub fn cumsum<D: Dim>(a: &mut VectorN<usize, D>, b: &mut VectorN<usize, D>) -> usize
where DefaultAllocator: Allocator<usize, D> {
assert!(a.len() == b.len());
let mut sum = 0;
for i in 0..a.len() {
b[i] = sum;
sum += a[i];
a[i] = b[i];
}
sum
}

13
src/sparse/mod.rs Normal file
View File

@ -0,0 +1,13 @@
//! Sparse matrices.
pub use self::cs_matrix::{
CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsStorageMut, CsVecStorage, CsVector,
};
pub use self::cs_matrix_cholesky::CsCholesky;
mod cs_matrix;
mod cs_matrix_cholesky;
mod cs_matrix_conversion;
mod cs_matrix_ops;
mod cs_matrix_solve;
pub(crate) mod cs_utils;

View File

@ -565,4 +565,4 @@ fn resize_empty_matrix() {
assert_eq!(m1, m5.resize(0, 0, 42)); assert_eq!(m1, m5.resize(0, 0, 42));
assert_eq!(m1, m6.resize(0, 0, 42)); assert_eq!(m1, m6.resize(0, 0, 42));
assert_eq!(m1, m7.resize(0, 0, 42)); assert_eq!(m1, m7.resize(0, 0, 42));
} }

View File

@ -195,10 +195,10 @@ fn from_columns() {
#[test] #[test]
fn from_columns_dynamic() { fn from_columns_dynamic() {
let columns = &[ let columns = &[
DVector::from_row_slice(3, &[11, 21, 31]), DVector::from_row_slice(&[11, 21, 31]),
DVector::from_row_slice(3, &[12, 22, 32]), DVector::from_row_slice(&[12, 22, 32]),
DVector::from_row_slice(3, &[13, 23, 33]), DVector::from_row_slice(&[13, 23, 33]),
DVector::from_row_slice(3, &[14, 24, 34]), DVector::from_row_slice(&[14, 24, 34]),
]; ];
let expected = DMatrix::from_row_slice(3, 4, &[11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34]); let expected = DMatrix::from_row_slice(3, 4, &[11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34]);
@ -233,8 +233,8 @@ fn from_not_enough_columns() {
#[should_panic] #[should_panic]
fn from_rows_with_different_dimensions() { fn from_rows_with_different_dimensions() {
let columns = &[ let columns = &[
DVector::from_row_slice(3, &[11, 21, 31]), DVector::from_row_slice(&[11, 21, 31]),
DVector::from_row_slice(3, &[12, 22, 32, 33]), DVector::from_row_slice(&[12, 22, 32, 33]),
]; ];
let _ = DMatrix::from_columns(columns); let _ = DMatrix::from_columns(columns);
@ -272,8 +272,8 @@ fn to_homogeneous() {
let a = Vector3::new(1.0, 2.0, 3.0); let a = Vector3::new(1.0, 2.0, 3.0);
let expected_a = Vector4::new(1.0, 2.0, 3.0, 0.0); let expected_a = Vector4::new(1.0, 2.0, 3.0, 0.0);
let b = DVector::from_row_slice(3, &[1.0, 2.0, 3.0]); let b = DVector::from_row_slice(&[1.0, 2.0, 3.0]);
let expected_b = DVector::from_row_slice(4, &[1.0, 2.0, 3.0, 0.0]); let expected_b = DVector::from_row_slice(&[1.0, 2.0, 3.0, 0.0]);
let c = Matrix2::new(1.0, 2.0, 3.0, 4.0); let c = Matrix2::new(1.0, 2.0, 3.0, 4.0);
let expected_c = Matrix3::new(1.0, 2.0, 0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 1.0); let expected_c = Matrix3::new(1.0, 2.0, 0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 1.0);
@ -287,6 +287,18 @@ fn to_homogeneous() {
assert_eq!(d.to_homogeneous(), expected_d); assert_eq!(d.to_homogeneous(), expected_d);
} }
#[test]
fn push() {
let a = Vector3::new(1.0, 2.0, 3.0);
let expected_a = Vector4::new(1.0, 2.0, 3.0, 4.0);
let b = DVector::from_row_slice(&[1.0, 2.0, 3.0]);
let expected_b = DVector::from_row_slice(&[1.0, 2.0, 3.0, 4.0]);
assert_eq!(a.push(4.0), expected_a);
assert_eq!(b.push(4.0), expected_b);
}
#[test] #[test]
fn simple_add() { fn simple_add() {
let a = Matrix2x3::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); let a = Matrix2x3::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

View File

@ -25,27 +25,35 @@ quickcheck!(
let viewmatrix = Isometry3::look_at_rh(&eye, &target, &up); let viewmatrix = Isometry3::look_at_rh(&eye, &target, &up);
let origin = Point3::origin(); let origin = Point3::origin();
relative_eq!(viewmatrix * eye, origin, epsilon = 1.0e-7) && relative_eq!(viewmatrix * eye, origin, epsilon = 1.0e-7)
relative_eq!((viewmatrix * (target - eye)).normalize(), -Vector3::z(), epsilon = 1.0e-7) && relative_eq!(
(viewmatrix * (target - eye)).normalize(),
-Vector3::z(),
epsilon = 1.0e-7
)
} }
fn observer_frame_3(eye: Point3<f64>, target: Point3<f64>, up: Vector3<f64>) -> bool { fn observer_frame_3(eye: Point3<f64>, target: Point3<f64>, up: Vector3<f64>) -> bool {
let observer = Isometry3::new_observer_frame(&eye, &target, &up); let observer = Isometry3::face_towards(&eye, &target, &up);
let origin = Point3::origin(); let origin = Point3::origin();
relative_eq!(observer * origin, eye, epsilon = 1.0e-7) && relative_eq!(observer * origin, eye, epsilon = 1.0e-7)
relative_eq!(observer * Vector3::z(), (target - eye).normalize(), epsilon = 1.0e-7) && relative_eq!(
observer * Vector3::z(),
(target - eye).normalize(),
epsilon = 1.0e-7
)
} }
fn inverse_is_identity(i: Isometry3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool { fn inverse_is_identity(i: Isometry3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool {
let ii = i.inverse(); let ii = i.inverse();
relative_eq!(i * ii, Isometry3::identity(), epsilon = 1.0e-7) && relative_eq!(i * ii, Isometry3::identity(), epsilon = 1.0e-7)
relative_eq!(ii * i, Isometry3::identity(), epsilon = 1.0e-7) && && relative_eq!(ii * i, Isometry3::identity(), epsilon = 1.0e-7)
relative_eq!((i * ii) * p, p, epsilon = 1.0e-7) && && relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
relative_eq!((ii * i) * p, p, epsilon = 1.0e-7) && && relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
relative_eq!((i * ii) * v, v, epsilon = 1.0e-7) && && relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
relative_eq!((ii * i) * v, v, epsilon = 1.0e-7) && relative_eq!((ii * i) * v, v, epsilon = 1.0e-7)
} }
fn inverse_is_parts_inversion(t: Translation3<f64>, r: UnitQuaternion<f64>) -> bool { fn inverse_is_parts_inversion(t: Translation3<f64>, r: UnitQuaternion<f64>) -> bool {
@ -54,14 +62,29 @@ quickcheck!(
} }
fn multiply_equals_alga_transform(i: Isometry3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool { fn multiply_equals_alga_transform(i: Isometry3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
i * v == i.transform_vector(&v) && i * v == i.transform_vector(&v)
i * p == i.transform_point(&p) && && i * p == i.transform_point(&p)
relative_eq!(i.inverse() * v, i.inverse_transform_vector(&v), epsilon = 1.0e-7) && && relative_eq!(
relative_eq!(i.inverse() * p, i.inverse_transform_point(&p), epsilon = 1.0e-7) i.inverse() * v,
i.inverse_transform_vector(&v),
epsilon = 1.0e-7
)
&& relative_eq!(
i.inverse() * p,
i.inverse_transform_point(&p),
epsilon = 1.0e-7
)
} }
fn composition2(i: Isometry2<f64>, uc: UnitComplex<f64>, r: Rotation2<f64>, fn composition2(
t: Translation2<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool { i: Isometry2<f64>,
uc: UnitComplex<f64>,
r: Rotation2<f64>,
t: Translation2<f64>,
v: Vector2<f64>,
p: Point2<f64>,
) -> bool
{
// (rotation × translation) * point = rotation × (translation * point) // (rotation × translation) * point = rotation × (translation * point)
relative_eq!((uc * t) * v, uc * v, epsilon = 1.0e-7) && relative_eq!((uc * t) * v, uc * v, epsilon = 1.0e-7) &&
relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) && relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) &&
@ -91,8 +114,15 @@ quickcheck!(
relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7) relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7)
} }
fn composition3(i: Isometry3<f64>, uq: UnitQuaternion<f64>, r: Rotation3<f64>, fn composition3(
t: Translation3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool { i: Isometry3<f64>,
uq: UnitQuaternion<f64>,
r: Rotation3<f64>,
t: Translation3<f64>,
v: Vector3<f64>,
p: Point3<f64>,
) -> bool
{
// (rotation × translation) * point = rotation × (translation * point) // (rotation × translation) * point = rotation × (translation * point)
relative_eq!((uq * t) * v, uq * v, epsilon = 1.0e-7) && relative_eq!((uq * t) * v, uq * v, epsilon = 1.0e-7) &&
relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) && relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) &&
@ -122,11 +152,18 @@ quickcheck!(
relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7) relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7)
} }
fn all_op_exist(i: Isometry3<f64>, uq: UnitQuaternion<f64>, t: Translation3<f64>, fn all_op_exist(
v: Vector3<f64>, p: Point3<f64>, r: Rotation3<f64>) -> bool { i: Isometry3<f64>,
let iMi = i * i; uq: UnitQuaternion<f64>,
t: Translation3<f64>,
v: Vector3<f64>,
p: Point3<f64>,
r: Rotation3<f64>,
) -> bool
{
let iMi = i * i;
let iMuq = i * uq; let iMuq = i * uq;
let iDi = i / i; let iDi = i / i;
let iDuq = i / uq; let iDuq = i / uq;
let iMp = i * p; let iMp = i * p;
@ -135,13 +172,13 @@ quickcheck!(
let iMt = i * t; let iMt = i * t;
let tMi = t * i; let tMi = t * i;
let tMr = t * r; let tMr = t * r;
let tMuq = t * uq; let tMuq = t * uq;
let uqMi = uq * i; let uqMi = uq * i;
let uqDi = uq / i; let uqDi = uq / i;
let rMt = r * t; let rMt = r * t;
let uqMt = uq * t; let uqMt = uq * t;
let mut iMt1 = i; let mut iMt1 = i;
@ -174,75 +211,57 @@ quickcheck!(
iDuq1 /= uq; iDuq1 /= uq;
iDuq2 /= &uq; iDuq2 /= &uq;
iMt == iMt1 && iMt == iMt1
iMt == iMt2 && && iMt == iMt2
&& iMi == iMi1
iMi == iMi1 && && iMi == iMi2
iMi == iMi2 && && iMuq == iMuq1
&& iMuq == iMuq2
iMuq == iMuq1 && && iDi == iDi1
iMuq == iMuq2 && && iDi == iDi2
&& iDuq == iDuq1
iDi == iDi1 && && iDuq == iDuq2
iDi == iDi2 && && iMi == &i * &i
&& iMi == i * &i
iDuq == iDuq1 && && iMi == &i * i
iDuq == iDuq2 && && iMuq == &i * &uq
&& iMuq == i * &uq
iMi == &i * &i && && iMuq == &i * uq
iMi == i * &i && && iDi == &i / &i
iMi == &i * i && && iDi == i / &i
&& iDi == &i / i
iMuq == &i * &uq && && iDuq == &i / &uq
iMuq == i * &uq && && iDuq == i / &uq
iMuq == &i * uq && && iDuq == &i / uq
&& iMp == &i * &p
iDi == &i / &i && && iMp == i * &p
iDi == i / &i && && iMp == &i * p
iDi == &i / i && && iMv == &i * &v
&& iMv == i * &v
iDuq == &i / &uq && && iMv == &i * v
iDuq == i / &uq && && iMt == &i * &t
iDuq == &i / uq && && iMt == i * &t
&& iMt == &i * t
iMp == &i * &p && && tMi == &t * &i
iMp == i * &p && && tMi == t * &i
iMp == &i * p && && tMi == &t * i
&& tMr == &t * &r
iMv == &i * &v && && tMr == t * &r
iMv == i * &v && && tMr == &t * r
iMv == &i * v && && tMuq == &t * &uq
&& tMuq == t * &uq
iMt == &i * &t && && tMuq == &t * uq
iMt == i * &t && && uqMi == &uq * &i
iMt == &i * t && && uqMi == uq * &i
&& uqMi == &uq * i
tMi == &t * &i && && uqDi == &uq / &i
tMi == t * &i && && uqDi == uq / &i
tMi == &t * i && && uqDi == &uq / i
&& rMt == &r * &t
tMr == &t * &r && && rMt == r * &t
tMr == t * &r && && rMt == &r * t
tMr == &t * r && && uqMt == &uq * &t
&& uqMt == uq * &t
tMuq == &t * &uq && && uqMt == &uq * t
tMuq == t * &uq &&
tMuq == &t * uq &&
uqMi == &uq * &i &&
uqMi == uq * &i &&
uqMi == &uq * i &&
uqDi == &uq / &i &&
uqDi == uq / &i &&
uqDi == &uq / i &&
rMt == &r * &t &&
rMt == r * &t &&
rMt == &r * t &&
uqMt == &uq * &t &&
uqMt == uq * &t &&
uqMt == &uq * t
} }
); );

View File

@ -8,33 +8,57 @@ quickcheck!(
fn inverse_is_identity(i: Similarity3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool { fn inverse_is_identity(i: Similarity3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool {
let ii = i.inverse(); let ii = i.inverse();
relative_eq!(i * ii, Similarity3::identity(), epsilon = 1.0e-7) && relative_eq!(i * ii, Similarity3::identity(), epsilon = 1.0e-7)
relative_eq!(ii * i, Similarity3::identity(), epsilon = 1.0e-7) && && relative_eq!(ii * i, Similarity3::identity(), epsilon = 1.0e-7)
relative_eq!((i * ii) * p, p, epsilon = 1.0e-7) && && relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
relative_eq!((ii * i) * p, p, epsilon = 1.0e-7) && && relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
relative_eq!((i * ii) * v, v, epsilon = 1.0e-7) && && relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
relative_eq!((ii * i) * v, v, epsilon = 1.0e-7) && relative_eq!((ii * i) * v, v, epsilon = 1.0e-7)
} }
fn inverse_is_parts_inversion(t: Translation3<f64>, r: UnitQuaternion<f64>, scaling: f64) -> bool { fn inverse_is_parts_inversion(
t: Translation3<f64>,
r: UnitQuaternion<f64>,
scaling: f64,
) -> bool
{
if relative_eq!(scaling, 0.0) { if relative_eq!(scaling, 0.0) {
true true
} } else {
else {
let s = Similarity3::from_isometry(t * r, scaling); let s = Similarity3::from_isometry(t * r, scaling);
s.inverse() == Similarity3::from_scaling(1.0 / scaling) * r.inverse() * t.inverse() s.inverse() == Similarity3::from_scaling(1.0 / scaling) * r.inverse() * t.inverse()
} }
} }
fn multiply_equals_alga_transform(s: Similarity3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool { fn multiply_equals_alga_transform(
s * v == s.transform_vector(&v) && s: Similarity3<f64>,
s * p == s.transform_point(&p) && v: Vector3<f64>,
relative_eq!(s.inverse() * v, s.inverse_transform_vector(&v), epsilon = 1.0e-7) && p: Point3<f64>,
relative_eq!(s.inverse() * p, s.inverse_transform_point(&p), epsilon = 1.0e-7) ) -> bool
{
s * v == s.transform_vector(&v)
&& s * p == s.transform_point(&p)
&& relative_eq!(
s.inverse() * v,
s.inverse_transform_vector(&v),
epsilon = 1.0e-7
)
&& relative_eq!(
s.inverse() * p,
s.inverse_transform_point(&p),
epsilon = 1.0e-7
)
} }
fn composition(i: Isometry3<f64>, uq: UnitQuaternion<f64>, fn composition(
t: Translation3<f64>, v: Vector3<f64>, p: Point3<f64>, scaling: f64) -> bool { i: Isometry3<f64>,
uq: UnitQuaternion<f64>,
t: Translation3<f64>,
v: Vector3<f64>,
p: Point3<f64>,
scaling: f64,
) -> bool
{
if relative_eq!(scaling, 0.0) { if relative_eq!(scaling, 0.0) {
return true; return true;
} }
@ -122,11 +146,18 @@ quickcheck!(
relative_eq!((s * i * t) * p, scaling * (i * (t * p)), epsilon = 1.0e-7) relative_eq!((s * i * t) * p, scaling * (i * (t * p)), epsilon = 1.0e-7)
} }
fn all_op_exist(s: Similarity3<f64>, i: Isometry3<f64>, uq: UnitQuaternion<f64>, fn all_op_exist(
t: Translation3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool { s: Similarity3<f64>,
let sMs = s * s; i: Isometry3<f64>,
uq: UnitQuaternion<f64>,
t: Translation3<f64>,
v: Vector3<f64>,
p: Point3<f64>,
) -> bool
{
let sMs = s * s;
let sMuq = s * uq; let sMuq = s * uq;
let sDs = s / s; let sDs = s / s;
let sDuq = s / uq; let sDuq = s / uq;
let sMp = s * p; let sMp = s * p;
@ -186,81 +217,61 @@ quickcheck!(
sDi1 /= i; sDi1 /= i;
sDi2 /= &i; sDi2 /= &i;
sMt == sMt1 && sMt == sMt1
sMt == sMt2 && && sMt == sMt2
&& sMs == sMs1
sMs == sMs1 && && sMs == sMs2
sMs == sMs2 && && sMuq == sMuq1
&& sMuq == sMuq2
sMuq == sMuq1 && && sMi == sMi1
sMuq == sMuq2 && && sMi == sMi2
&& sDs == sDs1
sMi == sMi1 && && sDs == sDs2
sMi == sMi2 && && sDuq == sDuq1
&& sDuq == sDuq2
sDs == sDs1 && && sDi == sDi1
sDs == sDs2 && && sDi == sDi2
&& sMs == &s * &s
sDuq == sDuq1 && && sMs == s * &s
sDuq == sDuq2 && && sMs == &s * s
&& sMuq == &s * &uq
sDi == sDi1 && && sMuq == s * &uq
sDi == sDi2 && && sMuq == &s * uq
&& sDs == &s / &s
sMs == &s * &s && && sDs == s / &s
sMs == s * &s && && sDs == &s / s
sMs == &s * s && && sDuq == &s / &uq
&& sDuq == s / &uq
sMuq == &s * &uq && && sDuq == &s / uq
sMuq == s * &uq && && sMp == &s * &p
sMuq == &s * uq && && sMp == s * &p
&& sMp == &s * p
sDs == &s / &s && && sMv == &s * &v
sDs == s / &s && && sMv == s * &v
sDs == &s / s && && sMv == &s * v
&& sMt == &s * &t
sDuq == &s / &uq && && sMt == s * &t
sDuq == s / &uq && && sMt == &s * t
sDuq == &s / uq && && tMs == &t * &s
&& tMs == t * &s
sMp == &s * &p && && tMs == &t * s
sMp == s * &p && && uqMs == &uq * &s
sMp == &s * p && && uqMs == uq * &s
&& uqMs == &uq * s
sMv == &s * &v && && uqDs == &uq / &s
sMv == s * &v && && uqDs == uq / &s
sMv == &s * v && && uqDs == &uq / s
&& sMi == &s * &i
sMt == &s * &t && && sMi == s * &i
sMt == s * &t && && sMi == &s * i
sMt == &s * t && && sDi == &s / &i
&& sDi == s / &i
tMs == &t * &s && && sDi == &s / i
tMs == t * &s && && iMs == &i * &s
tMs == &t * s && && iMs == i * &s
&& iMs == &i * s
uqMs == &uq * &s && && iDs == &i / &s
uqMs == uq * &s && && iDs == i / &s
uqMs == &uq * s && && iDs == &i / s
uqDs == &uq / &s &&
uqDs == uq / &s &&
uqDs == &uq / s &&
sMi == &s * &i &&
sMi == s * &i &&
sMi == &s * i &&
sDi == &s / &i &&
sDi == s / &i &&
sDi == &s / i &&
iMs == &i * &s &&
iMs == i * &s &&
iMs == &i * s &&
iDs == &i / &s &&
iDs == i / &s &&
iDs == &i / s
} }
); );

View File

@ -4,19 +4,17 @@
use na::{Point2, Rotation2, Unit, UnitComplex, Vector2}; use na::{Point2, Rotation2, Unit, UnitComplex, Vector2};
quickcheck!( quickcheck!(
/* /*
* *
* From/to rotation matrix. * From/to rotation matrix.
* *
*/ */
fn unit_complex_rotation_conversion(c: UnitComplex<f64>) -> bool { fn unit_complex_rotation_conversion(c: UnitComplex<f64>) -> bool {
let r = c.to_rotation_matrix(); let r = c.to_rotation_matrix();
let cc = UnitComplex::from_rotation_matrix(&r); let cc = UnitComplex::from_rotation_matrix(&r);
let rr = cc.to_rotation_matrix(); let rr = cc.to_rotation_matrix();
relative_eq!(c, cc, epsilon = 1.0e-7) && relative_eq!(c, cc, epsilon = 1.0e-7) && relative_eq!(r, rr, epsilon = 1.0e-7)
relative_eq!(r, rr, epsilon = 1.0e-7)
} }
/* /*
@ -25,19 +23,18 @@ quickcheck!(
* *
*/ */
fn unit_complex_transformation(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool { fn unit_complex_transformation(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool {
let r = c.to_rotation_matrix(); let r = c.to_rotation_matrix();
let rv = r * v; let rv = r * v;
let rp = r * p; let rp = r * p;
relative_eq!( c * v, rv, epsilon = 1.0e-7) && relative_eq!(c * v, rv, epsilon = 1.0e-7)
relative_eq!( c * &v, rv, epsilon = 1.0e-7) && && relative_eq!(c * &v, rv, epsilon = 1.0e-7)
relative_eq!(&c * v, rv, epsilon = 1.0e-7) && && relative_eq!(&c * v, rv, epsilon = 1.0e-7)
relative_eq!(&c * &v, rv, epsilon = 1.0e-7) && && relative_eq!(&c * &v, rv, epsilon = 1.0e-7)
&& relative_eq!(c * p, rp, epsilon = 1.0e-7)
relative_eq!( c * p, rp, epsilon = 1.0e-7) && && relative_eq!(c * &p, rp, epsilon = 1.0e-7)
relative_eq!( c * &p, rp, epsilon = 1.0e-7) && && relative_eq!(&c * p, rp, epsilon = 1.0e-7)
relative_eq!(&c * p, rp, epsilon = 1.0e-7) && && relative_eq!(&c * &p, rp, epsilon = 1.0e-7)
relative_eq!(&c * &p, rp, epsilon = 1.0e-7)
} }
/* /*
@ -47,15 +44,14 @@ quickcheck!(
*/ */
fn unit_complex_inv(c: UnitComplex<f64>) -> bool { fn unit_complex_inv(c: UnitComplex<f64>) -> bool {
let iq = c.inverse(); let iq = c.inverse();
relative_eq!(&iq * &c, UnitComplex::identity(), epsilon = 1.0e-7) && relative_eq!(&iq * &c, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!( iq * &c, UnitComplex::identity(), epsilon = 1.0e-7) && && relative_eq!(iq * &c, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!(&iq * c, UnitComplex::identity(), epsilon = 1.0e-7) && && relative_eq!(&iq * c, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!( iq * c, UnitComplex::identity(), epsilon = 1.0e-7) && && relative_eq!(iq * c, UnitComplex::identity(), epsilon = 1.0e-7)
&& relative_eq!(&c * &iq, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!(&c * &iq, UnitComplex::identity(), epsilon = 1.0e-7) && && relative_eq!(c * &iq, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!( c * &iq, UnitComplex::identity(), epsilon = 1.0e-7) && && relative_eq!(&c * iq, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!(&c * iq, UnitComplex::identity(), epsilon = 1.0e-7) && && relative_eq!(c * iq, UnitComplex::identity(), epsilon = 1.0e-7)
relative_eq!( c * iq, UnitComplex::identity(), epsilon = 1.0e-7)
} }
/* /*
@ -66,25 +62,30 @@ quickcheck!(
fn unit_complex_mul_vector(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool { fn unit_complex_mul_vector(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool {
let r = c.to_rotation_matrix(); let r = c.to_rotation_matrix();
relative_eq!(c * v, r * v, epsilon = 1.0e-7) && relative_eq!(c * v, r * v, epsilon = 1.0e-7) && relative_eq!(c * p, r * p, epsilon = 1.0e-7)
relative_eq!(c * p, r * p, epsilon = 1.0e-7)
} }
// Test that all operators (incl. all combinations of references) work. // Test that all operators (incl. all combinations of references) work.
// See the top comment on `geometry/quaternion_ops.rs` for details on which operations are // See the top comment on `geometry/quaternion_ops.rs` for details on which operations are
// supported. // supported.
fn all_op_exist(uc: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>, r: Rotation2<f64>) -> bool { fn all_op_exist(
uc: UnitComplex<f64>,
v: Vector2<f64>,
p: Point2<f64>,
r: Rotation2<f64>,
) -> bool
{
let uv = Unit::new_normalize(v); let uv = Unit::new_normalize(v);
let ucMuc = uc * uc; let ucMuc = uc * uc;
let ucMr = uc * r; let ucMr = uc * r;
let rMuc = r * uc; let rMuc = r * uc;
let ucDuc = uc / uc; let ucDuc = uc / uc;
let ucDr = uc / r; let ucDr = uc / r;
let rDuc = r / uc; let rDuc = r / uc;
let ucMp = uc * p; let ucMp = uc * p;
let ucMv = uc * v; let ucMv = uc * v;
let ucMuv = uc * uv; let ucMuv = uc * uv;
let mut ucMuc1 = uc; let mut ucMuc1 = uc;
@ -111,52 +112,40 @@ quickcheck!(
ucDr1 /= r; ucDr1 /= r;
ucDr2 /= &r; ucDr2 /= &r;
ucMuc1 == ucMuc && ucMuc1 == ucMuc
ucMuc1 == ucMuc2 && && ucMuc1 == ucMuc2
&& ucMr1 == ucMr
ucMr1 == ucMr && && ucMr1 == ucMr2
ucMr1 == ucMr2 && && ucDuc1 == ucDuc
&& ucDuc1 == ucDuc2
ucDuc1 == ucDuc && && ucDr1 == ucDr
ucDuc1 == ucDuc2 && && ucDr1 == ucDr2
&& ucMuc == &uc * &uc
ucDr1 == ucDr && && ucMuc == uc * &uc
ucDr1 == ucDr2 && && ucMuc == &uc * uc
&& ucMr == &uc * &r
ucMuc == &uc * &uc && && ucMr == uc * &r
ucMuc == uc * &uc && && ucMr == &uc * r
ucMuc == &uc * uc && && rMuc == &r * &uc
&& rMuc == r * &uc
ucMr == &uc * &r && && rMuc == &r * uc
ucMr == uc * &r && && ucDuc == &uc / &uc
ucMr == &uc * r && && ucDuc == uc / &uc
&& ucDuc == &uc / uc
rMuc == &r * &uc && && ucDr == &uc / &r
rMuc == r * &uc && && ucDr == uc / &r
rMuc == &r * uc && && ucDr == &uc / r
&& rDuc == &r / &uc
ucDuc == &uc / &uc && && rDuc == r / &uc
ucDuc == uc / &uc && && rDuc == &r / uc
ucDuc == &uc / uc && && ucMp == &uc * &p
&& ucMp == uc * &p
ucDr == &uc / &r && && ucMp == &uc * p
ucDr == uc / &r && && ucMv == &uc * &v
ucDr == &uc / r && && ucMv == uc * &v
&& ucMv == &uc * v
rDuc == &r / &uc && && ucMuv == &uc * &uv
rDuc == r / &uc && && ucMuv == uc * &uv
rDuc == &r / uc && && ucMuv == &uc * uv
ucMp == &uc * &p &&
ucMp == uc * &p &&
ucMp == &uc * p &&
ucMv == &uc * &v &&
ucMv == uc * &v &&
ucMv == &uc * v &&
ucMuv == &uc * &uv &&
ucMuv == uc * &uv &&
ucMuv == &uc * uv
} }
); );

View File

@ -16,3 +16,5 @@ extern crate serde_json;
mod core; mod core;
mod geometry; mod geometry;
mod linalg; mod linalg;
#[cfg(feature = "sparse")]
mod sparse;

View File

@ -104,3 +104,89 @@ fn symmetric_eigen_singular_24x24() {
epsilon = 1.0e-5 epsilon = 1.0e-5
)); ));
} }
// #[cfg(feature = "arbitrary")]
// quickcheck! {
// FIXME: full eigendecomposition is not implemented yet because of its complexity when some
// eigenvalues have multiplicity > 1.
//
// /*
// * NOTE: for the following tests, we use only upper-triangular matrices.
// * Thes ensures the schur decomposition will work, and allows use to test the eigenvector
// * computation.
// */
// fn eigen(n: usize) -> bool {
// let n = cmp::max(1, cmp::min(n, 10));
// let m = DMatrix::<f64>::new_random(n, n).upper_triangle();
//
// let eig = RealEigen::new(m.clone()).unwrap();
// verify_eigenvectors(m, eig)
// }
//
// fn eigen_with_adjascent_duplicate_diagonals(n: usize) -> bool {
// let n = cmp::max(1, cmp::min(n, 10));
// let mut m = DMatrix::<f64>::new_random(n, n).upper_triangle();
//
// // Suplicate some adjascent diagonal elements.
// for i in 0 .. n / 2 {
// m[(i * 2 + 1, i * 2 + 1)] = m[(i * 2, i * 2)];
// }
//
// let eig = RealEigen::new(m.clone()).unwrap();
// verify_eigenvectors(m, eig)
// }
//
// fn eigen_with_nonadjascent_duplicate_diagonals(n: usize) -> bool {
// let n = cmp::max(3, cmp::min(n, 10));
// let mut m = DMatrix::<f64>::new_random(n, n).upper_triangle();
//
// // Suplicate some diagonal elements.
// for i in n / 2 .. n {
// m[(i, i)] = m[(i - n / 2, i - n / 2)];
// }
//
// let eig = RealEigen::new(m.clone()).unwrap();
// verify_eigenvectors(m, eig)
// }
//
// fn eigen_static_square_4x4(m: Matrix4<f64>) -> bool {
// let m = m.upper_triangle();
// let eig = RealEigen::new(m.clone()).unwrap();
// verify_eigenvectors(m, eig)
// }
//
// fn eigen_static_square_3x3(m: Matrix3<f64>) -> bool {
// let m = m.upper_triangle();
// let eig = RealEigen::new(m.clone()).unwrap();
// verify_eigenvectors(m, eig)
// }
//
// fn eigen_static_square_2x2(m: Matrix2<f64>) -> bool {
// let m = m.upper_triangle();
// println!("{}", m);
// let eig = RealEigen::new(m.clone()).unwrap();
// verify_eigenvectors(m, eig)
// }
// }
//
// fn verify_eigenvectors<D: Dim>(m: MatrixN<f64, D>, mut eig: RealEigen<f64, D>) -> bool
// where DefaultAllocator: Allocator<f64, D, D> +
// Allocator<f64, D> +
// Allocator<usize, D, D> +
// Allocator<usize, D>,
// MatrixN<f64, D>: Display,
// VectorN<f64, D>: Display {
// let mv = &m * &eig.eigenvectors;
//
// println!("eigenvalues: {}eigenvectors: {}", eig.eigenvalues, eig.eigenvectors);
//
// let dim = m.nrows();
// for i in 0 .. dim {
// let mut col = eig.eigenvectors.column_mut(i);
// col *= eig.eigenvalues[i];
// }
//
// println!("{}{:.5}{:.5}", m, mv, eig.eigenvectors);
//
// relative_eq!(eig.eigenvectors, mv, epsilon = 1.0e-5)
// }

View File

@ -459,4 +459,4 @@ fn resize() {
assert_eq!(add_del, m.resize(5, 2, 42)); assert_eq!(add_del, m.resize(5, 2, 42));
assert_eq!(del_add, m.resize(1, 8, 42)); assert_eq!(del_add, m.resize(1, 8, 42));
} }
*/ */

View File

@ -3,8 +3,10 @@ use na::{DMatrix, Matrix6};
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
mod quickcheck_tests { mod quickcheck_tests {
use na::{
DMatrix, DVector, Matrix2, Matrix2x5, Matrix3, Matrix3x5, Matrix4, Matrix5x2, Matrix5x3,
};
use std::cmp; use std::cmp;
use na::{DMatrix, Matrix2, Matrix3, Matrix4, Matrix5x2, Matrix5x3, Matrix2x5, Matrix3x5, DVector};
quickcheck! { quickcheck! {
fn svd(m: DMatrix<f64>) -> bool { fn svd(m: DMatrix<f64>) -> bool {
@ -258,7 +260,6 @@ fn svd_singular_horizontal() {
assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5)); assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5));
} }
#[test] #[test]
fn svd_zeros() { fn svd_zeros() {
let m = DMatrix::from_element(10, 10, 0.0); let m = DMatrix::from_element(10, 10, 0.0);

Some files were not shown because too many files have changed in this diff Show More