diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index dd8d23bb..ee62301d 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -36,14 +36,20 @@ jobs: run: cargo build; - name: Build --features serde-serialize run: cargo build --features serde-serialize - - name: Build --all-features - run: cargo build --all-features; - - name: Build nalgebra-glm - run: cargo build -p nalgebra-glm --all-features; - name: Build nalgebra-lapack run: cd nalgebra-lapack; cargo build; - name: Build nalgebra-sparse run: cd nalgebra-sparse; cargo build; + # Run this on it’s own job because it alone takes a lot of time. + # So it’s best to let it run in parallel to the other 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; test-nalgebra: runs-on: ubuntu-latest # env: @@ -110,3 +116,16 @@ 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: + runs-on: ubuntu-latest + steps: + - uses: Jimver/cuda-toolkit@v0.2.4 + - name: Install nightly-2021-10-17 + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly-2021-10-17 + 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 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 281c8f8e..70b4958a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,31 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.29.1] - WIP +## [0.30.0] + +### Breaking changes +- The `Dim` trait is now marked as unsafe. + +### Modified +- Use more concise debug impls for matrices and geometric transformation types. ### Added - -- The conversion trait `From>` and method `from_vec_storage` for `RowDVector`. See [#975](https://github.com/dimforge/nalgebra/issues/975) +- 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. - Added the methods `Matrix::product`, `::row_product`, `::row_product_tr`, and `::column_product` to compute the product of the components, rows, or columns, of a single matrix or vector. - The `Default` trait is now implemented for most geometric types: `Point`, `Isometry`, `Rotation`, `Similarity`, `Transform`, `UnitComplex`, and `UnitQuaternion`. +- Added the `Scale` geometric type for representing non-uniform scaling. +- `nalgebra-sparse`: provide constructors for unsorted but otherwise valid data using the CSR format. +- Added `Cholesky::new_with_substitute` that will replace diagonal elements by a given constant whenever `Cholesky` + meets a non-definite-positiveness. + +### 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. ## [0.29.0] ### Breaking changes diff --git a/Cargo.toml b/Cargo.toml index f1e50ab9..61f0fd25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ compare = [ "matrixcompare-core" ] libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] macros = [ "nalgebra-macros" ] +cuda = [ "cust", "simba/cuda" ] # Conversion convert-mint = [ "mint" ] @@ -86,7 +87,7 @@ pest = { version = "2", optional = true } 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"] } +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 } @@ -94,6 +95,9 @@ glam016 = { package = "glam", version = "0.16", optional = true } glam017 = { package = "glam", version = "0.17", optional = true } glam018 = { package = "glam", version = "0.18", optional = true } +[target.'cfg(not(target_os = "cuda"))'.dependencies] +cust = { version = "0.1", optional = true } + [dev-dependencies] serde_json = "1.0" @@ -129,3 +133,6 @@ lto = true [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs features = [ "proptest-support", "compare", "macros", "rand" ] + +[patch.crates-io] +simba = { git = "https://github.com/dimforge/simba"} diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index edad31d7..cfe83bdc 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -22,6 +22,7 @@ std = [ "nalgebra/std", "simba/std" ] arbitrary = [ "nalgebra/arbitrary" ] serde-serialize = [ "nalgebra/serde-serialize-no-std" ] abomonation-serialize = [ "nalgebra/abomonation-serialize" ] +cuda = [ "nalgebra/cuda" ] # Conversion convert-mint = [ "nalgebra/mint" ] diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 3fc88ade..b46d442f 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -32,6 +32,10 @@ use std::mem; /// A array-based statically sized matrix data storage. #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct ArrayStorage(pub [[T; R]; C]); impl ArrayStorage { diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 9a51536c..86006f3d 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -13,6 +13,10 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Dim of dynamically-sized algebraic entities. #[derive(Clone, Copy, Eq, PartialEq, Debug)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct Dynamic { value: usize, } @@ -197,6 +201,10 @@ dim_ops!( ); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct Const; /// Trait implemented exclusively by type-level integers. diff --git a/src/base/indexing.rs b/src/base/indexing.rs index c2bb48ff..2c691bd1 100644 --- a/src/base/indexing.rs +++ b/src/base/indexing.rs @@ -589,7 +589,10 @@ where where S: RawStorageMut, { - matrix.data.get_unchecked_linear_mut(self) + let nrows = matrix.shape().0; + let row = self % nrows; + let col = self / nrows; + matrix.data.get_unchecked_mut(row, col) } } diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 983f9a86..5df2f78e 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -154,6 +154,10 @@ pub type MatrixCross = /// some concrete types for `T` and a compatible data storage type `S`). #[repr(C)] #[derive(Clone, Copy)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct Matrix { /// The data storage that contains all the matrix components. Disappointed? /// diff --git a/src/base/unit.rs b/src/base/unit.rs index 8d548687..22af401a 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -26,6 +26,10 @@ 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( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct Unit { pub(crate) value: T, } diff --git a/src/geometry/dual_quaternion.rs b/src/geometry/dual_quaternion.rs index e597cbf5..4280668a 100644 --- a/src/geometry/dual_quaternion.rs +++ b/src/geometry/dual_quaternion.rs @@ -39,6 +39,10 @@ use simba::scalar::{ClosedNeg, RealField}; /// See #[repr(C)] #[derive(Debug, Copy, Clone)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct DualQuaternion { /// The real component of the quaternion pub real: Quaternion, diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index bdd2de60..f020c0e9 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -54,7 +54,11 @@ use crate::geometry::{AbstractRotation, Point, Translation}; /// * [Conversion to a matrix `to_matrix`…](#conversion-to-a-matrix) /// #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize-no-std", @@ -170,20 +174,6 @@ where } } -impl Copy for Isometry where - Owned>: Copy -{ -} - -impl Clone for Isometry { - #[inline] - fn clone(&self) -> Self { - Self { - rotation: self.rotation.clone(), - translation: self.translation.clone(), - } - } -} /// # From the translation and rotation parts impl, const D: usize> Isometry { /// Creates a new isometry from its rotational and translational parts. diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index d4008173..18a7852d 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -19,19 +19,15 @@ use crate::geometry::{Point3, Projective3}; /// A 3D orthographic projection stored as a homogeneous 4x4 matrix. #[repr(C)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] +#[derive(Copy, Clone)] pub struct Orthographic3 { matrix: Matrix4, } -impl Copy for Orthographic3 {} - -impl Clone for Orthographic3 { - #[inline] - fn clone(&self) -> Self { - Self::from_matrix_unchecked(self.matrix.clone()) - } -} - impl fmt::Debug for Orthographic3 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.matrix.fmt(f) diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index 34af6f0b..59b7f9f2 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -20,19 +20,15 @@ use crate::geometry::{Point3, Projective3}; /// A 3D perspective projection stored as a homogeneous 4x4 matrix. #[repr(C)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] +#[derive(Copy, Clone)] pub struct Perspective3 { matrix: Matrix4, } -impl Copy for Perspective3 {} - -impl Clone for Perspective3 { - #[inline] - fn clone(&self) -> Self { - Self::from_matrix_unchecked(self.matrix.clone()) - } -} - impl fmt::Debug for Perspective3 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.matrix.fmt(f) diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 7930e8fb..0953a9ce 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -74,6 +74,15 @@ where { } +#[cfg(all(not(target_os = "cuda"), feature = "cuda"))] +unsafe impl cust::memory::DeviceCopy + for OPoint +where + DefaultAllocator: Allocator, + OVector: cust::memory::DeviceCopy, +{ +} + #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for OPoint where diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 968a9e18..05b73334 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -28,6 +28,10 @@ use crate::geometry::{Point3, Rotation}; /// that may be used as a rotation. #[repr(C)] #[derive(Copy, Clone)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. pub coords: Vector4, diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index e1da8d67..2d5e5d24 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -54,6 +54,11 @@ use crate::geometry::Point; /// * [Conversion to a matrix `matrix`, `to_homogeneous`…](#conversion-to-a-matrix) /// #[repr(C)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] +#[derive(Copy, Clone)] pub struct Rotation { matrix: SMatrix, } @@ -73,21 +78,6 @@ where } } -impl Copy for Rotation where - , Const>>::Buffer: Copy -{ -} - -impl Clone for Rotation -where - , Const>>::Buffer: Clone, -{ - #[inline] - fn clone(&self) -> Self { - Self::from_matrix_unchecked(self.matrix.clone()) - } -} - #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for Rotation where diff --git a/src/geometry/scale.rs b/src/geometry/scale.rs index 9f3e778c..b1d278d6 100755 --- a/src/geometry/scale.rs +++ b/src/geometry/scale.rs @@ -22,6 +22,11 @@ use crate::geometry::Point; /// A scale which supports non-uniform scaling. #[repr(C)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] +#[derive(Copy, Clone)] pub struct Scale { /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is /// scaled. @@ -43,18 +48,6 @@ where } } -impl Copy for Scale {} - -impl Clone for Scale -where - Owned>: Clone, -{ - #[inline] - fn clone(&self) -> Self { - Scale::from(self.vector.clone()) - } -} - #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for Scale where diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 1b685252..fd6b1d36 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -23,7 +23,11 @@ use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize-no-std", @@ -73,22 +77,6 @@ where } } -impl + Copy, const D: usize> Copy - for Similarity -where - Owned>: Copy, -{ -} - -impl + Clone, const D: usize> Clone - for Similarity -{ - #[inline] - fn clone(&self) -> Self { - Similarity::from_isometry(self.isometry.clone(), self.scaling.clone()) - } -} - impl Similarity where R: AbstractRotation, diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index d87a815d..b0b5cced 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -60,14 +60,26 @@ where /// Tag representing the most general (not necessarily inversible) `Transform` type. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub enum TGeneral {} /// Tag representing the most general inversible `Transform` type. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::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( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] pub enum TAffine {} impl TCategory for TGeneral { @@ -195,6 +207,16 @@ where { } +#[cfg(all(not(target_os = "cuda"), feature = "cuda"))] +unsafe impl + cust::memory::DeviceCopy for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + Owned, U1>, DimNameSum, U1>>: cust::memory::DeviceCopy, +{ +} + impl Clone for Transform where Const: DimNameAdd, diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 48656f9c..1ce8cba3 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -22,6 +22,11 @@ use crate::geometry::Point; /// A translation. #[repr(C)] +#[cfg_attr( + all(not(target_os = "cuda"), feature = "cuda"), + derive(cust::DeviceCopy) +)] +#[derive(Copy, Clone)] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. @@ -43,18 +48,6 @@ where } } -impl Copy for Translation {} - -impl Clone for Translation -where - Owned>: Clone, -{ - #[inline] - fn clone(&self) -> Self { - Translation::from(self.vector.clone()) - } -} - #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for Translation where