Merge branch 'dimforge:dev' into dev
This commit is contained in:
commit
331925e170
|
@ -4,6 +4,10 @@ documented here.
|
||||||
|
|
||||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed severe catastrophic cancellation issue in variance calculation.
|
||||||
|
|
||||||
## [0.32.2] (07 March 2023)
|
## [0.32.2] (07 March 2023)
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,7 @@ serde_json = "1.0"
|
||||||
rand_xorshift = "0.3"
|
rand_xorshift = "0.3"
|
||||||
rand_isaac = "0.3"
|
rand_isaac = "0.3"
|
||||||
criterion = { version = "0.4", features = ["html_reports"] }
|
criterion = { version = "0.4", features = ["html_reports"] }
|
||||||
|
nalgebra = { path = ".", features = ["debug", "compare", "rand", "macros"]}
|
||||||
|
|
||||||
# For matrix comparison macro
|
# For matrix comparison macro
|
||||||
matrixcompare = "0.3.0"
|
matrixcompare = "0.3.0"
|
||||||
|
|
|
@ -81,32 +81,32 @@ pub type MatrixXx5<T> = Matrix<T, Dyn, U5, VecStorage<T, Dyn, U5>>;
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type MatrixXx6<T> = Matrix<T, Dyn, U6, VecStorage<T, Dyn, U6>>;
|
pub type MatrixXx6<T> = Matrix<T, Dyn, U6, VecStorage<T, Dyn, U6>>;
|
||||||
|
|
||||||
/// 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.**
|
/// **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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type Matrix1xX<T> = Matrix<T, U1, Dyn, VecStorage<T, U1, Dyn>>;
|
pub type Matrix1xX<T> = Matrix<T, U1, Dyn, VecStorage<T, U1, Dyn>>;
|
||||||
/// A heap-allocated, row-major, matrix with 2 rows and a dynamic number of columns.
|
/// 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.**
|
/// **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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type Matrix2xX<T> = Matrix<T, U2, Dyn, VecStorage<T, U2, Dyn>>;
|
pub type Matrix2xX<T> = Matrix<T, U2, Dyn, VecStorage<T, U2, Dyn>>;
|
||||||
/// A heap-allocated, row-major, matrix with 3 rows and a dynamic number of columns.
|
/// 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.**
|
/// **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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type Matrix3xX<T> = Matrix<T, U3, Dyn, VecStorage<T, U3, Dyn>>;
|
pub type Matrix3xX<T> = Matrix<T, U3, Dyn, VecStorage<T, U3, Dyn>>;
|
||||||
/// A heap-allocated, row-major, matrix with 4 rows and a dynamic number of columns.
|
/// 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.**
|
/// **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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type Matrix4xX<T> = Matrix<T, U4, Dyn, VecStorage<T, U4, Dyn>>;
|
pub type Matrix4xX<T> = Matrix<T, U4, Dyn, VecStorage<T, U4, Dyn>>;
|
||||||
/// A heap-allocated, row-major, matrix with 5 rows and a dynamic number of columns.
|
/// 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.**
|
/// **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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub type Matrix5xX<T> = Matrix<T, U5, Dyn, VecStorage<T, U5, Dyn>>;
|
pub type Matrix5xX<T> = Matrix<T, U5, Dyn, VecStorage<T, U5, Dyn>>;
|
||||||
/// A heap-allocated, row-major, matrix with 6 rows and a dynamic number of columns.
|
/// 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.**
|
/// **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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
|
|
@ -2255,3 +2255,102 @@ where
|
||||||
Unit::new_unchecked(crate::convert_ref(self.as_ref()))
|
Unit::new_unchecked(crate::convert_ref(self.as_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, S> Matrix<T, U1, U1, S>
|
||||||
|
where
|
||||||
|
S: RawStorage<T, U1, U1>,
|
||||||
|
{
|
||||||
|
/// 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<T, U1>,
|
||||||
|
{
|
||||||
|
&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<T> super::alias::Matrix1<T> {
|
||||||
|
/// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -335,12 +335,12 @@ impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
T::zero()
|
T::zero()
|
||||||
} else {
|
} else {
|
||||||
let val = self.iter().cloned().fold((T::zero(), T::zero()), |a, b| {
|
let n_elements: T = crate::convert(self.len() as f64);
|
||||||
(a.0 + b.clone() * b.clone(), a.1 + b)
|
let mean = self.mean();
|
||||||
});
|
|
||||||
let denom = T::one() / crate::convert::<_, T>(self.len() as f64);
|
self.iter().cloned().fold(T::zero(), |acc, x| {
|
||||||
let vd = val.1 * denom.clone();
|
acc + (x.clone() - mean.clone()) * (x.clone() - mean.clone())
|
||||||
val.0 * denom - vd.clone() * vd
|
}) / n_elements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ mod reshape;
|
||||||
#[cfg(feature = "rkyv-serialize-no-std")]
|
#[cfg(feature = "rkyv-serialize-no-std")]
|
||||||
mod rkyv;
|
mod rkyv;
|
||||||
mod serde;
|
mod serde;
|
||||||
|
mod variance;
|
||||||
|
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
mod matrixcompare;
|
mod matrixcompare;
|
||||||
|
|
|
@ -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::<f64>::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::<f64>::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);
|
||||||
|
}
|
Loading…
Reference in New Issue