diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index c00b6cbc..97b42184 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -49,8 +49,6 @@ jobs: build-nalgebra-all-features: runs-on: ubuntu-latest steps: - # Needed because the --all-features build which enables cuda support. - - uses: Jimver/cuda-toolkit@v0.2.4 - uses: actions/checkout@v2 - run: cargo build --all-features; - run: cargo build -p nalgebra-glm --all-features; @@ -61,7 +59,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: test - run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests; + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; test-nalgebra-glm: runs-on: ubuntu-latest steps: @@ -120,20 +118,9 @@ jobs: run: xargo build --verbose --no-default-features -p nalgebra-glm --target=x86_64-unknown-linux-gnu; - name: build thumbv7em-none-eabihf nalgebra-glm run: xargo build --verbose --no-default-features -p nalgebra-glm --target=thumbv7em-none-eabihf; - build-cuda: + docs: runs-on: ubuntu-latest steps: - - uses: Jimver/cuda-toolkit@v0.2.4 - with: - cuda: '11.2.2' - - name: Install nightly-2021-12-04 - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly-2021-12-04 - override: true - - uses: actions/checkout@v2 - - run: rustup target add nvptx64-nvidia-cuda - - run: cargo build --no-default-features --features cuda - - run: cargo build --no-default-features --features cuda --target=nvptx64-nvidia-cuda - env: - CUDA_ARCH: "350" \ No newline at end of file + - uses: actions/checkout@v2 + - name: Generate documentation + run: cargo doc diff --git a/CHANGELOG.md b/CHANGELOG.md index bf6b6a0f..cc6d0a87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,180 @@ # Change Log + All notable changes to `nalgebra`, starting with the version 0.6.0 will be documented here. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.30.1] (09 Jan. 2022) +## Unreleased + +### Removed + +- The `cuda` feature has been removed, as the toolchain it depends on + is long abandoned. + +## [0.32.5] (28 March 2024) + +## Fixed + +- Fix numerical issue on SVD with near-identity matrix. + +## [0.32.4] (19 Feb 2023) + ### Added + +- Add the `glam-0.25` feature to enable conversion from/to types from `glam` v0.25. + +## [0.32.3] (09 July 2023) + +### Modified + +- Statically sized matrices are now serialized as tuples to match how serde + serialized plain arrays. +- Don’t require `Scalar` for matrix `PartialEq` and `Eq`. + +### Added + +- Allow trailing punctuation in macros `vector!`, `matrix!`, `point!`, etc. +- Add the methods `Matrix1::as_scalar`, `::as_scalar_mut`, `::to_scalar`, `::into_scalar`. +- Add `Rotation3::euler_angles_ordered`, a generalized euler angles calculation. +- Add the `glam-0.24` feature to enable conversion from/to types from `glam` v0.24. +- Add the `glam-0.25` feature to enable conversion from/to types from `glam` v0.25. +- Add the `lerp` method to points. +- Implement `Clone` for `MatrixIter`. + +### Fixed + +- Fixed severe catastrophic cancellation issue in variance calculation. + +## [0.32.2] (07 March 2023) + +### Added + +- Add the `glam-0.23` to enable conversion from/to type from `glam` v0.23. + +## [0.32.1] (14 Jan. 2023) + +### Modified + +- Updated `nalgebra-macros` to use the new `Dyn`, avoiding macro-generated deprecation warnings. + +## [0.32.0] (14 Jan. 2023) + +### Modified + +- Renamed all `MatrixSlice` types to `MatrixView`. In general all occurrences of the world `Slice` or `slice` have been + replaced by `View` or `view`. +- Deprecated all the types involving `Slice` in its name, in favor of the word `View`. +- Make it so that most `nalgebra` objects archive as themselves (when using `rkyv` for serialization). +- Renamed `Dynamic` to `Dyn` and make `Dyn` a tuple struct. + +### Added + +- Add `Cholesky::ln_determinant` to compute the natural logarithm of the determinant of a matrix decomposed + with Cholesky. This can be more numerically stable than computing the determinant itself when very small and/or + large values are involved. +- Added new methods `Matrix::as_view` and `Matrix::as_view_mut`, which are very useful when working with view-based + APIs. +- Added parallel column iterator using `rayon`: `Matrix::par_column_iter` and `Matrix::par_column_iter_mut`. The `rayon` + feature must be enabled to access these methods. +- Implement `ReshapableStorage` for matrix slices (only for unit strides at the moment). +- Add `U0, U1, …` constants alongside the `U0, U1, …` types. This lets us write `U4` instead of `U4::name()` or + `Const::<4>` when we need const dimensions. + +### Fixed + +- Fixed the implementation of `Rotation3::euler_angles` to return the angles in the documented order (roll, pitch, yaw). + +## [0.31.4] (13 Nov. 2022) + +### Added + +- Add a `convert-glam022` feature to enable conversion between `nalgebra` and `glam v0.22`. + +## [0.31.3] (30 Oct. 2022) + +### Added + +- Add `Matrix::try_cast` to attempt casting the inner scalar types when that cast may fail. + +### Fixed + +- Fixed the usage of `CheckBytes` with `rkyv`. + +## [0.31.2] (09 Oct. 2022) + +### Modified + +- Use `#[inline]` on the `Dim` implementation for `Const` to improve opt-level 1 performance. +- Make the `Point::new` constructions const-fn. + +### Added + +- Add `UnitVector::cast` to change the underlying scalar type. + +## [0.31.1] (31 July 2022) + +### Modified + +- Improve performances of multiplication of two sparse matrices. + +### Added + +- Add `Matrix::from_row_iterator` to build a matrix from an iterator yielding components in row-major order. +- Add support for conversion from/to types of `glam` 0.21. +- `nalgebra-sparse`: add support for the matrix-market export of sparse matrices. +- `nalgebra-lapack`: add a `GE` for solving the generalized eigenvalues problem. + +### Fixed + +- Fix `Rotation3::from_matrix` and `UnitQuaternion::from_matrix` when the input matrix is already a valid + rotation matrix. + +## [0.31.0] (30 Apr. 2022) + +### Breaking changes + +- Switch to `cust` 0.3 (for CUDA support). +- Switch to `rkyv` 0.7 +- Remove support for serialization based on `abomonation`. +- Remove support for conversions between `nalgebra` types and `glam` 0.13. + +### Modified + +- The aliases for `Const` types have been simplified to help `rust-analyzer`. + +### Added + +- Add `TryFrom` conversion between `UnitVector2/3/4` and `glam`’s `Vec2/3/4`. +- `nalgebra-sparse`: added support for serialization of sparse matrices with `serde`. +- `nalgebra-sparse`: add a CSC matrix constructor from unsorted (but valid) data. +- `nalgebra-lapack`: add generalized eigenvalues/eigenvectors calculation + QZ decomposition. + +### Fixed + +- Improve stability of SVD. +- Fix slerp for `UnitComplex`. + +## [0.30.1] (09 Jan. 2022) + +### Added + - Add conversion from/to types of `glam` 0.19 and 0.20. ## [0.30.0] (02 Jan. 2022) ### Breaking changes + - The `Dim` trait is now marked as unsafe. - The `Matrix::pow` and `Matrix::pow_mut` methods only allow positive integer exponents now. To compute negative exponents, the user is free to invert the matrix before calling `pow` with the exponent’s absolute value. - Remove the `Bounded` requirement from `RealField`. Replace it by methods returning `Option` so that they can still be implemented by unbounded types (by returning `None`). -- The `ComplexField` trait derives from `FromPrimitive` again. We can actually keep this because all its methods +- The `ComplexField` trait derives from `FromPrimitive` again. We can actually keep this because all its methods return `Option`, meaning that it could be implemented by any type. ### Modified + - Use more concise debug impls for matrices and geometric transformation types. - The singular values computed by the SVD are now sorted in increasing order by default. Use `SVD::new_unordered` instead to reproduce the older behavior without the sorting overhead. @@ -29,6 +184,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - The `Matrix::pow` and `Matrix::pow_mut` methods will now also work with integer matrices. ### Added + - Added the conversion trait `From>` and method `from_vec_storage` for `RowDVector`. - Added implementation of `From` and `Into` for converting between `nalgebra` types and types from `glam 0.18`. These can be enabled by enabling the `convert-glam018` cargo features. @@ -49,6 +205,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - `nalgebra-sparse`: added reading MatrixMarked data files to a sparse `CooMatrix`. ### Fixed + - Fixed a potential unsoundness with `matrix.get(i)` and `matrix.get_mut(i)` where `i` is an `usize`, and `matrix` is a matrix slice with non-default strides. - Fixed potential unsoundness with `vector.perp` where `vector` isn’t actually a 2D vector as expected. @@ -57,11 +214,12 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Fixed the `no-std` build of `nalgebra-glm`. - Fix the `pow` and `pow_mut` functions (the result was incorrect for some exponent values). - ## [0.29.0] + ### Breaking changes + - We updated to the version 0.6 of `simba`. This means that the trait bounds `T: na::RealField`, `na::ComplexField`, - `na::SimdRealField`, `na:SimdComplexField` no imply that `T: Copy` (they only imply that `T: Clone`). This may affect + `na::SimdRealField`, `na:SimdComplexField` no imply that `T: Copy` (they only imply that `T: Clone`). This may affect generic code. - The closure given to `apply`, `zip_apply`, `zip_zip_apply` must now modify the first argument inplace, instead of returning a new value. This makes these @@ -71,6 +229,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). way. ### Modified + - `Orthographic3::from_matrix_unchecked` is now `const fn`. - `Perspective3::from_matrix_unchecked` is now `const fn`. - `Rotation::from_matrix_unchecked` is now `const fn`. @@ -78,6 +237,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). `Copy` are now much safer to work with thanks to the refactoring of the `Allocator` system. ### Added + - The conversion traits form the `bytemuck` crates are now implemented for the geometric types too. - Added operator overloading for `Transform * UnitComplex`, `UnitComplex * Transform`, `Transform ×= UnitComplex`, `Transform ÷= UnitComplex`. @@ -88,47 +248,60 @@ This project adheres to [Semantic Versioning](https://semver.org/). cargo features. ## [0.28.0] + ### Added + - Implement `Hash` for `Transform`. - Implement `Borrow` and `BorrowMut` for contiguous slices. ### Modified -- The `OPoint` type has been added. It takes the dimension number as a type-level integer (e.g. `Const<3>`) instead + +- The `OPoint` type has been added. It takes the dimension number as a type-level integer (e.g. `Const<3>`) + instead of a const-generic. The type `Point` is now an alias for `OPoint`. This changes doesn't affect any of the existing code using `Point`. However, it will allow the use `OPoint` in a generic context where the dimension cannot be easily expressed as a const-generic (because of the current limitation of const-generics in Rust). -- Several clippy warnings were fixed. This results in some method signature changes (e.g. taking `self` instead of `&self`) +- Several clippy warnings were fixed. This results in some method signature changes (e.g. taking `self` instead + of `&self`) but this should not have any practical infulances on existing codebase. - The `Point::new` constructors are no longer const-fn. This is due to some limitations in const-fn not allowing custom trait-bounds. Use the `point!` macro instead to build points in const environments. - `Dynamic::new` and `Unit::new_unchecked` are now const-fn. - Methods returning `Result<(), ()>` now return `bool` instead. - + ### Fixed + - Fixed a potential unsoundess issue when converting a mutable slice to a `&mut[T]`. ## [0.27.1] + ### Fixed + - Fixed a bug in the conversion from `glam::Vec2` or `glam::DVec2` to `Isometry2`. ## [0.27.0] + This removes the `convert-glam` and `convert-glam-unchecked` optional features. Instead, this adds the `convert-glam013`, `convert-glam014`, and `convert-glam015` optional features for conversions targeting the versions 0.13, 0.14, and 0.15 of `glam`. ### Added + - Add macros `matrix!`, `dmatrix!`, `vector!`, `dvector!`, `point!` for constructing matrices/vectors/points in a - more convenient way. See [#886](https://github.com/dimforge/nalgebra/pull/886) and [#899](https://github.com/dimforge/nalgebra/pull/899). -- Add `CooMatrix::reserve` to `nalgebra-sparse`. + more convenient way. See [#886](https://github.com/dimforge/nalgebra/pull/886) + and [#899](https://github.com/dimforge/nalgebra/pull/899). +- Add `CooMatrix::reserve` to `nalgebra-sparse`. - Add basic support for serialization using `rkyv`. Can be enabled with the features `rkyv-serialize` or `rkyv-serialize-no-std`. - ### Fixed + - Fixed a potential unsoundness issue after deserializing an invalid `DVector` using `serde`. ## [0.26.2] + ### Added + - Conversion from an array `[T; D]` to an isometry `Isometry` (as a translation). - Conversion from a static vector `SVector` to an isometry `Isometry` (as a translation). - Conversion from a point `Point` to an isometry `Isometry` (as a translation). @@ -138,23 +311,26 @@ conversions targeting the versions 0.13, 0.14, and 0.15 of `glam`. - Conversion of a glam type `Vec2/3/4` from/to a `Translation2/3/4`. ## [0.26.1] + Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized with `serde`. ## [0.26.0] + This release integrates `min-const-generics` to nalgebra. See [our blog post](https://www.dimforge.com/blog/2021/04/12/integrating-const-generics-to-nalgebra) for details about this release. ### Added + - Add type aliases for unit vector, e.g., `UnitVector3`. - Add a `pow` and `pow_mut` function to square matrices. - Add `Cholesky::determinant` to compute the determinant of a matrix decomposed with Cholesky. - Add the `serde-serialize-no-std` feature to enable serialization of static matrices/vectors with serde, but without requiring `std`. - ### Modified + - The `serde` crate isn't enabled by default now. Enable the `serde-serialize` or the `serde-serialize-no-std` features instead. - The `Const` type has been introduced to represent dimensions known @@ -176,16 +352,22 @@ for details about this release. constructor is also a `const fn` now. ## [0.25.4] + ### Fixed + - Fix a compilation error when only the `serde-serialize` feature is enabled. ## [0.25.3] + ### Added + - The `Vector::simd_cap_magnitude` method to cap the magnitude of the vector with SIMD components. ## [0.25.2] + ### Added + - A `convert-glam` cargo feature to enable implementations of `From` traits to convert between `glam` types and `nalgebra` types. - A `convert-glam-unchecked` cargo feature to enable some extra `glam`/`nalgebra` conversions that may @@ -196,56 +378,70 @@ for details about this release. type of the components of a given entity. Example: `vector.cast::()`. ## [0.25.1] + This release replaces the version 0.25.0 which has been yanked. The 0.25.0 version added significant complication to build `nalgebra` targeting a `#[no-std]` platform not supported by `rand`. The `rand` dependency is now optional (and disabled by default). You may enable it with: + - The `rand-no-std` cargo feature when targeting a `#[no-std]` environment. - The `rand` cargo feature when targeting a `std` environment. ## [0.25.0] - Yanked + This updates all the dependencies of nalgebra to their latest version, including: + - rand 0.8 - proptest 1.0 - simba 0.4 ### New crate: nalgebra-sparse + Alongside this release of `nalgebra`, we are releasing `nalgebra-sparse`: a crate dedicated to sparse matrix computation with `nalgebra`. The `sparse` module of `nalgebra`itself still exists for backward compatibility, but it will be deprecated soon in favor of the `nalgebra-sparse` crate. ### Added + * Add `UnitDualQuaternion`, a dual-quaternion with unit magnitude which can be used as an isometry transformation. * Add `UDU::new()` and `matrix.udu()` to compute the UDU factorization of a matrix. * Add `ColPivQR::new()` and `matrix.col_piv_qr()` to compute the QR decomposition with column pivoting of a matrix. -* Add `from_basis_unchecked` to all the rotation types. This builds a rotation from a set of basis vectors (representing the columns of the corresponding rotation matrix). +* Add `from_basis_unchecked` to all the rotation types. This builds a rotation from a set of basis vectors (representing + the columns of the corresponding rotation matrix). * Add `Matrix::cap_magnitude` to cap the magnitude of a vector. -* Add `UnitQuaternion::append_axisangle_linearized` to approximately append a rotation represented as an axis-angle to a rotation represented as an unit quaternion. +* Add `UnitQuaternion::append_axisangle_linearized` to approximately append a rotation represented as an axis-angle to a + rotation represented as an unit quaternion. * Mark the iterators on matrix components as `DoubleEndedIter`. * Re-export `simba::simd::SimdValue` at the root of the `nalgebra` crate. ## [0.24.0] ### Added + * The `DualQuaternion` type. It is still work-in-progress, but the basics are here: creation from its real and dual part, multiplication of two dual quaternions, and normalization. - + ### Removed + * There is no blanket `impl PartialEq for Unit` anymore. Instead, it is implemented specifically for `UnitComplex`, `UnitQuaternion` and `Unit`. ## [0.23.2] + In this release, we improved the documentation of some of the geometric types by applying changes similar to what we did in the version 0.23.1 for matrices. ### Added + * The `Isometry::inv_mul` method which is a more efficient way of doing `isometry1.inverse() * isometry2`. ## [0.23.1] + In this release we improved the documentation of the matrix and vector types by: + - Grouping `impl` bocks logically, adding a title comment to these impl blocks. - Reference these impl blocks docs at the top of the documentation page for `Matrix`. - Reduce the depth of type aliasing. Now all vector and matrix types are aliases of `Matrix` @@ -254,237 +450,290 @@ In this release we improved the documentation of the matrix and vector types by: ## [0.23.0] ### Added - * The `.inverse_transform_unit_vector(v)` was added to `Rotation2/3`, `Isometry2/3`, `UnitQuaternion`, and `UnitComplex`. - It applies the corresponding rotation to a unit vector `Unit`. - * The `Point.map(f)` and `Point.apply(f)` to apply a function to each component of the point, similarly to `Vector.map(f)` - and `Vector.apply(f)`. - * The `Quaternion::from([N; 4])` conversion to build a quaternion from an array of four elements. - * The `Isometry::from(Translation)` conversion to build an isometry from a translation. - * The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit>` with its i-th component set to 1.0, and the - others set to zero. - * The `Isometry.lerp_slerp` and `Isometry.try_lerp_slerp` methods to interpolate between two isometries using linear - interpolation for the translational part, and spherical interpolation for the rotational part. - * The `Rotation2.slerp`, `Rotation3.slerp`, and `UnitQuaternion.slerp` method for - spherical interpolation. - + +* The `.inverse_transform_unit_vector(v)` was added to `Rotation2/3`, `Isometry2/3`, `UnitQuaternion`, + and `UnitComplex`. + It applies the corresponding rotation to a unit vector `Unit`. +* The `Point.map(f)` and `Point.apply(f)` to apply a function to each component of the point, similarly + to `Vector.map(f)` + and `Vector.apply(f)`. +* The `Quaternion::from([N; 4])` conversion to build a quaternion from an array of four elements. +* The `Isometry::from(Translation)` conversion to build an isometry from a translation. +* The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit>` with its i-th component set to 1.0, + and the + others set to zero. +* The `Isometry.lerp_slerp` and `Isometry.try_lerp_slerp` methods to interpolate between two isometries using linear + interpolation for the translational part, and spherical interpolation for the rotational part. +* The `Rotation2.slerp`, `Rotation3.slerp`, and `UnitQuaternion.slerp` method for + spherical interpolation. + ## [0.22.0] + In this release, we are using the new version 0.2 of simba. One major change of that version is that the use of `libm` is now opt-in when building targeting `no-std` environment. If you are using floating-point operations with nalgebra in a `no-std` environment, you will need to enable the new `libm` feature of nalgebra for your code to compile again. ### Added - * The `libm` feature that enables `libm` when building for `no-std` environment. - * The `libm-force` feature that enables `libm` even when building for a not `no-std` environment. - * `Cholesky::new_unchecked` which build a Cholesky decomposition without checking that its input is - positive-definite. It can be used with SIMD types. - * The `Default` trait is now implemented for matrices, and quaternions. They are all filled with zeros, - except for `UnitQuaternion` which is initialized with the identity. - * Matrix exponential `matrix.exp()`. - * The `Vector::ith(i, x)` that builds a vector filled with zeros except for the `i`-th component set to `x`. + +* The `libm` feature that enables `libm` when building for `no-std` environment. +* The `libm-force` feature that enables `libm` even when building for a not `no-std` environment. +* `Cholesky::new_unchecked` which build a Cholesky decomposition without checking that its input is + positive-definite. It can be used with SIMD types. +* The `Default` trait is now implemented for matrices, and quaternions. They are all filled with zeros, + except for `UnitQuaternion` which is initialized with the identity. +* Matrix exponential `matrix.exp()`. +* The `Vector::ith(i, x)` that builds a vector filled with zeros except for the `i`-th component set to `x`. ## [0.21.0] + In this release, we are no longer relying on traits from the __alga__ crate for our generic code. Instead, we use traits from the new [simba](https://crates.io/crates/simba) crate which are both -simpler, and allow for significant optimizations like AoSoA SIMD. +simpler, and allow for significant optimizations like AoSoA SIMD. Refer to the [monthly dimforge blogpost](https://www.dimforge.org/blog/2020/04/01/this-month-in-dimforge/) for details about this switch and its benefits. ### Added - * It is now possible to use SIMD types like `simba::f32x4` as scalar types for nalgebra's matrices and - geometric types. + +* It is now possible to use SIMD types like `simba::f32x4` as scalar types for nalgebra's matrices and + geometric types. + ### Modified - * Use of traits like `alga::general::{RealField, ComplexField}` have now been replaced by - `simba::scalar::{RealField, ComplexField}`. - * The implementation of traits from the __alga__ crate (and well as the dependency to _alga__) are now - omitted unless the `alga` cargo feature is activated. + +* Use of traits like `alga::general::{RealField, ComplexField}` have now been replaced by + `simba::scalar::{RealField, ComplexField}`. +* The implementation of traits from the __alga__ crate (and well as the dependency to _alga__) are now + omitted unless the `alga` cargo feature is activated. + ### Removed - * The `Neg` unary operator is no longer implemented for `UnitComplex` and `UnitQuaternion`. This caused - hard-to-track errors when we mistakenly write, e.g., `-q * v` instead of `-(q * v)`. - * The `na::convert_unchecked` is no longer marked as unsafe. + +* The `Neg` unary operator is no longer implemented for `UnitComplex` and `UnitQuaternion`. This caused + hard-to-track errors when we mistakenly write, e.g., `-q * v` instead of `-(q * v)`. +* The `na::convert_unchecked` is no longer marked as unsafe. ## [0.20.0] + ### Added - * `cholesky.rank_one_update(...)` which performs a rank-one update on the cholesky decomposition of a matrix. - * `From<&Matrix>` is now implemented for matrix slices. - * `.try_set_magnitude(...)` which sets the magnitude of a vector, while keeping its direction. - * Implementations of `From` and `Into` for the conversion between matrix slices and standard (`&[N]` `&mut [N]`) slices. + +* `cholesky.rank_one_update(...)` which performs a rank-one update on the cholesky decomposition of a matrix. +* `From<&Matrix>` is now implemented for matrix slices. +* `.try_set_magnitude(...)` which sets the magnitude of a vector, while keeping its direction. +* Implementations of `From` and `Into` for the conversion between matrix slices and standard (`&[N]` `&mut [N]`) slices. ### Modified - * We started some major changes in order to allow non-Copy types to be used as scalar types inside of matrices/vectors. + +* We started some major changes in order to allow non-Copy types to be used as scalar types inside of matrices/vectors. ## [0.19.0] + ### Added - * `.remove_rows_at` and `remove_columns_at` which removes a set of rows or columns (specified by indices) from a matrix. - * Several formatting traits have been implemented for all matrices/vectors: `LowerExp`, `UpperExp`, `Octal`, `LowerHex`, - `UpperHex`, `Binary`, `Pointer`. - * `UnitQuaternion::quaternions_mean(...)` which computes the mean rotation of a set of unit quaternions. This implements - the algorithm from _Oshman, Yaakov, and Avishy Carmi, "Attitude estimation from vector observations using a genetic-algorithm-embedded quaternion particle filter." + +* `.remove_rows_at` and `remove_columns_at` which removes a set of rows or columns (specified by indices) from a matrix. +* Several formatting traits have been implemented for all matrices/vectors: `LowerExp`, `UpperExp`, `Octal`, `LowerHex`, + `UpperHex`, `Binary`, `Pointer`. +* `UnitQuaternion::quaternions_mean(...)` which computes the mean rotation of a set of unit quaternions. This implements + the algorithm from _Oshman, Yaakov, and Avishy Carmi, "Attitude estimation from vector observations using a + genetic-algorithm-embedded quaternion particle filter." ### Modified - * It is now possible to get the `min/max` element of unsigned integer matrices. + +* It is now possible to get the `min/max` element of unsigned integer matrices. ### Added to nalgebra-glm - * Some infinite and reversed perspectives: `::infinite_perspective_rh_no`, `::infinite_perspective_rh_zo`, - `::reversed_perspective_rh_zo`, and `::reversed_infinite_perspective_rh_zo`. + +* Some infinite and reversed perspectives: `::infinite_perspective_rh_no`, `::infinite_perspective_rh_zo`, + `::reversed_perspective_rh_zo`, and `::reversed_infinite_perspective_rh_zo`. ## [0.18.0] + This release adds full complex number support to nalgebra. This includes all common vector/matrix operations as well as matrix decomposition. This excludes geometric type (like `Isometry`, `Rotation`, `Translation`, etc.) from the `geometry` module. ### Added + #### Quaternion and geometric operations - * Add trigonometric functions for quaternions: `.cos, .sin, .tan, .acos, .asin, .atan, .cosh, .sinh, .tanh, .acosh, .asinh, .atanh`. - * Add geometric algebra operations for quaternions: `.inner, .outer, .project, .rejection` - * Add `.left_div, .right_div` for quaternions. - * Add `.renormalize` to `Unit<...>` and `Rotation3` to correct potential drift due to repeated operations. - Those drifts could cause them not to be pure rotations anymore. + +* Add trigonometric functions for + quaternions: `.cos, .sin, .tan, .acos, .asin, .atan, .cosh, .sinh, .tanh, .acosh, .asinh, .atanh`. +* Add geometric algebra operations for quaternions: `.inner, .outer, .project, .rejection` +* Add `.left_div, .right_div` for quaternions. +* Add `.renormalize` to `Unit<...>` and `Rotation3` to correct potential drift due to repeated operations. + Those drifts could cause them not to be pure rotations anymore. #### Convolution - * `.convolve_full(kernel)` returns the convolution of `self` by `kernel`. - * `.convolve_valid(kernel)` returns the convolution of `self` by `kernel` after removal of all the elements relying on zero-padding. - * `.convolve_same(kernel)` returns the convolution of `self` by `kernel` with a result of the same size as `self`. + +* `.convolve_full(kernel)` returns the convolution of `self` by `kernel`. +* `.convolve_valid(kernel)` returns the convolution of `self` by `kernel` after removal of all the elements relying on + zero-padding. +* `.convolve_same(kernel)` returns the convolution of `self` by `kernel` with a result of the same size as `self`. #### Complex number support - * 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. - * Add `.camax()` which returns the matrix component with the greatest L1-norm. - * Add `.camin()` which returns the matrix component with the smallest L1-norm. - * Add `.ad_mul(b)` for matrix-multiplication of `self.adjoint() * b`. - * Add `.ad_mul_to(b)` which is the same as `.ad_mul` but with a provided matrix to be filled with the result of the multiplication. - * Add BLAS operations involving complex conjugation (following similar names as the original BLAS spec): - * `.dotc(rhs)` equal to `self.adjoint() * rhs`. - * `.gerc(alpha, x, y, beta)` equivalent to `self = alpha * x * y.adjoint() + beta * self` - * `.hegerc` which is like `gerc` but for Hermitian matrices. - * `.syger` which is the new name of `.ger_symm` which is equivalent to `self = alpha * x * y.transpose() + beta * self`. - * `.sygemv` which is the new name of `.gemv_symm` which is equivalent to `self = alpha * a * x + beta * self` with `a` symmetric. - * `.hegemv(alpha, a, x, beta)` which is like `.sygemv` but with `a` Hermitian. - * `.gemv_ad(alpha, a, x, beta)` which is equivalent to `self = alpha * a.adjoint() * x + beta * self`. - * `.gemm_ad(alpha, a, b, beta)` which is equivalent to `self = alpha * a.adjoint() * b + beta * self`. - * `.icamax()` which returns the index of the complex vector component with the greatest L1-norm. + +* 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. +* Add `.camax()` which returns the matrix component with the greatest L1-norm. +* Add `.camin()` which returns the matrix component with the smallest L1-norm. +* Add `.ad_mul(b)` for matrix-multiplication of `self.adjoint() * b`. +* Add `.ad_mul_to(b)` which is the same as `.ad_mul` but with a provided matrix to be filled with the result of the + multiplication. +* Add BLAS operations involving complex conjugation (following similar names as the original BLAS spec): + * `.dotc(rhs)` equal to `self.adjoint() * rhs`. + * `.gerc(alpha, x, y, beta)` equivalent to `self = alpha * x * y.adjoint() + beta * self` + * `.hegerc` which is like `gerc` but for Hermitian matrices. + * `.syger` which is the new name of `.ger_symm` which is equivalent + to `self = alpha * x * y.transpose() + beta * self`. + * `.sygemv` which is the new name of `.gemv_symm` which is equivalent to `self = alpha * a * x + beta * self` + with `a` symmetric. + * `.hegemv(alpha, a, x, beta)` which is like `.sygemv` but with `a` Hermitian. + * `.gemv_ad(alpha, a, x, beta)` which is equivalent to `self = alpha * a.adjoint() * x + beta * self`. + * `.gemm_ad(alpha, a, b, beta)` which is equivalent to `self = alpha * a.adjoint() * b + beta * self`. + * `.icamax()` which returns the index of the complex vector component with the greatest L1-norm. Note that all the other BLAS operation will continue to work for all fields, including floats and complex numbers. ### Renamed - * `RealSchur` has been renamed `Schur` because it can now work with complex matrices. +* `RealSchur` has been renamed `Schur` because it can now work with complex matrices. ## [0.17.0] ### 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 points. For example, you can do `p.zxy()` as an equivalent to `Point3::new(p.z, p.x, p.y)`. - * Add `.copy_from_slice` to copy matrix components from a slice in column-major order. - * Add `.dot` to quaternions. - * Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them. - * Add `.slerp` and `.try_slerp` to unit vectors. - * Add `.lerp` to vectors. - * Add `.to_projective` and `.as_projective` to `Perspective3` and `Orthographic3` in order to - use them as `Projective3` structures. - * Add `From/Into` impls to allow the conversion of any transformation type to a matrix. - * Add `Into` impls to convert a matrix slice into an owned matrix. - * Add `Point*::from_slice` to create a point from a slice. - * Add `.map_with_location` to matrices to apply a map which passes the component indices to the user-defined closure alongside - the component itself. - * Add impl `From` for `Point`. - * Add impl `From` for `Quaternion`. - * Add impl `From` for `Translation`. - * Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec` - as-is for its storage). - * Add `.to_homogeneous` to square matrices (and with dimensions higher than 1x1). This will increase their number of row - and columns by 1. The new column and row are filled with 0, except for the diagonal element which is set to 1. - * Implement `Extend` for matrices with a dynamic storage. The provided `Vec` is assumed to represent a column-major - matrix with the same number of rows as the one being extended. This will effectively append new columns on the right of - the matrix being extended. - * Implement `Extend` for vectors with a dynamic storage. This will concatenate the vector with the given `Vec`. - * Implement `Extend>` for matrices with dynamic storage. This will concatenate the columns of both matrices. - * Implement `Into` for the `MatrixVec` storage. - * Implement `Hash` for all matrices. - * Add a `.len()` method to retrieve the size of a `MatrixVec`. + +* 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 points. For example, you can do `p.zxy()` as an equivalent + to `Point3::new(p.z, p.x, p.y)`. +* Add `.copy_from_slice` to copy matrix components from a slice in column-major order. +* Add `.dot` to quaternions. +* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them. +* Add `.slerp` and `.try_slerp` to unit vectors. +* Add `.lerp` to vectors. +* Add `.to_projective` and `.as_projective` to `Perspective3` and `Orthographic3` in order to + use them as `Projective3` structures. +* Add `From/Into` impls to allow the conversion of any transformation type to a matrix. +* Add `Into` impls to convert a matrix slice into an owned matrix. +* Add `Point*::from_slice` to create a point from a slice. +* Add `.map_with_location` to matrices to apply a map which passes the component indices to the user-defined closure + alongside + the component itself. +* Add impl `From` for `Point`. +* Add impl `From` for `Quaternion`. +* Add impl `From` for `Translation`. +* Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec` + as-is for its storage). +* Add `.to_homogeneous` to square matrices (and with dimensions higher than 1x1). This will increase their number of row + and columns by 1. The new column and row are filled with 0, except for the diagonal element which is set to 1. +* Implement `Extend` for matrices with a dynamic storage. The provided `Vec` is assumed to represent a column-major + matrix with the same number of rows as the one being extended. This will effectively append new columns on the right + of + the matrix being extended. +* Implement `Extend` for vectors with a dynamic storage. This will concatenate the vector with the given `Vec`. +* Implement `Extend>` for matrices with dynamic storage. This will concatenate the columns of both matrices. +* Implement `Into` for the `MatrixVec` storage. +* Implement `Hash` for all matrices. +* Add a `.len()` method to retrieve the size of a `MatrixVec`. ### Modified - * 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). - * The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead. - * The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not have to - explicitly import the `Transform` trait from the alga crate. - * Renamed the matrix storage types: `MatrixArray` -> `ArrayStorage` and `MatrixVec` -> `VecStorage`. - * Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type. - This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`. - * Deprecate several functions at the root of the crate (replaced by methods). + +* 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). +* The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead. +* The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not + have to + explicitly import the `Transform` trait from the alga crate. +* Renamed the matrix storage types: `MatrixArray` -> `ArrayStorage` and `MatrixVec` -> `VecStorage`. +* Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type. + This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`. +* 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 - * 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 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). ## [0.16.0] + All dependencies have been updated to their latest versions. ## Modified - * Adjust `UnitQuaternion`s, `Rotation3`s, and `Rotation2`s generated from the `Standard` distribution to be uniformly distributed. + +* Adjust `UnitQuaternion`s, `Rotation3`s, and `Rotation2`s generated from the `Standard` distribution to be uniformly + distributed. + ### Added - * Add a feature `stdweb` to activate the dependency feature `rand/stdweb`. - * Add blas-like methods `.imin()` and `.imax()` that return the index of the minimum and maximum entry of a vector. - * Add construction of a `Point` from an array by implementing the `From` trait. - * Add support for generating uniformly distributed random unit column vectors using the `Standard` distribution. + +* Add a feature `stdweb` to activate the dependency feature `rand/stdweb`. +* Add blas-like methods `.imin()` and `.imax()` that return the index of the minimum and maximum entry of a vector. +* Add construction of a `Point` from an array by implementing the `From` trait. +* Add support for generating uniformly distributed random unit column vectors using the `Standard` distribution. ## [0.15.0] + The most notable change of this release is the support for using part of the library without the rust standard -library (i.e. it supports `#![no_std]`). See the corresponding [documentation](https://nalgebra.org/wasm_and_embedded_programming/). +library (i.e. it supports `#![no_std]`). See the +corresponding [documentation](https://nalgebra.org/wasm_and_embedded_programming/). + ### Modified - * Rename the `core` module to `base` to avoid conflicts with the `core` crate implicitly imported when - `#![no_std]` is enabled. - * Constructors of the `MatrixSlice*` types have been renamed from `new_*` to `from_slice_*`. This was - necessary to avoid the `incoherent_fundamental_impls` lint that is going to become a hard error. + +* Rename the `core` module to `base` to avoid conflicts with the `core` crate implicitly imported when + `#![no_std]` is enabled. +* Constructors of the `MatrixSlice*` types have been renamed from `new_*` to `from_slice_*`. This was + necessary to avoid the `incoherent_fundamental_impls` lint that is going to become a hard error. + ### Added - * Add `UnitQuaternion` constructor `::new_eps(...)` and `::from_scaled_axis_eps(...)` that return the - identity if the magnitude of the input axisangle is smaller than the epsilon provided. - * Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex` - to compute the rotation matrix between two 2D **unit** vectors. - * Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the - unit rotation axis, and the rotation angle simultaneously. - * Add functions to construct a random matrix with a user-defined distribution: `::from_distribution(...)`. + +* Add `UnitQuaternion` constructor `::new_eps(...)` and `::from_scaled_axis_eps(...)` that return the + identity if the magnitude of the input axisangle is smaller than the epsilon provided. +* Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex` + to compute the rotation matrix between two 2D **unit** vectors. +* Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the + unit rotation axis, and the rotation angle simultaneously. +* Add functions to construct a random matrix with a user-defined distribution: `::from_distribution(...)`. ## [0.14.0] + ### Modified - * Allow the `Isometry * Unit` multiplication. + +* Allow the `Isometry * Unit` multiplication. + ### Added - * Add blas-like operations: `.quadform(...)` and `.quadform_tr(...)` to compute respectively - the quadratic forms `self = alpha * A.transpose() * B * A + beta * self` and - `alpha * A * B * A.transpose() + beta * self`. Here, `A, B` are matrices with - `B` square, and `alpha, beta` are reals. - * Add blas-like operations: `.gemv_tr(...)` that behaves like `.gemv` except that the - provided matrix is assumed to be transposed. - * Add blas-like operations: `cmpy, cdpy` for component-wise multiplications and - division with scalar factors: - - `self <- alpha * self + beta * a * b` - - `self <- alpha * self + beta * a / b` - * `.cross_matrix()` returns the cross-product matrix of a given 3D vector, i.e., - the matrix `M` such that for all vector `v` we have - `M * v == self.cross(&v)`. - * `.iamin()` that returns the index of the vector entry with - the smallest absolute value. - * The `mint` feature that can be enabled in order to allow conversions from - and to types of the [mint](https://crates.io/crates/mint) crate. - * Aliases for matrix and vector slices. Their are named by adding `Slice` - before the dimension numbers, i.e., a 3x5 matrix slice with dimensions known - at compile-time is called `MatrixSlice3x5`. A vector slice with dimensions - unknown at compile-time is called `DVectorSlice`. - * Add functions for constructing matrix slices from a slice `&[N]`, e.g., - `MatrixSlice2::new(...)` and `MatrixSlice2::new_with_strides(...)`. - * The `::repeat(...)` constructor that is an alternative name to - `::from_element(...)`. - * `UnitQuaternion::scaled_rotation_between_axis(...)` and - `UnitQuaternion::rotation_between_axis(...)` that take Unit vectors instead of - Vector as arguments. - +* Add blas-like operations: `.quadform(...)` and `.quadform_tr(...)` to compute respectively + the quadratic forms `self = alpha * A.transpose() * B * A + beta * self` and + `alpha * A * B * A.transpose() + beta * self`. Here, `A, B` are matrices with + `B` square, and `alpha, beta` are reals. +* Add blas-like operations: `.gemv_tr(...)` that behaves like `.gemv` except that the + provided matrix is assumed to be transposed. +* Add blas-like operations: `cmpy, cdpy` for component-wise multiplications and + division with scalar factors: + - `self <- alpha * self + beta * a * b` + - `self <- alpha * self + beta * a / b` +* `.cross_matrix()` returns the cross-product matrix of a given 3D vector, i.e., + the matrix `M` such that for all vector `v` we have + `M * v == self.cross(&v)`. +* `.iamin()` that returns the index of the vector entry with + the smallest absolute value. +* The `mint` feature that can be enabled in order to allow conversions from + and to types of the [mint](https://crates.io/crates/mint) crate. +* Aliases for matrix and vector slices. Their are named by adding `Slice` + before the dimension numbers, i.e., a 3x5 matrix slice with dimensions known + at compile-time is called `MatrixSlice3x5`. A vector slice with dimensions + unknown at compile-time is called `DVectorSlice`. +* Add functions for constructing matrix slices from a slice `&[N]`, e.g., + `MatrixSlice2::new(...)` and `MatrixSlice2::new_with_strides(...)`. +* The `::repeat(...)` constructor that is an alternative name to + `::from_element(...)`. +* `UnitQuaternion::scaled_rotation_between_axis(...)` and + `UnitQuaternion::rotation_between_axis(...)` that take Unit vectors instead of + Vector as arguments. ## [0.13.0] @@ -495,157 +744,175 @@ This adds support for serialization using the [abomonation](https://crates.io/crates/abomonation) crate. ### Breaking semantic change - * The implementation of slicing with steps now matches the documentation. - Before, step identified the number to add to pass from one column/row index - to the next one. This made 0 step invalid. Now (and on the documentation so - far), the step is the number of ignored row/columns between each - row/column. Thus, a step of 0 means that no row/column is ignored. For - example, a step of, say, 3 on previous versions should now bet set to 2. + +* The implementation of slicing with steps now matches the documentation. + Before, step identified the number to add to pass from one column/row index + to the next one. This made 0 step invalid. Now (and on the documentation so + far), the step is the number of ignored row/columns between each + row/column. Thus, a step of 0 means that no row/column is ignored. For + example, a step of, say, 3 on previous versions should now bet set to 2. ### Modified - * The trait `Axpy` has been replaced by a method `.axpy`. - * The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we - reordered M and N to be in alphabetical order). - * In-place componentwise multiplication and division - `.component_mul_mut(...)` and `.component_div_mut(...)` have been deprecated - for a future renaming. Use `.component_mul_assign(...)` and - `.component_div_assign(...)` instead. + +* The trait `Axpy` has been replaced by a method `.axpy`. +* The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we + reordered M and N to be in alphabetical order). +* In-place componentwise multiplication and division + `.component_mul_mut(...)` and `.component_div_mut(...)` have been deprecated + for a future renaming. Use `.component_mul_assign(...)` and + `.component_div_assign(...)` instead. ### Added - * `alga::general::Real` is now re-exported by nalgebra. - elements.) - * `::zeros(...)` that creates a matrix filled with zeroes. - * `::from_partial_diagonal(...)` that creates a matrix from diagonal elements. - The matrix can be rectangular. If not enough elements are provided, the rest - of the diagonal is set to 0. - * `.conjugate_transpose()` computes the transposed conjugate of a - complex matrix. - * `.conjugate_transpose_to(...)` computes the transposed conjugate of a - complex matrix. The result written into a user-provided matrix. - * `.transpose_to(...)` is the same as `.transpose()` but stores the result in - the provided matrix. - * `.conjugate_transpose_to(...)` is the same as `.conjugate_transpose()` but - stores the result in the provided matrix. - * Implements `IntoIterator` for `&Matrix`, `&mut Matrix` and `Matrix`. - * `.mul_to(...)` multiplies two matrices and stores the result to the given buffer. - * `.tr_mul_to(...)` left-multiplies `self.transpose()` to another matrix and stores the result to the given buffer. - * `.add_scalar(...)` that adds a scalar to each component of a matrix. - * `.add_scalar_mut(...)` that adds in-place a scalar to each component of a matrix. - * `.kronecker(a, b)` computes the kronecker product (i.e. matrix tensor - product) of two matrices. - * `.apply(f)` replaces each component of a matrix with the results of the - closure `f` called on each of them. + +* `alga::general::Real` is now re-exported by nalgebra. + elements.) +* `::zeros(...)` that creates a matrix filled with zeroes. +* `::from_partial_diagonal(...)` that creates a matrix from diagonal elements. + The matrix can be rectangular. If not enough elements are provided, the rest + of the diagonal is set to 0. +* `.conjugate_transpose()` computes the transposed conjugate of a + complex matrix. +* `.conjugate_transpose_to(...)` computes the transposed conjugate of a + complex matrix. The result written into a user-provided matrix. +* `.transpose_to(...)` is the same as `.transpose()` but stores the result in + the provided matrix. +* `.conjugate_transpose_to(...)` is the same as `.conjugate_transpose()` but + stores the result in the provided matrix. +* Implements `IntoIterator` for `&Matrix`, `&mut Matrix` and `Matrix`. +* `.mul_to(...)` multiplies two matrices and stores the result to the given buffer. +* `.tr_mul_to(...)` left-multiplies `self.transpose()` to another matrix and stores the result to the given buffer. +* `.add_scalar(...)` that adds a scalar to each component of a matrix. +* `.add_scalar_mut(...)` that adds in-place a scalar to each component of a matrix. +* `.kronecker(a, b)` computes the kronecker product (i.e. matrix tensor + product) of two matrices. +* `.apply(f)` replaces each component of a matrix with the results of the + closure `f` called on each of them. Pure Rust implementation of some Blas operations: - * `.iamax()` returns the index of the maximum value of a vector. - * `.axpy(...)` computes `self = a * x + b * self`. - * `.gemv(...)` computes `self = alpha * a * x + beta * self` with a matrix and vector `a` and `x`. - * `.ger(...)` computes `self = alpha * x^t * y + beta * self` where `x` and `y` are vectors. - * `.gemm(...)` computes `self = alpha * a * b + beta * self` where `a` and `b` are matrices. - * `.gemv_symm(...)` is the same as `.gemv` except that `self` is assumed symmetric. - * `.ger_symm(...)` is the same as `.ger` except that `self` is assumed symmetric. +* `.iamax()` returns the index of the maximum value of a vector. +* `.axpy(...)` computes `self = a * x + b * self`. +* `.gemv(...)` computes `self = alpha * a * x + beta * self` with a matrix and vector `a` and `x`. +* `.ger(...)` computes `self = alpha * x^t * y + beta * self` where `x` and `y` are vectors. +* `.gemm(...)` computes `self = alpha * a * b + beta * self` where `a` and `b` are matrices. +* `.gemv_symm(...)` is the same as `.gemv` except that `self` is assumed symmetric. +* `.ger_symm(...)` is the same as `.ger` except that `self` is assumed symmetric. New slicing methods: - * `.rows_range(...)` that retrieves a reference to a range of rows. - * `.rows_range_mut(...)` that retrieves a mutable reference to a range of rows. - * `.columns_range(...)` that retrieves a reference to a range of columns. - * `.columns_range_mut(...)` that retrieves a mutable reference to a range of columns. + +* `.rows_range(...)` that retrieves a reference to a range of rows. +* `.rows_range_mut(...)` that retrieves a mutable reference to a range of rows. +* `.columns_range(...)` that retrieves a reference to a range of columns. +* `.columns_range_mut(...)` that retrieves a mutable reference to a range of columns. Matrix decompositions implemented in pure Rust: - * Cholesky, SVD, LU, QR, Hessenberg, Schur, Symmetric eigendecompositions, - Bidiagonal, Symmetric tridiagonal - * Computation of householder reflectors and givens rotations. + +* Cholesky, SVD, LU, QR, Hessenberg, Schur, Symmetric eigendecompositions, + Bidiagonal, Symmetric tridiagonal +* Computation of householder reflectors and givens rotations. Matrix edition: - * `.upper_triangle()` extracts the upper triangle of a matrix, including the diagonal. - * `.lower_triangle()` extracts the lower triangle of a matrix, including the diagonal. - * `.fill(...)` fills the matrix with a single value. - * `.fill_with_identity(...)` fills the matrix with the identity. - * `.fill_diagonal(...)` fills the matrix diagonal with a single value. - * `.fill_row(...)` fills a selected matrix row with a single value. - * `.fill_column(...)` fills a selected matrix column with a single value. - * `.set_diagonal(...)` sets the matrix diagonal. - * `.set_row(...)` sets a selected row. - * `.set_column(...)` sets a selected column. - * `.fill_lower_triangle(...)` fills some sub-diagonals below the main diagonal with a value. - * `.fill_upper_triangle(...)` fills some sub-diagonals above the main diagonal with a value. - * `.swap_rows(...)` swaps two rows. - * `.swap_columns(...)` swaps two columns. + +* `.upper_triangle()` extracts the upper triangle of a matrix, including the diagonal. +* `.lower_triangle()` extracts the lower triangle of a matrix, including the diagonal. +* `.fill(...)` fills the matrix with a single value. +* `.fill_with_identity(...)` fills the matrix with the identity. +* `.fill_diagonal(...)` fills the matrix diagonal with a single value. +* `.fill_row(...)` fills a selected matrix row with a single value. +* `.fill_column(...)` fills a selected matrix column with a single value. +* `.set_diagonal(...)` sets the matrix diagonal. +* `.set_row(...)` sets a selected row. +* `.set_column(...)` sets a selected column. +* `.fill_lower_triangle(...)` fills some sub-diagonals below the main diagonal with a value. +* `.fill_upper_triangle(...)` fills some sub-diagonals above the main diagonal with a value. +* `.swap_rows(...)` swaps two rows. +* `.swap_columns(...)` swaps two columns. Column removal: - * `.remove_column(...)` removes one column. - * `.remove_fixed_columns(...)` removes `D` columns. - * `.remove_columns(...)` removes a number of columns known at run-time. + +* `.remove_column(...)` removes one column. +* `.remove_fixed_columns(...)` removes `D` columns. +* `.remove_columns(...)` removes a number of columns known at run-time. Row removal: - * `.remove_row(...)` removes one row. - * `.remove_fixed_rows(...)` removes `D` rows. - * `.remove_rows(...)` removes a number of rows known at run-time. + +* `.remove_row(...)` removes one row. +* `.remove_fixed_rows(...)` removes `D` rows. +* `.remove_rows(...)` removes a number of rows known at run-time. Column insertion: - * `.insert_column(...)` adds one column at the given position. - * `.insert_fixed_columns(...)` adds `D` columns at the given position. - * `.insert_columns(...)` adds at the given position a number of columns known at run-time. + +* `.insert_column(...)` adds one column at the given position. +* `.insert_fixed_columns(...)` adds `D` columns at the given position. +* `.insert_columns(...)` adds at the given position a number of columns known at run-time. Row insertion: - * `.insert_row(...)` adds one row at the given position. - * `.insert_fixed_rows(...)` adds `D` rows at the given position. - * `.insert_rows(...)` adds at the given position a number of rows known at run-time. + +* `.insert_row(...)` adds one row at the given position. +* `.insert_fixed_rows(...)` adds `D` rows at the given position. +* `.insert_rows(...)` adds at the given position a number of rows known at run-time. ## [0.12.0] + The main change of this release is the update of the dependency serde to 1.0. ### Added - * `.trace()` that computes the trace of a matrix (the sum of its diagonal - elements.) + +* `.trace()` that computes the trace of a matrix (the sum of its diagonal + elements.) ## [0.11.0] + The [website](https://nalgebra.org) has been fully rewritten and gives a good overview of all the added/modified features. This version is a major rewrite of the library. Major changes are: - * Algebraic traits are now defined by the [alga](https://crates.io/crates/alga) crate. - All other mathematical traits, except `Axpy` have been removed from - **nalgebra**. - * Methods are now preferred to free functions because they do not require any - trait to be used anymore. - * Most algebraic entities can be parametrized by type-level integers - to specify their dimensions. Using `Dynamic` instead of a type-level - integer indicates that the dimension known at run-time only. - * Statically-sized **rectangular** matrices. - * More transformation types have been added: unit-sized complex numbers (for - 2D rotations), affine/projective/general transformations with `Affine2/3`, - `Projective2/3`, and `Transform2/3`. - * Serde serialization is now supported instead of `rustc_serialize`. Enable - it with the `serde-serialize` feature. - * Matrix **slices** are now implemented. + +* Algebraic traits are now defined by the [alga](https://crates.io/crates/alga) crate. + All other mathematical traits, except `Axpy` have been removed from + **nalgebra**. +* Methods are now preferred to free functions because they do not require any + trait to be used anymore. +* Most algebraic entities can be parametrized by type-level integers + to specify their dimensions. Using `Dynamic` instead of a type-level + integer indicates that the dimension known at run-time only. +* Statically-sized **rectangular** matrices. +* More transformation types have been added: unit-sized complex numbers (for + 2D rotations), affine/projective/general transformations with `Affine2/3`, + `Projective2/3`, and `Transform2/3`. +* Serde serialization is now supported instead of `rustc_serialize`. Enable + it with the `serde-serialize` feature. +* Matrix **slices** are now implemented. ### Added + Lots of features including rectangular matrices, slices, and Serde serialization. Refer to the brand new [website](https://nalgebra.org) for more details. The following free-functions have been added as well: - * `::id()` that returns the universal [identity element](https://nalgebra.org/performance_tricks/#the-id-type) - of type `Id`. - * `::inf_sup()` that returns both the infimum and supremum of a value at the - same time. - * `::partial_sort2()` that attempts to sort two values in increasing order. - * `::wrap()` that moves a value to the given interval by adding or removing - the interval width to it. + +* `::id()` that returns the universal [identity element](https://nalgebra.org/performance_tricks/#the-id-type) + of type `Id`. +* `::inf_sup()` that returns both the infimum and supremum of a value at the + same time. +* `::partial_sort2()` that attempts to sort two values in increasing order. +* `::wrap()` that moves a value to the given interval by adding or removing + the interval width to it. ### Modified - * `::cast` -> `::convert` - * `point.as_vector()` -> `point.coords` - * `na::origin` -> `P::origin()` - * `na::is_zero` -> `.is_zero()` (from num::Zero) - * `.transform` -> `.transform_point`/`.transform_vector` - * `.translate` -> `.translate_point` - * `::dimension::

` -> `::dimension::` - * `::angle_between` -> `::angle` + +* `::cast` -> `::convert` +* `point.as_vector()` -> `point.coords` +* `na::origin` -> `P::origin()` +* `na::is_zero` -> `.is_zero()` (from num::Zero) +* `.transform` -> `.transform_point`/`.transform_vector` +* `.translate` -> `.translate_point` +* `::dimension::

` -> `::dimension::` +* `::angle_between` -> `::angle` Componentwise multiplication and division has been replaced by methods: - * multiplication -> `.componentwise_mul`, `.componentwise_mul_mut`. - * division -> `.componentwise_div`, `.componentwise_div_mut`. + +* multiplication -> `.componentwise_mul`, `.componentwise_mul_mut`. +* division -> `.componentwise_div`, `.componentwise_div_mut`. The following free-functions are now replaced by methods (with the same names) only: @@ -653,63 +920,66 @@ only: `.eig`), `::hessenberg`, `::qr`, `::to_homogeneous`, `::to_rotation_matrix`, `::transpose`, `::shape`. - The following free-functions are now replaced by static methods only: - * `::householder_matrix` under the name `::new_householder_generic` - * `::identity` - * `::new_identity` under the name `::identity` - * `::from_homogeneous` - * `::repeat` under the name `::from_element` + +* `::householder_matrix` under the name `::new_householder_generic` +* `::identity` +* `::new_identity` under the name `::identity` +* `::from_homogeneous` +* `::repeat` under the name `::from_element` The following free-function are now replaced methods accessible through traits only: - * `::transform` -> methods `.transform_point` and `.transform_vector` of the `alga::linear::Transformation` trait. - * `::inverse_transform` -> methods `.inverse_transform_point` and - `.inverse_transform_vector` of the `alga::linear::ProjectiveTransformation` - trait. - * `::translate`, `::inverse_translate`, `::rotate`, `::inverse_rotate` -> - methods from the `alga::linear::Similarity` trait instead. Those have the - same names but end with `_point` or `_vector`, e.g., `.translate_point` and - `.translate_vector`. - * `::orthonormal_subspace_basis` -> method with the same name from - `alga::linear::FiniteDimInnerSpace`. - * `::canonical_basis_element` and `::canonical_basis` -> methods with the - same names from `alga::linear::FiniteDimVectorSpace`. - * `::rotation_between` -> method with the same name from the - `alga::linear::Rotation` trait. - * `::is_zero` -> method with the same name from `num::Zero`. - +* `::transform` -> methods `.transform_point` and `.transform_vector` of the `alga::linear::Transformation` trait. +* `::inverse_transform` -> methods `.inverse_transform_point` and + `.inverse_transform_vector` of the `alga::linear::ProjectiveTransformation` + trait. +* `::translate`, `::inverse_translate`, `::rotate`, `::inverse_rotate` -> + methods from the `alga::linear::Similarity` trait instead. Those have the + same names but end with `_point` or `_vector`, e.g., `.translate_point` and + `.translate_vector`. +* `::orthonormal_subspace_basis` -> method with the same name from + `alga::linear::FiniteDimInnerSpace`. +* `::canonical_basis_element` and `::canonical_basis` -> methods with the + same names from `alga::linear::FiniteDimVectorSpace`. +* `::rotation_between` -> method with the same name from the + `alga::linear::Rotation` trait. +* `::is_zero` -> method with the same name from `num::Zero`. ### Removed - * The free functions `::prepend_rotation`, `::append_rotation`, - `::append_rotation_wrt_center`, `::append_rotation_wrt_point`, - `::append_transformation`, and `::append_translation ` have been removed. - Instead, create the rotation or translation object explicitly and use - multiplication to compose it with anything else. - * The free function `::outer` has been removed. Use column-vector × - row-vector multiplication instead. +* The free functions `::prepend_rotation`, `::append_rotation`, + `::append_rotation_wrt_center`, `::append_rotation_wrt_point`, + `::append_transformation`, and `::append_translation ` have been removed. + Instead, create the rotation or translation object explicitly and use + multiplication to compose it with anything else. - * `::approx_eq`, `::approx_eq_eps` have been removed. Use the `relative_eq!` - macro from the [approx](https://crates.io/crates/approx) crate instead. +* The free function `::outer` has been removed. Use column-vector × + row-vector multiplication instead. - * `::covariance` has been removed. There is no replacement for now. - * `::mean` has been removed. There is no replacement for now. - * `::sample_sphere` has been removed. There is no replacement for now. - * `::cross_matrix` has been removed. There is no replacement for now. - * `::absolute_rotate` has been removed. There is no replacement for now. - * `::rotation`, `::transformation`, `::translation`, `::inverse_rotation`, - `::inverse_transformation`, `::inverse_translation` have been removed. Use - the appropriate methods/field of each transformation type, e.g., - `rotation.angle()` and `rotation.axis()`. +* `::approx_eq`, `::approx_eq_eps` have been removed. Use the `relative_eq!` + macro from the [approx](https://crates.io/crates/approx) crate instead. + +* `::covariance` has been removed. There is no replacement for now. +* `::mean` has been removed. There is no replacement for now. +* `::sample_sphere` has been removed. There is no replacement for now. +* `::cross_matrix` has been removed. There is no replacement for now. +* `::absolute_rotate` has been removed. There is no replacement for now. +* `::rotation`, `::transformation`, `::translation`, `::inverse_rotation`, + `::inverse_transformation`, `::inverse_translation` have been removed. Use + the appropriate methods/field of each transformation type, e.g., + `rotation.angle()` and `rotation.axis()`. ## [0.10.0] + ### Added + Binary operations are now allowed between references as well. For example `Vector3 + &Vector3` is now possible. ### Modified + Removed unused parameters to methods from the `ApproxEq` trait. Those were required before rust 1.0 to help type inference. They are not needed any more since it now allowed to write for a type `T` that implements `ApproxEq`: @@ -717,8 +987,10 @@ since it now allowed to write for a type `T` that implements `ApproxEq`: `ApproxEq::approx_epsilon(None::)`. ## [0.9.0] + ### Modified - * Renamed: + +* Renamed: - `::from_col_vector` -> `::from_column_vector` - `::from_col_iter` -> `::from_column_iter` - `.col_slice` -> `.column_slice` @@ -739,18 +1011,20 @@ Other similar trait changes are to be expected in the future, e.g., for the Methods marked `unsafe` for reasons unrelated to memory safety are no longer unsafe. Instead, their name end with `_unchecked`. In particular: + * `Rotation3::new_with_matrix` -> `Rotation3::from_matrix_unchecked` * `PerspectiveMatrix3::new_with_matrix` -> `PerspectiveMatrix3::from_matrix_unchecked` * `OrthographicMatrix3::new_with_matrix` -> `OrthographicMatrix3::from_matrix_unchecked` ### Added + - A `Unit` type that wraps normalized values. In particular, `UnitQuaternion` is now an alias for `Unit>`. - `.ln()`, `.exp()` and `.powf(..)` for quaternions and unit quaternions. - `::from_parts(...)` to build a quaternion from its scalar and vector parts. - The `Norm` trait now has a `try_normalize()` that returns `None` if the -norm is too small. + norm is too small. - The `BaseFloat` and `FloatVector` traits now inherit from `ApproxEq` as well. It is clear that performing computations with floats requires approximate equality. @@ -760,51 +1034,61 @@ crate for vectors, rotations and points. To enable them, activate the `abstract_algebra` feature. ## [0.8.0] + ### Modified - * Almost everything (types, methods, and traits) now use fulls names instead - of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are obvious. - Note however that: + +* Almost everything (types, methods, and traits) now use fulls names instead + of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are obvious. + Note however that: - `::sqnorm` becomes `::norm_squared`. - `::sqdist` becomes `::distance_squared`. - `::abs`, `::min`, etc. did not change as this is a common name for absolute values on, e.g., the libc. - Dynamically sized structures keep the `D` prefix, e.g., `DMat` becomes `DMatrix`. - * All files with abbreviated names have been renamed to their full version, - e.g., `vec.rs` becomes `vector.rs`. +* All files with abbreviated names have been renamed to their full version, + e.g., `vec.rs` becomes `vector.rs`. ## [0.7.0] -### Added - * Added implementation of assignment operators (+=, -=, etc.) for - everything. -### Modified - * Points and vectors are now linked to each other with associated types - (on the PointAsVector trait). +### Added + +* Added implementation of assignment operators (+=, -=, etc.) for + everything. + +### Modified + +* Points and vectors are now linked to each other with associated types + (on the PointAsVector trait). ## [0.6.0] + **Announcement:** a users forum has been created for `nalgebra`, `ncollide`, and `nphysics`. See you [there](https://users.nphysics.org)! ### Added - * Added a dependency to [generic-array](https://crates.io/crates/generic-array). Feature-gated: - requires `features="generic_sizes"`. - * Added statically sized vectors with user-defined sizes: `VectorN`. Feature-gated: requires - `features="generic_sizes"`. - * Added similarity transformations (an uniform scale followed by a rotation followed by a - translation): `Similarity2`, `Similarity3`. + +* Added a dependency to [generic-array](https://crates.io/crates/generic-array). Feature-gated: + requires `features="generic_sizes"`. +* Added statically sized vectors with user-defined sizes: `VectorN`. Feature-gated: requires + `features="generic_sizes"`. +* Added similarity transformations (an uniform scale followed by a rotation followed by a + translation): `Similarity2`, `Similarity3`. ### Removed - * Removed zero-sized elements `Vector0`, `Point0`. - * Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation too incomplete to be useful). + +* Removed zero-sized elements `Vector0`, `Point0`. +* Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation too incomplete to be + useful). ### Modified - * Vectors are now multipliable with isometries. This will result into a pure rotation (this is how - vectors differ from point semantically: they design directions, so they are not translatable). - * `{Isometry3, Rotation3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree - with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh` - variant to build a view matrix that - may be successfully used with `Persp` and `Ortho`. - * The old `{Isometry3, Rotation3}::look_at` implementations are now called `::new_observer_frame`. - * Rename every `fov` on `Persp` to `fovy`. - * Fixed the perspective and orthographic projection matrices. + +* Vectors are now multipliable with isometries. This will result into a pure rotation (this is how + vectors differ from point semantically: they design directions, so they are not translatable). +* `{Isometry3, Rotation3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree + with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh` + variant to build a view matrix that + may be successfully used with `Persp` and `Ortho`. +* The old `{Isometry3, Rotation3}::look_at` implementations are now called `::new_observer_frame`. +* Rename every `fov` on `Persp` to `fovy`. +* Fixed the perspective and orthographic projection matrices. diff --git a/Cargo.toml b/Cargo.toml index 8a3fea5c..2e31b1ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.30.1" +version = "0.32.3" authors = [ "Sébastien Crozet " ] description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." @@ -10,7 +10,7 @@ repository = "https://github.com/dimforge/nalgebra" readme = "README.md" categories = [ "science", "mathematics", "wasm", "no-std" ] keywords = [ "linear", "algebra", "matrix", "vector", "math" ] -license = "BSD-3-Clause" +license = "Apache-2.0" edition = "2018" exclude = ["/ci/*", "/.travis.yml", "/Makefile"] @@ -23,7 +23,7 @@ path = "src/lib.rs" [features] default = [ "std", "macros" ] -std = [ "matrixmultiply", "simba/std" ] +std = [ "matrixmultiply", "num-traits/std", "num-complex/std", "num-rational/std", "approx/std", "simba/std" ] sparse = [ ] debug = [ "approx/num-complex", "rand" ] alloc = [ ] @@ -32,12 +32,11 @@ compare = [ "matrixcompare-core" ] libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] -cuda = [ "cust_core", "simba/cuda" ] + # Conversion convert-mint = [ "mint" ] convert-bytemuck = [ "bytemuck" ] -convert-glam013 = [ "glam013" ] convert-glam014 = [ "glam014" ] convert-glam015 = [ "glam015" ] convert-glam016 = [ "glam016" ] @@ -45,6 +44,11 @@ convert-glam017 = [ "glam017" ] convert-glam018 = [ "glam018" ] convert-glam019 = [ "glam019" ] convert-glam020 = [ "glam020" ] +convert-glam021 = [ "glam021" ] +convert-glam022 = [ "glam022" ] +convert-glam023 = [ "glam023" ] +convert-glam024 = [ "glam024" ] +convert-glam025 = [ "glam025" ] # Serialization ## To use serde in a #[no-std] environment, enable the @@ -53,8 +57,8 @@ convert-glam020 = [ "glam020" ] ## `serde-serialize`. serde-serialize-no-std = [ "serde", "num-complex/serde" ] serde-serialize = [ "serde-serialize-no-std", "serde/std" ] -rkyv-serialize-no-std = [ "rkyv" ] -rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std" ] +rkyv-serialize-no-std = [ "rkyv/size_32" ] +rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std", "rkyv/validation" ] # Randomness ## To use rand in a #[no-std] environment, enable the @@ -66,21 +70,22 @@ rand = [ "rand-no-std", "rand-package/std", "rand-package/std_rng", "rand arbitrary = [ "quickcheck" ] proptest-support = [ "proptest" ] slow-tests = [] +rkyv-safe-deser = [ "rkyv-serialize", "rkyv/validation" ] [dependencies] -nalgebra-macros = { version = "0.1", path = "nalgebra-macros", optional = true } +nalgebra-macros = { version = "0.2.1", path = "nalgebra-macros", optional = true } typenum = "1.12" rand-package = { package = "rand", version = "0.8", optional = true, default-features = false } num-traits = { version = "0.2", default-features = false } num-complex = { version = "0.4", default-features = false } num-rational = { version = "0.4", default-features = false } approx = { version = "0.5", default-features = false } -simba = { version = "0.7", default-features = false } +simba = { version = "0.8", default-features = false } alga = { version = "0.9", default-features = false, optional = true } rand_distr = { version = "0.4", default-features = false, optional = true } matrixmultiply = { version = "0.3", optional = true } serde = { version = "1.0", default-features = false, features = [ "derive" ], optional = true } -rkyv = { version = "~0.6.4", default-features = false, features = ["const_generics"], optional = true } +rkyv = { version = "0.7.41", default-features = false, optional = true } mint = { version = "0.5", optional = true } quickcheck = { version = "1", optional = true } pest = { version = "2", optional = true } @@ -88,7 +93,6 @@ pest_derive = { version = "2", optional = true } bytemuck = { version = "1.5", optional = true } matrixcompare-core = { version = "0.1", optional = true } proptest = { version = "1", optional = true, default-features = false, features = ["std"] } -glam013 = { package = "glam", version = "0.13", optional = true } glam014 = { package = "glam", version = "0.14", optional = true } glam015 = { package = "glam", version = "0.15", optional = true } glam016 = { package = "glam", version = "0.16", optional = true } @@ -96,14 +100,19 @@ glam017 = { package = "glam", version = "0.17", optional = true } glam018 = { package = "glam", version = "0.18", optional = true } glam019 = { package = "glam", version = "0.19", optional = true } glam020 = { package = "glam", version = "0.20", optional = true } -cust_core = { version = "0.1", optional = true } - +glam021 = { package = "glam", version = "0.21", optional = true } +glam022 = { package = "glam", version = "0.22", optional = true } +glam023 = { package = "glam", version = "0.23", optional = true } +glam024 = { package = "glam", version = "0.24", optional = true } +glam025 = { package = "glam", version = "0.25", optional = true } +rayon = { version = "1.6", optional = true } [dev-dependencies] serde_json = "1.0" rand_xorshift = "0.3" rand_isaac = "0.3" -criterion = { version = "0.3", features = ["html_reports"] } +criterion = { version = "0.4", features = ["html_reports"] } +nalgebra = { path = ".", features = ["debug", "compare", "rand", "macros"]} # For matrix comparison macro matrixcompare = "0.3.0" @@ -131,6 +140,7 @@ required-features = ["rand"] lto = true [package.metadata.docs.rs] -# Enable certain features when building docs for docs.rs -features = [ "proptest-support", "compare", "macros", "rand" ] - +# Enable all the features when building the docs on docs.rs +all-features = true +# define the configuration attribute `docsrs` +rustdoc-args = ["--cfg", "docsrs"] diff --git a/README.md b/README.md index fa1e0904..857c84f2 100644 --- a/README.md +++ b/README.md @@ -29,19 +29,3 @@

----- - -## Acknowledgements -nalgebra is supported by our **platinum** sponsors: -

- - - -

- -And our gold sponsors: - -

- - - -

\ No newline at end of file diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs index 3c483c35..ec1102b7 100644 --- a/benches/core/matrix.rs +++ b/benches/core/matrix.rs @@ -53,7 +53,7 @@ fn mat_div_scalar(b: &mut criterion::Criterion) { b.bench_function("mat_div_scalar", move |bh| { bh.iter(|| { let mut aa = a.clone(); - let mut b = aa.slice_mut((0, 0), (1000, 1000)); + let mut b = aa.view_mut((0, 0), (1000, 1000)); b /= n }) }); @@ -142,7 +142,7 @@ fn iter(bench: &mut criterion::Criterion) { bench.bench_function("iter", move |bh| { bh.iter(|| { for value in a.iter() { - criterion::black_box(value); + std::hint::black_box(value); } }) }); @@ -154,7 +154,7 @@ fn iter_rev(bench: &mut criterion::Criterion) { bench.bench_function("iter_rev", move |bh| { bh.iter(|| { for value in a.iter().rev() { - criterion::black_box(value); + std::hint::black_box(value); } }) }); diff --git a/benches/lib.rs b/benches/lib.rs index 1f75ff7e..d0ade4b9 100644 --- a/benches/lib.rs +++ b/benches/lib.rs @@ -1,4 +1,3 @@ -#![feature(bench_black_box)] #![allow(unused_macros)] extern crate nalgebra as na; diff --git a/examples/cargo/Cargo.toml b/examples/cargo/Cargo.toml index 501ae23e..2e9d4f23 100644 --- a/examples/cargo/Cargo.toml +++ b/examples/cargo/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" authors = [ "You" ] [dependencies] -nalgebra = "0.30.0" +nalgebra = "0.32.0" [[bin]] name = "example" diff --git a/examples/dimensional_genericity.rs b/examples/dimensional_genericity.rs index 1fdd5a5f..e3c4fb5c 100644 --- a/examples/dimensional_genericity.rs +++ b/examples/dimensional_genericity.rs @@ -28,7 +28,7 @@ where } /// Reflects a 3D vector wrt. the 3D plane with normal `plane_normal`. -/// /!\ This is an exact replicate of `reflect_wrt_hyperplane2, but for 3D. +/// /!\ This is an exact replicate of `reflect_wrt_hyperplane2`, but for 3D. fn reflect_wrt_hyperplane3(plane_normal: &Unit>, vector: &Vector3) -> Vector3 where T: RealField, diff --git a/examples/reshaping.rs b/examples/reshaping.rs index b2178e79..78f7bcd5 100644 --- a/examples/reshaping.rs +++ b/examples/reshaping.rs @@ -2,7 +2,7 @@ extern crate nalgebra as na; -use na::{DMatrix, Dynamic, Matrix2x3, Matrix3x2, Const}; +use na::{DMatrix, Dyn, Matrix2x3, Matrix3x2, Const}; fn main() { // Matrices can be reshaped in-place without moving or copying values. @@ -46,9 +46,9 @@ fn main() { ], ); - let dm3 = dm1.reshape_generic(Dynamic::new(6), Dynamic::new(2)); + let dm3 = dm1.reshape_generic(Dyn(6), Dyn(2)); assert_eq!(dm3, dm2); // Invalid reshapings of dynamic matrices will panic at run-time. - //let dm4 = dm3.reshape_generic(Dynamic::new(6), Dynamic::new(6)); + //let dm4 = dm3.reshape_generic(Dyn(6), Dyn(6)); } diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index f8087581..6b06d9cc 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-glm" -version = "0.16.0" +version = "0.18.0" authors = ["sebcrozet "] description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." @@ -10,7 +10,7 @@ repository = "https://github.com/dimforge/nalgebra" readme = "../README.md" categories = [ "science", "mathematics", "wasm", "no standard library" ] keywords = [ "linear", "algebra", "matrix", "vector", "math" ] -license = "BSD-3-Clause" +license = "Apache-2.0" edition = "2018" [badges] @@ -21,12 +21,10 @@ default = [ "std" ] std = [ "nalgebra/std", "simba/std" ] arbitrary = [ "nalgebra/arbitrary" ] serde-serialize = [ "nalgebra/serde-serialize-no-std" ] -cuda = [ "nalgebra/cuda" ] # Conversion convert-mint = [ "nalgebra/mint" ] convert-bytemuck = [ "nalgebra/bytemuck" ] -convert-glam013 = [ "nalgebra/glam013" ] convert-glam014 = [ "nalgebra/glam014" ] convert-glam015 = [ "nalgebra/glam015" ] convert-glam016 = [ "nalgebra/glam016" ] @@ -36,5 +34,5 @@ convert-glam018 = [ "nalgebra/glam018" ] [dependencies] num-traits = { version = "0.2", default-features = false } approx = { version = "0.5", default-features = false } -simba = { version = "0.7", default-features = false } -nalgebra = { path = "..", version = "0.30", default-features = false } +simba = { version = "0.8", default-features = false } +nalgebra = { path = "..", version = "0.32", default-features = false } diff --git a/nalgebra-glm/LICENSE b/nalgebra-glm/LICENSE new file mode 120000 index 00000000..ea5b6064 --- /dev/null +++ b/nalgebra-glm/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/nalgebra-glm/src/aliases.rs b/nalgebra-glm/src/aliases.rs index ad16828f..e9f26f55 100644 --- a/nalgebra-glm/src/aliases.rs +++ b/nalgebra-glm/src/aliases.rs @@ -5,38 +5,38 @@ use na::{ /// A matrix with components of type `T`. It has `R` rows, and `C` columns. /// -/// In this library, vectors, represented as [`TVec`](type.TVec.html) and +/// In this library, vectors, represented as [`TVec`] and /// friends, are also matrices. Operations that operate on a matrix will /// also work on a vector. /// /// # See also: /// -/// * [`TMat2`](type.TMat2.html) -/// * [`TMat2x2`](type.TMat2x2.html) -/// * [`TMat2x3`](type.TMat2x3.html) -/// * [`TMat2x4`](type.TMat2x4.html) -/// * [`TMat3`](type.TMat3.html) -/// * [`TMat3x2`](type.TMat3x2.html) -/// * [`TMat3x3`](type.TMat3x3.html) -/// * [`TMat3x4`](type.TMat3x4.html) -/// * [`TMat4`](type.TMat4.html) -/// * [`TMat4x2`](type.TMat4x2.html) -/// * [`TMat4x3`](type.TMat4x3.html) -/// * [`TMat4x4`](type.TMat4x4.html) -/// * [`TVec`](type.TVec.html) +/// * [`TMat2`] +/// * [`TMat2x2`] +/// * [`TMat2x3`] +/// * [`TMat2x4`] +/// * [`TMat3`] +/// * [`TMat3x2`] +/// * [`TMat3x3`] +/// * [`TMat3x4`] +/// * [`TMat4`] +/// * [`TMat4x2`] +/// * [`TMat4x3`] +/// * [`TMat4x4`] +/// * [`TVec`] pub type TMat = SMatrix; /// A column vector with components of type `T`. It has `D` rows (and one column). /// /// In this library, vectors are represented as a single column matrix, so -/// operations on [`TMat`](type.TMat.html) are also valid on vectors. +/// operations on [`TMat`] are also valid on vectors. /// /// # See also: /// -/// * [`TMat`](type.TMat.html) -/// * [`TVec1`](type.TVec1.html) -/// * [`TVec2`](type.TVec2.html) -/// * [`TVec3`](type.TVec3.html) -/// * [`TVec4`](type.TVec4.html) +/// * [`TMat`] +/// * [`TVec1`] +/// * [`TVec2`] +/// * [`TVec3`] +/// * [`TVec4`] pub type TVec = SVector; /// A quaternion with components of type `T`. pub type Qua = Quaternion; @@ -47,28 +47,28 @@ pub type Qua = Quaternion; /// /// ## Constructors: /// -/// * [`make_vec1`](fn.make_vec1.html) -/// * [`vec1`](fn.vec1.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec4_to_vec1`](fn.vec4_to_vec1.html) +/// * [`make_vec1()`](crate::make_vec1) +/// * [`vec1()`](crate::vec1) +/// * [`vec2_to_vec1()`](crate::vec2_to_vec1) +/// * [`vec3_to_vec1()`](crate::vec3_to_vec1) +/// * [`vec4_to_vec1()`](crate::vec4_to_vec1) /// /// ## Related types: /// -/// * [`BVec1`](type.BVec1.html) -/// * [`DVec1`](type.DVec1.html) -/// * [`IVec1`](type.IVec1.html) -/// * [`I16Vec1`](type.I16Vec1.html) -/// * [`I32Vec1`](type.I32Vec1.html) -/// * [`I64Vec1`](type.I64Vec1.html) -/// * [`I8Vec1`](type.I8Vec1.html) -/// * [`TVec`](type.TVec.html) -/// * [`UVec1`](type.UVec1.html) -/// * [`U16Vec1`](type.U16Vec1.html) -/// * [`U32Vec1`](type.U32Vec1.html) -/// * [`U64Vec1`](type.U64Vec1.html) -/// * [`U8Vec1`](type.U8Vec1.html) -/// * [`Vec1`](type.Vec1.html) +/// * [`BVec1`] +/// * [`DVec1`] +/// * [`IVec1`] +/// * [`I16Vec1`] +/// * [`I32Vec1`] +/// * [`I64Vec1`] +/// * [`I8Vec1`] +/// * [`TVec`] +/// * [`UVec1`] +/// * [`U16Vec1`] +/// * [`U32Vec1`] +/// * [`U64Vec1`] +/// * [`U8Vec1`] +/// * [`Vec1`] pub type TVec1 = TVec; /// A 2D vector with components of type `T`. /// @@ -76,29 +76,28 @@ pub type TVec1 = TVec; /// /// ## Constructors: /// -/// * [`make_vec2`](fn.make_vec2.html) -/// * [`vec2`](fn.vec2.html) -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec4_to_vec2`](fn.vec4_to_vec2.html) +/// * [`make_vec2()`](crate::make_vec2) +/// * [`vec2()`](crate::vec2) +/// * [`vec1_to_vec2()`](crate::vec1_to_vec2) +/// * [`vec3_to_vec2()`](crate::vec3_to_vec2) +/// * [`vec4_to_vec2()`](crate::vec4_to_vec2) /// /// ## Related types: /// -/// * [`vec2`](fn.vec2.html) -/// * [`BVec2`](type.BVec2.html) -/// * [`DVec2`](type.DVec2.html) -/// * [`IVec2`](type.IVec2.html) -/// * [`I16Vec2`](type.I16Vec2.html) -/// * [`I32Vec2`](type.I32Vec2.html) -/// * [`I64Vec2`](type.I64Vec2.html) -/// * [`I8Vec2`](type.I8Vec2.html) -/// * [`TVec`](type.TVec.html) -/// * [`UVec2`](type.UVec2.html) -/// * [`U16Vec2`](type.U16Vec2.html) -/// * [`U32Vec2`](type.U32Vec2.html) -/// * [`U64Vec2`](type.U64Vec2.html) -/// * [`U8Vec2`](type.U8Vec2.html) -/// * [`Vec2`](type.Vec2.html) +/// * [`BVec2`] +/// * [`DVec2`] +/// * [`IVec2`] +/// * [`I16Vec2`] +/// * [`I32Vec2`] +/// * [`I64Vec2`] +/// * [`I8Vec2`] +/// * [`TVec`] +/// * [`UVec2`] +/// * [`U16Vec2`] +/// * [`U32Vec2`] +/// * [`U64Vec2`] +/// * [`U8Vec2`] +/// * [`Vec2`] pub type TVec2 = TVec; /// A 3D vector with components of type `T`. /// @@ -106,29 +105,28 @@ pub type TVec2 = TVec; /// /// ## Constructors: /// -/// * [`make_vec3`](fn.make_vec3.html) -/// * [`vec3`](fn.vec3.html) -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec4_to_vec3`](fn.vec4_to_vec3.html) +/// * [`make_vec3()`](crate::make_vec3) +/// * [`vec3()`](crate::vec3) +/// * [`vec1_to_vec3()`](crate::vec1_to_vec3) +/// * [`vec2_to_vec3()`](crate::vec2_to_vec3) +/// * [`vec4_to_vec3()`](crate::vec4_to_vec3) /// /// ## Related types: /// -/// * [`vec3`](fn.vec3.html) -/// * [`BVec3`](type.BVec3.html) -/// * [`DVec3`](type.DVec3.html) -/// * [`IVec3`](type.IVec3.html) -/// * [`I16Vec3`](type.I16Vec3.html) -/// * [`I32Vec3`](type.I32Vec3.html) -/// * [`I64Vec3`](type.I64Vec3.html) -/// * [`I8Vec3`](type.I8Vec3.html) -/// * [`TVec`](type.TVec.html) -/// * [`UVec3`](type.UVec3.html) -/// * [`U16Vec3`](type.U16Vec3.html) -/// * [`U32Vec3`](type.U32Vec3.html) -/// * [`U64Vec3`](type.U64Vec3.html) -/// * [`U8Vec3`](type.U8Vec3.html) -/// * [`Vec3`](type.Vec3.html) +/// * [`BVec3`] +/// * [`DVec3`] +/// * [`IVec3`] +/// * [`I16Vec3`] +/// * [`I32Vec3`] +/// * [`I64Vec3`] +/// * [`I8Vec3`] +/// * [`TVec`] +/// * [`UVec3`] +/// * [`U16Vec3`] +/// * [`U32Vec3`] +/// * [`U64Vec3`] +/// * [`U8Vec3`] +/// * [`Vec3`] pub type TVec3 = TVec; /// A 4D vector with components of type `T`. /// @@ -136,28 +134,27 @@ pub type TVec3 = TVec; /// /// ## Constructors: /// -/// * [`make_vec4`](fn.make_vec4.html) -/// * [`vec4`](fn.vec4.html) -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) +/// * [`make_vec4()`](crate::make_vec4) +/// * [`vec4()`](crate::vec4) +/// * [`vec1_to_vec4()`](crate::vec1_to_vec4) +/// * [`vec2_to_vec4()`](crate::vec2_to_vec4) +/// * [`vec3_to_vec4()`](crate::vec3_to_vec4) /// /// ## Related types: /// -/// * [`vec4`](fn.vec4.html) -/// * [`BVec4`](type.BVec4.html) -/// * [`DVec4`](type.DVec4.html) -/// * [`IVec4`](type.IVec4.html) -/// * [`I16Vec4`](type.I16Vec4.html) -/// * [`I32Vec4`](type.I32Vec4.html) -/// * [`I64Vec4`](type.I64Vec4.html) -/// * [`I8Vec4`](type.I8Vec4.html) -/// * [`UVec4`](type.UVec4.html) -/// * [`U16Vec4`](type.U16Vec4.html) -/// * [`U32Vec4`](type.U32Vec4.html) -/// * [`U64Vec4`](type.U64Vec4.html) -/// * [`U8Vec4`](type.U8Vec4.html) -/// * [`Vec4`](type.Vec4.html) +/// * [`BVec4`] +/// * [`DVec4`] +/// * [`IVec4`] +/// * [`I16Vec4`] +/// * [`I32Vec4`] +/// * [`I64Vec4`] +/// * [`I8Vec4`] +/// * [`UVec4`] +/// * [`U16Vec4`] +/// * [`U32Vec4`] +/// * [`U64Vec4`] +/// * [`U8Vec4`] +/// * [`Vec4`] pub type TVec4 = TVec; /// A 1D vector with boolean components. pub type BVec1 = TVec1; diff --git a/nalgebra-glm/src/common.rs b/nalgebra-glm/src/common.rs index 6ab20371..f41fafbb 100644 --- a/nalgebra-glm/src/common.rs +++ b/nalgebra-glm/src/common.rs @@ -1,5 +1,4 @@ use core::mem; -use na; use crate::aliases::{TMat, TVec}; use crate::traits::Number; @@ -20,7 +19,7 @@ use crate::RealNumber; /// /// # See also: /// -/// * [`sign`](fn.sign.html) +/// * [`sign()`] pub fn abs(x: &TMat) -> TMat { x.abs() } @@ -37,11 +36,11 @@ pub fn abs(x: &TMat) -> TMat /// /// # See also: /// -/// * [`ceil`](fn.ceil.html) -/// * [`floor`](fn.floor.html) -/// * [`fract`](fn.fract.html) -/// * [`round`](fn.round.html) -/// * [`trunc`](fn.trunc.html) +/// * [`ceil()`] +/// * [`floor()`] +/// * [`fract()`] +/// * [`round()`] +/// * [`trunc()`] pub fn ceil(x: &TVec) -> TVec { x.map(|x| x.ceil()) } @@ -65,8 +64,8 @@ pub fn ceil(x: &TVec) -> TVec { /// /// # See also: /// -/// * [`clamp`](fn.clamp.html) -/// * [`clamp_vec`](fn.clamp_vec.html) +/// * [`clamp()`] +/// * [`clamp_vec()`] pub fn clamp_scalar(x: T, min_val: T, max_val: T) -> T { na::clamp(x, min_val, max_val) } @@ -89,8 +88,8 @@ pub fn clamp_scalar(x: T, min_val: T, max_val: T) -> T { /// /// # See also: /// -/// * [`clamp_scalar`](fn.clamp_scalar.html) -/// * [`clamp_vec`](fn.clamp_vec.html) +/// * [`clamp_scalar()`] +/// * [`clamp_vec()`] pub fn clamp(x: &TVec, min_val: T, max_val: T) -> TVec { x.map(|x| na::clamp(x, min_val, max_val)) } @@ -120,8 +119,8 @@ pub fn clamp(x: &TVec, min_val: T, max_val: T) /// /// # See also: /// -/// * [`clamp_scalar`](fn.clamp_scalar.html) -/// * [`clamp`](fn.clamp.html) +/// * [`clamp_scalar()`] +/// * [`clamp()`] pub fn clamp_vec( x: &TVec, min_val: &TVec, @@ -136,13 +135,13 @@ pub fn clamp_vec( /// /// # See also: /// -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float()`] +/// * [`uint_bits_to_float_scalar()`] pub fn float_bits_to_int(v: f32) -> i32 { unsafe { mem::transmute(v) } } @@ -153,13 +152,13 @@ pub fn float_bits_to_int(v: f32) -> i32 { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_uint()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float()`] +/// * [`uint_bits_to_float_scalar()`] pub fn float_bits_to_int_vec(v: &TVec) -> TVec { v.map(float_bits_to_int) } @@ -170,13 +169,13 @@ pub fn float_bits_to_int_vec(v: &TVec) -> TVec { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float()`] +/// * [`uint_bits_to_float_scalar()`] pub fn float_bits_to_uint(v: f32) -> u32 { unsafe { mem::transmute(v) } } @@ -187,13 +186,13 @@ pub fn float_bits_to_uint(v: f32) -> u32 { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint()`] +/// * [`int_bits_to_float()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float()`] +/// * [`uint_bits_to_float_scalar()`] pub fn float_bits_to_uint_vec(v: &TVec) -> TVec { v.map(float_bits_to_uint) } @@ -210,10 +209,10 @@ pub fn float_bits_to_uint_vec(v: &TVec) -> TVec /// /// # See also: /// -/// * [`ceil`](fn.ceil.html) -/// * [`fract`](fn.fract.html) -/// * [`round`](fn.round.html) -/// * [`trunc`](fn.trunc.html) +/// * [`ceil()`] +/// * [`fract()`] +/// * [`round()`] +/// * [`trunc()`] pub fn floor(x: &TVec) -> TVec { x.map(|x| x.floor()) } @@ -236,10 +235,10 @@ pub fn floor(x: &TVec) -> TVec { /// /// # See also: /// -/// * [`ceil`](fn.ceil.html) -/// * [`floor`](fn.floor.html) -/// * [`round`](fn.round.html) -/// * [`trunc`](fn.trunc.html) +/// * [`ceil()`] +/// * [`floor()`] +/// * [`round()`] +/// * [`trunc()`] pub fn fract(x: &TVec) -> TVec { x.map(|x| x.fract()) } @@ -258,13 +257,13 @@ pub fn fract(x: &TVec) -> TVec { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float()`] +/// * [`uint_bits_to_float_scalar()`] pub fn int_bits_to_float(v: i32) -> f32 { f32::from_bits(v as u32) } @@ -275,13 +274,13 @@ pub fn int_bits_to_float(v: i32) -> f32 { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float()`] +/// * [`uint_bits_to_float()`] +/// * [`uint_bits_to_float_scalar()`] pub fn int_bits_to_float_vec(v: &TVec) -> TVec { v.map(int_bits_to_float) } @@ -315,8 +314,8 @@ pub fn int_bits_to_float_vec(v: &TVec) -> TVec { /// /// # See also: /// -/// * [`mix`](fn.mix.html) -/// * [`mix_vec`](fn.mix_vec.html) +/// * [`mix()`] +/// * [`mix_vec()`] pub fn mix_scalar(x: T, y: T, a: T) -> T { x * (T::one() - a) + y * a } @@ -336,8 +335,8 @@ pub fn mix_scalar(x: T, y: T, a: T) -> T { /// /// # See also: /// -/// * [`mix_scalar`](fn.mix_scalar.html) -/// * [`mix_vec`](fn.mix_vec.html) +/// * [`mix_scalar()`] +/// * [`mix_vec()`] pub fn mix(x: &TVec, y: &TVec, a: T) -> TVec { x * (T::one() - a) + y * a } @@ -359,14 +358,14 @@ pub fn mix(x: &TVec, y: &TVec, a: T) -> T /// /// # See also: /// -/// * [`mix_scalar`](fn.mix_scalar.html) -/// * [`mix`](fn.mix.html) +/// * [`mix_scalar()`] +/// * [`mix()`] pub fn mix_vec( x: &TVec, y: &TVec, a: &TVec, ) -> TVec { - x.component_mul(&(TVec::::repeat(T::one()) - a)) + y.component_mul(&a) + x.component_mul(&(TVec::::repeat(T::one()) - a)) + y.component_mul(a) } /// Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of the scalars x and y using the scalar value a. @@ -383,8 +382,8 @@ pub fn mix_vec( /// /// # See also: /// -/// * [`lerp`](fn.lerp.html) -/// * [`lerp_vec`](fn.lerp_vec.html) +/// * [`lerp()`] +/// * [`lerp_vec()`] pub fn lerp_scalar(x: T, y: T, a: T) -> T { mix_scalar(x, y, a) } @@ -405,8 +404,8 @@ pub fn lerp_scalar(x: T, y: T, a: T) -> T { /// /// # See also: /// -/// * [`lerp_scalar`](fn.lerp_scalar.html) -/// * [`lerp_vec`](fn.lerp_vec.html) +/// * [`lerp_scalar()`] +/// * [`lerp_vec()`] pub fn lerp(x: &TVec, y: &TVec, a: T) -> TVec { mix(x, y, a) } @@ -429,8 +428,8 @@ pub fn lerp(x: &TVec, y: &TVec, a: T) -> /// /// # See also: /// -/// * [`lerp_scalar`](fn.lerp_scalar.html) -/// * [`lerp`](fn.lerp.html) +/// * [`lerp_scalar()`] +/// * [`lerp()`] pub fn lerp_vec( x: &TVec, y: &TVec, @@ -445,7 +444,7 @@ pub fn lerp_vec( /// /// # See also: /// -/// * [`modf`](fn.modf.html) +/// * [`modf()`] pub fn modf_vec(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |x, y| x % y) } @@ -454,7 +453,7 @@ pub fn modf_vec(x: &TVec, y: &TVec) -> TV /// /// # See also: /// -/// * [`modf_vec`](fn.modf_vec.html) +/// * [`modf_vec()`] pub fn modf(x: T, i: T) -> T { x % i } @@ -473,10 +472,10 @@ pub fn modf(x: T, i: T) -> T { /// /// # See also: /// -/// * [`ceil`](fn.ceil.html) -/// * [`floor`](fn.floor.html) -/// * [`fract`](fn.fract.html) -/// * [`trunc`](fn.trunc.html) +/// * [`ceil()`] +/// * [`floor()`] +/// * [`fract()`] +/// * [`trunc()`] pub fn round(x: &TVec) -> TVec { x.map(|x| x.round()) } @@ -497,7 +496,7 @@ pub fn round(x: &TVec) -> TVec { /// /// # See also: /// -/// * [`abs`](fn.abs.html) +/// * [`abs()`] /// pub fn sign(x: &TVec) -> TVec { x.map(|x| if x.is_zero() { T::zero() } else { x.signum() }) @@ -545,10 +544,10 @@ pub fn step_vec(edge: &TVec, x: &TVec) -> /// /// # See also: /// -/// * [`ceil`](fn.ceil.html) -/// * [`floor`](fn.floor.html) -/// * [`fract`](fn.fract.html) -/// * [`round`](fn.round.html) +/// * [`ceil()`] +/// * [`floor()`] +/// * [`fract()`] +/// * [`round()`] pub fn trunc(x: &TVec) -> TVec { x.map(|x| x.trunc()) } @@ -559,13 +558,13 @@ pub fn trunc(x: &TVec) -> TVec { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float()`] pub fn uint_bits_to_float_scalar(v: u32) -> f32 { f32::from_bits(v) } @@ -576,13 +575,13 @@ pub fn uint_bits_to_float_scalar(v: u32) -> f32 { /// /// # See also: /// -/// * [`float_bits_to_int`](fn.float_bits_to_int.html) -/// * [`float_bits_to_int_vec`](fn.float_bits_to_int_vec.html) -/// * [`float_bits_to_uint`](fn.float_bits_to_uint.html) -/// * [`float_bits_to_uint_vec`](fn.float_bits_to_uint_vec.html) -/// * [`int_bits_to_float`](fn.int_bits_to_float.html) -/// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) -/// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) +/// * [`float_bits_to_int()`] +/// * [`float_bits_to_int_vec()`] +/// * [`float_bits_to_uint()`] +/// * [`float_bits_to_uint_vec()`] +/// * [`int_bits_to_float()`] +/// * [`int_bits_to_float_vec()`] +/// * [`uint_bits_to_float_scalar()`] pub fn uint_bits_to_float(v: &TVec) -> TVec { v.map(uint_bits_to_float_scalar) } diff --git a/nalgebra-glm/src/constructors.rs b/nalgebra-glm/src/constructors.rs index 8afdaa20..5a43f2b5 100644 --- a/nalgebra-glm/src/constructors.rs +++ b/nalgebra-glm/src/constructors.rs @@ -91,6 +91,7 @@ pub fn mat2x4(m11: T, m12: T, m13: T, m14: T, /// ); /// ``` #[rustfmt::skip] +#[allow(clippy::too_many_arguments)] pub fn mat3(m11: T, m12: T, m13: T, m21: T, m22: T, m23: T, m31: T, m32: T, m33: T) -> TMat3 { @@ -115,6 +116,7 @@ pub fn mat3x2(m11: T, m12: T, /// Create a new 3x3 matrix. #[rustfmt::skip] +#[allow(clippy::too_many_arguments)] pub fn mat3x3(m11: T, m12: T, m13: T, m21: T, m22: T, m23: T, m31: T, m32: T, m33: T) -> TMat3 { @@ -127,6 +129,7 @@ pub fn mat3x3(m11: T, m12: T, m13: T, /// Create a new 3x4 matrix. #[rustfmt::skip] +#[allow(clippy::too_many_arguments)] pub fn mat3x4(m11: T, m12: T, m13: T, m14: T, m21: T, m22: T, m23: T, m24: T, m31: T, m32: T, m33: T, m34: T) -> TMat3x4 { @@ -153,6 +156,7 @@ pub fn mat4x2(m11: T, m12: T, /// Create a new 4x3 matrix. #[rustfmt::skip] +#[allow(clippy::too_many_arguments)] pub fn mat4x3(m11: T, m12: T, m13: T, m21: T, m22: T, m23: T, m31: T, m32: T, m33: T, @@ -167,6 +171,7 @@ pub fn mat4x3(m11: T, m12: T, m13: T, /// Create a new 4x4 matrix. #[rustfmt::skip] +#[allow(clippy::too_many_arguments)] pub fn mat4x4(m11: T, m12: T, m13: T, m14: T, m21: T, m22: T, m23: T, m24: T, m31: T, m32: T, m33: T, m34: T, @@ -181,6 +186,7 @@ pub fn mat4x4(m11: T, m12: T, m13: T, m14: T, /// Create a new 4x4 matrix. #[rustfmt::skip] +#[allow(clippy::too_many_arguments)] pub fn mat4(m11: T, m12: T, m13: T, m14: T, m21: T, m22: T, m23: T, m24: T, m31: T, m32: T, m33: T, m34: T, diff --git a/nalgebra-glm/src/exponential.rs b/nalgebra-glm/src/exponential.rs index 6de9fc59..340389a2 100644 --- a/nalgebra-glm/src/exponential.rs +++ b/nalgebra-glm/src/exponential.rs @@ -5,7 +5,7 @@ use crate::RealNumber; /// /// # See also: /// -/// * [`exp2`](fn.exp2.html) +/// * [`exp2()`] pub fn exp(v: &TVec) -> TVec { v.map(|x| x.exp()) } @@ -14,7 +14,7 @@ pub fn exp(v: &TVec) -> TVec { /// /// # See also: /// -/// * [`exp`](fn.exp.html) +/// * [`exp()`] pub fn exp2(v: &TVec) -> TVec { v.map(|x| x.exp2()) } @@ -23,7 +23,7 @@ pub fn exp2(v: &TVec) -> TVec { /// /// # See also: /// -/// * [`sqrt`](fn.sqrt.html) +/// * [`sqrt()`] pub fn inversesqrt(v: &TVec) -> TVec { v.map(|x| T::one() / x.sqrt()) } @@ -32,7 +32,7 @@ pub fn inversesqrt(v: &TVec) -> TVec /// /// # See also: /// -/// * [`log2`](fn.log2.html) +/// * [`log2()`] pub fn log(v: &TVec) -> TVec { v.map(|x| x.ln()) } @@ -41,7 +41,7 @@ pub fn log(v: &TVec) -> TVec { /// /// # See also: /// -/// * [`log`](fn.log.html) +/// * [`log()`] pub fn log2(v: &TVec) -> TVec { v.map(|x| x.log2()) } @@ -55,10 +55,10 @@ pub fn pow(base: &TVec, exponent: &TVec(v: &TVec) -> TVec { v.map(|x| x.sqrt()) } diff --git a/nalgebra-glm/src/ext/matrix_projection.rs b/nalgebra-glm/src/ext/matrix_projection.rs index ad925a91..86a2cca9 100644 --- a/nalgebra-glm/src/ext/matrix_projection.rs +++ b/nalgebra-glm/src/ext/matrix_projection.rs @@ -1,5 +1,3 @@ -use na; - use crate::aliases::{TMat4, TVec2, TVec3, TVec4}; use crate::RealNumber; @@ -41,11 +39,11 @@ pub fn pick_matrix( /// /// # See also: /// -/// * [`project_no`](fn.project_no.html) -/// * [`project_zo`](fn.project_zo.html) -/// * [`unproject`](fn.unproject.html) -/// * [`unproject_no`](fn.unproject_no.html) -/// * [`unproject_zo`](fn.unproject_zo.html) +/// * [`project_no()`] +/// * [`project_zo()`] +/// * [`unproject()`] +/// * [`unproject_no()`] +/// * [`unproject_zo()`] pub fn project( obj: &TVec3, model: &TMat4, @@ -68,11 +66,11 @@ pub fn project( /// /// # See also: /// -/// * [`project`](fn.project.html) -/// * [`project_zo`](fn.project_zo.html) -/// * [`unproject`](fn.unproject.html) -/// * [`unproject_no`](fn.unproject_no.html) -/// * [`unproject_zo`](fn.unproject_zo.html) +/// * [`project()`] +/// * [`project_zo()`] +/// * [`unproject()`] +/// * [`unproject_no()`] +/// * [`unproject_zo()`] pub fn project_no( obj: &TVec3, model: &TMat4, @@ -96,11 +94,11 @@ pub fn project_no( /// /// # See also: /// -/// * [`project`](fn.project.html) -/// * [`project_no`](fn.project_no.html) -/// * [`unproject`](fn.unproject.html) -/// * [`unproject_no`](fn.unproject_no.html) -/// * [`unproject_zo`](fn.unproject_zo.html) +/// * [`project()`] +/// * [`project_no()`] +/// * [`unproject()`] +/// * [`unproject_no()`] +/// * [`unproject_zo()`] pub fn project_zo( obj: &TVec3, model: &TMat4, @@ -129,11 +127,11 @@ pub fn project_zo( /// /// # See also: /// -/// * [`project`](fn.project.html) -/// * [`project_no`](fn.project_no.html) -/// * [`project_zo`](fn.project_zo.html) -/// * [`unproject_no`](fn.unproject_no.html) -/// * [`unproject_zo`](fn.unproject_zo.html) +/// * [`project()`] +/// * [`project_no()`] +/// * [`project_zo()`] +/// * [`unproject_no()`] +/// * [`unproject_zo()`] pub fn unproject( win: &TVec3, model: &TMat4, @@ -156,11 +154,11 @@ pub fn unproject( /// /// # See also: /// -/// * [`project`](fn.project.html) -/// * [`project_no`](fn.project_no.html) -/// * [`project_zo`](fn.project_zo.html) -/// * [`unproject`](fn.unproject.html) -/// * [`unproject_zo`](fn.unproject_zo.html) +/// * [`project()`] +/// * [`project_no()`] +/// * [`project_zo()`] +/// * [`unproject()`] +/// * [`unproject_zo()`] pub fn unproject_no( win: &TVec3, model: &TMat4, @@ -193,11 +191,11 @@ pub fn unproject_no( /// /// # See also: /// -/// * [`project`](fn.project.html) -/// * [`project_no`](fn.project_no.html) -/// * [`project_zo`](fn.project_zo.html) -/// * [`unproject`](fn.unproject.html) -/// * [`unproject_no`](fn.unproject_no.html) +/// * [`project()`] +/// * [`project_no()`] +/// * [`project_zo()`] +/// * [`unproject()`] +/// * [`unproject_no()`] pub fn unproject_zo( win: &TVec3, model: &TMat4, diff --git a/nalgebra-glm/src/ext/matrix_transform.rs b/nalgebra-glm/src/ext/matrix_transform.rs index 793593b5..bc4f902e 100644 --- a/nalgebra-glm/src/ext/matrix_transform.rs +++ b/nalgebra-glm/src/ext/matrix_transform.rs @@ -18,8 +18,8 @@ pub fn identity() -> TMat { /// /// # See also: /// -/// * [`look_at_lh`](fn.look_at_lh.html) -/// * [`look_at_rh`](fn.look_at_rh.html) +/// * [`look_at_lh()`] +/// * [`look_at_rh()`] pub fn look_at(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { look_at_rh(eye, center, up) } @@ -34,8 +34,8 @@ pub fn look_at(eye: &TVec3, center: &TVec3, up: &TVec3) /// /// # See also: /// -/// * [`look_at`](fn.look_at.html) -/// * [`look_at_rh`](fn.look_at_rh.html) +/// * [`look_at()`] +/// * [`look_at_rh()`] pub fn look_at_lh(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { TMat::look_at_lh(&Point3::from(*eye), &Point3::from(*center), up) } @@ -50,8 +50,8 @@ pub fn look_at_lh(eye: &TVec3, center: &TVec3, up: &TVec3(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { TMat::look_at_rh(&Point3::from(*eye), &Point3::from(*center), up) } @@ -66,11 +66,11 @@ pub fn look_at_rh(eye: &TVec3, center: &TVec3, up: &TVec3(m: &TMat4, angle: T, axis: &TVec3) -> TMat4 { m * Rotation3::from_axis_angle(&Unit::new_normalize(*axis), angle).to_homogeneous() } @@ -84,11 +84,11 @@ pub fn rotate(m: &TMat4, angle: T, axis: &TVec3) -> TMat4(m: &TMat4, angle: T) -> TMat4 { rotate(m, angle, &TVec::x()) } @@ -102,11 +102,11 @@ pub fn rotate_x(m: &TMat4, angle: T) -> TMat4 { /// /// # See also: /// -/// * [`rotate`](fn.rotate.html) -/// * [`rotate_x`](fn.rotate_x.html) -/// * [`rotate_z`](fn.rotate_z.html) -/// * [`scale`](fn.scale.html) -/// * [`translate`](fn.translate.html) +/// * [`rotate()`] +/// * [`rotate_x()`] +/// * [`rotate_z()`] +/// * [`scale()`] +/// * [`translate()`] pub fn rotate_y(m: &TMat4, angle: T) -> TMat4 { rotate(m, angle, &TVec::y()) } @@ -120,11 +120,11 @@ pub fn rotate_y(m: &TMat4, angle: T) -> TMat4 { /// /// # See also: /// -/// * [`rotate`](fn.rotate.html) -/// * [`rotate_x`](fn.rotate_x.html) -/// * [`rotate_y`](fn.rotate_y.html) -/// * [`scale`](fn.scale.html) -/// * [`translate`](fn.translate.html) +/// * [`rotate()`] +/// * [`rotate_x()`] +/// * [`rotate_y()`] +/// * [`scale()`] +/// * [`translate()`] pub fn rotate_z(m: &TMat4, angle: T) -> TMat4 { rotate(m, angle, &TVec::z()) } @@ -138,11 +138,11 @@ pub fn rotate_z(m: &TMat4, angle: T) -> TMat4 { /// /// # See also: /// -/// * [`rotate`](fn.rotate.html) -/// * [`rotate_x`](fn.rotate_x.html) -/// * [`rotate_y`](fn.rotate_y.html) -/// * [`rotate_z`](fn.rotate_z.html) -/// * [`translate`](fn.translate.html) +/// * [`rotate()`] +/// * [`rotate_x()`] +/// * [`rotate_y()`] +/// * [`rotate_z()`] +/// * [`translate()`] pub fn scale(m: &TMat4, v: &TVec3) -> TMat4 { m.prepend_nonuniform_scaling(v) } @@ -156,11 +156,11 @@ pub fn scale(m: &TMat4, v: &TVec3) -> TMat4 { /// /// # See also: /// -/// * [`rotate`](fn.rotate.html) -/// * [`rotate_x`](fn.rotate_x.html) -/// * [`rotate_y`](fn.rotate_y.html) -/// * [`rotate_z`](fn.rotate_z.html) -/// * [`scale`](fn.scale.html) +/// * [`rotate()`] +/// * [`rotate_x()`] +/// * [`rotate_y()`] +/// * [`rotate_z()`] +/// * [`scale()`] pub fn translate(m: &TMat4, v: &TVec3) -> TMat4 { m.prepend_translation(v) } diff --git a/nalgebra-glm/src/ext/quaternion_common.rs b/nalgebra-glm/src/ext/quaternion_common.rs index 44b4a5bf..b1e10f74 100644 --- a/nalgebra-glm/src/ext/quaternion_common.rs +++ b/nalgebra-glm/src/ext/quaternion_common.rs @@ -1,4 +1,4 @@ -use na::{self, Unit}; +use na::Unit; use crate::aliases::Qua; use crate::RealNumber; diff --git a/nalgebra-glm/src/ext/scalar_common.rs b/nalgebra-glm/src/ext/scalar_common.rs index 696b97e4..c7d50da0 100644 --- a/nalgebra-glm/src/ext/scalar_common.rs +++ b/nalgebra-glm/src/ext/scalar_common.rs @@ -12,9 +12,9 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`max4_scalar`](fn.max4_scalar.html) -/// * [`min3_scalar`](fn.min3_scalar.html) -/// * [`min4_scalar`](fn.min4_scalar.html) +/// * [`max4_scalar()`] +/// * [`min3_scalar()`] +/// * [`min4_scalar()`] pub fn max2_scalar(a: T, b: T) -> T { if a >= b { a @@ -35,9 +35,9 @@ pub fn max2_scalar(a: T, b: T) -> T { /// /// # See also: /// -/// * [`max4_scalar`](fn.max4_scalar.html) -/// * [`min3_scalar`](fn.min3_scalar.html) -/// * [`min4_scalar`](fn.min4_scalar.html) +/// * [`max4_scalar()`] +/// * [`min3_scalar()`] +/// * [`min4_scalar()`] pub fn min2_scalar(a: T, b: T) -> T { if a <= b { a @@ -58,9 +58,9 @@ pub fn min2_scalar(a: T, b: T) -> T { /// /// # See also: /// -/// * [`max4_scalar`](fn.max4_scalar.html) -/// * [`min3_scalar`](fn.min3_scalar.html) -/// * [`min4_scalar`](fn.min4_scalar.html) +/// * [`max4_scalar()`] +/// * [`min3_scalar()`] +/// * [`min4_scalar()`] pub fn max3_scalar(a: T, b: T, c: T) -> T { max2_scalar(max2_scalar(a, b), c) } @@ -77,9 +77,9 @@ pub fn max3_scalar(a: T, b: T, c: T) -> T { /// /// # See also: /// -/// * [`max3_scalar`](fn.max3_scalar.html) -/// * [`min3_scalar`](fn.min3_scalar.html) -/// * [`min4_scalar`](fn.min4_scalar.html) +/// * [`max3_scalar()`] +/// * [`min3_scalar()`] +/// * [`min4_scalar()`] pub fn max4_scalar(a: T, b: T, c: T, d: T) -> T { max2_scalar(max2_scalar(a, b), max2_scalar(c, d)) } @@ -96,9 +96,9 @@ pub fn max4_scalar(a: T, b: T, c: T, d: T) -> T { /// /// # See also: /// -/// * [`max3_scalar`](fn.max3_scalar.html) -/// * [`max4_scalar`](fn.max4_scalar.html) -/// * [`min4_scalar`](fn.min4_scalar.html) +/// * [`max3_scalar()`] +/// * [`max4_scalar()`] +/// * [`min4_scalar()`] pub fn min3_scalar(a: T, b: T, c: T) -> T { min2_scalar(min2_scalar(a, b), c) } @@ -115,9 +115,9 @@ pub fn min3_scalar(a: T, b: T, c: T) -> T { /// /// # See also: /// -/// * [`max3_scalar`](fn.max3_scalar.html) -/// * [`max4_scalar`](fn.max4_scalar.html) -/// * [`min3_scalar`](fn.min3_scalar.html) +/// * [`max3_scalar()`] +/// * [`max4_scalar()`] +/// * [`min3_scalar()`] pub fn min4_scalar(a: T, b: T, c: T, d: T) -> T { min2_scalar(min2_scalar(a, b), min2_scalar(c, d)) } diff --git a/nalgebra-glm/src/ext/scalar_constants.rs b/nalgebra-glm/src/ext/scalar_constants.rs index 8ae418f2..5a3c8989 100644 --- a/nalgebra-glm/src/ext/scalar_constants.rs +++ b/nalgebra-glm/src/ext/scalar_constants.rs @@ -10,18 +10,18 @@ pub fn epsilon>() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`](crate::four_over_pi) +/// * [`half_pi()`](crate::half_pi) +/// * [`one_over_pi()`](crate::one_over_pi) +/// * [`one_over_two_pi()`](crate::one_over_two_pi) +/// * [`quarter_pi()`](crate::quarter_pi) +/// * [`root_half_pi()`](crate::root_half_pi) +/// * [`root_pi()`](crate::root_pi) +/// * [`root_two_pi()`](crate::root_two_pi) +/// * [`three_over_two_pi()`](crate::three_over_two_pi) +/// * [`two_over_pi()`](crate::two_over_pi) +/// * [`two_over_root_pi()`](crate::two_over_root_pi) +/// * [`two_pi()`](crate::two_pi) pub fn pi() -> T { T::pi() } diff --git a/nalgebra-glm/src/ext/vector_common.rs b/nalgebra-glm/src/ext/vector_common.rs index 4e1f7446..7cb591d1 100644 --- a/nalgebra-glm/src/ext/vector_common.rs +++ b/nalgebra-glm/src/ext/vector_common.rs @@ -5,15 +5,15 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max2`](fn.max2.html) -/// * [`max3`](fn.max3.html) -/// * [`max4`](fn.max4.html) -/// * [`min`](fn.min.html) -/// * [`min2`](fn.min2.html) -/// * [`min3`](fn.min3.html) -/// * [`min4`](fn.min4.html) +/// * [`comp_max()`](crate::comp_max) +/// * [`comp_min()`](crate::comp_min) +/// * [`max2()`] +/// * [`max3()`] +/// * [`max4()`] +/// * [`min()`] +/// * [`min2()`] +/// * [`min3()`] +/// * [`min4()`] pub fn max(a: &TVec, b: T) -> TVec { a.map(|a| crate::max2_scalar(a, b)) } @@ -22,15 +22,15 @@ pub fn max(a: &TVec, b: T) -> TVec { /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max`](fn.max.html) -/// * [`max3`](fn.max3.html) -/// * [`max4`](fn.max4.html) -/// * [`min`](fn.min.html) -/// * [`min2`](fn.min2.html) -/// * [`min3`](fn.min3.html) -/// * [`min4`](fn.min4.html) +/// * [`comp_max()`](crate::comp_max) +/// * [`comp_min()`](crate::comp_min) +/// * [`max()`] +/// * [`max3()`] +/// * [`max4()`] +/// * [`min()`] +/// * [`min2()`] +/// * [`min3()`] +/// * [`min4()`] pub fn max2(a: &TVec, b: &TVec) -> TVec { a.zip_map(b, |a, b| crate::max2_scalar(a, b)) } @@ -39,15 +39,15 @@ pub fn max2(a: &TVec, b: &TVec) -> TVec( a: &TVec, b: &TVec, @@ -60,15 +60,15 @@ pub fn max3( /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max`](fn.max.html) -/// * [`max2`](fn.max2.html) -/// * [`max3`](fn.max3.html) -/// * [`min`](fn.min.html) -/// * [`min2`](fn.min2.html) -/// * [`min3`](fn.min3.html) -/// * [`min4`](fn.min4.html) +/// * [`comp_max()`](crate::comp_max) +/// * [`comp_min()`](crate::comp_min) +/// * [`max()`] +/// * [`max2()`] +/// * [`max3()`] +/// * [`min()`] +/// * [`min2()`] +/// * [`min3()`] +/// * [`min4()`] pub fn max4( a: &TVec, b: &TVec, @@ -82,15 +82,15 @@ pub fn max4( /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max`](fn.max.html) -/// * [`max2`](fn.max2.html) -/// * [`max3`](fn.max3.html) -/// * [`max4`](fn.max4.html) -/// * [`min2`](fn.min2.html) -/// * [`min3`](fn.min3.html) -/// * [`min4`](fn.min4.html) +/// * [`comp_max()`](crate::comp_max) +/// * [`comp_min()`](crate::comp_min) +/// * [`max()`] +/// * [`max2()`] +/// * [`max3()`] +/// * [`max4()`] +/// * [`min2()`] +/// * [`min3()`] +/// * [`min4()`] pub fn min(x: &TVec, y: T) -> TVec { x.map(|x| crate::min2_scalar(x, y)) } @@ -99,15 +99,15 @@ pub fn min(x: &TVec, y: T) -> TVec { /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max`](fn.max.html) -/// * [`max2`](fn.max2.html) -/// * [`max3`](fn.max3.html) -/// * [`max4`](fn.max4.html) -/// * [`min`](fn.min.html) -/// * [`min3`](fn.min3.html) -/// * [`min4`](fn.min4.html) +/// * [`comp_max()`](crate::comp_max) +/// * [`comp_min()`](crate::comp_min) +/// * [`max()`] +/// * [`max2()`] +/// * [`max3()`] +/// * [`max4()`] +/// * [`min()`] +/// * [`min3()`] +/// * [`min4()`] pub fn min2(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |a, b| crate::min2_scalar(a, b)) } @@ -116,15 +116,15 @@ pub fn min2(x: &TVec, y: &TVec) -> TVec( a: &TVec, b: &TVec, @@ -137,15 +137,15 @@ pub fn min3( /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max`](fn.max.html) -/// * [`max2`](fn.max2.html) -/// * [`max3`](fn.max3.html) -/// * [`max4`](fn.max4.html) -/// * [`min`](fn.min.html) -/// * [`min2`](fn.min2.html) -/// * [`min3`](fn.min3.html) +/// * [`comp_max()`](crate::comp_max) +/// * [`comp_min()`](crate::comp_min) +/// * [`max()`] +/// * [`max2()`] +/// * [`max3()`] +/// * [`max4()`] +/// * [`min()`] +/// * [`min2()`] +/// * [`min3()`] pub fn min4( a: &TVec, b: &TVec, diff --git a/nalgebra-glm/src/ext/vector_relational.rs b/nalgebra-glm/src/ext/vector_relational.rs index baefe1bd..b3e38a02 100644 --- a/nalgebra-glm/src/ext/vector_relational.rs +++ b/nalgebra-glm/src/ext/vector_relational.rs @@ -5,9 +5,9 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`equal_eps_vec`](fn.equal_eps_vec.html) -/// * [`not_equal_eps`](fn.not_equal_eps.html) -/// * [`not_equal_eps_vec`](fn.not_equal_eps_vec.html) +/// * [`equal_eps_vec()`] +/// * [`not_equal_eps()`] +/// * [`not_equal_eps_vec()`] pub fn equal_eps( x: &TVec, y: &TVec, @@ -20,9 +20,9 @@ pub fn equal_eps( /// /// # See also: /// -/// * [`equal_eps`](fn.equal_eps.html) -/// * [`not_equal_eps`](fn.not_equal_eps.html) -/// * [`not_equal_eps_vec`](fn.not_equal_eps_vec.html) +/// * [`equal_eps()`] +/// * [`not_equal_eps()`] +/// * [`not_equal_eps_vec()`] pub fn equal_eps_vec( x: &TVec, y: &TVec, @@ -35,9 +35,9 @@ pub fn equal_eps_vec( /// /// # See also: /// -/// * [`equal_eps`](fn.equal_eps.html) -/// * [`equal_eps_vec`](fn.equal_eps_vec.html) -/// * [`not_equal_eps_vec`](fn.not_equal_eps_vec.html) +/// * [`equal_eps()`] +/// * [`equal_eps_vec()`] +/// * [`not_equal_eps_vec()`] pub fn not_equal_eps( x: &TVec, y: &TVec, @@ -50,9 +50,9 @@ pub fn not_equal_eps( /// /// # See also: /// -/// * [`equal_eps`](fn.equal_eps.html) -/// * [`equal_eps_vec`](fn.equal_eps_vec.html) -/// * [`not_equal_eps`](fn.not_equal_eps.html) +/// * [`equal_eps()`] +/// * [`equal_eps_vec()`] +/// * [`not_equal_eps()`] pub fn not_equal_eps_vec( x: &TVec, y: &TVec, diff --git a/nalgebra-glm/src/geometric.rs b/nalgebra-glm/src/geometric.rs index 95b78c96..2d4164c7 100644 --- a/nalgebra-glm/src/geometric.rs +++ b/nalgebra-glm/src/geometric.rs @@ -12,7 +12,7 @@ pub fn cross(x: &TVec3, y: &TVec3) -> TVec3 { /// /// # See also: /// -/// * [`distance2`](fn.distance2.html) +/// * [`distance2()`](crate::distance2) pub fn distance(p0: &TVec, p1: &TVec) -> T { (p1 - p0).norm() } @@ -37,13 +37,13 @@ pub fn faceforward( /// The magnitude of a vector. /// -/// A synonym for [`magnitude`](fn.magnitude.html). +/// A synonym for [`magnitude()`]. /// /// # See also: /// -/// * [`length2`](fn.length2.html) -/// * [`magnitude`](fn.magnitude.html) -/// * [`magnitude2`](fn.magnitude2.html) +/// * [`length2()`](crate::length2) +/// * [`magnitude()`] +/// * [`magnitude2()`](crate::magnitude2) pub fn length(x: &TVec) -> T { x.norm() } @@ -54,8 +54,8 @@ pub fn length(x: &TVec) -> T { /// /// # See also: /// -/// * [`length`](fn.length.html) -/// * [`magnitude2`](fn.magnitude2.html) +/// * [`length()`] +/// * [`magnitude2()`](crate::magnitude2) /// * [`nalgebra::norm`](../nalgebra/fn.norm.html) pub fn magnitude(x: &TVec) -> T { x.norm() diff --git a/nalgebra-glm/src/gtc/constants.rs b/nalgebra-glm/src/gtc/constants.rs index b08be4a9..da03a4b7 100644 --- a/nalgebra-glm/src/gtc/constants.rs +++ b/nalgebra-glm/src/gtc/constants.rs @@ -1,9 +1,8 @@ use crate::RealNumber; -use na; /// The Euler constant. /// -/// This is a shorthand alias for [`euler`](fn.euler.html). +/// This is a shorthand alias for [`euler()`]. pub fn e() -> T { T::e() } @@ -17,18 +16,18 @@ pub fn euler() -> T { /// /// # See also: /// -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn four_over_pi() -> T { na::convert::<_, T>(4.0) / T::pi() } @@ -42,18 +41,18 @@ pub fn golden_ratio() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn half_pi() -> T { T::frac_pi_2() } @@ -62,8 +61,8 @@ pub fn half_pi() -> T { /// /// # See also: /// -/// * [`ln_ten`](fn.ln_ten.html) -/// * [`ln_two`](fn.ln_two.html) +/// * [`ln_ten()`] +/// * [`ln_two()`] pub fn ln_ln_two() -> T { T::ln_2().ln() } @@ -72,8 +71,8 @@ pub fn ln_ln_two() -> T { /// /// # See also: /// -/// * [`ln_ln_two`](fn.ln_ln_two.html) -/// * [`ln_two`](fn.ln_two.html) +/// * [`ln_ln_two()`] +/// * [`ln_two()`] pub fn ln_ten() -> T { T::ln_10() } @@ -82,8 +81,8 @@ pub fn ln_ten() -> T { /// /// # See also: /// -/// * [`ln_ln_two`](fn.ln_ln_two.html) -/// * [`ln_ten`](fn.ln_ten.html) +/// * [`ln_ln_two()`] +/// * [`ln_ten()`] pub fn ln_two() -> T { T::ln_2() } @@ -95,18 +94,18 @@ pub use na::one; /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn one_over_pi() -> T { T::frac_1_pi() } @@ -120,18 +119,18 @@ pub fn one_over_root_two() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn one_over_two_pi() -> T { T::frac_1_pi() * na::convert(0.5) } @@ -140,18 +139,18 @@ pub fn one_over_two_pi() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn quarter_pi() -> T { T::frac_pi_4() } @@ -160,8 +159,8 @@ pub fn quarter_pi() -> T { /// /// # See also: /// -/// * [`root_three`](fn.root_three.html) -/// * [`root_two`](fn.root_two.html) +/// * [`root_three()`] +/// * [`root_two()`] pub fn root_five() -> T { na::convert::<_, T>(5.0).sqrt() } @@ -170,18 +169,18 @@ pub fn root_five() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn root_half_pi() -> T { (T::pi() / na::convert(2.0)).sqrt() } @@ -195,18 +194,18 @@ pub fn root_ln_four() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn root_pi() -> T { T::pi().sqrt() } @@ -215,8 +214,8 @@ pub fn root_pi() -> T { /// /// # See also: /// -/// * [`root_five`](fn.root_five.html) -/// * [`root_two`](fn.root_two.html) +/// * [`root_five()`] +/// * [`root_two()`] pub fn root_three() -> T { na::convert::<_, T>(3.0).sqrt() } @@ -225,8 +224,8 @@ pub fn root_three() -> T { /// /// # See also: /// -/// * [`root_five`](fn.root_five.html) -/// * [`root_three`](fn.root_three.html) +/// * [`root_five()`] +/// * [`root_three()`] pub fn root_two() -> T { // TODO: there should be a crate::sqrt_2() on the RealNumber trait. na::convert::<_, T>(2.0).sqrt() @@ -236,18 +235,18 @@ pub fn root_two() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn root_two_pi() -> T { T::two_pi().sqrt() } @@ -256,7 +255,7 @@ pub fn root_two_pi() -> T { /// /// # See also: /// -/// * [`two_thirds`](fn.two_thirds.html) +/// * [`two_thirds()`] pub fn third() -> T { na::convert(1.0 / 3.0) } @@ -265,18 +264,18 @@ pub fn third() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn three_over_two_pi() -> T { na::convert::<_, T>(3.0) / T::two_pi() } @@ -285,17 +284,18 @@ pub fn three_over_two_pi() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_root_pi()`] +/// * [`two_pi()`] pub fn two_over_pi() -> T { T::frac_2_pi() } @@ -304,18 +304,18 @@ pub fn two_over_pi() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_pi`](fn.two_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_pi()`] pub fn two_over_root_pi() -> T { T::frac_2_sqrt_pi() } @@ -324,18 +324,18 @@ pub fn two_over_root_pi() -> T { /// /// # See also: /// -/// * [`four_over_pi`](fn.four_over_pi.html) -/// * [`half_pi`](fn.half_pi.html) -/// * [`one_over_pi`](fn.one_over_pi.html) -/// * [`one_over_two_pi`](fn.one_over_two_pi.html) -/// * [`pi`](fn.pi.html) -/// * [`quarter_pi`](fn.quarter_pi.html) -/// * [`root_half_pi`](fn.root_half_pi.html) -/// * [`root_pi`](fn.root_pi.html) -/// * [`root_two_pi`](fn.root_two_pi.html) -/// * [`three_over_two_pi`](fn.three_over_two_pi.html) -/// * [`two_over_pi`](fn.two_over_pi.html) -/// * [`two_over_root_pi`](fn.two_over_root_pi.html) +/// * [`four_over_pi()`] +/// * [`half_pi()`] +/// * [`one_over_pi()`] +/// * [`one_over_two_pi()`] +/// * [`pi()`](crate::pi) +/// * [`quarter_pi()`] +/// * [`root_half_pi()`] +/// * [`root_pi()`] +/// * [`root_two_pi()`] +/// * [`three_over_two_pi()`] +/// * [`two_over_pi()`] +/// * [`two_over_root_pi()`] pub fn two_pi() -> T { T::two_pi() } @@ -344,7 +344,7 @@ pub fn two_pi() -> T { /// /// # See also: /// -/// * [`third`](fn.third.html) +/// * [`third()`] pub fn two_thirds() -> T { na::convert(2.0 / 3.0) } diff --git a/nalgebra-glm/src/gtc/epsilon.rs b/nalgebra-glm/src/gtc/epsilon.rs index fae29981..efe6ddd6 100644 --- a/nalgebra-glm/src/gtc/epsilon.rs +++ b/nalgebra-glm/src/gtc/epsilon.rs @@ -7,24 +7,24 @@ use na::DefaultAllocator; use crate::traits::{Alloc, Number, Dimension}; use crate::aliases::TVec; -/// Component-wise approximate equality beween two vectors. +/// Component-wise approximate equality between two vectors. pub fn epsilon_equal(x: &TVec, y: &TVec, epsilon: T) -> TVec where DefaultAllocator: Alloc { x.zip_map(y, |x, y| abs_diff_eq!(x, y, epsilon = epsilon)) } -/// Component-wise approximate equality beween two scalars. +/// Component-wise approximate equality between two scalars. pub fn epsilon_equal2>(x: T, y: T, epsilon: T) -> bool { abs_diff_eq!(x, y, epsilon = epsilon) } -/// Component-wise approximate non-equality beween two vectors. +/// Component-wise approximate non-equality between two vectors. pub fn epsilon_not_equal(x: &TVec, y: &TVec, epsilon: T) -> TVec where DefaultAllocator: Alloc { x.zip_map(y, |x, y| abs_diff_ne!(x, y, epsilon = epsilon)) } -/// Component-wise approximate non-equality beween two scalars. +/// Component-wise approximate non-equality between two scalars. pub fn epsilon_not_equal2>(x: T, y: T, epsilon: T) -> bool { abs_diff_ne!(x, y, epsilon = epsilon) } diff --git a/nalgebra-glm/src/gtc/matrix_access.rs b/nalgebra-glm/src/gtc/matrix_access.rs index 798c3b14..69695c8f 100644 --- a/nalgebra-glm/src/gtc/matrix_access.rs +++ b/nalgebra-glm/src/gtc/matrix_access.rs @@ -6,9 +6,9 @@ use crate::aliases::{TMat, TVec}; /// /// # See also: /// -/// * [`row`](fn.row.html) -/// * [`set_column`](fn.set_column.html) -/// * [`set_row`](fn.set_row.html) +/// * [`row()`] +/// * [`set_column()`] +/// * [`set_row()`] pub fn column( m: &TMat, index: usize, @@ -20,9 +20,9 @@ pub fn column( /// /// # See also: /// -/// * [`column`](fn.column.html) -/// * [`row`](fn.row.html) -/// * [`set_row`](fn.set_row.html) +/// * [`column()`] +/// * [`row()`] +/// * [`set_row()`] pub fn set_column( m: &TMat, index: usize, @@ -37,9 +37,9 @@ pub fn set_column( /// /// # See also: /// -/// * [`column`](fn.column.html) -/// * [`set_column`](fn.set_column.html) -/// * [`set_row`](fn.set_row.html) +/// * [`column()`] +/// * [`set_column()`] +/// * [`set_row()`] pub fn row( m: &TMat, index: usize, @@ -51,9 +51,9 @@ pub fn row( /// /// # See also: /// -/// * [`column`](fn.column.html) -/// * [`row`](fn.row.html) -/// * [`set_column`](fn.set_column.html) +/// * [`column()`] +/// * [`row()`] +/// * [`set_column()`] pub fn set_row( m: &TMat, index: usize, diff --git a/nalgebra-glm/src/gtc/type_ptr.rs b/nalgebra-glm/src/gtc/type_ptr.rs index cc8bb2a1..5f361de0 100644 --- a/nalgebra-glm/src/gtc/type_ptr.rs +++ b/nalgebra-glm/src/gtc/type_ptr.rs @@ -128,9 +128,9 @@ pub fn make_quat(ptr: &[T]) -> Qua { /// /// # See also: /// -/// * [`make_vec2`](fn.make_vec2.html) -/// * [`make_vec3`](fn.make_vec3.html) -/// * [`make_vec4`](fn.make_vec4.html) +/// * [`make_vec2()`] +/// * [`make_vec3()`] +/// * [`make_vec4()`] pub fn make_vec1(v: &TVec1) -> TVec1 { v.clone() } @@ -139,12 +139,11 @@ pub fn make_vec1(v: &TVec1) -> TVec1 { /// /// # See also: /// -/// * [`vec1_to_vec1`](fn.vec1_to_vec1.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec4_to_vec1`](fn.vec4_to_vec1.html) -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) +/// * [`vec3_to_vec1()`] +/// * [`vec4_to_vec1()`] +/// * [`vec1_to_vec2()`] +/// * [`vec1_to_vec3()`] +/// * [`vec1_to_vec4()`] pub fn vec2_to_vec1(v: &TVec2) -> TVec1 { TVec1::new(v.x.clone()) } @@ -153,12 +152,11 @@ pub fn vec2_to_vec1(v: &TVec2) -> TVec1 { /// /// # See also: /// -/// * [`vec1_to_vec1`](fn.vec1_to_vec1.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec4_to_vec1`](fn.vec4_to_vec1.html) -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) +/// * [`vec2_to_vec1()`] +/// * [`vec4_to_vec1()`] +/// * [`vec1_to_vec2()`] +/// * [`vec1_to_vec3()`] +/// * [`vec1_to_vec4()`] pub fn vec3_to_vec1(v: &TVec3) -> TVec1 { TVec1::new(v.x.clone()) } @@ -167,12 +165,11 @@ pub fn vec3_to_vec1(v: &TVec3) -> TVec1 { /// /// # See also: /// -/// * [`vec1_to_vec1`](fn.vec1_to_vec1.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) +/// * [`vec2_to_vec1()`] +/// * [`vec3_to_vec1()`] +/// * [`vec1_to_vec2()`] +/// * [`vec1_to_vec3()`] +/// * [`vec1_to_vec4()`] pub fn vec4_to_vec1(v: &TVec4) -> TVec1 { TVec1::new(v.x.clone()) } @@ -183,12 +180,12 @@ pub fn vec4_to_vec1(v: &TVec4) -> TVec1 { /// /// # See also: /// -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec4_to_vec2`](fn.vec4_to_vec2.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec2_to_vec2`](fn.vec2_to_vec2.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) +/// * [`vec3_to_vec2()`] +/// * [`vec4_to_vec2()`] +/// * [`vec2_to_vec1()`] +/// * [`vec2_to_vec2()`] +/// * [`vec2_to_vec3()`] +/// * [`vec2_to_vec4()`] pub fn vec1_to_vec2(v: &TVec1) -> TVec2 { TVec2::new(v.x.clone(), T::zero()) } @@ -197,13 +194,13 @@ pub fn vec1_to_vec2(v: &TVec1) -> TVec2 { /// /// # See also: /// -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec4_to_vec2`](fn.vec4_to_vec2.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec2_to_vec2`](fn.vec2_to_vec2.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) +/// * [`vec1_to_vec2()`] +/// * [`vec3_to_vec2()`] +/// * [`vec4_to_vec2()`] +/// * [`vec2_to_vec1()`] +/// * [`vec2_to_vec2()`] +/// * [`vec2_to_vec3()`] +/// * [`vec2_to_vec4()`] pub fn vec2_to_vec2(v: &TVec2) -> TVec2 { v.clone() } @@ -212,12 +209,12 @@ pub fn vec2_to_vec2(v: &TVec2) -> TVec2 { /// /// # See also: /// -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec4_to_vec2`](fn.vec4_to_vec2.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec2_to_vec2`](fn.vec2_to_vec2.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) +/// * [`vec1_to_vec2()`] +/// * [`vec4_to_vec2()`] +/// * [`vec2_to_vec1()`] +/// * [`vec2_to_vec2()`] +/// * [`vec2_to_vec3()`] +/// * [`vec2_to_vec4()`] pub fn vec3_to_vec2(v: &TVec3) -> TVec2 { TVec2::new(v.x.clone(), v.y.clone()) } @@ -226,12 +223,12 @@ pub fn vec3_to_vec2(v: &TVec3) -> TVec2 { /// /// # See also: /// -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec3_to_vec2`](fn.vec4_to_vec2.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec2_to_vec2`](fn.vec2_to_vec2.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) +/// * [`vec1_to_vec2()`] +/// * [`vec3_to_vec2()`] +/// * [`vec2_to_vec1()`] +/// * [`vec2_to_vec2()`] +/// * [`vec2_to_vec3()`] +/// * [`vec2_to_vec4()`] pub fn vec4_to_vec2(v: &TVec4) -> TVec2 { TVec2::new(v.x.clone(), v.y.clone()) } @@ -240,9 +237,9 @@ pub fn vec4_to_vec2(v: &TVec4) -> TVec2 { /// /// # See also: /// -/// * [`make_vec1`](fn.make_vec1.html) -/// * [`make_vec3`](fn.make_vec3.html) -/// * [`make_vec4`](fn.make_vec4.html) +/// * [`make_vec1()`] +/// * [`make_vec3()`] +/// * [`make_vec4()`] pub fn make_vec2(ptr: &[T]) -> TVec2 { TVec2::from_column_slice(ptr) } @@ -253,11 +250,11 @@ pub fn make_vec2(ptr: &[T]) -> TVec2 { /// /// # See also: /// -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec3_to_vec3`](fn.vec3_to_vec3.html) -/// * [`vec4_to_vec3`](fn.vec4_to_vec3.html) -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) +/// * [`vec2_to_vec3()`] +/// * [`vec3_to_vec3()`] +/// * [`vec4_to_vec3()`] +/// * [`vec1_to_vec2()`] +/// * [`vec1_to_vec4()`] pub fn vec1_to_vec3(v: &TVec1) -> TVec3 { TVec3::new(v.x.clone(), T::zero(), T::zero()) } @@ -268,12 +265,12 @@ pub fn vec1_to_vec3(v: &TVec1) -> TVec3 { /// /// # See also: /// -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec3_to_vec3`](fn.vec3_to_vec3.html) -/// * [`vec4_to_vec3`](fn.vec4_to_vec3.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) +/// * [`vec1_to_vec3()`] +/// * [`vec3_to_vec3()`] +/// * [`vec4_to_vec3()`] +/// * [`vec3_to_vec1()`] +/// * [`vec3_to_vec2()`] +/// * [`vec3_to_vec4()`] pub fn vec2_to_vec3(v: &TVec2) -> TVec3 { TVec3::new(v.x.clone(), v.y.clone(), T::zero()) } @@ -282,12 +279,12 @@ pub fn vec2_to_vec3(v: &TVec2) -> TVec3 { /// /// # See also: /// -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec4_to_vec3`](fn.vec4_to_vec3.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) +/// * [`vec1_to_vec3()`] +/// * [`vec2_to_vec3()`] +/// * [`vec4_to_vec3()`] +/// * [`vec3_to_vec1()`] +/// * [`vec3_to_vec2()`] +/// * [`vec3_to_vec4()`] pub fn vec3_to_vec3(v: &TVec3) -> TVec3 { v.clone() } @@ -296,12 +293,12 @@ pub fn vec3_to_vec3(v: &TVec3) -> TVec3 { /// /// # See also: /// -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) -/// * [`vec3_to_vec3`](fn.vec3_to_vec3.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) +/// * [`vec1_to_vec3()`] +/// * [`vec2_to_vec3()`] +/// * [`vec3_to_vec3()`] +/// * [`vec3_to_vec1()`] +/// * [`vec3_to_vec2()`] +/// * [`vec3_to_vec4()`] pub fn vec4_to_vec3(v: &TVec4) -> TVec3 { TVec3::new(v.x.clone(), v.y.clone(), v.z.clone()) } @@ -310,9 +307,9 @@ pub fn vec4_to_vec3(v: &TVec4) -> TVec3 { /// /// # See also: /// -/// * [`make_vec1`](fn.make_vec1.html) -/// * [`make_vec2`](fn.make_vec2.html) -/// * [`make_vec4`](fn.make_vec4.html) +/// * [`make_vec1()`] +/// * [`make_vec2()`] +/// * [`make_vec4()`] pub fn make_vec3(ptr: &[T]) -> TVec3 { TVec3::from_column_slice(ptr) } @@ -323,12 +320,12 @@ pub fn make_vec3(ptr: &[T]) -> TVec3 { /// /// # See also: /// -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) -/// * [`vec4_to_vec4`](fn.vec4_to_vec4.html) -/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html) -/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html) -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) +/// * [`vec2_to_vec4()`] +/// * [`vec3_to_vec4()`] +/// * [`vec4_to_vec4()`] +/// * [`vec1_to_vec2()`] +/// * [`vec1_to_vec3()`] +/// * [`vec1_to_vec4()`] pub fn vec1_to_vec4(v: &TVec1) -> TVec4 { TVec4::new(v.x, T::zero(), T::zero(), T::zero()) } @@ -339,12 +336,12 @@ pub fn vec1_to_vec4(v: &TVec1) -> TVec4 { /// /// # See also: /// -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) -/// * [`vec4_to_vec4`](fn.vec4_to_vec4.html) -/// * [`vec2_to_vec1`](fn.vec2_to_vec1.html) -/// * [`vec2_to_vec2`](fn.vec2_to_vec2.html) -/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html) +/// * [`vec1_to_vec4()`] +/// * [`vec3_to_vec4()`] +/// * [`vec4_to_vec4()`] +/// * [`vec2_to_vec1()`] +/// * [`vec2_to_vec2()`] +/// * [`vec2_to_vec3()`] pub fn vec2_to_vec4(v: &TVec2) -> TVec4 { TVec4::new(v.x, v.y, T::zero(), T::zero()) } @@ -355,12 +352,12 @@ pub fn vec2_to_vec4(v: &TVec2) -> TVec4 { /// /// # See also: /// -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) -/// * [`vec4_to_vec4`](fn.vec4_to_vec4.html) -/// * [`vec3_to_vec1`](fn.vec3_to_vec1.html) -/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) -/// * [`vec3_to_vec3`](fn.vec3_to_vec3.html) +/// * [`vec1_to_vec4()`] +/// * [`vec2_to_vec4()`] +/// * [`vec4_to_vec4()`] +/// * [`vec3_to_vec1()`] +/// * [`vec3_to_vec2()`] +/// * [`vec3_to_vec3()`] pub fn vec3_to_vec4(v: &TVec3) -> TVec4 { TVec4::new(v.x, v.y, v.z, T::zero()) } @@ -369,12 +366,12 @@ pub fn vec3_to_vec4(v: &TVec3) -> TVec4 { /// /// # See also: /// -/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html) -/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html) -/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) -/// * [`vec4_to_vec1`](fn.vec4_to_vec1.html) -/// * [`vec4_to_vec2`](fn.vec4_to_vec2.html) -/// * [`vec4_to_vec3`](fn.vec4_to_vec3.html) +/// * [`vec1_to_vec4()`] +/// * [`vec2_to_vec4()`] +/// * [`vec3_to_vec4()`] +/// * [`vec4_to_vec1()`] +/// * [`vec4_to_vec2()`] +/// * [`vec4_to_vec3()`] pub fn vec4_to_vec4(v: &TVec4) -> TVec4 { v.clone() } @@ -383,9 +380,9 @@ pub fn vec4_to_vec4(v: &TVec4) -> TVec4 { /// /// # See also: /// -/// * [`make_vec1`](fn.make_vec1.html) -/// * [`make_vec2`](fn.make_vec2.html) -/// * [`make_vec3`](fn.make_vec3.html) +/// * [`make_vec1()`] +/// * [`make_vec2()`] +/// * [`make_vec3()`] pub fn make_vec4(ptr: &[T]) -> TVec4 { TVec4::from_column_slice(ptr) } diff --git a/nalgebra-glm/src/gtx/component_wise.rs b/nalgebra-glm/src/gtx/component_wise.rs index 85d0dd71..7d8ac93f 100644 --- a/nalgebra-glm/src/gtx/component_wise.rs +++ b/nalgebra-glm/src/gtx/component_wise.rs @@ -16,9 +16,9 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`comp_mul`](fn.comp_mul.html) +/// * [`comp_max()`] +/// * [`comp_min()`] +/// * [`comp_mul()`] pub fn comp_add(m: &TMat) -> T { m.iter().fold(T::zero(), |x, y| x + *y) } @@ -38,13 +38,13 @@ pub fn comp_add(m: &TMat) -> /// /// # See also: /// -/// * [`comp_add`](fn.comp_add.html) -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) -/// * [`max`](fn.max.html) -/// * [`max2`](fn.max2.html) -/// * [`max3`](fn.max3.html) -/// * [`max4`](fn.max4.html) +/// * [`comp_add()`] +/// * [`comp_max()`] +/// * [`comp_min()`] +/// * [`max()`](crate::max) +/// * [`max2()`](crate::max2) +/// * [`max3()`](crate::max3) +/// * [`max4()`](crate::max4) pub fn comp_max(m: &TMat) -> T { m.iter() .fold(T::min_value(), |x, y| crate::max2_scalar(x, *y)) @@ -65,13 +65,13 @@ pub fn comp_max(m: &TMat) -> /// /// # See also: /// -/// * [`comp_add`](fn.comp_add.html) -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_mul`](fn.comp_mul.html) -/// * [`min`](fn.min.html) -/// * [`min2`](fn.min2.html) -/// * [`min3`](fn.min3.html) -/// * [`min4`](fn.min4.html) +/// * [`comp_add()`] +/// * [`comp_max()`] +/// * [`comp_mul()`] +/// * [`min()`](crate::min) +/// * [`min2()`](crate::min2) +/// * [`min3()`](crate::min3) +/// * [`min4()`](crate::min4) pub fn comp_min(m: &TMat) -> T { m.iter() .fold(T::max_value(), |x, y| crate::min2_scalar(x, *y)) @@ -92,9 +92,9 @@ pub fn comp_min(m: &TMat) -> /// /// # See also: /// -/// * [`comp_add`](fn.comp_add.html) -/// * [`comp_max`](fn.comp_max.html) -/// * [`comp_min`](fn.comp_min.html) +/// * [`comp_add()`] +/// * [`comp_max()`] +/// * [`comp_min()`] pub fn comp_mul(m: &TMat) -> T { m.iter().fold(T::one(), |x, y| x * *y) } diff --git a/nalgebra-glm/src/gtx/handed_coordinate_space.rs b/nalgebra-glm/src/gtx/handed_coordinate_space.rs index 1063db5e..2f1469a3 100644 --- a/nalgebra-glm/src/gtx/handed_coordinate_space.rs +++ b/nalgebra-glm/src/gtx/handed_coordinate_space.rs @@ -5,7 +5,7 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`right_handed`](fn.right_handed.html) +/// * [`right_handed()`] pub fn left_handed(a: &TVec3, b: &TVec3, c: &TVec3) -> bool { a.cross(b).dot(c) < T::zero() } @@ -14,7 +14,7 @@ pub fn left_handed(a: &TVec3, b: &TVec3, c: &TVec3) -> bool /// /// # See also: /// -/// * [`left_handed`](fn.left_handed.html) +/// * [`left_handed()`] pub fn right_handed(a: &TVec3, b: &TVec3, c: &TVec3) -> bool { a.cross(b).dot(c) > T::zero() } diff --git a/nalgebra-glm/src/gtx/matrix_cross_product.rs b/nalgebra-glm/src/gtx/matrix_cross_product.rs index 383bbdc0..fd3ed32e 100644 --- a/nalgebra-glm/src/gtx/matrix_cross_product.rs +++ b/nalgebra-glm/src/gtx/matrix_cross_product.rs @@ -5,7 +5,7 @@ use crate::RealNumber; /// /// # See also: /// -/// * [`matrix_cross`](fn.matrix_cross.html) +/// * [`matrix_cross()`] pub fn matrix_cross3(x: &TVec3) -> TMat3 { x.cross_matrix() } @@ -14,7 +14,7 @@ pub fn matrix_cross3(x: &TVec3) -> TMat3 { /// /// # See also: /// -/// * [`matrix_cross3`](fn.matrix_cross3.html) +/// * [`matrix_cross3()`] pub fn matrix_cross(x: &TVec3) -> TMat4 { crate::mat3_to_mat4(&x.cross_matrix()) } diff --git a/nalgebra-glm/src/gtx/matrix_operation.rs b/nalgebra-glm/src/gtx/matrix_operation.rs index a46a9a5c..f3fa7daa 100644 --- a/nalgebra-glm/src/gtx/matrix_operation.rs +++ b/nalgebra-glm/src/gtx/matrix_operation.rs @@ -7,14 +7,14 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal2x2(v: &TVec2) -> TMat2 { TMat2::from_diagonal(v) } @@ -23,14 +23,14 @@ pub fn diagonal2x2(v: &TVec2) -> TMat2 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal2x3(v: &TVec2) -> TMat2x3 { TMat2x3::from_partial_diagonal(v.as_slice()) } @@ -39,14 +39,14 @@ pub fn diagonal2x3(v: &TVec2) -> TMat2x3 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal2x4(v: &TVec2) -> TMat2x4 { TMat2x4::from_partial_diagonal(v.as_slice()) } @@ -55,14 +55,14 @@ pub fn diagonal2x4(v: &TVec2) -> TMat2x4 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal3x2(v: &TVec2) -> TMat3x2 { TMat3x2::from_partial_diagonal(v.as_slice()) } @@ -71,14 +71,14 @@ pub fn diagonal3x2(v: &TVec2) -> TMat3x2 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal3x3(v: &TVec3) -> TMat3 { TMat3::from_diagonal(v) } @@ -87,14 +87,14 @@ pub fn diagonal3x3(v: &TVec3) -> TMat3 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal3x4(v: &TVec3) -> TMat3x4 { TMat3x4::from_partial_diagonal(v.as_slice()) } @@ -103,14 +103,14 @@ pub fn diagonal3x4(v: &TVec3) -> TMat3x4 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x3()`] +/// * [`diagonal4x4()`] pub fn diagonal4x2(v: &TVec2) -> TMat4x2 { TMat4x2::from_partial_diagonal(v.as_slice()) } @@ -119,14 +119,14 @@ pub fn diagonal4x2(v: &TVec2) -> TMat4x2 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x4`](fn.diagonal4x4.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x4()`] pub fn diagonal4x3(v: &TVec3) -> TMat4x3 { TMat4x3::from_partial_diagonal(v.as_slice()) } @@ -135,14 +135,14 @@ pub fn diagonal4x3(v: &TVec3) -> TMat4x3 { /// /// # See also: /// -/// * [`diagonal2x2`](fn.diagonal2x2.html) -/// * [`diagonal2x3`](fn.diagonal2x3.html) -/// * [`diagonal2x4`](fn.diagonal2x4.html) -/// * [`diagonal3x2`](fn.diagonal3x2.html) -/// * [`diagonal3x3`](fn.diagonal3x3.html) -/// * [`diagonal3x4`](fn.diagonal3x4.html) -/// * [`diagonal4x2`](fn.diagonal4x2.html) -/// * [`diagonal4x3`](fn.diagonal4x3.html) +/// * [`diagonal2x2()`] +/// * [`diagonal2x3()`] +/// * [`diagonal2x4()`] +/// * [`diagonal3x2()`] +/// * [`diagonal3x3()`] +/// * [`diagonal3x4()`] +/// * [`diagonal4x2()`] +/// * [`diagonal4x3()`] pub fn diagonal4x4(v: &TVec4) -> TMat4 { TMat4::from_diagonal(v) } diff --git a/nalgebra-glm/src/gtx/norm.rs b/nalgebra-glm/src/gtx/norm.rs index cf7f541a..e21e61fb 100644 --- a/nalgebra-glm/src/gtx/norm.rs +++ b/nalgebra-glm/src/gtx/norm.rs @@ -5,7 +5,7 @@ use crate::RealNumber; /// /// # See also: /// -/// * [`distance`](fn.distance.html) +/// * [`distance()`](crate::distance) pub fn distance2(p0: &TVec, p1: &TVec) -> T { (p1 - p0).norm_squared() } @@ -14,9 +14,9 @@ pub fn distance2(p0: &TVec, p1: &TVec /// /// # See also: /// -/// * [`l1_norm`](fn.l1_norm.html) -/// * [`l2_distance`](fn.l2_distance.html) -/// * [`l2_norm`](fn.l2_norm.html) +/// * [`l1_norm()`] +/// * [`l2_distance()`] +/// * [`l2_norm()`] pub fn l1_distance(x: &TVec, y: &TVec) -> T { l1_norm(&(y - x)) } @@ -28,27 +28,27 @@ pub fn l1_distance(x: &TVec, y: &TVec /// /// # See also: /// -/// * [`l1_distance`](fn.l1_distance.html) -/// * [`l2_distance`](fn.l2_distance.html) -/// * [`l2_norm`](fn.l2_norm.html) +/// * [`l1_distance()`] +/// * [`l2_distance()`] +/// * [`l2_norm()`] pub fn l1_norm(v: &TVec) -> T { crate::comp_add(&v.abs()) } /// The l2-norm of `x - y`. /// -/// This is the same value as returned by [`length2`](fn.length2.html) and -/// [`magnitude2`](fn.magnitude2.html). +/// This is the same value as returned by [`length2()`] and +/// [`magnitude2()`]. /// /// # See also: /// -/// * [`l1_distance`](fn.l1_distance.html) -/// * [`l1_norm`](fn.l1_norm.html) -/// * [`l2_norm`](fn.l2_norm.html) -/// * [`length`](fn.length.html) -/// * [`length2`](fn.length2.html) -/// * [`magnitude`](fn.magnitude.html) -/// * [`magnitude2`](fn.magnitude2.html) +/// * [`l1_distance()`] +/// * [`l1_norm()`] +/// * [`l2_norm()`] +/// * [`length()`](crate::length) +/// * [`length2()`] +/// * [`magnitude()`](crate::magnitude) +/// * [`magnitude2()`] pub fn l2_distance(x: &TVec, y: &TVec) -> T { l2_norm(&(y - x)) } @@ -57,33 +57,33 @@ pub fn l2_distance(x: &TVec, y: &TVec /// /// This is also known as the Euclidean norm. /// -/// This is the same value as returned by [`length`](fn.length.html) and -/// [`magnitude`](fn.magnitude.html). +/// This is the same value as returned by [`length()`](crate::length) and +/// [`magnitude()`](crate::magnitude). /// /// # See also: /// -/// * [`l1_distance`](fn.l1_distance.html) -/// * [`l1_norm`](fn.l1_norm.html) -/// * [`l2_distance`](fn.l2_distance.html) -/// * [`length`](fn.length.html) -/// * [`length2`](fn.length2.html) -/// * [`magnitude`](fn.magnitude.html) -/// * [`magnitude2`](fn.magnitude2.html) +/// * [`l1_distance()`] +/// * [`l1_norm()`] +/// * [`l2_distance()`] +/// * [`length()`](crate::length) +/// * [`length2()`] +/// * [`magnitude()`](crate::magnitude) +/// * [`magnitude2()`] pub fn l2_norm(x: &TVec) -> T { x.norm() } /// The squared magnitude of `x`. /// -/// A synonym for [`magnitude2`](fn.magnitude2.html). +/// A synonym for [`magnitude2()`]. /// /// # See also: /// -/// * [`distance`](fn.distance.html) -/// * [`distance2`](fn.distance2.html) -/// * [`length`](fn.length.html) -/// * [`magnitude`](fn.magnitude.html) -/// * [`magnitude2`](fn.magnitude2.html) +/// * [`distance()`](crate::distance) +/// * [`distance2()`] +/// * [`length()`](crate::length) +/// * [`magnitude()`](crate::magnitude) +/// * [`magnitude2()`] pub fn length2(x: &TVec) -> T { x.norm_squared() } @@ -94,10 +94,10 @@ pub fn length2(x: &TVec) -> T { /// /// # See also: /// -/// * [`distance`](fn.distance.html) -/// * [`distance2`](fn.distance2.html) -/// * [`length2`](fn.length2.html) -/// * [`magnitude`](fn.magnitude.html) +/// * [`distance()`](crate::distance) +/// * [`distance2()`] +/// * [`length2()`] +/// * [`magnitude()`](crate::magnitude) /// * [`nalgebra::norm_squared`](../nalgebra/fn.norm_squared.html) pub fn magnitude2(x: &TVec) -> T { x.norm_squared() diff --git a/nalgebra-glm/src/gtx/normalize_dot.rs b/nalgebra-glm/src/gtx/normalize_dot.rs index 41146d7e..83932917 100644 --- a/nalgebra-glm/src/gtx/normalize_dot.rs +++ b/nalgebra-glm/src/gtx/normalize_dot.rs @@ -4,11 +4,11 @@ use crate::aliases::TVec; /// The dot product of the normalized version of `x` and `y`. /// -/// This is currently the same as [`normalize_dot`](fn.normalize_dot.html). +/// This is currently the same as [`normalize_dot()`] /// /// # See also: /// -/// * [`normalize_dot`](fn.normalize_dot.html`) +/// * [`normalize_dot()`] pub fn fast_normalize_dot(x: &TVec, y: &TVec) -> T { // XXX: improve those. x.normalize().dot(&y.normalize()) @@ -18,7 +18,7 @@ pub fn fast_normalize_dot(x: &TVec, y: &TVe /// /// # See also: /// -/// * [`fast_normalize_dot`](fn.fast_normalize_dot.html`) +/// * [`fast_normalize_dot()`] pub fn normalize_dot(x: &TVec, y: &TVec) -> T { // XXX: improve those. x.normalize().dot(&y.normalize()) diff --git a/nalgebra-glm/src/gtx/quaternion.rs b/nalgebra-glm/src/gtx/quaternion.rs index f912c409..736d3bbb 100644 --- a/nalgebra-glm/src/gtx/quaternion.rs +++ b/nalgebra-glm/src/gtx/quaternion.rs @@ -80,7 +80,7 @@ pub fn quat_to_mat3(x: &Qua) -> TMat3 { .into_inner() } -/// Converts a quaternion to a rotation matrix in homogenous coordinates. +/// Converts a quaternion to a rotation matrix in homogeneous coordinates. pub fn quat_to_mat4(x: &Qua) -> TMat4 { UnitQuaternion::new_unchecked(*x).to_homogeneous() } @@ -93,6 +93,6 @@ pub fn mat3_to_quat(x: &TMat3) -> Qua { /// Converts a rotation matrix in homogeneous coordinates to a quaternion. pub fn to_quat(x: &TMat4) -> Qua { - let rot = x.fixed_slice::<3, 3>(0, 0).into_owned(); + let rot = x.fixed_view::<3, 3>(0, 0).into_owned(); mat3_to_quat(&rot) } diff --git a/nalgebra-glm/src/gtx/transform.rs b/nalgebra-glm/src/gtx/transform.rs index 3587eb0f..c724c3bf 100644 --- a/nalgebra-glm/src/gtx/transform.rs +++ b/nalgebra-glm/src/gtx/transform.rs @@ -7,11 +7,11 @@ use crate::traits::{Number, RealNumber}; /// /// # See also: /// -/// * [`scaling`](fn.scaling.html) -/// * [`translation`](fn.translation.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`scaling()`] +/// * [`translation()`] +/// * [`rotation2d()`] +/// * [`scaling2d()`] +/// * [`translation2d()`] pub fn rotation(angle: T, v: &TVec3) -> TMat4 { Rotation3::from_axis_angle(&Unit::new_normalize(*v), angle).to_homogeneous() } @@ -20,11 +20,11 @@ pub fn rotation(angle: T, v: &TVec3) -> TMat4 { /// /// # See also: /// -/// * [`rotation`](fn.rotation.html) -/// * [`translation`](fn.translation.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotation()`] +/// * [`translation()`] +/// * [`rotation2d()`] +/// * [`scaling2d()`] +/// * [`translation2d()`] pub fn scaling(v: &TVec3) -> TMat4 { TMat4::new_nonuniform_scaling(v) } @@ -33,11 +33,11 @@ pub fn scaling(v: &TVec3) -> TMat4 { /// /// # See also: /// -/// * [`rotation`](fn.rotation.html) -/// * [`scaling`](fn.scaling.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotation()`] +/// * [`scaling()`] +/// * [`rotation2d()`] +/// * [`scaling2d()`] +/// * [`translation2d()`] pub fn translation(v: &TVec3) -> TMat4 { TMat4::new_translation(v) } @@ -46,11 +46,11 @@ pub fn translation(v: &TVec3) -> TMat4 { /// /// # See also: /// -/// * [`rotation`](fn.rotation.html) -/// * [`scaling`](fn.scaling.html) -/// * [`translation`](fn.translation.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotation()`] +/// * [`scaling()`] +/// * [`translation()`] +/// * [`scaling2d()`] +/// * [`translation2d()`] pub fn rotation2d(angle: T) -> TMat3 { Rotation2::new(angle).to_homogeneous() } @@ -59,11 +59,11 @@ pub fn rotation2d(angle: T) -> TMat3 { /// /// # See also: /// -/// * [`rotation`](fn.rotation.html) -/// * [`scaling`](fn.scaling.html) -/// * [`translation`](fn.translation.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotation()`] +/// * [`scaling()`] +/// * [`translation()`] +/// * [`rotation2d()`] +/// * [`translation2d()`] pub fn scaling2d(v: &TVec2) -> TMat3 { TMat3::new_nonuniform_scaling(v) } @@ -72,11 +72,11 @@ pub fn scaling2d(v: &TVec2) -> TMat3 { /// /// # See also: /// -/// * [`rotation`](fn.rotation.html) -/// * [`scaling`](fn.scaling.html) -/// * [`translation`](fn.translation.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scaling2d`](fn.scaling2d.html) +/// * [`rotation()`] +/// * [`scaling()`] +/// * [`translation()`] +/// * [`rotation2d()`] +/// * [`scaling2d()`] pub fn translation2d(v: &TVec2) -> TMat3 { TMat3::new_translation(v) } diff --git a/nalgebra-glm/src/gtx/transform2.rs b/nalgebra-glm/src/gtx/transform2.rs index f389e4b1..56f736d7 100644 --- a/nalgebra-glm/src/gtx/transform2.rs +++ b/nalgebra-glm/src/gtx/transform2.rs @@ -7,7 +7,7 @@ pub fn proj2d(m: &TMat3, normal: &TVec2) -> TMat3 { let mut res = TMat3::identity(); { - let mut part = res.fixed_slice_mut::<2, 2>(0, 0); + let mut part = res.fixed_view_mut::<2, 2>(0, 0); part -= normal * normal.transpose(); } @@ -19,7 +19,7 @@ pub fn proj(m: &TMat4, normal: &TVec3) -> TMat4 { let mut res = TMat4::identity(); { - let mut part = res.fixed_slice_mut::<3, 3>(0, 0); + let mut part = res.fixed_view_mut::<3, 3>(0, 0); part -= normal * normal.transpose(); } @@ -31,7 +31,7 @@ pub fn reflect2d(m: &TMat3, normal: &TVec2) -> TMat3 { let mut res = TMat3::identity(); { - let mut part = res.fixed_slice_mut::<2, 2>(0, 0); + let mut part = res.fixed_view_mut::<2, 2>(0, 0); part -= (normal * T::from_subset(&2.0)) * normal.transpose(); } @@ -43,7 +43,7 @@ pub fn reflect(m: &TMat4, normal: &TVec3) -> TMat4 { let mut res = TMat4::identity(); { - let mut part = res.fixed_slice_mut::<3, 3>(0, 0); + let mut part = res.fixed_view_mut::<3, 3>(0, 0); part -= (normal * T::from_subset(&2.0)) * normal.transpose(); } diff --git a/nalgebra-glm/src/gtx/transform2d.rs b/nalgebra-glm/src/gtx/transform2d.rs index 98d5205c..d796ca94 100644 --- a/nalgebra-glm/src/gtx/transform2d.rs +++ b/nalgebra-glm/src/gtx/transform2d.rs @@ -7,11 +7,11 @@ use crate::traits::{Number, RealNumber}; /// /// # See also: /// -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scale2d`](fn.scale2d.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translate2d`](fn.translate2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotation2d()`](crate::rotation2d) +/// * [`scale2d()`] +/// * [`scaling2d()`](crate::scaling2d) +/// * [`translate2d()`] +/// * [`translation2d()`](crate::translation2d) pub fn rotate2d(m: &TMat3, angle: T) -> TMat3 { m * UnitComplex::new(angle).to_homogeneous() } @@ -20,11 +20,11 @@ pub fn rotate2d(m: &TMat3, angle: T) -> TMat3 { /// /// # See also: /// -/// * [`rotate2d`](fn.rotate2d.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translate2d`](fn.translate2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotate2d()`] +/// * [`rotation2d()`](crate::rotation2d) +/// * [`scaling2d()`](crate::scaling2d) +/// * [`translate2d()`] +/// * [`translation2d()`](crate::translation2d) pub fn scale2d(m: &TMat3, v: &TVec2) -> TMat3 { m.prepend_nonuniform_scaling(v) } @@ -33,11 +33,11 @@ pub fn scale2d(m: &TMat3, v: &TVec2) -> TMat3 { /// /// # See also: /// -/// * [`rotate2d`](fn.rotate2d.html) -/// * [`rotation2d`](fn.rotation2d.html) -/// * [`scale2d`](fn.scale2d.html) -/// * [`scaling2d`](fn.scaling2d.html) -/// * [`translation2d`](fn.translation2d.html) +/// * [`rotate2d()`] +/// * [`rotation2d()`](crate::rotation2d) +/// * [`scale2d()`] +/// * [`scaling2d()`](crate::scaling2d) +/// * [`translation2d()`](crate::translation2d) pub fn translate2d(m: &TMat3, v: &TVec2) -> TMat3 { m.prepend_translation(v) } diff --git a/nalgebra-glm/src/gtx/vector_query.rs b/nalgebra-glm/src/gtx/vector_query.rs index d85d64a6..a0b9f621 100644 --- a/nalgebra-glm/src/gtx/vector_query.rs +++ b/nalgebra-glm/src/gtx/vector_query.rs @@ -7,7 +7,7 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`are_collinear2d`](fn.are_collinear2d.html) +/// * [`are_collinear2d()`] pub fn are_collinear(v0: &TVec3, v1: &TVec3, epsilon: T) -> bool { is_null(&v0.cross(v1), epsilon) } @@ -16,7 +16,7 @@ pub fn are_collinear(v0: &TVec3, v1: &TVec3, epsilon: T) -> boo /// /// # See also: /// -/// * [`are_collinear`](fn.are_collinear.html) +/// * [`are_collinear()`] pub fn are_collinear2d(v0: &TVec2, v1: &TVec2, epsilon: T) -> bool { abs_diff_eq!(v0.perp(v1), T::zero(), epsilon = epsilon) } @@ -41,7 +41,10 @@ pub fn is_comp_null(v: &TVec, epsilon: T) -> TV /// Returns `true` if `v` has a magnitude of 1 (up to an epsilon). pub fn is_normalized(v: &TVec, epsilon: T) -> bool { - abs_diff_eq!(v.norm_squared(), T::one(), epsilon = epsilon * epsilon) + // sqrt(1 + epsilon_{norm²} = 1 + epsilon_{norm} + // ==> epsilon_{norm²} = epsilon_{norm}² + 2*epsilon_{norm} + // For small epsilon, epsilon² is basically zero, so use 2*epsilon. + abs_diff_eq!(v.norm_squared(), T::one(), epsilon = epsilon + epsilon) } /// Returns `true` if `v` is zero (up to an epsilon). diff --git a/nalgebra-glm/src/lib.rs b/nalgebra-glm/src/lib.rs index 0a6da334..2601c76f 100644 --- a/nalgebra-glm/src/lib.rs +++ b/nalgebra-glm/src/lib.rs @@ -38,7 +38,7 @@ * All function names use `snake_case`, which is the Rust convention. * All type names use `CamelCase`, which is the Rust convention. * All function arguments, except for scalars, are all passed by-reference. - * The most generic vector and matrix types are [`TMat`](type.TMat.html) and [`TVec`](type.TVec.html) instead of `mat` and `vec`. + * The most generic vector and matrix types are [`TMat`] and [`TVec`] instead of `mat` and `vec`. * Some feature are not yet implemented and should be added in the future. In particular, no packing functions are available. * A few features are not implemented and will never be. This includes functions related to color @@ -47,17 +47,17 @@ In addition, because Rust does not allows function overloading, all functions must be given a unique name. Here are a few rules chosen arbitrarily for **nalgebra-glm**: - * Functions operating in 2d will usually end with the `2d` suffix, e.g., [`glm::rotate2d`](fn.rotate2d.html) is for 2D while [`glm::rotate`](fn.rotate.html) is for 3D. - * Functions operating on vectors will often end with the `_vec` suffix, possibly followed by the dimension of vector, e.g., [`glm::rotate_vec2`](fn.rotate_vec2.html). - * Every function related to quaternions start with the `quat_` prefix, e.g., [`glm::quat_dot(q1, q2)`](fn.quat_dot.html). + * Functions operating in 2d will usually end with the `2d` suffix, e.g., [`glm::rotate2d()`](crate::rotate2d) is for 2D while [`glm::rotate()`](crate::rotate) is for 3D. + * Functions operating on vectors will often end with the `_vec` suffix, possibly followed by the dimension of vector, e.g., [`glm::rotate_vec2()`](crate::rotate_vec2). + * Every function related to quaternions start with the `quat_` prefix, e.g., [`glm::quat_dot(q1, q2)`](crate::quat_dot). * All the conversion functions have unique names as described [below](#conversions). ### Vector and matrix construction Vectors, matrices, and quaternions can be constructed using several approaches: - * Using functions with the same name as their type in lower-case. For example [`glm::vec3(x, y, z)`](fn.vec3.html) will create a 3D vector. + * Using functions with the same name as their type in lower-case. For example [`glm::vec3(x, y, z)`](crate::vec3) will create a 3D vector. * Using the `::new` constructor. For example [`Vec3::new(x, y, z)`](../nalgebra/base/type.OMatrix.html#method.new-27) will create a 3D vector. - * Using the functions prefixed by `make_` to build a vector a matrix from a slice. For example [`glm::make_vec3(&[x, y, z])`](fn.make_vec3.html) will create a 3D vector. + * Using the functions prefixed by `make_` to build a vector a matrix from a slice. For example [`glm::make_vec3(&[x, y, z])`](crate::make_vec3) will create a 3D vector. Keep in mind that constructing a matrix using this type of functions require its components to be arranged in column-major order on the slice. - * Using a geometric construction function. For example [`glm::rotation(angle, axis)`](fn.rotation.html) will build a 4x4 homogeneous rotation matrix from an angle (in radians) and an axis. + * Using a geometric construction function. For example [`glm::rotation(angle, axis)`](crate::rotation) will build a 4x4 homogeneous rotation matrix from an angle (in radians) and an axis. * Using swizzling and conversions as described in the next sections. ### Swizzling Vector swizzling is a native feature of **nalgebra** itself. Therefore, you can use it with all @@ -75,9 +75,9 @@ It is often useful to convert one algebraic type to another. There are two main approaches for converting between types in `nalgebra-glm`: * Using function with the form `type1_to_type2` in order to convert an instance of `type1` into an instance of `type2`. - For example [`glm::mat3_to_mat4(m)`](fn.mat3_to_mat4.html) will convert the 3x3 matrix `m` to a 4x4 matrix by appending one column on the right + For example [`glm::mat3_to_mat4(m)`](crate::mat3_to_mat4) will convert the 3x3 matrix `m` to a 4x4 matrix by appending one column on the right and one row on the left. Those now row and columns are filled with 0 except for the diagonal element which is set to 1. - * Using one of the [`convert`](fn.convert.html), [`try_convert`](fn.try_convert.html), or [`convert_unchecked`](fn.convert_unchecked.html) functions. + * Using one of the [`convert`](crate::convert), [`try_convert`](crate::try_convert), or [`convert_unchecked`](crate::convert_unchecked) functions. These functions are directly re-exported from nalgebra and are extremely versatile: 1. The `convert` function can convert any type (especially geometric types from nalgebra like `Isometry3`) into another algebraic type which is equivalent but more general. For example, `let sim: Similarity3<_> = na::convert(isometry)` will convert an `Isometry3` into a `Similarity3`. diff --git a/nalgebra-glm/src/traits.rs b/nalgebra-glm/src/traits.rs index ccdb4a02..3d919eb1 100644 --- a/nalgebra-glm/src/traits.rs +++ b/nalgebra-glm/src/traits.rs @@ -1,7 +1,6 @@ use approx::AbsDiffEq; use num::{Bounded, Signed}; -use core::cmp::PartialOrd; use na::Scalar; use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, RealField}; diff --git a/nalgebra-glm/src/trigonometric.rs b/nalgebra-glm/src/trigonometric.rs index dce45738..597b037e 100644 --- a/nalgebra-glm/src/trigonometric.rs +++ b/nalgebra-glm/src/trigonometric.rs @@ -1,5 +1,3 @@ -use na; - use crate::aliases::TVec; use crate::RealNumber; diff --git a/nalgebra-glm/src/vector_relational.rs b/nalgebra-glm/src/vector_relational.rs index b8b3fbd7..e4e0a37f 100644 --- a/nalgebra-glm/src/vector_relational.rs +++ b/nalgebra-glm/src/vector_relational.rs @@ -16,8 +16,8 @@ use crate::traits::Number; /// /// # See also: /// -/// * [`any`](fn.any.html) -/// * [`not`](fn.not.html) +/// * [`any()`] +/// * [`not()`] pub fn all(v: &TVec) -> bool { v.iter().all(|x| *x) } @@ -40,8 +40,8 @@ pub fn all(v: &TVec) -> bool { /// /// # See also: /// -/// * [`all`](fn.all.html) -/// * [`not`](fn.not.html) +/// * [`all()`] +/// * [`not()`] pub fn any(v: &TVec) -> bool { v.iter().any(|x| *x) } @@ -59,12 +59,12 @@ pub fn any(v: &TVec) -> bool { /// /// # See also: /// -/// * [`greater_than`](fn.greater_than.html) -/// * [`greater_than_equal`](fn.greater_than_equal.html) -/// * [`less_than`](fn.less_than.html) -/// * [`less_than_equal`](fn.less_than_equal.html) -/// * [`not`](fn.not.html) -/// * [`not_equal`](fn.not_equal.html) +/// * [`greater_than()`] +/// * [`greater_than_equal()`] +/// * [`less_than()`] +/// * [`less_than_equal()`] +/// * [`not()`] +/// * [`not_equal()`] pub fn equal(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |x, y| x == y) } @@ -82,12 +82,12 @@ pub fn equal(x: &TVec, y: &TVec) -> TVec< /// /// # See also: /// -/// * [`equal`](fn.equal.html) -/// * [`greater_than_equal`](fn.greater_than_equal.html) -/// * [`less_than`](fn.less_than.html) -/// * [`less_than_equal`](fn.less_than_equal.html) -/// * [`not`](fn.not.html) -/// * [`not_equal`](fn.not_equal.html) +/// * [`equal()`] +/// * [`greater_than_equal()`] +/// * [`less_than()`] +/// * [`less_than_equal()`] +/// * [`not()`] +/// * [`not_equal()`] pub fn greater_than(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |x, y| x > y) } @@ -105,12 +105,12 @@ pub fn greater_than(x: &TVec, y: &TVec) - /// /// # See also: /// -/// * [`equal`](fn.equal.html) -/// * [`greater_than`](fn.greater_than.html) -/// * [`less_than`](fn.less_than.html) -/// * [`less_than_equal`](fn.less_than_equal.html) -/// * [`not`](fn.not.html) -/// * [`not_equal`](fn.not_equal.html) +/// * [`equal()`] +/// * [`greater_than()`] +/// * [`less_than()`] +/// * [`less_than_equal()`] +/// * [`not()`] +/// * [`not_equal()`] pub fn greater_than_equal( x: &TVec, y: &TVec, @@ -131,17 +131,17 @@ pub fn greater_than_equal( /// /// # See also: /// -/// * [`equal`](fn.equal.html) -/// * [`greater_than`](fn.greater_than.html) -/// * [`greater_than_equal`](fn.greater_than_equal.html) -/// * [`less_than_equal`](fn.less_than_equal.html) -/// * [`not`](fn.not.html) -/// * [`not_equal`](fn.not_equal.html) +/// * [`equal()`] +/// * [`greater_than()`] +/// * [`greater_than_equal()`] +/// * [`less_than_equal()`] +/// * [`not()`] +/// * [`not_equal()`] pub fn less_than(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |x, y| x < y) } -/// Component-wise `>=` comparison. +/// Component-wise `<=` comparison. /// /// # Examples: /// @@ -154,12 +154,12 @@ pub fn less_than(x: &TVec, y: &TVec) -> T /// /// # See also: /// -/// * [`equal`](fn.equal.html) -/// * [`greater_than`](fn.greater_than.html) -/// * [`greater_than_equal`](fn.greater_than_equal.html) -/// * [`less_than`](fn.less_than.html) -/// * [`not`](fn.not.html) -/// * [`not_equal`](fn.not_equal.html) +/// * [`equal()`] +/// * [`greater_than()`] +/// * [`greater_than_equal()`] +/// * [`less_than()`] +/// * [`not()`] +/// * [`not_equal()`] pub fn less_than_equal(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |x, y| x <= y) } @@ -176,14 +176,14 @@ pub fn less_than_equal(x: &TVec, y: &TVec /// /// # See also: /// -/// * [`all`](fn.all.html) -/// * [`any`](fn.any.html) -/// * [`equal`](fn.equal.html) -/// * [`greater_than`](fn.greater_than.html) -/// * [`greater_than_equal`](fn.greater_than_equal.html) -/// * [`less_than`](fn.less_than.html) -/// * [`less_than_equal`](fn.less_than_equal.html) -/// * [`not_equal`](fn.not_equal.html) +/// * [`all()`] +/// * [`any()`] +/// * [`equal()`] +/// * [`greater_than()`] +/// * [`greater_than_equal()`] +/// * [`less_than()`] +/// * [`less_than_equal()`] +/// * [`not_equal()`] pub fn not(v: &TVec) -> TVec { v.map(|x| !x) } @@ -201,12 +201,12 @@ pub fn not(v: &TVec) -> TVec { /// /// # See also: /// -/// * [`equal`](fn.equal.html) -/// * [`greater_than`](fn.greater_than.html) -/// * [`greater_than_equal`](fn.greater_than_equal.html) -/// * [`less_than`](fn.less_than.html) -/// * [`less_than_equal`](fn.less_than_equal.html) -/// * [`not`](fn.not.html) +/// * [`equal()`] +/// * [`greater_than()`] +/// * [`greater_than_equal()`] +/// * [`less_than()`] +/// * [`less_than_equal()`] +/// * [`not()`] pub fn not_equal(x: &TVec, y: &TVec) -> TVec { x.zip_map(y, |x, y| x != y) } diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index 7cdf9f78..95153a2c 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-lapack" -version = "0.21.0" +version = "0.24.0" authors = [ "Sébastien Crozet ", "Andrew Straw " ] description = "Matrix decompositions using nalgebra matrices and Lapack bindings." @@ -10,7 +10,7 @@ repository = "https://github.com/dimforge/nalgebra" readme = "../README.md" categories = [ "science", "mathematics" ] keywords = [ "linear", "algebra", "matrix", "vector", "lapack" ] -license = "BSD-3-Clause" +license = "MIT" edition = "2018" [badges] @@ -29,18 +29,19 @@ accelerate = ["lapack-src/accelerate"] intel-mkl = ["lapack-src/intel-mkl"] [dependencies] -nalgebra = { version = "0.30", path = ".." } +nalgebra = { version = "0.32", path = ".." } num-traits = "0.2" num-complex = { version = "0.4", default-features = false } -simba = "0.7" +simba = "0.8" serde = { version = "1.0", features = [ "derive" ], optional = true } lapack = { version = "0.19", default-features = false } lapack-src = { version = "0.8", default-features = false } # clippy = "*" [dev-dependencies] -nalgebra = { version = "0.30", features = [ "arbitrary", "rand" ], path = ".." } +nalgebra = { version = "0.32", features = [ "arbitrary", "rand" ], path = ".." } proptest = { version = "1", default-features = false, features = ["std"] } quickcheck = "1" approx = "0.5" rand = "0.8" + diff --git a/nalgebra-lapack/LICENSE.txt b/nalgebra-lapack/LICENSE similarity index 100% rename from nalgebra-lapack/LICENSE.txt rename to nalgebra-lapack/LICENSE diff --git a/nalgebra-lapack/src/eigen.rs b/nalgebra-lapack/src/eigen.rs index 8eab62d8..586c372f 100644 --- a/nalgebra-lapack/src/eigen.rs +++ b/nalgebra-lapack/src/eigen.rs @@ -7,13 +7,12 @@ use num_complex::Complex; use simba::scalar::RealField; use crate::ComplexHelper; -use na::allocator::Allocator; use na::dimension::{Const, Dim}; -use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; +use na::{allocator::Allocator, DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; use lapack; -/// Eigendecomposition of a real square matrix with real eigenvalues. +/// Eigendecomposition of a real square matrix with real or complex eigenvalues. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", @@ -36,8 +35,10 @@ pub struct Eigen where DefaultAllocator: Allocator + Allocator, { - /// The eigenvalues of the decomposed matrix. - pub eigenvalues: OVector, + /// The real parts of eigenvalues of the decomposed matrix. + pub eigenvalues_re: OVector, + /// The imaginary parts of the eigenvalues of the decomposed matrix. + pub eigenvalues_im: OVector, /// The (right) eigenvectors of the decomposed matrix. pub eigenvectors: Option>, /// The left eigenvectors of the decomposed matrix. @@ -69,8 +70,8 @@ where "Unable to compute the eigenvalue decomposition of a non-square matrix." ); - let ljob = if left_eigenvectors { b'V' } else { b'T' }; - let rjob = if eigenvectors { b'V' } else { b'T' }; + let ljob = if left_eigenvectors { b'V' } else { b'N' }; + let rjob = if eigenvectors { b'V' } else { b'N' }; let (nrows, ncols) = m.shape_generic(); let n = nrows.value(); @@ -104,213 +105,231 @@ where lapack_check!(info); let mut work = vec![T::zero(); lwork as usize]; + let mut vl = if left_eigenvectors { + Some(Matrix::zeros_generic(nrows, ncols)) + } else { + None + }; + let mut vr = if eigenvectors { + Some(Matrix::zeros_generic(nrows, ncols)) + } else { + None + }; - match (left_eigenvectors, eigenvectors) { - (true, true) => { - // TODO: avoid the initializations? - let mut vl = Matrix::zeros_generic(nrows, ncols); - let mut vr = Matrix::zeros_generic(nrows, ncols); - - T::xgeev( - ljob, - rjob, - n as i32, - m.as_mut_slice(), - lda, - wr.as_mut_slice(), - wi.as_mut_slice(), - &mut vl.as_mut_slice(), - n as i32, - &mut vr.as_mut_slice(), - n as i32, - &mut work, - lwork, - &mut info, - ); - lapack_check!(info); - - if wi.iter().all(|e| e.is_zero()) { - return Some(Self { - eigenvalues: wr, - left_eigenvectors: Some(vl), - eigenvectors: Some(vr), - }); - } - } - (true, false) => { - // TODO: avoid the initialization? - let mut vl = Matrix::zeros_generic(nrows, ncols); - - T::xgeev( - ljob, - rjob, - n as i32, - m.as_mut_slice(), - lda, - wr.as_mut_slice(), - wi.as_mut_slice(), - &mut vl.as_mut_slice(), - n as i32, - &mut placeholder2, - 1 as i32, - &mut work, - lwork, - &mut info, - ); - lapack_check!(info); - - if wi.iter().all(|e| e.is_zero()) { - return Some(Self { - eigenvalues: wr, - left_eigenvectors: Some(vl), - eigenvectors: None, - }); - } - } - (false, true) => { - // TODO: avoid the initialization? - let mut vr = Matrix::zeros_generic(nrows, ncols); - - T::xgeev( - ljob, - rjob, - n as i32, - m.as_mut_slice(), - lda, - wr.as_mut_slice(), - wi.as_mut_slice(), - &mut placeholder1, - 1 as i32, - &mut vr.as_mut_slice(), - n as i32, - &mut work, - lwork, - &mut info, - ); - lapack_check!(info); - - if wi.iter().all(|e| e.is_zero()) { - return Some(Self { - eigenvalues: wr, - left_eigenvectors: None, - eigenvectors: Some(vr), - }); - } - } - (false, false) => { - T::xgeev( - ljob, - rjob, - n as i32, - m.as_mut_slice(), - lda, - wr.as_mut_slice(), - wi.as_mut_slice(), - &mut placeholder1, - 1 as i32, - &mut placeholder2, - 1 as i32, - &mut work, - lwork, - &mut info, - ); - lapack_check!(info); - - if wi.iter().all(|e| e.is_zero()) { - return Some(Self { - eigenvalues: wr, - left_eigenvectors: None, - eigenvectors: None, - }); - } - } - } - - None - } - - /// The complex eigenvalues of the given matrix. - /// - /// Panics if the eigenvalue computation does not converge. - pub fn complex_eigenvalues(mut m: OMatrix) -> OVector, D> - where - DefaultAllocator: Allocator, D>, - { - assert!( - m.is_square(), - "Unable to compute the eigenvalue decomposition of a non-square matrix." - ); - - let nrows = m.shape_generic().0; - let n = nrows.value(); - - let lda = n as i32; - - // TODO: avoid the initialization? - let mut wr = Matrix::zeros_generic(nrows, Const::<1>); - let mut wi = Matrix::zeros_generic(nrows, Const::<1>); - - let mut info = 0; - let mut placeholder1 = [T::zero()]; - let mut placeholder2 = [T::zero()]; - - let lwork = T::xgeev_work_size( - b'T', - b'T', - n as i32, - m.as_mut_slice(), - lda, - wr.as_mut_slice(), - wi.as_mut_slice(), - &mut placeholder1, - n as i32, - &mut placeholder2, - n as i32, - &mut info, - ); - - lapack_panic!(info); - - let mut work = vec![T::zero(); lwork as usize]; + let vl_ref = vl + .as_mut() + .map(|m| m.as_mut_slice()) + .unwrap_or(&mut placeholder1); + let vr_ref = vr + .as_mut() + .map(|m| m.as_mut_slice()) + .unwrap_or(&mut placeholder2); T::xgeev( - b'T', - b'T', + ljob, + rjob, n as i32, m.as_mut_slice(), lda, wr.as_mut_slice(), wi.as_mut_slice(), - &mut placeholder1, - 1 as i32, - &mut placeholder2, - 1 as i32, + vl_ref, + if left_eigenvectors { n as i32 } else { 1 }, + vr_ref, + if eigenvectors { n as i32 } else { 1 }, &mut work, lwork, &mut info, ); - lapack_panic!(info); + lapack_check!(info); - let mut res = Matrix::zeros_generic(nrows, Const::<1>); + Some(Self { + eigenvalues_re: wr, + eigenvalues_im: wi, + left_eigenvectors: vl, + eigenvectors: vr, + }) + } - for i in 0..res.len() { - res[i] = Complex::new(wr[i].clone(), wi[i].clone()); - } - - res + /// Returns `true` if all the eigenvalues are real. + pub fn eigenvalues_are_real(&self) -> bool { + self.eigenvalues_im.iter().all(|e| e.is_zero()) } /// The determinant of the decomposed matrix. #[inline] #[must_use] - pub fn determinant(&self) -> T { - let mut det = T::one(); - for e in self.eigenvalues.iter() { - det *= e.clone(); + pub fn determinant(&self) -> Complex { + let mut det: Complex = na::one(); + for (re, im) in self.eigenvalues_re.iter().zip(self.eigenvalues_im.iter()) { + det *= Complex::new(re.clone(), im.clone()); } det } + + /// Returns a tuple of vectors. The elements of the tuple are the real parts of the eigenvalues, left eigenvectors and right eigenvectors respectively. + pub fn get_real_elements( + &self, + ) -> ( + Vec, + Option>>, + Option>>, + ) + where + DefaultAllocator: Allocator, + { + let (number_of_elements, _) = self.eigenvalues_re.shape_generic(); + let number_of_elements_value = number_of_elements.value(); + let mut eigenvalues = Vec::::with_capacity(number_of_elements_value); + let mut eigenvectors = match self.eigenvectors.is_some() { + true => Some(Vec::>::with_capacity( + number_of_elements_value, + )), + false => None, + }; + let mut left_eigenvectors = match self.left_eigenvectors.is_some() { + true => Some(Vec::>::with_capacity( + number_of_elements_value, + )), + false => None, + }; + + let mut c = 0; + while c < number_of_elements_value { + eigenvalues.push(self.eigenvalues_re[c].clone()); + + if eigenvectors.is_some() { + eigenvectors + .as_mut() + .unwrap() + .push(self.eigenvectors.as_ref().unwrap().column(c).into_owned()); + } + + if left_eigenvectors.is_some() { + left_eigenvectors.as_mut().unwrap().push( + self.left_eigenvectors + .as_ref() + .unwrap() + .column(c) + .into_owned(), + ); + } + if self.eigenvalues_im[c] != T::zero() { + //skip next entry + c += 1; + } + c += 1; + } + (eigenvalues, left_eigenvectors, eigenvectors) + } + + /// Returns a tuple of vectors. The elements of the tuple are the complex eigenvalues, complex left eigenvectors and complex right eigenvectors respectively. + /// The elements appear as conjugate pairs within each vector, with the positive of the pair always being first. + pub fn get_complex_elements( + &self, + ) -> ( + Option>>, + Option, D>>>, + Option, D>>>, + ) + where + DefaultAllocator: Allocator, D>, + { + match self.eigenvalues_are_real() { + true => (None, None, None), + false => { + let (number_of_elements, _) = self.eigenvalues_re.shape_generic(); + let number_of_elements_value = number_of_elements.value(); + let number_of_complex_entries = + self.eigenvalues_im + .iter() + .fold(0, |acc, e| if !e.is_zero() { acc + 1 } else { acc }); + let mut eigenvalues = Vec::>::with_capacity(number_of_complex_entries); + let mut eigenvectors = match self.eigenvectors.is_some() { + true => Some(Vec::, D>>::with_capacity( + number_of_complex_entries, + )), + false => None, + }; + let mut left_eigenvectors = match self.left_eigenvectors.is_some() { + true => Some(Vec::, D>>::with_capacity( + number_of_complex_entries, + )), + false => None, + }; + + let mut c = 0; + while c < number_of_elements_value { + if self.eigenvalues_im[c] != T::zero() { + //Complex conjugate pairs of eigenvalues appear consecutively with the eigenvalue having the positive imaginary part first. + eigenvalues.push(Complex::::new( + self.eigenvalues_re[c].clone(), + self.eigenvalues_im[c].clone(), + )); + eigenvalues.push(Complex::::new( + self.eigenvalues_re[c + 1].clone(), + self.eigenvalues_im[c + 1].clone(), + )); + + if eigenvectors.is_some() { + let mut vec = OVector::, D>::zeros_generic( + number_of_elements, + Const::<1>, + ); + let mut vec_conj = OVector::, D>::zeros_generic( + number_of_elements, + Const::<1>, + ); + + for r in 0..number_of_elements_value { + vec[r] = Complex::::new( + self.eigenvectors.as_ref().unwrap()[(r, c)].clone(), + self.eigenvectors.as_ref().unwrap()[(r, c + 1)].clone(), + ); + vec_conj[r] = Complex::::new( + self.eigenvectors.as_ref().unwrap()[(r, c)].clone(), + self.eigenvectors.as_ref().unwrap()[(r, c + 1)].clone(), + ); + } + + eigenvectors.as_mut().unwrap().push(vec); + eigenvectors.as_mut().unwrap().push(vec_conj); + } + + if left_eigenvectors.is_some() { + let mut vec = OVector::, D>::zeros_generic( + number_of_elements, + Const::<1>, + ); + let mut vec_conj = OVector::, D>::zeros_generic( + number_of_elements, + Const::<1>, + ); + + for r in 0..number_of_elements_value { + vec[r] = Complex::::new( + self.left_eigenvectors.as_ref().unwrap()[(r, c)].clone(), + self.left_eigenvectors.as_ref().unwrap()[(r, c + 1)].clone(), + ); + vec_conj[r] = Complex::::new( + self.left_eigenvectors.as_ref().unwrap()[(r, c)].clone(), + self.left_eigenvectors.as_ref().unwrap()[(r, c + 1)].clone(), + ); + } + + left_eigenvectors.as_mut().unwrap().push(vec); + left_eigenvectors.as_mut().unwrap().push(vec_conj); + } + //skip next entry + c += 1; + } + c += 1; + } + (Some(eigenvalues), left_eigenvectors, eigenvectors) + } + } + } } /* diff --git a/nalgebra-lapack/src/generalized_eigenvalues.rs b/nalgebra-lapack/src/generalized_eigenvalues.rs new file mode 100644 index 00000000..5d1e3ace --- /dev/null +++ b/nalgebra-lapack/src/generalized_eigenvalues.rs @@ -0,0 +1,350 @@ +#[cfg(feature = "serde-serialize")] +use serde::{Deserialize, Serialize}; + +use num::Zero; +use num_complex::Complex; + +use simba::scalar::RealField; + +use crate::ComplexHelper; +use na::allocator::Allocator; +use na::dimension::{Const, Dim}; +use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; + +use lapack; + +/// Generalized eigenvalues and generalized eigenvectors (left and right) of a pair of N*N real square matrices. +/// +/// Each generalized eigenvalue (lambda) satisfies determinant(A - lambda*B) = 0 +/// +/// The right eigenvector v(j) corresponding to the eigenvalue lambda(j) +/// of (A,B) satisfies +/// +/// A * v(j) = lambda(j) * B * v(j). +/// +/// The left eigenvector u(j) corresponding to the eigenvalue lambda(j) +/// of (A,B) satisfies +/// +/// u(j)**H * A = lambda(j) * u(j)**H * B . +/// where u(j)**H is the conjugate-transpose of u(j). +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize", + serde( + bound(serialize = "DefaultAllocator: Allocator + Allocator, + OVector: Serialize, + OMatrix: Serialize") + ) +)] +#[cfg_attr( + feature = "serde-serialize", + serde( + bound(deserialize = "DefaultAllocator: Allocator + Allocator, + OVector: Deserialize<'de>, + OMatrix: Deserialize<'de>") + ) +)] +#[derive(Clone, Debug)] +pub struct GeneralizedEigen +where + DefaultAllocator: Allocator + Allocator, +{ + alphar: OVector, + alphai: OVector, + beta: OVector, + vsl: OMatrix, + vsr: OMatrix, +} + +impl Copy for GeneralizedEigen +where + DefaultAllocator: Allocator + Allocator, + OMatrix: Copy, + OVector: Copy, +{ +} + +impl GeneralizedEigen +where + DefaultAllocator: Allocator + Allocator, +{ + /// Attempts to compute the generalized eigenvalues, and left and right associated eigenvectors + /// via the raw returns from LAPACK's dggev and sggev routines + /// + /// Panics if the method did not converge. + pub fn new(a: OMatrix, b: OMatrix) -> Self { + Self::try_new(a, b).expect("Calculation of generalized eigenvalues failed.") + } + + /// Attempts to compute the generalized eigenvalues (and eigenvectors) via the raw returns from LAPACK's + /// dggev and sggev routines + /// + /// Returns `None` if the method did not converge. + pub fn try_new(mut a: OMatrix, mut b: OMatrix) -> Option { + assert!( + a.is_square() && b.is_square(), + "Unable to compute the generalized eigenvalues of non-square matrices." + ); + + assert!( + a.shape_generic() == b.shape_generic(), + "Unable to compute the generalized eigenvalues of two square matrices of different dimensions." + ); + + let (nrows, ncols) = a.shape_generic(); + let n = nrows.value(); + + let mut info = 0; + + let mut alphar = Matrix::zeros_generic(nrows, Const::<1>); + let mut alphai = Matrix::zeros_generic(nrows, Const::<1>); + let mut beta = Matrix::zeros_generic(nrows, Const::<1>); + let mut vsl = Matrix::zeros_generic(nrows, ncols); + let mut vsr = Matrix::zeros_generic(nrows, ncols); + + let lwork = T::xggev_work_size( + b'V', + b'V', + n as i32, + a.as_mut_slice(), + n as i32, + b.as_mut_slice(), + n as i32, + alphar.as_mut_slice(), + alphai.as_mut_slice(), + beta.as_mut_slice(), + vsl.as_mut_slice(), + n as i32, + vsr.as_mut_slice(), + n as i32, + &mut info, + ); + lapack_check!(info); + + let mut work = vec![T::zero(); lwork as usize]; + + T::xggev( + b'V', + b'V', + n as i32, + a.as_mut_slice(), + n as i32, + b.as_mut_slice(), + n as i32, + alphar.as_mut_slice(), + alphai.as_mut_slice(), + beta.as_mut_slice(), + vsl.as_mut_slice(), + n as i32, + vsr.as_mut_slice(), + n as i32, + &mut work, + lwork, + &mut info, + ); + lapack_check!(info); + + Some(GeneralizedEigen { + alphar, + alphai, + beta, + vsl, + vsr, + }) + } + + /// Calculates the generalized eigenvectors (left and right) associated with the generalized eigenvalues + /// + /// Outputs two matrices. + /// The first output matrix contains the left eigenvectors of the generalized eigenvalues + /// as columns. + /// The second matrix contains the right eigenvectors of the generalized eigenvalues + /// as columns. + pub fn eigenvectors(&self) -> (OMatrix, D, D>, OMatrix, D, D>) + where + DefaultAllocator: + Allocator, D, D> + Allocator, D> + Allocator<(Complex, T), D>, + { + /* + How the eigenvectors are built up: + + Since the input entries are all real, the generalized eigenvalues if complex come in pairs + as a consequence of the [complex conjugate root thorem](https://en.wikipedia.org/wiki/Complex_conjugate_root_theorem) + The Lapack routine output reflects this by expecting the user to unpack the real and complex eigenvalues associated + eigenvectors from the real matrix output via the following procedure + + (Note: VL stands for the lapack real matrix output containing the left eigenvectors as columns, + VR stands for the lapack real matrix output containing the right eigenvectors as columns) + + If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, + then + + u(j) = VL(:,j)+i*VL(:,j+1) + u(j+1) = VL(:,j)-i*VL(:,j+1) + + and + + u(j) = VR(:,j)+i*VR(:,j+1) + v(j+1) = VR(:,j)-i*VR(:,j+1). + */ + + let n = self.vsl.shape().0; + + let mut l = self.vsl.map(|x| Complex::new(x, T::RealField::zero())); + + let mut r = self.vsr.map(|x| Complex::new(x, T::RealField::zero())); + + let eigenvalues = self.raw_eigenvalues(); + + let mut c = 0; + + while c < n { + if eigenvalues[c].0.im.abs() != T::RealField::zero() && c + 1 < n { + // taking care of the left eigenvector matrix + l.column_mut(c).zip_apply(&self.vsl.column(c + 1), |r, i| { + *r = Complex::new(r.re.clone(), i.clone()); + }); + l.column_mut(c + 1).zip_apply(&self.vsl.column(c), |i, r| { + *i = Complex::new(r.clone(), -i.re.clone()); + }); + + // taking care of the right eigenvector matrix + r.column_mut(c).zip_apply(&self.vsr.column(c + 1), |r, i| { + *r = Complex::new(r.re.clone(), i.clone()); + }); + r.column_mut(c + 1).zip_apply(&self.vsr.column(c), |i, r| { + *i = Complex::new(r.clone(), -i.re.clone()); + }); + + c += 2; + } else { + c += 1; + } + } + + (l, r) + } + + /// Outputs the unprocessed (almost) version of generalized eigenvalues ((alphar, alphai), beta) + /// straight from LAPACK + #[must_use] + pub fn raw_eigenvalues(&self) -> OVector<(Complex, T), D> + where + DefaultAllocator: Allocator<(Complex, T), D>, + { + let mut out = Matrix::from_element_generic( + self.vsl.shape_generic().0, + Const::<1>, + (Complex::zero(), T::RealField::zero()), + ); + + for i in 0..out.len() { + out[i] = (Complex::new(self.alphar[i], self.alphai[i]), self.beta[i]) + } + + out + } +} + +/* + * + * Lapack functions dispatch. + * + */ +/// Trait implemented by scalars for which Lapack implements the RealField GeneralizedEigen decomposition. +pub trait GeneralizedEigenScalar: Scalar { + #[allow(missing_docs)] + fn xggev( + jobvsl: u8, + jobvsr: u8, + n: i32, + a: &mut [Self], + lda: i32, + b: &mut [Self], + ldb: i32, + alphar: &mut [Self], + alphai: &mut [Self], + beta: &mut [Self], + vsl: &mut [Self], + ldvsl: i32, + vsr: &mut [Self], + ldvsr: i32, + work: &mut [Self], + lwork: i32, + info: &mut i32, + ); + + #[allow(missing_docs)] + fn xggev_work_size( + jobvsl: u8, + jobvsr: u8, + n: i32, + a: &mut [Self], + lda: i32, + b: &mut [Self], + ldb: i32, + alphar: &mut [Self], + alphai: &mut [Self], + beta: &mut [Self], + vsl: &mut [Self], + ldvsl: i32, + vsr: &mut [Self], + ldvsr: i32, + info: &mut i32, + ) -> i32; +} + +macro_rules! generalized_eigen_scalar_impl ( + ($N: ty, $xggev: path) => ( + impl GeneralizedEigenScalar for $N { + #[inline] + fn xggev(jobvsl: u8, + jobvsr: u8, + n: i32, + a: &mut [$N], + lda: i32, + b: &mut [$N], + ldb: i32, + alphar: &mut [$N], + alphai: &mut [$N], + beta : &mut [$N], + vsl: &mut [$N], + ldvsl: i32, + vsr: &mut [$N], + ldvsr: i32, + work: &mut [$N], + lwork: i32, + info: &mut i32) { + unsafe { $xggev(jobvsl, jobvsr, n, a, lda, b, ldb, alphar, alphai, beta, vsl, ldvsl, vsr, ldvsr, work, lwork, info); } + } + + + #[inline] + fn xggev_work_size(jobvsl: u8, + jobvsr: u8, + n: i32, + a: &mut [$N], + lda: i32, + b: &mut [$N], + ldb: i32, + alphar: &mut [$N], + alphai: &mut [$N], + beta : &mut [$N], + vsl: &mut [$N], + ldvsl: i32, + vsr: &mut [$N], + ldvsr: i32, + info: &mut i32) + -> i32 { + let mut work = [ Zero::zero() ]; + let lwork = -1 as i32; + + unsafe { $xggev(jobvsl, jobvsr, n, a, lda, b, ldb, alphar, alphai, beta, vsl, ldvsl, vsr, ldvsr, &mut work, lwork, info); } + ComplexHelper::real_part(work[0]) as i32 + } + } + ) +); + +generalized_eigen_scalar_impl!(f32, lapack::sggev); +generalized_eigen_scalar_impl!(f64, lapack::dggev); diff --git a/nalgebra-lapack/src/lib.rs b/nalgebra-lapack/src/lib.rs index 9cf0d73d..ea2e2b53 100644 --- a/nalgebra-lapack/src/lib.rs +++ b/nalgebra-lapack/src/lib.rs @@ -83,9 +83,11 @@ mod lapack_check; mod cholesky; mod eigen; +mod generalized_eigenvalues; mod hessenberg; mod lu; mod qr; +mod qz; mod schur; mod svd; mod symmetric_eigen; @@ -94,9 +96,11 @@ use num_complex::Complex; pub use self::cholesky::{Cholesky, CholeskyScalar}; pub use self::eigen::Eigen; +pub use self::generalized_eigenvalues::GeneralizedEigen; pub use self::hessenberg::Hessenberg; pub use self::lu::{LUScalar, LU}; pub use self::qr::QR; +pub use self::qz::QZ; pub use self::schur::Schur; pub use self::svd::SVD; pub use self::symmetric_eigen::SymmetricEigen; diff --git a/nalgebra-lapack/src/qr.rs b/nalgebra-lapack/src/qr.rs index 895e34f3..ade2e452 100644 --- a/nalgebra-lapack/src/qr.rs +++ b/nalgebra-lapack/src/qr.rs @@ -126,7 +126,7 @@ where let mut q = self .qr - .generic_slice((0, 0), (nrows, min_nrows_ncols)) + .generic_view((0, 0), (nrows, min_nrows_ncols)) .into_owned(); let mut info = 0; diff --git a/nalgebra-lapack/src/qz.rs b/nalgebra-lapack/src/qz.rs new file mode 100644 index 00000000..99f3c374 --- /dev/null +++ b/nalgebra-lapack/src/qz.rs @@ -0,0 +1,321 @@ +#[cfg(feature = "serde-serialize")] +use serde::{Deserialize, Serialize}; + +use num::Zero; +use num_complex::Complex; + +use simba::scalar::RealField; + +use crate::ComplexHelper; +use na::allocator::Allocator; +use na::dimension::{Const, Dim}; +use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar}; + +use lapack; + +/// QZ decomposition of a pair of N*N square matrices. +/// +/// Retrieves the left and right matrices of Schur Vectors (VSL and VSR) +/// the upper-quasitriangular matrix `S` and upper triangular matrix `T` such that the +/// decomposed input matrix `a` equals `VSL * S * VSL.transpose()` and +/// decomposed input matrix `b` equals `VSL * T * VSL.transpose()`. +#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize", + serde( + bound(serialize = "DefaultAllocator: Allocator + Allocator, + OVector: Serialize, + OMatrix: Serialize") + ) +)] +#[cfg_attr( + feature = "serde-serialize", + serde( + bound(deserialize = "DefaultAllocator: Allocator + Allocator, + OVector: Deserialize<'de>, + OMatrix: Deserialize<'de>") + ) +)] +#[derive(Clone, Debug)] +pub struct QZ +where + DefaultAllocator: Allocator + Allocator, +{ + alphar: OVector, + alphai: OVector, + beta: OVector, + vsl: OMatrix, + s: OMatrix, + vsr: OMatrix, + t: OMatrix, +} + +impl Copy for QZ +where + DefaultAllocator: Allocator + Allocator, + OMatrix: Copy, + OVector: Copy, +{ +} + +impl QZ +where + DefaultAllocator: Allocator + Allocator, +{ + /// Attempts to compute the QZ decomposition of input real square matrices `a` and `b`. + /// + /// i.e retrieves the left and right matrices of Schur Vectors (VSL and VSR) + /// the upper-quasitriangular matrix `S` and upper triangular matrix `T` such that the + /// decomposed matrix `a` equals `VSL * S * VSL.transpose()` and + /// decomposed matrix `b` equals `VSL * T * VSL.transpose()`. + /// + /// Panics if the method did not converge. + pub fn new(a: OMatrix, b: OMatrix) -> Self { + Self::try_new(a, b).expect("QZ decomposition: convergence failed.") + } + + /// Computes the decomposition of input matrices `a` and `b` into a pair of matrices of Schur vectors + /// , a quasi-upper triangular matrix and an upper-triangular matrix . + /// + /// Returns `None` if the method did not converge. + pub fn try_new(mut a: OMatrix, mut b: OMatrix) -> Option { + assert!( + a.is_square() && b.is_square(), + "Unable to compute the qz decomposition of non-square matrices." + ); + + assert!( + a.shape_generic() == b.shape_generic(), + "Unable to compute the qz decomposition of two square matrices of different dimensions." + ); + + let (nrows, ncols) = a.shape_generic(); + let n = nrows.value(); + + let mut info = 0; + + let mut alphar = Matrix::zeros_generic(nrows, Const::<1>); + let mut alphai = Matrix::zeros_generic(nrows, Const::<1>); + let mut beta = Matrix::zeros_generic(nrows, Const::<1>); + let mut vsl = Matrix::zeros_generic(nrows, ncols); + let mut vsr = Matrix::zeros_generic(nrows, ncols); + // Placeholders: + let mut bwork = [0i32]; + let mut unused = 0; + + let lwork = T::xgges_work_size( + b'V', + b'V', + b'N', + n as i32, + a.as_mut_slice(), + n as i32, + b.as_mut_slice(), + n as i32, + &mut unused, + alphar.as_mut_slice(), + alphai.as_mut_slice(), + beta.as_mut_slice(), + vsl.as_mut_slice(), + n as i32, + vsr.as_mut_slice(), + n as i32, + &mut bwork, + &mut info, + ); + lapack_check!(info); + + let mut work = vec![T::zero(); lwork as usize]; + + T::xgges( + b'V', + b'V', + b'N', + n as i32, + a.as_mut_slice(), + n as i32, + b.as_mut_slice(), + n as i32, + &mut unused, + alphar.as_mut_slice(), + alphai.as_mut_slice(), + beta.as_mut_slice(), + vsl.as_mut_slice(), + n as i32, + vsr.as_mut_slice(), + n as i32, + &mut work, + lwork, + &mut bwork, + &mut info, + ); + lapack_check!(info); + + Some(QZ { + alphar, + alphai, + beta, + vsl, + s: a, + vsr, + t: b, + }) + } + + /// Retrieves the left and right matrices of Schur Vectors (VSL and VSR) + /// the upper-quasitriangular matrix `S` and upper triangular matrix `T` such that the + /// decomposed input matrix `a` equals `VSL * S * VSL.transpose()` and + /// decomposed input matrix `b` equals `VSL * T * VSL.transpose()`. + pub fn unpack( + self, + ) -> ( + OMatrix, + OMatrix, + OMatrix, + OMatrix, + ) { + (self.vsl, self.s, self.t, self.vsr) + } + + /// outputs the unprocessed (almost) version of generalized eigenvalues ((alphar, alpai), beta) + /// straight from LAPACK + #[must_use] + pub fn raw_eigenvalues(&self) -> OVector<(Complex, T), D> + where + DefaultAllocator: Allocator<(Complex, T), D>, + { + let mut out = Matrix::from_element_generic( + self.vsl.shape_generic().0, + Const::<1>, + (Complex::zero(), T::RealField::zero()), + ); + + for i in 0..out.len() { + out[i] = ( + Complex::new(self.alphar[i].clone(), self.alphai[i].clone()), + self.beta[i].clone(), + ) + } + + out + } +} + +/* + * + * Lapack functions dispatch. + * + */ +/// Trait implemented by scalars for which Lapack implements the RealField QZ decomposition. +pub trait QZScalar: Scalar { + #[allow(missing_docs)] + fn xgges( + jobvsl: u8, + jobvsr: u8, + sort: u8, + // select: ??? + n: i32, + a: &mut [Self], + lda: i32, + b: &mut [Self], + ldb: i32, + sdim: &mut i32, + alphar: &mut [Self], + alphai: &mut [Self], + beta: &mut [Self], + vsl: &mut [Self], + ldvsl: i32, + vsr: &mut [Self], + ldvsr: i32, + work: &mut [Self], + lwork: i32, + bwork: &mut [i32], + info: &mut i32, + ); + + #[allow(missing_docs)] + fn xgges_work_size( + jobvsl: u8, + jobvsr: u8, + sort: u8, + // select: ??? + n: i32, + a: &mut [Self], + lda: i32, + b: &mut [Self], + ldb: i32, + sdim: &mut i32, + alphar: &mut [Self], + alphai: &mut [Self], + beta: &mut [Self], + vsl: &mut [Self], + ldvsl: i32, + vsr: &mut [Self], + ldvsr: i32, + bwork: &mut [i32], + info: &mut i32, + ) -> i32; +} + +macro_rules! qz_scalar_impl ( + ($N: ty, $xgges: path) => ( + impl QZScalar for $N { + #[inline] + fn xgges(jobvsl: u8, + jobvsr: u8, + sort: u8, + // select: ??? + n: i32, + a: &mut [$N], + lda: i32, + b: &mut [$N], + ldb: i32, + sdim: &mut i32, + alphar: &mut [$N], + alphai: &mut [$N], + beta : &mut [$N], + vsl: &mut [$N], + ldvsl: i32, + vsr: &mut [$N], + ldvsr: i32, + work: &mut [$N], + lwork: i32, + bwork: &mut [i32], + info: &mut i32) { + unsafe { $xgges(jobvsl, jobvsr, sort, None, n, a, lda, b, ldb, sdim, alphar, alphai, beta, vsl, ldvsl, vsr, ldvsr, work, lwork, bwork, info); } + } + + + #[inline] + fn xgges_work_size(jobvsl: u8, + jobvsr: u8, + sort: u8, + // select: ??? + n: i32, + a: &mut [$N], + lda: i32, + b: &mut [$N], + ldb: i32, + sdim: &mut i32, + alphar: &mut [$N], + alphai: &mut [$N], + beta : &mut [$N], + vsl: &mut [$N], + ldvsl: i32, + vsr: &mut [$N], + ldvsr: i32, + bwork: &mut [i32], + info: &mut i32) + -> i32 { + let mut work = [ Zero::zero() ]; + let lwork = -1 as i32; + + unsafe { $xgges(jobvsl, jobvsr, sort, None, n, a, lda, b, ldb, sdim, alphar, alphai, beta, vsl, ldvsl, vsr, ldvsr, &mut work, lwork, bwork, info); } + ComplexHelper::real_part(work[0]) as i32 + } + } + ) +); + +qz_scalar_impl!(f32, lapack::sgges); +qz_scalar_impl!(f64, lapack::dgges); diff --git a/nalgebra-lapack/src/svd.rs b/nalgebra-lapack/src/svd.rs index 972ffa1b..804284d9 100644 --- a/nalgebra-lapack/src/svd.rs +++ b/nalgebra-lapack/src/svd.rs @@ -157,7 +157,7 @@ macro_rules! svd_impl( let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols); { - let mut sres = res.generic_slice_mut((0, 0), (min_nrows_ncols, ncols)); + let mut sres = res.generic_view_mut((0, 0), (min_nrows_ncols, ncols)); sres.copy_from(&self.vt.rows_generic(0, min_nrows_ncols)); for i in 0 .. min_nrows_ncols.value() { @@ -183,7 +183,7 @@ macro_rules! svd_impl( let mut res: OMatrix<_, C, R> = Matrix::zeros_generic(ncols, nrows); { - let mut sres = res.generic_slice_mut((0, 0), (min_nrows_ncols, nrows)); + let mut sres = res.generic_view_mut((0, 0), (min_nrows_ncols, nrows)); self.u.columns_generic(0, min_nrows_ncols).transpose_to(&mut sres); for i in 0 .. min_nrows_ncols.value() { diff --git a/nalgebra-lapack/tests/linalg/cholesky.rs b/nalgebra-lapack/tests/linalg/cholesky.rs index 632347b8..0bf74dd4 100644 --- a/nalgebra-lapack/tests/linalg/cholesky.rs +++ b/nalgebra-lapack/tests/linalg/cholesky.rs @@ -58,8 +58,8 @@ proptest! { let sol1 = chol.solve(&b1).unwrap(); let sol2 = chol.solve(&b2).unwrap(); - prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-4)); + prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-4)); } } @@ -84,7 +84,7 @@ proptest! { let id1 = &m * &m1; let id2 = &m1 * &m; - prop_assert!(id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)) + prop_assert!(id1.is_identity(1.0e-4) && id2.is_identity(1.0e-4)) } } } diff --git a/nalgebra-lapack/tests/linalg/complex_eigen.rs b/nalgebra-lapack/tests/linalg/complex_eigen.rs new file mode 100644 index 00000000..aa3474b9 --- /dev/null +++ b/nalgebra-lapack/tests/linalg/complex_eigen.rs @@ -0,0 +1,47 @@ +use na::Matrix3; +use nalgebra_lapack::Eigen; +use num_complex::Complex; + +#[test] +fn complex_eigen() { + let m = Matrix3::::new( + 4.0 / 5.0, + -3.0 / 5.0, + 0.0, + 3.0 / 5.0, + 4.0 / 5.0, + 0.0, + 1.0, + 2.0, + 2.0, + ); + let eigen = Eigen::new(m, true, true).expect("Eigen Creation Failed!"); + let (some_eigenvalues, some_left_vec, some_right_vec) = eigen.get_complex_elements(); + let eigenvalues = some_eigenvalues.expect("Eigenvalues Failed"); + let _left_eigenvectors = some_left_vec.expect("Left Eigenvectors Failed"); + let eigenvectors = some_right_vec.expect("Right Eigenvectors Failed"); + + assert_relative_eq!( + eigenvalues[0].re, + Complex::::new(4.0 / 5.0, 3.0 / 5.0).re + ); + assert_relative_eq!( + eigenvalues[0].im, + Complex::::new(4.0 / 5.0, 3.0 / 5.0).im + ); + assert_relative_eq!( + eigenvalues[1].re, + Complex::::new(4.0 / 5.0, -3.0 / 5.0).re + ); + assert_relative_eq!( + eigenvalues[1].im, + Complex::::new(4.0 / 5.0, -3.0 / 5.0).im + ); + + assert_relative_eq!(eigenvectors[0][0].re, -12.0 / 32.7871926215100059134410999); + assert_relative_eq!(eigenvectors[0][0].im, -9.0 / 32.7871926215100059134410999); + assert_relative_eq!(eigenvectors[0][1].re, -9.0 / 32.7871926215100059134410999); + assert_relative_eq!(eigenvectors[0][1].im, 12.0 / 32.7871926215100059134410999); + assert_relative_eq!(eigenvectors[0][2].re, 25.0 / 32.7871926215100059134410999); + assert_relative_eq!(eigenvectors[0][2].im, 0.0); +} diff --git a/nalgebra-lapack/tests/linalg/generalized_eigenvalues.rs b/nalgebra-lapack/tests/linalg/generalized_eigenvalues.rs new file mode 100644 index 00000000..b0d9777c --- /dev/null +++ b/nalgebra-lapack/tests/linalg/generalized_eigenvalues.rs @@ -0,0 +1,72 @@ +use na::dimension::Const; +use na::{DMatrix, OMatrix}; +use nl::GeneralizedEigen; +use num_complex::Complex; +use simba::scalar::ComplexField; + +use crate::proptest::*; +use proptest::{prop_assert, prop_compose, proptest}; + +prop_compose! { + fn f64_dynamic_dim_squares() + (n in PROPTEST_MATRIX_DIM) + (a in matrix(PROPTEST_F64,n,n), b in matrix(PROPTEST_F64,n,n)) -> (DMatrix, DMatrix){ + (a,b) +}} + +proptest! { + #[test] + fn ge((a,b) in f64_dynamic_dim_squares()){ + + let a_c = a.clone().map(|x| Complex::new(x, 0.0)); + let b_c = b.clone().map(|x| Complex::new(x, 0.0)); + let n = a.shape_generic().0; + + let ge = GeneralizedEigen::new(a.clone(), b.clone()); + let (vsl,vsr) = ge.clone().eigenvectors(); + + + for (i,(alpha,beta)) in ge.raw_eigenvalues().iter().enumerate() { + let l_a = a_c.clone() * Complex::new(*beta, 0.0); + let l_b = b_c.clone() * *alpha; + + prop_assert!( + relative_eq!( + ((&l_a - &l_b)*vsr.column(i)).map(|x| x.modulus()), + OMatrix::zeros_generic(n, Const::<1>), + epsilon = 1.0e-5)); + + prop_assert!( + relative_eq!( + (vsl.column(i).adjoint()*(&l_a - &l_b)).map(|x| x.modulus()), + OMatrix::zeros_generic(Const::<1>, n), + epsilon = 1.0e-5)) + }; + } + + #[test] + fn ge_static(a in matrix4(), b in matrix4()) { + + let ge = GeneralizedEigen::new(a.clone(), b.clone()); + let a_c =a.clone().map(|x| Complex::new(x, 0.0)); + let b_c = b.clone().map(|x| Complex::new(x, 0.0)); + let (vsl,vsr) = ge.eigenvectors(); + let eigenvalues = ge.raw_eigenvalues(); + + for (i,(alpha,beta)) in eigenvalues.iter().enumerate() { + let l_a = a_c.clone() * Complex::new(*beta, 0.0); + let l_b = b_c.clone() * *alpha; + + prop_assert!( + relative_eq!( + ((&l_a - &l_b)*vsr.column(i)).map(|x| x.modulus()), + OMatrix::zeros_generic(Const::<4>, Const::<1>), + epsilon = 1.0e-5)); + prop_assert!( + relative_eq!((vsl.column(i).adjoint()*(&l_a - &l_b)).map(|x| x.modulus()), + OMatrix::zeros_generic(Const::<1>, Const::<4>), + epsilon = 1.0e-5)) + } + } + +} diff --git a/nalgebra-lapack/tests/linalg/lu.rs b/nalgebra-lapack/tests/linalg/lu.rs index 9665964e..b9d45208 100644 --- a/nalgebra-lapack/tests/linalg/lu.rs +++ b/nalgebra-lapack/tests/linalg/lu.rs @@ -51,10 +51,10 @@ proptest! { let tr_sol1 = lup.solve_transpose(&b1).unwrap(); let tr_sol2 = lup.solve_transpose(&b2).unwrap(); - prop_assert!(relative_eq!(&m * sol1, b1, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(&m * sol2, b2, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(&m * sol1, b1, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(&m * sol2, b2, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-5)); } #[test] @@ -68,10 +68,10 @@ proptest! { let tr_sol1 = lup.solve_transpose(&b1).unwrap(); let tr_sol2 = lup.solve_transpose(&b2).unwrap(); - prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-5)); } #[test] diff --git a/nalgebra-lapack/tests/linalg/mod.rs b/nalgebra-lapack/tests/linalg/mod.rs index a6742217..92425293 100644 --- a/nalgebra-lapack/tests/linalg/mod.rs +++ b/nalgebra-lapack/tests/linalg/mod.rs @@ -1,6 +1,9 @@ mod cholesky; +mod complex_eigen; +mod generalized_eigenvalues; mod lu; mod qr; +mod qz; mod real_eigensystem; mod schur; mod svd; diff --git a/nalgebra-lapack/tests/linalg/qz.rs b/nalgebra-lapack/tests/linalg/qz.rs new file mode 100644 index 00000000..c7a702ca --- /dev/null +++ b/nalgebra-lapack/tests/linalg/qz.rs @@ -0,0 +1,34 @@ +use na::DMatrix; +use nl::QZ; + +use crate::proptest::*; +use proptest::{prop_assert, prop_compose, proptest}; + +prop_compose! { + fn f64_dynamic_dim_squares() + (n in PROPTEST_MATRIX_DIM) + (a in matrix(PROPTEST_F64,n,n), b in matrix(PROPTEST_F64,n,n)) -> (DMatrix, DMatrix){ + (a,b) +}} + +proptest! { + #[test] + fn qz((a,b) in f64_dynamic_dim_squares()) { + + let qz = QZ::new(a.clone(), b.clone()); + let (vsl,s,t,vsr) = qz.clone().unpack(); + + prop_assert!(relative_eq!(&vsl * s * vsr.transpose(), a, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(vsl * t * vsr.transpose(), b, epsilon = 1.0e-7)); + + } + + #[test] + fn qz_static(a in matrix4(), b in matrix4()) { + let qz = QZ::new(a.clone(), b.clone()); + let (vsl,s,t,vsr) = qz.unpack(); + + prop_assert!(relative_eq!(&vsl * s * vsr.transpose(), a, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(vsl * t * vsr.transpose(), b, epsilon = 1.0e-7)); + } +} diff --git a/nalgebra-lapack/tests/linalg/real_eigensystem.rs b/nalgebra-lapack/tests/linalg/real_eigensystem.rs index 3d1c91eb..599d1b2a 100644 --- a/nalgebra-lapack/tests/linalg/real_eigensystem.rs +++ b/nalgebra-lapack/tests/linalg/real_eigensystem.rs @@ -13,30 +13,36 @@ proptest! { let m = DMatrix::::new_random(n, n); if let Some(eig) = Eigen::new(m.clone(), true, true) { - let eigvals = DMatrix::from_diagonal(&eig.eigenvalues); - let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap(); - let scaled_eigvectors = eig.eigenvectors.as_ref().unwrap() * &eigvals; + // TODO: test the complex case too. + if eig.eigenvalues_are_real() { + let eigvals = DMatrix::from_diagonal(&eig.eigenvalues_re); + let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap(); + let scaled_eigvectors = eig.eigenvectors.as_ref().unwrap() * &eigvals; - let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.as_ref().unwrap(); - let scaled_left_eigvectors = eig.left_eigenvectors.as_ref().unwrap() * &eigvals; + let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.as_ref().unwrap(); + let scaled_left_eigvectors = eig.left_eigenvectors.as_ref().unwrap() * &eigvals; - prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-5)); + } } } #[test] fn eigensystem_static(m in matrix4()) { if let Some(eig) = Eigen::new(m, true, true) { - let eigvals = Matrix4::from_diagonal(&eig.eigenvalues); - let transformed_eigvectors = m * eig.eigenvectors.unwrap(); - let scaled_eigvectors = eig.eigenvectors.unwrap() * eigvals; + // TODO: test the complex case too. + if eig.eigenvalues_are_real() { + let eigvals = Matrix4::from_diagonal(&eig.eigenvalues_re); + let transformed_eigvectors = m * eig.eigenvectors.unwrap(); + let scaled_eigvectors = eig.eigenvectors.unwrap() * eigvals; - let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.unwrap(); - let scaled_left_eigvectors = eig.left_eigenvectors.unwrap() * eigvals; + let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.unwrap(); + let scaled_left_eigvectors = eig.left_eigenvectors.unwrap() * eigvals; - prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-7)); - prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-7)); + prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-5)); + prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-5)); + } } } } diff --git a/nalgebra-lapack/tests/linalg/schur.rs b/nalgebra-lapack/tests/linalg/schur.rs index 0fd1cc33..ee7bad90 100644 --- a/nalgebra-lapack/tests/linalg/schur.rs +++ b/nalgebra-lapack/tests/linalg/schur.rs @@ -11,14 +11,17 @@ proptest! { let n = cmp::max(1, cmp::min(n, 10)); let m = DMatrix::::new_random(n, n); - let (vecs, vals) = Schur::new(m.clone()).unpack(); - - prop_assert!(relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)) + if let Some(schur) = Schur::try_new(m.clone()) { + let (vecs, vals) = schur.unpack(); + prop_assert!(relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-5)) + } } #[test] fn schur_static(m in matrix4()) { - let (vecs, vals) = Schur::new(m.clone()).unpack(); - prop_assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)) + if let Some(schur) = Schur::try_new(m.clone()) { + let (vecs, vals) = schur.unpack(); + prop_assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-5)) + } } } diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index bd37b689..8124ec78 100644 --- a/nalgebra-macros/Cargo.toml +++ b/nalgebra-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-macros" -version = "0.1.0" +version = "0.2.1" authors = [ "Andreas Longva", "Sébastien Crozet " ] edition = "2018" description = "Procedural macros for nalgebra" @@ -21,5 +21,5 @@ quote = "1.0" proc-macro2 = "1.0" [dev-dependencies] -nalgebra = { version = "0.30.0", path = ".." } +nalgebra = { version = "0.32.0", path = ".." } trybuild = "1.0.42" diff --git a/nalgebra-macros/LICENSE b/nalgebra-macros/LICENSE new file mode 120000 index 00000000..ea5b6064 --- /dev/null +++ b/nalgebra-macros/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 0d7889ae..827d6080 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -191,8 +191,8 @@ pub fn dmatrix(stream: TokenStream) -> TokenStream { let output = quote! { nalgebra::DMatrix::<_> ::from_vec_storage(nalgebra::VecStorage::new( - nalgebra::Dynamic::new(#row_dim), - nalgebra::Dynamic::new(#col_dim), + nalgebra::Dyn(#row_dim), + nalgebra::Dyn(#col_dim), vec!#array_tokens)) }; @@ -223,7 +223,7 @@ impl Parse for Vector { elements: Vec::new(), }) } else { - let elements = MatrixRowSyntax::parse_separated_nonempty(input)? + let elements = MatrixRowSyntax::parse_terminated(input)? .into_iter() .collect(); Ok(Self { elements }) @@ -285,7 +285,7 @@ pub fn dvector(stream: TokenStream) -> TokenStream { let output = quote! { nalgebra::DVector::<_> ::from_vec_storage(nalgebra::VecStorage::new( - nalgebra::Dynamic::new(#len), + nalgebra::Dyn(#len), nalgebra::Const::<1>, vec!#array_tokens)) }; diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 0e52da1f..ed6353d0 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -94,6 +94,12 @@ fn dmatrix_small_dims_exhaustive() { DMatrix::from_row_slice(4, 4, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])); } +#[test] +fn matrix_trailing_semi() { + matrix![1, 2;]; + dmatrix![1, 2;]; +} + // Skip rustfmt because it just makes the test bloated without making it more readable #[rustfmt::skip] #[test] @@ -151,6 +157,13 @@ fn dvector_small_dims_exhaustive() { assert_eq_and_type!(dvector![1, 2, 3, 4, 5, 6], DVector::from_column_slice(&[1, 2, 3, 4, 5, 6])); } +#[test] +fn vector_trailing_comma() { + vector![1, 2,]; + point![1, 2,]; + dvector![1, 2,]; +} + #[test] fn matrix_trybuild_tests() { let t = trybuild::TestCases::new(); diff --git a/nalgebra-sparse/Cargo.toml b/nalgebra-sparse/Cargo.toml index eec7326d..3a1bd20d 100644 --- a/nalgebra-sparse/Cargo.toml +++ b/nalgebra-sparse/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-sparse" -version = "0.6.0" +version = "0.9.0" authors = [ "Andreas Longva", "Sébastien Crozet " ] edition = "2018" description = "Sparse matrix computation based on nalgebra." @@ -24,7 +24,7 @@ io = [ "pest", "pest_derive" ] slow-tests = [] [dependencies] -nalgebra = { version="0.30", path = "../" } +nalgebra = { version="0.32", path = "../" } num-traits = { version = "0.2", default-features = false } proptest = { version = "1.0", optional = true } matrixcompare-core = { version = "0.1.0", optional = true } @@ -35,9 +35,10 @@ serde = { version = "1.0", default-features = false, features = [ "derive" ], op [dev-dependencies] itertools = "0.10" matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] } -nalgebra = { version="0.30", path = "../", features = ["compare"] } +nalgebra = { version="0.32", path = "../", features = ["compare"] } +tempfile = "3.3" serde_json = "1.0" [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs -features = [ "proptest-support", "compare" ] +features = [ "proptest-support", "compare", "io"] diff --git a/nalgebra-sparse/LICENSE b/nalgebra-sparse/LICENSE new file mode 120000 index 00000000..ea5b6064 --- /dev/null +++ b/nalgebra-sparse/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/nalgebra-sparse/src/convert/serial.rs b/nalgebra-sparse/src/convert/serial.rs index 50fc50e4..571e3376 100644 --- a/nalgebra-sparse/src/convert/serial.rs +++ b/nalgebra-sparse/src/convert/serial.rs @@ -306,7 +306,7 @@ where |val| sorted_vals.push(val), &idx_workspace[..count], &values_workspace[..count], - &Add::add, + Add::add, ); let new_col_count = sorted_minor_idx.len() - sorted_ja_current_len; diff --git a/nalgebra-sparse/src/coo.rs b/nalgebra-sparse/src/coo.rs index 2b302e37..6f969814 100644 --- a/nalgebra-sparse/src/coo.rs +++ b/nalgebra-sparse/src/coo.rs @@ -160,6 +160,25 @@ impl CooMatrix { } } + /// Try to construct a COO matrix from the given dimensions and a finite iterator of + /// (i, j, v) triplets. + /// + /// Returns an error if either row or column indices contain indices out of bounds. + /// Note that the COO format inherently supports duplicate entries, but they are not + /// eagerly summed. + /// + /// Implementation note: + /// Calls try_from_triplets so each value is scanned twice. + pub fn try_from_triplets_iter( + nrows: usize, + ncols: usize, + triplets: impl IntoIterator, + ) -> Result { + let (row_indices, (col_indices, values)) = + triplets.into_iter().map(|(r, c, v)| (r, (c, v))).unzip(); + Self::try_from_triplets(nrows, ncols, row_indices, col_indices, values) + } + /// An iterator over triplets (i, j, v). // TODO: Consider giving the iterator a concrete type instead of impl trait...? pub fn triplet_iter(&self) -> impl Iterator { @@ -170,6 +189,16 @@ impl CooMatrix { .map(|((i, j), v)| (*i, *j, v)) } + /// A mutable iterator over triplets (i, j, v). + // TODO: Consider giving the iterator a concrete type instead of impl trait...? + pub fn triplet_iter_mut(&mut self) -> impl Iterator { + self.row_indices + .iter() + .zip(&self.col_indices) + .zip(self.values.iter_mut()) + .map(|((i, j), v)| (*i, *j, v)) + } + /// Reserves capacity for COO matrix by at least `additional` elements. /// /// This increase the capacities of triplet holding arrays by reserving more space to avoid @@ -211,6 +240,13 @@ impl CooMatrix { self.values.push(v); } + /// Clear all triplets from the matrix. + pub fn clear_triplets(&mut self) { + self.col_indices.clear(); + self.row_indices.clear(); + self.values.clear(); + } + /// The number of rows in the matrix. #[inline] #[must_use] diff --git a/nalgebra-sparse/src/cs.rs b/nalgebra-sparse/src/cs.rs index 474eb2c0..30bdc9b8 100644 --- a/nalgebra-sparse/src/cs.rs +++ b/nalgebra-sparse/src/cs.rs @@ -1,4 +1,3 @@ -use std::mem::replace; use std::ops::Range; use num_traits::One; @@ -226,6 +225,15 @@ impl CsMatrix { } } +impl Default for CsMatrix { + fn default() -> Self { + Self { + sparsity_pattern: Default::default(), + values: vec![], + } + } +} + impl CsMatrix { #[inline] pub fn identity(n: usize) -> Self { @@ -360,7 +368,7 @@ where if let Some(minor_indices) = lane { let count = minor_indices.len(); - let remaining = replace(&mut self.remaining_values, &mut []); + let remaining = std::mem::take(&mut self.remaining_values); let (values_in_lane, remaining) = remaining.split_at_mut(count); self.remaining_values = remaining; self.current_lane_idx += 1; @@ -494,7 +502,7 @@ where assert_eq!(source_minor_indices.len(), values.len()); let nnz = values.len(); - // Count the number of occurences of each minor index + // Count the number of occurrences of each minor index let mut minor_counts = vec![0; minor_dim]; for minor_idx in source_minor_indices { minor_counts[*minor_idx] += 1; @@ -569,7 +577,7 @@ where } else if sort { unreachable!("Internal error: Sorting currently not supported if no values are present."); } - if major_offsets.len() == 0 { + if major_offsets.is_empty() { return Err(SparseFormatError::from_kind_and_msg( SparseFormatErrorKind::InvalidStructure, "Number of offsets should be greater than 0.", @@ -615,12 +623,12 @@ where )); } - let minor_idx_in_lane = minor_indices.get(range_start..range_end).ok_or( + let minor_idx_in_lane = minor_indices.get(range_start..range_end).ok_or_else(|| { SparseFormatError::from_kind_and_msg( SparseFormatErrorKind::IndexOutOfBounds, "A major offset is out of bounds.", - ), - )?; + ) + })?; // We test for in-bounds, uniqueness and monotonicity at the same time // to ensure that we only visit each minor index once @@ -653,9 +661,9 @@ where if !monotonic && sort { let range_size = range_end - range_start; minor_index_permutation.resize(range_size, 0); - compute_sort_permutation(&mut minor_index_permutation, &minor_idx_in_lane); + compute_sort_permutation(&mut minor_index_permutation, minor_idx_in_lane); minor_idx_buffer.clear(); - minor_idx_buffer.extend_from_slice(&minor_idx_in_lane); + minor_idx_buffer.extend_from_slice(minor_idx_in_lane); apply_permutation( &mut minor_indices[range_start..range_end], &minor_idx_buffer, diff --git a/nalgebra-sparse/src/csc.rs b/nalgebra-sparse/src/csc.rs index d926dafb..de4af43d 100644 --- a/nalgebra-sparse/src/csc.rs +++ b/nalgebra-sparse/src/csc.rs @@ -24,6 +24,7 @@ use std::slice::{Iter, IterMut}; /// # Usage /// /// ``` +/// use nalgebra_sparse::coo::CooMatrix; /// use nalgebra_sparse::csc::CscMatrix; /// use nalgebra::{DMatrix, Matrix3x4}; /// use matrixcompare::assert_matrix_eq; @@ -32,8 +33,9 @@ use std::slice::{Iter, IterMut}; /// // change the sparsity pattern of the matrix after it has been constructed. The easiest /// // way to construct a CSC matrix is to first incrementally construct a COO matrix, /// // and then convert it to CSC. -/// # use nalgebra_sparse::coo::CooMatrix; -/// # let coo = CooMatrix::::new(3, 3); +/// +/// let mut coo = CooMatrix::::new(3, 3); +/// coo.push(2, 0, 1.0); /// let csc = CscMatrix::from(&coo); /// /// // Alternatively, a CSC matrix can be constructed directly from raw CSC data. @@ -156,7 +158,7 @@ impl CscMatrix { /// an error is returned to indicate the failure. /// /// An error is returned if the data given does not conform to the CSC storage format. - /// See the documentation for [CscMatrix](struct.CscMatrix.html) for more information. + /// See the documentation for [`CscMatrix`] for more information. pub fn try_from_csc_data( num_rows: usize, num_cols: usize, @@ -182,7 +184,7 @@ impl CscMatrix { /// /// An error is returned if the data given does not conform to the CSC storage format /// with the exception of having unsorted row indices and values. - /// See the documentation for [CscMatrix](struct.CscMatrix.html) for more information. + /// See the documentation for [`CscMatrix`] for more information. pub fn try_from_unsorted_csc_data( num_rows: usize, num_cols: usize, @@ -572,6 +574,14 @@ impl CscMatrix { } } +impl Default for CscMatrix { + fn default() -> Self { + Self { + cs: Default::default(), + } + } +} + /// Convert pattern format errors into more meaningful CSC-specific errors. /// /// This ensures that the terminology is consistent: we are talking about rows and columns, @@ -615,6 +625,15 @@ pub struct CscTripletIter<'a, T> { values_iter: Iter<'a, T>, } +impl<'a, T> Clone for CscTripletIter<'a, T> { + fn clone(&self) -> Self { + CscTripletIter { + pattern_iter: self.pattern_iter.clone(), + values_iter: self.values_iter.clone(), + } + } +} + impl<'a, T: Clone> CscTripletIter<'a, T> { /// Adapts the triplet iterator to return owned values. /// @@ -746,7 +765,7 @@ impl<'a, T> CscColMut<'a, T> { } } -/// Column iterator for [CscMatrix](struct.CscMatrix.html). +/// Column iterator for [`CscMatrix`]. pub struct CscColIter<'a, T> { lane_iter: CsLaneIter<'a, T>, } @@ -759,7 +778,7 @@ impl<'a, T> Iterator for CscColIter<'a, T> { } } -/// Mutable column iterator for [CscMatrix](struct.CscMatrix.html). +/// Mutable column iterator for [`CscMatrix`]. pub struct CscColIterMut<'a, T> { lane_iter: CsLaneIterMut<'a, T>, } diff --git a/nalgebra-sparse/src/csr.rs b/nalgebra-sparse/src/csr.rs index 90be35f1..7a38aeeb 100644 --- a/nalgebra-sparse/src/csr.rs +++ b/nalgebra-sparse/src/csr.rs @@ -25,6 +25,7 @@ use std::slice::{Iter, IterMut}; /// # Usage /// /// ``` +/// use nalgebra_sparse::coo::CooMatrix; /// use nalgebra_sparse::csr::CsrMatrix; /// use nalgebra::{DMatrix, Matrix3x4}; /// use matrixcompare::assert_matrix_eq; @@ -33,8 +34,9 @@ use std::slice::{Iter, IterMut}; /// // change the sparsity pattern of the matrix after it has been constructed. The easiest /// // way to construct a CSR matrix is to first incrementally construct a COO matrix, /// // and then convert it to CSR. -/// # use nalgebra_sparse::coo::CooMatrix; -/// # let coo = CooMatrix::::new(3, 3); +/// +/// let mut coo = CooMatrix::::new(3, 3); +/// coo.push(2, 0, 1.0); /// let csr = CsrMatrix::from(&coo); /// /// // Alternatively, a CSR matrix can be constructed directly from raw CSR data. @@ -157,7 +159,7 @@ impl CsrMatrix { /// an error is returned to indicate the failure. /// /// An error is returned if the data given does not conform to the CSR storage format. - /// See the documentation for [CsrMatrix](struct.CsrMatrix.html) for more information. + /// See the documentation for [`CsrMatrix`] for more information. pub fn try_from_csr_data( num_rows: usize, num_cols: usize, @@ -183,7 +185,7 @@ impl CsrMatrix { /// /// An error is returned if the data given does not conform to the CSR storage format /// with the exception of having unsorted column indices and values. - /// See the documentation for [CsrMatrix](struct.CsrMatrix.html) for more information. + /// See the documentation for [`CsrMatrix`] for more information. pub fn try_from_unsorted_csr_data( num_rows: usize, num_cols: usize, @@ -573,6 +575,14 @@ impl CsrMatrix { } } +impl Default for CsrMatrix { + fn default() -> Self { + Self { + cs: Default::default(), + } + } +} + /// Convert pattern format errors into more meaningful CSR-specific errors. /// /// This ensures that the terminology is consistent: we are talking about rows and columns, @@ -616,6 +626,15 @@ pub struct CsrTripletIter<'a, T> { values_iter: Iter<'a, T>, } +impl<'a, T> Clone for CsrTripletIter<'a, T> { + fn clone(&self) -> Self { + CsrTripletIter { + pattern_iter: self.pattern_iter.clone(), + values_iter: self.values_iter.clone(), + } + } +} + impl<'a, T: Clone> CsrTripletIter<'a, T> { /// Adapts the triplet iterator to return owned values. /// @@ -751,7 +770,7 @@ impl<'a, T> CsrRowMut<'a, T> { } } -/// Row iterator for [CsrMatrix](struct.CsrMatrix.html). +/// Row iterator for [`CsrMatrix`]. pub struct CsrRowIter<'a, T> { lane_iter: CsLaneIter<'a, T>, } @@ -764,7 +783,7 @@ impl<'a, T> Iterator for CsrRowIter<'a, T> { } } -/// Mutable row iterator for [CsrMatrix](struct.CsrMatrix.html). +/// Mutable row iterator for [`CsrMatrix`]. pub struct CsrRowIterMut<'a, T> { lane_iter: CsLaneIterMut<'a, T>, } diff --git a/nalgebra-sparse/src/factorization/cholesky.rs b/nalgebra-sparse/src/factorization/cholesky.rs index 1f653278..f84e621f 100644 --- a/nalgebra-sparse/src/factorization/cholesky.rs +++ b/nalgebra-sparse/src/factorization/cholesky.rs @@ -3,7 +3,7 @@ use crate::ops::serial::spsolve_csc_lower_triangular; use crate::ops::Op; use crate::pattern::SparsityPattern; use core::{iter, mem}; -use nalgebra::{DMatrix, DMatrixSlice, DMatrixSliceMut, RealField}; +use nalgebra::{DMatrix, DMatrixView, DMatrixViewMut, RealField}; use std::fmt::{Display, Formatter}; /// A symbolic sparse Cholesky factorization of a CSC matrix. @@ -264,7 +264,7 @@ impl CscCholesky { /// /// Panics if `B` is not square. #[must_use = "Did you mean to use solve_mut()?"] - pub fn solve<'a>(&'a self, b: impl Into>) -> DMatrix { + pub fn solve<'a>(&'a self, b: impl Into>) -> DMatrix { let b = b.into(); let mut output = b.clone_owned(); self.solve_mut(&mut output); @@ -278,7 +278,7 @@ impl CscCholesky { /// # Panics /// /// Panics if `b` is not square. - pub fn solve_mut<'a>(&'a self, b: impl Into>) { + pub fn solve_mut<'a>(&'a self, b: impl Into>) { let expect_msg = "If the Cholesky factorization succeeded,\ then the triangular solve should never fail"; // Solve LY = B diff --git a/nalgebra-sparse/src/io/matrix_market.rs b/nalgebra-sparse/src/io/matrix_market.rs index dea284ee..975c586e 100644 --- a/nalgebra-sparse/src/io/matrix_market.rs +++ b/nalgebra-sparse/src/io/matrix_market.rs @@ -1,9 +1,9 @@ //! Implementation of matrix market io code. //! //! See the [website](https://math.nist.gov/MatrixMarket/formats.html) or the [paper](https://www.researchgate.net/publication/2630533_The_Matrix_Market_Exchange_Formats_Initial_Design) for more details about matrix market. -use crate::coo::CooMatrix; use crate::SparseFormatError; use crate::SparseFormatErrorKind; +use crate::{CooMatrix, CscMatrix, CsrMatrix}; use nalgebra::Complex; use pest::iterators::Pairs; use pest::Parser; @@ -12,7 +12,8 @@ use std::convert::Infallible; use std::convert::TryFrom; use std::fmt; use std::fmt::Formatter; -use std::fs; +use std::fs::{self, File}; +use std::io::{BufWriter, Write}; use std::num::ParseIntError; use std::num::TryFromIntError; use std::path::Path; @@ -267,7 +268,7 @@ impl fmt::Display for MatrixMarketError { write!(f, "InvalidHeader,")?; } MatrixMarketErrorKind::EntryMismatch => { - write!(f, "EntryNumUnmatched,")?; + write!(f, "EntryMismatch,")?; } MatrixMarketErrorKind::TypeMismatch => { write!(f, "TypeMismatch,")?; @@ -288,7 +289,7 @@ impl fmt::Display for MatrixMarketError { write!(f, "NotLowerTriangle,")?; } MatrixMarketErrorKind::NonSquare => { - write!(f, "NotSquareMatrix,")?; + write!(f, "NonSquare,")?; } } write!(f, " message: {}", self.message) @@ -506,6 +507,21 @@ mod internal { fn negative(self) -> Result; /// When matrix is a Hermitian matrix, it will convert itself to its conjugate. fn conjugate(self) -> Result; + /// Returns the name of SupportedMatrixMarketScalar, used when write the matrix + fn typename() -> &'static str; + /// Write the data self to w + fn write_matrix_market(&self, w: W) -> Result<(), std::fmt::Error>; + } + + pub trait SupportedMatrixMarketExport { + /// iterate over triplets + fn triplet_iter(&self) -> Box + '_>; + /// number of rows + fn nrows(&self) -> usize; + /// number of columns + fn ncols(&self) -> usize; + /// number of non-zeros + fn nnz(&self) -> usize; } } @@ -557,6 +573,17 @@ macro_rules! mm_int_impl { fn negative(self) -> Result { Ok(-self) } + #[inline] + fn typename() -> &'static str { + "integer" + } + #[inline] + fn write_matrix_market( + &self, + mut w: W, + ) -> Result<(), std::fmt::Error> { + write!(w, "{}", self) + } } }; } @@ -602,6 +629,17 @@ macro_rules! mm_real_impl { fn negative(self) -> Result { Ok(-self) } + #[inline] + fn typename() -> &'static str { + "real" + } + #[inline] + fn write_matrix_market( + &self, + mut w: W, + ) -> Result<(), std::fmt::Error> { + write!(w, "{}", self) + } } }; } @@ -648,6 +686,17 @@ macro_rules! mm_complex_impl { fn negative(self) -> Result { Ok(-self) } + #[inline] + fn typename() -> &'static str { + "complex" + } + #[inline] + fn write_matrix_market( + &self, + mut w: W, + ) -> Result<(), std::fmt::Error> { + write!(w, "{} {}", self.re, self.im) + } } }; } @@ -697,6 +746,17 @@ macro_rules! mm_pattern_impl { format!("Pattern type has no negative"), )) } + #[inline] + fn typename() -> &'static str { + "pattern" + } + #[inline] + fn write_matrix_market( + &self, + mut _w: W, + ) -> Result<(), std::fmt::Error> { + Ok(()) + } } }; } @@ -715,6 +775,46 @@ mm_complex_impl!(f64); mm_pattern_impl!(()); +/// A marker trait for sparse matrix types that can be exported to the matrix market format. +/// +/// This is a sealed trait; it cannot be implemented by external crates. This is done in order to prevent leaking +/// some of the implementation details we currently rely on. We may relax this restriction in the future. +pub trait MatrixMarketExport: + internal::SupportedMatrixMarketExport +{ +} + +macro_rules! mm_matrix_impl { + ($T_MATRIX:ty) => { + impl MatrixMarketExport for $T_MATRIX {} + + impl internal::SupportedMatrixMarketExport + for $T_MATRIX + { + #[inline] + fn triplet_iter(&self) -> Box + '_> { + Box::new(self.triplet_iter()) + } + #[inline] + fn nrows(&self) -> usize { + self.nrows() + } + #[inline] + fn ncols(&self) -> usize { + self.ncols() + } + #[inline] + fn nnz(&self) -> usize { + self.nnz() + } + } + }; +} + +mm_matrix_impl!(CooMatrix); +mm_matrix_impl!(CsrMatrix); +mm_matrix_impl!(CscMatrix); + #[derive(Parser)] #[grammar = "io/matrix_market.pest"] struct MatrixMarketParser; @@ -1329,3 +1429,123 @@ fn next_dense_coordinate( } } } + +/// Save a sparse matrix as a Matrix Market format string. +/// +/// The exporter only writes the matrix into `coordinate` and `general` format. +/// +/// +/// Examples +/// -------- +/// ``` +/// # use nalgebra_sparse::CooMatrix; +/// # fn main() -> Result<(), Box> { +/// use nalgebra_sparse::io::{save_to_matrix_market_str}; +/// let expected_str = r#"%%matrixmarket matrix coordinate integer general +/// % matrixmarket file generated by nalgebra-sparse. +/// 5 4 2 +/// 1 1 10 +/// 2 3 5 +/// "#; +/// let row_indices = vec![0,1]; +/// let col_indices = vec![0,2]; +/// let values = vec![10,5]; +/// let matrix = CooMatrix::try_from_triplets(5,4,row_indices,col_indices,values)?; +/// let generated_matrixmarket_str = save_to_matrix_market_str(&matrix); +/// assert_eq!(expected_str,generated_matrixmarket_str); +/// # Ok(()) } +/// ``` +pub fn save_to_matrix_market_str(sparse_matrix: &S) -> String +where + T: MatrixMarketScalar, + S: MatrixMarketExport, +{ + let mut bytes = Vec::::new(); + // This will call impl Write for Vec + // The vector will grow as needed. + // So, unwrap here won't cause any issue. + save_to_matrix_market(&mut bytes, sparse_matrix).unwrap(); + + String::from_utf8(bytes) + .expect("Unexpected non UTF-8 data was generated when export to matrix market string") +} + +/// Save a sparse matrix to a Matrix Market format file. +/// +/// The exporter only saves the matrix with the `coordinate` and `general` matrix market formats. +/// +/// Errors +/// -------- +/// +/// See [MatrixMarketErrorKind] for a list of possible error conditions. +/// +/// Examples +/// -------- +/// ```no_run +/// # fn main() -> Result<(), Box> { +/// use nalgebra_sparse::io::{save_to_matrix_market_file,load_coo_from_matrix_market_str}; +/// let str = r#" +/// %%matrixmarket matrix coordinate integer general +/// 5 4 2 +/// 1 1 10 +/// 2 3 5 +/// "#; +/// let matrix = load_coo_from_matrix_market_str::(&str)?; +/// save_to_matrix_market_file(&matrix,"path/to/matrix.mtx")?; +/// # Ok(()) } +/// ``` +pub fn save_to_matrix_market_file(sparse_matrix: &S, path: P) -> Result<(), std::io::Error> +where + T: MatrixMarketScalar, + S: MatrixMarketExport, + P: AsRef, +{ + let file = File::create(path)?; + let mut file = BufWriter::new(file); + save_to_matrix_market(&mut file, sparse_matrix)?; + // Quote from BufWriter doc. + // > It is critical to call flush before BufWriter is dropped. Though dropping will attempt to flush the contents of the buffer, any errors that happen in the process of dropping will be ignored. Calling flush ensures that the buffer is empty and thus dropping will not even attempt file operations. + file.flush() + .expect("Unexpected error when flushing the buffer data to File"); + Ok(()) +} + +/// Save a sparse matrix to an [std::io::Write] instance. +/// +/// This is the most general save functionality. See [save_to_matrix_market_file] and +/// [save_to_matrix_market_str] for higher-level functionality. +pub fn save_to_matrix_market(mut w: W, sparse_matrix: &S) -> Result<(), std::io::Error> +where + T: MatrixMarketScalar, + S: MatrixMarketExport, + W: Write, +{ + // write header + writeln!( + w, + "%%matrixmarket matrix coordinate {} general", + T::typename() + )?; + + //write comment + writeln!(w, "% matrixmarket file generated by nalgebra-sparse.")?; + + // write shape information + writeln!( + w, + "{} {} {}", + sparse_matrix.nrows(), + sparse_matrix.ncols(), + sparse_matrix.nnz() + )?; + + //write triplets + let mut buffer = String::new(); + for (r, c, d) in sparse_matrix.triplet_iter() { + buffer.clear(); + d.write_matrix_market(&mut buffer) + .expect("Unexpected format error was generated when write to String"); + writeln!(w, "{} {} {}", r + 1, c + 1, buffer)?; + } + Ok(()) +} diff --git a/nalgebra-sparse/src/io/mod.rs b/nalgebra-sparse/src/io/mod.rs index 89b21ffb..1f4cb081 100644 --- a/nalgebra-sparse/src/io/mod.rs +++ b/nalgebra-sparse/src/io/mod.rs @@ -6,7 +6,7 @@ //! //! | Format | Import | Export | //! | ------------------------------------------------|------------|------------| -//! | [Matrix market](#matrix-market-format) | Yes | No | +//! | [Matrix market](#matrix-market-format) | Yes | Yes | //! //! [Matrix market]: https://math.nist.gov/MatrixMarket/formats.html //! @@ -19,10 +19,12 @@ //! which also uses the Matrix Market file format. //! //! We currently offer functionality for importing a Matrix market file to an instance of a -//! [CooMatrix](crate::CooMatrix) through the function [load_coo_from_matrix_market_file]. It is also possible to load -//! a matrix stored in the matrix market format with the function [load_coo_from_matrix_market_str]. -//! -//! Export is currently not implemented, but [planned](https://github.com/dimforge/nalgebra/issues/1037). +//! [CooMatrix](crate::CooMatrix) through the function [load_coo_from_matrix_market_file], +//! as well as functionality for writing various sparse matrices to the matrix market format +//! through [save_to_matrix_market_file]. It is also possible to load +//! a matrix stored as a string in the matrix market format with the function +//! [load_coo_from_matrix_market_str], or similarly write to a string with +//! [save_to_matrix_market_str]. //! //! Our implementation is based on the [format description](https://math.nist.gov/MatrixMarket/formats.html) //! on the Matrix Market website and the @@ -32,7 +34,8 @@ //! > "*The Matrix Market Exchange Formats: Initial Design.*" (1996). pub use self::matrix_market::{ - load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, MatrixMarketError, - MatrixMarketErrorKind, MatrixMarketScalar, + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, save_to_matrix_market, + save_to_matrix_market_file, save_to_matrix_market_str, MatrixMarketError, + MatrixMarketErrorKind, MatrixMarketExport, MatrixMarketScalar, }; mod matrix_market; diff --git a/nalgebra-sparse/src/lib.rs b/nalgebra-sparse/src/lib.rs index 8567261a..a022dedb 100644 --- a/nalgebra-sparse/src/lib.rs +++ b/nalgebra-sparse/src/lib.rs @@ -143,8 +143,6 @@ )] pub extern crate nalgebra as na; -#[cfg(feature = "io")] -extern crate pest; #[macro_use] #[cfg(feature = "io")] extern crate pest_derive; @@ -201,7 +199,7 @@ impl SparseFormatError { } } -/// The type of format error described by a [SparseFormatError](struct.SparseFormatError.html). +/// The type of format error described by a [`SparseFormatError`]. #[non_exhaustive] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum SparseFormatErrorKind { diff --git a/nalgebra-sparse/src/ops/impl_std_ops.rs b/nalgebra-sparse/src/ops/impl_std_ops.rs index 107c38ba..63b6d22c 100644 --- a/nalgebra-sparse/src/ops/impl_std_ops.rs +++ b/nalgebra-sparse/src/ops/impl_std_ops.rs @@ -3,14 +3,14 @@ use crate::csr::CsrMatrix; use crate::ops::serial::{ spadd_csc_prealloc, spadd_csr_prealloc, spadd_pattern, spmm_csc_dense, spmm_csc_pattern, - spmm_csc_prealloc, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc, + spmm_csc_prealloc_unchecked, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc_unchecked, }; use crate::ops::Op; use nalgebra::allocator::Allocator; use nalgebra::base::storage::RawStorage; use nalgebra::constraint::{DimEq, ShapeConstraint}; use nalgebra::{ - ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dynamic, Matrix, OMatrix, + ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dyn, Matrix, OMatrix, Scalar, U1, }; use num_traits::{One, Zero}; @@ -59,7 +59,7 @@ macro_rules! impl_sp_plus_minus { let mut result = $matrix_type::try_from_pattern_and_values(pattern, values) .unwrap(); $spadd_fn(T::zero(), &mut result, T::one(), Op::NoOp(&a)).unwrap(); - $spadd_fn(T::one(), &mut result, $factor * T::one(), Op::NoOp(&b)).unwrap(); + $spadd_fn(T::one(), &mut result, $factor, Op::NoOp(&b)).unwrap(); result }); @@ -112,9 +112,9 @@ macro_rules! impl_spmm { } } -impl_spmm!(CsrMatrix, spmm_csr_pattern, spmm_csr_prealloc); +impl_spmm!(CsrMatrix, spmm_csr_pattern, spmm_csr_prealloc_unchecked); // Need to switch order of operations for CSC pattern -impl_spmm!(CscMatrix, spmm_csc_pattern, spmm_csc_prealloc); +impl_spmm!(CscMatrix, spmm_csc_pattern, spmm_csc_prealloc_unchecked); /// Implements Scalar * Matrix operations for *concrete* scalar types. The reason this is necessary /// is that we are not able to implement Mul> for all T generically due to orphan rules. @@ -273,8 +273,8 @@ macro_rules! impl_spmm_cs_dense { // Implement ref-ref impl_spmm_cs_dense!(&'a $matrix_type_name, &'a Matrix, $spmm_fn, |lhs, rhs| { let (_, ncols) = rhs.shape_generic(); - let nrows = Dynamic::new(lhs.nrows()); - let mut result = OMatrix::::zeros_generic(nrows, ncols); + let nrows = Dyn(lhs.nrows()); + let mut result = OMatrix::::zeros_generic(nrows, ncols); $spmm_fn(T::zero(), &mut result, T::one(), Op::NoOp(lhs), Op::NoOp(rhs)); result }); @@ -302,21 +302,21 @@ macro_rules! impl_spmm_cs_dense { R: Dim, C: Dim, S: RawStorage, - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, // TODO: Is it possible to simplify these bounds? ShapeConstraint: - // Bounds so that we can turn OMatrix into a DMatrixSliceMut - DimEq>::Buffer as RawStorage>::RStride> - + DimEq - + DimEq>::Buffer as RawStorage>::CStride> + // Bounds so that we can turn OMatrix into a DMatrixSliceMut + DimEq>::Buffer as RawStorage>::RStride> + + DimEq + + DimEq>::Buffer as RawStorage>::CStride> // Bounds so that we can turn &Matrix into a DMatrixSlice + DimEq - + DimEq - + DimEq + + DimEq + + DimEq { // We need the column dimension to be generic, so that if RHS is a vector, then // we also get a vector (and not a matrix) - type Output = OMatrix; + type Output = OMatrix; fn mul(self, rhs: $dense_matrix_type) -> Self::Output { let $lhs = self; diff --git a/nalgebra-sparse/src/ops/mod.rs b/nalgebra-sparse/src/ops/mod.rs index 9a73148c..5fa72b2a 100644 --- a/nalgebra-sparse/src/ops/mod.rs +++ b/nalgebra-sparse/src/ops/mod.rs @@ -149,8 +149,8 @@ impl Op { #[must_use] pub fn as_ref(&self) -> Op<&T> { match self { - Op::NoOp(obj) => Op::NoOp(&obj), - Op::Transpose(obj) => Op::Transpose(&obj), + Op::NoOp(obj) => Op::NoOp(obj), + Op::Transpose(obj) => Op::Transpose(obj), } } diff --git a/nalgebra-sparse/src/ops/serial/cs.rs b/nalgebra-sparse/src/ops/serial/cs.rs index 86484053..a2a132fc 100644 --- a/nalgebra-sparse/src/ops/serial/cs.rs +++ b/nalgebra-sparse/src/ops/serial/cs.rs @@ -2,7 +2,7 @@ use crate::cs::CsMatrix; use crate::ops::serial::{OperationError, OperationErrorKind}; use crate::ops::Op; use crate::SparseEntryMut; -use nalgebra::{ClosedAdd, ClosedMul, DMatrixSlice, DMatrixSliceMut, Scalar}; +use nalgebra::{ClosedAdd, ClosedMul, DMatrixView, DMatrixViewMut, Scalar}; use num_traits::{One, Zero}; fn spmm_cs_unexpected_entry() -> OperationError { @@ -20,6 +20,51 @@ fn spmm_cs_unexpected_entry() -> OperationError { /// reversed (since transpose(AB) = transpose(B) * transpose(A) and CSC(A) = transpose(CSR(A)). /// /// We assume here that the matrices have already been verified to be dimensionally compatible. +pub fn spmm_cs_prealloc_unchecked( + beta: T, + c: &mut CsMatrix, + alpha: T, + a: &CsMatrix, + b: &CsMatrix, +) -> Result<(), OperationError> +where + T: Scalar + ClosedAdd + ClosedMul + Zero + One, +{ + assert_eq!(c.pattern().major_dim(), a.pattern().major_dim()); + assert_eq!(c.pattern().minor_dim(), b.pattern().minor_dim()); + let some_val = Zero::zero(); + let mut scratchpad_values: Vec = vec![some_val; b.pattern().minor_dim()]; + for i in 0..c.pattern().major_dim() { + let a_lane_i = a.get_lane(i).unwrap(); + + let mut c_lane_i = c.get_lane_mut(i).unwrap(); + + for (&k, a_ik) in a_lane_i.minor_indices().iter().zip(a_lane_i.values()) { + let b_lane_k = b.get_lane(k).unwrap(); + let alpha_aik = alpha.clone() * a_ik.clone(); + for (j, b_kj) in b_lane_k.minor_indices().iter().zip(b_lane_k.values()) { + // use a dense scatter vector to accumulate non-zeros quickly + unsafe { + *scratchpad_values.get_unchecked_mut(*j) += alpha_aik.clone() * b_kj.clone(); + } + } + } + + //Get indices from C pattern and gather from the dense scratchpad_values + let (indices, values) = c_lane_i.indices_and_values_mut(); + values + .iter_mut() + .zip(indices) + .for_each(|(output_ref, index)| unsafe { + *output_ref = beta.clone() * output_ref.clone() + + scratchpad_values.get_unchecked(*index).clone(); + *scratchpad_values.get_unchecked_mut(*index) = Zero::zero(); + }); + } + + Ok(()) +} + pub fn spmm_cs_prealloc( beta: T, c: &mut CsMatrix, @@ -131,10 +176,10 @@ where /// the transposed operation must be specified for the CSC matrix. pub fn spmm_cs_dense( beta: T, - mut c: DMatrixSliceMut<'_, T>, + mut c: DMatrixViewMut<'_, T>, alpha: T, a: Op<&CsMatrix>, - b: Op>, + b: Op>, ) where T: Scalar + ClosedAdd + ClosedMul + Zero + One, { diff --git a/nalgebra-sparse/src/ops/serial/csc.rs b/nalgebra-sparse/src/ops/serial/csc.rs index e5c9ae4e..85e02eb4 100644 --- a/nalgebra-sparse/src/ops/serial/csc.rs +++ b/nalgebra-sparse/src/ops/serial/csc.rs @@ -1,8 +1,10 @@ use crate::csc::CscMatrix; -use crate::ops::serial::cs::{spadd_cs_prealloc, spmm_cs_dense, spmm_cs_prealloc}; +use crate::ops::serial::cs::{ + spadd_cs_prealloc, spmm_cs_dense, spmm_cs_prealloc, spmm_cs_prealloc_unchecked, +}; use crate::ops::serial::{OperationError, OperationErrorKind}; use crate::ops::Op; -use nalgebra::{ClosedAdd, ClosedMul, DMatrixSlice, DMatrixSliceMut, RealField, Scalar}; +use nalgebra::{ClosedAdd, ClosedMul, DMatrixView, DMatrixViewMut, RealField, Scalar}; use num_traits::{One, Zero}; use std::borrow::Cow; @@ -14,10 +16,10 @@ use std::borrow::Cow; /// Panics if the dimensions of the matrices involved are not compatible with the expression. pub fn spmm_csc_dense<'a, T>( beta: T, - c: impl Into>, + c: impl Into>, alpha: T, a: Op<&CscMatrix>, - b: Op>>, + b: Op>>, ) where T: Scalar + ClosedAdd + ClosedMul + Zero + One, { @@ -27,10 +29,10 @@ pub fn spmm_csc_dense<'a, T>( fn spmm_csc_dense_( beta: T, - c: DMatrixSliceMut<'_, T>, + c: DMatrixViewMut<'_, T>, alpha: T, a: Op<&CscMatrix>, - b: Op>, + b: Op>, ) where T: Scalar + ClosedAdd + ClosedMul + Zero + One, { @@ -83,35 +85,81 @@ where { assert_compatible_spmm_dims!(c, a, b); - use Op::{NoOp, Transpose}; + use Op::NoOp; match (&a, &b) { - (NoOp(ref a), NoOp(ref b)) => { + (NoOp(a), NoOp(b)) => { // Note: We have to reverse the order for CSC matrices spmm_cs_prealloc(beta, &mut c.cs, alpha, &b.cs, &a.cs) } - _ => { - // Currently we handle transposition by explicitly precomputing transposed matrices - // and calling the operation again without transposition - let a_ref: &CscMatrix = a.inner_ref(); - let b_ref: &CscMatrix = b.inner_ref(); - let (a, b) = { - use Cow::*; - match (&a, &b) { - (NoOp(_), NoOp(_)) => unreachable!(), - (Transpose(ref a), NoOp(_)) => (Owned(a.transpose()), Borrowed(b_ref)), - (NoOp(_), Transpose(ref b)) => (Borrowed(a_ref), Owned(b.transpose())), - (Transpose(ref a), Transpose(ref b)) => { - (Owned(a.transpose()), Owned(b.transpose())) - } - } - }; - - spmm_csc_prealloc(beta, c, alpha, NoOp(a.as_ref()), NoOp(b.as_ref())) - } + _ => spmm_csc_transposed(beta, c, alpha, a, b, spmm_csc_prealloc), } } +/// Faster sparse-sparse matrix multiplication, `C <- beta * C + alpha * op(A) * op(B)`. +/// This will not return an error even if the patterns don't match. +/// Should be used for situations where pattern creation immediately precedes multiplication. +/// +/// Panics if the dimensions of the matrices involved are not compatible with the expression. +pub fn spmm_csc_prealloc_unchecked( + beta: T, + c: &mut CscMatrix, + alpha: T, + a: Op<&CscMatrix>, + b: Op<&CscMatrix>, +) -> Result<(), OperationError> +where + T: Scalar + ClosedAdd + ClosedMul + Zero + One, +{ + assert_compatible_spmm_dims!(c, a, b); + + use Op::NoOp; + + match (&a, &b) { + (NoOp(a), NoOp(b)) => { + // Note: We have to reverse the order for CSC matrices + spmm_cs_prealloc_unchecked(beta, &mut c.cs, alpha, &b.cs, &a.cs) + } + _ => spmm_csc_transposed(beta, c, alpha, a, b, spmm_csc_prealloc_unchecked), + } +} + +fn spmm_csc_transposed( + beta: T, + c: &mut CscMatrix, + alpha: T, + a: Op<&CscMatrix>, + b: Op<&CscMatrix>, + spmm_kernel: F, +) -> Result<(), OperationError> +where + T: Scalar + ClosedAdd + ClosedMul + Zero + One, + F: Fn( + T, + &mut CscMatrix, + T, + Op<&CscMatrix>, + Op<&CscMatrix>, + ) -> Result<(), OperationError>, +{ + use Op::{NoOp, Transpose}; + + // Currently we handle transposition by explicitly precomputing transposed matrices + // and calling the operation again without transposition + let a_ref: &CscMatrix = a.inner_ref(); + let b_ref: &CscMatrix = b.inner_ref(); + let (a, b) = { + use Cow::*; + match (&a, &b) { + (NoOp(_), NoOp(_)) => unreachable!(), + (Transpose(a), NoOp(_)) => (Owned(a.transpose()), Borrowed(b_ref)), + (NoOp(_), Transpose(b)) => (Borrowed(a_ref), Owned(b.transpose())), + (Transpose(a), Transpose(b)) => (Owned(a.transpose()), Owned(b.transpose())), + } + }; + spmm_kernel(beta, c, alpha, NoOp(a.as_ref()), NoOp(b.as_ref())) +} + /// Solve the lower triangular system `op(L) X = B`. /// /// Only the lower triangular part of L is read, and the result is stored in B. @@ -125,7 +173,7 @@ where /// Panics if `L` is not square, or if `L` and `B` are not dimensionally compatible. pub fn spsolve_csc_lower_triangular<'a, T: RealField>( l: Op<&CscMatrix>, - b: impl Into>, + b: impl Into>, ) -> Result<(), OperationError> { let b = b.into(); let l_matrix = l.into_inner(); @@ -147,7 +195,7 @@ pub fn spsolve_csc_lower_triangular<'a, T: RealField>( fn spsolve_csc_lower_triangular_no_transpose( l: &CscMatrix, - b: DMatrixSliceMut<'_, T>, + b: DMatrixViewMut<'_, T>, ) -> Result<(), OperationError> { let mut x = b; @@ -205,7 +253,7 @@ fn spsolve_encountered_zero_diagonal() -> Result<(), OperationError> { fn spsolve_csc_lower_triangular_transpose( l: &CscMatrix, - b: DMatrixSliceMut<'_, T>, + b: DMatrixViewMut<'_, T>, ) -> Result<(), OperationError> { let mut x = b; diff --git a/nalgebra-sparse/src/ops/serial/csr.rs b/nalgebra-sparse/src/ops/serial/csr.rs index fa317bbf..366f30aa 100644 --- a/nalgebra-sparse/src/ops/serial/csr.rs +++ b/nalgebra-sparse/src/ops/serial/csr.rs @@ -1,18 +1,20 @@ use crate::csr::CsrMatrix; -use crate::ops::serial::cs::{spadd_cs_prealloc, spmm_cs_dense, spmm_cs_prealloc}; +use crate::ops::serial::cs::{ + spadd_cs_prealloc, spmm_cs_dense, spmm_cs_prealloc, spmm_cs_prealloc_unchecked, +}; use crate::ops::serial::OperationError; use crate::ops::Op; -use nalgebra::{ClosedAdd, ClosedMul, DMatrixSlice, DMatrixSliceMut, Scalar}; +use nalgebra::{ClosedAdd, ClosedMul, DMatrixView, DMatrixViewMut, Scalar}; use num_traits::{One, Zero}; use std::borrow::Cow; /// Sparse-dense matrix-matrix multiplication `C <- beta * C + alpha * op(A) * op(B)`. pub fn spmm_csr_dense<'a, T>( beta: T, - c: impl Into>, + c: impl Into>, alpha: T, a: Op<&CsrMatrix>, - b: Op>>, + b: Op>>, ) where T: Scalar + ClosedAdd + ClosedMul + Zero + One, { @@ -22,10 +24,10 @@ pub fn spmm_csr_dense<'a, T>( fn spmm_csr_dense_( beta: T, - c: DMatrixSliceMut<'_, T>, + c: DMatrixViewMut<'_, T>, alpha: T, a: Op<&CsrMatrix>, - b: Op>, + b: Op>, ) where T: Scalar + ClosedAdd + ClosedMul + Zero + One, { @@ -77,30 +79,71 @@ where { assert_compatible_spmm_dims!(c, a, b); - use Op::{NoOp, Transpose}; + use Op::NoOp; match (&a, &b) { - (NoOp(ref a), NoOp(ref b)) => spmm_cs_prealloc(beta, &mut c.cs, alpha, &a.cs, &b.cs), - _ => { - // Currently we handle transposition by explicitly precomputing transposed matrices - // and calling the operation again without transposition - // TODO: At least use workspaces to allow control of allocations. Maybe - // consider implementing certain patterns (like A^T * B) explicitly - let a_ref: &CsrMatrix = a.inner_ref(); - let b_ref: &CsrMatrix = b.inner_ref(); - let (a, b) = { - use Cow::*; - match (&a, &b) { - (NoOp(_), NoOp(_)) => unreachable!(), - (Transpose(ref a), NoOp(_)) => (Owned(a.transpose()), Borrowed(b_ref)), - (NoOp(_), Transpose(ref b)) => (Borrowed(a_ref), Owned(b.transpose())), - (Transpose(ref a), Transpose(ref b)) => { - (Owned(a.transpose()), Owned(b.transpose())) - } - } - }; - - spmm_csr_prealloc(beta, c, alpha, NoOp(a.as_ref()), NoOp(b.as_ref())) - } + (NoOp(a), NoOp(b)) => spmm_cs_prealloc(beta, &mut c.cs, alpha, &a.cs, &b.cs), + _ => spmm_csr_transposed(beta, c, alpha, a, b, spmm_csr_prealloc), } } + +/// Faster sparse-sparse matrix multiplication, `C <- beta * C + alpha * op(A) * op(B)`. +/// This will not return an error even if the patterns don't match. +/// Should be used for situations where pattern creation immediately precedes multiplication. +/// +/// Panics if the dimensions of the matrices involved are not compatible with the expression. +pub fn spmm_csr_prealloc_unchecked( + beta: T, + c: &mut CsrMatrix, + alpha: T, + a: Op<&CsrMatrix>, + b: Op<&CsrMatrix>, +) -> Result<(), OperationError> +where + T: Scalar + ClosedAdd + ClosedMul + Zero + One, +{ + assert_compatible_spmm_dims!(c, a, b); + + use Op::NoOp; + + match (&a, &b) { + (NoOp(a), NoOp(b)) => spmm_cs_prealloc_unchecked(beta, &mut c.cs, alpha, &a.cs, &b.cs), + _ => spmm_csr_transposed(beta, c, alpha, a, b, spmm_csr_prealloc_unchecked), + } +} + +fn spmm_csr_transposed( + beta: T, + c: &mut CsrMatrix, + alpha: T, + a: Op<&CsrMatrix>, + b: Op<&CsrMatrix>, + spmm_kernel: F, +) -> Result<(), OperationError> +where + T: Scalar + ClosedAdd + ClosedMul + Zero + One, + F: Fn( + T, + &mut CsrMatrix, + T, + Op<&CsrMatrix>, + Op<&CsrMatrix>, + ) -> Result<(), OperationError>, +{ + use Op::{NoOp, Transpose}; + + // Currently we handle transposition by explicitly precomputing transposed matrices + // and calling the operation again without transposition + let a_ref: &CsrMatrix = a.inner_ref(); + let b_ref: &CsrMatrix = b.inner_ref(); + let (a, b) = { + use Cow::*; + match (&a, &b) { + (NoOp(_), NoOp(_)) => unreachable!(), + (Transpose(a), NoOp(_)) => (Owned(a.transpose()), Borrowed(b_ref)), + (NoOp(_), Transpose(b)) => (Borrowed(a_ref), Owned(b.transpose())), + (Transpose(a), Transpose(b)) => (Owned(a.transpose()), Owned(b.transpose())), + } + }; + spmm_kernel(beta, c, alpha, NoOp(a.as_ref()), NoOp(b.as_ref())) +} diff --git a/nalgebra-sparse/src/ops/serial/pattern.rs b/nalgebra-sparse/src/ops/serial/pattern.rs index b73f3375..8806b4fc 100644 --- a/nalgebra-sparse/src/ops/serial/pattern.rs +++ b/nalgebra-sparse/src/ops/serial/pattern.rs @@ -125,18 +125,22 @@ fn iterate_union<'a>( ) -> impl Iterator + 'a { iter::from_fn(move || { if let (Some(a_item), Some(b_item)) = (sorted_a.first(), sorted_b.first()) { - let item = if a_item < b_item { - sorted_a = &sorted_a[1..]; - a_item - } else if b_item < a_item { - sorted_b = &sorted_b[1..]; - b_item - } else { - // Both lists contain the same element, advance both slices to avoid - // duplicate entries in the result - sorted_a = &sorted_a[1..]; - sorted_b = &sorted_b[1..]; - a_item + let item = match a_item.cmp(b_item) { + std::cmp::Ordering::Less => { + sorted_a = &sorted_a[1..]; + a_item + } + std::cmp::Ordering::Greater => { + sorted_b = &sorted_b[1..]; + b_item + } + std::cmp::Ordering::Equal => { + // Both lists contain the same element, advance both slices to avoid + // duplicate entries in the result + sorted_a = &sorted_a[1..]; + sorted_b = &sorted_b[1..]; + a_item + } }; Some(*item) } else if let Some(a_item) = sorted_a.first() { diff --git a/nalgebra-sparse/src/pattern.rs b/nalgebra-sparse/src/pattern.rs index c51945b7..803e7f2d 100644 --- a/nalgebra-sparse/src/pattern.rs +++ b/nalgebra-sparse/src/pattern.rs @@ -80,7 +80,7 @@ impl SparsityPattern { #[inline] #[must_use] pub fn major_dim(&self) -> usize { - assert!(self.major_offsets.len() > 0); + assert!(!self.major_offsets.is_empty()); self.major_offsets.len() - 1 } @@ -162,7 +162,7 @@ impl SparsityPattern { // We test for in-bounds, uniqueness and monotonicity at the same time // to ensure that we only visit each minor index once let mut iter = minor_indices.iter(); - let mut prev = None; + let mut prev: Option = None; while let Some(next) = iter.next().copied() { if next >= minor_dim { @@ -170,10 +170,10 @@ impl SparsityPattern { } if let Some(prev) = prev { - if prev > next { - return Err(NonmonotonicMinorIndices); - } else if prev == next { - return Err(DuplicateEntry); + match prev.cmp(&next) { + std::cmp::Ordering::Greater => return Err(NonmonotonicMinorIndices), + std::cmp::Ordering::Equal => return Err(DuplicateEntry), + std::cmp::Ordering::Less => {} } } prev = Some(next); @@ -195,6 +195,14 @@ impl SparsityPattern { /// /// Panics if the number of major offsets is not exactly one greater than the major dimension /// or if major offsets do not start with 0 and end with the number of minor indices. + /// + /// # Safety + /// + /// Assumes that the major offsets and indices adhere to the requirements of being a valid + /// sparsity pattern. + /// Specifically, that major offsets is monotonically increasing, and + /// `major_offsets[i]..major_offsets[i+1]` refers to a major lane in the sparsity pattern, + /// and `minor_indices[major_offsets[i]..major_offsets[i+1]]` is monotonically increasing. pub unsafe fn from_offset_and_indices_unchecked( major_dim: usize, minor_dim: usize, @@ -291,6 +299,16 @@ impl SparsityPattern { } } +impl Default for SparsityPattern { + fn default() -> Self { + Self { + major_offsets: vec![0], + minor_indices: vec![], + minor_dim: 0, + } + } +} + /// Error type for `SparsityPattern` format errors. #[non_exhaustive] #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/nalgebra-sparse/tests/unit_tests/coo.rs b/nalgebra-sparse/tests/unit_tests/coo.rs index c70c5f97..c3702c49 100644 --- a/nalgebra-sparse/tests/unit_tests/coo.rs +++ b/nalgebra-sparse/tests/unit_tests/coo.rs @@ -87,6 +87,40 @@ fn coo_construction_for_valid_data() { } } +#[test] +fn coo_triplets_iter_mut() { + // Arbitrary matrix, with duplicates + let i = vec![0, 1, 0, 0, 0, 0, 2, 1]; + let j = vec![0, 2, 0, 1, 0, 3, 3, 2]; + let v = vec![2, 3, 4, 7, 1, 3, 1, 5]; + let mut coo = + CooMatrix::::try_from_triplets(3, 5, i.clone(), j.clone(), v.clone()).unwrap(); + + let actual_triplets: Vec<_> = coo.triplet_iter_mut().map(|(i, j, v)| (i, j, *v)).collect(); + + let expected_triplets: Vec<_> = i + .iter() + .zip(&j) + .zip(&v) + .map(|((i, j), v)| (*i, *j, *v)) + .collect(); + assert_eq!(expected_triplets, actual_triplets); + + for (_i, _j, v) in coo.triplet_iter_mut() { + *v += *v; + } + + let actual_triplets: Vec<_> = coo.triplet_iter_mut().map(|(i, j, v)| (i, j, *v)).collect(); + let v = vec![4, 6, 8, 14, 2, 6, 2, 10]; + let expected_triplets: Vec<_> = i + .iter() + .zip(&j) + .zip(&v) + .map(|((i, j), v)| (*i, *j, *v)) + .collect(); + assert_eq!(expected_triplets, actual_triplets); +} + #[test] fn coo_try_from_triplets_reports_out_of_bounds_indices() { { @@ -150,6 +184,31 @@ fn coo_try_from_triplets_reports_out_of_bounds_indices() { } } +#[test] +fn coo_try_from_triplets_iter() { + // Check that try_from_triplets_iter panics when the triplet vectors have different lengths + macro_rules! assert_errs { + ($result:expr) => { + assert!(matches!( + $result.unwrap_err().kind(), + SparseFormatErrorKind::IndexOutOfBounds + )) + }; + } + + assert_errs!(CooMatrix::::try_from_triplets_iter( + 3, + 5, + vec![(0, 6, 3.0)].into_iter(), + )); + assert!(CooMatrix::::try_from_triplets_iter( + 3, + 5, + vec![(0, 3, 3.0), (1, 2, 2.0), (0, 3, 1.0),].into_iter(), + ) + .is_ok()); +} + #[test] fn coo_try_from_triplets_panics_on_mismatched_vectors() { // Check that try_from_triplets panics when the triplet vectors have different lengths @@ -226,6 +285,29 @@ fn coo_push_valid_entries() { ); } +#[test] +fn coo_clear_triplets_valid_entries() { + let mut coo = CooMatrix::new(3, 3); + + coo.push(0, 0, 1); + coo.push(0, 0, 2); + coo.push(2, 2, 3); + assert_eq!( + coo.triplet_iter().collect::>(), + vec![(0, 0, &1), (0, 0, &2), (2, 2, &3)] + ); + coo.clear_triplets(); + assert_eq!(coo.triplet_iter().collect::>(), vec![]); + // making sure everyhting works after clearing + coo.push(0, 0, 1); + coo.push(0, 0, 2); + coo.push(2, 2, 3); + assert_eq!( + coo.triplet_iter().collect::>(), + vec![(0, 0, &1), (0, 0, &2), (2, 2, &3)] + ); +} + #[test] fn coo_push_out_of_bounds_entries() { { @@ -291,8 +373,8 @@ fn coo_push_matrix_valid_entries() { // Works with sliced { let source = nalgebra::SMatrix::::new(6, 7, 8, 9); - let sliced = source.fixed_slice::<2, 1>(0, 0); - coo.push_matrix(1, 0, &sliced); + let view = source.fixed_view::<2, 1>(0, 0); + coo.push_matrix(1, 0, &view); assert_eq!( coo.triplet_iter().collect::>(), diff --git a/nalgebra-sparse/tests/unit_tests/csc.rs b/nalgebra-sparse/tests/unit_tests/csc.rs index 1554b8a6..b95f048f 100644 --- a/nalgebra-sparse/tests/unit_tests/csc.rs +++ b/nalgebra-sparse/tests/unit_tests/csc.rs @@ -12,6 +12,18 @@ use crate::common::csc_strategy; use std::collections::HashSet; +#[test] +fn csc_matrix_default() { + let matrix: CscMatrix = CscMatrix::default(); + + assert_eq!(matrix.nrows(), 0); + assert_eq!(matrix.ncols(), 0); + assert_eq!(matrix.nnz(), 0); + + assert_eq!(matrix.values(), &[]); + assert!(matrix.get_entry(0, 0).is_none()); +} + #[test] fn csc_matrix_valid_data() { // Construct matrix from valid data and check that selected methods return results diff --git a/nalgebra-sparse/tests/unit_tests/csr.rs b/nalgebra-sparse/tests/unit_tests/csr.rs index a00470d5..b2312932 100644 --- a/nalgebra-sparse/tests/unit_tests/csr.rs +++ b/nalgebra-sparse/tests/unit_tests/csr.rs @@ -12,6 +12,18 @@ use crate::common::csr_strategy; use std::collections::HashSet; +#[test] +fn csr_matrix_default() { + let matrix: CsrMatrix = CsrMatrix::default(); + + assert_eq!(matrix.nrows(), 0); + assert_eq!(matrix.ncols(), 0); + assert_eq!(matrix.nnz(), 0); + + assert_eq!(matrix.values(), &[]); + assert!(matrix.get_entry(0, 0).is_none()); +} + #[test] fn csr_matrix_valid_data() { // Construct matrix from valid data and check that selected methods return results diff --git a/nalgebra-sparse/tests/unit_tests/matrix_market.rs b/nalgebra-sparse/tests/unit_tests/matrix_market.rs index 48ff1a78..44e27644 100644 --- a/nalgebra-sparse/tests/unit_tests/matrix_market.rs +++ b/nalgebra-sparse/tests/unit_tests/matrix_market.rs @@ -1,12 +1,21 @@ use matrixcompare::assert_matrix_eq; -use nalgebra::dmatrix; +use nalgebra::matrix; use nalgebra::Complex; -use nalgebra_sparse::io::load_coo_from_matrix_market_str; +use nalgebra_sparse::io::{ + load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, save_to_matrix_market_file, + save_to_matrix_market_str, +}; +use nalgebra_sparse::proptest::coo_no_duplicates; use nalgebra_sparse::CooMatrix; +use proptest::prelude::*; +use tempfile::tempdir; + +type C64 = Complex; +type C32 = Complex; #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_real_general_empty() { +fn test_matrixmarket_load_sparse_real_general_empty() { // Test several valid zero-shapes of a sparse matrix let shapes = vec![ (0, 0), (1, 0), (0, 1) ]; let strings: Vec = shapes @@ -24,7 +33,7 @@ fn test_matrixmarket_sparse_real_general_empty() { #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_real_general_empty() { +fn test_matrixmarket_load_dense_real_general_empty() { // Test several valid zero-shapes of a dense matrix let shapes = vec![ (0, 0), (1, 0), (0, 1) ]; let strings: Vec = shapes @@ -42,7 +51,7 @@ fn test_matrixmarket_dense_real_general_empty() { #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_real_general() { +fn test_matrixmarket_load_sparse_real_general() { let file_str = r#" %%MatrixMarket matrix CoOrdinate real general % This is also an example of free-format features. @@ -89,7 +98,7 @@ fn test_matrixmarket_sparse_real_general() { 5 5 1.200e+01 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1.0, 0.0, 0.0, 6.0, 0.0; 0.0, 10.5, 0.0, 0.0, 0.0; 0.0, 0.0, 0.015, 0.0, 0.0; @@ -101,7 +110,7 @@ fn test_matrixmarket_sparse_real_general() { #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_int_symmetric() { +fn test_matrixmarket_load_sparse_int_symmetric() { let file_str = r#" %%MatrixMarket matrix coordinate integer symmetric % @@ -117,7 +126,7 @@ fn test_matrixmarket_sparse_int_symmetric() { 5 5 55 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 11, 0, 0, 0, -15; 0, 22, 23, 24, 0; 0, 23, 33, 0, 35; @@ -129,7 +138,7 @@ fn test_matrixmarket_sparse_int_symmetric() { #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_complex_hermitian() { +fn test_matrixmarket_load_sparse_complex_hermitian() { let file_str = r#" %%MatrixMarket matrix coordinate complex hermitian % @@ -144,19 +153,19 @@ fn test_matrixmarket_sparse_complex_hermitian() { "#; let sparse_mat = load_coo_from_matrix_market_str::>(file_str).unwrap(); - let expected = dmatrix![ - Complex::{re:1.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0},Complex::{re:0.0,im:0.0}; - Complex::{re:0.0,im:0.0}, Complex::{re:10.5,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:250.5,im:-22.22},Complex::{re:0.0,im:0.0}; - Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.015,im:0.0}, Complex::{re:0.0,im:0.0},Complex::{re:0.0,im:0.0}; - Complex::{re:0.0,im:0.0}, Complex::{re:250.5,im:22.22}, Complex::{re:0.0,im:0.0}, Complex::{re:-280.0,im:0.0},Complex::{re:0.0,im:-33.32}; - Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:0.0}, Complex::{re:0.0,im:33.32},Complex::{re:12.0,im:0.0}; + let expected = matrix![ + C64{re:1.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0},C64{re:0.0,im:0.0}; + C64{re:0.0,im:0.0}, C64{re:10.5,im:0.0}, C64{re:0.0,im:0.0}, C64{re:250.5,im:-22.22},C64{re:0.0,im:0.0}; + C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.015,im:0.0}, C64{re:0.0,im:0.0},C64{re:0.0,im:0.0}; + C64{re:0.0,im:0.0}, C64{re:250.5,im:22.22}, C64{re:0.0,im:0.0}, C64{re:-280.0,im:0.0},C64{re:0.0,im:-33.32}; + C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:0.0}, C64{re:0.0,im:33.32},C64{re:12.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); } #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_real_skew() { +fn test_matrixmarket_load_sparse_real_skew() { let file_str = r#" %%MatrixMarket matrix coordinate real skew-symmetric % @@ -167,7 +176,7 @@ fn test_matrixmarket_sparse_real_skew() { 5 3 -35.0 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 0.0, 0.0, 0.0, 0.0, 15.0; 0.0, 0.0, 23.0, 24.0, 0.0; 0.0, -23.0, 0.0, 0.0, 35.0; @@ -179,7 +188,7 @@ fn test_matrixmarket_sparse_real_skew() { #[test] #[rustfmt::skip] -fn test_matrixmarket_sparse_pattern_general() { +fn test_matrixmarket_load_sparse_pattern_general() { let file_str = r#" %%MatrixMarket matrix coordinate pattern general % @@ -198,10 +207,10 @@ fn test_matrixmarket_sparse_pattern_general() { let pattern_matrix = load_coo_from_matrix_market_str::<()>(file_str).unwrap(); let nrows = pattern_matrix.nrows(); let ncols = pattern_matrix.ncols(); - let (row_idx, col_idx, val) = pattern_matrix.disassemble(); + let (row_idx, col_idx, val) = pattern_matrix.clone().disassemble(); let values = vec![1; val.len()]; let sparse_mat = CooMatrix::try_from_triplets(nrows, ncols, row_idx, col_idx, values).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1, 0, 0, 0, 1; 0, 0, 1, 1, 0; 0, 1, 0, 0, 1; @@ -213,7 +222,7 @@ fn test_matrixmarket_sparse_pattern_general() { #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_real_general() { +fn test_matrixmarket_load_dense_real_general() { let file_str = r#" %%MatrixMarket matrix array real general % @@ -233,7 +242,7 @@ fn test_matrixmarket_dense_real_general() { "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1.0, 5.0, 9.0; 2.0, 6.0, 10.0; 3.0, 7.0, 11.0; @@ -244,7 +253,7 @@ fn test_matrixmarket_dense_real_general() { #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_real_symmetric() { +fn test_matrixmarket_load_dense_real_symmetric() { let file_str = r#" %%MatrixMarket matrix array real symmetric % @@ -262,7 +271,7 @@ fn test_matrixmarket_dense_real_symmetric() { "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 1.0, 2.0, 3.0, 4.0; 2.0, 5.0, 6.0, 7.0; 3.0, 6.0, 8.0, 9.0; @@ -273,7 +282,7 @@ fn test_matrixmarket_dense_real_symmetric() { #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_complex_hermitian() { +fn test_matrixmarket_load_dense_complex_hermitian() { let file_str = r#" %%MatrixMarket matrix array complex hermitian % @@ -290,19 +299,19 @@ fn test_matrixmarket_dense_complex_hermitian() { 10.0 0.0 "#; - let sparse_mat = load_coo_from_matrix_market_str::>(file_str).unwrap(); - let expected = dmatrix![ - Complex::{re:1.0,im:0.0}, Complex::{re:2.0,im:-2.0} ,Complex::{re:3.0,im:-3.0} ,Complex::{re:4.0,im:-4.0}; - Complex::{re:2.0,im:2.0}, Complex::{re:5.0,im:0.0} ,Complex::{re:6.0,im:-6.0} ,Complex::{re:7.0,im:-7.0}; - Complex::{re:3.0,im:3.0}, Complex::{re:6.0,im:6.0} ,Complex::{re:8.0,im:0.0} ,Complex::{re:9.0,im:-9.0}; - Complex::{re:4.0,im:4.0}, Complex::{re:7.0,im:7.0} ,Complex::{re:9.0,im:9.0} ,Complex::{re:10.0,im:0.0}; + let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); + let expected = matrix![ + C64{re:1.0,im:0.0}, C64{re:2.0,im:-2.0} ,C64{re:3.0,im:-3.0} ,C64{re:4.0,im:-4.0}; + C64{re:2.0,im:2.0}, C64{re:5.0,im:0.0} ,C64{re:6.0,im:-6.0} ,C64{re:7.0,im:-7.0}; + C64{re:3.0,im:3.0}, C64{re:6.0,im:6.0} ,C64{re:8.0,im:0.0} ,C64{re:9.0,im:-9.0}; + C64{re:4.0,im:4.0}, C64{re:7.0,im:7.0} ,C64{re:9.0,im:9.0} ,C64{re:10.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); } #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_int_skew() { +fn test_matrixmarket_load_dense_int_skew() { let file_str = r#" %%MatrixMarket matrix array integer skew-symmetric % @@ -315,7 +324,7 @@ fn test_matrixmarket_dense_int_skew() { 6 "#; let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); - let expected = dmatrix![ + let expected = matrix![ 0,-1,-2,-3; 1, 0,-4,-5; 2, 4, 0,-6; @@ -326,7 +335,7 @@ fn test_matrixmarket_dense_int_skew() { #[test] #[rustfmt::skip] -fn test_matrixmarket_dense_complex_general() { +fn test_matrixmarket_load_dense_complex_general() { let file_str = r#" %%MatrixMarket matrix array complex general % @@ -336,10 +345,124 @@ fn test_matrixmarket_dense_complex_general() { 1 0 1 0 "#; - let sparse_mat = load_coo_from_matrix_market_str::>(file_str).unwrap(); - let expected = dmatrix![ - Complex::{re:1.0,im:0.0},Complex::{re:1.0,im:0.0}; - Complex::{re:1.0,im:0.0},Complex::{re:1.0,im:0.0}; + let sparse_mat = load_coo_from_matrix_market_str::(file_str).unwrap(); + let expected = matrix![ + C32{re:1.0,im:0.0},C32{re:1.0,im:0.0}; + C32{re:1.0,im:0.0},C32{re:1.0,im:0.0}; ]; assert_matrix_eq!(sparse_mat, expected); } + +#[test] +#[rustfmt::skip] +fn test_matrixmarket_write_real(){ + let dense_matrix = matrix![ + 1.0, 2.0, 3.0; + 2.0, 0.0, 3.0; + ]; + let row_indices = vec![0,1,0,0,1]; + let col_indices = vec![0,0,1,2,2]; + let values = vec![1.0,2.0,2.0,3.0,3.0]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + assert_matrix_eq!(dense_matrix,coo_matrix); + let expected = r#"%%matrixmarket matrix coordinate real general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 1 +2 1 2 +1 2 2 +1 3 3 +2 3 3 +"#; + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str,expected); +} + +#[test] +fn test_matrixmarket_write_int() { + let dense_matrix = matrix![ + 1,2,3; + 2,0,3; + ]; + let row_indices = vec![0, 1, 0, 0, 1]; + let col_indices = vec![0, 0, 1, 2, 2]; + let values = vec![1, 2, 2, 3, 3]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + assert_matrix_eq!(dense_matrix, coo_matrix); + let expected = r#"%%matrixmarket matrix coordinate integer general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 1 +2 1 2 +1 2 2 +1 3 3 +2 3 3 +"#; + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str, expected); +} + +#[test] +fn test_matrixmarket_write_pattern() { + let row_indices = vec![0, 1, 0, 0, 1]; + let col_indices = vec![0, 0, 1, 2, 2]; + let values = vec![(), (), (), (), ()]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + let expected = r#"%%matrixmarket matrix coordinate pattern general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 +2 1 +1 2 +1 3 +2 3 +"#; + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str, expected); +} + +#[test] +fn test_matrixmarket_write_complex() { + let row_indices = vec![0, 1, 0, 0, 1]; + let col_indices = vec![0, 0, 1, 2, 2]; + let values = vec![ + C64 { re: 1.0, im: 2.0 }, + C64 { re: 2.0, im: 3.0 }, + C64 { re: 3.0, im: 4.0 }, + C64 { re: 4.0, im: 5.0 }, + C64 { re: 5.0, im: 6.0 }, + ]; + let coo_matrix = CooMatrix::try_from_triplets(2, 3, row_indices, col_indices, values).unwrap(); + let expected = r#"%%matrixmarket matrix coordinate complex general +% matrixmarket file generated by nalgebra-sparse. +2 3 5 +1 1 1 2 +2 1 2 3 +1 2 3 4 +1 3 4 5 +2 3 5 6 +"#; + let matrixmarket_str = save_to_matrix_market_str(&coo_matrix); + assert_eq!(matrixmarket_str, expected); +} + +proptest! { + #[test] + fn coo_matrix_market_roundtrip_str(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { + let generated_matrixmarket_string = save_to_matrix_market_str(&coo); + let generated_matrix = load_coo_from_matrix_market_str(&generated_matrixmarket_string).unwrap(); + assert_matrix_eq!(generated_matrix, coo); + } +} + +proptest! { + #[test] + fn coo_matrix_market_roundtrip_file(coo in coo_no_duplicates(-10 ..= 10, 0 ..= 10, 0..= 10, 100)) { + let temp_dir = tempdir().expect("Unable to create temporary directory"); + let file_path = temp_dir.path().join("temp.mtx"); + save_to_matrix_market_file(&coo,&file_path).unwrap(); + let generated_matrix = load_coo_from_matrix_market_file(file_path).unwrap(); + assert_matrix_eq!(generated_matrix, coo); + temp_dir.close().expect("Unable to delete temporary directory"); + } +} diff --git a/nalgebra-sparse/tests/unit_tests/ops.rs b/nalgebra-sparse/tests/unit_tests/ops.rs index f2a02fd8..c8d80f32 100644 --- a/nalgebra-sparse/tests/unit_tests/ops.rs +++ b/nalgebra-sparse/tests/unit_tests/ops.rs @@ -6,14 +6,15 @@ use nalgebra_sparse::csc::CscMatrix; use nalgebra_sparse::csr::CsrMatrix; use nalgebra_sparse::ops::serial::{ spadd_csc_prealloc, spadd_csr_prealloc, spadd_pattern, spmm_csc_dense, spmm_csc_prealloc, - spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc, spsolve_csc_lower_triangular, + spmm_csc_prealloc_unchecked, spmm_csr_dense, spmm_csr_pattern, spmm_csr_prealloc, + spmm_csr_prealloc_unchecked, spsolve_csc_lower_triangular, }; use nalgebra_sparse::ops::Op; use nalgebra_sparse::pattern::SparsityPattern; use nalgebra_sparse::proptest::{csc, csr, sparsity_pattern}; use nalgebra::proptest::{matrix, vector}; -use nalgebra::{DMatrix, DMatrixSlice, DMatrixSliceMut, Scalar}; +use nalgebra::{DMatrix, DMatrixView, DMatrixViewMut, Scalar}; use proptest::prelude::*; @@ -332,10 +333,10 @@ fn csc_square_with_non_zero_diagonals() -> impl Strategy> /// Helper function to help us call dense GEMM with our `Op` type fn dense_gemm<'a>( beta: i32, - c: impl Into>, + c: impl Into>, alpha: i32, - a: Op>>, - b: Op>>, + a: Op>>, + b: Op>>, ) { let mut c = c.into(); let a = a.convert(); @@ -543,6 +544,29 @@ proptest! { prop_assert_eq!(&c_pattern, c_csr.pattern()); } + #[test] + fn spmm_csr_prealloc_unchecked_test(SpmmCsrArgs { c, beta, alpha, a, b } + in spmm_csr_prealloc_args_strategy() + ) { + // Test that we get the expected result by comparing to an equivalent dense operation + // (here we give in the C matrix, so the sparsity pattern is essentially fixed) + let mut c_sparse = c.clone(); + spmm_csr_prealloc_unchecked(beta, &mut c_sparse, alpha, a.as_ref(), b.as_ref()).unwrap(); + + let mut c_dense = DMatrix::from(&c); + let op_a_dense = match a { + Op::NoOp(ref a) => DMatrix::from(a), + Op::Transpose(ref a) => DMatrix::from(a).transpose(), + }; + let op_b_dense = match b { + Op::NoOp(ref b) => DMatrix::from(b), + Op::Transpose(ref b) => DMatrix::from(b).transpose(), + }; + c_dense = beta * c_dense + alpha * &op_a_dense * op_b_dense; + + prop_assert_eq!(&DMatrix::from(&c_sparse), &c_dense); + } + #[test] fn spmm_csr_prealloc_test(SpmmCsrArgs { c, beta, alpha, a, b } in spmm_csr_prealloc_args_strategy() @@ -705,6 +729,29 @@ proptest! { prop_assert_eq!(&DMatrix::from(&c_sparse), &c_dense); } + #[test] + fn spmm_csc_prealloc_unchecked_test(SpmmCscArgs { c, beta, alpha, a, b } + in spmm_csc_prealloc_args_strategy() + ) { + // Test that we get the expected result by comparing to an equivalent dense operation + // (here we give in the C matrix, so the sparsity pattern is essentially fixed) + let mut c_sparse = c.clone(); + spmm_csc_prealloc_unchecked(beta, &mut c_sparse, alpha, a.as_ref(), b.as_ref()).unwrap(); + + let mut c_dense = DMatrix::from(&c); + let op_a_dense = match a { + Op::NoOp(ref a) => DMatrix::from(a), + Op::Transpose(ref a) => DMatrix::from(a).transpose(), + }; + let op_b_dense = match b { + Op::NoOp(ref b) => DMatrix::from(b), + Op::Transpose(ref b) => DMatrix::from(b).transpose(), + }; + c_dense = beta * c_dense + alpha * &op_a_dense * op_b_dense; + + prop_assert_eq!(&DMatrix::from(&c_sparse), &c_dense); + } + #[test] fn spmm_csc_prealloc_panics_on_dim_mismatch( (alpha, beta, c, a, b) diff --git a/nalgebra-sparse/tests/unit_tests/pattern.rs b/nalgebra-sparse/tests/unit_tests/pattern.rs index 310cffae..013f6263 100644 --- a/nalgebra-sparse/tests/unit_tests/pattern.rs +++ b/nalgebra-sparse/tests/unit_tests/pattern.rs @@ -1,5 +1,19 @@ use nalgebra_sparse::pattern::{SparsityPattern, SparsityPatternFormatError}; +#[test] +fn sparsity_pattern_default() { + // Check that the pattern created with `Default::default()` is equivalent to a zero-sized pattern. + let pattern = SparsityPattern::default(); + let zero = SparsityPattern::zeros(0, 0); + + assert_eq!(pattern.major_dim(), zero.major_dim()); + assert_eq!(pattern.minor_dim(), zero.minor_dim()); + assert_eq!(pattern.major_offsets(), zero.major_offsets()); + assert_eq!(pattern.minor_indices(), zero.minor_indices()); + + assert_eq!(pattern.nnz(), 0); +} + #[test] fn sparsity_pattern_valid_data() { // Construct pattern from valid data and check that selected methods return results diff --git a/src/base/alias.rs b/src/base/alias.rs index 68829d9a..a07ea9e7 100644 --- a/src/base/alias.rs +++ b/src/base/alias.rs @@ -1,5 +1,5 @@ #[cfg(any(feature = "alloc", feature = "std"))] -use crate::base::dimension::Dynamic; +use crate::base::dimension::Dyn; use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; use crate::base::storage::Owned; #[cfg(any(feature = "std", feature = "alloc"))] @@ -48,69 +48,69 @@ pub type SMatrix = /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type DMatrix = Matrix>; +pub type DMatrix = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 1 columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx1 = Matrix>; +pub type MatrixXx1 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 2 columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx2 = Matrix>; +pub type MatrixXx2 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 3 columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx3 = Matrix>; +pub type MatrixXx3 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 4 columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx4 = Matrix>; +pub type MatrixXx4 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 5 columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx5 = Matrix>; +pub type MatrixXx5 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 6 columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type MatrixXx6 = Matrix>; +pub type MatrixXx6 = Matrix>; -/// A heap-allocated, row-major, matrix with 1 rows and a dynamic number of columns. +/// A heap-allocated, column-major, matrix with 1 rows and a dynamic number of columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix1xX = Matrix>; -/// A heap-allocated, row-major, matrix with 2 rows and a dynamic number of columns. +pub type Matrix1xX = Matrix>; +/// A heap-allocated, column-major, matrix with 2 rows and a dynamic number of columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix2xX = Matrix>; -/// A heap-allocated, row-major, matrix with 3 rows and a dynamic number of columns. +pub type Matrix2xX = Matrix>; +/// A heap-allocated, column-major, matrix with 3 rows and a dynamic number of columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix3xX = Matrix>; -/// A heap-allocated, row-major, matrix with 4 rows and a dynamic number of columns. +pub type Matrix3xX = Matrix>; +/// A heap-allocated, column-major, matrix with 4 rows and a dynamic number of columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix4xX = Matrix>; -/// A heap-allocated, row-major, matrix with 5 rows and a dynamic number of columns. +pub type Matrix4xX = Matrix>; +/// A heap-allocated, column-major, matrix with 5 rows and a dynamic number of columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix5xX = Matrix>; -/// A heap-allocated, row-major, matrix with 6 rows and a dynamic number of columns. +pub type Matrix5xX = Matrix>; +/// A heap-allocated, column-major, matrix with 6 rows and a dynamic number of columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] -pub type Matrix6xX = Matrix>; +pub type Matrix6xX = Matrix>; /// A stack-allocated, column-major, 1x1 square matrix. /// @@ -276,7 +276,7 @@ pub type Matrix6x5 = Matrix>; */ /// A dynamically sized column vector. #[cfg(any(feature = "std", feature = "alloc"))] -pub type DVector = Matrix>; +pub type DVector = Matrix>; /// An owned D-dimensional column vector. pub type OVector = Matrix>; @@ -316,7 +316,7 @@ pub type Vector6 = Matrix>; */ /// A dynamically sized row vector. #[cfg(any(feature = "std", feature = "alloc"))] -pub type RowDVector = Matrix>; +pub type RowDVector = Matrix>; /// An owned D-dimensional row vector. pub type RowOVector = Matrix>; diff --git a/src/base/alias_slice.rs b/src/base/alias_slice.rs index 929d2f03..9c1a9a87 100644 --- a/src/base/alias_slice.rs +++ b/src/base/alias_slice.rs @@ -1,6 +1,7 @@ -use crate::base::dimension::{Dynamic, U1, U2, U3, U4, U5, U6}; -use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; +use crate::base::dimension::{Dyn, U1, U2, U3, U4, U5, U6}; +use crate::base::matrix_view::{ViewStorage, ViewStorageMut}; use crate::base::{Const, Matrix}; +use crate::slice_deprecation_note; /* * @@ -13,286 +14,345 @@ use crate::base::{Const, Matrix}; /// A column-major matrix slice with dimensions known at compile-time. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SMatrixView)] pub type SMatrixSlice<'a, T, const R: usize, const C: usize> = - Matrix, Const, SliceStorage<'a, T, Const, Const, Const<1>, Const>>; + Matrix, Const, ViewStorage<'a, T, Const, Const, Const<1>, Const>>; /// A column-major matrix slice dynamic numbers of rows and columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** -pub type DMatrixSlice<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(DMatrixView)] +pub type DMatrixSlice<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major 1x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1)] pub type MatrixSlice1<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 2x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2)] pub type MatrixSlice2<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 3x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3)] pub type MatrixSlice3<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 4x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4)] pub type MatrixSlice4<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 5x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5)] pub type MatrixSlice5<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 6x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6)] pub type MatrixSlice6<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 1x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x2)] pub type MatrixSlice1x2<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x3)] pub type MatrixSlice1x3<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x4)] pub type MatrixSlice1x4<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x5)] pub type MatrixSlice1x5<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x6)] pub type MatrixSlice1x6<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 2x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x1)] pub type MatrixSlice2x1<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x3)] pub type MatrixSlice2x3<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x4)] pub type MatrixSlice2x4<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x5)] pub type MatrixSlice2x5<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x6)] pub type MatrixSlice2x6<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 3x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x1)] pub type MatrixSlice3x1<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x2)] pub type MatrixSlice3x2<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x4)] pub type MatrixSlice3x4<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x5)] pub type MatrixSlice3x5<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x6)] pub type MatrixSlice3x6<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 4x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x1)] pub type MatrixSlice4x1<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x2)] pub type MatrixSlice4x2<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x3)] pub type MatrixSlice4x3<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x5)] pub type MatrixSlice4x5<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x6)] pub type MatrixSlice4x6<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 5x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x1)] pub type MatrixSlice5x1<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x2)] pub type MatrixSlice5x2<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x3)] pub type MatrixSlice5x3<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x4)] pub type MatrixSlice5x4<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x6)] pub type MatrixSlice5x6<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 6x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x1)] pub type MatrixSlice6x1<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x2)] pub type MatrixSlice6x2<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x3)] pub type MatrixSlice6x3<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x4)] pub type MatrixSlice6x4<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x5)] pub type MatrixSlice6x5<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major matrix slice with 1 row and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView1xX)] pub type MatrixSlice1xX<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major matrix slice with 2 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView2xX)] pub type MatrixSlice2xX<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major matrix slice with 3 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView3xX)] pub type MatrixSlice3xX<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major matrix slice with 4 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView4xX)] pub type MatrixSlice4xX<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major matrix slice with 5 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView5xX)] pub type MatrixSlice5xX<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major matrix slice with 6 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView6xX)] pub type MatrixSlice6xX<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 1 column. -pub type MatrixSliceXx1<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewXx1)] +pub type MatrixSliceXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 2 columns. -pub type MatrixSliceXx2<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewXx2)] +pub type MatrixSliceXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 3 columns. -pub type MatrixSliceXx3<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewXx3)] +pub type MatrixSliceXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 4 columns. -pub type MatrixSliceXx4<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewXx4)] +pub type MatrixSliceXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 5 columns. -pub type MatrixSliceXx5<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewXx5)] +pub type MatrixSliceXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 6 columns. -pub type MatrixSliceXx6<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewXx6)] +pub type MatrixSliceXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column vector slice with dimensions known at compile-time. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView)] pub type VectorSlice<'a, T, D, RStride = U1, CStride = D> = - Matrix>; + Matrix>; /// A column vector slice with dimensions known at compile-time. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SVectorView)] pub type SVectorSlice<'a, T, const D: usize> = - Matrix, Const<1>, SliceStorage<'a, T, Const, Const<1>, Const<1>, Const>>; + Matrix, Const<1>, ViewStorage<'a, T, Const, Const<1>, Const<1>, Const>>; /// A column vector slice dynamic numbers of rows and columns. -pub type DVectorSlice<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(DVectorView)] +pub type DVectorSlice<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A 1D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView1)] pub type VectorSlice1<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A 2D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView2)] pub type VectorSlice2<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A 3D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView3)] pub type VectorSlice3<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A 4D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView4)] pub type VectorSlice4<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A 5D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView5)] pub type VectorSlice5<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A 6D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView6)] pub type VectorSlice6<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /* * @@ -304,297 +364,358 @@ pub type VectorSlice6<'a, T, RStride = U1, CStride = U6> = /// A column-major matrix slice with `R` rows and `C` columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = "Use MatrixViewMut instead, which has an identical definition."] pub type MatrixSliceMutMN<'a, T, R, C, RStride = U1, CStride = R> = - Matrix>; + Matrix>; /// A column-major matrix slice with `D` rows and columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = "Use MatrixViewMut instead."] pub type MatrixSliceMutN<'a, T, D, RStride = U1, CStride = D> = - Matrix>; + Matrix>; /// A column-major matrix slice with dimensions known at compile-time. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SMatrixViewMut)] pub type SMatrixSliceMut<'a, T, const R: usize, const C: usize> = - Matrix, Const, SliceStorageMut<'a, T, Const, Const, Const<1>, Const>>; + Matrix, Const, ViewStorageMut<'a, T, Const, Const, Const<1>, Const>>; /// A column-major matrix slice dynamic numbers of rows and columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** -pub type DMatrixSliceMut<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(DMatrixViewMut)] +pub type DMatrixSliceMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major 1x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1)] pub type MatrixSliceMut1<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 2x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2)] pub type MatrixSliceMut2<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 3x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3)] pub type MatrixSliceMut3<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 4x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4)] pub type MatrixSliceMut4<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 5x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5)] pub type MatrixSliceMut5<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 6x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6)] pub type MatrixSliceMut6<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 1x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x2)] pub type MatrixSliceMut1x2<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x3)] pub type MatrixSliceMut1x3<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x4)] pub type MatrixSliceMut1x4<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x5)] pub type MatrixSliceMut1x5<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 1x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x6)] pub type MatrixSliceMut1x6<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major 2x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x1)] pub type MatrixSliceMut2x1<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x3)] pub type MatrixSliceMut2x3<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x4)] pub type MatrixSliceMut2x4<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x5)] pub type MatrixSliceMut2x5<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 2x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x6)] pub type MatrixSliceMut2x6<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major 3x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x1)] pub type MatrixSliceMut3x1<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x2)] pub type MatrixSliceMut3x2<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x4)] pub type MatrixSliceMut3x4<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x5)] pub type MatrixSliceMut3x5<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 3x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x6)] pub type MatrixSliceMut3x6<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major 4x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x1)] pub type MatrixSliceMut4x1<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x2)] pub type MatrixSliceMut4x2<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x3)] pub type MatrixSliceMut4x3<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x5)] pub type MatrixSliceMut4x5<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 4x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x6)] pub type MatrixSliceMut4x6<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major 5x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x1)] pub type MatrixSliceMut5x1<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x2)] pub type MatrixSliceMut5x2<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x3)] pub type MatrixSliceMut5x3<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x4)] pub type MatrixSliceMut5x4<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 5x6 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x6)] pub type MatrixSliceMut5x6<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major 6x1 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x1)] pub type MatrixSliceMut6x1<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x2 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x2)] pub type MatrixSliceMut6x2<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x3 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x3)] pub type MatrixSliceMut6x3<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x4 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x4)] pub type MatrixSliceMut6x4<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major 6x5 matrix slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x5)] pub type MatrixSliceMut6x5<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major matrix slice with 1 row and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut1xX)] pub type MatrixSliceMut1xX<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A column-major matrix slice with 2 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut2xX)] pub type MatrixSliceMut2xX<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A column-major matrix slice with 3 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut3xX)] pub type MatrixSliceMut3xX<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A column-major matrix slice with 4 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut4xX)] pub type MatrixSliceMut4xX<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A column-major matrix slice with 5 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut5xX)] pub type MatrixSliceMut5xX<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A column-major matrix slice with 6 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut6xX)] pub type MatrixSliceMut6xX<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 1 column. -pub type MatrixSliceMutXx1<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewMutXx1)] +pub type MatrixSliceMutXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 2 columns. -pub type MatrixSliceMutXx2<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewMutXx2)] +pub type MatrixSliceMutXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 3 columns. -pub type MatrixSliceMutXx3<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewMutXx3)] +pub type MatrixSliceMutXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 4 columns. -pub type MatrixSliceMutXx4<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewMutXx4)] +pub type MatrixSliceMutXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 5 columns. -pub type MatrixSliceMutXx5<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewMutXx5)] +pub type MatrixSliceMutXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column-major matrix slice with a number of rows chosen at runtime and 6 columns. -pub type MatrixSliceMutXx6<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(MatrixViewMutXx6)] +pub type MatrixSliceMutXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A column vector slice with dimensions known at compile-time. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut)] pub type VectorSliceMut<'a, T, D, RStride = U1, CStride = D> = - Matrix>; + Matrix>; /// A column vector slice with dimensions known at compile-time. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SVectorViewMut)] pub type SVectorSliceMut<'a, T, const D: usize> = - Matrix, Const<1>, SliceStorageMut<'a, T, Const, Const<1>, Const<1>, Const>>; + Matrix, Const<1>, ViewStorageMut<'a, T, Const, Const<1>, Const<1>, Const>>; /// A column vector slice dynamic numbers of rows and columns. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** -pub type DVectorSliceMut<'a, T, RStride = U1, CStride = Dynamic> = - Matrix>; +#[deprecated = slice_deprecation_note!(DVectorViewMut)] +pub type DVectorSliceMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; /// A 1D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut1)] pub type VectorSliceMut1<'a, T, RStride = U1, CStride = U1> = - Matrix>; + Matrix>; /// A 2D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut2)] pub type VectorSliceMut2<'a, T, RStride = U1, CStride = U2> = - Matrix>; + Matrix>; /// A 3D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut3)] pub type VectorSliceMut3<'a, T, RStride = U1, CStride = U3> = - Matrix>; + Matrix>; /// A 4D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut4)] pub type VectorSliceMut4<'a, T, RStride = U1, CStride = U4> = - Matrix>; + Matrix>; /// A 5D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut5)] pub type VectorSliceMut5<'a, T, RStride = U1, CStride = U5> = - Matrix>; + Matrix>; /// A 6D column vector slice. /// /// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut6)] pub type VectorSliceMut6<'a, T, RStride = U1, CStride = U6> = - Matrix>; + Matrix>; diff --git a/src/base/alias_view.rs b/src/base/alias_view.rs new file mode 100644 index 00000000..19a6caec --- /dev/null +++ b/src/base/alias_view.rs @@ -0,0 +1,875 @@ +use crate::base::dimension::{Dyn, U1, U2, U3, U4, U5, U6}; +use crate::base::matrix_view::{ViewStorage, ViewStorageMut}; +use crate::base::{Const, Matrix}; + +/* + * + * + * Matrix view aliases. + * + * + */ +// NOTE: we can't provide defaults for the strides because it's not supported yet by min_const_generics. +/// An immutable column-major matrix view with dimensions known at compile-time. +/// +/// See [`SMatrixViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SMatrixView<'a, T, const R: usize, const C: usize> = + Matrix, Const, ViewStorage<'a, T, Const, Const, Const<1>, Const>>; + +/// An immutable column-major matrix view dynamic numbers of rows and columns. +/// +/// See [`DMatrixViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DMatrixView<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// An immutable column-major 1x1 matrix view. +/// +/// See [`MatrixViewMut1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 2x2 matrix view. +/// +/// See [`MatrixViewMut2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 3x3 matrix view. +/// +/// See [`MatrixViewMut3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 4x4 matrix view. +/// +/// See [`MatrixViewMut4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 5x5 matrix view. +/// +/// See [`MatrixViewMut5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 6x6 matrix view. +/// +/// See [`MatrixViewMut6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// An immutable column-major 1x2 matrix view. +/// +/// See [`MatrixViewMut1x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x2<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x3 matrix view. +/// +/// See [`MatrixViewMut1x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x3<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x4 matrix view. +/// +/// See [`MatrixViewMut1x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x4<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x5 matrix view. +/// +/// See [`MatrixViewMut1x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x5<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x6 matrix view. +/// +/// See [`MatrixViewMut1x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x6<'a, T, RStride = U1, CStride = U1> = + Matrix>; + +/// An immutable column-major 2x1 matrix view. +/// +/// See [`MatrixViewMut2x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x1<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x3 matrix view. +/// +/// See [`MatrixViewMut2x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x3<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x4 matrix view. +/// +/// See [`MatrixViewMut2x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x4<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x5 matrix view. +/// +/// See [`MatrixViewMut2x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x5<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x6 matrix view. +/// +/// See [`MatrixViewMut2x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x6<'a, T, RStride = U1, CStride = U2> = + Matrix>; + +/// An immutable column-major 3x1 matrix view. +/// +/// See [`MatrixViewMut3x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x1<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x2 matrix view. +/// +/// See [`MatrixViewMut3x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x2<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x4 matrix view. +/// +/// See [`MatrixViewMut3x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x4<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x5 matrix view. +/// +/// See [`MatrixViewMut3x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x5<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x6 matrix view. +/// +/// See [`MatrixViewMut3x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x6<'a, T, RStride = U1, CStride = U3> = + Matrix>; + +/// An immutable column-major 4x1 matrix view. +/// +/// See [`MatrixViewMut4x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x1<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x2 matrix view. +/// +/// See [`MatrixViewMut4x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x2<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x3 matrix view. +/// +/// See [`MatrixViewMut4x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x3<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x5 matrix view. +/// +/// See [`MatrixViewMut4x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x5<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x6 matrix view. +/// +/// See [`MatrixViewMut4x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x6<'a, T, RStride = U1, CStride = U4> = + Matrix>; + +/// An immutable column-major 5x1 matrix view. +/// +/// See [`MatrixViewMut5x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x1<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x2 matrix view. +/// +/// See [`MatrixViewMut5x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x2<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x3 matrix view. +/// +/// See [`MatrixViewMut5x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x3<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x4 matrix view. +/// +/// See [`MatrixViewMut5x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x4<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x6 matrix view. +/// +/// See [`MatrixViewMut5x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x6<'a, T, RStride = U1, CStride = U5> = + Matrix>; + +/// An immutable column-major 6x1 matrix view. +/// +/// See [`MatrixViewMut6x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x1<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x2 matrix view. +/// +/// See [`MatrixViewMut6x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x2<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x3 matrix view. +/// +/// See [`MatrixViewMut6x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x3<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x4 matrix view. +/// +/// See [`MatrixViewMut6x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x4<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x5 matrix view. +/// +/// See [`MatrixViewMut6x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x5<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// An immutable column-major matrix view with 1 row and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut1xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1xX<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major matrix view with 2 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut2xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2xX<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major matrix view with 3 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut3xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3xX<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major matrix view with 4 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut4xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4xX<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major matrix view with 5 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut5xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5xX<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major matrix view with 6 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut6xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6xX<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// An immutable column-major matrix view with a number of rows chosen at runtime and 1 column. +/// +/// See [`MatrixViewMutXx1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 2 columns. +/// +/// See [`MatrixViewMutXx2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 3 columns. +/// +/// See [`MatrixViewMutXx3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 4 columns. +/// +/// See [`MatrixViewMutXx4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 5 columns. +/// +/// See [`MatrixViewMutXx5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 6 columns. +/// +/// See [`MatrixViewMutXx6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// An immutable column vector view with dimensions known at compile-time. +/// +/// See [`VectorViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// An immutable column vector view with dimensions known at compile-time. +/// +/// See [`SVectorViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SVectorView<'a, T, const D: usize> = + Matrix, Const<1>, ViewStorage<'a, T, Const, Const<1>, Const<1>, Const>>; + +/// An immutable column vector view dynamic numbers of rows and columns. +/// +/// See [`DVectorViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DVectorView<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// An immutable 1D column vector view. +/// +/// See [`VectorViewMut1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable 2D column vector view. +/// +/// See [`VectorViewMut2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable 3D column vector view. +/// +/// See [`VectorViewMut3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable 4D column vector view. +/// +/// See [`VectorViewMut4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable 5D column vector view. +/// +/// See [`VectorViewMut5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable 6D column vector view. +/// +/// See [`VectorViewMut6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/* + * + * + * Same thing, but for mutable views. + * + * + */ + +/// A mutable column-major matrix view with dimensions known at compile-time. +/// +/// See [`SMatrixView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SMatrixViewMut<'a, T, const R: usize, const C: usize> = + Matrix, Const, ViewStorageMut<'a, T, Const, Const, Const<1>, Const>>; + +/// A mutable column-major matrix view dynamic numbers of rows and columns. +/// +/// See [`DMatrixView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DMatrixViewMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A mutable column-major 1x1 matrix view. +/// +/// See [`MatrixView1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 2x2 matrix view. +/// +/// See [`MatrixView2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 3x3 matrix view. +/// +/// See [`MatrixView3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 4x4 matrix view. +/// +/// See [`MatrixView4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 5x5 matrix view. +/// +/// See [`MatrixView5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 6x6 matrix view. +/// +/// See [`MatrixView6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A mutable column-major 1x2 matrix view. +/// +/// See [`MatrixView1x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x2<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x3 matrix view. +/// +/// See [`MatrixView1x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x3<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x4 matrix view. +/// +/// See [`MatrixView1x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x4<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x5 matrix view. +/// +/// See [`MatrixView1x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x5<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x6 matrix view. +/// +/// See [`MatrixView1x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x6<'a, T, RStride = U1, CStride = U1> = + Matrix>; + +/// A mutable column-major 2x1 matrix view. +/// +/// See [`MatrixView2x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x1<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x3 matrix view. +/// +/// See [`MatrixView2x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x3<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x4 matrix view. +/// +/// See [`MatrixView2x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x4<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x5 matrix view. +/// +/// See [`MatrixView2x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x5<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x6 matrix view. +/// +/// See [`MatrixView2x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x6<'a, T, RStride = U1, CStride = U2> = + Matrix>; + +/// A mutable column-major 3x1 matrix view. +/// +/// See [`MatrixView3x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x1<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x2 matrix view. +/// +/// See [`MatrixView3x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x2<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x4 matrix view. +/// +/// See [`MatrixView3x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x4<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x5 matrix view. +/// +/// See [`MatrixView3x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x5<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x6 matrix view. +/// +/// See [`MatrixView3x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x6<'a, T, RStride = U1, CStride = U3> = + Matrix>; + +/// A mutable column-major 4x1 matrix view. +/// +/// See [`MatrixView4x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x1<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x2 matrix view. +/// +/// See [`MatrixView4x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x2<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x3 matrix view. +/// +/// See [`MatrixView4x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x3<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x5 matrix view. +/// +/// See [`MatrixView4x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x5<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x6 matrix view. +/// +/// See [`MatrixView4x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x6<'a, T, RStride = U1, CStride = U4> = + Matrix>; + +/// A mutable column-major 5x1 matrix view. +/// +/// See [`MatrixView5x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x1<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x2 matrix view. +/// +/// See [`MatrixView5x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x2<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x3 matrix view. +/// +/// See [`MatrixView5x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x3<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x4 matrix view. +/// +/// See [`MatrixView5x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x4<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x6 matrix view. +/// +/// See [`MatrixView5x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x6<'a, T, RStride = U1, CStride = U5> = + Matrix>; + +/// A mutable column-major 6x1 matrix view. +/// +/// See [`MatrixView6x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x1<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x2 matrix view. +/// +/// See [`MatrixView6x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x2<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x3 matrix view. +/// +/// See [`MatrixView6x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x3<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x4 matrix view. +/// +/// See [`MatrixView6x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x4<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x5 matrix view. +/// +/// See [`MatrixView6x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x5<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A mutable column-major matrix view with 1 row and a number of columns chosen at runtime. +/// +/// See [`MatrixView1xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1xX<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major matrix view with 2 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView2xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2xX<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major matrix view with 3 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView3xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3xX<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major matrix view with 4 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView4xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4xX<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major matrix view with 5 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView5xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5xX<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major matrix view with 6 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView6xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6xX<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A mutable column-major matrix view with a number of rows chosen at runtime and 1 column. +/// +/// See [`MatrixViewXx1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 2 columns. +/// +/// See [`MatrixViewXx2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 3 columns. +/// +/// See [`MatrixViewXx3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 4 columns. +/// +/// See [`MatrixViewXx4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 5 columns. +/// +/// See [`MatrixViewXx5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 6 columns. +/// +/// See [`MatrixViewXx6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A mutable column vector view with dimensions known at compile-time. +/// +/// See [`VectorView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// A mutable column vector view with dimensions known at compile-time. +/// +/// See [`SVectorView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SVectorViewMut<'a, T, const D: usize> = + Matrix, Const<1>, ViewStorageMut<'a, T, Const, Const<1>, Const<1>, Const>>; + +/// A mutable column vector view dynamic numbers of rows and columns. +/// +/// See [`DVectorView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DVectorViewMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A mutable 1D column vector view. +/// +/// See [`VectorView1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable 2D column vector view. +/// +/// See [`VectorView2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable 3D column vector view. +/// +/// See [`VectorView3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable 4D column vector view. +/// +/// See [`VectorView4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable 5D column vector view. +/// +/// See [`VectorView5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable 6D column vector view. +/// +/// See [`VectorView6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut6<'a, T, RStride = U1, CStride = U6> = + Matrix>; diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 29286420..10c4bd31 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -15,14 +15,14 @@ use std::mem::MaybeUninit; /// /// An allocator is said to be: /// − static: if `R` and `C` both implement `DimName`. -/// − dynamic: if either one (or both) of `R` or `C` is equal to `Dynamic`. +/// − dynamic: if either one (or both) of `R` or `C` is equal to `Dyn`. /// /// Every allocator must be both static and dynamic. Though not all implementations may share the /// same `Buffer` type. pub trait Allocator: Any + Sized { - /// The type of buffer this allocator can instanciate. + /// The type of buffer this allocator can instantiate. type Buffer: StorageMut + IsContiguous + Clone + Debug; - /// The type of buffer with uninitialized components this allocator can instanciate. + /// The type of buffer with uninitialized components this allocator can instantiate. type BufferUninit: RawStorageMut, R, C> + IsContiguous; /// Allocates a buffer with the given number of rows and columns without initializing its content. @@ -41,6 +41,41 @@ pub trait Allocator: Any + Sized { ncols: C, iter: I, ) -> Self::Buffer; + + #[inline] + /// Allocates a buffer initialized with the content of the given row-major order iterator. + fn allocate_from_row_iterator>( + nrows: R, + ncols: C, + iter: I, + ) -> Self::Buffer { + let mut res = Self::allocate_uninit(nrows, ncols); + let mut count = 0; + + unsafe { + // OK because the allocated buffer is guaranteed to be contiguous. + let res_ptr = res.as_mut_slice_unchecked(); + + for (k, e) in iter + .into_iter() + .take(ncols.value() * nrows.value()) + .enumerate() + { + let i = k / ncols.value(); + let j = k % ncols.value(); + // result[(i, j)] = e; + *res_ptr.get_unchecked_mut(i + j * nrows.value()) = MaybeUninit::new(e); + count += 1; + } + + assert!( + count == nrows.value() * ncols.value(), + "Matrix init. from row iterator: iterator not long enough." + ); + + >::assume_init(res) + } + } } /// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` × diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index b6bd236a..4ac738a1 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -5,12 +5,15 @@ use std::ops::Mul; #[cfg(feature = "serde-serialize-no-std")] use serde::de::{Error, SeqAccess, Visitor}; #[cfg(feature = "serde-serialize-no-std")] -use serde::ser::SerializeSeq; +use serde::ser::SerializeTuple; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde-serialize-no-std")] use std::marker::PhantomData; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; use crate::base::dimension::{Const, ToTypenum}; @@ -27,7 +30,18 @@ use std::mem; /// A array-based statically sized matrix data storage. #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "ArrayStorage", + bound(archive = " + T: rkyv::Archive, + [[T; R]; C]: rkyv::Archive + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] pub struct ArrayStorage(pub [[T; R]; C]); impl ArrayStorage { @@ -177,7 +191,7 @@ where where S: Serializer, { - let mut serializer = serializer.serialize_seq(Some(R * C))?; + let mut serializer = serializer.serialize_tuple(R * C)?; for e in self.as_slice().iter() { serializer.serialize_element(e)?; @@ -196,7 +210,7 @@ where where D: Deserializer<'a>, { - deserializer.deserialize_seq(ArrayStorageVisitor::new()) + deserializer.deserialize_tuple(R * C, ArrayStorageVisitor::new()) } } @@ -273,45 +287,3 @@ unsafe impl by for ArrayStorage { } - -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::ArrayStorage; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for ArrayStorage { - type Archived = ArrayStorage; - type Resolver = <[[T; R]; C] as Archive>::Resolver; - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut core::mem::MaybeUninit, - ) { - self.0.resolve( - pos + offset_of!(Self::Archived, 0), - resolver, - project_struct!(out: Self::Archived => 0), - ); - } - } - - impl, S: Fallible + ?Sized, const R: usize, const C: usize> Serialize - for ArrayStorage - { - fn serialize(&self, serializer: &mut S) -> Result { - self.0.serialize(serializer) - } - } - - impl - Deserialize, D> for ArrayStorage - where - T::Archived: Deserialize, - { - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(ArrayStorage(self.0.deserialize(deserializer)?)) - } - } -} diff --git a/src/base/blas.rs b/src/base/blas.rs index e65304b5..e5741568 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -7,11 +7,11 @@ use crate::base::blas_uninit::{axcpy_uninit, gemm_uninit, gemv_uninit}; use crate::base::constraint::{ AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, }; -use crate::base::dimension::{Const, Dim, Dynamic, U1, U2, U3, U4}; +use crate::base::dimension::{Const, Dim, Dyn, U1, U2, U3, U4}; use crate::base::storage::{Storage, StorageMut}; use crate::base::uninit::Init; use crate::base::{ - DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice, + DVectorView, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorView, }; /// # Dot/scalar product @@ -363,8 +363,8 @@ where x: &Vector, beta: T, dot: impl Fn( - &DVectorSlice<'_, T, SB::RStride, SB::CStride>, - &DVectorSlice<'_, T, SC::RStride, SC::CStride>, + &DVectorView<'_, T, SB::RStride, SB::CStride>, + &DVectorView<'_, T, SC::RStride, SC::CStride>, ) -> T, ) where T: One, @@ -393,7 +393,7 @@ where let col2 = a.column(0); let val = unsafe { x.vget_unchecked(0).clone() }; self.axpy(alpha.clone() * val, &col2, beta); - self[0] += alpha.clone() * dot(&a.slice_range(1.., 0), &x.rows_range(1..)); + self[0] += alpha.clone() * dot(&a.view_range(1.., 0), &x.rows_range(1..)); for j in 1..dim2 { let col2 = a.column(j); @@ -506,7 +506,7 @@ where a: &Matrix, x: &Vector, beta: T, - dot: impl Fn(&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>, &Vector) -> T, + dot: impl Fn(&VectorView<'_, T, R2, SB::RStride, SB::CStride>, &Vector) -> T, ) where T: One, SB: Storage, @@ -890,9 +890,9 @@ where for j in 0..dim1 { let val = unsafe { conjugate(y.vget_unchecked(j).clone()) }; - let subdim = Dynamic::new(dim1 - j); + let subdim = Dyn(dim1 - j); // TODO: avoid bound checks. - self.generic_slice_mut((j, j), (subdim, Const::<1>)).axpy( + self.generic_view_mut((j, j), (subdim, Const::<1>)).axpy( alpha.clone() * val, &x.rows_range(j..), beta.clone(), diff --git a/src/base/blas_uninit.rs b/src/base/blas_uninit.rs index 7e449d7d..33a7aa70 100644 --- a/src/base/blas_uninit.rs +++ b/src/base/blas_uninit.rs @@ -13,16 +13,17 @@ use matrixmultiply; use num::{One, Zero}; use simba::scalar::{ClosedAdd, ClosedMul}; #[cfg(feature = "std")] -use std::mem; +use std::{any::TypeId, mem}; use crate::base::constraint::{ AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, }; -use crate::base::dimension::{Dim, Dynamic, U1}; +#[cfg(feature = "std")] +use crate::base::dimension::Dyn; +use crate::base::dimension::{Dim, U1}; use crate::base::storage::{RawStorage, RawStorageMut}; use crate::base::uninit::InitStatus; use crate::base::{Matrix, Scalar, Vector}; -use std::any::TypeId; // # Safety // The content of `y` must only contain values for which @@ -209,16 +210,16 @@ pub unsafe fn gemm_uninit< #[cfg(feature = "std")] { - // We assume large matrices will be Dynamic but small matrices static. + // We assume large matrices will be Dyn but small matrices static. // We could use matrixmultiply for large statically-sized matrices but the performance // threshold to activate it would be different from SMALL_DIM because our code optimizes // better for statically-sized matrices. - if R1::is::() - || C1::is::() - || R2::is::() - || C2::is::() - || R3::is::() - || C3::is::() + if R1::is::() + || C1::is::() + || R2::is::() + || C2::is::() + || R3::is::() + || C3::is::() { // matrixmultiply can be used only if the std feature is available. let nrows1 = y.nrows(); diff --git a/src/base/cg.rs b/src/base/cg.rs index ef3ad5b5..586c923e 100644 --- a/src/base/cg.rs +++ b/src/base/cg.rs @@ -59,7 +59,7 @@ where SB: Storage>, { let mut res = Self::identity(); - res.generic_slice_mut( + res.generic_view_mut( (0, D::dim() - 1), (DimNameDiff::::name(), Const::<1>), ) @@ -382,19 +382,19 @@ impl>, { let scale = self - .generic_slice( + .generic_view( (D::dim() - 1, 0), (Const::<1>, DimNameDiff::::name()), ) .tr_dot(shift); - let post_translation = self.generic_slice( + let post_translation = self.generic_view( (0, 0), (DimNameDiff::::name(), DimNameDiff::::name()), ) * shift; self[(D::dim() - 1, D::dim() - 1)] += scale; - let mut translation = self.generic_slice_mut( + let mut translation = self.generic_view_mut( (0, D::dim() - 1), (DimNameDiff::::name(), Const::<1>), ); @@ -415,11 +415,11 @@ where &self, v: &OVector>, ) -> OVector> { - let transform = self.generic_slice( + let transform = self.generic_view( (0, 0), (DimNameDiff::::name(), DimNameDiff::::name()), ); - let normalizer = self.generic_slice( + let normalizer = self.generic_view( (D::dim() - 1, 0), (Const::<1>, DimNameDiff::::name()), ); @@ -437,9 +437,9 @@ impl, Const<3>>> SquareMatrix, /// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates. #[inline] pub fn transform_point(&self, pt: &Point) -> Point { - let transform = self.fixed_slice::<2, 2>(0, 0); - let translation = self.fixed_slice::<2, 1>(0, 2); - let normalizer = self.fixed_slice::<1, 2>(2, 0); + let transform = self.fixed_view::<2, 2>(0, 0); + let translation = self.fixed_view::<2, 1>(0, 2); + let normalizer = self.fixed_view::<1, 2>(2, 0); let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((2, 2)).clone() }; if !n.is_zero() { @@ -454,9 +454,9 @@ impl, Const<4>>> SquareMatrix, /// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates. #[inline] pub fn transform_point(&self, pt: &Point) -> Point { - let transform = self.fixed_slice::<3, 3>(0, 0); - let translation = self.fixed_slice::<3, 1>(0, 3); - let normalizer = self.fixed_slice::<1, 3>(3, 0); + let transform = self.fixed_view::<3, 3>(0, 0); + let translation = self.fixed_view::<3, 1>(0, 3); + let normalizer = self.fixed_view::<1, 3>(3, 0); let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((3, 3)).clone() }; if !n.is_zero() { diff --git a/src/base/constraint.rs b/src/base/constraint.rs index b8febd03..1960cb54 100644 --- a/src/base/constraint.rs +++ b/src/base/constraint.rs @@ -1,12 +1,12 @@ //! Compatibility constraints between matrix shapes, e.g., for addition or multiplication. -use crate::base::dimension::{Dim, DimName, Dynamic}; +use crate::base::dimension::{Dim, DimName, Dyn}; /// A type used in `where` clauses for enforcing constraints. #[derive(Copy, Clone, Debug)] pub struct ShapeConstraint; -/// Constraints `C1` and `R2` to be equivalent. +/// Constrains `C1` and `R2` to be equivalent. pub trait AreMultipliable: DimEq {} impl AreMultipliable for ShapeConstraint where @@ -14,7 +14,7 @@ impl AreMultipliable for Sha { } -/// Constraints `D1` and `D2` to be equivalent. +/// Constrains `D1` and `D2` to be equivalent. pub trait DimEq { /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level /// constant. @@ -25,17 +25,17 @@ impl DimEq for ShapeConstraint { type Representative = D; } -impl DimEq for ShapeConstraint { +impl DimEq for ShapeConstraint { type Representative = D; } -impl DimEq for ShapeConstraint { +impl DimEq for ShapeConstraint { type Representative = D; } macro_rules! equality_trait_decl( ($($doc: expr, $Trait: ident),* $(,)*) => {$( - // XXX: we can't do something like `DimEq for D2` because we would require a blancket impl… + // XXX: we can't do something like `DimEq for D2` because we would require a blanket impl… #[doc = $doc] pub trait $Trait: DimEq + DimEq { /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level @@ -47,28 +47,28 @@ macro_rules! equality_trait_decl( type Representative = D; } - impl $Trait for ShapeConstraint { + impl $Trait for ShapeConstraint { type Representative = D; } - impl $Trait for ShapeConstraint { + impl $Trait for ShapeConstraint { type Representative = D; } )*} ); equality_trait_decl!( - "Constraints `D1` and `D2` to be equivalent. \ + "Constrains `D1` and `D2` to be equivalent. \ They are both assumed to be the number of \ rows of a matrix.", SameNumberOfRows, - "Constraints `D1` and `D2` to be equivalent. \ + "Constrains `D1` and `D2` to be equivalent. \ They are both assumed to be the number of \ columns of a matrix.", SameNumberOfColumns ); -/// Constraints D1 and D2 to be equivalent, where they both designate dimensions of algebraic +/// Constrains D1 and D2 to be equivalent, where they both designate dimensions of algebraic /// entities (e.g. square matrices). pub trait SameDimension: SameNumberOfRows + SameNumberOfColumns @@ -82,10 +82,10 @@ impl SameDimension for ShapeConstraint { type Representative = D; } -impl SameDimension for ShapeConstraint { +impl SameDimension for ShapeConstraint { type Representative = D; } -impl SameDimension for ShapeConstraint { +impl SameDimension for ShapeConstraint { type Representative = D; } diff --git a/src/base/construction.rs b/src/base/construction.rs index fe4e4b08..43475179 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -19,7 +19,7 @@ use typenum::{self, Cmp, Greater}; use simba::scalar::{ClosedAdd, ClosedMul}; use crate::base::allocator::Allocator; -use crate::base::dimension::{Dim, DimName, Dynamic, ToTypenum}; +use crate::base::dimension::{Dim, DimName, Dyn, ToTypenum}; use crate::base::storage::RawStorage; use crate::base::{ ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector, @@ -86,6 +86,17 @@ where Self::from_data(DefaultAllocator::allocate_from_iterator(nrows, ncols, iter)) } + /// Creates a matrix with all its elements filled by an row-major order iterator. + #[inline] + pub fn from_row_iterator_generic(nrows: R, ncols: C, iter: I) -> Self + where + I: IntoIterator, + { + Self::from_data(DefaultAllocator::allocate_from_row_iterator( + nrows, ncols, iter, + )) + } + /// Creates a matrix with its elements filled with the components provided by a slice in /// row-major order. /// @@ -215,7 +226,7 @@ where SB: RawStorage, C>, { assert!(!rows.is_empty(), "At least one row must be given."); - let nrows = R::try_to_usize().unwrap_or_else(|| rows.len()); + let nrows = R::try_to_usize().unwrap_or(rows.len()); let ncols = rows[0].len(); assert!( rows.len() == nrows, @@ -257,7 +268,7 @@ where SB: RawStorage, { assert!(!columns.is_empty(), "At least one column must be given."); - let ncols = C::try_to_usize().unwrap_or_else(|| columns.len()); + let ncols = C::try_to_usize().unwrap_or(columns.len()); let nrows = columns[0].len(); assert!( columns.len() == ncols, @@ -306,12 +317,12 @@ where /// /// # Example /// ``` - /// # use nalgebra::{Dynamic, DMatrix, Matrix, Const}; + /// # use nalgebra::{Dyn, DMatrix, Matrix, Const}; /// /// let vec = vec![0, 1, 2, 3, 4, 5]; /// let vec_ptr = vec.as_ptr(); /// - /// let matrix = Matrix::from_vec_generic(Dynamic::new(vec.len()), Const::<1>, vec); + /// let matrix = Matrix::from_vec_generic(Dyn(vec.len()), Const::<1>, vec); /// let matrix_storage_ptr = matrix.data.as_vec().as_ptr(); /// /// // `matrix` is backed by exactly the same `Vec` as it was constructed from. @@ -479,6 +490,36 @@ macro_rules! impl_constructors( Self::from_iterator_generic($($gargs, )* iter) } + /// Creates a matrix or vector with all its elements filled by a row-major iterator. + /// + /// The output matrix is filled row-by-row. + /// + /// ## Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_row_iterator((0..3).into_iter()); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_row_iterator(3, (0..3).into_iter()); + /// let m = Matrix2x3::from_row_iterator((0..6).into_iter()); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_row_iterator(2, 3, (0..6).into_iter()); + /// + /// // For Vectors from_row_iterator is identical to from_iterator + /// 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_iterator($($args: usize,)* iter: I) -> Self + where I: IntoIterator { + Self::from_row_iterator_generic($($gargs, )* iter) + } + /// Creates a matrix or vector filled with the results of a function applied to each of its /// component coordinates. /// @@ -615,35 +656,35 @@ where } /// # Constructors of matrices with a dynamic number of columns -impl OMatrix +impl OMatrix where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { - impl_constructors!(R, Dynamic; + impl_constructors!(R, Dyn; => R: DimName; - R::name(), Dynamic::new(ncols); + R::name(), Dyn(ncols); ncols); } /// # Constructors of dynamic vectors and matrices with a dynamic number of rows -impl OMatrix +impl OMatrix where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { - impl_constructors!(Dynamic, C; + impl_constructors!(Dyn, C; => C: DimName; - Dynamic::new(nrows), C::name(); + Dyn(nrows), C::name(); nrows); } /// # Constructors of fully dynamic matrices -impl OMatrix +impl OMatrix where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { - impl_constructors!(Dynamic, Dynamic; + impl_constructors!(Dyn, Dyn; ; - Dynamic::new(nrows), Dynamic::new(ncols); + Dyn(nrows), Dyn(ncols); nrows, ncols); } @@ -749,19 +790,19 @@ impl_constructors_from_data!(data; R, C; // Arguments for Matri R::name(), C::name(); // Arguments for `_generic` constructors. ); // Arguments for non-generic constructors. -impl_constructors_from_data!(data; R, Dynamic; +impl_constructors_from_data!(data; R, Dyn; => R: DimName; -R::name(), Dynamic::new(data.len() / R::dim()); +R::name(), Dyn(data.len() / R::dim()); ); -impl_constructors_from_data!(data; Dynamic, C; +impl_constructors_from_data!(data; Dyn, C; => C: DimName; -Dynamic::new(data.len() / C::dim()), C::name(); +Dyn(data.len() / C::dim()), C::name(); ); -impl_constructors_from_data!(data; Dynamic, Dynamic; +impl_constructors_from_data!(data; Dyn, Dyn; ; - Dynamic::new(nrows), Dynamic::new(ncols); + Dyn(nrows), Dyn(ncols); nrows, ncols); /* diff --git a/src/base/construction_slice.rs b/src/base/construction_view.rs similarity index 67% rename from src/base/construction_slice.rs rename to src/base/construction_view.rs index 7094bdca..21819e04 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_view.rs @@ -1,18 +1,18 @@ -use crate::base::dimension::{Const, Dim, DimName, Dynamic}; -use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; -use crate::base::{MatrixSlice, MatrixSliceMutMN, Scalar}; +use crate::base::dimension::{Const, Dim, DimName, Dyn}; +use crate::base::matrix_view::{ViewStorage, ViewStorageMut}; +use crate::base::{MatrixView, MatrixViewMut, Scalar}; use num_rational::Ratio; -/// # Creating matrix slices from `&[T]` +/// # Creating matrix views from `&[T]` impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> - MatrixSlice<'a, T, R, C, RStride, CStride> + MatrixView<'a, T, R, C, RStride, CStride> { - /// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances. + /// Creates, without bounds checking, a matrix view from an array and with dimensions and strides specified by generic types instances. /// /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. - /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub unsafe fn from_slice_with_strides_generic_unchecked( data: &'a [T], @@ -22,7 +22,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> rstride: RStride, cstride: CStride, ) -> Self { - let data = SliceStorage::from_raw_parts( + let data = ViewStorage::from_raw_parts( data.as_ptr().add(start), (nrows, ncols), (rstride, cstride), @@ -30,10 +30,10 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Self::from_data(data) } - /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances. + /// Creates a matrix view from an array and with dimensions and strides specified by generic types instances. /// /// Panics if the input data array dose not contain enough elements. - /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub fn from_slice_with_strides_generic( data: &'a [T], @@ -48,7 +48,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> assert!( data.len() + cstride.value() + rstride.value() >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1, - "Matrix slice: input data buffer to small." + "Matrix view: input data buffer too small." ); unsafe { @@ -57,12 +57,12 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> } } -impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> { - /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances. +impl<'a, T: Scalar, R: Dim, C: Dim> MatrixView<'a, T, R, C> { + /// Creates, without bound-checking, a matrix view from an array and with dimensions specified by generic types instances. /// /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. - /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub unsafe fn from_slice_generic_unchecked( data: &'a [T], @@ -75,10 +75,10 @@ impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> { ) } - /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances. + /// Creates a matrix view from an array and with dimensions and strides specified by generic types instances. /// /// Panics if the input data array dose not contain enough elements. - /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub fn from_slice_generic(data: &'a [T], nrows: R, ncols: C) -> Self { Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows) @@ -87,8 +87,8 @@ impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> { macro_rules! impl_constructors( ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { - impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSlice<'a, T, $($Dims),*> { - /// Creates a new matrix slice from the given data array. + impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixView<'a, T, $($Dims),*> { + /// Creates a new matrix view from the given data array. /// /// Panics if `data` does not contain enough elements. #[inline] @@ -96,26 +96,33 @@ macro_rules! impl_constructors( Self::from_slice_generic(data, $($gargs),*) } - /// Creates, without bound checking, a new matrix slice from the given data array. + /// Creates, without bound checking, a new matrix view from the given data array. + /// # Safety + /// `data[start..start+rstride * cstride]` must be within bounds. #[inline] pub unsafe fn from_slice_unchecked(data: &'a [T], start: usize, $($args: usize),*) -> Self { Self::from_slice_generic_unchecked(data, start, $($gargs),*) } } - impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSlice<'a, T, $($Dims,)* Dynamic, Dynamic> { - /// Creates a new matrix slice with the specified strides from the given data array. + impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixView<'a, T, $($Dims,)* Dyn, Dyn> { + /// Creates a new matrix view with the specified strides from the given data array. /// /// Panics if `data` does not contain enough elements. #[inline] pub fn from_slice_with_strides(data: &'a [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self { - Self::from_slice_with_strides_generic(data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) + Self::from_slice_with_strides_generic(data, $($gargs,)* Dyn(rstride), Dyn(cstride)) } - /// Creates, without bound checking, a new matrix slice with the specified strides from the given data array. + /// Creates, without bound checking, a new matrix view with the specified strides from the given data array. + /// + /// # Safety + /// + /// `start`, `rstride`, and `cstride`, with the given matrix size will not index + /// outside of `data`. #[inline] pub unsafe fn from_slice_with_strides_unchecked(data: &'a [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { - Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) + Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dyn(rstride), Dyn(cstride)) } } } @@ -127,30 +134,30 @@ impl_constructors!(R, C; // Arguments for Matrix R: DimName; - R::name(), Dynamic::new(ncols); + R::name(), Dyn(ncols); ncols); -impl_constructors!(Dynamic, C; +impl_constructors!(Dyn, C; => C: DimName; - Dynamic::new(nrows), C::name(); + Dyn(nrows), C::name(); nrows); -impl_constructors!(Dynamic, Dynamic; +impl_constructors!(Dyn, Dyn; ; - Dynamic::new(nrows), Dynamic::new(ncols); + Dyn(nrows), Dyn(ncols); nrows, ncols); -/// # Creating mutable matrix slices from `&mut [T]` +/// # Creating mutable matrix views from `&mut [T]` impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> - MatrixSliceMutMN<'a, T, R, C, RStride, CStride> + MatrixViewMut<'a, T, R, C, RStride, CStride> { - /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances. + /// Creates, without bound-checking, a mutable matrix view from an array and with dimensions and strides specified by generic types instances. /// /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. - /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub unsafe fn from_slice_with_strides_generic_unchecked( data: &'a mut [T], @@ -160,7 +167,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> rstride: RStride, cstride: CStride, ) -> Self { - let data = SliceStorageMut::from_raw_parts( + let data = ViewStorageMut::from_raw_parts( data.as_mut_ptr().add(start), (nrows, ncols), (rstride, cstride), @@ -168,10 +175,10 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Self::from_data(data) } - /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances. + /// Creates a mutable matrix view from an array and with dimensions and strides specified by generic types instances. /// /// Panics if the input data array dose not contain enough elements. - /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub fn from_slice_with_strides_generic( data: &'a mut [T], @@ -186,7 +193,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> assert!( data.len() + cstride.value() + rstride.value() >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1, - "Matrix slice: input data buffer to small." + "Matrix view: input data buffer too small." ); assert!( @@ -208,7 +215,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> } } }, - "Matrix slice: dimensions and strides result in aliased indices." + "Matrix view: dimensions and strides result in aliased indices." ); unsafe { @@ -217,12 +224,12 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> } } -impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> { - /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances. +impl<'a, T: Scalar, R: Dim, C: Dim> MatrixViewMut<'a, T, R, C> { + /// Creates, without bound-checking, a mutable matrix view from an array and with dimensions specified by generic types instances. /// /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. - /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub unsafe fn from_slice_generic_unchecked( data: &'a mut [T], @@ -235,10 +242,10 @@ impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> { ) } - /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances. + /// Creates a mutable matrix view from an array and with dimensions and strides specified by generic types instances. /// /// Panics if the input data array dose not contain enough elements. - /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. #[inline] pub fn from_slice_generic(data: &'a mut [T], nrows: R, ncols: C) -> Self { Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows) @@ -247,8 +254,8 @@ impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> { macro_rules! impl_constructors_mut( ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { - impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, T, $($Dims),*> { - /// Creates a new mutable matrix slice from the given data array. + impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixViewMut<'a, T, $($Dims),*> { + /// Creates a new mutable matrix view from the given data array. /// /// Panics if `data` does not contain enough elements. #[inline] @@ -256,28 +263,34 @@ macro_rules! impl_constructors_mut( Self::from_slice_generic(data, $($gargs),*) } - /// Creates, without bound checking, a new mutable matrix slice from the given data array. + /// Creates, without bound checking, a new mutable matrix view from the given data array. + /// + /// # Safety + /// + /// `data[start..start+(R * C)]` must be within bounds. #[inline] pub unsafe fn from_slice_unchecked(data: &'a mut [T], start: usize, $($args: usize),*) -> Self { Self::from_slice_generic_unchecked(data, start, $($gargs),*) } } - impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, T, $($Dims,)* Dynamic, Dynamic> { - /// Creates a new mutable matrix slice with the specified strides from the given data array. + impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixViewMut<'a, T, $($Dims,)* Dyn, Dyn> { + /// Creates a new mutable matrix view with the specified strides from the given data array. /// /// Panics if `data` does not contain enough elements. #[inline] pub fn from_slice_with_strides_mut(data: &'a mut [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self { Self::from_slice_with_strides_generic( - data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) + data, $($gargs,)* Dyn(rstride), Dyn(cstride)) } - /// Creates, without bound checking, a new mutable matrix slice with the specified strides from the given data array. + /// Creates, without bound checking, a new mutable matrix view with the specified strides from the given data array. + /// # Safety + /// `data[start..start+rstride * cstride]` must be within bounds. #[inline] pub unsafe fn from_slice_with_strides_unchecked(data: &'a mut [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { Self::from_slice_with_strides_generic_unchecked( - data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride)) + data, start, $($gargs,)* Dyn(rstride), Dyn(cstride)) } } } @@ -289,17 +302,17 @@ impl_constructors_mut!(R, C; // Arguments for Matrix R: DimName; - R::name(), Dynamic::new(ncols); + R::name(), Dyn(ncols); ncols); -impl_constructors_mut!(Dynamic, C; +impl_constructors_mut!(Dyn, C; => C: DimName; - Dynamic::new(nrows), C::name(); + Dyn(nrows), C::name(); nrows); -impl_constructors_mut!(Dynamic, Dynamic; +impl_constructors_mut!(Dyn, Dyn; ; - Dynamic::new(nrows), Dynamic::new(ncols); + Dyn(nrows), Dyn(ncols); nrows, ncols); diff --git a/src/base/conversion.rs b/src/base/conversion.rs index dd71186f..783e6d9e 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -8,22 +8,22 @@ use simba::simd::{PrimitiveSimdValue, SimdValue}; use crate::base::allocator::{Allocator, SameShapeAllocator}; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -#[cfg(any(feature = "std", feature = "alloc"))] -use crate::base::dimension::Dynamic; use crate::base::dimension::{ - Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, + Const, Dim, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, }; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::dimension::{DimName, Dyn}; use crate::base::iter::{MatrixIter, MatrixIterMut}; use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut}; use crate::base::{ - ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice, - MatrixSliceMut, OMatrix, Scalar, + ArrayStorage, DVectorView, DVectorViewMut, DefaultAllocator, Matrix, MatrixView, MatrixViewMut, + OMatrix, Scalar, }; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::{DVector, RowDVector, VecStorage}; -use crate::base::{SliceStorage, SliceStorageMut}; +use crate::base::{ViewStorage, ViewStorageMut}; use crate::constraint::DimEq; -use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector, VectorSlice, VectorSliceMut}; +use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector, VectorView, VectorViewMut}; use std::mem::MaybeUninit; // TODO: too bad this won't work for slice conversions. @@ -98,6 +98,18 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorage> IntoIterator } } +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> IntoIterator + for Matrix> +{ + type Item = &'a T; + type IntoIter = MatrixIter<'a, T, R, C, ViewStorage<'a, T, R, C, RStride, CStride>>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + MatrixIter::new_owned(self.data) + } +} + impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut> IntoIterator for &'a mut Matrix { @@ -110,6 +122,18 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut> IntoIterator } } +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> IntoIterator + for Matrix> +{ + type Item = &'a mut T; + type IntoIter = MatrixIterMut<'a, T, R, C, ViewStorageMut<'a, T, R, C, RStride, CStride>>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + MatrixIterMut::new_owned_mut(self.data) + } +} + impl From<[T; D]> for SVector { #[inline] fn from(arr: [T; D]) -> Self { @@ -126,19 +150,19 @@ impl From> for [T; D] { } impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const D: usize> - From, RStride, CStride>> for [T; D] + From, RStride, CStride>> for [T; D] { #[inline] - fn from(vec: VectorSlice<'a, T, Const, RStride, CStride>) -> Self { + fn from(vec: VectorView<'a, T, Const, RStride, CStride>) -> Self { vec.into_owned().into() } } impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const D: usize> - From, RStride, CStride>> for [T; D] + From, RStride, CStride>> for [T; D] { #[inline] - fn from(vec: VectorSliceMut<'a, T, Const, RStride, CStride>) -> Self { + fn from(vec: VectorViewMut<'a, T, Const, RStride, CStride>) -> Self { vec.into_owned().into() } } @@ -221,19 +245,19 @@ impl From> for [[T; } impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const R: usize, const C: usize> - From, Const, RStride, CStride>> for [[T; R]; C] + From, Const, RStride, CStride>> for [[T; R]; C] { #[inline] - fn from(mat: MatrixSlice<'a, T, Const, Const, RStride, CStride>) -> Self { + fn from(mat: MatrixView<'a, T, Const, Const, RStride, CStride>) -> Self { mat.into_owned().into() } } impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const R: usize, const C: usize> - From, Const, RStride, CStride>> for [[T; R]; C] + From, Const, RStride, CStride>> for [[T; R]; C] { #[inline] - fn from(mat: MatrixSliceMut<'a, T, Const, Const, RStride, CStride>) -> Self { + fn from(mat: MatrixViewMut<'a, T, Const, Const, RStride, CStride>) -> Self { mat.into_owned().into() } } @@ -289,192 +313,183 @@ impl_from_into_asref_borrow_2D!( ); impl<'a, T, RStride, CStride, const R: usize, const C: usize> - From, Const, RStride, CStride>> + From, Const, RStride, CStride>> for Matrix, Const, ArrayStorage> where T: Scalar, RStride: Dim, CStride: Dim, { - fn from(matrix_slice: MatrixSlice<'a, T, Const, Const, RStride, CStride>) -> Self { - matrix_slice.into_owned() + fn from(matrix_view: MatrixView<'a, T, Const, Const, RStride, CStride>) -> Self { + matrix_view.into_owned() } } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, T, C, RStride, CStride> From> - for Matrix> +impl<'a, T, C, RStride, CStride> From> + for Matrix> where T: Scalar, C: Dim, RStride: Dim, CStride: Dim, { - fn from(matrix_slice: MatrixSlice<'a, T, Dynamic, C, RStride, CStride>) -> Self { - matrix_slice.into_owned() + fn from(matrix_view: MatrixView<'a, T, Dyn, C, RStride, CStride>) -> Self { + matrix_view.into_owned() } } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, T, R, RStride, CStride> From> - for Matrix> +impl<'a, T, R, RStride, CStride> From> + for Matrix> where T: Scalar, R: DimName, RStride: Dim, CStride: Dim, { - fn from(matrix_slice: MatrixSlice<'a, T, R, Dynamic, RStride, CStride>) -> Self { - matrix_slice.into_owned() + fn from(matrix_view: MatrixView<'a, T, R, Dyn, RStride, CStride>) -> Self { + matrix_view.into_owned() } } impl<'a, T, RStride, CStride, const R: usize, const C: usize> - From, Const, RStride, CStride>> + From, Const, RStride, CStride>> for Matrix, Const, ArrayStorage> where T: Scalar, RStride: Dim, CStride: Dim, { - fn from(matrix_slice: MatrixSliceMut<'a, T, Const, Const, RStride, CStride>) -> Self { - matrix_slice.into_owned() + fn from(matrix_view: MatrixViewMut<'a, T, Const, Const, RStride, CStride>) -> Self { + matrix_view.into_owned() } } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, T, C, RStride, CStride> From> - for Matrix> +impl<'a, T, C, RStride, CStride> From> + for Matrix> where T: Scalar, C: Dim, RStride: Dim, CStride: Dim, { - fn from(matrix_slice: MatrixSliceMut<'a, T, Dynamic, C, RStride, CStride>) -> Self { - matrix_slice.into_owned() + fn from(matrix_view: MatrixViewMut<'a, T, Dyn, C, RStride, CStride>) -> Self { + matrix_view.into_owned() } } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, T, R, RStride, CStride> From> - for Matrix> +impl<'a, T, R, RStride, CStride> From> + for Matrix> where T: Scalar, R: DimName, RStride: Dim, CStride: Dim, { - fn from(matrix_slice: MatrixSliceMut<'a, T, R, Dynamic, RStride, CStride>) -> Self { - matrix_slice.into_owned() + fn from(matrix_view: MatrixViewMut<'a, T, R, Dyn, RStride, CStride>) -> Self { + matrix_view.into_owned() } } -impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a Matrix> - for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride> +impl<'a, T, R, C, RView, CView, RStride, CStride, S> From<&'a Matrix> + for MatrixView<'a, T, RView, CView, RStride, CStride> where - T: Scalar, R: Dim, C: Dim, - RSlice: Dim, - CSlice: Dim, + RView: Dim, + CView: Dim, RStride: Dim, CStride: Dim, S: RawStorage, - ShapeConstraint: DimEq - + DimEq - + DimEq - + DimEq, + ShapeConstraint: + DimEq + DimEq + DimEq + DimEq, { fn from(m: &'a Matrix) -> Self { let (row, col) = m.shape_generic(); - let row_slice = RSlice::from_usize(row.value()); - let col_slice = CSlice::from_usize(col.value()); + let rows_result = RView::from_usize(row.value()); + let cols_result = CView::from_usize(col.value()); let (rstride, cstride) = m.strides(); - let rstride_slice = RStride::from_usize(rstride); - let cstride_slice = CStride::from_usize(cstride); + let rstride_result = RStride::from_usize(rstride); + let cstride_result = CStride::from_usize(cstride); unsafe { - let data = SliceStorage::from_raw_parts( + let data = ViewStorage::from_raw_parts( m.data.ptr(), - (row_slice, col_slice), - (rstride_slice, cstride_slice), + (rows_result, cols_result), + (rstride_result, cstride_result), ); Matrix::from_data_statically_unchecked(data) } } } -impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix> - for MatrixSlice<'a, T, RSlice, CSlice, RStride, CStride> +impl<'a, T, R, C, RView, CView, RStride, CStride, S> From<&'a mut Matrix> + for MatrixView<'a, T, RView, CView, RStride, CStride> where - T: Scalar, R: Dim, C: Dim, - RSlice: Dim, - CSlice: Dim, + RView: Dim, + CView: Dim, RStride: Dim, CStride: Dim, S: RawStorage, - ShapeConstraint: DimEq - + DimEq - + DimEq - + DimEq, + ShapeConstraint: + DimEq + DimEq + DimEq + DimEq, { fn from(m: &'a mut Matrix) -> Self { let (row, col) = m.shape_generic(); - let row_slice = RSlice::from_usize(row.value()); - let col_slice = CSlice::from_usize(col.value()); + let rows_result = RView::from_usize(row.value()); + let cols_result = CView::from_usize(col.value()); let (rstride, cstride) = m.strides(); - let rstride_slice = RStride::from_usize(rstride); - let cstride_slice = CStride::from_usize(cstride); + let rstride_result = RStride::from_usize(rstride); + let cstride_result = CStride::from_usize(cstride); unsafe { - let data = SliceStorage::from_raw_parts( + let data = ViewStorage::from_raw_parts( m.data.ptr(), - (row_slice, col_slice), - (rstride_slice, cstride_slice), + (rows_result, cols_result), + (rstride_result, cstride_result), ); Matrix::from_data_statically_unchecked(data) } } } -impl<'a, T, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix> - for MatrixSliceMut<'a, T, RSlice, CSlice, RStride, CStride> +impl<'a, T, R, C, RView, CView, RStride, CStride, S> From<&'a mut Matrix> + for MatrixViewMut<'a, T, RView, CView, RStride, CStride> where - T: Scalar, R: Dim, C: Dim, - RSlice: Dim, - CSlice: Dim, + RView: Dim, + CView: Dim, RStride: Dim, CStride: Dim, S: RawStorageMut, - ShapeConstraint: DimEq - + DimEq - + DimEq - + DimEq, + ShapeConstraint: + DimEq + DimEq + DimEq + DimEq, { fn from(m: &'a mut Matrix) -> Self { let (row, col) = m.shape_generic(); - let row_slice = RSlice::from_usize(row.value()); - let col_slice = CSlice::from_usize(col.value()); + let rows_result = RView::from_usize(row.value()); + let cols_result = CView::from_usize(col.value()); let (rstride, cstride) = m.strides(); - let rstride_slice = RStride::from_usize(rstride); - let cstride_slice = CStride::from_usize(cstride); + let rstride_result = RStride::from_usize(rstride); + let cstride_result = CStride::from_usize(cstride); unsafe { - let data = SliceStorageMut::from_raw_parts( + let data = ViewStorageMut::from_raw_parts( m.data.ptr_mut(), - (row_slice, col_slice), - (rstride_slice, cstride_slice), + (rows_result, cols_result), + (rstride_result, cstride_result), ); Matrix::from_data_statically_unchecked(data) } @@ -482,7 +497,7 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, T: Scalar> From> for DVector { +impl From> for DVector { #[inline] fn from(vec: Vec) -> Self { Self::from_vec(vec) @@ -490,7 +505,7 @@ impl<'a, T: Scalar> From> for DVector { } #[cfg(any(feature = "std", feature = "alloc"))] -impl<'a, T: Scalar> From> for RowDVector { +impl From> for RowDVector { #[inline] fn from(vec: Vec) -> Self { Self::from_vec(vec) @@ -515,28 +530,28 @@ impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut + IsContigu } } -impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorSlice<'a, T> { +impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorView<'a, T> { #[inline] fn from(slice: &'a [T]) -> Self { Self::from_slice(slice, slice.len()) } } -impl<'a, T: Scalar> From> for &'a [T] { - fn from(vec: DVectorSlice<'a, T>) -> &'a [T] { +impl<'a, T: Scalar> From> for &'a [T] { + fn from(vec: DVectorView<'a, T>) -> &'a [T] { vec.data.into_slice() } } -impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> { +impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorViewMut<'a, T> { #[inline] fn from(slice: &'a mut [T]) -> Self { Self::from_slice(slice, slice.len()) } } -impl<'a, T: Scalar> From> for &'a mut [T] { - fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] { +impl<'a, T: Scalar> From> for &'a mut [T] { + fn from(vec: DVectorViewMut<'a, T>) -> &'a mut [T] { vec.data.into_slice_mut() } } diff --git a/src/base/default_allocator.rs b/src/base/default_allocator.rs index 09197bbd..3c132413 100644 --- a/src/base/default_allocator.rs +++ b/src/base/default_allocator.rs @@ -12,21 +12,23 @@ use alloc::vec::Vec; use super::Const; use crate::base::allocator::{Allocator, Reallocator}; use crate::base::array_storage::ArrayStorage; +use crate::base::dimension::Dim; #[cfg(any(feature = "alloc", feature = "std"))] -use crate::base::dimension::Dynamic; -use crate::base::dimension::{Dim, DimName}; +use crate::base::dimension::{DimName, Dyn}; use crate::base::storage::{RawStorage, RawStorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::vec_storage::VecStorage; use crate::base::Scalar; -use std::mem::{ManuallyDrop, MaybeUninit}; +#[cfg(any(feature = "std", feature = "alloc"))] +use std::mem::ManuallyDrop; +use std::mem::MaybeUninit; /* * * Allocator. * */ -/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized +/// An allocator based on [`ArrayStorage`] and [`VecStorage`] for statically-sized and dynamically-sized /// matrices respectively. #[derive(Copy, Clone, Debug)] pub struct DefaultAllocator; @@ -82,15 +84,15 @@ impl Allocator, Const> } } -// Dynamic - Static -// Dynamic - Dynamic +// Dyn - Static +// Dyn - Dyn #[cfg(any(feature = "std", feature = "alloc"))] -impl Allocator for DefaultAllocator { - type Buffer = VecStorage; - type BufferUninit = VecStorage, Dynamic, C>; +impl Allocator for DefaultAllocator { + type Buffer = VecStorage; + type BufferUninit = VecStorage, Dyn, C>; #[inline] - fn allocate_uninit(nrows: Dynamic, ncols: C) -> VecStorage, Dynamic, C> { + fn allocate_uninit(nrows: Dyn, ncols: C) -> VecStorage, Dyn, C> { let mut data = Vec::new(); let length = nrows.value() * ncols.value(); data.reserve_exact(length); @@ -99,9 +101,7 @@ impl Allocator for DefaultAllocator { } #[inline] - unsafe fn assume_init( - uninit: VecStorage, Dynamic, C>, - ) -> VecStorage { + unsafe fn assume_init(uninit: VecStorage, Dyn, C>) -> VecStorage { // Avoids a double-drop. let (nrows, ncols) = uninit.shape(); let vec: Vec<_> = uninit.into(); @@ -117,7 +117,7 @@ impl Allocator for DefaultAllocator { #[inline] fn allocate_from_iterator>( - nrows: Dynamic, + nrows: Dyn, ncols: C, iter: I, ) -> Self::Buffer { @@ -130,14 +130,14 @@ impl Allocator for DefaultAllocator { } } -// Static - Dynamic +// Static - Dyn #[cfg(any(feature = "std", feature = "alloc"))] -impl Allocator for DefaultAllocator { - type Buffer = VecStorage; - type BufferUninit = VecStorage, R, Dynamic>; +impl Allocator for DefaultAllocator { + type Buffer = VecStorage; + type BufferUninit = VecStorage, R, Dyn>; #[inline] - fn allocate_uninit(nrows: R, ncols: Dynamic) -> VecStorage, R, Dynamic> { + fn allocate_uninit(nrows: R, ncols: Dyn) -> VecStorage, R, Dyn> { let mut data = Vec::new(); let length = nrows.value() * ncols.value(); data.reserve_exact(length); @@ -147,9 +147,7 @@ impl Allocator for DefaultAllocator { } #[inline] - unsafe fn assume_init( - uninit: VecStorage, R, Dynamic>, - ) -> VecStorage { + unsafe fn assume_init(uninit: VecStorage, R, Dyn>) -> VecStorage { // Avoids a double-drop. let (nrows, ncols) = uninit.shape(); let vec: Vec<_> = uninit.into(); @@ -166,7 +164,7 @@ impl Allocator for DefaultAllocator { #[inline] fn allocate_from_iterator>( nrows: R, - ncols: Dynamic, + ncols: Dyn, iter: I, ) -> Self::Buffer { let it = iter.into_iter(); @@ -215,20 +213,20 @@ where } } -// Static × Static -> Dynamic × Any +// Static × Static -> Dyn × Any #[cfg(any(feature = "std", feature = "alloc"))] impl - Reallocator, Const, Dynamic, CTo> for DefaultAllocator + Reallocator, Const, Dyn, CTo> for DefaultAllocator where CTo: Dim, { #[inline] unsafe fn reallocate_copy( - rto: Dynamic, + rto: Dyn, cto: CTo, buf: ArrayStorage, - ) -> VecStorage, Dynamic, CTo> { - let mut res = >::allocate_uninit(rto, cto); + ) -> VecStorage, Dyn, CTo> { + let mut res = >::allocate_uninit(rto, cto); let (rfrom, cfrom) = buf.shape(); @@ -246,20 +244,20 @@ where } } -// Static × Static -> Static × Dynamic +// Static × Static -> Static × Dyn #[cfg(any(feature = "std", feature = "alloc"))] impl - Reallocator, Const, RTo, Dynamic> for DefaultAllocator + Reallocator, Const, RTo, Dyn> for DefaultAllocator where RTo: DimName, { #[inline] unsafe fn reallocate_copy( rto: RTo, - cto: Dynamic, + cto: Dyn, buf: ArrayStorage, - ) -> VecStorage, RTo, Dynamic> { - let mut res = >::allocate_uninit(rto, cto); + ) -> VecStorage, RTo, Dyn> { + let mut res = >::allocate_uninit(rto, cto); let (rfrom, cfrom) = buf.shape(); @@ -279,60 +277,58 @@ where // All conversion from a dynamic buffer to a dynamic buffer. #[cfg(any(feature = "std", feature = "alloc"))] -impl Reallocator - for DefaultAllocator -{ +impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( - rto: Dynamic, + rto: Dyn, cto: CTo, - buf: VecStorage, - ) -> VecStorage, Dynamic, CTo> { + buf: VecStorage, + ) -> VecStorage, Dyn, CTo> { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } } #[cfg(any(feature = "std", feature = "alloc"))] -impl Reallocator +impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( rto: RTo, - cto: Dynamic, - buf: VecStorage, - ) -> VecStorage, RTo, Dynamic> { + cto: Dyn, + buf: VecStorage, + ) -> VecStorage, RTo, Dyn> { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } } #[cfg(any(feature = "std", feature = "alloc"))] -impl Reallocator +impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( - rto: Dynamic, + rto: Dyn, cto: CTo, - buf: VecStorage, - ) -> VecStorage, Dynamic, CTo> { + buf: VecStorage, + ) -> VecStorage, Dyn, CTo> { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } } #[cfg(any(feature = "std", feature = "alloc"))] -impl Reallocator +impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( rto: RTo, - cto: Dynamic, - buf: VecStorage, - ) -> VecStorage, RTo, Dynamic> { + cto: Dyn, + buf: VecStorage, + ) -> VecStorage, RTo, Dyn> { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } diff --git a/src/base/dimension.rs b/src/base/dimension.rs index de51339f..17b9d9d3 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -8,54 +8,69 @@ use std::fmt::Debug; use std::ops::{Add, Div, Mul, Sub}; use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Dim of dynamically-sized algebraic entities. #[derive(Clone, Copy, Eq, PartialEq, Debug)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -pub struct Dynamic { - value: usize, -} +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) +)] +#[cfg_attr( + feature = "rkyv-serialize", + archive_attr(derive(bytecheck::CheckBytes)) +)] +pub struct Dyn(pub usize); -impl Dynamic { +#[deprecated(note = "use Dyn instead.")] +pub type Dynamic = Dyn; + +impl Dyn { /// A dynamic size equal to `value`. #[inline] + #[deprecated(note = "use Dyn(value) instead.")] pub const fn new(value: usize) -> Self { - Self { value } + Self(value) } } #[cfg(feature = "serde-serialize-no-std")] -impl Serialize for Dynamic { +impl Serialize for Dyn { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - self.value.serialize(serializer) + self.0.serialize(serializer) } } #[cfg(feature = "serde-serialize-no-std")] -impl<'de> Deserialize<'de> for Dynamic { +impl<'de> Deserialize<'de> for Dyn { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - usize::deserialize(deserializer).map(|x| Dynamic { value: x }) + usize::deserialize(deserializer).map(|x| Dyn(x)) } } -/// Trait implemented by `Dynamic`. +/// Trait implemented by `Dyn`. pub trait IsDynamic {} -/// Trait implemented by `Dynamic` and type-level integers different from `U1`. +/// Trait implemented by `Dyn` and type-level integers different from `U1`. pub trait IsNotStaticOne {} -impl IsDynamic for Dynamic {} -impl IsNotStaticOne for Dynamic {} +impl IsDynamic for Dyn {} +impl IsNotStaticOne for Dyn {} /// Trait implemented by any type that can be used as a dimension. This includes type-level -/// integers and `Dynamic` (for dimensions not known at compile-time). +/// integers and `Dyn` (for dimensions not known at compile-time). +/// +/// # Safety +/// +/// Hoists integers to the type level, including binary operations. pub unsafe trait Dim: Any + Debug + Copy + PartialEq + Send + Sync { #[inline(always)] fn is() -> bool { @@ -63,7 +78,7 @@ pub unsafe trait Dim: Any + Debug + Copy + PartialEq + Send + Sync { } /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self = - /// Dynamic`. + /// Dyn`. fn try_to_usize() -> Option; /// Gets the run-time value of `self`. For type-level integers, this is the same as @@ -75,7 +90,7 @@ pub unsafe trait Dim: Any + Debug + Copy + PartialEq + Send + Sync { fn from_usize(dim: usize) -> Self; } -unsafe impl Dim for Dynamic { +unsafe impl Dim for Dyn { #[inline] fn try_to_usize() -> Option { None @@ -83,30 +98,30 @@ unsafe impl Dim for Dynamic { #[inline] fn from_usize(dim: usize) -> Self { - Self::new(dim) + Self(dim) } #[inline] fn value(&self) -> usize { - self.value + self.0 } } -impl Add for Dynamic { - type Output = Dynamic; +impl Add for Dyn { + type Output = Dyn; #[inline] fn add(self, rhs: usize) -> Self { - Self::new(self.value + rhs) + Self(self.0 + rhs) } } -impl Sub for Dynamic { - type Output = Dynamic; +impl Sub for Dyn { + type Output = Dyn; #[inline] fn sub(self, rhs: usize) -> Self { - Self::new(self.value - rhs) + Self(self.0 - rhs) } } @@ -144,22 +159,22 @@ macro_rules! dim_ops( } } - impl $DimOp for Dynamic { - type Output = Dynamic; + impl $DimOp for Dyn { + type Output = Dyn; #[inline] - fn $op(self, other: D) -> Dynamic { - Dynamic::new($op_path(self.value, other.value())) + fn $op(self, other: D) -> Dyn { + Dyn($op_path(self.value(), other.value())) } } // TODO: use Const instead of D: DimName? - impl $DimOp for D { - type Output = Dynamic; + impl $DimOp for D { + type Output = Dyn; #[inline] - fn $op(self, other: Dynamic) -> Dynamic { - Dynamic::new($op_path(self.value(), other.value)) + fn $op(self, other: Dyn) -> Dyn { + Dyn($op_path(self.value(), other.value())) } } @@ -198,7 +213,12 @@ dim_ops!( ); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive(as = "Self") +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] pub struct Const; /// Trait implemented exclusively by type-level integers. @@ -233,37 +253,6 @@ impl<'de, const D: usize> Deserialize<'de> for Const { } } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Const; - use rkyv::{Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Const { - type Archived = Self; - type Resolver = (); - - fn resolve( - &self, - _: usize, - _: Self::Resolver, - _: &mut core::mem::MaybeUninit, - ) { - } - } - - impl Serialize for Const { - fn serialize(&self, _: &mut S) -> Result { - Ok(()) - } - } - - impl Deserialize for Const { - fn deserialize(&self, _: &mut D) -> Result { - Ok(Const) - } - } -} - pub trait ToConst { type Const: DimName; } @@ -273,14 +262,17 @@ pub trait ToTypenum { } unsafe impl Dim for Const { + #[inline] fn try_to_usize() -> Option { Some(T) } + #[inline] fn value(&self) -> usize { T } + #[inline] fn from_usize(dim: usize) -> Self { assert_eq!(dim, T); Self @@ -324,6 +316,11 @@ macro_rules! from_to_typenum ( } impl IsNotStaticOne for $D { } + + /// The constant dimension + #[doc = stringify!($VAL)] + /// . + pub const $D: $D = Const::<$VAL>; )*} ); @@ -337,3 +334,7 @@ from_to_typenum!( U111, 111; U112, 112; U113, 113; U114, 114; U115, 115; U116, 116; U117, 117; U118, 118; U119, 119; U120, 120; U121, 121; U122, 122; U123, 123; U124, 124; U125, 125; U126, 126; U127, 127 ); + +/// The constant dimension 1. +// Note: We add U1 separately since it's not covered by the from_to_typenum! macro. +pub const U1: U1 = Const::<1>; diff --git a/src/base/edition.rs b/src/base/edition.rs index 760b3950..b5c31819 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -7,7 +7,7 @@ use std::ptr; use crate::base::allocator::{Allocator, Reallocator}; use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; #[cfg(any(feature = "std", feature = "alloc"))] -use crate::base::dimension::Dynamic; +use crate::base::dimension::Dyn; use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1}; use crate::base::storage::{RawStorage, RawStorageMut, ReshapableStorage}; use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector}; @@ -48,15 +48,15 @@ impl> Matrix { /// Creates a new matrix by extracting the given set of rows from `self`. #[cfg(any(feature = "std", feature = "alloc"))] #[must_use] - pub fn select_rows<'a, I>(&self, irows: I) -> OMatrix + pub fn select_rows<'a, I>(&self, irows: I) -> OMatrix where I: IntoIterator, I::IntoIter: ExactSizeIterator + Clone, - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { let irows = irows.into_iter(); let ncols = self.shape_generic().1; - let mut res = Matrix::uninit(Dynamic::new(irows.len()), ncols); + let mut res = Matrix::uninit(Dyn(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. @@ -85,15 +85,15 @@ impl> Matrix { /// Creates a new matrix by extracting the given set of columns from `self`. #[cfg(any(feature = "std", feature = "alloc"))] #[must_use] - pub fn select_columns<'a, I>(&self, icols: I) -> OMatrix + pub fn select_columns<'a, I>(&self, icols: I) -> OMatrix where I: IntoIterator, I::IntoIter: ExactSizeIterator, - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { let icols = icols.into_iter(); let nrows = self.shape_generic().0; - let mut res = Matrix::uninit(nrows, Dynamic::new(icols.len())); + let mut res = Matrix::uninit(nrows, Dyn(icols.len())); for (destination, source) in icols.enumerate() { // NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit. @@ -359,10 +359,10 @@ impl> Matrix { /// Removes all columns in `indices` #[cfg(any(feature = "std", feature = "alloc"))] - pub fn remove_columns_at(self, indices: &[usize]) -> OMatrix + pub fn remove_columns_at(self, indices: &[usize]) -> OMatrix where - C: DimSub, - DefaultAllocator: Reallocator, + C: DimSub, + DefaultAllocator: Reallocator, { let mut m = self.into_owned(); let (nrows, ncols) = m.shape_generic(); @@ -400,7 +400,7 @@ impl> Matrix { unsafe { let new_data = DefaultAllocator::reallocate_copy( nrows, - ncols.sub(Dynamic::from_usize(offset)), + ncols.sub(Dyn::from_usize(offset)), m.data, ); @@ -410,10 +410,10 @@ impl> Matrix { /// Removes all rows in `indices` #[cfg(any(feature = "std", feature = "alloc"))] - pub fn remove_rows_at(self, indices: &[usize]) -> OMatrix + pub fn remove_rows_at(self, indices: &[usize]) -> OMatrix where - R: DimSub, - DefaultAllocator: Reallocator, + R: DimSub, + DefaultAllocator: Reallocator, { let mut m = self.into_owned(); let (nrows, ncols) = m.shape_generic(); @@ -448,7 +448,7 @@ impl> Matrix { // be assumed to be initialized. unsafe { let new_data = DefaultAllocator::reallocate_copy( - nrows.sub(Dynamic::from_usize(offset / ncols.value())), + nrows.sub(Dyn::from_usize(offset / ncols.value())), ncols, m.data, ); @@ -474,12 +474,12 @@ impl> Matrix { /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included). #[inline] #[cfg(any(feature = "std", feature = "alloc"))] - pub fn remove_columns(self, i: usize, n: usize) -> OMatrix + pub fn remove_columns(self, i: usize, n: usize) -> OMatrix where - C: DimSub, - DefaultAllocator: Reallocator, + C: DimSub, + DefaultAllocator: Reallocator, { - self.remove_columns_generic(i, Dynamic::new(n)) + self.remove_columns_generic(i, Dyn(n)) } /// Removes `nremove.value()` columns from this matrix, starting with the `i`-th (included). @@ -569,12 +569,12 @@ impl> Matrix { /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included). #[inline] #[cfg(any(feature = "std", feature = "alloc"))] - pub fn remove_rows(self, i: usize, n: usize) -> OMatrix + pub fn remove_rows(self, i: usize, n: usize) -> OMatrix where - R: DimSub, - DefaultAllocator: Reallocator, + R: DimSub, + DefaultAllocator: Reallocator, { - self.remove_rows_generic(i, Dynamic::new(n)) + self.remove_rows_generic(i, Dyn(n)) } /// Removes `nremove.value()` rows from this matrix, starting with the `i`-th (included). @@ -598,7 +598,7 @@ impl> Matrix { if nremove.value() != 0 { unsafe { compress_rows( - &mut m.as_mut_slice(), + m.as_mut_slice(), nrows.value(), ncols.value(), i, @@ -659,12 +659,12 @@ impl> Matrix { /// Inserts `n` columns filled with `val` starting at the `i-th` position. #[inline] #[cfg(any(feature = "std", feature = "alloc"))] - pub fn insert_columns(self, i: usize, n: usize, val: T) -> OMatrix + pub fn insert_columns(self, i: usize, n: usize, val: T) -> OMatrix where - C: DimAdd, - DefaultAllocator: Reallocator, + C: DimAdd, + DefaultAllocator: Reallocator, { - let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dynamic::new(n)) }; + let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dyn(n)) }; res.columns_mut(i, n) .fill_with(|| MaybeUninit::new(val.clone())); @@ -752,12 +752,12 @@ impl> Matrix { /// Inserts `n` rows filled with `val` starting at the `i-th` position. #[inline] #[cfg(any(feature = "std", feature = "alloc"))] - pub fn insert_rows(self, i: usize, n: usize, val: T) -> OMatrix + pub fn insert_rows(self, i: usize, n: usize, val: T) -> OMatrix where - R: DimAdd, - DefaultAllocator: Reallocator, + R: DimAdd, + DefaultAllocator: Reallocator, { - let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dynamic::new(n)) }; + let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dyn(n)) }; res.rows_mut(i, n) .fill_with(|| MaybeUninit::new(val.clone())); @@ -796,7 +796,7 @@ impl> Matrix { if ninsert.value() != 0 { extend_rows( - &mut res.as_mut_slice(), + res.as_mut_slice(), nrows.value(), ncols.value(), i, @@ -815,11 +815,11 @@ impl> Matrix { /// 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`. #[cfg(any(feature = "std", feature = "alloc"))] - pub fn resize(self, new_nrows: usize, new_ncols: usize, val: T) -> OMatrix + pub fn resize(self, new_nrows: usize, new_ncols: usize, val: T) -> OMatrix where - DefaultAllocator: Reallocator, + DefaultAllocator: Reallocator, { - self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) + self.resize_generic(Dyn(new_nrows), Dyn(new_ncols), val) } /// Resizes this matrix vertically, i.e., so that it contains `new_nrows` rows while keeping the same number of columns. @@ -827,12 +827,12 @@ impl> Matrix { /// 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: T) -> OMatrix + pub fn resize_vertically(self, new_nrows: usize, val: T) -> OMatrix where - DefaultAllocator: Reallocator, + DefaultAllocator: Reallocator, { let ncols = self.shape_generic().1; - self.resize_generic(Dynamic::new(new_nrows), ncols, val) + self.resize_generic(Dyn(new_nrows), ncols, val) } /// Resizes this matrix horizontally, i.e., so that it contains `new_ncolumns` columns while keeping the same number of columns. @@ -840,12 +840,12 @@ impl> Matrix { /// 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: T) -> OMatrix + pub fn resize_horizontally(self, new_ncols: usize, val: T) -> OMatrix where - DefaultAllocator: Reallocator, + DefaultAllocator: Reallocator, { let nrows = self.shape_generic().0; - self.resize_generic(nrows, Dynamic::new(new_ncols), val) + self.resize_generic(nrows, Dyn(new_ncols), val) } /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. @@ -909,7 +909,7 @@ impl> Matrix { unsafe { if new_nrows.value() < nrows { compress_rows( - &mut data.as_mut_slice(), + data.as_mut_slice(), nrows, ncols, new_nrows.value(), @@ -923,7 +923,7 @@ impl> Matrix { new_nrows, new_ncols, data.data, )); extend_rows( - &mut res.as_mut_slice(), + res.as_mut_slice(), nrows, new_ncols.value(), nrows, @@ -938,7 +938,7 @@ impl> Matrix { } if new_nrows.value() > nrows { - res.slice_range_mut(nrows.., ..cmp::min(ncols, new_ncols.value())) + res.view_range_mut(nrows.., ..cmp::min(ncols, new_ncols.value())) .fill_with(|| MaybeUninit::new(val.clone())); } @@ -962,7 +962,7 @@ impl> Matrix { /// # Examples /// /// ``` - /// # use nalgebra::{Matrix3x2, Matrix2x3, DMatrix, Const, Dynamic}; + /// # use nalgebra::{Matrix3x2, Matrix2x3, DMatrix, Const, Dyn}; /// /// let m1 = Matrix2x3::new( /// 1.1, 1.2, 1.3, @@ -998,7 +998,7 @@ impl> Matrix { /// 0.0, 0.0, /// ], /// ); - /// let reshaped = dm1.reshape_generic(Dynamic::new(6), Dynamic::new(2)); + /// let reshaped = dm1.reshape_generic(Dyn(6), Dyn(2)); /// assert_eq!(reshaped, dm2); /// ``` pub fn reshape_generic( @@ -1018,7 +1018,7 @@ impl> Matrix { /// # In-place resizing #[cfg(any(feature = "std", feature = "alloc"))] -impl OMatrix { +impl OMatrix { /// Resizes this matrix in-place. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more @@ -1027,7 +1027,7 @@ impl OMatrix { /// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`. pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: T) where - DefaultAllocator: Reallocator, + DefaultAllocator: Reallocator, { // TODO: avoid the clone. *self = self.clone().resize(new_nrows, new_ncols, val); @@ -1035,9 +1035,9 @@ impl OMatrix { } #[cfg(any(feature = "std", feature = "alloc"))] -impl OMatrix +impl OMatrix where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { /// Changes the number of rows of this matrix in-place. /// @@ -1048,7 +1048,7 @@ where #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: T) where - DefaultAllocator: Reallocator, + DefaultAllocator: Reallocator, { // TODO: avoid the clone. *self = self.clone().resize_vertically(new_nrows, val); @@ -1056,9 +1056,9 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -impl OMatrix +impl OMatrix where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { /// Changes the number of column of this matrix in-place. /// @@ -1069,7 +1069,7 @@ where #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: T) where - DefaultAllocator: Reallocator, + DefaultAllocator: Reallocator, { // TODO: avoid the clone. *self = self.clone().resize_horizontally(new_ncols, val); @@ -1077,7 +1077,7 @@ where } // Move the elements of `data` in such a way that the matrix with -// the rows `[i, i + nremove[` deleted is represented in a contigous +// the rows `[i, i + nremove[` deleted is represented in a contiguous // way in `data` after this method completes. // Every deleted element are manually dropped by this method. unsafe fn compress_rows( @@ -1167,7 +1167,7 @@ unsafe fn extend_rows(data: &mut [T], nrows: usize, ncols: usize, i: usize, n /// Extend the number of columns of the `Matrix` with elements from /// a given iterator. #[cfg(any(feature = "std", feature = "alloc"))] -impl Extend for Matrix +impl Extend for Matrix where T: Scalar, R: Dim, @@ -1178,7 +1178,7 @@ where /// /// # Example /// ``` - /// # use nalgebra::{DMatrix, Dynamic, Matrix, OMatrix, Matrix3}; + /// # use nalgebra::{DMatrix, Dyn, Matrix, OMatrix, Matrix3}; /// /// let data = vec![0, 1, 2, // column 1 /// 3, 4, 5]; // column 2 @@ -1198,7 +1198,7 @@ where /// `Matrix`. /// /// ```should_panic - /// # use nalgebra::{DMatrix, Dynamic, OMatrix}; + /// # use nalgebra::{DMatrix, Dyn, OMatrix}; /// let data = vec![0, 1, 2, // column 1 /// 3, 4, 5]; // column 2 /// @@ -1215,7 +1215,7 @@ where /// Extend the number of rows of the `Vector` with elements from /// a given iterator. #[cfg(any(feature = "std", feature = "alloc"))] -impl Extend for Matrix +impl Extend for Matrix where T: Scalar, S: Extend, @@ -1236,7 +1236,7 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -impl Extend> for Matrix +impl Extend> for Matrix where T: Scalar, R: Dim, diff --git a/src/base/indexing.rs b/src/base/indexing.rs index 2c691bd1..5a860fe0 100644 --- a/src/base/indexing.rs +++ b/src/base/indexing.rs @@ -3,7 +3,7 @@ use crate::base::storage::{RawStorage, RawStorageMut}; use crate::base::{ - Const, Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1, + Const, Dim, DimDiff, DimName, DimSub, Dyn, Matrix, MatrixView, MatrixViewMut, Scalar, U1, }; use std::ops; @@ -49,7 +49,7 @@ fn dimrange_usize() { } impl DimRange for ops::Range { - type Length = Dynamic; + type Length = Dyn; #[inline(always)] fn lower(&self, _: D) -> usize { @@ -58,7 +58,7 @@ impl DimRange for ops::Range { #[inline(always)] fn length(&self, _: D) -> Self::Length { - Dynamic::new(self.end.saturating_sub(self.start)) + Dyn(self.end.saturating_sub(self.start)) } #[inline(always)] @@ -74,24 +74,24 @@ fn dimrange_range_usize() { assert!(DimRange::contained_by(&(0..1), Const::<1>)); assert!(DimRange::contained_by( &((usize::MAX - 1)..usize::MAX), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); assert_eq!( - DimRange::length(&((usize::MAX - 1)..usize::MAX), Dynamic::new(usize::MAX)), - Dynamic::new(1) + DimRange::length(&((usize::MAX - 1)..usize::MAX), Dyn(usize::MAX)), + Dyn(1) ); assert_eq!( - DimRange::length(&(usize::MAX..(usize::MAX - 1)), Dynamic::new(usize::MAX)), - Dynamic::new(0) + DimRange::length(&(usize::MAX..(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(0) ); assert_eq!( - DimRange::length(&(usize::MAX..usize::MAX), Dynamic::new(usize::MAX)), - Dynamic::new(0) + DimRange::length(&(usize::MAX..usize::MAX), Dyn(usize::MAX)), + Dyn(0) ); } impl DimRange for ops::RangeFrom { - type Length = Dynamic; + type Length = Dyn; #[inline(always)] fn lower(&self, _: D) -> usize { @@ -116,16 +116,13 @@ fn dimrange_rangefrom_usize() { assert!(DimRange::contained_by(&(0..), Const::<1>)); assert!(DimRange::contained_by( &((usize::MAX - 1)..), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); assert_eq!( - DimRange::length(&((usize::MAX - 1)..), Dynamic::new(usize::MAX)), - Dynamic::new(1) - ); - assert_eq!( - DimRange::length(&(usize::MAX..), Dynamic::new(usize::MAX)), - Dynamic::new(0) + DimRange::length(&((usize::MAX - 1)..), Dyn(usize::MAX)), + Dyn(1) ); + assert_eq!(DimRange::length(&(usize::MAX..), Dyn(usize::MAX)), Dyn(0)); } impl DimRange for ops::RangeFrom @@ -181,7 +178,7 @@ fn dimrange_rangefull() { } impl DimRange for ops::RangeInclusive { - type Length = Dynamic; + type Length = Dyn; #[inline(always)] fn lower(&self, _: D) -> usize { @@ -190,7 +187,7 @@ impl DimRange for ops::RangeInclusive { #[inline(always)] fn length(&self, _: D) -> Self::Length { - Dynamic::new(if self.end() < self.start() { + Dyn(if self.end() < self.start() { 0 } else { self.end().wrapping_sub(self.start().wrapping_sub(1)) @@ -209,33 +206,33 @@ fn dimrange_rangeinclusive_usize() { assert!(DimRange::contained_by(&(0..=0), Const::<1>)); assert!(!DimRange::contained_by( &(usize::MAX..=usize::MAX), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); assert!(!DimRange::contained_by( &((usize::MAX - 1)..=usize::MAX), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); assert!(DimRange::contained_by( &((usize::MAX - 1)..=(usize::MAX - 1)), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); - assert_eq!(DimRange::length(&(0..=0), Const::<1>), Dynamic::new(1)); + assert_eq!(DimRange::length(&(0..=0), Const::<1>), Dyn(1)); assert_eq!( - DimRange::length(&((usize::MAX - 1)..=usize::MAX), Dynamic::new(usize::MAX)), - Dynamic::new(2) + DimRange::length(&((usize::MAX - 1)..=usize::MAX), Dyn(usize::MAX)), + Dyn(2) ); assert_eq!( - DimRange::length(&(usize::MAX..=(usize::MAX - 1)), Dynamic::new(usize::MAX)), - Dynamic::new(0) + DimRange::length(&(usize::MAX..=(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(0) ); assert_eq!( - DimRange::length(&(usize::MAX..=usize::MAX), Dynamic::new(usize::MAX)), - Dynamic::new(1) + DimRange::length(&(usize::MAX..=usize::MAX), Dyn(usize::MAX)), + Dyn(1) ); } impl DimRange for ops::RangeTo { - type Length = Dynamic; + type Length = Dyn; #[inline(always)] fn lower(&self, _: D) -> usize { @@ -244,7 +241,7 @@ impl DimRange for ops::RangeTo { #[inline(always)] fn length(&self, _: D) -> Self::Length { - Dynamic::new(self.end) + Dyn(self.end) } #[inline(always)] @@ -260,20 +257,20 @@ fn dimrange_rangeto_usize() { assert!(DimRange::contained_by(&(..0), Const::<1>)); assert!(DimRange::contained_by( &(..(usize::MAX - 1)), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); assert_eq!( - DimRange::length(&(..(usize::MAX - 1)), Dynamic::new(usize::MAX)), - Dynamic::new(usize::MAX - 1) + DimRange::length(&(..(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(usize::MAX - 1) ); assert_eq!( - DimRange::length(&(..usize::MAX), Dynamic::new(usize::MAX)), - Dynamic::new(usize::MAX) + DimRange::length(&(..usize::MAX), Dyn(usize::MAX)), + Dyn(usize::MAX) ); } impl DimRange for ops::RangeToInclusive { - type Length = Dynamic; + type Length = Dyn; #[inline(always)] fn lower(&self, _: D) -> usize { @@ -282,7 +279,7 @@ impl DimRange for ops::RangeToInclusive { #[inline(always)] fn length(&self, _: D) -> Self::Length { - Dynamic::new(self.end + 1) + Dyn(self.end + 1) } #[inline(always)] @@ -296,17 +293,14 @@ fn dimrange_rangetoinclusive_usize() { assert!(!DimRange::contained_by(&(..=0), Const::<0>)); assert!(!DimRange::contained_by(&(..=1), Const::<0>)); assert!(DimRange::contained_by(&(..=0), Const::<1>)); - assert!(!DimRange::contained_by( - &(..=(usize::MAX)), - Dynamic::new(usize::MAX) - )); + assert!(!DimRange::contained_by(&(..=(usize::MAX)), Dyn(usize::MAX))); assert!(DimRange::contained_by( &(..=(usize::MAX - 1)), - Dynamic::new(usize::MAX) + Dyn(usize::MAX) )); assert_eq!( - DimRange::length(&(..=(usize::MAX - 1)), Dynamic::new(usize::MAX)), - Dynamic::new(usize::MAX) + DimRange::length(&(..=(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(usize::MAX) ); } @@ -378,7 +372,7 @@ pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>: } } -/// # Slicing based on ranges +/// # Views based on ranges /// ## Indices to Individual Elements /// ### Two-Dimensional Indices /// ``` @@ -525,6 +519,10 @@ impl> Matrix { /// Produces a view of the data at the given index, without doing /// any bounds checking. + /// + /// # Safety + /// + /// `index` must within bounds of the array. #[inline] #[must_use] pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::Output @@ -536,6 +534,9 @@ impl> Matrix { /// Returns a mutable view of the data at the given index, without doing /// any bounds checking. + /// # Safety + /// + /// `index` must within bounds of the array. #[inline] #[must_use] pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut @@ -669,7 +670,7 @@ macro_rules! impl_index_pair { $( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)* $( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),* { - type Output = MatrixSlice<'a, T, $ROut, $COut, S::RStride, S::CStride>; + type Output = MatrixView<'a, T, $ROut, $COut, S::RStride, S::CStride>; #[doc(hidden)] #[inline(always)] @@ -682,13 +683,13 @@ macro_rules! impl_index_pair { #[doc(hidden)] #[inline(always)] unsafe fn get_unchecked(self, matrix: &'a Matrix) -> Self::Output { - use crate::base::SliceStorage; + use crate::base::ViewStorage; let (rows, cols) = self; let (nrows, ncols) = matrix.shape_generic(); let data = - SliceStorage::new_unchecked(&matrix.data, + ViewStorage::new_unchecked(&matrix.data, (rows.lower(nrows), cols.lower(ncols)), (rows.length(nrows), cols.length(ncols))); @@ -705,18 +706,18 @@ macro_rules! impl_index_pair { $( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)* $( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),* { - type OutputMut = MatrixSliceMut<'a, T, $ROut, $COut, S::RStride, S::CStride>; + type OutputMut = MatrixViewMut<'a, T, $ROut, $COut, S::RStride, S::CStride>; #[doc(hidden)] #[inline(always)] unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut { - use crate::base::SliceStorageMut; + use crate::base::ViewStorageMut; let (rows, cols) = self; let (nrows, ncols) = matrix.shape_generic(); let data = - SliceStorageMut::new_unchecked(&mut matrix.data, + ViewStorageMut::new_unchecked(&mut matrix.data, (rows.lower(nrows), cols.lower(ncols)), (rows.length(nrows), cols.length(ncols))); @@ -742,12 +743,12 @@ macro_rules! impl_index_pairs { impl_index_pairs! { index R with { [<> usize => U1], - [<> ops::Range => Dynamic], - [<> ops::RangeFrom => Dynamic], + [<> ops::Range => Dyn], + [<> ops::RangeFrom => Dyn], [<> ops::RangeFull => R], - [<> ops::RangeInclusive => Dynamic], - [<> ops::RangeTo => Dynamic], - [<> ops::RangeToInclusive => Dynamic], + [<> ops::RangeInclusive => Dyn], + [<> ops::RangeTo => Dyn], + [<> ops::RangeToInclusive => Dyn], [ ops::RangeFrom => DimDiff @@ -755,12 +756,12 @@ impl_index_pairs! { } index C with { [<> usize => U1], - [<> ops::Range => Dynamic], - [<> ops::RangeFrom => Dynamic], + [<> ops::Range => Dyn], + [<> ops::RangeFrom => Dyn], [<> ops::RangeFull => C], - [<> ops::RangeInclusive => Dynamic], - [<> ops::RangeTo => Dynamic], - [<> ops::RangeToInclusive => Dynamic], + [<> ops::RangeInclusive => Dyn], + [<> ops::RangeTo => Dyn], + [<> ops::RangeToInclusive => Dyn], [ ops::RangeFrom => DimDiff diff --git a/src/base/iter.rs b/src/base/iter.rs index b68e1051..5da43721 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -1,31 +1,40 @@ //! Matrix iterators. +// only enables the `doc_cfg` feature when +// the `docsrs` configuration attribute is defined +#![cfg_attr(docsrs, feature(doc_cfg))] + +use core::fmt::Debug; +use core::ops::Range; use std::iter::FusedIterator; use std::marker::PhantomData; use std::mem; use crate::base::dimension::{Dim, U1}; use crate::base::storage::{RawStorage, RawStorageMut}; -use crate::base::{Matrix, MatrixSlice, MatrixSliceMut, Scalar}; +use crate::base::{Matrix, MatrixView, MatrixViewMut, Scalar, ViewStorage, ViewStorageMut}; + +#[derive(Clone, Debug)] +struct RawIter { + ptr: Ptr, + inner_ptr: Ptr, + inner_end: Ptr, + size: usize, + strides: (RStride, CStride), + _phantoms: PhantomData<(fn() -> T, R, C)>, +} macro_rules! iterator { - (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { - /// An iterator through a dense matrix with arbitrary strides matrix. - #[derive(Debug)] - pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage> { - ptr: $Ptr, - inner_ptr: $Ptr, - inner_end: $Ptr, - size: usize, // We can't use an end pointer here because a stride might be zero. - strides: (S::RStride, S::CStride), - _phantoms: PhantomData<($Ref, R, C, S)>, - } - + (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty, $($derives:ident),* $(,)?) => { // TODO: we need to specialize for the case where the matrix storage is owned (in which // case the iterator is trivial because it does not have any stride). - impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> $Name<'a, T, R, C, S> { + impl + RawIter<$Ptr, T, R, C, RStride, CStride> + { /// Creates a new iterator for the given matrix storage. - pub fn new(storage: $SRef) -> $Name<'a, T, R, C, S> { + fn new<'a, S: $Storage>( + storage: $SRef, + ) -> Self { let shape = storage.shape(); let strides = storage.strides(); let inner_offset = shape.0.value() * strides.0.value(); @@ -33,7 +42,7 @@ macro_rules! iterator { let ptr = storage.$ptr(); // If we have a size of 0, 'ptr' must be - // dangling. Howver, 'inner_offset' might + // dangling. However, 'inner_offset' might // not be zero if only one dimension is zero, so // we don't want to call 'offset'. // This pointer will never actually get used @@ -49,7 +58,7 @@ macro_rules! iterator { unsafe { ptr.add(inner_offset) } }; - $Name { + RawIter { ptr, inner_ptr: ptr, inner_end, @@ -60,11 +69,13 @@ macro_rules! iterator { } } - impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> Iterator for $Name<'a, T, R, C, S> { - type Item = $Ref; + impl Iterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + type Item = $Ptr; #[inline] - fn next(&mut self) -> Option<$Ref> { + fn next(&mut self) -> Option { unsafe { if self.size == 0 { None @@ -96,10 +107,7 @@ macro_rules! iterator { self.ptr = self.ptr.add(stride); } - // We want either `& *last` or `&mut *last` here, depending - // on the mutability of `$Ref`. - #[allow(clippy::transmute_ptr_to_ref)] - Some(mem::transmute(old)) + Some(old) } } } @@ -115,11 +123,11 @@ macro_rules! iterator { } } - impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> DoubleEndedIterator - for $Name<'a, T, R, C, S> + impl DoubleEndedIterator + for RawIter<$Ptr, T, R, C, RStride, CStride> { #[inline] - fn next_back(&mut self) -> Option<$Ref> { + fn next_back(&mut self) -> Option { unsafe { if self.size == 0 { None @@ -146,21 +154,85 @@ macro_rules! iterator { .ptr .add((outer_remaining * outer_stride + inner_remaining * inner_stride)); - // We want either `& *last` or `&mut *last` here, depending - // on the mutability of `$Ref`. - #[allow(clippy::transmute_ptr_to_ref)] - Some(mem::transmute(last)) + Some(last) } } } } + impl ExactSizeIterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + #[inline] + fn len(&self) -> usize { + self.size + } + } + + impl FusedIterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + } + + /// An iterator through a dense matrix with arbitrary strides matrix. + #[derive($($derives),*)] + pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage> { + inner: RawIter<$Ptr, T, R, C, S::RStride, S::CStride>, + _marker: PhantomData<$Ref>, + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> $Name<'a, T, R, C, S> { + /// Creates a new iterator for the given matrix storage. + pub fn new(storage: $SRef) -> Self { + Self { + inner: RawIter::<$Ptr, T, R, C, S::RStride, S::CStride>::new(storage), + _marker: PhantomData, + } + } + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> Iterator for $Name<'a, T, R, C, S> { + type Item = $Ref; + + #[inline(always)] + fn next(&mut self) -> Option { + // We want either `& *last` or `&mut *last` here, depending + // on the mutability of `$Ref`. + #[allow(clippy::transmute_ptr_to_ref)] + self.inner.next().map(|ptr| unsafe { mem::transmute(ptr) }) + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + #[inline(always)] + fn count(self) -> usize { + self.inner.count() + } + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> DoubleEndedIterator + for $Name<'a, T, R, C, S> + { + #[inline(always)] + fn next_back(&mut self) -> Option { + // We want either `& *last` or `&mut *last` here, depending + // on the mutability of `$Ref`. + #[allow(clippy::transmute_ptr_to_ref)] + self.inner + .next_back() + .map(|ptr| unsafe { mem::transmute(ptr) }) + } + } + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> ExactSizeIterator for $Name<'a, T, R, C, S> { - #[inline] + #[inline(always)] fn len(&self) -> usize { - self.size + self.inner.len() } } @@ -171,8 +243,32 @@ macro_rules! iterator { }; } -iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S); -iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S); +iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S, Clone, Debug); +iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S, Debug); + +impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + MatrixIter<'a, T, R, C, ViewStorage<'a, T, R, C, RStride, CStride>> +{ + /// Creates a new iterator for the given matrix storage view. + pub fn new_owned(storage: ViewStorage<'a, T, R, C, RStride, CStride>) -> Self { + Self { + inner: RawIter::<*const T, T, R, C, RStride, CStride>::new(&storage), + _marker: PhantomData, + } + } +} + +impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + MatrixIterMut<'a, T, R, C, ViewStorageMut<'a, T, R, C, RStride, CStride>> +{ + /// Creates a new iterator for the given matrix storage view. + pub fn new_owned_mut(mut storage: ViewStorageMut<'a, T, R, C, RStride, CStride>) -> Self { + Self { + inner: RawIter::<*mut T, T, R, C, RStride, CStride>::new(&mut storage), + _marker: PhantomData, + } + } +} /* * @@ -193,7 +289,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> RowIter<'a, T, R, C, S> } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for RowIter<'a, T, R, C, S> { - type Item = MatrixSlice<'a, T, U1, C, S::RStride, S::CStride>; + type Item = MatrixView<'a, T, U1, C, S::RStride, S::CStride>; #[inline] fn next(&mut self) -> Option { @@ -254,7 +350,7 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> RowIterMut<'a, T, R, impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator for RowIterMut<'a, T, R, C, S> { - type Item = MatrixSliceMut<'a, T, U1, C, S::RStride, S::CStride>; + type Item = MatrixViewMut<'a, T, U1, C, S::RStride, S::CStride>; #[inline] fn next(&mut self) -> Option { @@ -288,7 +384,6 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte } /* - * * Column iterators. * */ @@ -296,23 +391,46 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte /// An iterator through the columns of a matrix. pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage> { mat: &'a Matrix, - curr: usize, + range: Range, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, S> { + /// a new column iterator covering all columns of the matrix pub(crate) fn new(mat: &'a Matrix) -> Self { - ColumnIter { mat, curr: 0 } + ColumnIter { + mat, + range: 0..mat.ncols(), + } + } + + #[cfg(feature = "rayon")] + pub(crate) fn split_at(self, index: usize) -> (Self, Self) { + // SAFETY: this makes sure the generated ranges are valid. + let split_pos = (self.range.start + index).min(self.range.end); + + let left_iter = ColumnIter { + mat: self.mat, + range: self.range.start..split_pos, + }; + + let right_iter = ColumnIter { + mat: self.mat, + range: split_pos..self.range.end, + }; + + (left_iter, right_iter) } } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter<'a, T, R, C, S> { - type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>; + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; #[inline] fn next(&mut self) -> Option { - if self.curr < self.mat.ncols() { - let res = self.mat.column(self.curr); - self.curr += 1; + debug_assert!(self.range.start <= self.range.end); + if self.range.start < self.range.end { + let res = self.mat.column(self.range.start); + self.range.start += 1; Some(res) } else { None @@ -321,15 +439,29 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter #[inline] fn size_hint(&self) -> (usize, Option) { - ( - self.mat.ncols() - self.curr, - Some(self.mat.ncols() - self.curr), - ) + let hint = self.range.len(); + (hint, Some(hint)) } #[inline] fn count(self) -> usize { - self.mat.ncols() - self.curr + self.range.len() + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> DoubleEndedIterator + for ColumnIter<'a, T, R, C, S> +{ + fn next_back(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if !self.range.is_empty() { + self.range.end -= 1; + debug_assert!(self.range.end < self.mat.ncols()); + debug_assert!(self.range.end >= self.range.start); + Some(self.mat.column(self.range.end)) + } else { + None + } } } @@ -338,7 +470,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat { #[inline] fn len(&self) -> usize { - self.mat.ncols() - self.curr + self.range.end - self.range.start } } @@ -346,19 +478,40 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterat #[derive(Debug)] pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { mat: *mut Matrix, - curr: usize, + range: Range, phantom: PhantomData<&'a mut Matrix>, } impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { pub(crate) fn new(mat: &'a mut Matrix) -> Self { + let range = 0..mat.ncols(); ColumnIterMut { mat, - curr: 0, - phantom: PhantomData, + range, + phantom: Default::default(), } } + #[cfg(feature = "rayon")] + pub(crate) fn split_at(self, index: usize) -> (Self, Self) { + // SAFETY: this makes sure the generated ranges are valid. + let split_pos = (self.range.start + index).min(self.range.end); + + let left_iter = ColumnIterMut { + mat: self.mat, + range: self.range.start..split_pos, + phantom: Default::default(), + }; + + let right_iter = ColumnIterMut { + mat: self.mat, + range: split_pos..self.range.end, + phantom: Default::default(), + }; + + (left_iter, right_iter) + } + fn ncols(&self) -> usize { unsafe { (*self.mat).ncols() } } @@ -367,13 +520,14 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator for ColumnIterMut<'a, T, R, C, S> { - type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>; + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; #[inline] - fn next(&mut self) -> Option { - if self.curr < self.ncols() { - let res = unsafe { (*self.mat).column_mut(self.curr) }; - self.curr += 1; + fn next(&'_ mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if self.range.start < self.range.end { + let res = unsafe { (*self.mat).column_mut(self.range.start) }; + self.range.start += 1; Some(res) } else { None @@ -382,12 +536,13 @@ impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator #[inline] fn size_hint(&self) -> (usize, Option) { - (self.ncols() - self.curr, Some(self.ncols() - self.curr)) + let hint = self.range.len(); + (hint, Some(hint)) } #[inline] fn count(self) -> usize { - self.ncols() - self.curr + self.range.len() } } @@ -396,6 +551,22 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIte { #[inline] fn len(&self) -> usize { - self.ncols() - self.curr + self.range.len() + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedIterator + for ColumnIterMut<'a, T, R, C, S> +{ + fn next_back(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if !self.range.is_empty() { + self.range.end -= 1; + debug_assert!(self.range.end < self.ncols()); + debug_assert!(self.range.end >= self.range.start); + Some(unsafe { (*self.mat).column_mut(self.range.end) }) + } else { + None + } } } diff --git a/src/base/matrix.rs b/src/base/matrix.rs index f12cb3fa..7daa4f1a 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -11,6 +11,13 @@ use std::mem; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "rkyv-serialize-no-std")] +use super::rkyv_wrappers::CustomPhantom; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{with::With, Archive, Archived}; + use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, SupersetOf}; use simba::simd::SimdPartialOrd; @@ -27,7 +34,7 @@ use crate::{ArrayStorage, SMatrix, SimdComplexField, Storage, UninitMatrix}; use crate::storage::IsContiguous; use crate::uninit::{Init, InitStatus, Uninit}; #[cfg(any(feature = "std", feature = "alloc"))] -use crate::{DMatrix, DVector, Dynamic, RowDVector, VecStorage}; +use crate::{DMatrix, DVector, Dyn, RowDVector, VecStorage}; use std::mem::MaybeUninit; /// A square matrix. @@ -96,16 +103,17 @@ pub type MatrixCross = /// /// #### Iteration, map, and fold /// - [Iteration on components, rows, and columns `iter`, `column_iter`…](#iteration-on-components-rows-and-columns) +/// - [Parallel iterators using rayon `par_column_iter`, `par_column_iter_mut`…](#parallel-iterators-using-rayon) /// - [Elementwise mapping and folding `map`, `fold`, `zip_map`…](#elementwise-mapping-and-folding) /// - [Folding or columns and rows `compress_rows`, `compress_columns`…](#folding-on-columns-and-rows) /// -/// #### Vector and matrix slicing -/// - [Creating matrix slices from `&[T]` `from_slice`, `from_slice_with_strides`…](#creating-matrix-slices-from-t) -/// - [Creating mutable matrix slices from `&mut [T]` `from_slice_mut`, `from_slice_with_strides_mut`…](#creating-mutable-matrix-slices-from-mut-t) -/// - [Slicing based on index and length `row`, `columns`, `slice`…](#slicing-based-on-index-and-length) -/// - [Mutable slicing based on index and length `row_mut`, `columns_mut`, `slice_mut`…](#mutable-slicing-based-on-index-and-length) -/// - [Slicing based on ranges `rows_range`, `columns_range`…](#slicing-based-on-ranges) -/// - [Mutable slicing based on ranges `rows_range_mut`, `columns_range_mut`…](#mutable-slicing-based-on-ranges) +/// #### Vector and matrix views +/// - [Creating matrix views from `&[T]` `from_slice`, `from_slice_with_strides`…](#creating-matrix-views-from-t) +/// - [Creating mutable matrix views from `&mut [T]` `from_slice_mut`, `from_slice_with_strides_mut`…](#creating-mutable-matrix-views-from-mut-t) +/// - [Views based on index and length `row`, `columns`, `view`…](#views-based-on-index-and-length) +/// - [Mutable views based on index and length `row_mut`, `columns_mut`, `view_mut`…](#mutable-views-based-on-index-and-length) +/// - [Views based on ranges `rows_range`, `columns_range`…](#views-based-on-ranges) +/// - [Mutable views based on ranges `rows_range_mut`, `columns_range_mut`…](#mutable-views-based-on-ranges) /// /// #### In-place modification of a single matrix or vector /// - [In-place filling `fill`, `fill_diagonal`, `fill_with_identity`…](#in-place-filling) @@ -140,17 +148,29 @@ pub type MatrixCross = /// - type-level unsigned integer constants (e.g. `U1024`, `U10000`) from the `typenum::` crate. /// Using those, you will not get error messages as nice as for numbers smaller than 128 defined on /// the `nalgebra::` module. -/// - the special value `Dynamic` from the `nalgebra::` root module. This indicates that the +/// - the special value `Dyn` from the `nalgebra::` root module. This indicates that the /// specified dimension is not known at compile-time. Note that this will generally imply that the /// matrix data storage `S` performs a dynamic allocation and contains extra metadata for the /// matrix shape. /// -/// Note that mixing `Dynamic` with type-level unsigned integers is allowed. Actually, a -/// dynamically-sized column vector should be represented as a `Matrix` (given +/// Note that mixing `Dyn` with type-level unsigned integers is allowed. Actually, a +/// dynamically-sized column vector should be represented as a `Matrix` (given /// some concrete types for `T` and a compatible data storage type `S`). #[repr(C)] #[derive(Clone, Copy)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Matrix", + bound(archive = " + T: Archive, + S: Archive, + With, CustomPhantom<(Archived, R, C)>>: Archive, R, C)>> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] pub struct Matrix { /// The data storage that contains all the matrix components. Disappointed? /// @@ -187,6 +207,7 @@ pub struct Matrix { // of the `RawStorage` trait. However, because we don't have // specialization, this is not possible because these `T, R, C` // allows us to desambiguate a lot of configurations. + #[cfg_attr(feature = "rkyv-serialize-no-std", with(CustomPhantom<(T::Archived, R, C)>))] _phantoms: PhantomData<(T, R, C)>, } @@ -288,56 +309,13 @@ where { } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Matrix; - use core::marker::PhantomData; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Matrix { - type Archived = Matrix; - type Resolver = S::Resolver; - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut core::mem::MaybeUninit, - ) { - self.data.resolve( - pos + offset_of!(Self::Archived, data), - resolver, - project_struct!(out: Self::Archived => data), - ); - } - } - - impl, _S: Fallible + ?Sized> Serialize<_S> - for Matrix - { - fn serialize(&self, serializer: &mut _S) -> Result { - self.data.serialize(serializer) - } - } - - impl - Deserialize, D> - for Matrix - where - S::Archived: Deserialize, - { - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Matrix { - data: self.data.deserialize(deserializer)?, - _phantoms: PhantomData, - }) - } - } -} - impl Matrix { /// Creates a new matrix with the given data without statically checking that the matrix /// dimension matches the storage dimension. + /// + /// # Safety + /// + /// The storage dimension must match the given dimensions. #[inline(always)] pub const unsafe fn from_data_statically_unchecked(data: S) -> Matrix { Matrix { @@ -368,7 +346,7 @@ impl DMatrix { /// /// This method exists primarily as a workaround for the fact that `from_data` can not /// work in `const fn` contexts. - pub const fn from_vec_storage(storage: VecStorage) -> Self { + pub const fn from_vec_storage(storage: VecStorage) -> Self { // This is sound because the dimensions of the matrix and the storage are guaranteed // to be the same unsafe { Self::from_data_statically_unchecked(storage) } @@ -383,7 +361,7 @@ impl DVector { /// /// This method exists primarily as a workaround for the fact that `from_data` can not /// work in `const fn` contexts. - pub const fn from_vec_storage(storage: VecStorage) -> Self { + pub const fn from_vec_storage(storage: VecStorage) -> Self { // This is sound because the dimensions of the matrix and the storage are guaranteed // to be the same unsafe { Self::from_data_statically_unchecked(storage) } @@ -398,7 +376,7 @@ impl RowDVector { /// /// This method exists primarily as a workaround for the fact that `from_data` can not /// work in `const fn` contexts. - pub const fn from_vec_storage(storage: VecStorage) -> Self { + pub const fn from_vec_storage(storage: VecStorage) -> Self { // This is sound because the dimensions of the matrix and the storage are guaranteed // to be the same unsafe { Self::from_data_statically_unchecked(storage) } @@ -444,7 +422,7 @@ impl> Matrix { (nrows.value(), ncols.value()) } - /// The shape of this matrix wrapped into their representative types (`Const` or `Dynamic`). + /// The shape of this matrix wrapped into their representative types (`Const` or `Dyn`). #[inline] #[must_use] pub fn shape_generic(&self) -> (R, C) { @@ -485,7 +463,7 @@ impl> Matrix { /// ``` /// # use nalgebra::DMatrix; /// let mat = DMatrix::::zeros(10, 10); - /// let slice = mat.slice_with_steps((0, 0), (5, 3), (1, 2)); + /// let view = mat.view_with_steps((0, 0), (5, 3), (1, 2)); /// // The column strides is the number of steps (here 2) multiplied by the corresponding dimension. /// assert_eq!(mat.strides(), (1, 10)); /// ``` @@ -778,6 +756,24 @@ impl> Matrix { crate::convert(self) } + /// Attempts to cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let q = Vector3::new(1.0f64, 2.0, 3.0); + /// let q2 = q.try_cast::(); + /// assert_eq!(q2, Some(Vector3::new(1, 2, 3))); + /// ``` + pub fn try_cast(self) -> Option> + where + T: Scalar, + Self: SupersetOf>, + DefaultAllocator: Allocator, + { + crate::try_convert(self) + } + /// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure. /// /// The initialization closure is given the first component of this matrix: @@ -1201,6 +1197,10 @@ impl> Matrix { } /// Swaps two entries without bound-checking. + /// + /// # Safety + /// + /// Both `(r, c)` must have `r < nrows(), c < ncols()`. #[inline] pub unsafe fn swap_unchecked(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) { debug_assert!(row_cols1.0 < self.nrows() && row_cols1.1 < self.ncols()); @@ -1307,6 +1307,8 @@ impl> Matrix { impl> Vector { /// Gets a reference to the i-th element of this column vector without bound checking. + /// # Safety + /// `i` must be less than `D`. #[inline] #[must_use] pub unsafe fn vget_unchecked(&self, i: usize) -> &T { @@ -1318,6 +1320,8 @@ impl> Vector { impl> Vector { /// Gets a mutable reference to the i-th element of this column vector without bound checking. + /// # Safety + /// `i` must be less than `D`. #[inline] #[must_use] pub unsafe fn vget_unchecked_mut(&mut self, i: usize) -> &mut T { @@ -1654,7 +1658,7 @@ impl + IsNotStaticOne, S: RawStorage::from_usize(self.nrows() + 1); let mut res = OMatrix::identity_generic(dim, dim); - res.generic_slice_mut::((0, 0), self.shape_generic()) + res.generic_view_mut::((0, 0), self.shape_generic()) .copy_from(self); res } @@ -1682,7 +1686,7 @@ impl, S: RawStorage> Vector { { if v[v.len() - 1].is_zero() { let nrows = D::from_usize(v.len() - 1); - Some(v.generic_slice((0, 0), (nrows, Const::<1>)).into_owned()) + Some(v.generic_view((0, 0), (nrows, Const::<1>)).into_owned()) } else { None } @@ -1702,7 +1706,7 @@ impl, S: RawStorage> Vector { let mut res = Matrix::uninit(hnrows, Const::<1>); // This is basically a copy_from except that we warp the copied // values into MaybeUninit. - res.generic_slice_mut((0, 0), self.shape_generic()) + res.generic_view_mut((0, 0), self.shape_generic()) .zip_apply(self, |out, e| *out = MaybeUninit::new(e)); res[(len, 0)] = MaybeUninit::new(element); @@ -1868,14 +1872,14 @@ where impl Eq for Matrix where - T: Scalar + Eq, + T: Eq, S: RawStorage, { } impl PartialEq> for Matrix where - T: Scalar + PartialEq, + T: PartialEq, C: Dim, C2: Dim, R: Dim, @@ -2228,3 +2232,127 @@ where } } } + +impl Unit> +where + T: Scalar, + D: Dim, + S: RawStorage, +{ + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::::y_axis(); + /// let v2 = v.cast::(); + /// assert_eq!(v2, Vector3::::y_axis()); + /// ``` + pub fn cast(self) -> Unit> + where + T: Scalar, + OVector: SupersetOf>, + DefaultAllocator: Allocator, + { + Unit::new_unchecked(crate::convert_ref(self.as_ref())) + } +} + +impl Matrix +where + S: RawStorage, +{ + /// Returns a reference to the single element in this matrix. + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let inner_product: f32 = *(v.transpose() * v).as_scalar(); + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let inner_product = (v * v.transpose()).item(); // Typo, does not compile. + ///``` + pub fn as_scalar(&self) -> &T { + &self[(0, 0)] + } + /// Get a mutable reference to the single element in this matrix + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product = (v.transpose() * v); + /// *inner_product.as_scalar_mut() = 3.; + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product = (v * v.transpose()); + /// *inner_product.as_scalar_mut() = 3.; + ///``` + pub fn as_scalar_mut(&mut self) -> &mut T + where + S: RawStorageMut, + { + &mut self[(0, 0)] + } + /// Convert this 1x1 matrix by reference into a scalar. + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product: f32 = (v.transpose() * v).to_scalar(); + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product: f32 = (v * v.transpose()).to_scalar(); + ///``` + pub fn to_scalar(&self) -> T + where + T: Clone, + { + self.as_scalar().clone() + } +} + +impl super::alias::Matrix1 { + /// Convert this 1x1 matrix into a scalar. + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Matrix2, U1}; + /// let v = Vector3::new(0., 0., 1.); + /// let inner_product: f32 = (v.transpose() * v).into_scalar(); + /// assert_eq!(inner_product, 1.); + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product: f32 = (v * v.transpose()).into_scalar(); + ///``` + pub fn into_scalar(self) -> T { + let [[scalar]] = self.data.0; + scalar + } +} diff --git a/src/base/matrix_slice.rs b/src/base/matrix_slice.rs deleted file mode 100644 index 5fbd4b01..00000000 --- a/src/base/matrix_slice.rs +++ /dev/null @@ -1,955 +0,0 @@ -use std::marker::PhantomData; -use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; -use std::slice; - -use crate::base::allocator::Allocator; -use crate::base::default_allocator::DefaultAllocator; -use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1}; -use crate::base::iter::MatrixIter; -use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage}; -use crate::base::{Matrix, Scalar}; - -macro_rules! slice_storage_impl( - ($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { - #[doc = $doc] - #[derive(Debug)] - pub struct $T<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> { - ptr: $Ptr, - shape: (R, C), - strides: (RStride, CStride), - _phantoms: PhantomData<$Ref>, - } - - unsafe impl<'a, T: Send, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Send - for $T<'a, T, R, C, RStride, CStride> - {} - - unsafe impl<'a, T: Sync, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Sync - for $T<'a, T, R, C, RStride, CStride> - {} - - impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> $T<'a, T, R, C, RStride, CStride> { - /// Create a new matrix slice without bound checking and from a raw pointer. - #[inline] - pub unsafe fn from_raw_parts(ptr: $Ptr, - shape: (R, C), - strides: (RStride, CStride)) - -> Self - where RStride: Dim, - CStride: Dim { - - $T { - ptr, - shape, - strides, - _phantoms: PhantomData - } - } - } - - // Dynamic is arbitrary. It's just to be able to call the constructors with `Slice::` - impl<'a, T, R: Dim, C: Dim> $T<'a, T, R, C, Dynamic, Dynamic> { - /// Create a new matrix slice without bound checking. - #[inline] - pub unsafe fn new_unchecked(storage: $SRef, start: (usize, usize), shape: (R, C)) - -> $T<'a, T, R, C, S::RStride, S::CStride> - where RStor: Dim, - CStor: Dim, - S: $Storage { - - let strides = storage.strides(); - $T::new_with_strides_unchecked(storage, start, shape, strides) - } - - /// Create a new matrix slice without bound checking. - #[inline] - pub unsafe fn new_with_strides_unchecked(storage: $SRef, - start: (usize, usize), - shape: (R, C), - strides: (RStride, CStride)) - -> $T<'a, T, R, C, RStride, CStride> - where RStor: Dim, - CStor: Dim, - S: $Storage, - RStride: Dim, - CStride: Dim { - $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides) - } - } - - impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> - $T<'a, T, R, C, RStride, CStride> - where - Self: RawStorage + IsContiguous - { - /// Extracts the original slice from this storage - pub fn into_slice(self) -> &'a [T] { - let (nrows, ncols) = self.shape(); - if nrows.value() != 0 && ncols.value() != 0 { - let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); - unsafe { slice::from_raw_parts(self.ptr, sz + 1) } - } else { - unsafe { slice::from_raw_parts(self.ptr, 0) } - } - } - } - } -); - -slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \ - to another matrix data storage."; - RawStorage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T)); - -slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Only contains an \ - internal mutable reference to another matrix data storage."; - RawStorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T) -); - -impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy - for SliceStorage<'a, T, R, C, RStride, CStride> -{ -} - -impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone - for SliceStorage<'a, T, R, C, RStride, CStride> -{ - #[inline] - fn clone(&self) -> Self { - Self { - ptr: self.ptr, - shape: self.shape, - strides: self.strides, - _phantoms: PhantomData, - } - } -} - -impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> - SliceStorageMut<'a, T, R, C, RStride, CStride> -where - Self: RawStorageMut + IsContiguous, -{ - /// Extracts the original slice from this storage - pub fn into_slice_mut(self) -> &'a mut [T] { - let (nrows, ncols) = self.shape(); - if nrows.value() != 0 && ncols.value() != 0 { - let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); - unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) } - } else { - unsafe { slice::from_raw_parts_mut(self.ptr, 0) } - } - } -} - -macro_rules! storage_impl( - ($($T: ident),* $(,)*) => {$( - unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage - for $T<'a, T, R, C, RStride, CStride> { - - type RStride = RStride; - type CStride = CStride; - - #[inline] - fn ptr(&self) -> *const T { - self.ptr - } - - #[inline] - fn shape(&self) -> (R, C) { - self.shape - } - - #[inline] - fn strides(&self) -> (Self::RStride, Self::CStride) { - self.strides - } - - #[inline] - fn is_contiguous(&self) -> bool { - // Common cases that can be deduced at compile-time even if one of the dimensions - // is Dynamic. - if (RStride::is::() && C::is::()) || // Column vector. - (CStride::is::() && R::is::()) { // Row vector. - true - } - else { - let (nrows, _) = self.shape(); - let (srows, scols) = self.strides(); - - srows.value() == 1 && scols.value() == nrows.value() - } - } - - #[inline] - unsafe fn as_slice_unchecked(&self) -> &[T] { - let (nrows, ncols) = self.shape(); - if nrows.value() != 0 && ncols.value() != 0 { - let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); - slice::from_raw_parts(self.ptr, sz + 1) - } - else { - slice::from_raw_parts(self.ptr, 0) - } - } - } - - unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage - for $T<'a, T, R, C, RStride, CStride> { - #[inline] - fn into_owned(self) -> Owned - where DefaultAllocator: Allocator { - self.clone_owned() - } - - #[inline] - fn clone_owned(&self) -> Owned - where DefaultAllocator: Allocator { - let (nrows, ncols) = self.shape(); - let it = MatrixIter::new(self).cloned(); - DefaultAllocator::allocate_from_iterator(nrows, ncols, it) - } - } - )*} -); - -storage_impl!(SliceStorage, SliceStorageMut); - -unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut - for SliceStorageMut<'a, T, R, C, RStride, CStride> -{ - #[inline] - fn ptr_mut(&mut self) -> *mut T { - self.ptr - } - - #[inline] - unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] { - let (nrows, ncols) = self.shape(); - if nrows.value() != 0 && ncols.value() != 0 { - let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); - slice::from_raw_parts_mut(self.ptr, sz + 1) - } else { - slice::from_raw_parts_mut(self.ptr, 0) - } - } -} - -unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous for SliceStorage<'a, T, R, U1, U1, CStride> {} -unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous - for SliceStorageMut<'a, T, R, U1, U1, CStride> -{ -} - -unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous - for SliceStorage<'a, T, R, C, U1, R> -{ -} -unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous - for SliceStorageMut<'a, T, R, C, U1, R> -{ -} - -impl> Matrix { - #[inline] - fn assert_slice_index( - &self, - start: (usize, usize), - shape: (usize, usize), - steps: (usize, usize), - ) { - let my_shape = self.shape(); - // NOTE: we don't do any subtraction to avoid underflow for zero-sized matrices. - // - // Terms that would have been negative are moved to the other side of the inequality - // instead. - assert!( - start.0 + (steps.0 + 1) * shape.0 <= my_shape.0 + steps.0, - "Matrix slicing out of bounds." - ); - assert!( - start.1 + (steps.1 + 1) * shape.1 <= my_shape.1 + steps.1, - "Matrix slicing out of bounds." - ); - } -} - -macro_rules! matrix_slice_impl( - ($me: ident: $Me: ty, $MatrixSlice: ident, $SliceStorage: ident, $Storage: ident.$get_addr: ident (), $data: expr; - $row: ident, - $row_part: ident, - $rows: ident, - $rows_with_step: ident, - $fixed_rows: ident, - $fixed_rows_with_step: ident, - $rows_generic: ident, - $rows_generic_with_step: ident, - $column: ident, - $column_part: ident, - $columns: ident, - $columns_with_step: ident, - $fixed_columns: ident, - $fixed_columns_with_step: ident, - $columns_generic: ident, - $columns_generic_with_step: ident, - $slice: ident, - $slice_with_steps: ident, - $fixed_slice: ident, - $fixed_slice_with_steps: ident, - $generic_slice: ident, - $generic_slice_with_steps: ident, - $rows_range_pair: ident, - $columns_range_pair: ident) => { - /* - * - * Row slicing. - * - */ - /// Returns a slice containing the i-th row of this matrix. - #[inline] - pub fn $row($me: $Me, i: usize) -> $MatrixSlice<'_, T, U1, C, S::RStride, S::CStride> { - $me.$fixed_rows::<1>(i) - } - - /// Returns a slice containing the `n` first elements of the i-th row of this matrix. - #[inline] - pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixSlice<'_, T, U1, Dynamic, S::RStride, S::CStride> { - $me.$generic_slice((i, 0), (Const::<1>, Dynamic::new(n))) - } - - /// Extracts from this matrix a set of consecutive rows. - #[inline] - pub fn $rows($me: $Me, first_row: usize, nrows: usize) - -> $MatrixSlice<'_, T, Dynamic, C, S::RStride, S::CStride> { - - $me.$rows_generic(first_row, Dynamic::new(nrows)) - } - - /// Extracts from this matrix a set of consecutive rows regularly skipping `step` rows. - #[inline] - pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) - -> $MatrixSlice<'_, T, Dynamic, C, Dynamic, S::CStride> { - - $me.$rows_generic_with_step(first_row, Dynamic::new(nrows), step) - } - - /// Extracts a compile-time number of consecutive rows from this matrix. - #[inline] - pub fn $fixed_rows($me: $Me, first_row: usize) - -> $MatrixSlice<'_, T, Const, C, S::RStride, S::CStride> { - - $me.$rows_generic(first_row, Const::) - } - - /// Extracts from this matrix a compile-time number of rows regularly skipping `step` - /// rows. - #[inline] - pub fn $fixed_rows_with_step($me: $Me, first_row: usize, step: usize) - -> $MatrixSlice<'_, T, Const, C, Dynamic, S::CStride> { - - $me.$rows_generic_with_step(first_row, Const::, step) - } - - /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both - /// argument may or may not be values known at compile-time. - #[inline] - pub fn $rows_generic($me: $Me, row_start: usize, nrows: RSlice) - -> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> { - - let my_shape = $me.shape_generic(); - $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); - - let shape = (nrows, my_shape.1); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape); - Matrix::from_data_statically_unchecked(data) - } - } - - /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both - /// argument may or may not be values known at compile-time. - #[inline] - pub fn $rows_generic_with_step($me: $Me, row_start: usize, nrows: RSlice, step: usize) - -> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride> - where RSlice: Dim { - - let my_shape = $me.shape_generic(); - let my_strides = $me.data.strides(); - $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); - - let strides = (Dynamic::new((step + 1) * my_strides.0.value()), my_strides.1); - let shape = (nrows, my_shape.1); - - unsafe { - let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides); - Matrix::from_data_statically_unchecked(data) - } - } - - /* - * - * Column slicing. - * - */ - /// Returns a slice containing the i-th column of this matrix. - #[inline] - pub fn $column($me: $Me, i: usize) -> $MatrixSlice<'_, T, R, U1, S::RStride, S::CStride> { - $me.$fixed_columns::<1>(i) - } - - /// Returns a slice containing the `n` first elements of the i-th column of this matrix. - #[inline] - pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixSlice<'_, T, Dynamic, U1, S::RStride, S::CStride> { - $me.$generic_slice((0, i), (Dynamic::new(n), Const::<1>)) - } - - /// Extracts from this matrix a set of consecutive columns. - #[inline] - pub fn $columns($me: $Me, first_col: usize, ncols: usize) - -> $MatrixSlice<'_, T, R, Dynamic, S::RStride, S::CStride> { - - $me.$columns_generic(first_col, Dynamic::new(ncols)) - } - - /// Extracts from this matrix a set of consecutive columns regularly skipping `step` - /// columns. - #[inline] - pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) - -> $MatrixSlice<'_, T, R, Dynamic, S::RStride, Dynamic> { - - $me.$columns_generic_with_step(first_col, Dynamic::new(ncols), step) - } - - /// Extracts a compile-time number of consecutive columns from this matrix. - #[inline] - pub fn $fixed_columns($me: $Me, first_col: usize) - -> $MatrixSlice<'_, T, R, Const, S::RStride, S::CStride> { - - $me.$columns_generic(first_col, Const::) - } - - /// Extracts from this matrix a compile-time number of columns regularly skipping - /// `step` columns. - #[inline] - pub fn $fixed_columns_with_step($me: $Me, first_col: usize, step: usize) - -> $MatrixSlice<'_, T, R, Const, S::RStride, Dynamic> { - - $me.$columns_generic_with_step(first_col, Const::, step) - } - - /// Extracts from this matrix `ncols` columns. The number of columns may or may not be - /// known at compile-time. - #[inline] - pub fn $columns_generic($me: $Me, first_col: usize, ncols: CSlice) - -> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> { - - let my_shape = $me.shape_generic(); - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); - let shape = (my_shape.0, ncols); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (0, first_col), shape); - Matrix::from_data_statically_unchecked(data) - } - } - - - /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may - /// or may not be values known at compile-time. - #[inline] - pub fn $columns_generic_with_step($me: $Me, first_col: usize, ncols: CSlice, step: usize) - -> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> { - - let my_shape = $me.shape_generic(); - let my_strides = $me.data.strides(); - - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); - - let strides = (my_strides.0, Dynamic::new((step + 1) * my_strides.1.value())); - let shape = (my_shape.0, ncols); - - unsafe { - let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides); - Matrix::from_data_statically_unchecked(data) - } - } - - /* - * - * General slicing. - * - */ - /// Slices this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` - /// consecutive elements. - #[inline] - pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) - -> $MatrixSlice<'_, T, Dynamic, Dynamic, S::RStride, S::CStride> { - - $me.assert_slice_index(start, shape, (0, 0)); - let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); - - unsafe { - let data = $SliceStorage::new_unchecked($data, start, shape); - Matrix::from_data_statically_unchecked(data) - } - } - - - /// Slices this matrix starting at its component `(start.0, start.1)` and with - /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is - /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the - /// original matrix. - #[inline] - pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) - -> $MatrixSlice<'_, T, Dynamic, Dynamic, Dynamic, Dynamic> { - let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); - - $me.$generic_slice_with_steps(start, shape, steps) - } - - /// Slices this matrix starting at its component `(irow, icol)` and with `(R::dim(), - /// CSlice::dim())` consecutive components. - #[inline] - pub fn $fixed_slice($me: $Me, irow: usize, icol: usize) - -> $MatrixSlice<'_, T, Const, Const, S::RStride, S::CStride> { - - $me.assert_slice_index((irow, icol), (RSLICE, CSLICE), (0, 0)); - let shape = (Const::, Const::); - - unsafe { - let data = $SliceStorage::new_unchecked($data, (irow, icol), shape); - Matrix::from_data_statically_unchecked(data) - } - } - - /// Slices this matrix starting at its component `(start.0, start.1)` and with - /// `(RSLICE, CSLICE)` components. Each row (resp. column) of the sliced - /// matrix is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of - /// the original matrix. - #[inline] - pub fn $fixed_slice_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) - -> $MatrixSlice<'_, T, Const, Const, Dynamic, Dynamic> { - let shape = (Const::, Const::); - $me.$generic_slice_with_steps(start, shape, steps) - } - - /// Creates a slice that may or may not have a fixed size and stride. - #[inline] - pub fn $generic_slice($me: $Me, start: (usize, usize), shape: (RSlice, CSlice)) - -> $MatrixSlice<'_, T, RSlice, CSlice, S::RStride, S::CStride> - where RSlice: Dim, - CSlice: Dim { - - $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0)); - - unsafe { - let data = $SliceStorage::new_unchecked($data, start, shape); - Matrix::from_data_statically_unchecked(data) - } - } - - /// Creates a slice that may or may not have a fixed size and stride. - #[inline] - pub fn $generic_slice_with_steps($me: $Me, - start: (usize, usize), - shape: (RSlice, CSlice), - steps: (usize, usize)) - -> $MatrixSlice<'_, T, RSlice, CSlice, Dynamic, Dynamic> - where RSlice: Dim, - CSlice: Dim { - - $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), steps); - - let my_strides = $me.data.strides(); - let strides = (Dynamic::new((steps.0 + 1) * my_strides.0.value()), - Dynamic::new((steps.1 + 1) * my_strides.1.value())); - - unsafe { - let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides); - Matrix::from_data_statically_unchecked(data) - } - } - - /* - * - * Splitting. - * - */ - /// Splits this `NxM` matrix into two parts delimited by two ranges. - /// - /// Panics if the ranges overlap or if the first range is empty. - #[inline] - pub fn $rows_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) - -> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>, - $MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) { - - let (nrows, ncols) = $me.shape_generic(); - let strides = $me.data.strides(); - - let start1 = r1.begin(nrows); - let start2 = r2.begin(nrows); - - let end1 = r1.end(nrows); - let end2 = r2.end(nrows); - - let nrows1 = r1.size(nrows); - let nrows2 = r2.size(nrows); - - assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the slice ranges must not overlap."); - assert!(end2 <= nrows.value(), "Rows range pair: index out of range."); - - unsafe { - let ptr1 = $data.$get_addr(start1, 0); - let ptr2 = $data.$get_addr(start2, 0); - - let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); - let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); - let slice1 = Matrix::from_data_statically_unchecked(data1); - let slice2 = Matrix::from_data_statically_unchecked(data2); - - (slice1, slice2) - } - } - - /// Splits this `NxM` matrix into two parts delimited by two ranges. - /// - /// Panics if the ranges overlap or if the first range is empty. - #[inline] - pub fn $columns_range_pair, Range2: SliceRange>($me: $Me, r1: Range1, r2: Range2) - -> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>, - $MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) { - - let (nrows, ncols) = $me.shape_generic(); - let strides = $me.data.strides(); - - let start1 = r1.begin(ncols); - let start2 = r2.begin(ncols); - - let end1 = r1.end(ncols); - let end2 = r2.end(ncols); - - let ncols1 = r1.size(ncols); - let ncols2 = r2.size(ncols); - - assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the slice ranges must not overlap."); - assert!(end2 <= ncols.value(), "Columns range pair: index out of range."); - - unsafe { - let ptr1 = $data.$get_addr(0, start1); - let ptr2 = $data.$get_addr(0, start2); - - let data1 = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); - let data2 = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); - let slice1 = Matrix::from_data_statically_unchecked(data1); - let slice2 = Matrix::from_data_statically_unchecked(data2); - - (slice1, slice2) - } - } - } -); - -/// A matrix slice. -pub type MatrixSlice<'a, T, R, C, RStride = U1, CStride = R> = - Matrix>; -/// A mutable matrix slice. -pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> = - Matrix>; - -/// # Slicing based on index and length -impl> Matrix { - matrix_slice_impl!( - self: &Self, MatrixSlice, SliceStorage, RawStorage.get_address_unchecked(), &self.data; - row, - row_part, - rows, - rows_with_step, - fixed_rows, - fixed_rows_with_step, - rows_generic, - rows_generic_with_step, - column, - column_part, - columns, - columns_with_step, - fixed_columns, - fixed_columns_with_step, - columns_generic, - columns_generic_with_step, - slice, - slice_with_steps, - fixed_slice, - fixed_slice_with_steps, - generic_slice, - generic_slice_with_steps, - rows_range_pair, - columns_range_pair); -} - -/// # Mutable slicing based on index and length -impl> Matrix { - matrix_slice_impl!( - self: &mut Self, MatrixSliceMut, SliceStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data; - row_mut, - row_part_mut, - rows_mut, - rows_with_step_mut, - fixed_rows_mut, - fixed_rows_with_step_mut, - rows_generic_mut, - rows_generic_with_step_mut, - column_mut, - column_part_mut, - columns_mut, - columns_with_step_mut, - fixed_columns_mut, - fixed_columns_with_step_mut, - columns_generic_mut, - columns_generic_with_step_mut, - slice_mut, - slice_with_steps_mut, - fixed_slice_mut, - fixed_slice_with_steps_mut, - generic_slice_mut, - generic_slice_with_steps_mut, - rows_range_pair_mut, - columns_range_pair_mut); -} - -/// A range with a size that may be known at compile-time. -/// -/// This may be: -/// * A single `usize` index, e.g., `4` -/// * A left-open range `std::ops::RangeTo`, e.g., `.. 4` -/// * A right-open range `std::ops::RangeFrom`, e.g., `4 ..` -/// * A full range `std::ops::RangeFull`, e.g., `..` -pub trait SliceRange { - /// Type of the range size. May be a type-level integer. - type Size: Dim; - - /// The start index of the range. - fn begin(&self, shape: D) -> usize; - // NOTE: this is the index immediately after the last index. - /// The index immediately after the last index inside of the range. - fn end(&self, shape: D) -> usize; - /// The number of elements of the range, i.e., `self.end - self.begin`. - fn size(&self, shape: D) -> Self::Size; -} - -impl SliceRange for usize { - type Size = U1; - - #[inline(always)] - fn begin(&self, _: D) -> usize { - *self - } - - #[inline(always)] - fn end(&self, _: D) -> usize { - *self + 1 - } - - #[inline(always)] - fn size(&self, _: D) -> Self::Size { - Const::<1> - } -} - -impl SliceRange for Range { - type Size = Dynamic; - - #[inline(always)] - fn begin(&self, _: D) -> usize { - self.start - } - - #[inline(always)] - fn end(&self, _: D) -> usize { - self.end - } - - #[inline(always)] - fn size(&self, _: D) -> Self::Size { - Dynamic::new(self.end - self.start) - } -} - -impl SliceRange for RangeFrom { - type Size = Dynamic; - - #[inline(always)] - fn begin(&self, _: D) -> usize { - self.start - } - - #[inline(always)] - fn end(&self, dim: D) -> usize { - dim.value() - } - - #[inline(always)] - fn size(&self, dim: D) -> Self::Size { - Dynamic::new(dim.value() - self.start) - } -} - -impl SliceRange for RangeTo { - type Size = Dynamic; - - #[inline(always)] - fn begin(&self, _: D) -> usize { - 0 - } - - #[inline(always)] - fn end(&self, _: D) -> usize { - self.end - } - - #[inline(always)] - fn size(&self, _: D) -> Self::Size { - Dynamic::new(self.end) - } -} - -impl SliceRange for RangeFull { - type Size = D; - - #[inline(always)] - fn begin(&self, _: D) -> usize { - 0 - } - - #[inline(always)] - fn end(&self, dim: D) -> usize { - dim.value() - } - - #[inline(always)] - fn size(&self, dim: D) -> Self::Size { - dim - } -} - -impl SliceRange for RangeInclusive { - type Size = Dynamic; - - #[inline(always)] - fn begin(&self, _: D) -> usize { - *self.start() - } - - #[inline(always)] - fn end(&self, _: D) -> usize { - *self.end() + 1 - } - - #[inline(always)] - fn size(&self, _: D) -> Self::Size { - Dynamic::new(*self.end() + 1 - *self.start()) - } -} - -// TODO: see how much of this overlaps with the general indexing -// methods from indexing.rs. -impl> Matrix { - /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed - /// by the range `cols`. - #[inline] - #[must_use] - pub fn slice_range( - &self, - rows: RowRange, - cols: ColRange, - ) -> MatrixSlice<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> - where - RowRange: SliceRange, - ColRange: SliceRange, - { - let (nrows, ncols) = self.shape_generic(); - self.generic_slice( - (rows.begin(nrows), cols.begin(ncols)), - (rows.size(nrows), cols.size(ncols)), - ) - } - - /// Slice containing all the rows indexed by the range `rows`. - #[inline] - #[must_use] - pub fn rows_range>( - &self, - rows: RowRange, - ) -> MatrixSlice<'_, T, RowRange::Size, C, S::RStride, S::CStride> { - self.slice_range(rows, ..) - } - - /// Slice containing all the columns indexed by the range `rows`. - #[inline] - #[must_use] - pub fn columns_range>( - &self, - cols: ColRange, - ) -> MatrixSlice<'_, T, R, ColRange::Size, S::RStride, S::CStride> { - self.slice_range(.., cols) - } -} - -// TODO: see how much of this overlaps with the general indexing -// methods from indexing.rs. -impl> Matrix { - /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns - /// indexed by the range `cols`. - pub fn slice_range_mut( - &mut self, - rows: RowRange, - cols: ColRange, - ) -> MatrixSliceMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> - where - RowRange: SliceRange, - ColRange: SliceRange, - { - let (nrows, ncols) = self.shape_generic(); - self.generic_slice_mut( - (rows.begin(nrows), cols.begin(ncols)), - (rows.size(nrows), cols.size(ncols)), - ) - } - - /// Slice containing all the rows indexed by the range `rows`. - #[inline] - pub fn rows_range_mut>( - &mut self, - rows: RowRange, - ) -> MatrixSliceMut<'_, T, RowRange::Size, C, S::RStride, S::CStride> { - self.slice_range_mut(rows, ..) - } - - /// Slice containing all the columns indexed by the range `cols`. - #[inline] - pub fn columns_range_mut>( - &mut self, - cols: ColRange, - ) -> MatrixSliceMut<'_, T, R, ColRange::Size, S::RStride, S::CStride> { - self.slice_range_mut(.., cols) - } -} - -impl<'a, T, R, C, RStride, CStride> From> - for MatrixSlice<'a, T, R, C, RStride, CStride> -where - R: Dim, - C: Dim, - RStride: Dim, - CStride: Dim, -{ - fn from(slice_mut: MatrixSliceMut<'a, T, 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) } - } -} diff --git a/src/base/matrix_view.rs b/src/base/matrix_view.rs new file mode 100644 index 00000000..ab3d68ce --- /dev/null +++ b/src/base/matrix_view.rs @@ -0,0 +1,1241 @@ +use std::marker::PhantomData; +use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; +use std::slice; + +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Const, Dim, DimName, Dyn, IsNotStaticOne, U1}; +use crate::base::iter::MatrixIter; +use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage}; +use crate::base::{Matrix, Scalar}; +use crate::constraint::{DimEq, ShapeConstraint}; +use crate::ReshapableStorage; + +macro_rules! view_storage_impl ( + ($doc: expr; $Storage: ident as $SRef: ty; $legacy_name:ident => $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { + #[doc = $doc] + #[derive(Debug)] + pub struct $T<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> { + ptr: $Ptr, + shape: (R, C), + strides: (RStride, CStride), + _phantoms: PhantomData<$Ref>, + } + + #[doc = $doc] + /// + /// This type alias exists only for legacy purposes and is deprecated. It will be removed + /// in a future release. Please use + /// [` + #[doc = stringify!($T)] + /// `] instead. See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) + /// for the rationale. + #[deprecated = "Use ViewStorage(Mut) instead."] + pub type $legacy_name<'a, T, R, C, RStride, CStride> = $T<'a, T, R, C, RStride, CStride>; + + unsafe impl<'a, T: Send, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Send + for $T<'a, T, R, C, RStride, CStride> + {} + + unsafe impl<'a, T: Sync, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Sync + for $T<'a, T, R, C, RStride, CStride> + {} + + impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> $T<'a, T, R, C, RStride, CStride> { + /// Create a new matrix view without bounds checking and from a raw pointer. + /// + /// # Safety + /// + /// `*ptr` must point to memory that is valid `[T; R * C]`. + #[inline] + pub unsafe fn from_raw_parts(ptr: $Ptr, + shape: (R, C), + strides: (RStride, CStride)) + -> Self + where RStride: Dim, + CStride: Dim { + + $T { + ptr, + shape, + strides, + _phantoms: PhantomData + } + } + } + + // Dyn is arbitrary. It's just to be able to call the constructors with `Slice::` + impl<'a, T, R: Dim, C: Dim> $T<'a, T, R, C, Dyn, Dyn> { + /// Create a new matrix view without bounds checking. + /// + /// # Safety + /// + /// `storage` contains sufficient elements beyond `start + R * C` such that all + /// accesses are within bounds. + #[inline] + pub unsafe fn new_unchecked(storage: $SRef, start: (usize, usize), shape: (R, C)) + -> $T<'a, T, R, C, S::RStride, S::CStride> + where RStor: Dim, + CStor: Dim, + S: $Storage { + + let strides = storage.strides(); + $T::new_with_strides_unchecked(storage, start, shape, strides) + } + + /// Create a new matrix view without bounds checking. + /// + /// # Safety + /// + /// `strides` must be a valid stride indexing. + #[inline] + pub unsafe fn new_with_strides_unchecked(storage: $SRef, + start: (usize, usize), + shape: (R, C), + strides: (RStride, CStride)) + -> $T<'a, T, R, C, RStride, CStride> + where RStor: Dim, + CStor: Dim, + S: $Storage, + RStride: Dim, + CStride: Dim { + $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides) + } + } + + impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + $T<'a, T, R, C, RStride, CStride> + where + Self: RawStorage + IsContiguous + { + /// Extracts the original slice from this storage. + pub fn into_slice(self) -> &'a [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts(self.ptr, sz + 1) } + } else { + unsafe { slice::from_raw_parts(self.ptr, 0) } + } + } + } + } +); + +view_storage_impl!("A matrix data storage for a matrix view. Only contains an internal reference \ + to another matrix data storage."; + RawStorage as &'a S; SliceStorage => ViewStorage.get_address_unchecked(*const T as &'a T)); + +view_storage_impl!("A mutable matrix data storage for mutable matrix view. Only contains an \ + internal mutable reference to another matrix data storage."; + RawStorageMut as &'a mut S; SliceStorageMut => ViewStorageMut.get_address_unchecked_mut(*mut T as &'a mut T) +); + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy + for ViewStorage<'a, T, R, C, RStride, CStride> +{ +} + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone + for ViewStorage<'a, T, R, C, RStride, CStride> +{ + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + ViewStorageMut<'a, T, R, C, RStride, CStride> +where + Self: RawStorageMut + IsContiguous, +{ + /// Extracts the original slice from this storage + pub fn into_slice_mut(self) -> &'a mut [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) } + } else { + unsafe { slice::from_raw_parts_mut(self.ptr, 0) } + } + } +} + +macro_rules! storage_impl( + ($($T: ident),* $(,)*) => {$( + unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage + for $T<'a, T, R, C, RStride, CStride> { + + type RStride = RStride; + type CStride = CStride; + + #[inline] + fn ptr(&self) -> *const T { + self.ptr + } + + #[inline] + fn shape(&self) -> (R, C) { + self.shape + } + + #[inline] + fn strides(&self) -> (Self::RStride, Self::CStride) { + self.strides + } + + #[inline] + fn is_contiguous(&self) -> bool { + // Common cases that can be deduced at compile-time even if one of the dimensions + // is Dyn. + if (RStride::is::() && C::is::()) || // Column vector. + (CStride::is::() && R::is::()) { // Row vector. + true + } + else { + let (nrows, _) = self.shape(); + let (srows, scols) = self.strides(); + + srows.value() == 1 && scols.value() == nrows.value() + } + } + + #[inline] + unsafe fn as_slice_unchecked(&self) -> &[T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + slice::from_raw_parts(self.ptr, sz + 1) + } + else { + slice::from_raw_parts(self.ptr, 0) + } + } + } + + unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage + for $T<'a, T, R, C, RStride, CStride> { + #[inline] + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator { + self.clone_owned() + } + + #[inline] + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator { + let (nrows, ncols) = self.shape(); + let it = MatrixIter::new(self).cloned(); + DefaultAllocator::allocate_from_iterator(nrows, ncols, it) + } + } + )*} +); + +storage_impl!(ViewStorage, ViewStorageMut); + +unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut + for ViewStorageMut<'a, T, R, C, RStride, CStride> +{ + #[inline] + fn ptr_mut(&mut self) -> *mut T { + self.ptr + } + + #[inline] + unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + slice::from_raw_parts_mut(self.ptr, sz + 1) + } else { + slice::from_raw_parts_mut(self.ptr, 0) + } + } +} + +unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous for ViewStorage<'a, T, R, U1, U1, CStride> {} +unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous + for ViewStorageMut<'a, T, R, U1, U1, CStride> +{ +} + +unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous + for ViewStorage<'a, T, R, C, U1, R> +{ +} +unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous + for ViewStorageMut<'a, T, R, C, U1, R> +{ +} + +impl> Matrix { + #[inline] + fn assert_view_index( + &self, + start: (usize, usize), + shape: (usize, usize), + steps: (usize, usize), + ) { + let my_shape = self.shape(); + // NOTE: we don't do any subtraction to avoid underflow for zero-sized matrices. + // + // Terms that would have been negative are moved to the other side of the inequality + // instead. + assert!( + start.0 + (steps.0 + 1) * shape.0 <= my_shape.0 + steps.0, + "Matrix slicing out of bounds." + ); + assert!( + start.1 + (steps.1 + 1) * shape.1 <= my_shape.1 + steps.1, + "Matrix slicing out of bounds." + ); + } +} + +macro_rules! matrix_view_impl ( + ($me: ident: $Me: ty, $MatrixView: ident, $ViewStorage: ident, $Storage: ident.$get_addr: ident (), $data: expr; + $row: ident, + $row_part: ident, + $rows: ident, + $rows_with_step: ident, + $fixed_rows: ident, + $fixed_rows_with_step: ident, + $rows_generic: ident, + $rows_generic_with_step: ident, + $column: ident, + $column_part: ident, + $columns: ident, + $columns_with_step: ident, + $fixed_columns: ident, + $fixed_columns_with_step: ident, + $columns_generic: ident, + $columns_generic_with_step: ident, + $slice: ident => $view:ident, + $slice_with_steps: ident => $view_with_steps:ident, + $fixed_slice: ident => $fixed_view:ident, + $fixed_slice_with_steps: ident => $fixed_view_with_steps:ident, + $generic_slice: ident => $generic_view:ident, + $generic_slice_with_steps: ident => $generic_view_with_steps:ident, + $rows_range_pair: ident, + $columns_range_pair: ident) => { + /* + * + * Row slicing. + * + */ + /// Returns a view containing the i-th row of this matrix. + #[inline] + pub fn $row($me: $Me, i: usize) -> $MatrixView<'_, T, U1, C, S::RStride, S::CStride> { + $me.$fixed_rows::<1>(i) + } + + /// Returns a view containing the `n` first elements of the i-th row of this matrix. + #[inline] + pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixView<'_, T, U1, Dyn, S::RStride, S::CStride> { + $me.$generic_view((i, 0), (Const::<1>, Dyn(n))) + } + + /// Extracts from this matrix a set of consecutive rows. + #[inline] + pub fn $rows($me: $Me, first_row: usize, nrows: usize) + -> $MatrixView<'_, T, Dyn, C, S::RStride, S::CStride> { + + $me.$rows_generic(first_row, Dyn(nrows)) + } + + /// Extracts from this matrix a set of consecutive rows regularly skipping `step` rows. + #[inline] + pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) + -> $MatrixView<'_, T, Dyn, C, Dyn, S::CStride> { + + $me.$rows_generic_with_step(first_row, Dyn(nrows), step) + } + + /// Extracts a compile-time number of consecutive rows from this matrix. + #[inline] + pub fn $fixed_rows($me: $Me, first_row: usize) + -> $MatrixView<'_, T, Const, C, S::RStride, S::CStride> { + + $me.$rows_generic(first_row, Const::) + } + + /// Extracts from this matrix a compile-time number of rows regularly skipping `step` + /// rows. + #[inline] + pub fn $fixed_rows_with_step($me: $Me, first_row: usize, step: usize) + -> $MatrixView<'_, T, Const, C, Dyn, S::CStride> { + + $me.$rows_generic_with_step(first_row, Const::, step) + } + + /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both + /// argument may or may not be values known at compile-time. + #[inline] + pub fn $rows_generic($me: $Me, row_start: usize, nrows: RView) + -> $MatrixView<'_, T, RView, C, S::RStride, S::CStride> { + + let my_shape = $me.shape_generic(); + $me.assert_view_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); + + let shape = (nrows, my_shape.1); + + unsafe { + let data = $ViewStorage::new_unchecked($data, (row_start, 0), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both + /// argument may or may not be values known at compile-time. + #[inline] + pub fn $rows_generic_with_step($me: $Me, row_start: usize, nrows: RView, step: usize) + -> $MatrixView<'_, T, RView, C, Dyn, S::CStride> + where RView: Dim { + + let my_shape = $me.shape_generic(); + let my_strides = $me.data.strides(); + $me.assert_view_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); + + let strides = (Dyn((step + 1) * my_strides.0.value()), my_strides.1); + let shape = (nrows, my_shape.1); + + unsafe { + let data = $ViewStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides); + Matrix::from_data_statically_unchecked(data) + } + } + + /* + * + * Column slicing. + * + */ + /// Returns a view containing the i-th column of this matrix. + #[inline] + pub fn $column($me: $Me, i: usize) -> $MatrixView<'_, T, R, U1, S::RStride, S::CStride> { + $me.$fixed_columns::<1>(i) + } + + /// Returns a view containing the `n` first elements of the i-th column of this matrix. + #[inline] + pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixView<'_, T, Dyn, U1, S::RStride, S::CStride> { + $me.$generic_view((0, i), (Dyn(n), Const::<1>)) + } + + /// Extracts from this matrix a set of consecutive columns. + #[inline] + pub fn $columns($me: $Me, first_col: usize, ncols: usize) + -> $MatrixView<'_, T, R, Dyn, S::RStride, S::CStride> { + + $me.$columns_generic(first_col, Dyn(ncols)) + } + + /// Extracts from this matrix a set of consecutive columns regularly skipping `step` + /// columns. + #[inline] + pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) + -> $MatrixView<'_, T, R, Dyn, S::RStride, Dyn> { + + $me.$columns_generic_with_step(first_col, Dyn(ncols), step) + } + + /// Extracts a compile-time number of consecutive columns from this matrix. + #[inline] + pub fn $fixed_columns($me: $Me, first_col: usize) + -> $MatrixView<'_, T, R, Const, S::RStride, S::CStride> { + + $me.$columns_generic(first_col, Const::) + } + + /// Extracts from this matrix a compile-time number of columns regularly skipping + /// `step` columns. + #[inline] + pub fn $fixed_columns_with_step($me: $Me, first_col: usize, step: usize) + -> $MatrixView<'_, T, R, Const, S::RStride, Dyn> { + + $me.$columns_generic_with_step(first_col, Const::, step) + } + + /// Extracts from this matrix `ncols` columns. The number of columns may or may not be + /// known at compile-time. + #[inline] + pub fn $columns_generic($me: $Me, first_col: usize, ncols: CView) + -> $MatrixView<'_, T, R, CView, S::RStride, S::CStride> { + + let my_shape = $me.shape_generic(); + $me.assert_view_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $ViewStorage::new_unchecked($data, (0, first_col), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + + /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may + /// or may not be values known at compile-time. + #[inline] + pub fn $columns_generic_with_step($me: $Me, first_col: usize, ncols: CView, step: usize) + -> $MatrixView<'_, T, R, CView, S::RStride, Dyn> { + + let my_shape = $me.shape_generic(); + let my_strides = $me.data.strides(); + + $me.assert_view_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); + + let strides = (my_strides.0, Dyn((step + 1) * my_strides.1.value())); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $ViewStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides); + Matrix::from_data_statically_unchecked(data) + } + } + + /* + * + * General slicing. + * + */ + /// Slices this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` + /// consecutive elements. + #[inline] + #[deprecated = slice_deprecation_note!($view)] + pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, S::RStride, S::CStride> { + $me.$view(start, shape) + } + + /// Return a view of this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` + /// consecutive elements. + #[inline] + pub fn $view($me: $Me, start: (usize, usize), shape: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, S::RStride, S::CStride> { + + $me.assert_view_index(start, shape, (0, 0)); + let shape = (Dyn(shape.0), Dyn(shape.1)); + + unsafe { + let data = $ViewStorage::new_unchecked($data, start, shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Slices this matrix starting at its component `(start.0, start.1)` and with + /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is + /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the + /// original matrix. + #[inline] + #[deprecated = slice_deprecation_note!($view_with_steps)] + pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, Dyn, Dyn> { + $me.$view_with_steps(start, shape, steps) + } + + /// Return a view of this matrix starting at its component `(start.0, start.1)` and with + /// `(shape.0, shape.1)` components. Each row (resp. column) of the matrix view is + /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the + /// original matrix. + #[inline] + pub fn $view_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, Dyn, Dyn> { + let shape = (Dyn(shape.0), Dyn(shape.1)); + $me.$generic_view_with_steps(start, shape, steps) + } + + /// Slices this matrix starting at its component `(irow, icol)` and with `(R::dim(), + /// CView::dim())` consecutive components. + #[inline] + #[deprecated = slice_deprecation_note!($fixed_view)] + pub fn $fixed_slice($me: $Me, irow: usize, icol: usize) + -> $MatrixView<'_, T, Const, Const, S::RStride, S::CStride> { + $me.$fixed_view(irow, icol) + } + + /// Return a view of this matrix starting at its component `(irow, icol)` and with `(R::dim(), + /// CView::dim())` consecutive components. + #[inline] + pub fn $fixed_view($me: $Me, irow: usize, icol: usize) + -> $MatrixView<'_, T, Const, Const, S::RStride, S::CStride> { + + $me.assert_view_index((irow, icol), (RVIEW, CVIEW), (0, 0)); + let shape = (Const::, Const::); + + unsafe { + let data = $ViewStorage::new_unchecked($data, (irow, icol), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Slices this matrix starting at its component `(start.0, start.1)` and with + /// `(RVIEW, CVIEW)` components. Each row (resp. column) of the sliced + /// matrix is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of + /// the original matrix. + #[inline] + #[deprecated = slice_deprecation_note!($fixed_view_with_steps)] + pub fn $fixed_slice_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Const, Const, Dyn, Dyn> { + $me.$fixed_view_with_steps(start, steps) + } + + /// Returns a view of this matrix starting at its component `(start.0, start.1)` and with + /// `(RVIEW, CVIEW)` components. Each row (resp. column) of the matrix view + /// is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of + /// the original matrix. + #[inline] + pub fn $fixed_view_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Const, Const, Dyn, Dyn> { + let shape = (Const::, Const::); + $me.$generic_view_with_steps(start, shape, steps) + } + + /// Creates a slice that may or may not have a fixed size and stride. + #[inline] + #[deprecated = slice_deprecation_note!($generic_view)] + pub fn $generic_slice($me: $Me, start: (usize, usize), shape: (RView, CView)) + -> $MatrixView<'_, T, RView, CView, S::RStride, S::CStride> + where RView: Dim, + CView: Dim { + $me.$generic_view(start, shape) + } + + /// Creates a matrix view that may or may not have a fixed size and stride. + #[inline] + pub fn $generic_view($me: $Me, start: (usize, usize), shape: (RView, CView)) + -> $MatrixView<'_, T, RView, CView, S::RStride, S::CStride> + where RView: Dim, + CView: Dim { + + $me.assert_view_index(start, (shape.0.value(), shape.1.value()), (0, 0)); + + unsafe { + let data = $ViewStorage::new_unchecked($data, start, shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Creates a slice that may or may not have a fixed size and stride. + #[inline] + #[deprecated = slice_deprecation_note!($generic_view_with_steps)] + pub fn $generic_slice_with_steps($me: $Me, + start: (usize, usize), + shape: (RView, CView), + steps: (usize, usize)) + -> $MatrixView<'_, T, RView, CView, Dyn, Dyn> + where RView: Dim, + CView: Dim { + $me.$generic_view_with_steps(start, shape, steps) + } + + /// Creates a matrix view that may or may not have a fixed size and stride. + #[inline] + pub fn $generic_view_with_steps($me: $Me, + start: (usize, usize), + shape: (RView, CView), + steps: (usize, usize)) + -> $MatrixView<'_, T, RView, CView, Dyn, Dyn> + where RView: Dim, + CView: Dim { + + $me.assert_view_index(start, (shape.0.value(), shape.1.value()), steps); + + let my_strides = $me.data.strides(); + let strides = (Dyn((steps.0 + 1) * my_strides.0.value()), + Dyn((steps.1 + 1) * my_strides.1.value())); + + unsafe { + let data = $ViewStorage::new_with_strides_unchecked($data, start, shape, strides); + Matrix::from_data_statically_unchecked(data) + } + } + + /* + * + * Splitting. + * + */ + /// Splits this `NxM` matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $rows_range_pair, Range2: DimRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixView<'_, T, Range1::Size, C, S::RStride, S::CStride>, + $MatrixView<'_, T, Range2::Size, C, S::RStride, S::CStride>) { + + let (nrows, ncols) = $me.shape_generic(); + let strides = $me.data.strides(); + + let start1 = r1.begin(nrows); + let start2 = r2.begin(nrows); + + let end1 = r1.end(nrows); + let end2 = r2.end(nrows); + + let nrows1 = r1.size(nrows); + let nrows2 = r2.size(nrows); + + assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the ranges must not overlap."); + assert!(end2 <= nrows.value(), "Rows range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(start1, 0); + let ptr2 = $data.$get_addr(start2, 0); + + let data1 = $ViewStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); + let data2 = $ViewStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); + let view1 = Matrix::from_data_statically_unchecked(data1); + let view2 = Matrix::from_data_statically_unchecked(data2); + + (view1, view2) + } + } + + /// Splits this `NxM` matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $columns_range_pair, Range2: DimRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixView<'_, T, R, Range1::Size, S::RStride, S::CStride>, + $MatrixView<'_, T, R, Range2::Size, S::RStride, S::CStride>) { + + let (nrows, ncols) = $me.shape_generic(); + let strides = $me.data.strides(); + + let start1 = r1.begin(ncols); + let start2 = r2.begin(ncols); + + let end1 = r1.end(ncols); + let end2 = r2.end(ncols); + + let ncols1 = r1.size(ncols); + let ncols2 = r2.size(ncols); + + assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the ranges must not overlap."); + assert!(end2 <= ncols.value(), "Columns range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(0, start1); + let ptr2 = $data.$get_addr(0, start2); + + let data1 = $ViewStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); + let data2 = $ViewStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); + let view1 = Matrix::from_data_statically_unchecked(data1); + let view2 = Matrix::from_data_statically_unchecked(data2); + + (view1, view2) + } + } + } +); + +/// A matrix slice. +/// +/// This type alias exists only for legacy purposes and is deprecated. It will be removed +/// in a future release. Please use [`MatrixView`] instead. +/// See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) +/// for the rationale. +#[deprecated = "Use MatrixView instead."] +pub type MatrixSlice<'a, T, R, C, RStride = U1, CStride = R> = + MatrixView<'a, T, R, C, RStride, CStride>; + +/// A matrix view. +pub type MatrixView<'a, T, R, C, RStride = U1, CStride = R> = + Matrix>; + +/// A mutable matrix slice. +/// +/// This type alias exists only for legacy purposes and is deprecated. It will be removed +/// in a future release. Please use [`MatrixViewMut`] instead. +/// See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) +/// for the rationale. +#[deprecated = "Use MatrixViewMut instead."] +pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> = + MatrixViewMut<'a, T, R, C, RStride, CStride>; + +/// A mutable matrix view. +pub type MatrixViewMut<'a, T, R, C, RStride = U1, CStride = R> = + Matrix>; + +/// # Views based on index and length +impl> Matrix { + matrix_view_impl!( + self: &Self, MatrixView, ViewStorage, RawStorage.get_address_unchecked(), &self.data; + row, + row_part, + rows, + rows_with_step, + fixed_rows, + fixed_rows_with_step, + rows_generic, + rows_generic_with_step, + column, + column_part, + columns, + columns_with_step, + fixed_columns, + fixed_columns_with_step, + columns_generic, + columns_generic_with_step, + slice => view, + slice_with_steps => view_with_steps, + fixed_slice => fixed_view, + fixed_slice_with_steps => fixed_view_with_steps, + generic_slice => generic_view, + generic_slice_with_steps => generic_view_with_steps, + rows_range_pair, + columns_range_pair); +} + +/// # Mutable views based on index and length +impl> Matrix { + matrix_view_impl!( + self: &mut Self, MatrixViewMut, ViewStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data; + row_mut, + row_part_mut, + rows_mut, + rows_with_step_mut, + fixed_rows_mut, + fixed_rows_with_step_mut, + rows_generic_mut, + rows_generic_with_step_mut, + column_mut, + column_part_mut, + columns_mut, + columns_with_step_mut, + fixed_columns_mut, + fixed_columns_with_step_mut, + columns_generic_mut, + columns_generic_with_step_mut, + slice_mut => view_mut, + slice_with_steps_mut => view_with_steps_mut, + fixed_slice_mut => fixed_view_mut, + fixed_slice_with_steps_mut => fixed_view_with_steps_mut, + generic_slice_mut => generic_view_mut, + generic_slice_with_steps_mut => generic_view_with_steps_mut, + rows_range_pair_mut, + columns_range_pair_mut); +} + +/// A range with a size that may be known at compile-time. +/// +/// This may be: +/// * A single `usize` index, e.g., `4` +/// * A left-open range `std::ops::RangeTo`, e.g., `.. 4` +/// * A right-open range `std::ops::RangeFrom`, e.g., `4 ..` +/// * A full range `std::ops::RangeFull`, e.g., `..` +pub trait DimRange { + /// Type of the range size. May be a type-level integer. + type Size: Dim; + + /// The start index of the range. + fn begin(&self, shape: D) -> usize; + // NOTE: this is the index immediately after the last index. + /// The index immediately after the last index inside of the range. + fn end(&self, shape: D) -> usize; + /// The number of elements of the range, i.e., `self.end - self.begin`. + fn size(&self, shape: D) -> Self::Size; +} + +/// A range with a size that may be known at compile-time. +/// +/// This is merely a legacy trait alias to minimize breakage. Use the [`DimRange`] trait instead. +#[deprecated = slice_deprecation_note!(DimRange)] +pub trait SliceRange: DimRange {} + +#[allow(deprecated)] +impl, D: Dim> SliceRange for R {} + +impl DimRange for usize { + type Size = U1; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + *self + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + *self + 1 + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Const::<1> + } +} + +impl DimRange for Range { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + self.end + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dyn(self.end - self.start) + } +} + +impl DimRange for RangeFrom { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn end(&self, dim: D) -> usize { + dim.value() + } + + #[inline(always)] + fn size(&self, dim: D) -> Self::Size { + Dyn(dim.value() - self.start) + } +} + +impl DimRange for RangeTo { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + self.end + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dyn(self.end) + } +} + +impl DimRange for RangeFull { + type Size = D; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn end(&self, dim: D) -> usize { + dim.value() + } + + #[inline(always)] + fn size(&self, dim: D) -> Self::Size { + dim + } +} + +impl DimRange for RangeInclusive { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + *self.start() + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + *self.end() + 1 + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dyn(*self.end() + 1 - *self.start()) + } +} + +// TODO: see how much of this overlaps with the general indexing +// methods from indexing.rs. +impl> Matrix { + /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed + /// by the range `cols`. + #[inline] + #[must_use] + #[deprecated = slice_deprecation_note!(view_range)] + pub fn slice_range( + &self, + rows: RowRange, + cols: ColRange, + ) -> MatrixView<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + let (nrows, ncols) = self.shape_generic(); + self.generic_view( + (rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols)), + ) + } + + /// Returns a view containing the rows indexed by the range `rows` and the columns indexed + /// by the range `cols`. + #[inline] + #[must_use] + pub fn view_range( + &self, + rows: RowRange, + cols: ColRange, + ) -> MatrixView<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + let (nrows, ncols) = self.shape_generic(); + self.generic_view( + (rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols)), + ) + } + + /// View containing all the rows indexed by the range `rows`. + #[inline] + #[must_use] + pub fn rows_range>( + &self, + rows: RowRange, + ) -> MatrixView<'_, T, RowRange::Size, C, S::RStride, S::CStride> { + self.view_range(rows, ..) + } + + /// View containing all the columns indexed by the range `rows`. + #[inline] + #[must_use] + pub fn columns_range>( + &self, + cols: ColRange, + ) -> MatrixView<'_, T, R, ColRange::Size, S::RStride, S::CStride> { + self.view_range(.., cols) + } +} + +// TODO: see how much of this overlaps with the general indexing +// methods from indexing.rs. +impl> Matrix { + /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns + /// indexed by the range `cols`. + #[deprecated = slice_deprecation_note!(view_range_mut)] + pub fn slice_range_mut( + &mut self, + rows: RowRange, + cols: ColRange, + ) -> MatrixViewMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + self.view_range_mut(rows, cols) + } + + /// Return a mutable view containing the rows indexed by the range `rows` and the columns + /// indexed by the range `cols`. + pub fn view_range_mut( + &mut self, + rows: RowRange, + cols: ColRange, + ) -> MatrixViewMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + let (nrows, ncols) = self.shape_generic(); + self.generic_view_mut( + (rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols)), + ) + } + + /// Mutable view containing all the rows indexed by the range `rows`. + #[inline] + pub fn rows_range_mut>( + &mut self, + rows: RowRange, + ) -> MatrixViewMut<'_, T, RowRange::Size, C, S::RStride, S::CStride> { + self.view_range_mut(rows, ..) + } + + /// Mutable view containing all the columns indexed by the range `cols`. + #[inline] + pub fn columns_range_mut>( + &mut self, + cols: ColRange, + ) -> MatrixViewMut<'_, T, R, ColRange::Size, S::RStride, S::CStride> { + self.view_range_mut(.., cols) + } +} + +impl<'a, T, R, C, RStride, CStride> From> + for MatrixView<'a, T, R, C, RStride, CStride> +where + R: Dim, + C: Dim, + RStride: Dim, + CStride: Dim, +{ + fn from(view_mut: MatrixViewMut<'a, T, R, C, RStride, CStride>) -> Self { + let data = ViewStorage { + ptr: view_mut.data.ptr, + shape: view_mut.data.shape, + strides: view_mut.data.strides, + _phantoms: PhantomData, + }; + + unsafe { Matrix::from_data_statically_unchecked(data) } + } +} + +impl Matrix +where + R: Dim, + C: Dim, + S: RawStorage, +{ + /// Returns this matrix as a view. + /// + /// The returned view type is generally ambiguous unless specified. + /// This is particularly useful when working with functions or methods that take + /// matrix views as input. + /// + /// # Panics + /// Panics if the dimensions of the view and the matrix are not compatible and this cannot + /// be proven at compile-time. This might happen, for example, when constructing a static + /// view of size 3x3 from a dynamically sized matrix of dimension 5x5. + /// + /// # Examples + /// ``` + /// use nalgebra::{DMatrixSlice, SMatrixView}; + /// + /// fn consume_view(_: DMatrixSlice) {} + /// + /// let matrix = nalgebra::Matrix3::zeros(); + /// consume_view(matrix.as_view()); + /// + /// let dynamic_view: DMatrixSlice = matrix.as_view(); + /// let static_view_from_dyn: SMatrixView = dynamic_view.as_view(); + /// ``` + pub fn as_view( + &self, + ) -> MatrixView<'_, T, RView, CView, RViewStride, CViewStride> + where + RView: Dim, + CView: Dim, + RViewStride: Dim, + CViewStride: Dim, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, + { + // Defer to (&matrix).into() + self.into() + } +} + +impl Matrix +where + R: Dim, + C: Dim, + S: RawStorageMut, +{ + /// Returns this matrix as a mutable view. + /// + /// The returned view type is generally ambiguous unless specified. + /// This is particularly useful when working with functions or methods that take + /// matrix views as input. + /// + /// # Panics + /// Panics if the dimensions of the view and the matrix are not compatible and this cannot + /// be proven at compile-time. This might happen, for example, when constructing a static + /// view of size 3x3 from a dynamically sized matrix of dimension 5x5. + /// + /// # Examples + /// ``` + /// use nalgebra::{DMatrixViewMut, SMatrixViewMut}; + /// + /// fn consume_view(_: DMatrixViewMut) {} + /// + /// let mut matrix = nalgebra::Matrix3::zeros(); + /// consume_view(matrix.as_view_mut()); + /// + /// let mut dynamic_view: DMatrixViewMut = matrix.as_view_mut(); + /// let static_view_from_dyn: SMatrixViewMut = dynamic_view.as_view_mut(); + /// ``` + pub fn as_view_mut( + &mut self, + ) -> MatrixViewMut<'_, T, RView, CView, RViewStride, CViewStride> + where + RView: Dim, + CView: Dim, + RViewStride: Dim, + CViewStride: Dim, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, + { + // Defer to (&mut matrix).into() + self.into() + } +} + +// TODO: Arbitrary strides? +impl<'a, T, R1, C1, R2, C2> ReshapableStorage + for ViewStorage<'a, T, R1, C1, U1, R1> +where + T: Scalar, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, +{ + type Output = ViewStorage<'a, T, R2, C2, U1, R2>; + + fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output { + let (r1, c1) = self.shape(); + assert_eq!(nrows.value() * ncols.value(), r1.value() * c1.value()); + let ptr = self.ptr(); + let new_shape = (nrows, ncols); + let strides = (U1::name(), nrows); + unsafe { ViewStorage::from_raw_parts(ptr, new_shape, strides) } + } +} + +// TODO: Arbitrary strides? +impl<'a, T, R1, C1, R2, C2> ReshapableStorage + for ViewStorageMut<'a, T, R1, C1, U1, R1> +where + T: Scalar, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, +{ + type Output = ViewStorageMut<'a, T, R2, C2, U1, R2>; + + fn reshape_generic(mut self, nrows: R2, ncols: C2) -> Self::Output { + let (r1, c1) = self.shape(); + assert_eq!(nrows.value() * ncols.value(), r1.value() * c1.value()); + let ptr = self.ptr_mut(); + let new_shape = (nrows, ncols); + let strides = (U1::name(), nrows); + unsafe { ViewStorageMut::from_raw_parts(ptr, new_shape, strides) } + } +} diff --git a/src/base/mod.rs b/src/base/mod.rs index c6279ba3..0f09cc33 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -12,18 +12,19 @@ pub mod storage; mod alias; mod alias_slice; +mod alias_view; mod array_storage; mod cg; mod componentwise; #[macro_use] mod construction; -mod construction_slice; +mod construction_view; mod conversion; mod edition; pub mod indexing; mod matrix; mod matrix_simba; -mod matrix_slice; +mod matrix_view; mod norm; mod properties; mod scalar; @@ -41,6 +42,12 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; +#[cfg(feature = "rayon")] +pub mod par_iter; + +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_wrappers; + pub use self::matrix::*; pub use self::norm::*; pub use self::scalar::*; @@ -51,8 +58,9 @@ pub use self::dimension::*; pub use self::alias::*; pub use self::alias_slice::*; +pub use self::alias_view::*; pub use self::array_storage::*; -pub use self::matrix_slice::*; +pub use self::matrix_view::*; pub use self::storage::*; #[cfg(any(feature = "std", feature = "alloc"))] pub use self::vec_storage::*; diff --git a/src/base/norm.rs b/src/base/norm.rs index 11f5661f..e9010273 100644 --- a/src/base/norm.rs +++ b/src/base/norm.rs @@ -336,7 +336,7 @@ impl> Matrix { /// Sets the magnitude of this vector unless it is smaller than `min_magnitude`. /// /// If `self.magnitude()` is smaller than `min_magnitude`, it will be left unchanged. - /// Otherwise this is equivalent to: `*self = self.normalize() * magnitude. + /// Otherwise this is equivalent to: `*self = self.normalize() * magnitude`. #[inline] pub fn try_set_magnitude(&mut self, magnitude: T::RealField, min_magnitude: T::RealField) where @@ -525,7 +525,7 @@ where let (elt, basis) = vs[..i + 1].split_last_mut().unwrap(); for basis_element in &basis[..nbasis_elements] { - *elt -= &*basis_element * elt.dot(basis_element) + *elt -= basis_element * elt.dot(basis_element) } } diff --git a/src/base/ops.rs b/src/base/ops.rs index 6b6d0c45..d5cf3a51 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -11,10 +11,10 @@ use crate::base::blas_uninit::gemm_uninit; use crate::base::constraint::{ AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, }; -use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic}; +use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dyn}; use crate::base::storage::{Storage, StorageMut}; use crate::base::uninit::Uninit; -use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorSlice}; +use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorView}; use crate::storage::IsContiguous; use crate::uninit::{Init, InitStatus}; use crate::{RawStorage, RawStorageMut, SimdComplexField}; @@ -374,10 +374,10 @@ where } } -impl iter::Sum for OMatrix +impl iter::Sum for OMatrix where T: Scalar + ClosedAdd + Zero, - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { /// # Example /// ``` @@ -395,7 +395,7 @@ where /// # use nalgebra::DMatrix; /// iter::empty::>().sum::>(); // panics! /// ``` - fn sum>>(mut iter: I) -> OMatrix { + fn sum>>(mut iter: I) -> OMatrix { if let Some(first) = iter.next() { iter.fold(first, |acc, x| acc + x) } else { @@ -414,10 +414,10 @@ where } } -impl<'a, T, C: Dim> iter::Sum<&'a OMatrix> for OMatrix +impl<'a, T, C: Dim> iter::Sum<&'a OMatrix> for OMatrix where T: Scalar + ClosedAdd + Zero, - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { /// # Example /// ``` @@ -435,7 +435,7 @@ where /// # use nalgebra::DMatrix; /// iter::empty::<&DMatrix>().sum::>(); // panics! /// ``` - fn sum>>(mut iter: I) -> OMatrix { + fn sum>>(mut iter: I) -> OMatrix { if let Some(first) = iter.next() { iter.fold(first.clone(), |acc, x| acc + x) } else { @@ -703,8 +703,8 @@ where rhs: &Matrix, out: &mut Matrix, dot: impl Fn( - &VectorSlice<'_, T, R1, SA::RStride, SA::CStride>, - &VectorSlice<'_, T, R2, SB::RStride, SB::CStride>, + &VectorView<'_, T, R1, SA::RStride, SA::CStride>, + &VectorView<'_, T, R2, SB::RStride, SB::CStride>, ) -> T, ) where Status: InitStatus, diff --git a/src/base/par_iter.rs b/src/base/par_iter.rs new file mode 100644 index 00000000..c4af719a --- /dev/null +++ b/src/base/par_iter.rs @@ -0,0 +1,285 @@ +//! Parallel iterators for matrices compatible with rayon. + +// only enables the `doc_cfg` feature when +// the `docsrs` configuration attribute is defined +#![cfg_attr(docsrs, feature(doc_cfg))] + +use crate::{ + iter::{ColumnIter, ColumnIterMut}, + Dim, Matrix, MatrixView, MatrixViewMut, RawStorage, RawStorageMut, Scalar, U1, +}; +use rayon::iter::plumbing::Producer; +use rayon::{iter::plumbing::bridge, prelude::*}; + +/// A rayon parallel iterator over the columns of a matrix. It is created +/// using the [`par_column_iter`] method of [`Matrix`]. +/// +/// *Only available if compiled with the feature `rayon`.* +/// [`par_column_iter`]: crate::Matrix::par_column_iter +/// [`Matrix`]: crate::Matrix +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { + mat: &'a Matrix, +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R, Cols, S> { + /// Create a new parallel iterator for the given matrix. + fn new(matrix: &'a Matrix) -> Self { + Self { mat: matrix } + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator + for ParColumnIter<'a, T, R, Cols, S> +where + T: Sync + Send + Scalar, + S: Sync, +{ + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; + + fn drive_unindexed(self, consumer: Consumer) -> Consumer::Result + where + Consumer: rayon::iter::plumbing::UnindexedConsumer, + { + bridge(self, consumer) + } + + fn opt_len(&self) -> Option { + Some(self.mat.ncols()) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`.* +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator + for ParColumnIter<'a, T, R, Cols, S> +where + T: Send + Sync + Scalar, + S: Sync, +{ + fn len(&self) -> usize { + self.mat.ncols() + } + + fn drive>(self, consumer: C) -> C::Result { + bridge(self, consumer) + } + + fn with_producer>( + self, + callback: CB, + ) -> CB::Output { + let producer = ColumnProducer(ColumnIter::new(self.mat)); + callback.callback(producer) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// A rayon parallel iterator through the mutable columns of a matrix. +/// *Only available if compiled with the feature `rayon`.* +pub struct ParColumnIterMut< + 'a, + T, + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, +> { + mat: &'a mut Matrix, +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *only available if compiled with the feature `rayon`* +impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, +{ + /// create a new parallel iterator for the given matrix. + fn new(mat: &'a mut Matrix) -> Self { + Self { mat } + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`* +impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, + T: Send + Sync + Scalar, + S: Send + Sync, +{ + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: rayon::iter::plumbing::UnindexedConsumer, + { + bridge(self, consumer) + } + + fn opt_len(&self) -> Option { + Some(self.mat.ncols()) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`* +impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, + T: Send + Sync + Scalar, + S: Send + Sync, +{ + fn drive>(self, consumer: C) -> C::Result { + bridge(self, consumer) + } + + fn len(&self) -> usize { + self.mat.ncols() + } + + fn with_producer>( + self, + callback: CB, + ) -> CB::Output { + let producer = ColumnProducerMut(ColumnIterMut::new(self.mat)); + callback.callback(producer) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// # Parallel iterators using `rayon` +/// *Only available if compiled with the feature `rayon`* +impl> Matrix +where + T: Send + Sync + Scalar, + S: Sync, +{ + /// Iterate through the columns of the matrix in parallel using rayon. + /// This iterates over *immutable* references to the columns of the matrix, + /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] + /// instead. + /// + /// # Example + /// Using parallel column iterators to calculate the sum of the maximum + /// elements in each column: + /// ``` + /// use nalgebra::{dmatrix, DMatrix}; + /// use rayon::prelude::*; + /// + /// let matrix : DMatrix = dmatrix![1.0, 0.0, 5.0; + /// 2.0, 4.0, 1.0; + /// 3.0, 2.0, 2.0; + /// ]; + /// let sum_of_max :f64 = matrix + /// .par_column_iter() + /// .map(|col| col.max()) + /// .sum(); + /// + /// assert_eq!(sum_of_max,3.0 + 4.0 + 5.0); + /// + /// ``` + /// + /// [`par_column_iter_mut`]: crate::Matrix::par_column_iter_mut + pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { + ParColumnIter::new(self) + } + + /// Mutably iterate through the columns of this matrix in parallel using rayon. + /// Allows mutable access to the columns in parallel using mutable references. + /// If mutable access to the columns is not required rather use [`par_column_iter`] + /// instead. + /// + /// # Example + /// Normalize each column of a matrix with respect to its own maximum value. + /// + /// ``` + /// use nalgebra::{dmatrix, DMatrix}; + /// use rayon::prelude::*; + /// + /// let mut matrix : DMatrix = dmatrix![ + /// 2.0, 4.0, 6.0; + /// 1.0, 2.0, 3.0; + /// ]; + /// matrix.par_column_iter_mut().for_each(|mut col| col /= col.max()); + /// + /// assert_eq!(matrix, dmatrix![1.0, 1.0, 1.0; 0.5, 0.5, 0.5]); + /// ``` + /// + /// [`par_column_iter`]: crate::Matrix::par_column_iter + pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> + where + S: RawStorageMut, + { + ParColumnIterMut::new(self) + } +} + +/// A private helper newtype that wraps the `ColumnIter` and implements +/// the rayon `Producer` trait. It's just here so we don't have to make the +/// rayon trait part of the public interface of the `ColumnIter`. +struct ColumnProducer<'a, T, R: Dim, C: Dim, S: RawStorage>(ColumnIter<'a, T, R, C, S>); + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *only available if compiled with the feature `rayon`* +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer + for ColumnProducer<'a, T, R, Cols, S> +where + T: Send + Sync + Scalar, + S: Sync, +{ + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIter<'a, T, R, Cols, S>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0 + } + + #[inline] + fn split_at(self, index: usize) -> (Self, Self) { + // The index is relative to the size of this current iterator. + // It will always start at zero so it serves as an offset. + let (left_iter, right_iter) = self.0.split_at(index); + (Self(left_iter), Self(right_iter)) + } +} + +/// See `ColumnProducer`. A private wrapper newtype that keeps the Producer +/// implementation private +struct ColumnProducerMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>( + ColumnIterMut<'a, T, R, C, S>, +); + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer + for ColumnProducerMut<'a, T, R, C, S> +where + T: Send + Sync + Scalar, + S: Send + Sync, +{ + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIterMut<'a, T, R, C, S>; + + fn into_iter(self) -> Self::IntoIter { + self.0 + } + + fn split_at(self, index: usize) -> (Self, Self) { + // The index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset. + let (left_iter, right_iter) = self.0.split_at(index); + (Self(left_iter), Self(right_iter)) + } +} + +/// this implementation is safe because we are enforcing exclusive access +/// to the columns through the active range of the iterator +unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send + for ColumnIterMut<'a, T, R, C, S> +{ +} diff --git a/src/base/rkyv_wrappers.rs b/src/base/rkyv_wrappers.rs new file mode 100644 index 00000000..f50ae73e --- /dev/null +++ b/src/base/rkyv_wrappers.rs @@ -0,0 +1,46 @@ +//! Wrapper that allows changing the generic type of a PhantomData +//! +//! Copied from (MIT-Apache2 licences) which isn’t published yet. + +use rkyv::{ + with::{ArchiveWith, DeserializeWith, SerializeWith}, + Fallible, +}; +use std::marker::PhantomData; + +/// A wrapper that allows for changing the generic type of a `PhantomData`. +pub struct CustomPhantom { + _data: PhantomData<*const NT>, +} + +impl ArchiveWith> for CustomPhantom { + type Archived = PhantomData; + type Resolver = (); + + #[inline] + unsafe fn resolve_with( + _: &PhantomData, + _: usize, + _: Self::Resolver, + _: *mut Self::Archived, + ) { + } +} + +impl SerializeWith, S> + for CustomPhantom +{ + #[inline] + fn serialize_with(_: &PhantomData, _: &mut S) -> Result { + Ok(()) + } +} + +impl + DeserializeWith, PhantomData, D> for CustomPhantom +{ + #[inline] + fn deserialize_with(_: &PhantomData, _: &mut D) -> Result, D::Error> { + Ok(PhantomData) + } +} diff --git a/src/base/statistics.rs b/src/base/statistics.rs index 320cd12f..5bb05fd0 100644 --- a/src/base/statistics.rs +++ b/src/base/statistics.rs @@ -1,6 +1,6 @@ use crate::allocator::Allocator; use crate::storage::RawStorage; -use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1}; +use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorView, U1}; use num::{One, Zero}; use simba::scalar::{ClosedAdd, ClosedMul, Field, SupersetOf}; use std::mem::MaybeUninit; @@ -13,7 +13,7 @@ impl> Matrix { #[must_use] pub fn compress_rows( &self, - f: impl Fn(VectorSlice<'_, T, R, S::RStride, S::CStride>) -> T, + f: impl Fn(VectorView<'_, T, R, S::RStride, S::CStride>) -> T, ) -> RowOVector where DefaultAllocator: Allocator, @@ -41,7 +41,7 @@ impl> Matrix { #[must_use] pub fn compress_rows_tr( &self, - f: impl Fn(VectorSlice<'_, T, R, S::RStride, S::CStride>) -> T, + f: impl Fn(VectorView<'_, T, R, S::RStride, S::CStride>) -> T, ) -> OVector where DefaultAllocator: Allocator, @@ -67,7 +67,7 @@ impl> Matrix { pub fn compress_columns( &self, init: OVector, - f: impl Fn(&mut OVector, VectorSlice<'_, T, R, S::RStride, S::CStride>), + f: impl Fn(&mut OVector, VectorView<'_, T, R, S::RStride, S::CStride>), ) -> OVector where DefaultAllocator: Allocator, @@ -335,12 +335,12 @@ impl> Matrix { if self.is_empty() { T::zero() } else { - let val = self.iter().cloned().fold((T::zero(), T::zero()), |a, b| { - (a.0 + b.clone() * b.clone(), a.1 + b) - }); - let denom = T::one() / crate::convert::<_, T>(self.len() as f64); - let vd = val.1 * denom.clone(); - val.0 * denom - vd.clone() * vd + let n_elements: T = crate::convert(self.len() as f64); + let mean = self.mean(); + + self.iter().cloned().fold(T::zero(), |acc, x| { + acc + (x.clone() - mean.clone()) * (x - mean.clone()) + }) / n_elements } } diff --git a/src/base/storage.rs b/src/base/storage.rs index 76a60ce3..b39d0f3d 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -32,6 +32,8 @@ pub type CStride = /// The trait shared by all matrix data storage. /// /// TODO: doc +/// # Safety +/// /// In generic code, it is recommended use the `Storage` trait bound instead. The `RawStorage` /// trait bound is generally used by code that needs to work with storages that contains /// `MaybeUninit` elements. @@ -122,13 +124,21 @@ pub unsafe trait RawStorage: Sized { /// # Safety /// The matrix components may not be stored in a contiguous way, depending on the strides. /// This method is unsafe because this can yield to invalid aliasing when called on some pairs - /// of matrix slices originating from the same matrix with strides. + /// of matrix views originating from the same matrix with strides. /// /// Call the safe alternative `matrix.as_slice()` instead. unsafe fn as_slice_unchecked(&self) -> &[T]; } /// Trait shared by all matrix data storage that don’t contain any uninitialized elements. +/// +/// # Safety +/// +/// Note that `Self` must always have a number of elements compatible with the matrix length (given +/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait +/// should **not** allow the user to modify the size of the underlying buffer with safe methods +/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the +/// vector's size so that it no longer contains enough elements: this will lead to UB. pub unsafe trait Storage: RawStorage { /// Builds a matrix data storage that does not contain any reference. fn into_owned(self) -> Owned @@ -143,12 +153,14 @@ pub unsafe trait Storage: RawStorage { /// Trait implemented by matrix data storage that can provide a mutable access to its elements. /// +/// # Safety +/// /// In generic code, it is recommended use the `StorageMut` trait bound instead. The /// `RawStorageMut` trait bound is generally used by code that needs to work with storages that /// contains `MaybeUninit` elements. /// /// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable -/// matrix slice can provide mutable access to its elements even if it does not own its data (it +/// matrix view can provide mutable access to its elements even if it does not own its data (it /// contains only an internal reference to them). pub unsafe trait RawStorageMut: RawStorage { /// The matrix mutable data pointer. @@ -194,10 +206,28 @@ pub unsafe trait RawStorageMut: RawStorage { /// /// # Safety /// If the indices are out of bounds, the method will cause undefined behavior. + /// + /// # Validity + /// The default implementation of this trait function is only guaranteed to be + /// sound if invocations of `self.ptr_mut()` and `self.get_address_unchecked_linear_mut()` + /// result in stable references. If any of the data pointed to by these trait methods + /// moves as a consequence of invoking either of these methods then this default + /// trait implementation may be invalid or unsound and should be overridden. #[inline] unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) { - let a = self.get_address_unchecked_linear_mut(i1); - let b = self.get_address_unchecked_linear_mut(i2); + // we can't just use the pointers returned from `get_address_unchecked_linear_mut` because calling a + // method taking self mutably invalidates any existing (mutable) pointers. since `get_address_unchecked_linear_mut` can + // also be overriden by a custom implementation, we can't just use `wrapping_add` assuming that's what the method does. + // instead, we use `offset_from` to compute the re-calculate the pointers from the base pointer. + // this is sound as long as this trait matches the Validity preconditions + // (and it's the caller's responsibility to ensure the indices are in-bounds). + let base = self.ptr_mut(); + let offset1 = self.get_address_unchecked_linear_mut(i1).offset_from(base); + let offset2 = self.get_address_unchecked_linear_mut(i2).offset_from(base); + + let base = self.ptr_mut(); + let a = base.offset(offset1); + let b = base.offset(offset2); ptr::swap(a, b); } @@ -226,6 +256,10 @@ pub unsafe trait RawStorageMut: RawStorage { } /// Trait shared by all mutable matrix data storage that don’t contain any uninitialized elements. +/// +/// # Safety +/// +/// See safety note for `Storage`, `RawStorageMut`. pub unsafe trait StorageMut: Storage + RawStorageMut { @@ -241,6 +275,8 @@ where /// Marker trait indicating that a storage is stored contiguously in memory. /// +/// # Safety +/// /// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value /// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because /// failing to comply to this may cause Undefined Behaviors. diff --git a/src/base/uninit.rs b/src/base/uninit.rs index ad2759eb..401e3336 100644 --- a/src/base/uninit.rs +++ b/src/base/uninit.rs @@ -34,7 +34,7 @@ pub unsafe trait InitStatus: Copy { /// A type implementing `InitStatus` indicating that the value is completely initialized. pub struct Init; #[derive(Copy, Clone, Debug, PartialEq, Eq)] -/// A type implementing `InitStatus` indicating that the value is completely unitialized. +/// A type implementing `InitStatus` indicating that the value is completely uninitialized. pub struct Uninit; unsafe impl InitStatus for Init { diff --git a/src/base/unit.rs b/src/base/unit.rs index bb8b56a1..b8e62b8c 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -9,6 +9,9 @@ use crate::base::DefaultAllocator; use crate::storage::RawStorage; use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A wrapper that ensures the underlying algebraic entity has a unit norm. /// /// **It is likely that the only piece of documentation that you need in this page are:** @@ -21,7 +24,17 @@ use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealF /// in their documentation, read their dedicated pages directly. #[repr(transparent)] #[derive(Clone, Hash, Copy)] -// #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Unit", + bound(archive = " + T: rkyv::Archive, + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] pub struct Unit { pub(crate) value: T, } @@ -58,57 +71,6 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Unit { } } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Unit; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Unit { - type Archived = Unit; - type Resolver = T::Resolver; - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut ::core::mem::MaybeUninit, - ) { - self.value.resolve( - pos + offset_of!(Self::Archived, value), - resolver, - project_struct!(out: Self::Archived => value), - ); - } - } - - impl, S: Fallible + ?Sized> Serialize for Unit { - fn serialize(&self, serializer: &mut S) -> Result { - self.value.serialize(serializer) - } - } - - impl Deserialize, D> for Unit - where - T::Archived: Deserialize, - { - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Unit { - value: self.value.deserialize(deserializer)?, - }) - } - } -} - -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for Unit> -where - T: Scalar, - R: Dim, - C: Dim, - S: RawStorage + Copy, -{ -} - impl PartialEq for Unit> where T: Scalar + PartialEq, diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index 414354cd..5b29b6a3 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -4,7 +4,7 @@ use alloc::vec::Vec; use crate::base::allocator::Allocator; use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::base::default_allocator::DefaultAllocator; -use crate::base::dimension::{Dim, DimName, Dynamic, U1}; +use crate::base::dimension::{Dim, DimName, Dyn, U1}; use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage}; use crate::base::{Scalar, Vector}; @@ -31,6 +31,46 @@ pub struct VecStorage { ncols: C, } +impl Default for VecStorage { + fn default() -> Self { + Self { + data: Vec::new(), + nrows: Dyn::from_usize(0), + ncols: Dyn::from_usize(0), + } + } +} + +impl Default for VecStorage { + fn default() -> Self { + Self { + data: Vec::new(), + nrows: R::name(), + ncols: Dyn::from_usize(0), + } + } +} + +impl Default for VecStorage { + fn default() -> Self { + Self { + data: Vec::new(), + nrows: Dyn::from_usize(0), + ncols: C::name(), + } + } +} + +impl Default for VecStorage { + fn default() -> Self { + let nrows = R::name(); + let ncols = C::name(); + let mut data = Vec::new(); + data.resize_with(nrows.value() * ncols.value(), Default::default); + Self { data, nrows, ncols } + } +} + #[cfg(feature = "serde-serialize")] impl Serialize for VecStorage where @@ -148,7 +188,7 @@ impl VecStorage { }; // Avoid double-free by forgetting `self` because its data buffer has - // been transfered to `new_data`. + // been transferred to `new_data`. std::mem::forget(self); new_data } @@ -188,13 +228,13 @@ impl From> for Vec { /* * - * Dynamic − Static - * Dynamic − Dynamic + * Dyn − Static + * Dyn − Dyn * */ -unsafe impl RawStorage for VecStorage { +unsafe impl RawStorage for VecStorage { type RStride = U1; - type CStride = Dynamic; + type CStride = Dyn; #[inline] fn ptr(&self) -> *const T { @@ -202,7 +242,7 @@ unsafe impl RawStorage for VecStorage { } #[inline] - fn shape(&self) -> (Dynamic, C) { + fn shape(&self) -> (Dyn, C) { (self.nrows, self.ncols) } @@ -222,28 +262,28 @@ unsafe impl RawStorage for VecStorage { } } -unsafe impl Storage for VecStorage +unsafe impl Storage for VecStorage where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { #[inline] - fn into_owned(self) -> Owned + fn into_owned(self) -> Owned where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { self } #[inline] - fn clone_owned(&self) -> Owned + fn clone_owned(&self) -> Owned where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { self.clone() } } -unsafe impl RawStorage for VecStorage { +unsafe impl RawStorage for VecStorage { type RStride = U1; type CStride = R; @@ -253,7 +293,7 @@ unsafe impl RawStorage for VecStorage (R, Dynamic) { + fn shape(&self) -> (R, Dyn) { (self.nrows, self.ncols) } @@ -273,22 +313,22 @@ unsafe impl RawStorage for VecStorage Storage for VecStorage +unsafe impl Storage for VecStorage where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { #[inline] - fn into_owned(self) -> Owned + fn into_owned(self) -> Owned where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { self } #[inline] - fn clone_owned(&self) -> Owned + fn clone_owned(&self) -> Owned where - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { self.clone() } @@ -299,7 +339,7 @@ where * RawStorageMut, ContiguousStorage. * */ -unsafe impl RawStorageMut for VecStorage { +unsafe impl RawStorageMut for VecStorage { #[inline] fn ptr_mut(&mut self) -> *mut T { self.data.as_mut_ptr() @@ -313,15 +353,15 @@ unsafe impl RawStorageMut for VecStorage IsContiguous for VecStorage {} -impl ReshapableStorage for VecStorage +impl ReshapableStorage for VecStorage where T: Scalar, C1: Dim, C2: Dim, { - type Output = VecStorage; + type Output = VecStorage; - fn reshape_generic(self, nrows: Dynamic, ncols: C2) -> Self::Output { + fn reshape_generic(self, nrows: Dyn, ncols: C2) -> Self::Output { assert_eq!(nrows.value() * ncols.value(), self.data.len()); VecStorage { data: self.data, @@ -331,15 +371,15 @@ where } } -impl ReshapableStorage for VecStorage +impl ReshapableStorage for VecStorage where T: Scalar, C1: Dim, R2: DimName, { - type Output = VecStorage; + type Output = VecStorage; - fn reshape_generic(self, nrows: R2, ncols: Dynamic) -> Self::Output { + fn reshape_generic(self, nrows: R2, ncols: Dyn) -> Self::Output { assert_eq!(nrows.value() * ncols.value(), self.data.len()); VecStorage { data: self.data, @@ -349,7 +389,7 @@ where } } -unsafe impl RawStorageMut for VecStorage { +unsafe impl RawStorageMut for VecStorage { #[inline] fn ptr_mut(&mut self) -> *mut T { self.data.as_mut_ptr() @@ -361,15 +401,15 @@ unsafe impl RawStorageMut for VecStorage ReshapableStorage for VecStorage +impl ReshapableStorage for VecStorage where T: Scalar, R1: DimName, C2: Dim, { - type Output = VecStorage; + type Output = VecStorage; - fn reshape_generic(self, nrows: Dynamic, ncols: C2) -> Self::Output { + fn reshape_generic(self, nrows: Dyn, ncols: C2) -> Self::Output { assert_eq!(nrows.value() * ncols.value(), self.data.len()); VecStorage { data: self.data, @@ -379,15 +419,15 @@ where } } -impl ReshapableStorage for VecStorage +impl ReshapableStorage for VecStorage where T: Scalar, R1: DimName, R2: DimName, { - type Output = VecStorage; + type Output = VecStorage; - fn reshape_generic(self, nrows: R2, ncols: Dynamic) -> Self::Output { + fn reshape_generic(self, nrows: R2, ncols: Dyn) -> Self::Output { assert_eq!(nrows.value() * ncols.value(), self.data.len()); VecStorage { data: self.data, @@ -397,7 +437,7 @@ where } } -impl Extend for VecStorage { +impl Extend for VecStorage { /// Extends the number of columns of the `VecStorage` with elements /// from the given iterator. /// @@ -407,13 +447,13 @@ impl Extend for VecStorage { /// `VecStorage`. fn extend>(&mut self, iter: I) { self.data.extend(iter); - self.ncols = Dynamic::new(self.data.len() / self.nrows.value()); + self.ncols = Dyn(self.data.len() / self.nrows.value()); assert!(self.data.len() % self.nrows.value() == 0, "The number of elements produced by the given iterator was not a multiple of the number of rows."); } } -impl<'a, T: 'a + Copy, R: Dim> Extend<&'a T> for VecStorage { +impl<'a, T: 'a + Copy, R: Dim> Extend<&'a T> for VecStorage { /// Extends the number of columns of the `VecStorage` with elements /// from the given iterator. /// @@ -426,7 +466,7 @@ impl<'a, T: 'a + Copy, R: Dim> Extend<&'a T> for VecStorage { } } -impl Extend> for VecStorage +impl Extend> for VecStorage where T: Scalar, R: Dim, @@ -450,15 +490,15 @@ where assert_eq!(nrows, vector.shape().0); self.data.extend(vector.iter().cloned()); } - self.ncols = Dynamic::new(self.data.len() / nrows); + self.ncols = Dyn(self.data.len() / nrows); } } -impl Extend for VecStorage { +impl Extend for VecStorage { /// Extends the number of rows of the `VecStorage` with elements /// from the given iterator. fn extend>(&mut self, iter: I) { self.data.extend(iter); - self.nrows = Dynamic::new(self.data.len()); + self.nrows = Dyn(self.data.len()); } } diff --git a/src/debug/random_orthogonal.rs b/src/debug/random_orthogonal.rs index c9684238..18924fb2 100644 --- a/src/debug/random_orthogonal.rs +++ b/src/debug/random_orthogonal.rs @@ -4,7 +4,7 @@ use crate::base::storage::Owned; use quickcheck::{Arbitrary, Gen}; use crate::base::allocator::Allocator; -use crate::base::dimension::{Dim, Dynamic}; +use crate::base::dimension::{Dim, Dyn}; use crate::base::Scalar; use crate::base::{DefaultAllocator, OMatrix}; use crate::linalg::givens::GivensRotation; @@ -12,7 +12,7 @@ use simba::scalar::ComplexField; /// A random orthogonal matrix. #[derive(Clone, Debug)] -pub struct RandomOrthogonal +pub struct RandomOrthogonal where DefaultAllocator: Allocator, { diff --git a/src/debug/random_sdp.rs b/src/debug/random_sdp.rs index a915f2fc..278071a8 100644 --- a/src/debug/random_sdp.rs +++ b/src/debug/random_sdp.rs @@ -4,7 +4,7 @@ use crate::base::storage::Owned; use quickcheck::{Arbitrary, Gen}; use crate::base::allocator::Allocator; -use crate::base::dimension::{Dim, Dynamic}; +use crate::base::dimension::{Dim, Dyn}; use crate::base::Scalar; use crate::base::{DefaultAllocator, OMatrix}; use simba::scalar::ComplexField; @@ -13,7 +13,7 @@ use crate::debug::RandomOrthogonal; /// A random, well-conditioned, symmetric definite-positive matrix. #[derive(Clone, Debug)] -pub struct RandomSDP +pub struct RandomSDP where DefaultAllocator: Allocator, { diff --git a/src/geometry/dual_quaternion.rs b/src/geometry/dual_quaternion.rs index 719ae13d..8bd0cc81 100644 --- a/src/geometry/dual_quaternion.rs +++ b/src/geometry/dual_quaternion.rs @@ -1,6 +1,9 @@ // The macros break if the references are taken out, for some reason. #![allow(clippy::op_ref)] +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + use crate::{ Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3, Unit, UnitQuaternion, Vector3, Zero, U8, @@ -40,7 +43,18 @@ use simba::scalar::{ClosedNeg, RealField}; /// See #[repr(C)] #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "DualQuaternion", + bound(archive = " + T: rkyv::Archive, + Quaternion: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] pub struct DualQuaternion { /// The real component of the quaternion pub real: Quaternion, @@ -82,7 +96,7 @@ where /// /// let dq_normalized = dq.normalize(); /// - /// relative_eq!(dq_normalized.real.norm(), 1.0); + /// assert_relative_eq!(dq_normalized.real.norm(), 1.0); /// ``` #[inline] #[must_use = "Did you mean to use normalize_mut()?"] @@ -107,7 +121,7 @@ where /// /// dq.normalize_mut(); /// - /// relative_eq!(dq.real.norm(), 1.0); + /// assert_relative_eq!(dq.real.norm(), 1.0); /// ``` #[inline] pub fn normalize_mut(&mut self) -> T { @@ -305,7 +319,8 @@ where } impl DualQuaternion { - fn to_vector(self) -> OVector { + #[allow(clippy::wrong_self_convention)] + fn to_vector(&self) -> OVector { self.as_ref().clone().into() } } @@ -320,9 +335,9 @@ impl> AbsDiffEq for DualQuaternion { #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - self.clone().to_vector().abs_diff_eq(&other.clone().to_vector(), epsilon.clone()) || + self.to_vector().abs_diff_eq(&other.to_vector(), epsilon.clone()) || // Account for the double-covering of S², i.e. q = -q - self.clone().to_vector().iter().zip(other.clone().to_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-b.clone(), epsilon.clone())) + self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-b.clone(), epsilon.clone())) } } @@ -339,9 +354,9 @@ impl> RelativeEq for DualQuaternion { epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - self.clone().to_vector().relative_eq(&other.clone().to_vector(), epsilon.clone(), max_relative.clone()) || + self.to_vector().relative_eq(&other.to_vector(), epsilon.clone(), max_relative.clone()) || // Account for the double-covering of S², i.e. q = -q - self.clone().to_vector().iter().zip(other.clone().to_vector().iter()).all(|(a, b)| a.relative_eq(&-b.clone(), epsilon.clone(), max_relative.clone())) + self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.relative_eq(&-b.clone(), epsilon.clone(), max_relative.clone())) } } @@ -353,9 +368,9 @@ impl> UlpsEq for DualQuaternion { #[inline] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { - self.clone().to_vector().ulps_eq(&other.clone().to_vector(), epsilon.clone(), max_ulps) || + self.to_vector().ulps_eq(&other.to_vector(), epsilon.clone(), max_ulps) || // Account for the double-covering of S², i.e. q = -q. - self.clone().to_vector().iter().zip(other.clone().to_vector().iter()).all(|(a, b)| a.ulps_eq(&-b.clone(), epsilon.clone(), max_ulps)) + self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.ulps_eq(&-b.clone(), epsilon.clone(), max_ulps)) } } diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs old mode 100755 new mode 100644 index 0179f1ff..e2dc93a3 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -14,6 +14,9 @@ use crate::base::storage::Owned; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit}; use crate::geometry::{AbstractRotation, Point, Translation}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A direct isometry, i.e., a rotation followed by a translation (aka. a rigid-body motion). /// /// This is also known as an element of a Special Euclidean (SE) group. @@ -21,6 +24,7 @@ use crate::geometry::{AbstractRotation, Point, Translation}; /// A 2D isometry is composed of: /// - A translation part of type [`Translation2`](crate::Translation2) /// - A rotation part which can either be a [`UnitComplex`](crate::UnitComplex) or a [`Rotation2`](crate::Rotation2). +/// /// A 3D isometry is composed of: /// - A translation part of type [`Translation3`](crate::Translation3) /// - A rotation part which can either be a [`UnitQuaternion`](crate::UnitQuaternion) or a [`Rotation3`](crate::Rotation3). @@ -50,7 +54,6 @@ use crate::geometry::{AbstractRotation, Point, Translation}; /// #[repr(C)] #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize-no-std", @@ -66,6 +69,19 @@ use crate::geometry::{AbstractRotation, Point, Translation}; Owned>: Deserialize<'de>, T: Scalar")) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Isometry", + bound(archive = " + T: rkyv::Archive, + R: rkyv::Archive, + Translation: rkyv::Archive> + ") + ) +)] pub struct Isometry { /// The pure rotational part of this isometry. pub rotation: R, @@ -73,66 +89,6 @@ pub struct Isometry { pub translation: Translation, } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Isometry; - use crate::{base::Scalar, geometry::Translation}; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Isometry - where - T::Archived: Scalar, - { - type Archived = Isometry; - type Resolver = (R::Resolver, as Archive>::Resolver); - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut core::mem::MaybeUninit, - ) { - self.rotation.resolve( - pos + offset_of!(Self::Archived, rotation), - resolver.0, - project_struct!(out: Self::Archived => rotation), - ); - self.translation.resolve( - pos + offset_of!(Self::Archived, translation), - resolver.1, - project_struct!(out: Self::Archived => translation), - ); - } - } - - impl, R: Serialize, S: Fallible + ?Sized, const D: usize> - Serialize for Isometry - where - T::Archived: Scalar, - { - fn serialize(&self, serializer: &mut S) -> Result { - Ok(( - self.rotation.serialize(serializer)?, - self.translation.serialize(serializer)?, - )) - } - } - - impl - Deserialize, _D> for Isometry - where - T::Archived: Scalar + Deserialize, - R::Archived: Scalar + Deserialize, - { - fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { - Ok(Isometry { - rotation: self.rotation.deserialize(deserializer)?, - translation: self.translation.deserialize(deserializer)?, - }) - } - } -} - impl hash::Hash for Isometry where Owned>: hash::Hash, @@ -480,7 +436,7 @@ impl Isometry { DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, { let mut res: OMatrix = crate::convert_ref(&self.rotation); - res.fixed_slice_mut::(0, D) + res.fixed_view_mut::(0, D) .copy_from(&self.translation.vector); res diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index cce2932d..a2664170 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -372,7 +372,7 @@ macro_rules! look_at_isometry_construction_impl( /// Builds a left-handed look-at view matrix. /// /// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin. - /// This conforms to the common notion of right handed camera look-at **view matrix** from + /// This conforms to the common notion of left handed camera look-at **view matrix** from /// the computer graphics community, i.e. the camera is assumed to look toward its local `z` axis. /// /// # Arguments diff --git a/src/geometry/isometry_conversion.rs b/src/geometry/isometry_conversion.rs index 627ea3ee..06507631 100644 --- a/src/geometry/isometry_conversion.rs +++ b/src/geometry/isometry_conversion.rs @@ -153,8 +153,8 @@ where #[inline] fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { - let rot = m.fixed_slice::(0, 0); - let bottom = m.fixed_slice::<1, D>(D, 0); + let rot = m.fixed_view::(0, 0); + let bottom = m.fixed_view::<1, D>(D, 0); // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && @@ -168,7 +168,7 @@ where fn from_superset_unchecked( m: &OMatrix, U1>, DimNameSum, U1>>, ) -> Self { - let t = m.fixed_slice::(0, D).into_owned(); + let t = m.fixed_view::(0, D).into_owned(); let t = Translation { vector: crate::convert_unchecked(t), }; diff --git a/src/geometry/isometry_interpolation.rs b/src/geometry/isometry_interpolation.rs index 90f2c7ae..d6c20503 100644 --- a/src/geometry/isometry_interpolation.rs +++ b/src/geometry/isometry_interpolation.rs @@ -42,7 +42,7 @@ impl Isometry3 { /// Attempts to interpolate between two isometries using a linear interpolation for the translation part, /// and a spherical interpolation for the rotation part. /// - /// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation + /// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation /// is not well-defined). /// /// # Examples: @@ -118,7 +118,7 @@ impl IsometryMatrix3 { /// Attempts to interpolate between two isometries using a linear interpolation for the translation part, /// and a spherical interpolation for the rotation part. /// - /// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation + /// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation /// is not well-defined). /// /// # Examples: diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index 1119d4e3..5cf2a4c8 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -17,9 +17,23 @@ use crate::base::{Matrix4, Vector, Vector3}; use crate::geometry::{Point3, Projective3}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A 3D orthographic projection stored as a homogeneous 4x4 matrix. #[repr(C)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Orthographic3", + bound(archive = " + T: rkyv::Archive, + Matrix4: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[derive(Copy, Clone)] pub struct Orthographic3 { matrix: Matrix4, diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index 8ebab3e4..fd0c75dd 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -18,9 +18,23 @@ use crate::base::{Matrix4, Vector, Vector3}; use crate::geometry::{Point3, Projective3}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A 3D perspective projection stored as a homogeneous 4x4 matrix. #[repr(C)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Perspective3", + bound(archive = " + T: rkyv::Archive, + Matrix4: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[derive(Copy, Clone)] pub struct Perspective3 { matrix: Matrix4, diff --git a/src/geometry/point.rs b/src/geometry/point.rs index cdc590fa..94bd95a7 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -1,9 +1,11 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num::One; +use num::{One, Zero}; use std::cmp::Ordering; use std::fmt; use std::hash; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -13,6 +15,7 @@ use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::iter::{MatrixIter, MatrixIterMut}; use crate::base::{Const, DefaultAllocator, OVector, Scalar}; +use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub}; use std::mem::MaybeUninit; /// A point in an euclidean space. @@ -36,6 +39,20 @@ use std::mem::MaybeUninit; /// of said transformations for details. #[repr(C)] #[derive(Clone)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "OPoint", + bound(archive = " + T: rkyv::Archive, + T::Archived: Scalar, + OVector: rkyv::Archive>, + DefaultAllocator: Allocator, + ") + ) +)] pub struct OPoint where DefaultAllocator: Allocator, @@ -69,14 +86,6 @@ where { } -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for OPoint -where - DefaultAllocator: Allocator, - OVector: cust_core::DeviceCopy, -{ -} - #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for OPoint where @@ -199,7 +208,7 @@ where let mut res = crate::Matrix::uninit(DimNameSum::::name(), Const::<1>); // This is basically a copy_from except that we warp the copied // values into MaybeUninit. - res.generic_slice_mut((0, 0), self.coords.shape_generic()) + res.generic_view_mut((0, 0), self.coords.shape_generic()) .zip_apply(&self.coords, |out, e| *out = MaybeUninit::new(e)); res[(len, 0)] = MaybeUninit::new(T::one()); @@ -207,6 +216,31 @@ where unsafe { res.assume_init() } } + /// Linear interpolation between two points. + /// + /// Returns `self * (1.0 - t) + rhs.coords * t`, i.e., the linear blend of the points + /// `self` and `rhs` using the scalar value `t`. + /// + /// The value for a is not restricted to the range `[0, 1]`. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Point3; + /// let a = Point3::new(1.0, 2.0, 3.0); + /// let b = Point3::new(10.0, 20.0, 30.0); + /// assert_eq!(a.lerp(&b, 0.1), Point3::new(1.9, 3.8, 5.7)); + /// ``` + #[must_use] + pub fn lerp(&self, rhs: &OPoint, t: T) -> OPoint + where + T: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, + { + OPoint { + coords: self.coords.lerp(&rhs.coords, t), + } + } + /// Creates a new point with the given coordinates. #[deprecated(note = "Use Point::from(vector) instead.")] #[inline] @@ -275,6 +309,10 @@ where } /// Gets a reference to i-th element of this point without bound-checking. + /// + /// # Safety + /// + /// `i` must be less than `self.len()`. #[inline] #[must_use] pub unsafe fn get_unchecked(&self, i: usize) -> &T { @@ -302,6 +340,10 @@ where } /// Gets a mutable reference to i-th element of this point without bound-checking. + /// + /// # Safety + /// + /// `i` must be less than `self.len()`. #[inline] #[must_use] pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut T { @@ -309,6 +351,10 @@ where } /// Swaps two entries without bound-checking. + /// + /// # Safety + /// + /// `i1` and `i2` must be less than `self.len()`. #[inline] pub unsafe fn swap_unchecked(&mut self, i1: usize, i2: usize) { self.coords.swap_unchecked((i1, 0), (i2, 0)) @@ -457,10 +503,11 @@ where let mut it = self.coords.iter(); - write!(f, "{}", *it.next().unwrap())?; + ::fmt(it.next().unwrap(), f)?; for comp in it { - write!(f, ", {}", *comp)?; + write!(f, ", ")?; + ::fmt(comp, f)?; } write!(f, "}}") diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index 2136080a..b60e65ac 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -113,7 +113,7 @@ where DefaultAllocator: Allocator>, { if !v[D::dim()].is_zero() { - let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); + let coords = v.generic_view((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); Some(Self::from(coords)) } else { None @@ -202,7 +202,7 @@ impl Point1 { /// assert_eq!(p.x, 1.0); /// ``` #[inline] - pub fn new(x: T) -> Self { + pub const fn new(x: T) -> Self { Point { coords: Vector1::new(x), } @@ -216,7 +216,7 @@ macro_rules! componentwise_constructors_impl( #[doc = $doc] #[doc = "```"] #[inline] - pub fn new($($args: T),*) -> Self { + pub const fn new($($args: T),*) -> Self { Point { coords: $Vector::new($($args),*) } } } diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index ce1bd930..81870379 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -66,7 +66,7 @@ where #[inline] fn from_superset_unchecked(v: &OVector>) -> Self { - let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); + let coords = v.generic_view((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); Self { coords: crate::convert_unchecked(coords), } diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs old mode 100755 new mode 100644 index 987c9757..829a7da2 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -14,16 +14,30 @@ use simba::simd::{SimdBool, SimdOption, SimdRealField}; use crate::base::dimension::{U1, U3, U4}; use crate::base::storage::{CStride, RStride}; use crate::base::{ - Matrix3, Matrix4, MatrixSlice, MatrixSliceMut, Normed, Scalar, Unit, Vector3, Vector4, + Matrix3, Matrix4, MatrixView, MatrixViewMut, Normed, Scalar, Unit, Vector3, Vector4, }; use crate::geometry::{Point3, Rotation}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A quaternion. See the type alias `UnitQuaternion = Unit` for a quaternion /// that may be used as a rotation. #[repr(C)] #[derive(Copy, Clone)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Quaternion", + bound(archive = " + T: rkyv::Archive, + Vector4: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. pub coords: Vector4, @@ -97,48 +111,6 @@ where } } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Quaternion; - use crate::base::Vector4; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Quaternion { - type Archived = Quaternion; - type Resolver = as Archive>::Resolver; - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut core::mem::MaybeUninit, - ) { - self.coords.resolve( - pos + offset_of!(Self::Archived, coords), - resolver, - project_struct!(out: Self::Archived => coords), - ); - } - } - - impl, S: Fallible + ?Sized> Serialize for Quaternion { - fn serialize(&self, serializer: &mut S) -> Result { - self.coords.serialize(serializer) - } - } - - impl Deserialize, D> for Quaternion - where - T::Archived: Deserialize, - { - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Quaternion { - coords: self.coords.deserialize(deserializer)?, - }) - } - } -} - impl Quaternion where T::Element: SimdRealField, @@ -165,7 +137,7 @@ where /// # use nalgebra::Quaternion; /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// let q_normalized = q.normalize(); - /// relative_eq!(q_normalized.norm(), 1.0); + /// assert_relative_eq!(q_normalized.norm(), 1.0); /// ``` #[inline] #[must_use = "Did you mean to use normalize_mut()?"] @@ -225,7 +197,7 @@ where /// ``` #[inline] #[must_use] - pub fn vector(&self) -> MatrixSlice<'_, T, U3, U1, RStride, CStride> { + pub fn vector(&self) -> MatrixView<'_, T, U3, U1, RStride, CStride> { self.coords.fixed_rows::<3>(0) } @@ -298,7 +270,7 @@ where /// ``` /// # use nalgebra::Quaternion; /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); - /// assert_eq!(q.magnitude_squared(), 30.0); + /// assert_eq!(q.norm_squared(), 30.0); /// ``` #[inline] #[must_use] @@ -618,7 +590,7 @@ where #[inline] pub fn vector_mut( &mut self, - ) -> MatrixSliceMut<'_, T, U3, U1, RStride, CStride> { + ) -> MatrixViewMut<'_, T, U3, U1, RStride, CStride> { self.coords.fixed_rows_mut::<3>(0) } @@ -1043,9 +1015,6 @@ impl fmt::Display for Quaternion { /// A unit quaternions. May be used to represent a rotation. pub type UnitQuaternion = Unit>; -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for UnitQuaternion {} - impl PartialEq for UnitQuaternion { #[inline] fn eq(&self, rhs: &Self) -> bool { @@ -1357,7 +1326,7 @@ where } } - /// The rotation axis and angle in ]0, pi] of this unit quaternion. + /// The rotation axis and angle in (0, pi] of this unit quaternion. /// /// Returns `None` if the angle is zero. /// @@ -1607,7 +1576,7 @@ where #[inline] #[must_use] pub fn inverse_transform_point(&self, pt: &Point3) -> Point3 { - // TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement + // TODO: would it be useful performance-wise not to call inverse explicitly (i-e. implement // the inverse transformation explicitly here) ? self.inverse() * pt } diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs old mode 100755 new mode 100644 index 4dbcfb43..d09a862a --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -17,6 +17,9 @@ use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::{Const, DefaultAllocator, OMatrix, SMatrix, SVector, Scalar, Unit}; use crate::geometry::Point; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A rotation matrix. /// /// This is also known as an element of a Special Orthogonal (SO) group. @@ -49,7 +52,18 @@ use crate::geometry::Point; /// * [Conversion to a matrix `matrix`, `to_homogeneous`…](#conversion-to-a-matrix) /// #[repr(C)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Rotation", + bound(archive = " + T: rkyv::Archive, + SMatrix: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[derive(Copy, Clone)] pub struct Rotation { matrix: SMatrix, @@ -170,6 +184,10 @@ impl Rotation { } /// A mutable reference to the underlying matrix representation of this rotation. + /// + /// # Safety + /// + /// Invariants of the rotation matrix should not be violated. #[inline] #[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")] pub unsafe fn matrix_mut(&mut self) -> &mut SMatrix { @@ -253,7 +271,7 @@ impl Rotation { // adding the additional traits `DimAdd` and `IsNotStaticOne`. Maybe // these things will get nicer once specialization lands in Rust. let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); - res.fixed_slice_mut::(0, 0).copy_from(&self.matrix); + res.fixed_view_mut::(0, 0).copy_from(&self.matrix); res } diff --git a/src/geometry/rotation_conversion.rs b/src/geometry/rotation_conversion.rs index 517010a0..c37b5cdd 100644 --- a/src/geometry/rotation_conversion.rs +++ b/src/geometry/rotation_conversion.rs @@ -211,8 +211,8 @@ where #[inline] fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { - let rot = m.fixed_slice::(0, 0); - let bottom = m.fixed_slice::<1, D>(D, 0); + let rot = m.fixed_view::(0, 0); + let bottom = m.fixed_view::<1, D>(D, 0); // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && @@ -226,7 +226,7 @@ where fn from_superset_unchecked( m: &OMatrix, U1>, DimNameSum, U1>>, ) -> Self { - let r = m.fixed_slice::(0, 0); + let r = m.fixed_view::(0, 0); Self::from_matrix_unchecked(crate::convert_unchecked(r.into_owned())) } } diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index e37826bf..ace42487 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -19,7 +19,9 @@ use crate::base::allocator::Allocator; use crate::base::dimension::{Const, DimDiff, DimSub, U1, U2, U3}; use crate::base::storage::Storage; use crate::base::{ArrayStorage, DefaultAllocator}; -use crate::base::{Matrix2, Matrix3, SMatrix, SVector, Unit, Vector, Vector1, Vector2, Vector3}; +use crate::base::{ + Matrix2, Matrix3, SMatrix, SVector, Unit, UnitVector3, Vector, Vector1, Vector2, Vector3, +}; use crate::geometry::{Rotation, Rotation2, Rotation3, UnitComplex, UnitQuaternion}; @@ -478,9 +480,10 @@ where SB: Storage, SC: Storage, { + // Gram–Schmidt process let zaxis = dir.normalize(); let xaxis = up.cross(&zaxis).normalize(); - let yaxis = zaxis.cross(&xaxis).normalize(); + let yaxis = zaxis.cross(&xaxis); Self::from_matrix_unchecked(SMatrix::::new( xaxis.x.clone(), @@ -732,9 +735,12 @@ where T: RealField, { if max_iter == 0 { - max_iter = usize::max_value(); + max_iter = usize::MAX; } + // Using sqrt(eps) ensures we perturb with something larger than eps; clamp to eps to handle the case of eps > 1.0 + let eps_disturbance = eps.clone().sqrt().max(eps.clone() * eps.clone()); + let mut perturbation_axes = Vector3::x_axis(); let mut rot = guess.into_inner(); for _ in 0..max_iter { @@ -750,7 +756,33 @@ where if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, eps.clone()) { rot = Rotation3::from_axis_angle(&axis, angle) * rot; } else { - break; + // Check if stuck in a maximum w.r.t. the norm (m - rot).norm() + let mut perturbed = rot.clone(); + let norm_squared = (m - &rot).norm_squared(); + let mut new_norm_squared: T; + + // Perturb until the new norm is significantly different + loop { + perturbed *= + Rotation3::from_axis_angle(&perturbation_axes, eps_disturbance.clone()); + new_norm_squared = (m - &perturbed).norm_squared(); + if abs_diff_ne!( + norm_squared, + new_norm_squared, + epsilon = T::default_epsilon() + ) { + break; + } + } + + // If new norm is larger, it's a minimum + if norm_squared < new_norm_squared { + break; + } + + // If not, continue from perturbed rotation, but use a different axes for the next perturbation + perturbation_axes = UnitVector3::new_unchecked(perturbation_axes.yzx()); + rot = perturbed; } } @@ -848,7 +880,7 @@ impl Rotation3 { } } - /// The rotation axis and angle in ]0, pi] of this rotation matrix. + /// The rotation axis and angle in (0, pi] of this rotation matrix. /// /// Returns `None` if the angle is zero. /// @@ -927,13 +959,15 @@ impl Rotation3 { { // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh // https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 + // where roll, pitch, yaw angles are referred to as ψ, θ, ϕ, if self[(2, 0)].clone().abs() < T::one() { - let yaw = -self[(2, 0)].clone().asin(); - let roll = (self[(2, 1)].clone() / yaw.clone().cos()) - .atan2(self[(2, 2)].clone() / yaw.clone().cos()); - let pitch = (self[(1, 0)].clone() / yaw.clone().cos()) - .atan2(self[(0, 0)].clone() / yaw.clone().cos()); - (roll, yaw, pitch) + let pitch = -self[(2, 0)].clone().asin(); + let theta_cos = pitch.clone().cos(); + let roll = (self[(2, 1)].clone() / theta_cos.clone()) + .atan2(self[(2, 2)].clone() / theta_cos.clone()); + let yaw = + (self[(1, 0)].clone() / theta_cos.clone()).atan2(self[(0, 0)].clone() / theta_cos); + (roll, pitch, yaw) } else if self[(2, 0)].clone() <= -T::one() { ( self[(0, 1)].clone().atan2(self[(0, 2)].clone()), @@ -948,6 +982,176 @@ impl Rotation3 { ) } } + + /// Represent this rotation as Euler angles. + /// + /// Returns the angles produced in the order provided by seq parameter, along with the + /// observability flag. The Euler axes passed to seq must form an orthonormal basis. If the + /// rotation is gimbal locked, then the observability flag is false. + /// + /// # Panics + /// + /// Panics if the Euler axes in `seq` are not orthonormal. + /// + /// # Example 1: + /// ``` + /// use std::f64::consts::PI; + /// use approx::assert_relative_eq; + /// use nalgebra::{Matrix3, Rotation3, Unit, Vector3}; + /// + /// // 3-1-2 + /// let n = [ + /// Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)), + /// Unit::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), + /// Unit::new_unchecked(Vector3::new(0.0, 1.0, 0.0)), + /// ]; + /// + /// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0); + /// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0); + /// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0); + /// + /// let d = r3 * r2 * r1; + /// + /// let (angles, observable) = d.euler_angles_ordered(n, false); + /// assert!(observable); + /// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12); + /// ``` + /// + /// # Example 2: + /// ``` + /// use std::f64::consts::PI; + /// use approx::assert_relative_eq; + /// use nalgebra::{Matrix3, Rotation3, Unit, Vector3}; + /// + /// let sqrt_2 = 2.0_f64.sqrt(); + /// let n = [ + /// Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, 1.0 / sqrt_2, 0.0)), + /// Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, -1.0 / sqrt_2, 0.0)), + /// Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)), + /// ]; + /// + /// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0); + /// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0); + /// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0); + /// + /// let d = r3 * r2 * r1; + /// + /// let (angles, observable) = d.euler_angles_ordered(n, false); + /// assert!(observable); + /// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12); + /// ``` + /// + /// Algorithm based on: + /// Malcolm D. Shuster, F. Landis Markley, “General formula for extraction the Euler + /// angles”, Journal of guidance, control, and dynamics, vol. 29.1, pp. 215-221. 2006, + /// and modified to be able to produce extrinsic rotations. + #[must_use] + pub fn euler_angles_ordered( + &self, + mut seq: [Unit>; 3], + extrinsic: bool, + ) -> ([T; 3], bool) + where + T: RealField + Copy, + { + let mut angles = [T::zero(); 3]; + let eps = T::from_subset(&1e-7); + let two = T::from_subset(&2.0); + + if extrinsic { + seq.reverse(); + } + + let [n1, n2, n3] = &seq; + assert_relative_eq!(n1.dot(n2), T::zero(), epsilon = eps); + assert_relative_eq!(n3.dot(n1), T::zero(), epsilon = eps); + + let n1_c_n2 = n1.cross(n2); + let s1 = n1_c_n2.dot(n3); + let c1 = n1.dot(n3); + let lambda = s1.atan2(c1); + + let mut c = Matrix3::zeros(); + c.column_mut(0).copy_from(n2); + c.column_mut(1).copy_from(&n1_c_n2); + c.column_mut(2).copy_from(n1); + c.transpose_mut(); + + let r1l = Matrix3::new( + T::one(), + T::zero(), + T::zero(), + T::zero(), + c1, + s1, + T::zero(), + -s1, + c1, + ); + let o_t = c * self.matrix() * (c.transpose() * r1l); + angles[1] = o_t.m33.acos(); + + let safe1 = angles[1].abs() >= eps; + let safe2 = (angles[1] - T::pi()).abs() >= eps; + let observable = safe1 && safe2; + angles[1] += lambda; + + if observable { + angles[0] = o_t.m13.atan2(-o_t.m23); + angles[2] = o_t.m31.atan2(o_t.m32); + } else { + // gimbal lock detected + if extrinsic { + // angle1 is initialized to zero + if !safe1 { + angles[2] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22); + } else { + angles[2] = -(o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22); + }; + } else { + // angle3 is initialized to zero + if !safe1 { + angles[0] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22); + } else { + angles[0] = (o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22); + }; + }; + }; + + let adjust = if seq[0] == seq[2] { + // lambda = 0, so ensure angle2 -> [0, pi] + angles[1] < T::zero() || angles[1] > T::pi() + } else { + // lamda = + or - pi/2, so ensure angle2 -> [-pi/2, pi/2] + angles[1] < -T::frac_pi_2() || angles[1] > T::frac_pi_2() + }; + + // dont adjust gimbal locked rotation + if adjust && observable { + angles[0] += T::pi(); + angles[1] = two * lambda - angles[1]; + angles[2] -= T::pi(); + } + + // ensure all angles are within [-pi, pi] + for angle in angles.as_mut_slice().iter_mut() { + if *angle < -T::pi() { + *angle += T::two_pi(); + } else if *angle > T::pi() { + *angle -= T::two_pi(); + } + } + + if extrinsic { + angles.reverse(); + } + + (angles, observable) + } } #[cfg(feature = "rand-no-std")] diff --git a/src/geometry/scale.rs b/src/geometry/scale.rs old mode 100755 new mode 100644 index abaeeccc..31985e5a --- a/src/geometry/scale.rs +++ b/src/geometry/scale.rs @@ -15,9 +15,23 @@ use crate::ClosedMul; use crate::geometry::Point; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A scale which supports non-uniform scaling. #[repr(C)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Scale", + bound(archive = " + T: rkyv::Archive, + SVector: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[derive(Copy, Clone)] pub struct Scale { /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is @@ -84,49 +98,6 @@ where } } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Scale; - use crate::base::SVector; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Scale { - type Archived = Scale; - type Resolver = as Archive>::Resolver; - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut core::mem::MaybeUninit, - ) { - self.vector.resolve( - pos + offset_of!(Self::Archived, vector), - resolver, - project_struct!(out: Self::Archived => vector), - ); - } - } - - impl, S: Fallible + ?Sized, const D: usize> Serialize for Scale { - fn serialize(&self, serializer: &mut S) -> Result { - self.vector.serialize(serializer) - } - } - - impl Deserialize, _D> - for Scale - where - T::Archived: Deserialize, - { - fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { - Ok(Scale { - vector: self.vector.deserialize(deserializer)?, - }) - } - } -} - impl Scale { /// Inverts `self`. /// @@ -157,7 +128,7 @@ impl Scale { return None; } } - return Some(self.vector.map(|e| T::one() / e).into()); + Some(self.vector.map(|e| T::one() / e).into()) } /// Inverts `self`. @@ -177,13 +148,17 @@ impl Scale { /// assert_eq!(t.inverse_unchecked() * t, Scale2::identity()); /// } /// ``` + /// + /// # Safety + /// + /// Should only be used if all scaling is known to be non-zero. #[inline] #[must_use] pub unsafe fn inverse_unchecked(&self) -> Scale where T: ClosedDiv + One, { - return self.vector.map(|e| T::one() / e).into(); + self.vector.map(|e| T::one() / e).into() } /// Inverts `self`. @@ -211,8 +186,7 @@ impl Scale { where T: ClosedDiv + One + Zero, { - return self - .vector + self.vector .map(|e| { if e != T::zero() { T::one() / e @@ -220,7 +194,7 @@ impl Scale { T::zero() } }) - .into(); + .into() } /// Converts this Scale into its equivalent homogeneous transformation matrix. @@ -258,7 +232,7 @@ impl Scale { for i in 0..D { v[i] = self.vector[i].clone(); } - return OMatrix::from_diagonal(&v); + OMatrix::from_diagonal(&v) } /// Inverts `self` in-place. diff --git a/src/geometry/scale_conversion.rs b/src/geometry/scale_conversion.rs index 2dc670a1..2d807e3a 100644 --- a/src/geometry/scale_conversion.rs +++ b/src/geometry/scale_conversion.rs @@ -102,7 +102,7 @@ where fn from_superset_unchecked( m: &OMatrix, U1>, DimNameSum, U1>>, ) -> Self { - let v = m.fixed_slice::(0, 0).diagonal(); + let v = m.fixed_view::(0, 0).diagonal(); Self { vector: crate::convert_unchecked(v), } diff --git a/src/geometry/scale_ops.rs b/src/geometry/scale_ops.rs index c056a301..b22f7b53 100644 --- a/src/geometry/scale_ops.rs +++ b/src/geometry/scale_ops.rs @@ -83,28 +83,28 @@ add_sub_impl!(Mul, mul, ClosedMul; (Const, U1), (Const, U1) -> (Const, U1) const D; for; where; self: &'a Scale, right: &'b SVector, Output = SVector; - SVector::from(self.vector.component_mul(&right)); + self.vector.component_mul(right); 'a, 'b); add_sub_impl!(Mul, mul, ClosedMul; (Const, U1), (Const, U1) -> (Const, U1) const D; for; where; self: &'a Scale, right: SVector, Output = SVector; - SVector::from(self.vector.component_mul(&right)); + self.vector.component_mul(&right); 'a); add_sub_impl!(Mul, mul, ClosedMul; (Const, U1), (Const, U1) -> (Const, U1) const D; for; where; self: Scale, right: &'b SVector, Output = SVector; - SVector::from(self.vector.component_mul(&right)); + self.vector.component_mul(right); 'b); add_sub_impl!(Mul, mul, ClosedMul; (Const, U1), (Const, U1) -> (Const, U1) const D; for; where; self: Scale, right: SVector, Output = SVector; - SVector::from(self.vector.component_mul(&right)); ); + self.vector.component_mul(&right); ); // Scale *= Scale add_sub_assign_impl!(MulAssign, mul_assign, ClosedMul; diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs old mode 100755 new mode 100644 index 9658685e..630ebac6 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -15,10 +15,12 @@ use crate::base::storage::Owned; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. #[repr(C)] #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize-no-std", @@ -34,6 +36,19 @@ use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; DefaultAllocator: Allocator>, Owned>: Deserialize<'de>")) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Similarity", + bound(archive = " + T: rkyv::Archive, + R: rkyv::Archive, + Isometry: rkyv::Archive> + ") + ) +)] pub struct Similarity { /// The part of this similarity that does not include the scaling factor. pub isometry: Isometry, @@ -296,7 +311,7 @@ impl Similarity { { let mut res = self.isometry.to_homogeneous(); - for e in res.fixed_slice_mut::(0, 0).iter_mut() { + for e in res.fixed_view_mut::(0, 0).iter_mut() { *e *= self.scaling.clone() } diff --git a/src/geometry/similarity_conversion.rs b/src/geometry/similarity_conversion.rs index 6bc12814..e5d28906 100644 --- a/src/geometry/similarity_conversion.rs +++ b/src/geometry/similarity_conversion.rs @@ -106,7 +106,7 @@ where #[inline] fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { - let mut rot = m.fixed_slice::(0, 0).clone_owned(); + let mut rot = m.fixed_view::(0, 0).clone_owned(); if rot .fixed_columns_mut::<1>(0) .try_normalize_mut(T2::zero()) @@ -128,7 +128,7 @@ where rot.fixed_columns_mut::<1>(2).neg_mut(); } - let bottom = m.fixed_slice::<1, D>(D, 0); + let bottom = m.fixed_view::<1, D>(D, 0); // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && // The normalized block part is a rotation. @@ -145,22 +145,22 @@ where m: &OMatrix, U1>, DimNameSum, U1>>, ) -> Self { let mut mm = m.clone_owned(); - let na = mm.fixed_slice_mut::(0, 0).normalize_mut(); - let nb = mm.fixed_slice_mut::(0, 1).normalize_mut(); - let nc = mm.fixed_slice_mut::(0, 2).normalize_mut(); + let na = mm.fixed_view_mut::(0, 0).normalize_mut(); + let nb = mm.fixed_view_mut::(0, 1).normalize_mut(); + let nc = mm.fixed_view_mut::(0, 2).normalize_mut(); let mut scale = (na + nb + nc) / crate::convert(3.0); // We take the mean, for robustness. // TODO: could we avoid the explicit computation of the determinant? // (its sign is needed to see if the scaling factor is negative). - if mm.fixed_slice::(0, 0).determinant() < T2::zero() { - mm.fixed_slice_mut::(0, 0).neg_mut(); - mm.fixed_slice_mut::(0, 1).neg_mut(); - mm.fixed_slice_mut::(0, 2).neg_mut(); + if mm.fixed_view::(0, 0).determinant() < T2::zero() { + mm.fixed_view_mut::(0, 0).neg_mut(); + mm.fixed_view_mut::(0, 1).neg_mut(); + mm.fixed_view_mut::(0, 2).neg_mut(); scale = -scale; } - let t = m.fixed_slice::(0, D).into_owned(); + let t = m.fixed_view::(0, D).into_owned(); let t = Translation { vector: crate::convert_unchecked(t), }; diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index 2a7ca112..5e468792 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -60,17 +60,14 @@ where /// Tag representing the most general (not necessarily inversible) `Transform` type. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub enum TGeneral {} /// Tag representing the most general inversible `Transform` type. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub enum TProjective {} /// Tag representing an affine `Transform`. Its bottom-row is equal to `(0, 0 ... 0, 1)`. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub enum TAffine {} impl TCategory for TGeneral { @@ -122,7 +119,7 @@ macro_rules! category_mul_impl( )*} ); -// We require stability uppon multiplication. +// We require stability upon multiplication. impl TCategoryMul for T { type Representative = T; } @@ -198,16 +195,6 @@ where { } -#[cfg(feature = "cuda")] -unsafe impl - cust_core::DeviceCopy for Transform -where - Const: DimNameAdd, - DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, - Owned, U1>, DimNameSum, U1>>: cust_core::DeviceCopy, -{ -} - impl Clone for Transform where Const: DimNameAdd, @@ -411,7 +398,7 @@ where /// 3.0, 4.0, 0.0, /// 0.0, 0.0, 1.0); /// let t = Transform2::from_matrix_unchecked(m); - /// assert_eq!(t.into_inner(), m); + /// assert_eq!(t.to_homogeneous(), m); /// ``` #[inline] #[must_use] diff --git a/src/geometry/transform_ops.rs b/src/geometry/transform_ops.rs index 8a500676..4c6284d0 100644 --- a/src/geometry/transform_ops.rs +++ b/src/geometry/transform_ops.rs @@ -120,10 +120,10 @@ md_impl_all!( [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => { - let transform = self.matrix().fixed_slice::(0, 0); + let transform = self.matrix().fixed_view::(0, 0); if C::has_normalizer() { - let normalizer = self.matrix().fixed_slice::<1, D>(D, 0); + let normalizer = self.matrix().fixed_view::<1, D>(D, 0); let n = normalizer.tr_dot(rhs); if !n.is_zero() { @@ -148,11 +148,11 @@ md_impl_all!( [ref val] => self * &rhs; [val ref] => &self * rhs; [ref ref] => { - let transform = self.matrix().fixed_slice::(0, 0); - let translation = self.matrix().fixed_slice::(0, D); + let transform = self.matrix().fixed_view::(0, 0); + let translation = self.matrix().fixed_view::(0, D); if C::has_normalizer() { - let normalizer = self.matrix().fixed_slice::<1, D>(D, 0); + let normalizer = self.matrix().fixed_view::<1, D>(D, 0); #[allow(clippy::suspicious_arithmetic_impl)] let n = normalizer.tr_dot(&rhs.coords) + unsafe { self.matrix().get_unchecked((D, D)).clone() }; diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs old mode 100755 new mode 100644 index e1921d0a..d626b1dc --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -15,9 +15,23 @@ use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; use crate::geometry::Point; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + /// A translation. #[repr(C)] -#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Translation", + bound(archive = " + T: rkyv::Archive, + SVector: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[derive(Copy, Clone)] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is @@ -84,49 +98,6 @@ where } } -#[cfg(feature = "rkyv-serialize-no-std")] -mod rkyv_impl { - use super::Translation; - use crate::base::SVector; - use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - - impl Archive for Translation { - type Archived = Translation; - type Resolver = as Archive>::Resolver; - - fn resolve( - &self, - pos: usize, - resolver: Self::Resolver, - out: &mut core::mem::MaybeUninit, - ) { - self.vector.resolve( - pos + offset_of!(Self::Archived, vector), - resolver, - project_struct!(out: Self::Archived => vector), - ); - } - } - - impl, S: Fallible + ?Sized, const D: usize> Serialize for Translation { - fn serialize(&self, serializer: &mut S) -> Result { - self.vector.serialize(serializer) - } - } - - impl Deserialize, _D> - for Translation - where - T::Archived: Deserialize, - { - fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { - Ok(Translation { - vector: self.vector.deserialize(deserializer)?, - }) - } - } -} - impl Translation { /// Creates a new translation from the given vector. #[inline] @@ -185,7 +156,7 @@ impl Translation { DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, { let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); - res.fixed_slice_mut::(0, D).copy_from(&self.vector); + res.fixed_view_mut::(0, D).copy_from(&self.vector); res } diff --git a/src/geometry/translation_conversion.rs b/src/geometry/translation_conversion.rs index 70000efb..73646780 100644 --- a/src/geometry/translation_conversion.rs +++ b/src/geometry/translation_conversion.rs @@ -159,7 +159,7 @@ where #[inline] fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { - let id = m.generic_slice((0, 0), (DimNameSum::, U1>::name(), Const::)); + let id = m.generic_view((0, 0), (DimNameSum::, U1>::name(), Const::)); // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && @@ -173,7 +173,7 @@ where fn from_superset_unchecked( m: &OMatrix, U1>, DimNameSum, U1>>, ) -> Self { - let t = m.fixed_slice::(0, D); + let t = m.fixed_view::(0, D); Self { vector: crate::convert_unchecked(t.into_owned()), } diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index caf25493..a04df89b 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -31,9 +31,6 @@ use std::cmp::{Eq, PartialEq}; /// * [Conversion to a matrix `to_rotation_matrix`, `to_homogeneous`…](#conversion-to-a-matrix) pub type UnitComplex = Unit>; -#[cfg(feature = "cuda")] -unsafe impl cust_core::DeviceCopy for UnitComplex {} - impl PartialEq for UnitComplex { #[inline] fn eq(&self, rhs: &Self) -> bool { @@ -132,7 +129,7 @@ where Vector1::new(self.angle()) } - /// The rotation axis and angle in ]0, pi] of this complex number. + /// The rotation axis and angle in (0, pi] of this complex number. /// /// This is generally used in the context of generic programming. Using /// the `.angle()` method instead is more common. @@ -347,7 +344,7 @@ where #[inline] #[must_use] pub fn inverse_transform_point(&self, pt: &Point2) -> Point2 { - // TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement + // TODO: would it be useful performance-wise not to call inverse explicitly (i-e. implement // the inverse transformation explicitly here) ? self.inverse() * pt } @@ -410,7 +407,8 @@ where #[inline] #[must_use] pub fn slerp(&self, other: &Self, t: T) -> Self { - Self::new(self.angle() * (T::one() - t.clone()) + other.angle() * t) + let delta = other / self; + self * Self::new(delta.angle() * t) } } diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index ebf4e81d..9536e87f 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -131,10 +131,11 @@ where /// /// # Example /// ``` + /// #[macro_use] extern crate approx; /// # use nalgebra::UnitComplex; /// let c = UnitComplex::new(1.0f64); /// let c2 = c.cast::(); - /// assert_eq!(c2, UnitComplex::new(1.0f32)); + /// assert_relative_eq!(c2, UnitComplex::new(1.0f32)); /// ``` pub fn cast(self) -> UnitComplex where diff --git a/src/lib.rs b/src/lib.rs index 92b28dcb..8532d532 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ explicitly, and call free-functions using the `na::` prefix: ``` #[macro_use] -extern crate approx; // For the macro relative_eq! +extern crate approx; // For the macro assert_relative_eq! extern crate nalgebra as na; use na::{Vector3, Rotation3}; @@ -36,8 +36,8 @@ fn main() { let angle = 1.57; let b = Rotation3::from_axis_angle(&axis, angle); - relative_eq!(b.axis().unwrap(), axis); - relative_eq!(b.angle(), angle); + assert_relative_eq!(b.axis().unwrap(), axis); + assert_relative_eq!(b.angle(), angle); } ``` @@ -46,28 +46,34 @@ fn main() { **nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with an optimized set of tools for computer graphics and physics. Those features include: -* A single parametrizable type `Matrix` for vectors, (square or rectangular) matrices, and slices - with dimensions known either at compile-time (using type-level integers) or at runtime. +* A single parametrizable type [`Matrix`](Matrix) for vectors, (square or rectangular) matrices, and + slices with dimensions known either at compile-time (using type-level integers) or at runtime. * Matrices and vectors with compile-time sizes are statically allocated while dynamic ones are allocated on the heap. -* Convenient aliases for low-dimensional matrices and vectors: `Vector1` to `Vector6` and - `Matrix1x1` to `Matrix6x6`, including rectangular matrices like `Matrix2x5`. -* Points sizes known at compile time, and convenience aliases: `Point1` to `Point6`. -* Translation (seen as a transformation that composes by multiplication): `Translation2`, - `Translation3`. -* Rotation matrices: `Rotation2`, `Rotation3`. -* Quaternions: `Quaternion`, `UnitQuaternion` (for 3D rotation). -* Unit complex numbers can be used for 2D rotation: `UnitComplex`. -* Algebraic entities with a norm equal to one: `Unit`, e.g., `Unit>`. -* Isometries (translation ⨯ rotation): `Isometry2`, `Isometry3` -* Similarity transformations (translation ⨯ rotation ⨯ uniform scale): `Similarity2`, `Similarity3`. -* Affine transformations stored as a homogeneous matrix: `Affine2`, `Affine3`. -* Projective (i.e. invertible) transformations stored as a homogeneous matrix: `Projective2`, - `Projective3`. +* Convenient aliases for low-dimensional matrices and vectors: [`Vector1`](Vector1) to + [`Vector6`](Vector6) and [`Matrix1x1`](Matrix1) to [`Matrix6x6`](Matrix6), including rectangular + matrices like [`Matrix2x5`](Matrix2x5). +* Points sizes known at compile time, and convenience aliases: [`Point1`](Point1) to + [`Point6`](Point6). +* Translation (seen as a transformation that composes by multiplication): + [`Translation2`](Translation2), [`Translation3`](Translation3). +* Rotation matrices: [`Rotation2`](Rotation2), [`Rotation3`](Rotation3). +* Quaternions: [`Quaternion`](Quaternion), [`UnitQuaternion`](UnitQuaternion) (for 3D rotation). +* Unit complex numbers can be used for 2D rotation: [`UnitComplex`](UnitComplex). +* Algebraic entities with a norm equal to one: [`Unit`](Unit), e.g., `Unit>`. +* Isometries (translation ⨯ rotation): [`Isometry2`](Isometry2), [`Isometry3`](Isometry3) +* Similarity transformations (translation ⨯ rotation ⨯ uniform scale): + [`Similarity2`](Similarity2), [`Similarity3`](Similarity3). +* Affine transformations stored as a homogeneous matrix: + [`Affine2`](Affine2), [`Affine3`](Affine3). +* Projective (i.e. invertible) transformations stored as a homogeneous matrix: + [`Projective2`](Projective2), [`Projective3`](Projective3). * General transformations that does not have to be invertible, stored as a homogeneous matrix: - `Transform2`, `Transform3`. -* 3D projections for computer graphics: `Perspective3`, `Orthographic3`. -* Matrix factorizations: `Cholesky`, `QR`, `LU`, `FullPivLU`, `SVD`, `Schur`, `Hessenberg`, `SymmetricEigen`. + [`Transform2`](Transform2), [`Transform3`](Transform3). +* 3D projections for computer graphics: [`Perspective3`](Perspective3), + [`Orthographic3`](Orthographic3). +* Matrix factorizations: [`Cholesky`](Cholesky), [`QR`](QR), [`LU`](LU), [`FullPivLU`](FullPivLU), + [`SVD`](SVD), [`Schur`](Schur), [`Hessenberg`](Hessenberg), [`SymmetricEigen`](SymmetricEigen). * Insertion and removal of rows of columns of a matrix. */ @@ -77,19 +83,31 @@ an optimized set of tools for computer graphics and physics. Those features incl unused_variables, unused_mut, unused_parens, - unused_qualifications, - unused_results, rust_2018_idioms, rust_2018_compatibility, future_incompatible, missing_copy_implementations )] +#![cfg_attr(not(feature = "rkyv-serialize-no-std"), deny(unused_results))] // TODO: deny this globally once bytecheck stops generating unused results. #![doc( html_favicon_url = "https://nalgebra.org/img/favicon.ico", html_root_url = "https://docs.rs/nalgebra/0.25.0" )] #![cfg_attr(not(feature = "std"), no_std)] +/// Generates an appropriate deprecation note with a suggestion for replacement. +/// +/// Used for deprecating slice types in various locations throughout the library. +/// See #1076 for more information. +macro_rules! slice_deprecation_note { + ($replacement:ident) => { + concat!("Use ", stringify!($replacement), + r###" instead. See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) for more information."###) + } +} + +pub(crate) use slice_deprecation_note; + #[cfg(feature = "rand-no-std")] extern crate rand_package as rand; @@ -108,8 +126,6 @@ extern crate alloc; #[cfg(not(feature = "std"))] extern crate core as std; -#[cfg(feature = "io")] -extern crate pest; #[macro_use] #[cfg(feature = "io")] extern crate pest_derive; @@ -157,8 +173,8 @@ pub use simba::simd::{SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField, /// /// # See also: /// -/// * [`origin`](../nalgebra/fn.origin.html) -/// * [`zero`](fn.zero.html) +/// * [`origin()`](crate::OPoint::origin) +/// * [`zero()`] #[inline] pub fn one() -> T { T::one() @@ -168,8 +184,8 @@ pub fn one() -> T { /// /// # See also: /// -/// * [`one`](fn.one.html) -/// * [`origin`](../nalgebra/fn.origin.html) +/// * [`one()`] +/// * [`origin()`](crate::OPoint::origin) #[inline] pub fn zero() -> T { T::zero() @@ -246,7 +262,7 @@ pub fn min(a: T, b: T) -> T { /// The absolute value of `a`. /// -/// Deprecated: Use [`Matrix::abs`] or [`ComplexField::abs`] instead. +/// Deprecated: Use [`Matrix::abs()`] or [`ComplexField::abs()`] instead. #[deprecated(note = "use the inherent method `Matrix::abs` or `ComplexField::abs` instead")] #[inline] pub fn abs(a: &T) -> T { @@ -384,8 +400,8 @@ pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &' /// /// # See also: /// -/// * [distance](fn.distance.html) -/// * [`distance_squared`](fn.distance_squared.html) +/// * [`distance()`] +/// * [`distance_squared()`] #[inline] pub fn center( p1: &Point, @@ -398,8 +414,8 @@ pub fn center( /// /// # See also: /// -/// * [center](fn.center.html) -/// * [`distance_squared`](fn.distance_squared.html) +/// * [`center()`] +/// * [`distance_squared()`] #[inline] pub fn distance( p1: &Point, @@ -412,8 +428,8 @@ pub fn distance( /// /// # See also: /// -/// * [center](fn.center.html) -/// * [distance](fn.distance.html) +/// * [`center()`] +/// * [`distance()`] #[inline] pub fn distance_squared( p1: &Point, @@ -427,15 +443,15 @@ pub fn distance_squared( */ /// Converts an object from one type to an equivalent or more general one. /// -/// See also [`try_convert`](fn.try_convert.html) for conversion to more specific types. +/// See also [`try_convert()`] for conversion to more specific types. /// /// # See also: /// -/// * [`convert_ref`](fn.convert_ref.html) -/// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) -/// * [`is_convertible`](../nalgebra/fn.is_convertible.html) -/// * [`try_convert`](fn.try_convert.html) -/// * [`try_convert_ref`](fn.try_convert_ref.html) +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] #[inline] pub fn convert>(t: From) -> To { To::from_subset(&t) @@ -443,46 +459,46 @@ pub fn convert>(t: From) -> To { /// Attempts to convert an object to a more specific one. /// -/// See also [`convert`](fn.convert.html) for conversion to more general types. +/// See also [`convert()`] for conversion to more general types. /// /// # See also: /// -/// * [convert](fn.convert.html) -/// * [`convert_ref`](fn.convert_ref.html) -/// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) -/// * [`is_convertible`](../nalgebra/fn.is_convertible.html) -/// * [`try_convert_ref`](fn.try_convert_ref.html) +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert_ref()`] #[inline] pub fn try_convert, To>(t: From) -> Option { t.to_subset() } -/// Indicates if [`try_convert`](fn.try_convert.html) will succeed without +/// Indicates if [`try_convert()`] will succeed without /// actually performing the conversion. /// /// # See also: /// -/// * [convert](fn.convert.html) -/// * [`convert_ref`](fn.convert_ref.html) -/// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) -/// * [`try_convert`](fn.try_convert.html) -/// * [`try_convert_ref`](fn.try_convert_ref.html) +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] #[inline] pub fn is_convertible, To>(t: &From) -> bool { t.is_in_subset() } -/// Use with care! Same as [`try_convert`](fn.try_convert.html) but +/// Use with care! Same as [`try_convert()`] but /// without any property checks. /// /// # See also: /// -/// * [convert](fn.convert.html) -/// * [`convert_ref`](fn.convert_ref.html) -/// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) -/// * [`is_convertible`](../nalgebra/fn.is_convertible.html) -/// * [`try_convert`](fn.try_convert.html) -/// * [`try_convert_ref`](fn.try_convert_ref.html) +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] #[inline] pub fn convert_unchecked, To>(t: From) -> To { t.to_subset_unchecked() @@ -492,11 +508,11 @@ pub fn convert_unchecked, To>(t: From) -> To { /// /// # See also: /// -/// * [convert](fn.convert.html) -/// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) -/// * [`is_convertible`](../nalgebra/fn.is_convertible.html) -/// * [`try_convert`](fn.try_convert.html) -/// * [`try_convert_ref`](fn.try_convert_ref.html) +/// * [`convert()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] #[inline] pub fn convert_ref>(t: &From) -> To { To::from_subset(t) @@ -506,26 +522,26 @@ pub fn convert_ref>(t: &From) -> To { /// /// # See also: /// -/// * [convert](fn.convert.html) -/// * [`convert_ref`](fn.convert_ref.html) -/// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) -/// * [`is_convertible`](../nalgebra/fn.is_convertible.html) -/// * [`try_convert`](fn.try_convert.html) +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] #[inline] pub fn try_convert_ref, To>(t: &From) -> Option { t.to_subset() } -/// Use with care! Same as [`try_convert`](fn.try_convert.html) but +/// Use with care! Same as [`try_convert()`] but /// without any property checks. /// /// # See also: /// -/// * [convert](fn.convert.html) -/// * [`convert_ref`](fn.convert_ref.html) -/// * [`is_convertible`](../nalgebra/fn.is_convertible.html) -/// * [`try_convert`](fn.try_convert.html) -/// * [`try_convert_ref`](fn.try_convert_ref.html) +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] #[inline] pub fn convert_ref_unchecked, To>(t: &From) -> To { t.to_subset_unchecked() diff --git a/src/linalg/bidiagonal.rs b/src/linalg/bidiagonal.rs index c6b02975..4faa9c5a 100644 --- a/src/linalg/bidiagonal.rs +++ b/src/linalg/bidiagonal.rs @@ -8,6 +8,7 @@ use simba::scalar::ComplexField; use crate::geometry::Reflection; use crate::linalg::householder; +use crate::num::Zero; use std::mem::MaybeUninit; /// The bidiagonalization of a general matrix. @@ -202,7 +203,7 @@ where ); let start = self.axis_shift(); - res.slice_mut(start, (d.value() - 1, d.value() - 1)) + res.view_mut(start, (d.value() - 1, d.value() - 1)) .set_partial_diagonal( self.off_diagonal .iter() @@ -226,11 +227,15 @@ where let shift = self.axis_shift().0; for i in (0..dim - shift).rev() { - let axis = self.uv.slice_range(i + shift.., i); - // TODO: sometimes, the axis might have a zero magnitude. + let axis = self.uv.view_range(i + shift.., i); + + // Sometimes, the axis might have a zero magnitude. + if axis.norm_squared().is_zero() { + continue; + } let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); - let mut res_rows = res.slice_range_mut(i + shift.., i..); + let mut res_rows = res.view_range_mut(i + shift.., i..); let sign = if self.upper_diagonal { self.diagonal[i].clone().signum() @@ -260,13 +265,17 @@ where let shift = self.axis_shift().1; for i in (0..min_nrows_ncols.value() - shift).rev() { - let axis = self.uv.slice_range(i, i + shift..); + let axis = self.uv.view_range(i, i + shift..); let mut axis_packed = axis_packed.rows_range_mut(i + shift..); axis_packed.tr_copy_from(&axis); - // TODO: sometimes, the axis might have a zero magnitude. + + // Sometimes, the axis might have a zero magnitude. + if axis_packed.norm_squared().is_zero() { + continue; + } let refl = Reflection::new(Unit::new_unchecked(axis_packed), T::zero()); - let mut res_rows = res.slice_range_mut(i.., i + shift..); + let mut res_rows = res.view_range_mut(i.., i + shift..); let sign = if self.upper_diagonal { self.off_diagonal[i].clone().signum() @@ -304,7 +313,7 @@ where } } -// impl + DimSub> Bidiagonal +// impl + DimSub> Bidiagonal // where DefaultAllocator: Allocator + // Allocator { // /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. @@ -346,7 +355,7 @@ where // *b.vget_unchecked_mut(i) = coeff; // } // -// b.rows_range_mut(.. i).axpy(-coeff, &self.uv.slice_range(.. i, i), T::one()); +// b.rows_range_mut(.. i).axpy(-coeff, &self.uv.view_range(.. i, i), T::one()); // } // } // } diff --git a/src/linalg/cholesky.rs b/src/linalg/cholesky.rs index f61a4e63..02101748 100644 --- a/src/linalg/cholesky.rs +++ b/src/linalg/cholesky.rs @@ -1,7 +1,7 @@ #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Serialize}; -use num::One; +use num::{One, Zero}; use simba::scalar::ComplexField; use simba::simd::SimdComplexField; @@ -67,7 +67,7 @@ where *matrix.get_unchecked_mut((j, j)) = denom.clone(); } - let mut col = matrix.slice_range_mut(j + 1.., j); + let mut col = matrix.view_range_mut(j + 1.., j); col /= denom; } @@ -161,6 +161,27 @@ where } prod_diag.simd_modulus_squared() } + + /// Computes the natural logarithm of determinant of the decomposed matrix. + /// + /// This method is more robust than `.determinant()` to very small or very + /// large determinants since it returns the natural logarithm of the + /// determinant rather than the determinant itself. + #[must_use] + pub fn ln_determinant(&self) -> T::SimdRealField { + let dim = self.chol.nrows(); + let mut sum_diag = T::SimdRealField::zero(); + for i in 0..dim { + sum_diag += unsafe { + self.chol + .get_unchecked((i, i)) + .clone() + .simd_modulus_squared() + .simd_ln() + }; + } + sum_diag + } } impl Cholesky @@ -228,7 +249,7 @@ where *matrix.get_unchecked_mut((j, j)) = denom.clone(); } - let mut col = matrix.slice_range_mut(j + 1.., j); + let mut col = matrix.view_range_mut(j + 1.., j); col /= denom; continue; } @@ -283,17 +304,17 @@ where self.chol.shape_generic().0.add(Const::<1>), self.chol.shape_generic().1.add(Const::<1>), ); - chol.slice_range_mut(..j, ..j) - .copy_from(&self.chol.slice_range(..j, ..j)); - chol.slice_range_mut(..j, j + 1..) - .copy_from(&self.chol.slice_range(..j, j..)); - chol.slice_range_mut(j + 1.., ..j) - .copy_from(&self.chol.slice_range(j.., ..j)); - chol.slice_range_mut(j + 1.., j + 1..) - .copy_from(&self.chol.slice_range(j.., j..)); + chol.view_range_mut(..j, ..j) + .copy_from(&self.chol.view_range(..j, ..j)); + chol.view_range_mut(..j, j + 1..) + .copy_from(&self.chol.view_range(..j, j..)); + chol.view_range_mut(j + 1.., ..j) + .copy_from(&self.chol.view_range(j.., ..j)); + chol.view_range_mut(j + 1.., j + 1..) + .copy_from(&self.chol.view_range(j.., j..)); // update the jth row - let top_left_corner = self.chol.slice_range(..j, ..j); + let top_left_corner = self.chol.view_range(..j, ..j); let col_j = col[j].clone(); let (mut new_rowj_adjoint, mut new_colj) = col.rows_range_pair_mut(..j, j + 1..); @@ -302,14 +323,14 @@ where "Cholesky::insert_column : Unable to solve lower triangular system!" ); - new_rowj_adjoint.adjoint_to(&mut chol.slice_range_mut(j, ..j)); + new_rowj_adjoint.adjoint_to(&mut chol.view_range_mut(j, ..j)); // update the center element let center_element = T::sqrt(col_j - T::from_real(new_rowj_adjoint.norm_squared())); chol[(j, j)] = center_element.clone(); // update the jth column - let bottom_left_corner = self.chol.slice_range(j.., ..j); + let bottom_left_corner = self.chol.view_range(j.., ..j); // new_colj = (col_jplus - bottom_left_corner * new_rowj.adjoint()) / center_element; new_colj.gemm( -T::one() / center_element.clone(), @@ -317,10 +338,10 @@ where &new_rowj_adjoint, T::one() / center_element, ); - chol.slice_range_mut(j + 1.., j).copy_from(&new_colj); + chol.view_range_mut(j + 1.., j).copy_from(&new_colj); // update the bottom right corner - let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..); + let mut bottom_right_corner = chol.view_range_mut(j + 1.., j + 1..); Self::xx_rank_one_update( &mut bottom_right_corner, &mut new_colj, @@ -348,17 +369,17 @@ where self.chol.shape_generic().0.sub(Const::<1>), self.chol.shape_generic().1.sub(Const::<1>), ); - chol.slice_range_mut(..j, ..j) - .copy_from(&self.chol.slice_range(..j, ..j)); - chol.slice_range_mut(..j, j..) - .copy_from(&self.chol.slice_range(..j, j + 1..)); - chol.slice_range_mut(j.., ..j) - .copy_from(&self.chol.slice_range(j + 1.., ..j)); - chol.slice_range_mut(j.., j..) - .copy_from(&self.chol.slice_range(j + 1.., j + 1..)); + chol.view_range_mut(..j, ..j) + .copy_from(&self.chol.view_range(..j, ..j)); + chol.view_range_mut(..j, j..) + .copy_from(&self.chol.view_range(..j, j + 1..)); + chol.view_range_mut(j.., ..j) + .copy_from(&self.chol.view_range(j + 1.., ..j)); + chol.view_range_mut(j.., j..) + .copy_from(&self.chol.view_range(j + 1.., j + 1..)); // updates the bottom right corner - let mut bottom_right_corner = chol.slice_range_mut(j.., j..); + let mut bottom_right_corner = chol.view_range_mut(j.., j..); let mut workspace = self.chol.column(j).clone_owned(); let mut old_colj = workspace.rows_range_mut(j + 1..); Self::xx_rank_one_update(&mut bottom_right_corner, &mut old_colj, T::RealField::one()); @@ -370,7 +391,7 @@ where /// performs a rank one update such that we end up with the decomposition of `M + sigma * (x * x.adjoint())`. /// /// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column` - /// where it is used on a square slice of the decomposition + /// where it is used on a square view of the decomposition fn xx_rank_one_update( chol: &mut Matrix, x: &mut Vector, @@ -404,7 +425,7 @@ where beta += sigma_xj2 / diag2; // updates the terms of L let mut xjplus = x.rows_range_mut(j + 1..); - let mut col_j = chol.slice_range_mut(j + 1.., j); + let mut col_j = chol.view_range_mut(j + 1.., j); // temp_jplus -= (wj / T::from_real(diag)) * col_j; xjplus.axpy(-xj.clone() / T::from_real(diag.clone()), &col_j, T::one()); if gamma != crate::zero::() { diff --git a/src/linalg/col_piv_qr.rs b/src/linalg/col_piv_qr.rs index 822448e3..bd234b60 100644 --- a/src/linalg/col_piv_qr.rs +++ b/src/linalg/col_piv_qr.rs @@ -78,7 +78,7 @@ where let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>); for i in 0..min_nrows_ncols.value() { - let piv = matrix.slice_range(i.., i..).icamax_full(); + let piv = matrix.view_range(i.., i..).icamax_full(); let col_piv = piv.1 + i; matrix.swap_columns(i, col_piv); p.append_permutation(i, col_piv); @@ -144,11 +144,11 @@ where let dim = self.diag.len(); for i in (0..dim).rev() { - let axis = self.col_piv_qr.slice_range(i.., i); + let axis = self.col_piv_qr.view_range(i.., i); // TODO: sometimes, the axis might have a zero magnitude. let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); - let mut res_rows = res.slice_range_mut(i.., i..); + let mut res_rows = res.view_range_mut(i.., i..); refl.reflect_with_sign(&mut res_rows, self.diag[i].clone().signum()); } @@ -191,7 +191,7 @@ where let dim = self.diag.len(); for i in 0..dim { - let axis = self.col_piv_qr.slice_range(i.., i); + let axis = self.col_piv_qr.view_range(i.., i); let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); let mut rhs_rows = rhs.rows_range_mut(i..); @@ -281,7 +281,7 @@ where } b.rows_range_mut(..i) - .axpy(-coeff, &self.col_piv_qr.slice_range(..i, i), T::one()); + .axpy(-coeff, &self.col_piv_qr.view_range(..i, i), T::one()); } } diff --git a/src/linalg/convolution.rs b/src/linalg/convolution.rs index 2402bb3d..b0abe994 100644 --- a/src/linalg/convolution.rs +++ b/src/linalg/convolution.rs @@ -47,11 +47,11 @@ impl> Vector { let u_f = cmp::min(i, vec - 1); if u_i == u_f { - conv[i] += self[u_i].clone() * kernel[(i - u_i)].clone(); + conv[i] += self[u_i].clone() * kernel[i - u_i].clone(); } else { for u in u_i..(u_f + 1) { if i - u < ker { - conv[i] += self[u].clone() * kernel[(i - u)].clone(); + conv[i] += self[u].clone() * kernel[i - u].clone(); } } } diff --git a/src/linalg/eigen.rs b/src/linalg/eigen.rs index 37b5ddea..a1f6172e 100644 --- a/src/linalg/eigen.rs +++ b/src/linalg/eigen.rs @@ -8,7 +8,7 @@ use std::fmt::Display; use std::ops::MulAssign; use crate::allocator::Allocator; -use crate::base::dimension::{Dim, DimDiff, DimSub, Dynamic, U1, U2, U3}; +use crate::base::dimension::{Dim, DimDiff, DimSub, Dyn, U1, U2, U3}; use crate::base::storage::Storage; use crate::base::{ DefaultAllocator, Hessenberg, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3, @@ -52,8 +52,8 @@ where impl Eigen where - D: DimSub, // For Hessenberg. - ShapeConstraint: DimEq>, // For Hessenberg. + D: DimSub, // For Hessenberg. + ShapeConstraint: DimEq>, // For Hessenberg. DefaultAllocator: Allocator> + Allocator> + Allocator diff --git a/src/linalg/full_piv_lu.rs b/src/linalg/full_piv_lu.rs index b11bf4d6..2037e285 100644 --- a/src/linalg/full_piv_lu.rs +++ b/src/linalg/full_piv_lu.rs @@ -64,7 +64,7 @@ where } for i in 0..min_nrows_ncols.value() { - let piv = matrix.slice_range(i.., i..).icamax_full(); + let piv = matrix.view_range(i.., i..).icamax_full(); let row_piv = piv.0 + i; let col_piv = piv.1 + i; let diag = matrix[(row_piv, col_piv)].clone(); diff --git a/src/linalg/givens.rs b/src/linalg/givens.rs index 30e2bed3..dbd25439 100644 --- a/src/linalg/givens.rs +++ b/src/linalg/givens.rs @@ -17,7 +17,7 @@ pub struct GivensRotation { // Matrix = UnitComplex * Matrix impl GivensRotation { - /// The Givents rotation that does nothing. + /// The Givens rotation that does nothing. pub fn identity() -> Self { Self { c: T::RealField::one(), @@ -88,13 +88,13 @@ impl GivensRotation { } } - /// The cos part of this roration. + /// The cos part of this rotation. #[must_use] pub fn c(&self) -> T::RealField { self.c.clone() } - /// The sin part of this roration. + /// The sin part of this rotation. #[must_use] pub fn s(&self) -> T { self.s.clone() diff --git a/src/linalg/hessenberg.rs b/src/linalg/hessenberg.rs index 2f85d462..0313a0bb 100644 --- a/src/linalg/hessenberg.rs +++ b/src/linalg/hessenberg.rs @@ -113,7 +113,7 @@ where let dim = self.hess.nrows(); self.hess.fill_lower_triangle(T::zero(), 2); self.hess - .slice_mut((1, 0), (dim - 1, dim - 1)) + .view_mut((1, 0), (dim - 1, dim - 1)) .set_partial_diagonal( self.subdiag .iter() @@ -132,7 +132,7 @@ where let dim = self.hess.nrows(); let mut res = self.hess.clone(); res.fill_lower_triangle(T::zero(), 2); - res.slice_mut((1, 0), (dim - 1, dim - 1)) + res.view_mut((1, 0), (dim - 1, dim - 1)) .set_partial_diagonal( self.subdiag .iter() diff --git a/src/linalg/householder.rs b/src/linalg/householder.rs index 688930a3..dbae93f9 100644 --- a/src/linalg/householder.rs +++ b/src/linalg/householder.rs @@ -34,6 +34,17 @@ pub fn reflection_axis_mut>( if !factor.is_zero() { column.unscale_mut(factor.sqrt()); + + // Normalize again, making sure the vector is unit-sized. + // If `factor` had a very small value, the first normalization + // (dividing by `factor.sqrt()`) might end up with a slightly + // non-unit vector (especially when using 32-bits float). + // Decompositions strongly rely on that unit-vector property, + // so we run a second normalization (that is much more numerically + // stable since the norm is close to 1) to ensure it has a unit + // size. + let _ = column.normalize_mut(); + (-signed_norm, true) } else { // TODO: not sure why we don't have a - sign here. @@ -64,8 +75,8 @@ where if not_zero { let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); let sign = reflection_norm.clone().signum(); - if let Some(mut work) = bilateral { - refl.reflect_rows_with_sign(&mut right, &mut work, sign.clone()); + if let Some(work) = bilateral { + refl.reflect_rows_with_sign(&mut right, work, sign.clone()); } refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate()); } @@ -128,10 +139,10 @@ where let mut res = OMatrix::identity_generic(dim, dim); for i in (0..dim.value() - 1).rev() { - let axis = m.slice_range(i + 1.., i); + let axis = m.view_range(i + 1.., i); let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); - let mut res_rows = res.slice_range_mut(i + 1.., i..); + let mut res_rows = res.view_range_mut(i + 1.., i..); refl.reflect_with_sign(&mut res_rows, signs[i].clone().signum()); } diff --git a/src/linalg/inverse.rs b/src/linalg/inverse.rs index f07be14a..91d45587 100644 --- a/src/linalg/inverse.rs +++ b/src/linalg/inverse.rs @@ -8,7 +8,11 @@ use crate::base::{DefaultAllocator, OMatrix, SquareMatrix}; use crate::linalg::lu; impl> SquareMatrix { - /// Attempts to invert this matrix. + /// Attempts to invert this square matrix. + /// + /// # Panics + /// + /// Panics if `self` isn’t a square matrix. #[inline] #[must_use = "Did you mean to use try_inverse_mut()?"] pub fn try_inverse(self) -> Option> @@ -25,8 +29,12 @@ impl> SquareMatrix { } impl> SquareMatrix { - /// Attempts to invert this matrix in-place. Returns `false` and leaves `self` untouched if + /// Attempts to invert this square matrix in-place. Returns `false` and leaves `self` untouched if /// inversion fails. + /// + /// # Panics + /// + /// Panics if `self` isn’t a square matrix. #[inline] pub fn try_inverse_mut(&mut self) -> bool where diff --git a/src/linalg/lu.rs b/src/linalg/lu.rs index 01ae46f0..a5e87072 100644 --- a/src/linalg/lu.rs +++ b/src/linalg/lu.rs @@ -64,7 +64,7 @@ where out.fill_with_identity(); for i in 0..dim { - let piv = matrix.slice_range(i.., i).icamax() + i; + let piv = matrix.view_range(i.., i).icamax() + i; let diag = matrix[(piv, i)].clone(); if diag.is_zero() { @@ -100,7 +100,7 @@ where } for i in 0..min_nrows_ncols.value() { - let piv = matrix.slice_range(i.., i).icamax() + i; + let piv = matrix.view_range(i.., i).icamax() + i; let diag = matrix[(piv, i)].clone(); if diag.is_zero() { @@ -338,7 +338,7 @@ where T: Scalar + Field, S: StorageMut, { - let mut submat = matrix.slice_range_mut(i.., i..); + let mut submat = matrix.view_range_mut(i.., i..); let inv_diag = T::one() / diag; @@ -368,7 +368,7 @@ pub fn gauss_step_swap( S: StorageMut, { let piv = piv - i; - let mut submat = matrix.slice_range_mut(i.., i..); + let mut submat = matrix.view_range_mut(i.., i..); let inv_diag = T::one() / diag; diff --git a/src/linalg/permutation_sequence.rs b/src/linalg/permutation_sequence.rs index f4521988..9e4eb37b 100644 --- a/src/linalg/permutation_sequence.rs +++ b/src/linalg/permutation_sequence.rs @@ -7,7 +7,7 @@ use simba::scalar::ClosedNeg; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, OVector, Scalar}; #[cfg(any(feature = "std", feature = "alloc"))] -use crate::dimension::Dynamic; +use crate::dimension::Dyn; use crate::dimension::{Const, Dim, DimName}; use crate::storage::StorageMut; @@ -51,14 +51,14 @@ where } #[cfg(any(feature = "std", feature = "alloc"))] -impl PermutationSequence +impl PermutationSequence where - DefaultAllocator: Allocator<(usize, usize), Dynamic>, + DefaultAllocator: Allocator<(usize, usize), Dyn>, { /// Creates a new dynamically-allocated sequence of `n` identity permutations. #[inline] pub fn identity(n: usize) -> Self { - Self::identity_generic(Dynamic::new(n)) + Self::identity_generic(Dyn(n)) } } diff --git a/src/linalg/qr.rs b/src/linalg/qr.rs index 1b06e34b..54921939 100644 --- a/src/linalg/qr.rs +++ b/src/linalg/qr.rs @@ -116,11 +116,11 @@ where let dim = self.diag.len(); for i in (0..dim).rev() { - let axis = self.qr.slice_range(i.., i); + let axis = self.qr.view_range(i.., i); // TODO: sometimes, the axis might have a zero magnitude. let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); - let mut res_rows = res.slice_range_mut(i.., i..); + let mut res_rows = res.view_range_mut(i.., i..); refl.reflect_with_sign(&mut res_rows, self.diag[i].clone().signum()); } @@ -161,7 +161,7 @@ where let dim = self.diag.len(); for i in 0..dim { - let axis = self.qr.slice_range(i.., i); + let axis = self.qr.view_range(i.., i); let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); let mut rhs_rows = rhs.rows_range_mut(i..); @@ -247,7 +247,7 @@ where } b.rows_range_mut(..i) - .axpy(-coeff, &self.qr.slice_range(..i, i), T::one()); + .axpy(-coeff, &self.qr.view_range(..i, i), T::one()); } } diff --git a/src/linalg/schur.rs b/src/linalg/schur.rs index c7753cee..3f734723 100644 --- a/src/linalg/schur.rs +++ b/src/linalg/schur.rs @@ -8,7 +8,7 @@ use simba::scalar::{ComplexField, RealField}; use std::cmp; use crate::allocator::Allocator; -use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dynamic, U1, U2}; +use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dyn, U1, U2}; use crate::base::storage::Storage; use crate::base::{DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3}; @@ -174,19 +174,18 @@ where { let krows = cmp::min(k + 4, end + 1); let mut work = work.rows_mut(0, krows); - refl.reflect(&mut t.generic_slice_mut( - (k, k), - (Const::<3>, Dynamic::new(dim.value() - k)), - )); + refl.reflect( + &mut t.generic_view_mut((k, k), (Const::<3>, Dyn(dim.value() - k))), + ); refl.reflect_rows( - &mut t.generic_slice_mut((0, k), (Dynamic::new(krows), Const::<3>)), + &mut t.generic_view_mut((0, k), (Dyn(krows), Const::<3>)), &mut work, ); } if let Some(ref mut q) = q { refl.reflect_rows( - &mut q.generic_slice_mut((0, k), (dim, Const::<3>)), + &mut q.generic_view_mut((0, k), (dim, Const::<3>)), work, ); } @@ -211,38 +210,36 @@ where { let mut work = work.rows_mut(0, end + 1); - refl.reflect(&mut t.generic_slice_mut( - (m, m), - (Const::<2>, Dynamic::new(dim.value() - m)), - )); + refl.reflect( + &mut t.generic_view_mut((m, m), (Const::<2>, Dyn(dim.value() - m))), + ); refl.reflect_rows( - &mut t.generic_slice_mut((0, m), (Dynamic::new(end + 1), Const::<2>)), + &mut t.generic_view_mut((0, m), (Dyn(end + 1), Const::<2>)), &mut work, ); } if let Some(ref mut q) = q { - refl.reflect_rows( - &mut q.generic_slice_mut((0, m), (dim, Const::<2>)), - work, - ); + refl.reflect_rows(&mut q.generic_view_mut((0, m), (dim, Const::<2>)), work); } } } else { // Decouple the 2x2 block if it has real eigenvalues. - if let Some(rot) = compute_2x2_basis(&t.fixed_slice::<2, 2>(start, start)) { + if let Some(rot) = compute_2x2_basis(&t.fixed_view::<2, 2>(start, start)) { let inv_rot = rot.inverse(); - inv_rot.rotate(&mut t.generic_slice_mut( - (start, start), - (Const::<2>, Dynamic::new(dim.value() - start)), - )); + inv_rot.rotate( + &mut t.generic_view_mut( + (start, start), + (Const::<2>, Dyn(dim.value() - start)), + ), + ); rot.rotate_rows( - &mut t.generic_slice_mut((0, start), (Dynamic::new(end + 1), Const::<2>)), + &mut t.generic_view_mut((0, start), (Dyn(end + 1), Const::<2>)), ); t[(end, start)] = T::zero(); if let Some(ref mut q) = q { - rot.rotate_rows(&mut q.generic_slice_mut((0, start), (dim, Const::<2>))); + rot.rotate_rows(&mut q.generic_view_mut((0, start), (dim, Const::<2>))); } } @@ -427,9 +424,9 @@ where { let dim = m.shape_generic().0; let mut q = None; - match compute_2x2_basis(&m.fixed_slice::<2, 2>(0, 0)) { + match compute_2x2_basis(&m.fixed_view::<2, 2>(0, 0)) { Some(rot) => { - let mut m = m.fixed_slice_mut::<2, 2>(0, 0); + let mut m = m.fixed_view_mut::<2, 2>(0, 0); let inv_rot = rot.inverse(); inv_rot.rotate(&mut m); rot.rotate_rows(&mut m); @@ -530,7 +527,7 @@ where if self.nrows() == 2 { // TODO: can we avoid this slicing // (which is needed here just to transform D to U2)? - let me = self.fixed_slice::<2, 2>(0, 0); + let me = self.fixed_view::<2, 2>(0, 0); return match compute_2x2_eigvals(&me) { Some((a, b)) => { work[0] = a; diff --git a/src/linalg/solve.rs b/src/linalg/solve.rs index 7409e7fb..237986a8 100644 --- a/src/linalg/solve.rs +++ b/src/linalg/solve.rs @@ -5,7 +5,7 @@ use crate::base::allocator::Allocator; use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::base::dimension::{Dim, U1}; use crate::base::storage::{Storage, StorageMut}; -use crate::base::{DVectorSlice, DefaultAllocator, Matrix, OMatrix, SquareMatrix, Vector}; +use crate::base::{DVectorView, DefaultAllocator, Matrix, OMatrix, SquareMatrix, Vector}; impl> SquareMatrix { /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only @@ -93,7 +93,7 @@ impl> SquareMatrix { } b.rows_range_mut(i + 1..) - .axpy(-coeff, &self.slice_range(i + 1.., i), T::one()); + .axpy(-coeff, &self.view_range(i + 1.., i), T::one()); } true @@ -125,7 +125,7 @@ impl> SquareMatrix { for i in 0..dim - 1 { let coeff = unsafe { bcol.vget_unchecked(i).clone() } / diag.clone(); bcol.rows_range_mut(i + 1..) - .axpy(-coeff, &self.slice_range(i + 1.., i), T::one()); + .axpy(-coeff, &self.view_range(i + 1.., i), T::one()); } } @@ -175,7 +175,7 @@ impl> SquareMatrix { } b.rows_range_mut(..i) - .axpy(-coeff, &self.slice_range(..i, i), T::one()); + .axpy(-coeff, &self.view_range(..i, i), T::one()); } true @@ -376,8 +376,8 @@ impl> SquareMatrix { b: &mut Vector, conjugate: impl Fn(T) -> T, dot: impl Fn( - &DVectorSlice<'_, T, S::RStride, S::CStride>, - &DVectorSlice<'_, T, S2::RStride, S2::CStride>, + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, ) -> T, ) -> bool where @@ -387,7 +387,7 @@ impl> SquareMatrix { let dim = self.nrows(); for i in (0..dim).rev() { - let dot = dot(&self.slice_range(i + 1.., i), &b.slice_range(i + 1.., 0)); + let dot = dot(&self.view_range(i + 1.., i), &b.view_range(i + 1.., 0)); unsafe { let b_i = b.vget_unchecked_mut(i); @@ -411,8 +411,8 @@ impl> SquareMatrix { b: &mut Vector, conjugate: impl Fn(T) -> T, dot: impl Fn( - &DVectorSlice<'_, T, S::RStride, S::CStride>, - &DVectorSlice<'_, T, S2::RStride, S2::CStride>, + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, ) -> T, ) -> bool where @@ -422,7 +422,7 @@ impl> SquareMatrix { let dim = self.nrows(); for i in 0..dim { - let dot = dot(&self.slice_range(..i, i), &b.slice_range(..i, 0)); + let dot = dot(&self.view_range(..i, i), &b.view_range(..i, 0)); unsafe { let b_i = b.vget_unchecked_mut(i); @@ -514,7 +514,7 @@ impl> SquareMatrix { } b.rows_range_mut(i + 1..) - .axpy(-coeff.clone(), &self.slice_range(i + 1.., i), T::one()); + .axpy(-coeff.clone(), &self.view_range(i + 1.., i), T::one()); } } @@ -539,7 +539,7 @@ impl> SquareMatrix { for i in 0..dim - 1 { let coeff = unsafe { bcol.vget_unchecked(i).clone() } / diag.clone(); bcol.rows_range_mut(i + 1..) - .axpy(-coeff, &self.slice_range(i + 1.., i), T::one()); + .axpy(-coeff, &self.view_range(i + 1.., i), T::one()); } } } @@ -575,7 +575,7 @@ impl> SquareMatrix { } b.rows_range_mut(..i) - .axpy(-coeff, &self.slice_range(..i, i), T::one()); + .axpy(-coeff, &self.view_range(..i, i), T::one()); } } @@ -734,8 +734,8 @@ impl> SquareMatrix { b: &mut Vector, conjugate: impl Fn(T) -> T, dot: impl Fn( - &DVectorSlice<'_, T, S::RStride, S::CStride>, - &DVectorSlice<'_, T, S2::RStride, S2::CStride>, + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, ) -> T, ) where S2: StorageMut, @@ -744,7 +744,7 @@ impl> SquareMatrix { let dim = self.nrows(); for i in (0..dim).rev() { - let dot = dot(&self.slice_range(i + 1.., i), &b.slice_range(i + 1.., 0)); + let dot = dot(&self.view_range(i + 1.., i), &b.view_range(i + 1.., 0)); unsafe { let b_i = b.vget_unchecked_mut(i); @@ -760,15 +760,15 @@ impl> SquareMatrix { b: &mut Vector, conjugate: impl Fn(T) -> T, dot: impl Fn( - &DVectorSlice<'_, T, S::RStride, S::CStride>, - &DVectorSlice<'_, T, S2::RStride, S2::CStride>, + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, ) -> T, ) where S2: StorageMut, ShapeConstraint: SameNumberOfRows, { for i in 0..self.nrows() { - let dot = dot(&self.slice_range(..i, i), &b.slice_range(..i, 0)); + let dot = dot(&self.view_range(..i, i), &b.view_range(..i, 0)); unsafe { let b_i = b.vget_unchecked_mut(i); diff --git a/src/linalg/svd.rs b/src/linalg/svd.rs index 06bae4a3..39283e24 100644 --- a/src/linalg/svd.rs +++ b/src/linalg/svd.rs @@ -724,7 +724,7 @@ where /// Sort the estimated components of the SVD by its singular values in descending order. /// Such an ordering is often implicitly required when the decompositions are used for estimation or fitting purposes. - /// Using this function is only required if `new_unordered` or `try_new_unorderd` were used and the specific sorting is required afterward. + /// Using this function is only required if `new_unordered` or `try_new_unordered` were used and the specific sorting is required afterward. pub fn sort_by_singular_values(&mut self) { const VALUE_PROCESSED: usize = usize::MAX; diff --git a/src/linalg/svd2.rs b/src/linalg/svd2.rs index 3bbd9a1b..f23fed50 100644 --- a/src/linalg/svd2.rs +++ b/src/linalg/svd2.rs @@ -21,7 +21,7 @@ pub fn svd_ordered2( // because q >= 0 and r >= 0. let sx = q.clone() + r.clone(); let sy = q - r; - let sy_sign = if sy < T::zero() { -one.clone() } else { one }; + let sy_sign = if sy < T::zero() { -one } else { one }; let singular_values = Vector2::new(sx, sy * sy_sign.clone()); if compute_u || compute_v { diff --git a/src/linalg/svd3.rs b/src/linalg/svd3.rs index b36e0889..a8c39d28 100644 --- a/src/linalg/svd3.rs +++ b/src/linalg/svd3.rs @@ -13,7 +13,7 @@ pub fn svd_ordered3( eps: T, niter: usize, ) -> Option> { - let s = m.tr_mul(&m); + let s = m.tr_mul(m); let mut v = s.try_symmetric_eigen(eps, niter)?.eigenvectors; let mut b = m * &v; diff --git a/src/linalg/symmetric_eigen.rs b/src/linalg/symmetric_eigen.rs index 61e1d0c1..70cad8a1 100644 --- a/src/linalg/symmetric_eigen.rs +++ b/src/linalg/symmetric_eigen.rs @@ -360,7 +360,7 @@ mod test { #[test] fn wilkinson_shift_random() { for _ in 0..1000 { - let m = Matrix2::new_random(); + let m = Matrix2::::new_random(); let m = m * m.transpose(); let expected = expected_shift(m); diff --git a/src/proptest/mod.rs b/src/proptest/mod.rs index a7cbe549..6701be7c 100644 --- a/src/proptest/mod.rs +++ b/src/proptest/mod.rs @@ -16,17 +16,17 @@ //! provides tools for generating matrices and vectors, and not any of the geometry types. //! There are essentially two ways of using this functionality: //! -//! - Using the [matrix](fn.matrix.html) function to generate matrices with constraints +//! - Using the [`matrix()`] function to generate matrices with constraints //! on dimensions and elements. -//! - Relying on the `Arbitrary` implementation of `OMatrix`. +//! - Relying on the [`Arbitrary`] implementation of [`OMatrix`]. //! //! The first variant is almost always preferred in practice. Read on to discover why. //! //! ### Using free function strategies //! //! In `proptest`, it is usually preferable to have free functions that generate *strategies*. -//! Currently, the [matrix](fn.matrix.html) function fills this role. The analogous function for -//! column vectors is [vector](fn.vector.html). Let's take a quick look at how it may be used: +//! Currently, the [`matrix()`] function fills this role. The analogous function for +//! column vectors is [`vector()`]. Let's take a quick look at how it may be used: //! ``` //! use nalgebra::proptest::matrix; //! use proptest::prelude::*; @@ -50,14 +50,14 @@ //! For example, let's consider a toy example where we need to generate pairs of matrices //! with exactly 3 rows fixed at compile-time and the same number of columns, but we want the //! number of columns to vary. One way to do this is to use `proptest` combinators in combination -//! with [matrix](fn.matrix.html) as follows: +//! with [`matrix()`] as follows: //! //! ``` -//! use nalgebra::{Dynamic, OMatrix, Const}; +//! use nalgebra::{Dyn, OMatrix, Const}; //! use nalgebra::proptest::matrix; //! use proptest::prelude::*; //! -//! type MyMatrix = OMatrix, Dynamic>; +//! type MyMatrix = OMatrix, Dyn>; //! //! /// Returns a strategy for pairs of matrices with `U3` rows and the same number of //! /// columns. @@ -93,7 +93,7 @@ //! If you don't care about the dimensions of matrices, you can write tests like these: //! //! ``` -//! use nalgebra::{DMatrix, DVector, Dynamic, Matrix3, OMatrix, Vector3, U3}; +//! use nalgebra::{DMatrix, DVector, Dyn, Matrix3, OMatrix, Vector3, U3}; //! use proptest::prelude::*; //! //! proptest! { @@ -108,7 +108,7 @@ //! # /* //! #[test] //! # */ -//! fn test_static_and_mixed(matrix: Matrix3, matrix2: OMatrix) { +//! fn test_static_and_mixed(matrix: Matrix3, matrix2: OMatrix) { //! // Test some property involving these matrices //! } //! @@ -141,7 +141,7 @@ //! PROPTEST_MAX_SHRINK_ITERS=100000 cargo test my_failing_test //! ``` use crate::allocator::Allocator; -use crate::{Const, DefaultAllocator, Dim, DimName, Dynamic, OMatrix, Scalar, U1}; +use crate::{Const, DefaultAllocator, Dim, DimName, Dyn, OMatrix, Scalar, U1}; use proptest::arbitrary::Arbitrary; use proptest::collection::vec; use proptest::strategy::{BoxedStrategy, Just, NewTree, Strategy, ValueTree}; @@ -167,9 +167,9 @@ pub struct MatrixParameters { /// of matrices with `proptest`. In most cases, you do not need to concern yourself with /// `DimRange` directly, as it supports conversion from other types such as `U3` or inclusive /// ranges such as `5 ..= 6`. The latter example corresponds to dimensions from (inclusive) -/// `Dynamic::new(5)` to `Dynamic::new(6)` (inclusive). +/// `Dyn(5)` to `Dyn(6)` (inclusive). #[derive(Debug, Clone, PartialEq, Eq)] -pub struct DimRange(RangeInclusive); +pub struct DimRange(RangeInclusive); impl DimRange { /// The lower bound for dimensions generated. @@ -195,9 +195,9 @@ impl From> for DimRange { } } -impl From> for DimRange { +impl From> for DimRange { fn from(range: RangeInclusive) -> Self { - DimRange::from(Dynamic::new(*range.start())..=Dynamic::new(*range.end())) + DimRange::from(Dyn(*range.start())..=Dyn(*range.end())) } } @@ -208,14 +208,14 @@ impl DimRange { } } -impl From for DimRange { +impl From for DimRange { fn from(dim: usize) -> Self { - DimRange::from(Dynamic::new(dim)) + DimRange::from(Dyn(dim)) } } -/// The default range used for Dynamic dimensions when generating arbitrary matrices. -fn dynamic_dim_range() -> DimRange { +/// The default range used for Dyn dimensions when generating arbitrary matrices. +fn dynamic_dim_range() -> DimRange { DimRange::from(0..=6) } @@ -225,7 +225,7 @@ fn dynamic_dim_range() -> DimRange { /// ## Examples /// ``` /// use nalgebra::proptest::matrix; -/// use nalgebra::{OMatrix, Const, Dynamic}; +/// use nalgebra::{OMatrix, Const, Dyn}; /// use proptest::prelude::*; /// /// proptest! { @@ -234,7 +234,7 @@ fn dynamic_dim_range() -> DimRange { /// # */ /// fn my_test(a in matrix(0 .. 5i32, Const::<3>, 0 ..= 5)) { /// // Let's make sure we've got the correct type first -/// let a: OMatrix<_, Const::<3>, Dynamic> = a; +/// let a: OMatrix<_, Const::<3>, Dyn> = a; /// prop_assert!(a.nrows() == 3); /// prop_assert!(a.ncols() <= 5); /// prop_assert!(a.iter().all(|x_ij| *x_ij >= 0 && *x_ij < 5)); @@ -316,7 +316,7 @@ where /// with length in the provided range. /// /// This is a convenience function for calling -/// [`matrix(value_strategy, length, U1)`](fn.matrix.html) and should +/// [`matrix(value_strategy, length, U1)`](crate::matrix) and should /// be used when you only want to generate column vectors, as it's simpler and makes the intent /// clear. pub fn vector( @@ -347,7 +347,7 @@ where } } -impl Default for MatrixParameters +impl Default for MatrixParameters where NParameters: Default, R: DimName, @@ -361,7 +361,7 @@ where } } -impl Default for MatrixParameters +impl Default for MatrixParameters where NParameters: Default, C: DimName, @@ -375,7 +375,7 @@ where } } -impl Default for MatrixParameters +impl Default for MatrixParameters where NParameters: Default, { diff --git a/src/sparse/cs_matrix.rs b/src/sparse/cs_matrix.rs index 14f8d41e..9a240ff6 100644 --- a/src/sparse/cs_matrix.rs +++ b/src/sparse/cs_matrix.rs @@ -7,7 +7,7 @@ use std::slice; use crate::allocator::Allocator; use crate::sparse::cs_utils; -use crate::{Const, DefaultAllocator, Dim, Dynamic, Matrix, OVector, Scalar, Vector, U1}; +use crate::{Const, DefaultAllocator, Dim, Dyn, Matrix, OVector, Scalar, Vector, U1}; pub struct ColumnEntries<'a, T> { curr: usize, @@ -236,16 +236,16 @@ impl CsStorageMut for CsVecStorage pub struct CsSliceStorage<'a, T: Scalar, R: Dim, C: DimAdd> { shape: (R, C), p: VectorSlice>, - i: VectorSlice, - vals: VectorSlice, + i: VectorSlice, + vals: VectorSlice, }*/ /// A compressed sparse column matrix. #[derive(Clone, Debug, PartialEq)] pub struct CsMatrix< T: Scalar, - R: Dim = Dynamic, - C: Dim = Dynamic, + R: Dim = Dyn, + C: Dim = Dyn, S: CsStorage = CsVecStorage, > { pub(crate) data: S, @@ -253,7 +253,7 @@ pub struct CsMatrix< } /// A column compressed sparse vector. -pub type CsVector> = CsMatrix; +pub type CsVector> = CsMatrix; impl CsMatrix where @@ -342,8 +342,8 @@ impl CsMatrix { vals: Vec, ) -> Self { - let nrows = Dynamic::new(nrows); - let ncols = Dynamic::new(ncols); + let nrows = Dyn(nrows); + let ncols = Dyn(ncols); let p = DVector::from_data(VecStorage::new(ncols, U1, p)); Self::from_parts_generic(nrows, ncols, p, i, vals) } @@ -498,7 +498,7 @@ where } } - // Remove dupliate entries on a sorted CsMatrix. + // Remove duplicate entries on a sorted CsMatrix. pub(crate) fn dedup(&mut self) where T: Zero + ClosedAdd, diff --git a/src/sparse/cs_matrix_conversion.rs b/src/sparse/cs_matrix_conversion.rs index e7ff8c36..4154f452 100644 --- a/src/sparse/cs_matrix_conversion.rs +++ b/src/sparse/cs_matrix_conversion.rs @@ -5,7 +5,7 @@ use crate::allocator::Allocator; use crate::sparse::cs_utils; use crate::sparse::{CsMatrix, CsStorage}; use crate::storage::Storage; -use crate::{DefaultAllocator, Dim, Dynamic, Matrix, OMatrix, Scalar}; +use crate::{DefaultAllocator, Dim, Dyn, Matrix, OMatrix, Scalar}; impl<'a, T: Scalar + Zero + ClosedAdd> CsMatrix { /// Creates a column-compressed sparse matrix from a sparse matrix in triplet form. @@ -16,7 +16,7 @@ impl<'a, T: Scalar + Zero + ClosedAdd> CsMatrix { icols: &[usize], vals: &[T], ) -> Self { - Self::from_triplet_generic(Dynamic::new(nrows), Dynamic::new(ncols), irows, icols, vals) + Self::from_triplet_generic(Dyn(nrows), Dyn(ncols), irows, icols, vals) } } diff --git a/src/third_party/glam/common/glam_isometry.rs b/src/third_party/glam/common/glam_isometry.rs index 3a8d4961..7b188c39 100644 --- a/src/third_party/glam/common/glam_isometry.rs +++ b/src/third_party/glam/common/glam_isometry.rs @@ -1,5 +1,5 @@ use super::glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; -use crate::{Isometry2, Isometry3, Matrix3, Matrix4, Translation3, UnitQuaternion, Vector2}; +use crate::{Isometry2, Isometry3, Matrix3, Matrix4, Translation3, UnitQuaternion}; use std::convert::TryFrom; impl From> for Mat3 { @@ -36,18 +36,18 @@ impl From> for (DVec3, DQuat) { } } -impl From> for (Vec3, Quat) { - fn from(iso: Isometry2) -> (Vec3, Quat) { - let tra = Vec3::new(iso.translation.x, iso.translation.y, 0.0); - let rot = Quat::from_axis_angle(Vec3::Z, iso.rotation.angle()); +impl From> for (Vec2, f32) { + fn from(iso: Isometry2) -> (Vec2, f32) { + let tra = Vec2::new(iso.translation.x, iso.translation.y); + let rot = iso.rotation.angle(); (tra, rot) } } -impl From> for (DVec3, DQuat) { - fn from(iso: Isometry2) -> (DVec3, DQuat) { - let tra = DVec3::new(iso.translation.x, iso.translation.y, 0.0); - let rot = DQuat::from_axis_angle(DVec3::Z, iso.rotation.angle()); +impl From> for (DVec2, f64) { + fn from(iso: Isometry2) -> (DVec2, f64) { + let tra = DVec2::new(iso.translation.x, iso.translation.y); + let rot = iso.rotation.angle(); (tra, rot) } } @@ -64,30 +64,6 @@ impl From<(DVec3, DQuat)> for Isometry3 { } } -impl From<(Vec3, Quat)> for Isometry2 { - fn from((tra, rot): (Vec3, Quat)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) - } -} - -impl From<(DVec3, DQuat)> for Isometry2 { - fn from((tra, rot): (DVec3, DQuat)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) - } -} - -impl From<(Vec2, Quat)> for Isometry2 { - fn from((tra, rot): (Vec2, Quat)) -> Self { - Isometry2::new(tra.into(), rot.to_axis_angle().1) - } -} - -impl From<(DVec2, DQuat)> for Isometry2 { - fn from((tra, rot): (DVec2, DQuat)) -> Self { - Isometry2::new(tra.into(), rot.to_axis_angle().1) - } -} - impl From<(Vec2, f32)> for Isometry2 { fn from((tra, rot): (Vec2, f32)) -> Self { Isometry2::new(tra.into(), rot) @@ -112,18 +88,6 @@ impl From for Isometry3 { } } -impl From for Isometry2 { - fn from(rot: Quat) -> Self { - Isometry2::new(Vector2::zeros(), rot.to_axis_angle().1) - } -} - -impl From for Isometry2 { - fn from(rot: DQuat) -> Self { - Isometry2::new(Vector2::zeros(), rot.to_axis_angle().1) - } -} - impl From for Isometry3 { fn from(tra: Vec3) -> Self { Isometry3::from_parts(tra.into(), UnitQuaternion::identity()) @@ -148,18 +112,6 @@ impl From for Isometry2 { } } -impl From for Isometry2 { - fn from(tra: Vec3) -> Self { - Isometry2::new([tra.x, tra.y].into(), 0.0) - } -} - -impl From for Isometry2 { - fn from(tra: DVec3) -> Self { - Isometry2::new([tra.x, tra.y].into(), 0.0) - } -} - impl TryFrom for Isometry2 { type Error = (); diff --git a/src/third_party/glam/common/glam_matrix.rs b/src/third_party/glam/common/glam_matrix.rs index 80f88054..26f58803 100644 --- a/src/third_party/glam/common/glam_matrix.rs +++ b/src/third_party/glam/common/glam_matrix.rs @@ -3,14 +3,18 @@ use super::glam::{ Mat4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4, }; use crate::storage::RawStorage; -use crate::{Matrix, Matrix2, Matrix3, Matrix4, Vector, Vector2, Vector3, Vector4, U2, U3, U4}; +use crate::{ + Matrix, Matrix2, Matrix3, Matrix4, Unit, UnitVector2, UnitVector3, UnitVector4, Vector, + Vector2, Vector3, Vector4, U2, U3, U4, +}; +use std::convert::TryFrom; macro_rules! impl_vec_conversion( ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { impl From<$Vec2> for Vector2<$N> { #[inline] fn from(e: $Vec2) -> Vector2<$N> { - (*e.as_ref()).into() + <[$N;2]>::from(e).into() } } @@ -27,7 +31,7 @@ macro_rules! impl_vec_conversion( impl From<$Vec3> for Vector3<$N> { #[inline] fn from(e: $Vec3) -> Vector3<$N> { - (*e.as_ref()).into() + <[$N;3]>::from(e).into() } } @@ -44,7 +48,7 @@ macro_rules! impl_vec_conversion( impl From<$Vec4> for Vector4<$N> { #[inline] fn from(e: $Vec4) -> Vector4<$N> { - (*e.as_ref()).into() + <[$N;4]>::from(e).into() } } @@ -66,6 +70,63 @@ impl_vec_conversion!(i32, IVec2, IVec3, IVec4); impl_vec_conversion!(u32, UVec2, UVec3, UVec4); impl_vec_conversion!(bool, BVec2, BVec3, BVec4); +const ERR: &'static str = "Normalization failed."; + +macro_rules! impl_unit_vec_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl TryFrom<$Vec2> for UnitVector2<$N> { + type Error = &'static str; + #[inline] + fn try_from(e: $Vec2) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } + } + + impl From> for $Vec2 + { + #[inline] + fn from(e: UnitVector2<$N>) -> $Vec2 { + e.into_inner().into() + } + } + + impl TryFrom<$Vec3> for UnitVector3<$N> { + type Error = &'static str; + #[inline] + fn try_from(e: $Vec3) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } + } + + impl From> for $Vec3 + { + #[inline] + fn from(e: UnitVector3<$N>) -> $Vec3 { + e.into_inner().into() + } + } + + impl TryFrom<$Vec4> for UnitVector4<$N> { + type Error = &'static str; + #[inline] + fn try_from(e: $Vec4) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } + } + + impl From> for $Vec4 + { + #[inline] + fn from(e: UnitVector4<$N>) -> $Vec4 { + e.into_inner().into() + } + } + } +); + +impl_unit_vec_conversion!(f32, Vec2, Vec3, Vec4); +impl_unit_vec_conversion!(f64, DVec2, DVec3, DVec4); + impl From for Vector3 { #[inline] fn from(e: Vec3A) -> Vector3 { @@ -83,6 +144,21 @@ where } } +impl TryFrom for UnitVector3 { + type Error = &'static str; + #[inline] + fn try_from(e: Vec3A) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } +} + +impl From> for Vec3A { + #[inline] + fn from(e: UnitVector3) -> Vec3A { + e.into_inner().into() + } +} + impl From for Matrix2 { #[inline] fn from(e: Mat2) -> Matrix2 { diff --git a/src/third_party/glam/common/glam_point.rs b/src/third_party/glam/common/glam_point.rs index b15a6c6d..205986b8 100644 --- a/src/third_party/glam/common/glam_point.rs +++ b/src/third_party/glam/common/glam_point.rs @@ -9,7 +9,7 @@ macro_rules! impl_point_conversion( impl From<$Vec2> for Point2<$N> { #[inline] fn from(e: $Vec2) -> Point2<$N> { - (*e.as_ref()).into() + <[$N;2]>::from(e).into() } } @@ -23,7 +23,7 @@ macro_rules! impl_point_conversion( impl From<$Vec3> for Point3<$N> { #[inline] fn from(e: $Vec3) -> Point3<$N> { - (*e.as_ref()).into() + <[$N;3]>::from(e).into() } } @@ -37,7 +37,7 @@ macro_rules! impl_point_conversion( impl From<$Vec4> for Point4<$N> { #[inline] fn from(e: $Vec4) -> Point4<$N> { - (*e.as_ref()).into() + <[$N;4]>::from(e).into() } } diff --git a/src/third_party/glam/mod.rs b/src/third_party/glam/mod.rs index d24ff7e5..680e65e5 100644 --- a/src/third_party/glam/mod.rs +++ b/src/third_party/glam/mod.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "glam013")] -mod v013; #[cfg(feature = "glam014")] mod v014; #[cfg(feature = "glam015")] @@ -14,3 +12,13 @@ mod v018; mod v019; #[cfg(feature = "glam020")] mod v020; +#[cfg(feature = "glam021")] +mod v021; +#[cfg(feature = "glam022")] +mod v022; +#[cfg(feature = "glam023")] +mod v023; +#[cfg(feature = "glam024")] +mod v024; +#[cfg(feature = "glam025")] +mod v025; diff --git a/src/third_party/glam/v013/mod.rs b/src/third_party/glam/v021/mod.rs similarity index 93% rename from src/third_party/glam/v013/mod.rs rename to src/third_party/glam/v021/mod.rs index 4787fb21..d0168923 100644 --- a/src/third_party/glam/v013/mod.rs +++ b/src/third_party/glam/v021/mod.rs @@ -15,4 +15,4 @@ mod glam_translation; #[path = "../common/glam_unit_complex.rs"] mod glam_unit_complex; -pub(self) use glam013 as glam; +pub(self) use glam021 as glam; diff --git a/src/third_party/glam/v022/mod.rs b/src/third_party/glam/v022/mod.rs new file mode 100644 index 00000000..de27f929 --- /dev/null +++ b/src/third_party/glam/v022/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam022 as glam; diff --git a/src/third_party/glam/v023/mod.rs b/src/third_party/glam/v023/mod.rs new file mode 100644 index 00000000..45b1ad47 --- /dev/null +++ b/src/third_party/glam/v023/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam023 as glam; diff --git a/src/third_party/glam/v024/mod.rs b/src/third_party/glam/v024/mod.rs new file mode 100644 index 00000000..3dae276f --- /dev/null +++ b/src/third_party/glam/v024/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam024 as glam; diff --git a/src/third_party/glam/v025/mod.rs b/src/third_party/glam/v025/mod.rs new file mode 100644 index 00000000..b9f41e34 --- /dev/null +++ b/src/third_party/glam/v025/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam025 as glam; diff --git a/tests/core/conversion.rs b/tests/core/conversion.rs index 5374c399..096f235b 100644 --- a/tests/core/conversion.rs +++ b/tests/core/conversion.rs @@ -7,7 +7,7 @@ use na::{ RowVector5, RowVector6, Similarity3, Transform3, UnitQuaternion, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, }; -use na::{DMatrix, DMatrixSlice, DMatrixSliceMut, MatrixSlice, MatrixSliceMut}; +use na::{DMatrix, DMatrixView, DMatrixViewMut, MatrixView, MatrixViewMut}; use na::{U1, U3, U4}; use crate::proptest::*; @@ -266,24 +266,24 @@ fn matrix_slice_from_matrix_ref() { // Note: these have to be macros, and not functions, because the input type is different // across the different tests. Moreover, the output type depends on the stride of the input, // which is different for static and dynamic matrices. - macro_rules! dynamic_slice { + macro_rules! dynamic_view { ($mref:expr) => { - DMatrixSlice::<_>::from($mref) + DMatrixView::<_>::from($mref) }; } - macro_rules! dynamic_slice_mut { + macro_rules! dynamic_view_mut { ($mref:expr) => { - DMatrixSliceMut::<_>::from($mref) + DMatrixViewMut::<_>::from($mref) }; } - macro_rules! fixed_slice { + macro_rules! fixed_view { ($mref:expr) => { - MatrixSlice::<_, U3, U4, U1, U3>::from($mref) + MatrixView::<_, U3, U4, U1, U3>::from($mref) }; } - macro_rules! fixed_slice_mut { + macro_rules! fixed_view_mut { ($mref:expr) => { - MatrixSliceMut::<_, U3, U4, U1, U3>::from($mref) + MatrixViewMut::<_, U3, U4, U1, U3>::from($mref) }; } @@ -291,66 +291,66 @@ fn matrix_slice_from_matrix_ref() { // Self and RHS. See issue #674. Once this is implemented, we can remove `into_owned` // from the below tests. - // Construct slices from reference to a + // Construct views from reference to a { - assert_eq!(a, fixed_slice!(&a).into_owned()); - assert_eq!(d, dynamic_slice!(&a).into_owned()); + assert_eq!(a, fixed_view!(&a).into_owned()); + assert_eq!(d, dynamic_view!(&a).into_owned()); } - // Construct slices from mutable reference to a + // Construct views from mutable reference to a { let mut a_clone = a.clone(); - assert_eq!(a, fixed_slice!(&mut a_clone).into_owned()); - assert_eq!(d, dynamic_slice!(&mut a_clone).into_owned()); + assert_eq!(a, fixed_view!(&mut a_clone).into_owned()); + assert_eq!(d, dynamic_view!(&mut a_clone).into_owned()); } // Construct mutable slices from mutable reference to a { let mut a_clone = a.clone(); - assert_eq!(a, fixed_slice_mut!(&mut a_clone).into_owned()); - assert_eq!(d, dynamic_slice_mut!(&mut a_clone).into_owned()); + assert_eq!(a, fixed_view_mut!(&mut a_clone).into_owned()); + assert_eq!(d, dynamic_view_mut!(&mut a_clone).into_owned()); } // Construct slices from reference to d { - assert_eq!(a, fixed_slice!(&d).into_owned()); - assert_eq!(d, dynamic_slice!(&d).into_owned()); + assert_eq!(a, fixed_view!(&d).into_owned()); + assert_eq!(d, dynamic_view!(&d).into_owned()); } // Construct slices from mutable reference to d { let mut d_clone = a.clone(); - assert_eq!(a, fixed_slice!(&mut d_clone).into_owned()); - assert_eq!(d, dynamic_slice!(&mut d_clone).into_owned()); + assert_eq!(a, fixed_view!(&mut d_clone).into_owned()); + assert_eq!(d, dynamic_view!(&mut d_clone).into_owned()); } // Construct mutable slices from mutable reference to d { let mut d_clone = d.clone(); - assert_eq!(a, fixed_slice_mut!(&mut d_clone).into_owned()); - assert_eq!(d, dynamic_slice_mut!(&mut d_clone).into_owned()); + assert_eq!(a, fixed_view_mut!(&mut d_clone).into_owned()); + assert_eq!(d, dynamic_view_mut!(&mut d_clone).into_owned()); } // Construct slices from a slice of a { - let mut a_slice = fixed_slice!(&a); - assert_eq!(a, fixed_slice!(&a_slice).into_owned()); - assert_eq!(a, fixed_slice!(&mut a_slice).into_owned()); - assert_eq!(d, dynamic_slice!(&a_slice).into_owned()); - assert_eq!(d, dynamic_slice!(&mut a_slice).into_owned()); + let mut a_slice = fixed_view!(&a); + assert_eq!(a, fixed_view!(&a_slice).into_owned()); + assert_eq!(a, fixed_view!(&mut a_slice).into_owned()); + assert_eq!(d, dynamic_view!(&a_slice).into_owned()); + assert_eq!(d, dynamic_view!(&mut a_slice).into_owned()); } // Construct slices from a slice mut of a { // Need a clone of a here, so that we can both have a mutable borrow and compare equality let mut a_clone = a.clone(); - let mut a_slice = fixed_slice_mut!(&mut a_clone); + let mut a_slice = fixed_view_mut!(&mut a_clone); - assert_eq!(a, fixed_slice!(&a_slice).into_owned()); - assert_eq!(a, fixed_slice!(&mut a_slice).into_owned()); - assert_eq!(d, dynamic_slice!(&a_slice).into_owned()); - assert_eq!(d, dynamic_slice!(&mut a_slice).into_owned()); - assert_eq!(a, fixed_slice_mut!(&mut a_slice).into_owned()); - assert_eq!(d, dynamic_slice_mut!(&mut a_slice).into_owned()); + assert_eq!(a, fixed_view!(&a_slice).into_owned()); + assert_eq!(a, fixed_view!(&mut a_slice).into_owned()); + assert_eq!(d, dynamic_view!(&a_slice).into_owned()); + assert_eq!(d, dynamic_view!(&mut a_slice).into_owned()); + assert_eq!(a, fixed_view_mut!(&mut a_slice).into_owned()); + assert_eq!(d, dynamic_view_mut!(&mut a_slice).into_owned()); } } diff --git a/tests/core/edition.rs b/tests/core/edition.rs index bd882652..f5a51874 100644 --- a/tests/core/edition.rs +++ b/tests/core/edition.rs @@ -2,7 +2,7 @@ use na::{ DMatrix, Matrix, Matrix3, Matrix3x4, Matrix3x5, Matrix4, Matrix4x3, Matrix4x5, Matrix5, Matrix5x3, Matrix5x4, }; -use na::{Dynamic, U3, U5}; +use na::{Dyn, U3, U5}; #[test] #[rustfmt::skip] @@ -257,7 +257,7 @@ fn remove_columns() { assert_eq!(m.remove_fixed_columns::<2>(2), expected_b3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, U3, Dynamic, _> = m.remove_columns(3, 2); + let computed: Matrix<_, U3, Dyn, _> = m.remove_columns(3, 2); assert!(computed.eq(&expected_b2)); /* @@ -391,7 +391,7 @@ fn remove_rows() { assert_eq!(m.remove_fixed_rows::<2>(2), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, Dynamic, U3, _> = m.remove_rows(3, 2); + let computed: Matrix<_, Dyn, U3, _> = m.remove_rows(3, 2); assert!(computed.eq(&expected2)); } @@ -508,7 +508,7 @@ fn insert_columns() { assert_eq!(m.insert_fixed_columns::<2>(2, 0), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, U5, Dynamic, _> = m.insert_columns(3, 2, 0); + let computed: Matrix<_, U5, Dyn, _> = m.insert_columns(3, 2, 0); assert!(computed.eq(&expected2)); } @@ -581,7 +581,7 @@ fn insert_rows() { assert_eq!(m.insert_fixed_rows::<2>(2, 0), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, Dynamic, U5, _> = m.insert_rows(3, 2, 0); + let computed: Matrix<_, Dyn, U5, _> = m.insert_rows(3, 2, 0); assert!(computed.eq(&expected2)); } diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 8a545e97..501a0566 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1,80 +1,126 @@ +use na::iter::MatrixIter; use num::{One, Zero}; use std::cmp::Ordering; use na::dimension::{U15, U8}; use na::{ self, Const, DMatrix, DVector, Matrix2, Matrix2x3, Matrix2x4, Matrix3, Matrix3x2, Matrix3x4, - Matrix4, Matrix4x3, Matrix4x5, Matrix5, Matrix6, OMatrix, RowVector3, RowVector4, RowVector5, - Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, + Matrix4, Matrix4x3, Matrix4x5, Matrix5, Matrix6, MatrixView2x3, MatrixViewMut2x3, OMatrix, + RowVector3, RowVector4, RowVector5, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, }; #[test] fn iter() { let a = Matrix2x3::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); + let view: MatrixView2x3<_> = (&a).into(); - let mut it = a.iter(); - assert_eq!(*it.next().unwrap(), 1.0); - assert_eq!(*it.next().unwrap(), 4.0); - assert_eq!(*it.next().unwrap(), 2.0); - assert_eq!(*it.next().unwrap(), 5.0); - assert_eq!(*it.next().unwrap(), 3.0); - assert_eq!(*it.next().unwrap(), 6.0); - assert!(it.next().is_none()); + fn test<'a, F: Fn() -> I, I: Iterator + DoubleEndedIterator>(it: F) { + { + let mut it = it(); + assert_eq!(*it.next().unwrap(), 1.0); + assert_eq!(*it.next().unwrap(), 4.0); + assert_eq!(*it.next().unwrap(), 2.0); + assert_eq!(*it.next().unwrap(), 5.0); + assert_eq!(*it.next().unwrap(), 3.0); + assert_eq!(*it.next().unwrap(), 6.0); + assert!(it.next().is_none()); + } - let mut it = a.iter(); - assert_eq!(*it.next().unwrap(), 1.0); - assert_eq!(*it.next_back().unwrap(), 6.0); - assert_eq!(*it.next_back().unwrap(), 3.0); - assert_eq!(*it.next_back().unwrap(), 5.0); - assert_eq!(*it.next().unwrap(), 4.0); - assert_eq!(*it.next().unwrap(), 2.0); - assert!(it.next().is_none()); + { + let mut it = it(); + assert_eq!(*it.next().unwrap(), 1.0); + assert_eq!(*it.next_back().unwrap(), 6.0); + assert_eq!(*it.next_back().unwrap(), 3.0); + assert_eq!(*it.next_back().unwrap(), 5.0); + assert_eq!(*it.next().unwrap(), 4.0); + assert_eq!(*it.next().unwrap(), 2.0); + assert!(it.next().is_none()); + } + { + let mut it = it().rev(); + assert_eq!(*it.next().unwrap(), 6.0); + assert_eq!(*it.next().unwrap(), 3.0); + assert_eq!(*it.next().unwrap(), 5.0); + assert_eq!(*it.next().unwrap(), 2.0); + assert_eq!(*it.next().unwrap(), 4.0); + assert_eq!(*it.next().unwrap(), 1.0); + assert!(it.next().is_none()); + } + } - let mut it = a.iter().rev(); - assert_eq!(*it.next().unwrap(), 6.0); - assert_eq!(*it.next().unwrap(), 3.0); - assert_eq!(*it.next().unwrap(), 5.0); - assert_eq!(*it.next().unwrap(), 2.0); - assert_eq!(*it.next().unwrap(), 4.0); - assert_eq!(*it.next().unwrap(), 1.0); - assert!(it.next().is_none()); + test(|| a.iter()); + test(|| view.into_iter()); let row = a.row(0); - let mut it = row.iter(); - assert_eq!(*it.next().unwrap(), 1.0); - assert_eq!(*it.next().unwrap(), 2.0); - assert_eq!(*it.next().unwrap(), 3.0); - assert!(it.next().is_none()); + let row_test = |mut it: MatrixIter<_, _, _, _>| { + assert_eq!(*it.next().unwrap(), 1.0); + assert_eq!(*it.next().unwrap(), 2.0); + assert_eq!(*it.next().unwrap(), 3.0); + assert!(it.next().is_none()); + }; + row_test(row.iter()); + row_test(row.into_iter()); let row = a.row(1); - let mut it = row.iter(); - assert_eq!(*it.next().unwrap(), 4.0); - assert_eq!(*it.next().unwrap(), 5.0); - assert_eq!(*it.next().unwrap(), 6.0); - assert!(it.next().is_none()); + let row_test = |mut it: MatrixIter<_, _, _, _>| { + assert_eq!(*it.next().unwrap(), 4.0); + assert_eq!(*it.next().unwrap(), 5.0); + assert_eq!(*it.next().unwrap(), 6.0); + assert!(it.next().is_none()); + }; + row_test(row.iter()); + row_test(row.into_iter()); let m22 = row.column(1); - let mut it = m22.iter(); - assert_eq!(*it.next().unwrap(), 5.0); - assert!(it.next().is_none()); + let m22_test = |mut it: MatrixIter<_, _, _, _>| { + assert_eq!(*it.next().unwrap(), 5.0); + assert!(it.next().is_none()); + }; + m22_test(m22.iter()); + m22_test(m22.into_iter()); let col = a.column(0); - let mut it = col.iter(); - assert_eq!(*it.next().unwrap(), 1.0); - assert_eq!(*it.next().unwrap(), 4.0); - assert!(it.next().is_none()); + let col_test = |mut it: MatrixIter<_, _, _, _>| { + assert_eq!(*it.next().unwrap(), 1.0); + assert_eq!(*it.next().unwrap(), 4.0); + assert!(it.next().is_none()); + }; + col_test(col.iter()); + col_test(col.into_iter()); let col = a.column(1); - let mut it = col.iter(); - assert_eq!(*it.next().unwrap(), 2.0); - assert_eq!(*it.next().unwrap(), 5.0); - assert!(it.next().is_none()); + let col_test = |mut it: MatrixIter<_, _, _, _>| { + assert_eq!(*it.next().unwrap(), 2.0); + assert_eq!(*it.next().unwrap(), 5.0); + assert!(it.next().is_none()); + }; + col_test(col.iter()); + col_test(col.into_iter()); let col = a.column(2); - let mut it = col.iter(); - assert_eq!(*it.next().unwrap(), 3.0); - assert_eq!(*it.next().unwrap(), 6.0); - assert!(it.next().is_none()); + let col_test = |mut it: MatrixIter<_, _, _, _>| { + assert_eq!(*it.next().unwrap(), 3.0); + assert_eq!(*it.next().unwrap(), 6.0); + assert!(it.next().is_none()); + }; + col_test(col.iter()); + col_test(col.into_iter()); +} + +#[test] +fn iter_mut() { + let mut a = Matrix2x3::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); + + for v in a.iter_mut() { + *v *= 2.0; + } + assert_eq!(a, Matrix2x3::new(2.0, 4.0, 6.0, 8.0, 10.0, 12.0)); + + let view: MatrixViewMut2x3<_> = MatrixViewMut2x3::from(&mut a); + for v in view.into_iter() { + *v *= 2.0; + } + assert_eq!(a, Matrix2x3::new(4.0, 8.0, 12.0, 16.0, 20.0, 24.0)); } #[test] @@ -1066,43 +1112,43 @@ fn partial_eq_different_types() { let static_mat = Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8); let mut typenum_static_mat = OMatrix::, Const<4>>::zeros(); - let mut slice = typenum_static_mat.slice_mut((0, 0), (2, 4)); - slice += static_mat; + let mut view = typenum_static_mat.view_mut((0, 0), (2, 4)); + view += static_mat; - let fslice_of_dmat = dynamic_mat.fixed_slice::<2, 2>(0, 0); - let dslice_of_dmat = dynamic_mat.slice((0, 0), (2, 2)); - let fslice_of_smat = static_mat.fixed_slice::<2, 2>(0, 0); - let dslice_of_smat = static_mat.slice((0, 0), (2, 2)); + let fview_of_dmat = dynamic_mat.fixed_view::<2, 2>(0, 0); + let dview_of_dmat = dynamic_mat.view((0, 0), (2, 2)); + let fview_of_smat = static_mat.fixed_view::<2, 2>(0, 0); + let dview_of_smat = static_mat.view((0, 0), (2, 2)); assert_eq!(dynamic_mat, static_mat); assert_eq!(static_mat, dynamic_mat); - assert_eq!(dynamic_mat, slice); - assert_eq!(slice, dynamic_mat); + assert_eq!(dynamic_mat, view); + assert_eq!(view, dynamic_mat); - assert_eq!(static_mat, slice); - assert_eq!(slice, static_mat); + assert_eq!(static_mat, view); + assert_eq!(view, static_mat); - assert_eq!(fslice_of_dmat, dslice_of_dmat); - assert_eq!(dslice_of_dmat, fslice_of_dmat); + assert_eq!(fview_of_dmat, dview_of_dmat); + assert_eq!(dview_of_dmat, fview_of_dmat); - assert_eq!(fslice_of_dmat, fslice_of_smat); - assert_eq!(fslice_of_smat, fslice_of_dmat); + assert_eq!(fview_of_dmat, fview_of_smat); + assert_eq!(fview_of_smat, fview_of_dmat); - assert_eq!(fslice_of_dmat, dslice_of_smat); - assert_eq!(dslice_of_smat, fslice_of_dmat); + assert_eq!(fview_of_dmat, dview_of_smat); + assert_eq!(dview_of_smat, fview_of_dmat); - assert_eq!(dslice_of_dmat, fslice_of_smat); - assert_eq!(fslice_of_smat, dslice_of_dmat); + assert_eq!(dview_of_dmat, fview_of_smat); + assert_eq!(fview_of_smat, dview_of_dmat); - assert_eq!(dslice_of_dmat, dslice_of_smat); - assert_eq!(dslice_of_smat, dslice_of_dmat); + assert_eq!(dview_of_dmat, dview_of_smat); + assert_eq!(dview_of_smat, dview_of_dmat); - assert_eq!(fslice_of_smat, dslice_of_smat); - assert_eq!(dslice_of_smat, fslice_of_smat); + assert_eq!(fview_of_smat, dview_of_smat); + assert_eq!(dview_of_smat, fview_of_smat); - assert_ne!(dynamic_mat, dslice_of_smat); - assert_ne!(dslice_of_smat, dynamic_mat); + assert_ne!(dynamic_mat, dview_of_smat); + assert_ne!(dview_of_smat, dynamic_mat); // TODO - implement those comparisons // assert_ne!(static_mat, typenum_static_mat); @@ -1136,3 +1182,153 @@ fn omatrix_to_string() { (svec.to_string(), smatr.to_string()) ); } + +#[test] +fn column_iteration() { + // dynamic matrix + let dmat = nalgebra::dmatrix![ + 13,14,15; + 23,24,25; + 33,34,35; + ]; + let mut col_iter = dmat.column_iter(); + assert_eq!(col_iter.next(), Some(dmat.column(0))); + assert_eq!(col_iter.next(), Some(dmat.column(1))); + assert_eq!(col_iter.next(), Some(dmat.column(2))); + assert_eq!(col_iter.next(), None); + + // statically sized matrix + let smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; + let mut col_iter = smat.column_iter(); + assert_eq!(col_iter.next(), Some(smat.column(0))); + assert_eq!(col_iter.next(), Some(smat.column(1))); + assert_eq!(col_iter.next(), None); +} + +#[test] +fn column_iteration_mut() { + let mut dmat = nalgebra::dmatrix![ + 13,14,15; + 23,24,25; + 33,34,35; + ]; + let mut cloned = dmat.clone(); + let mut col_iter = dmat.column_iter_mut(); + assert_eq!(col_iter.next(), Some(cloned.column_mut(0))); + assert_eq!(col_iter.next(), Some(cloned.column_mut(1))); + assert_eq!(col_iter.next(), Some(cloned.column_mut(2))); + assert_eq!(col_iter.next(), None); + + // statically sized matrix + let mut smat: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; + let mut cloned = smat.clone(); + let mut col_iter = smat.column_iter_mut(); + assert_eq!(col_iter.next(), Some(cloned.column_mut(0))); + assert_eq!(col_iter.next(), Some(cloned.column_mut(1))); + assert_eq!(col_iter.next(), None); +} + +#[test] +fn column_iteration_double_ended() { + let dmat = nalgebra::dmatrix![ + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; + let mut col_iter = dmat.column_iter(); + assert_eq!(col_iter.next(), Some(dmat.column(0))); + assert_eq!(col_iter.next(), Some(dmat.column(1))); + assert_eq!(col_iter.next_back(), Some(dmat.column(4))); + assert_eq!(col_iter.next_back(), Some(dmat.column(3))); + assert_eq!(col_iter.next(), Some(dmat.column(2))); + assert_eq!(col_iter.next_back(), None); + assert_eq!(col_iter.next(), None); +} + +#[test] +fn column_iterator_double_ended_mut() { + let mut dmat = nalgebra::dmatrix![ + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; + let mut cloned = dmat.clone(); + let mut col_iter_mut = dmat.column_iter_mut(); + assert_eq!(col_iter_mut.next(), Some(cloned.column_mut(0))); + assert_eq!(col_iter_mut.next(), Some(cloned.column_mut(1))); + assert_eq!(col_iter_mut.next_back(), Some(cloned.column_mut(4))); + assert_eq!(col_iter_mut.next_back(), Some(cloned.column_mut(3))); + assert_eq!(col_iter_mut.next(), Some(cloned.column_mut(2))); + assert_eq!(col_iter_mut.next_back(), None); + assert_eq!(col_iter_mut.next(), None); +} + +#[test] +#[cfg(feature = "rayon")] +fn parallel_column_iteration() { + use nalgebra::dmatrix; + use rayon::prelude::*; + let dmat: DMatrix = dmatrix![ + 13.,14.; + 23.,24.; + 33.,34.; + ]; + let cloned = dmat.clone(); + // test that correct columns are iterated over + dmat.par_column_iter().enumerate().for_each(|(idx, col)| { + assert_eq!(col, cloned.column(idx)); + }); + // test that a more complex expression produces the same + // result as the serial equivalent + let par_result: f64 = dmat.par_column_iter().map(|col| col.norm()).sum(); + let ser_result: f64 = dmat.column_iter().map(|col| col.norm()).sum(); + assert_eq!(par_result, ser_result); + + // repeat this test using mutable iterators + let mut dmat = dmat; + dmat.par_column_iter_mut() + .enumerate() + .for_each(|(idx, col)| { + assert_eq!(col, cloned.column(idx)); + }); + + let par_mut_result: f64 = dmat.par_column_iter_mut().map(|col| col.norm()).sum(); + assert_eq!(par_mut_result, ser_result); +} + +#[test] +#[cfg(feature = "rayon")] +fn column_iteration_mut_double_ended() { + let dmat = nalgebra::dmatrix![ + 13,14,15,16,17; + 23,24,25,26,27; + 33,34,35,36,37; + ]; + let cloned = dmat.clone(); + let mut col_iter = dmat.column_iter(); + assert_eq!(col_iter.next(), Some(cloned.column(0))); + assert_eq!(col_iter.next(), Some(cloned.column(1))); + assert_eq!(col_iter.next_back(), Some(cloned.column(4))); + assert_eq!(col_iter.next_back(), Some(cloned.column(3))); + assert_eq!(col_iter.next(), Some(cloned.column(2))); + assert_eq!(col_iter.next_back(), None); + assert_eq!(col_iter.next(), None); +} + +#[test] +#[cfg(feature = "rayon")] +fn parallel_column_iteration_mut() { + use rayon::prelude::*; + let mut first = DMatrix::::zeros(400, 300); + let mut second = DMatrix::::zeros(400, 300); + first + .column_iter_mut() + .enumerate() + .for_each(|(idx, mut col)| col[idx] = 1.); + second + .par_column_iter_mut() + .enumerate() + .for_each(|(idx, mut col)| col[idx] = 1.); + assert_eq!(first, second); + assert_eq!(second, DMatrix::identity(400, 300)); +} diff --git a/tests/core/matrix_slice.rs b/tests/core/matrix_view.rs similarity index 79% rename from tests/core/matrix_slice.rs rename to tests/core/matrix_view.rs index ada5297e..4ce49d02 100644 --- a/tests/core/matrix_slice.rs +++ b/tests/core/matrix_view.rs @@ -1,22 +1,22 @@ #![allow(non_snake_case)] use na::{ - DMatrix, DMatrixSlice, DMatrixSliceMut, Matrix2, Matrix2x3, Matrix2x4, Matrix2x6, Matrix3, - Matrix3x2, Matrix3x4, Matrix4x2, Matrix6x2, MatrixSlice2, MatrixSlice2x3, MatrixSlice2xX, - MatrixSlice3, MatrixSlice3x2, MatrixSliceMut2, MatrixSliceMut2x3, MatrixSliceMut2xX, - MatrixSliceMut3, MatrixSliceMut3x2, MatrixSliceMutXx3, MatrixSliceXx3, RowVector4, Vector3, + DMatrix, DMatrixView, DMatrixViewMut, Matrix2, Matrix2x3, Matrix2x4, Matrix2x6, Matrix3, + Matrix3x2, Matrix3x4, Matrix4x2, Matrix6x2, MatrixView2, MatrixView2x3, MatrixView2xX, + MatrixView3, MatrixView3x2, MatrixViewMut2, MatrixViewMut2x3, MatrixViewMut2xX, MatrixViewMut3, + MatrixViewMut3x2, MatrixViewMutXx3, MatrixViewXx3, RowVector4, Vector3, }; #[test] #[rustfmt::skip] -fn nested_fixed_slices() { +fn nested_fixed_views() { let a = Matrix3x4::new(11.0, 12.0, 13.0, 14.0, 21.0, 22.0, 23.0, 24.0, 31.0, 32.0, 33.0, 34.0); - let s1 = a.fixed_slice::<3, 3>(0, 1); // Simple slice. - let s2 = s1.fixed_slice::<2, 2>(1, 1); // Slice of slice. - let s3 = s1.fixed_slice_with_steps::<2, 2>((0, 0), (1, 1)); // Slice of slice with steps. + let s1 = a.fixed_view::<3, 3>(0, 1); // Simple view. + let s2 = s1.fixed_view::<2, 2>(1, 1); // View of view. + let s3 = s1.fixed_view_with_steps::<2, 2>((0, 0), (1, 1)); // View of view with steps. let expected_owned_s1 = Matrix3::new(12.0, 13.0, 14.0, 22.0, 23.0, 24.0, @@ -35,14 +35,14 @@ fn nested_fixed_slices() { #[test] #[rustfmt::skip] -fn nested_slices() { +fn nested_views() { let a = Matrix3x4::new(11.0, 12.0, 13.0, 14.0, 21.0, 22.0, 23.0, 24.0, 31.0, 32.0, 33.0, 34.0); - let s1 = a.slice((0, 1), (3, 3)); - let s2 = s1.slice((1, 1), (2, 2)); - let s3 = s1.slice_with_steps((0, 0), (2, 2), (1, 1)); + let s1 = a.view((0, 1), (3, 3)); + let s2 = s1.view((1, 1), (2, 2)); + let s3 = s1.view_with_steps((0, 0), (2, 2), (1, 1)); let expected_owned_s1 = DMatrix::from_row_slice(3, 3, &[ 12.0, 13.0, 14.0, 22.0, 23.0, 24.0, @@ -61,14 +61,14 @@ fn nested_slices() { #[test] #[rustfmt::skip] -fn slice_mut() { +fn view_mut() { let mut a = Matrix3x4::new(11.0, 12.0, 13.0, 14.0, 21.0, 22.0, 23.0, 24.0, 31.0, 32.0, 33.0, 34.0); { - // We modify `a` through the mutable slice. - let mut s1 = a.slice_with_steps_mut((0, 1), (2, 2), (1, 1)); + // We modify `a` through the mutable view. + let mut s1 = a.view_with_steps_mut((0, 1), (2, 2), (1, 1)); s1.fill(0.0); } @@ -81,7 +81,7 @@ fn slice_mut() { #[test] #[rustfmt::skip] -fn nested_row_slices() { +fn nested_row_views() { let a = Matrix6x2::new(11.0, 12.0, 21.0, 22.0, 31.0, 32.0, @@ -105,7 +105,7 @@ fn nested_row_slices() { #[test] #[rustfmt::skip] -fn row_slice_mut() { +fn row_view_mut() { let mut a = Matrix6x2::new(11.0, 12.0, 21.0, 22.0, 31.0, 32.0, @@ -113,7 +113,7 @@ fn row_slice_mut() { 51.0, 52.0, 61.0, 62.0); { - // We modify `a` through the mutable slice. + // We modify `a` through the mutable view. let mut s1 = a.rows_with_step_mut(1, 3, 1); s1.fill(0.0); } @@ -130,7 +130,7 @@ fn row_slice_mut() { #[test] #[rustfmt::skip] -fn nested_col_slices() { +fn nested_col_views() { let a = Matrix2x6::new(11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); let s1 = a.fixed_columns::<4>(1); @@ -148,12 +148,12 @@ fn nested_col_slices() { #[test] #[rustfmt::skip] -fn col_slice_mut() { +fn col_view_mut() { let mut a = Matrix2x6::new(11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0); { - // We modify `a` through the mutable slice. + // We modify `a` through the mutable view. let mut s1 = a.columns_with_step_mut(1, 3, 1); s1.fill(0.0); } @@ -203,7 +203,7 @@ fn columns_range_pair() { #[test] #[rustfmt::skip] -fn new_slice() { +fn new_from_slice() { let data = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ]; @@ -214,13 +214,13 @@ fn new_slice() { let expected3x2 = Matrix3x2::from_column_slice(&data); { - let m2 = MatrixSlice2::from_slice(&data); - let m3 = MatrixSlice3::from_slice(&data); - let m2x3 = MatrixSlice2x3::from_slice(&data); - let m3x2 = MatrixSlice3x2::from_slice(&data); - let m2xX = MatrixSlice2xX::from_slice(&data, 3); - let mXx3 = MatrixSliceXx3::from_slice(&data, 2); - let mXxX = DMatrixSlice::from_slice(&data, 2, 3); + let m2 = MatrixView2::from_slice(&data); + let m3 = MatrixView3::from_slice(&data); + let m2x3 = MatrixView2x3::from_slice(&data); + let m3x2 = MatrixView3x2::from_slice(&data); + let m2xX = MatrixView2xX::from_slice(&data, 3); + let mXx3 = MatrixViewXx3::from_slice(&data, 2); + let mXxX = DMatrixView::from_slice(&data, 2, 3); assert!(m2.eq(&expected2)); assert!(m3.eq(&expected3)); @@ -234,7 +234,7 @@ fn new_slice() { #[test] #[rustfmt::skip] -fn new_slice_mut() { +fn new_from_slice_mut() { let data = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ]; @@ -252,31 +252,31 @@ fn new_slice_mut() { 9.0, 10.0, 11.0, 12.0 ]; let mut data_mut = data.clone(); - MatrixSliceMut2::from_slice(&mut data_mut).fill(0.0); + MatrixViewMut2::from_slice(&mut data_mut).fill(0.0); assert!(data_mut == expected2); let mut data_mut = data.clone(); - MatrixSliceMut3::from_slice(&mut data_mut).fill(0.0); + MatrixViewMut3::from_slice(&mut data_mut).fill(0.0); assert!(data_mut == expected3); let mut data_mut = data.clone(); - MatrixSliceMut2x3::from_slice(&mut data_mut).fill(0.0); + MatrixViewMut2x3::from_slice(&mut data_mut).fill(0.0); assert!(data_mut == expected2x3); let mut data_mut = data.clone(); - MatrixSliceMut3x2::from_slice(&mut data_mut).fill(0.0); + MatrixViewMut3x2::from_slice(&mut data_mut).fill(0.0); assert!(data_mut == expected3x2); let mut data_mut = data.clone(); - MatrixSliceMut2xX::from_slice(&mut data_mut, 3).fill(0.0); + MatrixViewMut2xX::from_slice(&mut data_mut, 3).fill(0.0); assert!(data_mut == expected2x3); let mut data_mut = data.clone(); - MatrixSliceMutXx3::from_slice(&mut data_mut, 2).fill(0.0); + MatrixViewMutXx3::from_slice(&mut data_mut, 2).fill(0.0); assert!(data_mut == expected2x3); let mut data_mut = data.clone(); - DMatrixSliceMut::from_slice(&mut data_mut, 2, 3).fill(0.0); + DMatrixViewMut::from_slice(&mut data_mut, 2, 3).fill(0.0); assert!(data_mut == expected2x3); } @@ -324,14 +324,14 @@ fn columns_with_step_out_of_bounds() { #[test] #[should_panic] -fn slice_out_of_bounds() { +fn view_out_of_bounds() { let a = Matrix3x4::::zeros(); - a.slice((1, 2), (3, 1)); + a.view((1, 2), (3, 1)); } #[test] #[should_panic] -fn slice_with_steps_out_of_bounds() { +fn view_with_steps_out_of_bounds() { let a = Matrix3x4::::zeros(); - a.slice_with_steps((1, 2), (2, 2), (0, 1)); + a.view_with_steps((1, 2), (2, 2), (0, 1)); } diff --git a/tests/core/mod.rs b/tests/core/mod.rs index 5fb8c82b..f0484e4d 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -4,10 +4,14 @@ mod conversion; mod edition; mod empty; mod matrix; -mod matrix_slice; +mod matrix_view; #[cfg(feature = "mint")] mod mint; +mod reshape; +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv; mod serde; +mod variance; #[cfg(feature = "compare")] mod matrixcompare; diff --git a/tests/core/reshape.rs b/tests/core/reshape.rs new file mode 100644 index 00000000..3873667f --- /dev/null +++ b/tests/core/reshape.rs @@ -0,0 +1,80 @@ +use na::{ + Const, DMatrix, DMatrixView, DMatrixViewMut, Dyn, Matrix, MatrixView, MatrixViewMut, SMatrix, + SMatrixView, SMatrixViewMut, VecStorage, U3, U4, +}; +use nalgebra_macros::matrix; +use simba::scalar::SupersetOf; + +const MATRIX: SMatrix = matrix![ + 1, 2, 3; + 4, 5, 6; + 7, 8, 9; + 10, 11, 12 +]; + +const RESHAPED_MATRIX: SMatrix = matrix![ + 1, 10, 8, 6; + 4, 2, 11, 9; + 7, 5, 3, 12 +]; + +// Helper alias for making it easier to specify dynamically allocated matrices with +// different dimension types (unlike DMatrix) +type GenericDMatrix = Matrix>; + +#[test] +fn reshape_owned() { + macro_rules! test_reshape { + ($in_matrix:ty => $out_matrix:ty, $rows:expr, $cols:expr) => {{ + // This is a pretty weird way to convert, but Matrix implements SubsetOf + let matrix: $in_matrix = MATRIX.to_subset().unwrap(); + let reshaped: $out_matrix = matrix.reshape_generic($rows, $cols); + assert_eq!(reshaped, RESHAPED_MATRIX); + }}; + } + + test_reshape!(SMatrix<_, 4, 3> => SMatrix<_, 3, 4>, U3, U4); + test_reshape!(GenericDMatrix<_, U4, Dyn> => GenericDMatrix<_, Dyn, Dyn>, Dyn(3), Dyn(4)); + test_reshape!(GenericDMatrix<_, U4, Dyn> => GenericDMatrix<_, U3, Dyn>, U3, Dyn(4)); + test_reshape!(GenericDMatrix<_, U4, Dyn> => GenericDMatrix<_, Dyn, U4>, Dyn(3), U4); + test_reshape!(DMatrix<_> => DMatrix<_>, Dyn(3), Dyn(4)); +} + +#[test] +fn reshape_slice() { + macro_rules! test_reshape { + ($in_slice:ty => $out_slice:ty, $rows:expr, $cols:expr) => { + // We test both that types check out by being explicit about types + // and the actual contents of the matrix + { + // By constructing the slice from a mutable reference we can obtain *either* + // an immutable slice or a mutable slice, which simplifies the testing of both + // types of mutability + let mut source_matrix = MATRIX.clone(); + let slice: $in_slice = Matrix::from(&mut source_matrix); + let reshaped: $out_slice = slice.reshape_generic($rows, $cols); + assert_eq!(reshaped, RESHAPED_MATRIX); + } + }; + } + + // Static "source slice" + test_reshape!(SMatrixView<_, 4, 3> => SMatrixView<_, 3, 4>, U3, U4); + test_reshape!(SMatrixView<_, 4, 3> => DMatrixView<_>, Dyn(3), Dyn(4)); + test_reshape!(SMatrixView<_, 4, 3> => MatrixView<_, Const<3>, Dyn>, U3, Dyn(4)); + test_reshape!(SMatrixView<_, 4, 3> => MatrixView<_, Dyn, Const<4>>, Dyn(3), U4); + test_reshape!(SMatrixViewMut<_, 4, 3> => SMatrixViewMut<_, 3, 4>, U3, U4); + test_reshape!(SMatrixViewMut<_, 4, 3> => DMatrixViewMut<_>, Dyn(3), Dyn(4)); + test_reshape!(SMatrixViewMut<_, 4, 3> => MatrixViewMut<_, Const<3>, Dyn>, U3, Dyn(4)); + test_reshape!(SMatrixViewMut<_, 4, 3> => MatrixViewMut<_, Dyn, Const<4>>, Dyn(3), U4); + + // Dyn "source slice" + test_reshape!(DMatrixView<_> => SMatrixView<_, 3, 4>, U3, U4); + test_reshape!(DMatrixView<_> => DMatrixView<_>, Dyn(3), Dyn(4)); + test_reshape!(DMatrixView<_> => MatrixView<_, Const<3>, Dyn>, U3, Dyn(4)); + test_reshape!(DMatrixView<_> => MatrixView<_, Dyn, Const<4>>, Dyn(3), U4); + test_reshape!(DMatrixViewMut<_> => SMatrixViewMut<_, 3, 4>, U3, U4); + test_reshape!(DMatrixViewMut<_> => DMatrixViewMut<_>, Dyn(3), Dyn(4)); + test_reshape!(DMatrixViewMut<_> => MatrixViewMut<_, Const<3>, Dyn>, U3, Dyn(4)); + test_reshape!(DMatrixViewMut<_> => MatrixViewMut<_, Dyn, Const<4>>, Dyn(3), U4); +} diff --git a/tests/core/rkyv.rs b/tests/core/rkyv.rs new file mode 100644 index 00000000..ffe9ed30 --- /dev/null +++ b/tests/core/rkyv.rs @@ -0,0 +1,62 @@ +#![cfg(feature = "rkyv-serialize")] + +use na::{ + Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix3x4, Point2, Point3, Quaternion, Rotation2, + Rotation3, Similarity3, SimilarityMatrix2, SimilarityMatrix3, Translation2, Translation3, +}; +use rand; +use rkyv::{Deserialize, Infallible}; + +macro_rules! test_rkyv_same_type( + ($($test: ident, $ty: ident);* $(;)*) => {$( + #[test] + fn $test() { + let value: $ty = rand::random(); + let bytes = rkyv::to_bytes::<_, 256>(&value).unwrap(); + + let archived = rkyv::check_archived_root::<$ty>(&bytes[..]).unwrap(); + // Compare archived and non-archived + assert_eq!(archived, &value); + + // Make sure Debug implementations are the same for Archived and non-Archived versions. + assert_eq!(format!("{:?}", value), format!("{:?}", archived)); + } + )*} +); +macro_rules! test_rkyv_diff_type( + ($($test: ident, $ty: ident);* $(;)*) => {$( + #[test] + fn $test() { + let value: $ty = Default::default(); + let bytes = rkyv::to_bytes::<_, 256>(&value).unwrap(); + + let archived = rkyv::check_archived_root::<$ty>(&bytes[..]).unwrap(); + let deserialized: $ty = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(deserialized, value); + } + )*} +); + +// Tests to make sure +test_rkyv_same_type!( + rkyv_same_type_matrix3x4, Matrix3x4; + rkyv_same_type_point3, Point3; + rkyv_same_type_translation3, Translation3; + rkyv_same_type_rotation3, Rotation3; + rkyv_same_type_isometry3, Isometry3; + rkyv_same_type_isometry_matrix3, IsometryMatrix3; + rkyv_same_type_similarity3, Similarity3; + rkyv_same_type_similarity_matrix3, SimilarityMatrix3; + rkyv_same_type_quaternion, Quaternion; + rkyv_same_type_point2, Point2; + rkyv_same_type_translation2, Translation2; + rkyv_same_type_rotation2, Rotation2; + // rkyv_same_type_isometry2, Isometry2; + rkyv_same_type_isometry_matrix2, IsometryMatrix2; + // rkyv_same_type_similarity2, Similarity2; + rkyv_same_type_similarity_matrix2, SimilarityMatrix2; +); + +test_rkyv_diff_type! { + rkyv_diff_type_matrix3x4, Matrix3x4; +} diff --git a/tests/core/variance.rs b/tests/core/variance.rs new file mode 100644 index 00000000..eb08ea0f --- /dev/null +++ b/tests/core/variance.rs @@ -0,0 +1,18 @@ +use nalgebra::DVector; + +#[test] +fn test_variance_catastrophic_cancellation() { + let long_repeating_vector = DVector::repeat(10_000, 100000000.0); + assert_eq!(long_repeating_vector.variance(), 0.0); + + let short_vec = DVector::from_vec(vec![1., 2., 3.]); + assert_eq!(short_vec.variance(), 2.0 / 3.0); + + let short_vec = + DVector::::from_vec(vec![1.0e8 + 4.0, 1.0e8 + 7.0, 1.0e8 + 13.0, 1.0e8 + 16.0]); + assert_eq!(short_vec.variance(), 22.5); + + let short_vec = + DVector::::from_vec(vec![1.0e9 + 4.0, 1.0e9 + 7.0, 1.0e9 + 13.0, 1.0e9 + 16.0]); + assert_eq!(short_vec.variance(), 22.5); +} diff --git a/tests/geometry/point.rs b/tests/geometry/point.rs index 22b0f598..42adf118 100644 --- a/tests/geometry/point.rs +++ b/tests/geometry/point.rs @@ -92,3 +92,11 @@ fn to_homogeneous() { assert_eq!(a.to_homogeneous(), expected); } + +#[test] +fn display_fmt_respects_modifiers() { + let p = Point3::new(1.23, 3.45, 5.67); + assert_eq!(&format!("{p}"), "{1.23, 3.45, 5.67}"); + assert_eq!(&format!("{p:.1}"), "{1.2, 3.5, 5.7}"); + assert_eq!(&format!("{p:.0}"), "{1, 3, 6}"); +} diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index 056df627..dde2e764 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -1,4 +1,7 @@ -use na::{Quaternion, RealField, UnitQuaternion, Vector2, Vector3}; +use na::{ + Matrix3, Quaternion, RealField, Rotation3, UnitQuaternion, UnitVector3, Vector2, Vector3, +}; +use std::f64::consts::PI; #[test] fn angle_2() { @@ -16,6 +19,58 @@ fn angle_3() { assert_eq!(a.angle(&b), 0.0); } +#[test] +fn from_rotation_matrix() { + // Test degenerate case when from_matrix gets stuck in Identity rotation + let identity = + Rotation3::from_matrix(&Matrix3::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)); + assert_relative_eq!(identity, &Rotation3::identity(), epsilon = 0.001); + let rotated_z = + Rotation3::from_matrix(&Matrix3::new(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0)); + assert_relative_eq!( + rotated_z, + &Rotation3::from_axis_angle(&UnitVector3::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), PI), + epsilon = 0.001 + ); + // Test that issue 627 is fixed + let m_627 = Matrix3::::new(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0); + assert_relative_ne!(identity, Rotation3::from_matrix(&m_627), epsilon = 0.01); + assert_relative_eq!( + Rotation3::from_matrix_unchecked(m_627.clone()), + Rotation3::from_matrix(&m_627), + epsilon = 0.001 + ); + // Test that issue 1078 is fixed + let m_1078 = Matrix3::::new(0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0); + assert_relative_ne!(identity, Rotation3::from_matrix(&m_1078), epsilon = 0.01); + assert_relative_eq!( + Rotation3::from_matrix_unchecked(m_1078.clone()), + Rotation3::from_matrix(&m_1078), + epsilon = 0.001 + ); + // Additional test cases for eps >= 1.0 + assert_relative_ne!( + identity, + Rotation3::from_matrix_eps(&m_627, 1.2, 0, Rotation3::identity()), + epsilon = 0.6 + ); + assert_relative_eq!( + Rotation3::from_matrix_unchecked(m_627.clone()), + Rotation3::from_matrix_eps(&m_627, 1.2, 0, Rotation3::identity()), + epsilon = 0.6 + ); + assert_relative_ne!( + identity, + Rotation3::from_matrix_eps(&m_1078, 1.0, 0, Rotation3::identity()), + epsilon = 0.1 + ); + assert_relative_eq!( + Rotation3::from_matrix_unchecked(m_1078.clone()), + Rotation3::from_matrix_eps(&m_1078, 1.0, 0, Rotation3::identity()), + epsilon = 0.1 + ); +} + #[test] fn quaternion_euler_angles_issue_494() { let quat = UnitQuaternion::from_quaternion(Quaternion::new( @@ -32,7 +87,9 @@ fn quaternion_euler_angles_issue_494() { #[cfg(feature = "proptest-support")] mod proptest_tests { + use approx::AbsDiffEq; use na::{self, Matrix, Rotation, Rotation2, Rotation3, SMatrix, Unit, Vector}; + use na::{UnitComplex, UnitQuaternion}; use num_traits::Zero; use simba::scalar::RealField; use std::f64; @@ -231,6 +288,75 @@ mod proptest_tests { } } + // + //In general, `slerp(a,b,t)` should equal `(b/a)^t * a` even though in practice, + //we may not use that formula directly for complex numbers or quaternions + // + + #[test] + fn slerp_powf_agree_2(a in unit_complex(), b in unit_complex(), t in PROPTEST_F64) { + let z1 = a.slerp(&b, t); + let z2 = (b/a).powf(t) * a; + prop_assert!(relative_eq!(z1,z2,epsilon=1e-10)); + } + + #[test] + fn slerp_powf_agree_3(a in unit_quaternion(), b in unit_quaternion(), t in PROPTEST_F64) { + if let Some(z1) = a.try_slerp(&b, t, f64::default_epsilon()) { + let z2 = (b/a).powf(t) * a; + prop_assert!(relative_eq!(z1,z2,epsilon=1e-10)); + } + } + + // + //when not antipodal, slerp should always take the shortest path between two orientations + // + + #[test] + fn slerp_takes_shortest_path_2( + z in unit_complex(), dtheta in -f64::pi()..f64::pi(), t in 0.0..1.0f64 + ) { + + //ambiguous when at ends of angle range, so we don't really care here + if dtheta.abs() != f64::pi() { + + //make two complex numbers separated by an angle between -pi and pi + let (z1, z2) = (z, z * UnitComplex::new(dtheta)); + let z3 = z1.slerp(&z2, t); + + //since the angle is no larger than a half-turn, and t is between 0 and 1, + //the shortest path just corresponds to adding the scaled angle + let a1 = z3.angle(); + let a2 = na::wrap(z1.angle() + dtheta*t, -f64::pi(), f64::pi()); + + prop_assert!(relative_eq!(a1, a2, epsilon=1e-10)); + } + + } + + #[test] + fn slerp_takes_shortest_path_3( + q in unit_quaternion(), dtheta in -f64::pi()..f64::pi(), t in 0.0..1.0f64 + ) { + + //ambiguous when at ends of angle range, so we don't really care here + if let Some(axis) = q.axis() { + + //make two quaternions separated by an angle between -pi and pi + let (q1, q2) = (q, q * UnitQuaternion::from_axis_angle(&axis, dtheta)); + let q3 = q1.slerp(&q2, t); + + //since the angle is no larger than a half-turn, and t is between 0 and 1, + //the shortest path just corresponds to adding the scaled angle + let q4 = q1 * UnitQuaternion::from_axis_angle(&axis, dtheta*t); + prop_assert!(relative_eq!(q3, q4, epsilon=1e-10)); + + } + + } + + + } //creates N rotation planes and angles diff --git a/tests/linalg/bidiagonal.rs b/tests/linalg/bidiagonal.rs index aaee393f..80096733 100644 --- a/tests/linalg/bidiagonal.rs +++ b/tests/linalg/bidiagonal.rs @@ -1,6 +1,6 @@ -#![cfg(feature = "proptest-support")] - -macro_rules! gen_tests( +#[cfg(feature = "proptest-support")] +mod proptest_tests { + macro_rules! gen_tests( ($module: ident, $scalar: expr) => { mod $module { #[allow(unused_imports)] @@ -54,8 +54,9 @@ macro_rules! gen_tests( } ); -gen_tests!(complex, complex_f64()); -gen_tests!(f64, PROPTEST_F64); + gen_tests!(complex, complex_f64()); + gen_tests!(f64, PROPTEST_F64); +} #[test] fn bidiagonal_identity() { @@ -74,3 +75,31 @@ fn bidiagonal_identity() { let (u, d, v_t) = bidiagonal.unpack(); assert_eq!(m, &u * d * &v_t); } + +#[test] +fn bidiagonal_regression_issue_1313() { + let s = 6.123234e-16_f32; + let mut m = nalgebra::dmatrix![ + 10.0, 0.0, 0.0, 0.0, -10.0, 0.0, 0.0, 0.0; + s, 10.0, 0.0, 10.0, s, 0.0, 0.0, 0.0; + 20.0, -20.0, 0.0, 20.0, 20.0, 0.0, 0.0, 0.0; + ]; + m.unscale_mut(m.camax()); + let bidiagonal = m.clone().bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + let m2 = &u * d * &v_t; + assert_relative_eq!(m, m2, epsilon = 1e-6); +} + +#[test] +fn bidiagonal_regression_issue_1313_minimal() { + let s = 6.123234e-17_f32; + let m = nalgebra::dmatrix![ + 1.0, 0.0, -1.0; + s, 1.0, s; + ]; + let bidiagonal = m.clone().bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + let m2 = &u * &d * &v_t; + assert_relative_eq!(m, m2, epsilon = 1e-6); +} diff --git a/tests/linalg/cholesky.rs b/tests/linalg/cholesky.rs index 891e54ca..a73fa947 100644 --- a/tests/linalg/cholesky.rs +++ b/tests/linalg/cholesky.rs @@ -15,7 +15,7 @@ macro_rules! gen_tests( ($module: ident, $scalar: ty) => { mod $module { use na::debug::RandomSDP; - use na::dimension::{Const, Dynamic}; + use na::dimension::{Const, Dyn}; use na::{DMatrix, DVector, Matrix4x3, Vector4}; use rand::random; use simba::scalar::ComplexField; @@ -28,7 +28,7 @@ macro_rules! gen_tests( proptest! { #[test] fn cholesky(n in PROPTEST_MATRIX_DIM) { - let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let m = RandomSDP::new(Dyn(n), || random::<$scalar>().0).unwrap(); let l = m.clone().cholesky().unwrap().unpack(); prop_assert!(relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7)); } @@ -44,7 +44,7 @@ macro_rules! gen_tests( #[test] fn cholesky_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) { - let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let m = RandomSDP::new(Dyn(n), || random::<$scalar>().0).unwrap(); let chol = m.clone().cholesky().unwrap(); let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0); @@ -73,7 +73,7 @@ macro_rules! gen_tests( #[test] fn cholesky_inverse(n in PROPTEST_MATRIX_DIM) { - let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let m = RandomSDP::new(Dyn(n), || random::<$scalar>().0).unwrap(); let m1 = m.clone().cholesky().unwrap().inverse(); let id1 = &m * &m1; let id2 = &m1 * &m; @@ -93,7 +93,7 @@ macro_rules! gen_tests( #[test] fn cholesky_determinant(n in PROPTEST_MATRIX_DIM) { - let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let m = RandomSDP::new(Dyn(n), || random::<$scalar>().0).unwrap(); let lu_det = m.clone().lu().determinant(); assert_relative_eq!(lu_det.imaginary(), 0., epsilon = 1.0e-7); let chol_det = m.cholesky().unwrap().determinant(); @@ -137,7 +137,7 @@ macro_rules! gen_tests( fn cholesky_insert_column(n in PROPTEST_MATRIX_DIM) { let n = n.max(1).min(10); let j = random::() % n; - let m_updated = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let m_updated = RandomSDP::new(Dyn(n), || random::<$scalar>().0).unwrap(); // build m and col from m_updated let col = m_updated.column(j); @@ -154,7 +154,7 @@ macro_rules! gen_tests( fn cholesky_remove_column(n in PROPTEST_MATRIX_DIM) { let n = n.max(1).min(10); let j = random::() % n; - let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let m = RandomSDP::new(Dyn(n), || random::<$scalar>().0).unwrap(); // remove column from cholesky decomposition and rebuild m let chol = m.clone().cholesky().unwrap().remove_column(j); diff --git a/tests/linalg/convolution.rs b/tests/linalg/convolution.rs index b2e151d3..eba8b84d 100644 --- a/tests/linalg/convolution.rs +++ b/tests/linalg/convolution.rs @@ -16,7 +16,7 @@ fn convolve_same_check() { assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); - // Dynamic Tests + // Dyn Tests let actual_d = DVector::from_vec(vec![1.0, 4.0, 7.0, 10.0]); let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) .convolve_same(DVector::from_vec(vec![1.0, 2.0])); @@ -54,7 +54,7 @@ fn convolve_full_check() { assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); - // Dynamic Tests + // Dyn Tests let actual_d = DVector::from_vec(vec![1.0, 4.0, 7.0, 10.0, 8.0]); let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) .convolve_full(DVector::from_vec(vec![1.0, 2.0])); @@ -90,7 +90,7 @@ fn convolve_valid_check() { assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); - // Dynamic Tests + // Dyn Tests let actual_d = DVector::from_vec(vec![4.0, 7.0, 10.0]); let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) .convolve_valid(DVector::from_vec(vec![1.0, 2.0])); diff --git a/tests/linalg/eigen.rs b/tests/linalg/eigen.rs index 162aad6a..7a944c44 100644 --- a/tests/linalg/eigen.rs +++ b/tests/linalg/eigen.rs @@ -1,4 +1,4 @@ -use na::DMatrix; +use na::{DMatrix, Matrix3}; #[cfg(feature = "proptest-support")] mod proptest_tests { @@ -116,6 +116,31 @@ fn symmetric_eigen_singular_24x24() { ); } +// Regression test for #1368 +#[test] +fn very_small_deviation_from_identity_issue_1368() { + let m = Matrix3::::new( + 1.0, + 3.1575704e-23, + 8.1146196e-23, + 3.1575704e-23, + 1.0, + 1.7471054e-22, + 8.1146196e-23, + 1.7471054e-22, + 1.0, + ); + + for v in m + .try_symmetric_eigen(f32::EPSILON, 0) + .unwrap() + .eigenvalues + .into_iter() + { + assert_relative_eq!(*v, 1.); + } +} + // #[cfg(feature = "arbitrary")] // quickcheck! { // TODO: full eigendecomposition is not implemented yet because of its complexity when some @@ -123,7 +148,7 @@ fn symmetric_eigen_singular_24x24() { // // /* // * 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 +// * This ensures the schur decomposition will work, and allows use to test the eigenvector // * computation. // */ // fn eigen(n: usize) -> bool { @@ -134,11 +159,11 @@ fn symmetric_eigen_singular_24x24() { // verify_eigenvectors(m, eig) // } // -// fn eigen_with_adjascent_duplicate_diagonals(n: usize) -> bool { +// fn eigen_with_adjacent_duplicate_diagonals(n: usize) -> bool { // let n = cmp::max(1, cmp::min(n, 10)); // let mut m = DMatrix::::new_random(n, n).upper_triangle(); // -// // Suplicate some adjascent diagonal elements. +// // Suplicate some adjacent diagonal elements. // for i in 0 .. n / 2 { // m[(i * 2 + 1, i * 2 + 1)] = m[(i * 2, i * 2)]; // } @@ -147,7 +172,7 @@ fn symmetric_eigen_singular_24x24() { // verify_eigenvectors(m, eig) // } // -// fn eigen_with_nonadjascent_duplicate_diagonals(n: usize) -> bool { +// fn eigen_with_nonadjacent_duplicate_diagonals(n: usize) -> bool { // let n = cmp::max(3, cmp::min(n, 10)); // let mut m = DMatrix::::new_random(n, n).upper_triangle(); // diff --git a/tests/linalg/full_piv_lu.rs b/tests/linalg/full_piv_lu.rs index 7ac95b0f..24e3bb48 100644 --- a/tests/linalg/full_piv_lu.rs +++ b/tests/linalg/full_piv_lu.rs @@ -253,7 +253,7 @@ fn remove_columns() { assert_eq!(m.remove_fixed_columns::(2), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, U3, Dynamic, _> = m.remove_columns(3, 2); + let computed: Matrix<_, U3, Dyn, _> = m.remove_columns(3, 2); assert!(computed.eq(&expected2)); } @@ -309,7 +309,7 @@ fn remove_rows() { assert_eq!(m.remove_fixed_rows::(2), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, Dynamic, U3, _> = m.remove_rows(3, 2); + let computed: Matrix<_, Dyn, U3, _> = m.remove_rows(3, 2); assert!(computed.eq(&expected2)); } @@ -374,7 +374,7 @@ fn insert_columns() { assert_eq!(m.insert_fixed_columns::(2, 0), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, U5, Dynamic, _> = m.insert_columns(3, 2, 0); + let computed: Matrix<_, U5, Dyn, _> = m.insert_columns(3, 2, 0); assert!(computed.eq(&expected2)); } @@ -434,7 +434,7 @@ fn insert_rows() { assert_eq!(m.insert_fixed_rows::<2>(2, 0), expected3); // The following is just to verify that the return type dimensions is correctly inferred. - let computed: Matrix<_, Dynamic, U5, _> = m.insert_rows(3, 2, 0); + let computed: Matrix<_, Dyn, U5, _> = m.insert_rows(3, 2, 0); assert!(computed.eq(&expected2)); } diff --git a/tests/linalg/svd.rs b/tests/linalg/svd.rs index 900901ad..d8b23d02 100644 --- a/tests/linalg/svd.rs +++ b/tests/linalg/svd.rs @@ -499,3 +499,17 @@ fn svd_regression_issue_1072() { epsilon = 1e-9 ); } + +#[test] +// Exercises bug reported in issue #1313 of nalgebra (https://github.com/dimforge/nalgebra/issues/1313) +fn svd_regression_issue_1313() { + let s = 6.123234e-16_f32; + let m = nalgebra::dmatrix![ + 10.0, 0.0, 0.0, 0.0, -10.0, 0.0, 0.0, 0.0; + s, 10.0, 0.0, 10.0, s, 0.0, 0.0, 0.0; + 20.0, -20.0, 0.0, 20.0, 20.0, 0.0, 0.0, 0.0; + ]; + let svd = m.clone().svd(true, true); + let m2 = svd.recompose().unwrap(); + assert_relative_eq!(&m, &m2, epsilon = 1e-5); +} diff --git a/tests/proptest/mod.rs b/tests/proptest/mod.rs index ec2e2c7b..cedfae84 100644 --- a/tests/proptest/mod.rs +++ b/tests/proptest/mod.rs @@ -101,11 +101,11 @@ pub fn dvector() -> impl Strategy> { pub fn dmatrix_( scalar_strategy: ScalarStrategy, -) -> impl Strategy> +) -> impl Strategy> where ScalarStrategy: Strategy + Clone + 'static, ScalarStrategy::Value: Scalar, - DefaultAllocator: Allocator, + DefaultAllocator: Allocator, { matrix(scalar_strategy, PROPTEST_MATRIX_DIM, PROPTEST_MATRIX_DIM) } @@ -114,7 +114,7 @@ where // where // RangeInclusive: Strategy, // T: Scalar + PartialEq + Copy, -// DefaultAllocator: Allocator, +// DefaultAllocator: Allocator, // { // vector(range, PROPTEST_MATRIX_DIM) // } @@ -213,9 +213,9 @@ fn test_matrix_output_types() { // Test that the dimension types are correct for the given inputs let _: MatrixStrategy<_, U3, U4> = matrix(-5..5, Const::<3>, Const::<4>); let _: MatrixStrategy<_, U3, U3> = matrix(-5..5, Const::<3>, Const::<3>); - let _: MatrixStrategy<_, U3, Dynamic> = matrix(-5..5, Const::<3>, 1..=5); - let _: MatrixStrategy<_, Dynamic, U3> = matrix(-5..5, 1..=5, Const::<3>); - let _: MatrixStrategy<_, Dynamic, Dynamic> = matrix(-5..5, 1..=5, 1..=5); + let _: MatrixStrategy<_, U3, Dyn> = matrix(-5..5, Const::<3>, 1..=5); + let _: MatrixStrategy<_, Dyn, U3> = matrix(-5..5, 1..=5, Const::<3>); + let _: MatrixStrategy<_, Dyn, Dyn> = matrix(-5..5, 1..=5, 1..=5); } // Below we have some tests to ensure that specific instances of OMatrix are usable @@ -225,10 +225,10 @@ proptest! { fn ensure_arbitrary_test_compiles_matrix3(_: Matrix3) {} #[test] - fn ensure_arbitrary_test_compiles_matrixmn_u3_dynamic(_: OMatrix) {} + fn ensure_arbitrary_test_compiles_matrixmn_u3_dynamic(_: OMatrix) {} #[test] - fn ensure_arbitrary_test_compiles_matrixmn_dynamic_u3(_: OMatrix) {} + fn ensure_arbitrary_test_compiles_matrixmn_dynamic_u3(_: OMatrix) {} #[test] fn ensure_arbitrary_test_compiles_dmatrix(_: DMatrix) {}