Merge branch 'dimforge:dev' into dev

This commit is contained in:
Marc Haubenstock 2022-10-26 12:45:48 +02:00 committed by GitHub
commit 14394b7e67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 202 additions and 21 deletions

View File

@ -61,7 +61,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;
test-nalgebra-glm:
runs-on: ubuntu-latest
steps:

View File

@ -4,6 +4,16 @@ documented here.
This project adheres to [Semantic Versioning](https://semver.org/).
## [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

View File

@ -1,6 +1,6 @@
[package]
name = "nalgebra"
version = "0.31.1"
version = "0.31.2"
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices."
@ -66,6 +66,7 @@ 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 }

View File

@ -170,6 +170,16 @@ impl<T> CooMatrix<T> {
.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<Item = (usize, usize, &mut T)> {
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

View File

@ -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::<f64>::new(3, 3);
///
/// let mut coo = CooMatrix::<f64>::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.

View File

@ -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::<f64>::new(3, 3);
///
/// let mut coo = CooMatrix::<f64>::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.

View File

@ -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::<i32>::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() {
{

View File

@ -27,11 +27,14 @@ use std::mem;
/// A array-based statically sized matrix data storage.
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct ArrayStorage<T, const R: usize, const C: usize>(pub [[T; R]; C]);

View File

@ -13,11 +13,14 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Dim of dynamically-sized algebraic entities.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct Dynamic {
value: usize,
@ -207,7 +210,10 @@ dim_ops!(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct Const<const R: usize>;

View File

@ -150,11 +150,14 @@ pub type MatrixCross<T, R1, C1, R2, C2> =
/// some concrete types for `T` and a compatible data storage type `S`).
#[repr(C)]
#[derive(Clone, Copy)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct Matrix<T, R, C, S> {
/// The data storage that contains all the matrix components. Disappointed?

View File

@ -21,11 +21,14 @@ 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 = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
// #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct Unit<T> {
pub(crate) value: T,

View File

@ -40,11 +40,14 @@ use simba::scalar::{ClosedNeg, RealField};
/// See <https://github.com/dimforge/nalgebra/issues/487>
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct DualQuaternion<T> {
/// The real component of the quaternion

View File

@ -70,7 +70,10 @@ use crate::geometry::{AbstractRotation, Point, Translation};
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct Isometry<T, R, const D: usize> {
/// The pure rotational part of this isometry.
pub rotation: R,

View File

@ -19,11 +19,14 @@ use crate::geometry::{Point3, Projective3};
/// A 3D orthographic projection stored as a homogeneous 4x4 matrix.
#[repr(C)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)]
pub struct Orthographic3<T> {

View File

@ -20,11 +20,14 @@ use crate::geometry::{Point3, Projective3};
/// A 3D perspective projection stored as a homogeneous 4x4 matrix.
#[repr(C)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)]
pub struct Perspective3<T> {

View File

@ -40,7 +40,10 @@ use std::mem::MaybeUninit;
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct OPoint<T: Scalar, D: DimName>
where
DefaultAllocator: Allocator<T, D>,

View File

@ -202,11 +202,29 @@ impl<T: Scalar> Point1<T> {
/// assert_eq!(p.x, 1.0);
/// ```
#[inline]
#[cfg(not(feature = "cuda"))]
pub const fn new(x: T) -> Self {
Point {
coords: Vector1::new(x),
}
}
/// Initializes this point from its components.
///
/// # Example
///
/// ```
/// # use nalgebra::Point1;
/// let p = Point1::new(1.0);
/// assert_eq!(p.x, 1.0);
/// ```
#[inline]
#[cfg(feature = "cuda")]
pub fn new(x: T) -> Self {
Point {
coords: Vector1::new(x),
}
}
}
macro_rules! componentwise_constructors_impl(
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
@ -216,9 +234,22 @@ macro_rules! componentwise_constructors_impl(
#[doc = $doc]
#[doc = "```"]
#[inline]
#[cfg(not(feature = "cuda"))]
pub const fn new($($args: T),*) -> Self {
Point { coords: $Vector::new($($args),*) }
}
// TODO: always let new be const once CUDA updates its supported
// nightly version to something more recent.
#[doc = "Initializes this point from its components."]
#[doc = "# Example\n```"]
#[doc = $doc]
#[doc = "```"]
#[inline]
#[cfg(feature = "cuda")]
pub fn new($($args: T),*) -> Self {
Point { coords: $Vector::new($($args),*) }
}
}
)*}
);

View File

@ -23,11 +23,14 @@ use crate::geometry::{Point3, Rotation};
/// that may be used as a rotation.
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
pub struct Quaternion<T> {
/// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order.

View File

@ -49,11 +49,14 @@ use crate::geometry::Point;
/// * [Conversion to a matrix <span style="float:right;">`matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
///
#[repr(C)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)]
pub struct Rotation<T, const D: usize> {

View File

@ -17,11 +17,14 @@ use crate::geometry::Point;
/// A scale which supports non-uniform scaling.
#[repr(C)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)]
pub struct Scale<T, const D: usize> {

View File

@ -38,7 +38,10 @@ use crate::geometry::{AbstractRotation, Isometry, Point, Translation};
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct Similarity<T, R, const D: usize> {
/// The part of this similarity that does not include the scaling factor.
pub isometry: Isometry<T, R, D>,

View File

@ -17,11 +17,14 @@ use crate::geometry::Point;
/// A translation.
#[repr(C)]
#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
#[cfg_attr(
feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(
feature = "rkyv-serialize",
archive_attr(derive(bytecheck::CheckBytes))
)]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)]
pub struct Translation<T, const D: usize> {

View File

@ -7,6 +7,8 @@ mod matrix;
mod matrix_slice;
#[cfg(feature = "mint")]
mod mint;
#[cfg(feature = "rkyv-serialize-no-std")]
mod rkyv;
mod serde;
#[cfg(feature = "compare")]

44
tests/core/rkyv.rs Normal file
View File

@ -0,0 +1,44 @@
use na::{
Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix3x4, Point2, Point3, Quaternion, Rotation2,
Rotation3, Similarity3, SimilarityMatrix2, SimilarityMatrix3, Translation2, Translation3,
};
use rkyv::ser::{serializers::AllocSerializer, Serializer};
macro_rules! test_rkyv(
($($test: ident, $ty: ident);* $(;)*) => {$(
#[test]
fn $test() {
let v: $ty<f32> = rand::random();
// serialize
let mut serializer = AllocSerializer::<0>::default();
serializer.serialize_value(&v).unwrap();
let serialized = serializer.into_serializer().into_inner();
let deserialized: $ty<f32> = unsafe { rkyv::from_bytes_unchecked(&serialized).unwrap() };
assert_eq!(v, deserialized);
#[cfg(feature = "rkyv-safe-deser")]
{
let deserialized: $ty<f32> = rkyv::from_bytes(&serialized).unwrap();
assert_eq!(v, deserialized);
}
}
)*}
);
test_rkyv!(
rkyv_matrix3x4, Matrix3x4;
rkyv_point3, Point3;
rkyv_translation3, Translation3;
rkyv_rotation3, Rotation3;
rkyv_isometry3, Isometry3;
rkyv_isometry_matrix3, IsometryMatrix3;
rkyv_similarity3, Similarity3;
rkyv_similarity_matrix3, SimilarityMatrix3;
rkyv_quaternion, Quaternion;
rkyv_point2, Point2;
rkyv_translation2, Translation2;
rkyv_rotation2, Rotation2;
rkyv_isometry_matrix2, IsometryMatrix2;
rkyv_similarity_matrix2, SimilarityMatrix2;
);