Merge pull request #966 from dimforge/dev

Release v0.29.0
This commit is contained in:
Sébastien Crozet 2021-08-08 18:04:20 +02:00 committed by GitHub
commit fef43a6146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
180 changed files with 4175 additions and 3223 deletions

View File

@ -4,6 +4,35 @@ documented here.
This project adheres to [Semantic Versioning](https://semver.org/).
## [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
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
methods more versatile, and avoid useless clones when using non-Copy scalar
types.
- The `Allocator` trait signature has been significantly modified in order to handle uninitialized matrices in a sound
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`.
- The `Scalar` is now automatically implemented for most `'static + Clone` types. Type that implement `Clone` but not
`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`.
- Added `Reflection::bias()` to retrieve the bias of the reflection.
- Added `Reflection1..Reflection6` aliases for 1D to 6D reflections.
- Added implementation of `From` and `Into` for converting between `nalgebra` types and types from
`glam 0.16` and `glam 0.17`. These can be enabled by enabling the `convert-glam016`, and/or `convert-glam017`
cargo features.
## [0.28.0]
### Added
- Implement `Hash` for `Transform`.

View File

@ -1,6 +1,6 @@
[package]
name = "nalgebra"
version = "0.28.0"
version = "0.29.0"
authors = [ "Sébastien Crozet <developer@crozet.re>" ]
description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices."
@ -31,7 +31,6 @@ io = [ "pest", "pest_derive" ]
compare = [ "matrixcompare-core" ]
libm = [ "simba/libm" ]
libm-force = [ "simba/libm_force" ]
no_unsound_assume_init = [ ]
macros = [ "nalgebra-macros" ]
# Conversion
@ -40,6 +39,8 @@ convert-bytemuck = [ "bytemuck" ]
convert-glam013 = [ "glam013" ]
convert-glam014 = [ "glam014" ]
convert-glam015 = [ "glam015" ]
convert-glam016 = [ "glam016" ]
convert-glam017 = [ "glam017" ]
# Serialization
## To use serde in a #[no-std] environment, enable the
@ -71,7 +72,7 @@ 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.5", default-features = false }
simba = { version = "0.6", 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 }
@ -88,6 +89,8 @@ proptest = { version = "1", optional = true, default-features = false,
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 }
glam017 = { package = "glam", version = "0.17", optional = true }
[dev-dependencies]
@ -114,9 +117,13 @@ harness = false
path = "benches/lib.rs"
required-features = ["rand"]
#[profile.bench]
#opt-level = 0
#lto = false
[profile.bench]
lto = true
[package.metadata.docs.rs]
# Enable certain features when building docs for docs.rs
features = [ "proptest-support", "compare", "macros" ]
features = [ "proptest-support", "compare", "macros", "rand" ]

2
clippy.toml Normal file
View File

@ -0,0 +1,2 @@
too-many-arguments-threshold = 8
type-complexity-threshold = 675

View File

@ -4,7 +4,7 @@ version = "0.0.0"
authors = [ "You" ]
[dependencies]
nalgebra = "0.28.0"
nalgebra = "0.29.0"
[[bin]]
name = "example"

View File

@ -26,5 +26,5 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
[dependencies]
num-traits = { version = "0.2", default-features = false }
approx = { version = "0.5", default-features = false }
simba = { version = "0.5", default-features = false }
nalgebra = { path = "..", version = "0.28", default-features = false }
simba = { version = "0.6", default-features = false }
nalgebra = { path = "..", version = "0.29", default-features = false }

View File

@ -320,7 +320,7 @@ pub type DMat4x4 = Matrix4<f64>;
pub type Mat2 = Matrix2<f32>;
/// A 2x2 matrix with `f32` components.
pub type Mat2x2 = Matrix2<f32>;
/// A 2x2 matrix with `f32` components.
/// A 2x3 matrix with `f32` components.
pub type Mat2x3 = Matrix2x3<f32>;
/// A 2x4 matrix with `f32` components.
pub type Mat2x4 = Matrix2x4<f32>;

View File

@ -1,9 +1,9 @@
use core::mem;
use na::{self, RealField};
use num::FromPrimitive;
use na;
use crate::aliases::{TMat, TVec};
use crate::traits::Number;
use crate::RealNumber;
/// For each matrix or vector component `x` if `x >= 0`; otherwise, it returns `-x`.
///
@ -42,7 +42,7 @@ pub fn abs<T: Number, const R: usize, const C: usize>(x: &TMat<T, R, C>) -> TMat
/// * [`fract`](fn.fract.html)
/// * [`round`](fn.round.html)
/// * [`trunc`](fn.trunc.html)
pub fn ceil<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn ceil<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|x| x.ceil())
}
@ -214,7 +214,7 @@ pub fn float_bits_to_uint_vec<const D: usize>(v: &TVec<f32, D>) -> TVec<u32, D>
/// * [`fract`](fn.fract.html)
/// * [`round`](fn.round.html)
/// * [`trunc`](fn.trunc.html)
pub fn floor<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn floor<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|x| x.floor())
}
@ -240,13 +240,13 @@ pub fn floor<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
/// * [`floor`](fn.floor.html)
/// * [`round`](fn.round.html)
/// * [`trunc`](fn.trunc.html)
pub fn fract<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn fract<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|x| x.fract())
}
//// TODO: should be implemented for TVec/TMat?
///// Returns the (significant, exponent) of this float number.
//pub fn frexp<T: RealField>(x: T, exp: T) -> (T, T) {
//pub fn frexp<T: RealNumber>(x: T, exp: T) -> (T, T) {
// // TODO: is there a better approach?
// let e = x.log2().ceil();
// (x * (-e).exp2(), e)
@ -297,7 +297,7 @@ pub fn int_bits_to_float_vec<const D: usize>(v: &TVec<i32, D>) -> TVec<f32, D> {
//}
///// Returns the (significant, exponent) of this float number.
//pub fn ldexp<T: RealField>(x: T, exp: T) -> T {
//pub fn ldexp<T: RealNumber>(x: T, exp: T) -> T {
// // TODO: is there a better approach?
// x * (exp).exp2()
//}
@ -477,7 +477,7 @@ pub fn modf<T: Number>(x: T, i: T) -> T {
/// * [`floor`](fn.floor.html)
/// * [`fract`](fn.fract.html)
/// * [`trunc`](fn.trunc.html)
pub fn round<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn round<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|x| x.round())
}
@ -507,9 +507,9 @@ pub fn sign<T: Number, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
///
/// This is useful in cases where you would want a threshold function with a smooth transition.
/// This is equivalent to: `let result = clamp((x - edge0) / (edge1 - edge0), 0, 1); return t * t * (3 - 2 * t);` Results are undefined if `edge0 >= edge1`.
pub fn smoothstep<T: Number>(edge0: T, edge1: T, x: T) -> T {
let _3: T = FromPrimitive::from_f64(3.0).unwrap();
let _2: T = FromPrimitive::from_f64(2.0).unwrap();
pub fn smoothstep<T: RealNumber>(edge0: T, edge1: T, x: T) -> T {
let _3 = T::from_subset(&3.0f64);
let _2 = T::from_subset(&2.0f64);
let t = na::clamp((x - edge0) / (edge1 - edge0), T::zero(), T::one());
t * t * (_3 - t * _2)
}
@ -549,7 +549,7 @@ pub fn step_vec<T: Number, const D: usize>(edge: &TVec<T, D>, x: &TVec<T, D>) ->
/// * [`floor`](fn.floor.html)
/// * [`fract`](fn.fract.html)
/// * [`round`](fn.round.html)
pub fn trunc<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn trunc<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|x| x.trunc())
}

View File

@ -2,7 +2,8 @@ use crate::aliases::{
Qua, TMat, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3, TVec1,
TVec2, TVec3, TVec4,
};
use na::{RealField, Scalar};
use crate::RealNumber;
use na::Scalar;
/// Creates a new 1D vector.
///
@ -178,6 +179,6 @@ pub fn mat4<T: Scalar>(m11: T, m12: T, m13: T, m14: T,
}
/// Creates a new quaternion.
pub fn quat<T: RealField>(x: T, y: T, z: T, w: T) -> Qua<T> {
pub fn quat<T: RealNumber>(x: T, y: T, z: T, w: T) -> Qua<T> {
Qua::new(w, x, y, z)
}

View File

@ -1,12 +1,12 @@
use crate::aliases::TVec;
use na::RealField;
use crate::RealNumber;
/// Component-wise exponential.
///
/// # See also:
///
/// * [`exp2`](fn.exp2.html)
pub fn exp<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
pub fn exp<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
v.map(|x| x.exp())
}
@ -15,7 +15,7 @@ pub fn exp<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
/// # See also:
///
/// * [`exp`](fn.exp.html)
pub fn exp2<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
pub fn exp2<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
v.map(|x| x.exp2())
}
@ -24,7 +24,7 @@ pub fn exp2<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
/// # See also:
///
/// * [`sqrt`](fn.sqrt.html)
pub fn inversesqrt<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
pub fn inversesqrt<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
v.map(|x| T::one() / x.sqrt())
}
@ -33,7 +33,7 @@ pub fn inversesqrt<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
/// # See also:
///
/// * [`log2`](fn.log2.html)
pub fn log<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
pub fn log<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
v.map(|x| x.ln())
}
@ -42,12 +42,12 @@ pub fn log<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
/// # See also:
///
/// * [`log`](fn.log.html)
pub fn log2<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
pub fn log2<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
v.map(|x| x.log2())
}
/// Component-wise power.
pub fn pow<T: RealField, const D: usize>(base: &TVec<T, D>, exponent: &TVec<T, D>) -> TVec<T, D> {
pub fn pow<T: RealNumber, const D: usize>(base: &TVec<T, D>, exponent: &TVec<T, D>) -> TVec<T, D> {
base.zip_map(exponent, |b, e| b.powf(e))
}
@ -59,6 +59,6 @@ pub fn pow<T: RealField, const D: usize>(base: &TVec<T, D>, exponent: &TVec<T, D
/// * [`exp2`](fn.exp2.html)
/// * [`inversesqrt`](fn.inversesqrt.html)
/// * [`pow`](fn.pow.html)
pub fn sqrt<T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
pub fn sqrt<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<T, D> {
v.map(|x| x.sqrt())
}

View File

@ -1,51 +1,51 @@
use crate::aliases::TMat4;
use na::RealField;
use crate::RealNumber;
//pub fn frustum<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//pub fn frustum_lh<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_lh<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_lr_no<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_lr_no<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_lh_zo<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_lh_zo<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_no<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_no<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_rh<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_rh<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_rh_no<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_rh_no<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_rh_zo<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_rh_zo<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn frustum_zo<T: RealField>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
//pub fn frustum_zo<T: RealNumber>(left: T, right: T, bottom: T, top: T, near: T, far: T) -> TMat4<T> {
// unimplemented!()
//}
//pub fn infinite_perspective<T: RealField>(fovy: T, aspect: T, near: T) -> TMat4<T> {
//pub fn infinite_perspective<T: RealNumber>(fovy: T, aspect: T, near: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn infinite_perspective_lh<T: RealField>(fovy: T, aspect: T, near: T) -> TMat4<T> {
//pub fn infinite_perspective_lh<T: RealNumber>(fovy: T, aspect: T, near: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn infinite_ortho<T: RealField>(left: T, right: T, bottom: T, top: T) -> TMat4<T> {
//pub fn infinite_ortho<T: RealNumber>(left: T, right: T, bottom: T, top: T) -> TMat4<T> {
// unimplemented!()
//}
@ -60,7 +60,7 @@ use na::RealField;
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> TMat4<T> {
pub fn ortho<T: RealNumber>(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> TMat4<T> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
@ -75,7 +75,14 @@ pub fn ortho<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zfar:
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> TMat4<T> {
pub fn ortho_lh<T: RealNumber>(
left: T,
right: T,
bottom: T,
top: T,
znear: T,
zfar: T,
) -> TMat4<T> {
ortho_lh_no(left, right, bottom, top, znear, zfar)
}
@ -90,7 +97,7 @@ pub fn ortho_lh<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zf
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh_no<T: RealField>(
pub fn ortho_lh_no<T: RealNumber>(
left: T,
right: T,
bottom: T,
@ -122,7 +129,7 @@ pub fn ortho_lh_no<T: RealField>(
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_lh_zo<T: RealField>(
pub fn ortho_lh_zo<T: RealNumber>(
left: T,
right: T,
bottom: T,
@ -155,7 +162,14 @@ pub fn ortho_lh_zo<T: RealField>(
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_no<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> TMat4<T> {
pub fn ortho_no<T: RealNumber>(
left: T,
right: T,
bottom: T,
top: T,
znear: T,
zfar: T,
) -> TMat4<T> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
@ -170,7 +184,14 @@ pub fn ortho_no<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zf
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> TMat4<T> {
pub fn ortho_rh<T: RealNumber>(
left: T,
right: T,
bottom: T,
top: T,
znear: T,
zfar: T,
) -> TMat4<T> {
ortho_rh_no(left, right, bottom, top, znear, zfar)
}
@ -185,7 +206,7 @@ pub fn ortho_rh<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zf
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh_no<T: RealField>(
pub fn ortho_rh_no<T: RealNumber>(
left: T,
right: T,
bottom: T,
@ -217,7 +238,7 @@ pub fn ortho_rh_no<T: RealField>(
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_rh_zo<T: RealField>(
pub fn ortho_rh_zo<T: RealNumber>(
left: T,
right: T,
bottom: T,
@ -250,7 +271,14 @@ pub fn ortho_rh_zo<T: RealField>(
/// * `znear` - Distance from the viewer to the near clipping plane
/// * `zfar` - Distance from the viewer to the far clipping plane
///
pub fn ortho_zo<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> TMat4<T> {
pub fn ortho_zo<T: RealNumber>(
left: T,
right: T,
bottom: T,
top: T,
znear: T,
zfar: T,
) -> TMat4<T> {
ortho_rh_zo(left, right, bottom, top, znear, zfar)
}
@ -264,7 +292,7 @@ pub fn ortho_zo<T: RealField>(left: T, right: T, bottom: T, top: T, znear: T, zf
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov<T: RealField>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_fov<T: RealNumber>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
perspective_fov_rh_no(fov, width, height, near, far)
}
@ -278,7 +306,7 @@ pub fn perspective_fov<T: RealField>(fov: T, width: T, height: T, near: T, far:
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh<T: RealField>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_fov_lh<T: RealNumber>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
perspective_fov_lh_no(fov, width, height, near, far)
}
@ -292,7 +320,7 @@ pub fn perspective_fov_lh<T: RealField>(fov: T, width: T, height: T, near: T, fa
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh_no<T: RealField>(
pub fn perspective_fov_lh_no<T: RealNumber>(
fov: T,
width: T,
height: T,
@ -328,7 +356,7 @@ pub fn perspective_fov_lh_no<T: RealField>(
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_lh_zo<T: RealField>(
pub fn perspective_fov_lh_zo<T: RealNumber>(
fov: T,
width: T,
height: T,
@ -364,7 +392,7 @@ pub fn perspective_fov_lh_zo<T: RealField>(
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_no<T: RealField>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_fov_no<T: RealNumber>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
perspective_fov_rh_no(fov, width, height, near, far)
}
@ -378,7 +406,7 @@ pub fn perspective_fov_no<T: RealField>(fov: T, width: T, height: T, near: T, fa
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh<T: RealField>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_fov_rh<T: RealNumber>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
perspective_fov_rh_no(fov, width, height, near, far)
}
@ -392,7 +420,7 @@ pub fn perspective_fov_rh<T: RealField>(fov: T, width: T, height: T, near: T, fa
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh_no<T: RealField>(
pub fn perspective_fov_rh_no<T: RealNumber>(
fov: T,
width: T,
height: T,
@ -428,7 +456,7 @@ pub fn perspective_fov_rh_no<T: RealField>(
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_rh_zo<T: RealField>(
pub fn perspective_fov_rh_zo<T: RealNumber>(
fov: T,
width: T,
height: T,
@ -464,7 +492,7 @@ pub fn perspective_fov_rh_zo<T: RealField>(
/// * `near` - Distance from the viewer to the near clipping plane
/// * `far` - Distance from the viewer to the far clipping plane
///
pub fn perspective_fov_zo<T: RealField>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_fov_zo<T: RealNumber>(fov: T, width: T, height: T, near: T, far: T) -> TMat4<T> {
perspective_fov_rh_zo(fov, width, height, near, far)
}
@ -479,7 +507,7 @@ pub fn perspective_fov_zo<T: RealField>(fov: T, width: T, height: T, near: T, fa
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
// TODO: Breaking change - revert back to proper glm conventions?
//
// Prior to changes to support configuring the behaviour of this function it was simply
@ -508,7 +536,7 @@ pub fn perspective<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_lh<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
perspective_lh_no(aspect, fovy, near, far)
}
@ -523,7 +551,7 @@ pub fn perspective_lh<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh_no<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_lh_no<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
assert!(
!relative_eq!(far - near, T::zero()),
"The near-plane and far-plane must not be superimposed."
@ -559,7 +587,7 @@ pub fn perspective_lh_no<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> T
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_lh_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_lh_zo<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
assert!(
!relative_eq!(far - near, T::zero()),
"The near-plane and far-plane must not be superimposed."
@ -595,7 +623,7 @@ pub fn perspective_lh_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> T
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_no<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_no<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
perspective_rh_no(aspect, fovy, near, far)
}
@ -610,7 +638,7 @@ pub fn perspective_no<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_rh<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
perspective_rh_no(aspect, fovy, near, far)
}
@ -625,7 +653,7 @@ pub fn perspective_rh<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh_no<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_rh_no<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
assert!(
!relative_eq!(far - near, T::zero()),
"The near-plane and far-plane must not be superimposed."
@ -662,7 +690,7 @@ pub fn perspective_rh_no<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> T
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_rh_zo<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
assert!(
!relative_eq!(far - near, T::zero()),
"The near-plane and far-plane must not be superimposed."
@ -699,7 +727,7 @@ pub fn perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> T
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn perspective_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn perspective_zo<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
perspective_rh_zo(aspect, fovy, near, far)
}
@ -713,7 +741,7 @@ pub fn perspective_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat
///
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
pub fn infinite_perspective_rh_no<T: RealField>(aspect: T, fovy: T, near: T) -> TMat4<T> {
pub fn infinite_perspective_rh_no<T: RealNumber>(aspect: T, fovy: T, near: T) -> TMat4<T> {
let f = T::one() / (fovy * na::convert(0.5)).tan();
let mut mat = TMat4::zeros();
@ -738,7 +766,7 @@ pub fn infinite_perspective_rh_no<T: RealField>(aspect: T, fovy: T, near: T) ->
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
///
// https://discourse.nphysics.org/t/reversed-z-and-infinite-zfar-in-projections/341/2
pub fn infinite_perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T) -> TMat4<T> {
pub fn infinite_perspective_rh_zo<T: RealNumber>(aspect: T, fovy: T, near: T) -> TMat4<T> {
let f = T::one() / (fovy * na::convert(0.5)).tan();
let mut mat = TMat4::zeros();
@ -763,7 +791,7 @@ pub fn infinite_perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T) ->
/// # Important note
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
// NOTE: The variants `_no` of reversed perspective are not useful.
pub fn reversed_perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
pub fn reversed_perspective_rh_zo<T: RealNumber>(aspect: T, fovy: T, near: T, far: T) -> TMat4<T> {
let one = T::one();
let two = crate::convert(2.0);
let mut mat = TMat4::zeros();
@ -791,7 +819,7 @@ pub fn reversed_perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T, far
/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API.
// Credit: https://discourse.nphysics.org/t/reversed-z-and-infinite-zfar-in-projections/341/2
// NOTE: The variants `_no` of reversed perspective are not useful.
pub fn reversed_infinite_perspective_rh_zo<T: RealField>(aspect: T, fovy: T, near: T) -> TMat4<T> {
pub fn reversed_infinite_perspective_rh_zo<T: RealNumber>(aspect: T, fovy: T, near: T) -> TMat4<T> {
let f = T::one() / (fovy * na::convert(0.5)).tan();
let mut mat = TMat4::zeros();
@ -803,10 +831,10 @@ pub fn reversed_infinite_perspective_rh_zo<T: RealField>(aspect: T, fovy: T, nea
mat
}
//pub fn tweaked_infinite_perspective<T: RealField>(fovy: T, aspect: T, near: T) -> TMat4<T> {
//pub fn tweaked_infinite_perspective<T: RealNumber>(fovy: T, aspect: T, near: T) -> TMat4<T> {
// unimplemented!()
//}
//
//pub fn tweaked_infinite_perspective_ep<T: RealField>(fovy: T, aspect: T, near: T, ep: T) -> TMat4<T> {
//pub fn tweaked_infinite_perspective_ep<T: RealNumber>(fovy: T, aspect: T, near: T, ep: T) -> TMat4<T> {
// unimplemented!()
//}

View File

@ -1,6 +1,7 @@
use na::{self, RealField};
use na;
use crate::aliases::{TMat4, TVec2, TVec3, TVec4};
use crate::RealNumber;
/// Define a picking region.
///
@ -9,7 +10,7 @@ use crate::aliases::{TMat4, TVec2, TVec3, TVec4};
/// * `center` - Specify the center of a picking region in window coordinates.
/// * `delta` - Specify the width and height, respectively, of the picking region in window coordinates.
/// * `viewport` - Rendering viewport.
pub fn pick_matrix<T: RealField>(
pub fn pick_matrix<T: RealNumber>(
center: &TVec2<T>,
delta: &TVec2<T>,
viewport: &TVec4<T>,
@ -45,7 +46,7 @@ pub fn pick_matrix<T: RealField>(
/// * [`unproject`](fn.unproject.html)
/// * [`unproject_no`](fn.unproject_no.html)
/// * [`unproject_zo`](fn.unproject_zo.html)
pub fn project<T: RealField>(
pub fn project<T: RealNumber>(
obj: &TVec3<T>,
model: &TMat4<T>,
proj: &TMat4<T>,
@ -72,7 +73,7 @@ pub fn project<T: RealField>(
/// * [`unproject`](fn.unproject.html)
/// * [`unproject_no`](fn.unproject_no.html)
/// * [`unproject_zo`](fn.unproject_zo.html)
pub fn project_no<T: RealField>(
pub fn project_no<T: RealNumber>(
obj: &TVec3<T>,
model: &TMat4<T>,
proj: &TMat4<T>,
@ -100,7 +101,7 @@ pub fn project_no<T: RealField>(
/// * [`unproject`](fn.unproject.html)
/// * [`unproject_no`](fn.unproject_no.html)
/// * [`unproject_zo`](fn.unproject_zo.html)
pub fn project_zo<T: RealField>(
pub fn project_zo<T: RealNumber>(
obj: &TVec3<T>,
model: &TMat4<T>,
proj: &TMat4<T>,
@ -133,7 +134,7 @@ pub fn project_zo<T: RealField>(
/// * [`project_zo`](fn.project_zo.html)
/// * [`unproject_no`](fn.unproject_no.html)
/// * [`unproject_zo`](fn.unproject_zo.html)
pub fn unproject<T: RealField>(
pub fn unproject<T: RealNumber>(
win: &TVec3<T>,
model: &TMat4<T>,
proj: &TMat4<T>,
@ -160,7 +161,7 @@ pub fn unproject<T: RealField>(
/// * [`project_zo`](fn.project_zo.html)
/// * [`unproject`](fn.unproject.html)
/// * [`unproject_zo`](fn.unproject_zo.html)
pub fn unproject_no<T: RealField>(
pub fn unproject_no<T: RealNumber>(
win: &TVec3<T>,
model: &TMat4<T>,
proj: &TMat4<T>,
@ -197,7 +198,7 @@ pub fn unproject_no<T: RealField>(
/// * [`project_zo`](fn.project_zo.html)
/// * [`unproject`](fn.unproject.html)
/// * [`unproject_no`](fn.unproject_no.html)
pub fn unproject_zo<T: RealField>(
pub fn unproject_zo<T: RealNumber>(
win: &TVec3<T>,
model: &TMat4<T>,
proj: &TMat4<T>,

View File

@ -1,7 +1,7 @@
use na::{Point3, RealField, Rotation3, Unit};
use na::{Point3, Rotation3, Unit};
use crate::aliases::{TMat, TMat4, TVec, TVec3};
use crate::traits::Number;
use crate::traits::{Number, RealNumber};
/// The identity matrix.
pub fn identity<T: Number, const D: usize>() -> TMat<T, D, D> {
@ -20,7 +20,7 @@ pub fn identity<T: Number, const D: usize>() -> TMat<T, D, D> {
///
/// * [`look_at_lh`](fn.look_at_lh.html)
/// * [`look_at_rh`](fn.look_at_rh.html)
pub fn look_at<T: RealField>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
pub fn look_at<T: RealNumber>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
look_at_rh(eye, center, up)
}
@ -36,7 +36,7 @@ pub fn look_at<T: RealField>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -
///
/// * [`look_at`](fn.look_at.html)
/// * [`look_at_rh`](fn.look_at_rh.html)
pub fn look_at_lh<T: RealField>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
pub fn look_at_lh<T: RealNumber>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
TMat::look_at_lh(&Point3::from(*eye), &Point3::from(*center), up)
}
@ -52,7 +52,7 @@ pub fn look_at_lh<T: RealField>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>
///
/// * [`look_at`](fn.look_at.html)
/// * [`look_at_lh`](fn.look_at_lh.html)
pub fn look_at_rh<T: RealField>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
pub fn look_at_rh<T: RealNumber>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
TMat::look_at_rh(&Point3::from(*eye), &Point3::from(*center), up)
}
@ -71,7 +71,7 @@ pub fn look_at_rh<T: RealField>(eye: &TVec3<T>, center: &TVec3<T>, up: &TVec3<T>
/// * [`rotate_z`](fn.rotate_z.html)
/// * [`scale`](fn.scale.html)
/// * [`translate`](fn.translate.html)
pub fn rotate<T: RealField>(m: &TMat4<T>, angle: T, axis: &TVec3<T>) -> TMat4<T> {
pub fn rotate<T: RealNumber>(m: &TMat4<T>, angle: T, axis: &TVec3<T>) -> TMat4<T> {
m * Rotation3::from_axis_angle(&Unit::new_normalize(*axis), angle).to_homogeneous()
}
@ -89,7 +89,7 @@ pub fn rotate<T: RealField>(m: &TMat4<T>, angle: T, axis: &TVec3<T>) -> TMat4<T>
/// * [`rotate_z`](fn.rotate_z.html)
/// * [`scale`](fn.scale.html)
/// * [`translate`](fn.translate.html)
pub fn rotate_x<T: RealField>(m: &TMat4<T>, angle: T) -> TMat4<T> {
pub fn rotate_x<T: RealNumber>(m: &TMat4<T>, angle: T) -> TMat4<T> {
rotate(m, angle, &TVec::x())
}
@ -107,7 +107,7 @@ pub fn rotate_x<T: RealField>(m: &TMat4<T>, angle: T) -> TMat4<T> {
/// * [`rotate_z`](fn.rotate_z.html)
/// * [`scale`](fn.scale.html)
/// * [`translate`](fn.translate.html)
pub fn rotate_y<T: RealField>(m: &TMat4<T>, angle: T) -> TMat4<T> {
pub fn rotate_y<T: RealNumber>(m: &TMat4<T>, angle: T) -> TMat4<T> {
rotate(m, angle, &TVec::y())
}
@ -125,7 +125,7 @@ pub fn rotate_y<T: RealField>(m: &TMat4<T>, angle: T) -> TMat4<T> {
/// * [`rotate_y`](fn.rotate_y.html)
/// * [`scale`](fn.scale.html)
/// * [`translate`](fn.translate.html)
pub fn rotate_z<T: RealField>(m: &TMat4<T>, angle: T) -> TMat4<T> {
pub fn rotate_z<T: RealNumber>(m: &TMat4<T>, angle: T) -> TMat4<T> {
rotate(m, angle, &TVec::z())
}

View File

@ -1,36 +1,37 @@
use na::{self, RealField, Unit};
use na::{self, Unit};
use crate::aliases::Qua;
use crate::RealNumber;
/// The conjugate of `q`.
pub fn quat_conjugate<T: RealField>(q: &Qua<T>) -> Qua<T> {
pub fn quat_conjugate<T: RealNumber>(q: &Qua<T>) -> Qua<T> {
q.conjugate()
}
/// The inverse of `q`.
pub fn quat_inverse<T: RealField>(q: &Qua<T>) -> Qua<T> {
pub fn quat_inverse<T: RealNumber>(q: &Qua<T>) -> Qua<T> {
q.try_inverse().unwrap_or_else(na::zero)
}
//pub fn quat_isinf<T: RealField>(x: &Qua<T>) -> TVec<bool, U4> {
//pub fn quat_isinf<T: RealNumber>(x: &Qua<T>) -> TVec<bool, U4> {
// x.coords.map(|e| e.is_inf())
//}
//pub fn quat_isnan<T: RealField>(x: &Qua<T>) -> TVec<bool, U4> {
//pub fn quat_isnan<T: RealNumber>(x: &Qua<T>) -> TVec<bool, U4> {
// x.coords.map(|e| e.is_nan())
//}
/// Interpolate linearly between `x` and `y`.
pub fn quat_lerp<T: RealField>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
pub fn quat_lerp<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
x.lerp(y, a)
}
//pub fn quat_mix<T: RealField>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
//pub fn quat_mix<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
// x * (T::one() - a) + y * a
//}
/// Interpolate spherically between `x` and `y`.
pub fn quat_slerp<T: RealField>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
pub fn quat_slerp<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
Unit::new_normalize(*x)
.slerp(&Unit::new_normalize(*y), a)
.into_inner()

View File

@ -1,28 +1,28 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::Qua;
/// Multiplies two quaternions.
pub fn quat_cross<T: RealField>(q1: &Qua<T>, q2: &Qua<T>) -> Qua<T> {
pub fn quat_cross<T: RealNumber>(q1: &Qua<T>, q2: &Qua<T>) -> Qua<T> {
q1 * q2
}
/// The scalar product of two quaternions.
pub fn quat_dot<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> T {
pub fn quat_dot<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> T {
x.dot(y)
}
/// The magnitude of the quaternion `q`.
pub fn quat_length<T: RealField>(q: &Qua<T>) -> T {
pub fn quat_length<T: RealNumber>(q: &Qua<T>) -> T {
q.norm()
}
/// The magnitude of the quaternion `q`.
pub fn quat_magnitude<T: RealField>(q: &Qua<T>) -> T {
pub fn quat_magnitude<T: RealNumber>(q: &Qua<T>) -> T {
q.norm()
}
/// Normalizes the quaternion `q`.
pub fn quat_normalize<T: RealField>(q: &Qua<T>) -> Qua<T> {
pub fn quat_normalize<T: RealNumber>(q: &Qua<T>) -> Qua<T> {
q.normalize()
}

View File

@ -1,23 +1,22 @@
use na::RealField;
use crate::aliases::{Qua, TVec};
use crate::RealNumber;
/// Component-wise equality comparison between two quaternions.
pub fn quat_equal<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
pub fn quat_equal<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
crate::equal(&x.coords, &y.coords)
}
/// Component-wise approximate equality comparison between two quaternions.
pub fn quat_equal_eps<T: RealField>(x: &Qua<T>, y: &Qua<T>, epsilon: T) -> TVec<bool, 4> {
pub fn quat_equal_eps<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, epsilon: T) -> TVec<bool, 4> {
crate::equal_eps(&x.coords, &y.coords, epsilon)
}
/// Component-wise non-equality comparison between two quaternions.
pub fn quat_not_equal<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
pub fn quat_not_equal<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
crate::not_equal(&x.coords, &y.coords)
}
/// Component-wise approximate non-equality comparison between two quaternions.
pub fn quat_not_equal_eps<T: RealField>(x: &Qua<T>, y: &Qua<T>, epsilon: T) -> TVec<bool, 4> {
pub fn quat_not_equal_eps<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, epsilon: T) -> TVec<bool, 4> {
crate::not_equal_eps(&x.coords, &y.coords, epsilon)
}

View File

@ -1,27 +1,28 @@
use na::{RealField, Unit, UnitQuaternion};
use na::{Unit, UnitQuaternion};
use crate::aliases::{Qua, TVec3};
use crate::RealNumber;
/// Computes the quaternion exponential.
pub fn quat_exp<T: RealField>(q: &Qua<T>) -> Qua<T> {
pub fn quat_exp<T: RealNumber>(q: &Qua<T>) -> Qua<T> {
q.exp()
}
/// Computes the quaternion logarithm.
pub fn quat_log<T: RealField>(q: &Qua<T>) -> Qua<T> {
pub fn quat_log<T: RealNumber>(q: &Qua<T>) -> Qua<T> {
q.ln()
}
/// Raises the quaternion `q` to the power `y`.
pub fn quat_pow<T: RealField>(q: &Qua<T>, y: T) -> Qua<T> {
pub fn quat_pow<T: RealNumber>(q: &Qua<T>, y: T) -> Qua<T> {
q.powf(y)
}
/// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`.
pub fn quat_rotate<T: RealField>(q: &Qua<T>, angle: T, axis: &TVec3<T>) -> Qua<T> {
pub fn quat_rotate<T: RealNumber>(q: &Qua<T>, angle: T, axis: &TVec3<T>) -> Qua<T> {
q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner()
}
//pub fn quat_sqrt<T: RealField>(q: &Qua<T>) -> Qua<T> {
//pub fn quat_sqrt<T: RealNumber>(q: &Qua<T>) -> Qua<T> {
// unimplemented!()
//}

View File

@ -1,19 +1,20 @@
use na::{RealField, Unit, UnitQuaternion};
use na::{Unit, UnitQuaternion};
use crate::aliases::{Qua, TVec3};
use crate::RealNumber;
/// The rotation angle of this quaternion assumed to be normalized.
pub fn quat_angle<T: RealField>(x: &Qua<T>) -> T {
pub fn quat_angle<T: RealNumber>(x: &Qua<T>) -> T {
UnitQuaternion::from_quaternion(*x).angle()
}
/// Creates a quaternion from an axis and an angle.
pub fn quat_angle_axis<T: RealField>(angle: T, axis: &TVec3<T>) -> Qua<T> {
pub fn quat_angle_axis<T: RealNumber>(angle: T, axis: &TVec3<T>) -> Qua<T> {
UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner()
}
/// The rotation axis of a quaternion assumed to be normalized.
pub fn quat_axis<T: RealField>(x: &Qua<T>) -> TVec3<T> {
pub fn quat_axis<T: RealNumber>(x: &Qua<T>) -> TVec3<T> {
if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() {
a.into_inner()
} else {

View File

@ -1,5 +1,5 @@
use crate::RealNumber;
use approx::AbsDiffEq;
use na::RealField;
/// Default epsilon value used for approximate comparison.
pub fn epsilon<T: AbsDiffEq<Epsilon = T>>() -> T {
@ -22,6 +22,6 @@ pub fn epsilon<T: AbsDiffEq<Epsilon = T>>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn pi<T: RealField>() -> T {
pub fn pi<T: RealNumber>() -> T {
T::pi()
}

View File

@ -1,4 +1,4 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::{TVec, TVec3};
use crate::traits::Number;
@ -13,7 +13,7 @@ pub fn cross<T: Number>(x: &TVec3<T>, y: &TVec3<T>) -> TVec3<T> {
/// # See also:
///
/// * [`distance2`](fn.distance2.html)
pub fn distance<T: RealField, const D: usize>(p0: &TVec<T, D>, p1: &TVec<T, D>) -> T {
pub fn distance<T: RealNumber, const D: usize>(p0: &TVec<T, D>, p1: &TVec<T, D>) -> T {
(p1 - p0).norm()
}
@ -44,7 +44,7 @@ pub fn faceforward<T: Number, const D: usize>(
/// * [`length2`](fn.length2.html)
/// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude2`](fn.magnitude2.html)
pub fn length<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
pub fn length<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> T {
x.norm()
}
@ -57,12 +57,12 @@ pub fn length<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
/// * [`length`](fn.length.html)
/// * [`magnitude2`](fn.magnitude2.html)
/// * [`nalgebra::norm`](../nalgebra/fn.norm.html)
pub fn magnitude<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
pub fn magnitude<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> T {
x.norm()
}
/// Normalizes a vector.
pub fn normalize<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn normalize<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.normalize()
}
@ -73,7 +73,7 @@ pub fn reflect_vec<T: Number, const D: usize>(i: &TVec<T, D>, n: &TVec<T, D>) ->
}
/// For the incident vector `i` and surface normal `n`, and the ratio of indices of refraction `eta`, return the refraction vector.
pub fn refract_vec<T: RealField, const D: usize>(
pub fn refract_vec<T: RealNumber, const D: usize>(
i: &TVec<T, D>,
n: &TVec<T, D>,
eta: T,

View File

@ -1,14 +1,15 @@
use na::{self, RealField};
use crate::RealNumber;
use na;
/// The Euler constant.
///
/// This is a shorthand alias for [`euler`](fn.euler.html).
pub fn e<T: RealField>() -> T {
pub fn e<T: RealNumber>() -> T {
T::e()
}
/// The Euler constant.
pub fn euler<T: RealField>() -> T {
pub fn euler<T: RealNumber>() -> T {
T::e()
}
@ -28,12 +29,12 @@ pub fn euler<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn four_over_pi<T: RealField>() -> T {
pub fn four_over_pi<T: RealNumber>() -> T {
na::convert::<_, T>(4.0) / T::pi()
}
/// Returns the golden ratio.
pub fn golden_ratio<T: RealField>() -> T {
pub fn golden_ratio<T: RealNumber>() -> T {
(T::one() + root_five()) / na::convert(2.0)
}
@ -53,7 +54,7 @@ pub fn golden_ratio<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn half_pi<T: RealField>() -> T {
pub fn half_pi<T: RealNumber>() -> T {
T::frac_pi_2()
}
@ -63,7 +64,7 @@ pub fn half_pi<T: RealField>() -> T {
///
/// * [`ln_ten`](fn.ln_ten.html)
/// * [`ln_two`](fn.ln_two.html)
pub fn ln_ln_two<T: RealField>() -> T {
pub fn ln_ln_two<T: RealNumber>() -> T {
T::ln_2().ln()
}
@ -73,7 +74,7 @@ pub fn ln_ln_two<T: RealField>() -> T {
///
/// * [`ln_ln_two`](fn.ln_ln_two.html)
/// * [`ln_two`](fn.ln_two.html)
pub fn ln_ten<T: RealField>() -> T {
pub fn ln_ten<T: RealNumber>() -> T {
T::ln_10()
}
@ -83,7 +84,7 @@ pub fn ln_ten<T: RealField>() -> T {
///
/// * [`ln_ln_two`](fn.ln_ln_two.html)
/// * [`ln_ten`](fn.ln_ten.html)
pub fn ln_two<T: RealField>() -> T {
pub fn ln_two<T: RealNumber>() -> T {
T::ln_2()
}
@ -106,12 +107,12 @@ pub use na::one;
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn one_over_pi<T: RealField>() -> T {
pub fn one_over_pi<T: RealNumber>() -> T {
T::frac_1_pi()
}
/// Returns `1 / sqrt(2)`.
pub fn one_over_root_two<T: RealField>() -> T {
pub fn one_over_root_two<T: RealNumber>() -> T {
T::one() / root_two()
}
@ -131,7 +132,7 @@ pub fn one_over_root_two<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn one_over_two_pi<T: RealField>() -> T {
pub fn one_over_two_pi<T: RealNumber>() -> T {
T::frac_1_pi() * na::convert(0.5)
}
@ -151,7 +152,7 @@ pub fn one_over_two_pi<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn quarter_pi<T: RealField>() -> T {
pub fn quarter_pi<T: RealNumber>() -> T {
T::frac_pi_4()
}
@ -161,7 +162,7 @@ pub fn quarter_pi<T: RealField>() -> T {
///
/// * [`root_three`](fn.root_three.html)
/// * [`root_two`](fn.root_two.html)
pub fn root_five<T: RealField>() -> T {
pub fn root_five<T: RealNumber>() -> T {
na::convert::<_, T>(5.0).sqrt()
}
@ -181,12 +182,12 @@ pub fn root_five<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn root_half_pi<T: RealField>() -> T {
pub fn root_half_pi<T: RealNumber>() -> T {
(T::pi() / na::convert(2.0)).sqrt()
}
/// Returns `sqrt(ln(4))`.
pub fn root_ln_four<T: RealField>() -> T {
pub fn root_ln_four<T: RealNumber>() -> T {
na::convert::<_, T>(4.0).ln().sqrt()
}
@ -206,7 +207,7 @@ pub fn root_ln_four<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn root_pi<T: RealField>() -> T {
pub fn root_pi<T: RealNumber>() -> T {
T::pi().sqrt()
}
@ -216,7 +217,7 @@ pub fn root_pi<T: RealField>() -> T {
///
/// * [`root_five`](fn.root_five.html)
/// * [`root_two`](fn.root_two.html)
pub fn root_three<T: RealField>() -> T {
pub fn root_three<T: RealNumber>() -> T {
na::convert::<_, T>(3.0).sqrt()
}
@ -226,8 +227,8 @@ pub fn root_three<T: RealField>() -> T {
///
/// * [`root_five`](fn.root_five.html)
/// * [`root_three`](fn.root_three.html)
pub fn root_two<T: RealField>() -> T {
// TODO: there should be a crate::sqrt_2() on the RealField trait.
pub fn root_two<T: RealNumber>() -> T {
// TODO: there should be a crate::sqrt_2() on the RealNumber trait.
na::convert::<_, T>(2.0).sqrt()
}
@ -247,7 +248,7 @@ pub fn root_two<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn root_two_pi<T: RealField>() -> T {
pub fn root_two_pi<T: RealNumber>() -> T {
T::two_pi().sqrt()
}
@ -256,7 +257,7 @@ pub fn root_two_pi<T: RealField>() -> T {
/// # See also:
///
/// * [`two_thirds`](fn.two_thirds.html)
pub fn third<T: RealField>() -> T {
pub fn third<T: RealNumber>() -> T {
na::convert(1.0 / 3.0)
}
@ -276,7 +277,7 @@ pub fn third<T: RealField>() -> T {
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_over_root_pi`](fn.two_over_root_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn three_over_two_pi<T: RealField>() -> T {
pub fn three_over_two_pi<T: RealNumber>() -> T {
na::convert::<_, T>(3.0) / T::two_pi()
}
@ -295,7 +296,7 @@ pub fn three_over_two_pi<T: RealField>() -> T {
/// * [`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)
pub fn two_over_pi<T: RealField>() -> T {
pub fn two_over_pi<T: RealNumber>() -> T {
T::frac_2_pi()
}
@ -315,7 +316,7 @@ pub fn two_over_pi<T: RealField>() -> T {
/// * [`three_over_two_pi`](fn.three_over_two_pi.html)
/// * [`two_over_pi`](fn.two_over_pi.html)
/// * [`two_pi`](fn.two_pi.html)
pub fn two_over_root_pi<T: RealField>() -> T {
pub fn two_over_root_pi<T: RealNumber>() -> T {
T::frac_2_sqrt_pi()
}
@ -335,7 +336,7 @@ pub fn two_over_root_pi<T: RealField>() -> T {
/// * [`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)
pub fn two_pi<T: RealField>() -> T {
pub fn two_pi<T: RealNumber>() -> T {
T::two_pi()
}
@ -344,7 +345,7 @@ pub fn two_pi<T: RealField>() -> T {
/// # See also:
///
/// * [`third`](fn.third.html)
pub fn two_thirds<T: RealField>() -> T {
pub fn two_thirds<T: RealNumber>() -> T {
na::convert(2.0 / 3.0)
}

View File

@ -1,15 +1,15 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::TMat;
/// Fast matrix inverse for affine matrix.
pub fn affine_inverse<T: RealField, const D: usize>(m: TMat<T, D, D>) -> TMat<T, D, D> {
pub fn affine_inverse<T: RealNumber, const D: usize>(m: TMat<T, D, D>) -> TMat<T, D, D> {
// TODO: this should be optimized.
m.try_inverse().unwrap_or_else(TMat::<_, D, D>::zeros)
}
/// Compute the transpose of the inverse of a matrix.
pub fn inverse_transpose<T: RealField, const D: usize>(m: TMat<T, D, D>) -> TMat<T, D, D> {
pub fn inverse_transpose<T: RealNumber, const D: usize>(m: TMat<T, D, D>) -> TMat<T, D, D> {
m.try_inverse()
.unwrap_or_else(TMat::<_, D, D>::zeros)
.transpose()

View File

@ -1,4 +1,4 @@
use na::{DefaultAllocator, RealField, Scalar, U3, U4};
use na::{DefaultAllocator, RealNumber, Scalar, U3, U4};
use crate::aliases::*;
@ -53,7 +53,7 @@ pub fn packRGBM<T: Scalar>(rgb: &TVec3<T>) -> TVec4<T> {
unimplemented!()
}
pub fn packSnorm<I: Scalar, T: RealField, const D: usize>(v: TVec<T, D>) -> TVec<I, D>
pub fn packSnorm<I: Scalar, T: RealNumber, const D: usize>(v: TVec<T, D>) -> TVec<I, D>
where
DefaultAllocator: Alloc<T, D> + Alloc<I, D>,
{
@ -104,7 +104,7 @@ pub fn packUint4x8(v: &U8Vec4) -> i32 {
unimplemented!()
}
pub fn packUnorm<UI: Scalar, T: RealField, const D: usize>(v: &TVec<T, D>) -> TVec<UI, D>
pub fn packUnorm<UI: Scalar, T: RealNumber, const D: usize>(v: &TVec<T, D>) -> TVec<UI, D>
where
DefaultAllocator: Alloc<T, D> + Alloc<UI, D>,
{
@ -199,7 +199,7 @@ pub fn unpackRGBM<T: Scalar>(rgbm: &TVec4<T>) -> TVec3<T> {
unimplemented!()
}
pub fn unpackSnorm<I: Scalar, T: RealField, const D: usize>(v: &TVec<I, D>) -> TVec<T, D>
pub fn unpackSnorm<I: Scalar, T: RealNumber, const D: usize>(v: &TVec<I, D>) -> TVec<T, D>
where
DefaultAllocator: Alloc<T, D> + Alloc<I, D>,
{
@ -250,7 +250,7 @@ pub fn unpackUint4x8(p: i32) -> U8Vec4 {
unimplemented!()
}
pub fn unpackUnorm<UI: Scalar, T: RealField, const D: usize>(v: &TVec<UI, D>) -> TVec<T, D>
pub fn unpackUnorm<UI: Scalar, T: RealNumber, const D: usize>(v: &TVec<UI, D>) -> TVec<T, D>
where
DefaultAllocator: Alloc<T, D> + Alloc<UI, D>,
{

View File

@ -1,36 +1,37 @@
use na::{RealField, UnitQuaternion};
use na::UnitQuaternion;
use crate::aliases::{Qua, TMat4, TVec, TVec3};
use crate::RealNumber;
/// Euler angles of the quaternion `q` as (pitch, yaw, roll).
pub fn quat_euler_angles<T: RealField>(x: &Qua<T>) -> TVec3<T> {
pub fn quat_euler_angles<T: RealNumber>(x: &Qua<T>) -> TVec3<T> {
let q = UnitQuaternion::new_unchecked(*x);
let a = q.euler_angles();
TVec3::new(a.2, a.1, a.0)
}
/// Component-wise `>` comparison between two quaternions.
pub fn quat_greater_than<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
pub fn quat_greater_than<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
crate::greater_than(&x.coords, &y.coords)
}
/// Component-wise `>=` comparison between two quaternions.
pub fn quat_greater_than_equal<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
pub fn quat_greater_than_equal<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
crate::greater_than_equal(&x.coords, &y.coords)
}
/// Component-wise `<` comparison between two quaternions.
pub fn quat_less_than<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
pub fn quat_less_than<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
crate::less_than(&x.coords, &y.coords)
}
/// Component-wise `<=` comparison between two quaternions.
pub fn quat_less_than_equal<T: RealField>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
pub fn quat_less_than_equal<T: RealNumber>(x: &Qua<T>, y: &Qua<T>) -> TVec<bool, 4> {
crate::less_than_equal(&x.coords, &y.coords)
}
/// Convert a quaternion to a rotation matrix in homogeneous coordinates.
pub fn quat_cast<T: RealField>(x: &Qua<T>) -> TMat4<T> {
pub fn quat_cast<T: RealNumber>(x: &Qua<T>) -> TMat4<T> {
crate::quat_to_mat4(x)
}
@ -41,34 +42,34 @@ pub fn quat_cast<T: RealField>(x: &Qua<T>) -> TMat4<T> {
/// * `direction` - Direction vector point at where to look
/// * `up` - Object up vector
///
pub fn quat_look_at<T: RealField>(direction: &TVec3<T>, up: &TVec3<T>) -> Qua<T> {
pub fn quat_look_at<T: RealNumber>(direction: &TVec3<T>, up: &TVec3<T>) -> Qua<T> {
quat_look_at_rh(direction, up)
}
/// Computes a left-handed look-at quaternion (equivalent to a left-handed look-at matrix).
pub fn quat_look_at_lh<T: RealField>(direction: &TVec3<T>, up: &TVec3<T>) -> Qua<T> {
pub fn quat_look_at_lh<T: RealNumber>(direction: &TVec3<T>, up: &TVec3<T>) -> Qua<T> {
UnitQuaternion::look_at_lh(direction, up).into_inner()
}
/// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix).
pub fn quat_look_at_rh<T: RealField>(direction: &TVec3<T>, up: &TVec3<T>) -> Qua<T> {
pub fn quat_look_at_rh<T: RealNumber>(direction: &TVec3<T>, up: &TVec3<T>) -> Qua<T> {
UnitQuaternion::look_at_rh(direction, up).into_inner()
}
/// The "roll" Euler angle of the quaternion `x` assumed to be normalized.
pub fn quat_roll<T: RealField>(x: &Qua<T>) -> T {
pub fn quat_roll<T: RealNumber>(x: &Qua<T>) -> T {
// TODO: optimize this.
quat_euler_angles(x).z
}
/// The "yaw" Euler angle of the quaternion `x` assumed to be normalized.
pub fn quat_yaw<T: RealField>(x: &Qua<T>) -> T {
pub fn quat_yaw<T: RealNumber>(x: &Qua<T>) -> T {
// TODO: optimize this.
quat_euler_angles(x).y
}
/// The "pitch" Euler angle of the quaternion `x` assumed to be normalized.
pub fn quat_pitch<T: RealField>(x: &Qua<T>) -> T {
pub fn quat_pitch<T: RealNumber>(x: &Qua<T>) -> T {
// TODO: optimize this.
quat_euler_angles(x).x
}

View File

@ -1,4 +1,4 @@
use na::{DefaultAllocator, RealField, Scalar, U3};
use na::{DefaultAllocator, RealNumber, Scalar, U3};
use crate::aliases::TVec;
use crate::traits::{Alloc, Dimension, Number};

View File

@ -1,10 +1,10 @@
use na::{Quaternion, RealField, Scalar};
use na::{Quaternion, Scalar};
use crate::aliases::{
Qua, TMat, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3, TVec1,
TVec2, TVec3, TVec4,
};
use crate::traits::Number;
use crate::traits::{Number, RealNumber};
/// Creates a 2x2 matrix from a slice arranged in column-major order.
pub fn make_mat2<T: Scalar>(ptr: &[T]) -> TMat2<T> {
@ -76,12 +76,7 @@ pub fn mat2_to_mat3<T: Number>(m: &TMat2<T>) -> TMat3<T> {
/// Converts a 3x3 matrix to a 2x2 matrix.
pub fn mat3_to_mat2<T: Scalar>(m: &TMat3<T>) -> TMat2<T> {
TMat2::new(
m.m11.inlined_clone(),
m.m12.inlined_clone(),
m.m21.inlined_clone(),
m.m22.inlined_clone(),
)
TMat2::new(m.m11.clone(), m.m12.clone(), m.m21.clone(), m.m22.clone())
}
/// Converts a 3x3 matrix to a 4x4 matrix.
@ -97,15 +92,15 @@ pub fn mat3_to_mat4<T: Number>(m: &TMat3<T>) -> TMat4<T> {
/// Converts a 4x4 matrix to a 3x3 matrix.
pub fn mat4_to_mat3<T: Scalar>(m: &TMat4<T>) -> TMat3<T> {
TMat3::new(
m.m11.inlined_clone(),
m.m12.inlined_clone(),
m.m13.inlined_clone(),
m.m21.inlined_clone(),
m.m22.inlined_clone(),
m.m23.inlined_clone(),
m.m31.inlined_clone(),
m.m32.inlined_clone(),
m.m33.inlined_clone(),
m.m11.clone(),
m.m12.clone(),
m.m13.clone(),
m.m21.clone(),
m.m22.clone(),
m.m23.clone(),
m.m31.clone(),
m.m32.clone(),
m.m33.clone(),
)
}
@ -121,16 +116,11 @@ pub fn mat2_to_mat4<T: Number>(m: &TMat2<T>) -> TMat4<T> {
/// Converts a 4x4 matrix to a 2x2 matrix.
pub fn mat4_to_mat2<T: Scalar>(m: &TMat4<T>) -> TMat2<T> {
TMat2::new(
m.m11.inlined_clone(),
m.m12.inlined_clone(),
m.m21.inlined_clone(),
m.m22.inlined_clone(),
)
TMat2::new(m.m11.clone(), m.m12.clone(), m.m21.clone(), m.m22.clone())
}
/// Creates a quaternion from a slice arranged as `[x, y, z, w]`.
pub fn make_quat<T: RealField>(ptr: &[T]) -> Qua<T> {
pub fn make_quat<T: RealNumber>(ptr: &[T]) -> Qua<T> {
Quaternion::from(TVec4::from_column_slice(ptr))
}
@ -156,7 +146,7 @@ pub fn make_vec1<T: Scalar>(v: &TVec1<T>) -> TVec1<T> {
/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html)
/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html)
pub fn vec2_to_vec1<T: Scalar>(v: &TVec2<T>) -> TVec1<T> {
TVec1::new(v.x.inlined_clone())
TVec1::new(v.x.clone())
}
/// Creates a 1D vector from another vector.
@ -170,7 +160,7 @@ pub fn vec2_to_vec1<T: Scalar>(v: &TVec2<T>) -> TVec1<T> {
/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html)
/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html)
pub fn vec3_to_vec1<T: Scalar>(v: &TVec3<T>) -> TVec1<T> {
TVec1::new(v.x.inlined_clone())
TVec1::new(v.x.clone())
}
/// Creates a 1D vector from another vector.
@ -184,7 +174,7 @@ pub fn vec3_to_vec1<T: Scalar>(v: &TVec3<T>) -> TVec1<T> {
/// * [`vec1_to_vec3`](fn.vec1_to_vec3.html)
/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html)
pub fn vec4_to_vec1<T: Scalar>(v: &TVec4<T>) -> TVec1<T> {
TVec1::new(v.x.inlined_clone())
TVec1::new(v.x.clone())
}
/// Creates a 2D vector from another vector.
@ -200,7 +190,7 @@ pub fn vec4_to_vec1<T: Scalar>(v: &TVec4<T>) -> TVec1<T> {
/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html)
/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html)
pub fn vec1_to_vec2<T: Number>(v: &TVec1<T>) -> TVec2<T> {
TVec2::new(v.x.inlined_clone(), T::zero())
TVec2::new(v.x.clone(), T::zero())
}
/// Creates a 2D vector from another vector.
@ -229,7 +219,7 @@ pub fn vec2_to_vec2<T: Scalar>(v: &TVec2<T>) -> TVec2<T> {
/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html)
/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html)
pub fn vec3_to_vec2<T: Scalar>(v: &TVec3<T>) -> TVec2<T> {
TVec2::new(v.x.inlined_clone(), v.y.inlined_clone())
TVec2::new(v.x.clone(), v.y.clone())
}
/// Creates a 2D vector from another vector.
@ -243,7 +233,7 @@ pub fn vec3_to_vec2<T: Scalar>(v: &TVec3<T>) -> TVec2<T> {
/// * [`vec2_to_vec3`](fn.vec2_to_vec3.html)
/// * [`vec2_to_vec4`](fn.vec2_to_vec4.html)
pub fn vec4_to_vec2<T: Scalar>(v: &TVec4<T>) -> TVec2<T> {
TVec2::new(v.x.inlined_clone(), v.y.inlined_clone())
TVec2::new(v.x.clone(), v.y.clone())
}
/// Creates a 2D vector from a slice.
@ -269,7 +259,7 @@ pub fn make_vec2<T: Scalar>(ptr: &[T]) -> TVec2<T> {
/// * [`vec1_to_vec2`](fn.vec1_to_vec2.html)
/// * [`vec1_to_vec4`](fn.vec1_to_vec4.html)
pub fn vec1_to_vec3<T: Number>(v: &TVec1<T>) -> TVec3<T> {
TVec3::new(v.x.inlined_clone(), T::zero(), T::zero())
TVec3::new(v.x.clone(), T::zero(), T::zero())
}
/// Creates a 3D vector from another vector.
@ -285,7 +275,7 @@ pub fn vec1_to_vec3<T: Number>(v: &TVec1<T>) -> TVec3<T> {
/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html)
/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html)
pub fn vec2_to_vec3<T: Number>(v: &TVec2<T>) -> TVec3<T> {
TVec3::new(v.x.inlined_clone(), v.y.inlined_clone(), T::zero())
TVec3::new(v.x.clone(), v.y.clone(), T::zero())
}
/// Creates a 3D vector from another vector.
@ -313,11 +303,7 @@ pub fn vec3_to_vec3<T: Scalar>(v: &TVec3<T>) -> TVec3<T> {
/// * [`vec3_to_vec2`](fn.vec3_to_vec2.html)
/// * [`vec3_to_vec4`](fn.vec3_to_vec4.html)
pub fn vec4_to_vec3<T: Scalar>(v: &TVec4<T>) -> TVec3<T> {
TVec3::new(
v.x.inlined_clone(),
v.y.inlined_clone(),
v.z.inlined_clone(),
)
TVec3::new(v.x.clone(), v.y.clone(), v.z.clone())
}
/// Creates a 3D vector from another vector.

View File

@ -1,163 +1,163 @@
use na::{RealField, U3, U4};
use na::{RealNumber, U3, U4};
use crate::aliases::{TMat, TVec};
pub fn derivedEulerAngleX<T: RealField>(angleX: T, angularVelocityX: T) -> TMat4<T> {
pub fn derivedEulerAngleX<T: RealNumber>(angleX: T, angularVelocityX: T) -> TMat4<T> {
unimplemented!()
}
pub fn derivedEulerAngleY<T: RealField>(angleY: T, angularVelocityY: T) -> TMat4<T> {
pub fn derivedEulerAngleY<T: RealNumber>(angleY: T, angularVelocityY: T) -> TMat4<T> {
unimplemented!()
}
pub fn derivedEulerAngleZ<T: RealField>(angleZ: T, angularVelocityZ: T) -> TMat4<T> {
pub fn derivedEulerAngleZ<T: RealNumber>(angleZ: T, angularVelocityZ: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleX<T: RealField>(angleX: T) -> TMat4<T> {
pub fn eulerAngleX<T: RealNumber>(angleX: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleXY<T: RealField>(angleX: T, angleY: T) -> TMat4<T> {
pub fn eulerAngleXY<T: RealNumber>(angleX: T, angleY: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleXYX<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleXYX<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleXYZ<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleXYZ<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleXZ<T: RealField>(angleX: T, angleZ: T) -> TMat4<T> {
pub fn eulerAngleXZ<T: RealNumber>(angleX: T, angleZ: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleXZX<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleXZX<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleXZY<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleXZY<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleY<T: RealField>(angleY: T) -> TMat4<T> {
pub fn eulerAngleY<T: RealNumber>(angleY: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleYX<T: RealField>(angleY: T, angleX: T) -> TMat4<T> {
pub fn eulerAngleYX<T: RealNumber>(angleY: T, angleX: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleYXY<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleYXY<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleYXZ<T: RealField>(yaw: T, pitch: T, roll: T) -> TMat4<T> {
pub fn eulerAngleYXZ<T: RealNumber>(yaw: T, pitch: T, roll: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleYZ<T: RealField>(angleY: T, angleZ: T) -> TMat4<T> {
pub fn eulerAngleYZ<T: RealNumber>(angleY: T, angleZ: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleYZX<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleYZX<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleYZY<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleYZY<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZ<T: RealField>(angleZ: T) -> TMat4<T> {
pub fn eulerAngleZ<T: RealNumber>(angleZ: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZX<T: RealField>(angle: T, angleX: T) -> TMat4<T> {
pub fn eulerAngleZX<T: RealNumber>(angle: T, angleX: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZXY<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleZXY<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZXZ<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleZXZ<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZY<T: RealField>(angleZ: T, angleY: T) -> TMat4<T> {
pub fn eulerAngleZY<T: RealNumber>(angleZ: T, angleY: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZYX<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleZYX<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn eulerAngleZYZ<T: RealField>(t1: T, t2: T, t3: T) -> TMat4<T> {
pub fn eulerAngleZYZ<T: RealNumber>(t1: T, t2: T, t3: T) -> TMat4<T> {
unimplemented!()
}
pub fn extractEulerAngleXYX<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleXYX<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleXYZ<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleXYZ<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleXZX<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleXZX<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleXZY<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleXZY<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleYXY<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleYXY<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleYXZ<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleYXZ<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleYZX<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleYZX<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleYZY<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleYZY<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleZXY<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleZXY<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleZXZ<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleZXZ<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleZYX<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleZYX<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn extractEulerAngleZYZ<T: RealField>(M: &TMat4<T>) -> (T, T, T) {
pub fn extractEulerAngleZYZ<T: RealNumber>(M: &TMat4<T>) -> (T, T, T) {
unimplemented!()
}
pub fn orientate2<T: RealField>(angle: T) -> TMat3x3<T> {
pub fn orientate2<T: RealNumber>(angle: T) -> TMat3x3<T> {
unimplemented!()
}
pub fn orientate3<T: RealField>(angles: TVec3<T>) -> TMat3x3<T> {
pub fn orientate3<T: RealNumber>(angles: TVec3<T>) -> TMat3x3<T> {
unimplemented!()
}
pub fn orientate4<T: RealField>(angles: TVec3<T>) -> TMat4<T> {
pub fn orientate4<T: RealNumber>(angles: TVec3<T>) -> TMat4<T> {
unimplemented!()
}
pub fn yawPitchRoll<T: RealField>(yaw: T, pitch: T, roll: T) -> TMat4<T> {
pub fn yawPitchRoll<T: RealNumber>(yaw: T, pitch: T, roll: T) -> TMat4<T> {
unimplemented!()
}

View File

@ -1,13 +1,12 @@
use na::RealField;
use crate::aliases::{TMat3, TMat4, TVec3};
use crate::RealNumber;
/// Builds a 3x3 matrix `m` such that for any `v`: `m * v == cross(x, v)`.
///
/// # See also:
///
/// * [`matrix_cross`](fn.matrix_cross.html)
pub fn matrix_cross3<T: RealField>(x: &TVec3<T>) -> TMat3<T> {
pub fn matrix_cross3<T: RealNumber>(x: &TVec3<T>) -> TMat3<T> {
x.cross_matrix()
}
@ -16,6 +15,6 @@ pub fn matrix_cross3<T: RealField>(x: &TVec3<T>) -> TMat3<T> {
/// # See also:
///
/// * [`matrix_cross3`](fn.matrix_cross3.html)
pub fn matrix_cross<T: RealField>(x: &TVec3<T>) -> TMat4<T> {
pub fn matrix_cross<T: RealNumber>(x: &TVec3<T>) -> TMat4<T> {
crate::mat3_to_mat4(&x.cross_matrix())
}

View File

@ -1,13 +1,12 @@
use na::RealField;
use crate::aliases::TVec;
use crate::RealNumber;
/// The squared distance between two points.
///
/// # See also:
///
/// * [`distance`](fn.distance.html)
pub fn distance2<T: RealField, const D: usize>(p0: &TVec<T, D>, p1: &TVec<T, D>) -> T {
pub fn distance2<T: RealNumber, const D: usize>(p0: &TVec<T, D>, p1: &TVec<T, D>) -> T {
(p1 - p0).norm_squared()
}
@ -18,7 +17,7 @@ pub fn distance2<T: RealField, const D: usize>(p0: &TVec<T, D>, p1: &TVec<T, D>)
/// * [`l1_norm`](fn.l1_norm.html)
/// * [`l2_distance`](fn.l2_distance.html)
/// * [`l2_norm`](fn.l2_norm.html)
pub fn l1_distance<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
pub fn l1_distance<T: RealNumber, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
l1_norm(&(y - x))
}
@ -32,7 +31,7 @@ pub fn l1_distance<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>)
/// * [`l1_distance`](fn.l1_distance.html)
/// * [`l2_distance`](fn.l2_distance.html)
/// * [`l2_norm`](fn.l2_norm.html)
pub fn l1_norm<T: RealField, const D: usize>(v: &TVec<T, D>) -> T {
pub fn l1_norm<T: RealNumber, const D: usize>(v: &TVec<T, D>) -> T {
crate::comp_add(&v.abs())
}
@ -50,7 +49,7 @@ pub fn l1_norm<T: RealField, const D: usize>(v: &TVec<T, D>) -> T {
/// * [`length2`](fn.length2.html)
/// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude2`](fn.magnitude2.html)
pub fn l2_distance<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
pub fn l2_distance<T: RealNumber, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
l2_norm(&(y - x))
}
@ -70,7 +69,7 @@ pub fn l2_distance<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>)
/// * [`length2`](fn.length2.html)
/// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude2`](fn.magnitude2.html)
pub fn l2_norm<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
pub fn l2_norm<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> T {
x.norm()
}
@ -85,7 +84,7 @@ pub fn l2_norm<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
/// * [`length`](fn.length.html)
/// * [`magnitude`](fn.magnitude.html)
/// * [`magnitude2`](fn.magnitude2.html)
pub fn length2<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
pub fn length2<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> T {
x.norm_squared()
}
@ -100,14 +99,14 @@ pub fn length2<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
/// * [`length2`](fn.length2.html)
/// * [`magnitude`](fn.magnitude.html)
/// * [`nalgebra::norm_squared`](../nalgebra/fn.norm_squared.html)
pub fn magnitude2<T: RealField, const D: usize>(x: &TVec<T, D>) -> T {
pub fn magnitude2<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> T {
x.norm_squared()
}
//pub fn lxNorm<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>, unsigned int Depth) -> T {
//pub fn lxNorm<T: RealNumber, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>, unsigned int Depth) -> T {
// unimplemented!()
//}
//
//pub fn lxNorm<T: RealField, const D: usize>(x: &TVec<T, D>, unsigned int Depth) -> T {
//pub fn lxNorm<T: RealNumber, const D: usize>(x: &TVec<T, D>, unsigned int Depth) -> T {
// unimplemented!()
//}

View File

@ -1,10 +1,10 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::TVec3;
/// The normal vector of the given triangle.
///
/// The normal is computed as the normalized vector `cross(p2 - p1, p3 - p1)`.
pub fn triangle_normal<T: RealField>(p1: &TVec3<T>, p2: &TVec3<T>, p3: &TVec3<T>) -> TVec3<T> {
pub fn triangle_normal<T: RealNumber>(p1: &TVec3<T>, p2: &TVec3<T>, p3: &TVec3<T>) -> TVec3<T> {
(p2 - p1).cross(&(p3 - p1)).normalize()
}

View File

@ -1,4 +1,4 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::TVec;
@ -9,7 +9,7 @@ use crate::aliases::TVec;
/// # See also:
///
/// * [`normalize_dot`](fn.normalize_dot.html`)
pub fn fast_normalize_dot<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
pub fn fast_normalize_dot<T: RealNumber, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
// XXX: improve those.
x.normalize().dot(&y.normalize())
}
@ -19,7 +19,7 @@ pub fn fast_normalize_dot<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec
/// # See also:
///
/// * [`fast_normalize_dot`](fn.fast_normalize_dot.html`)
pub fn normalize_dot<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
pub fn normalize_dot<T: RealNumber, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
// XXX: improve those.
x.normalize().dot(&y.normalize())
}

View File

@ -1,97 +1,98 @@
use na::{RealField, Rotation3, Unit, UnitQuaternion};
use na::{Rotation3, Unit, UnitQuaternion};
use crate::aliases::{Qua, TMat3, TMat4, TVec3, TVec4};
use crate::RealNumber;
/// Rotate the vector `v` by the quaternion `q` assumed to be normalized.
pub fn quat_cross_vec<T: RealField>(q: &Qua<T>, v: &TVec3<T>) -> TVec3<T> {
pub fn quat_cross_vec<T: RealNumber>(q: &Qua<T>, v: &TVec3<T>) -> TVec3<T> {
UnitQuaternion::new_unchecked(*q) * v
}
/// Rotate the vector `v` by the inverse of the quaternion `q` assumed to be normalized.
pub fn quat_inv_cross_vec<T: RealField>(v: &TVec3<T>, q: &Qua<T>) -> TVec3<T> {
pub fn quat_inv_cross_vec<T: RealNumber>(v: &TVec3<T>, q: &Qua<T>) -> TVec3<T> {
UnitQuaternion::new_unchecked(*q).inverse() * v
}
/// The quaternion `w` component.
pub fn quat_extract_real_component<T: RealField>(q: &Qua<T>) -> T {
pub fn quat_extract_real_component<T: RealNumber>(q: &Qua<T>) -> T {
q.w
}
/// Normalized linear interpolation between two quaternions.
pub fn quat_fast_mix<T: RealField>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
pub fn quat_fast_mix<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
Unit::new_unchecked(*x)
.nlerp(&Unit::new_unchecked(*y), a)
.into_inner()
}
//pub fn quat_intermediate<T: RealField>(prev: &Qua<T>, curr: &Qua<T>, next: &Qua<T>) -> Qua<T> {
//pub fn quat_intermediate<T: RealNumber>(prev: &Qua<T>, curr: &Qua<T>, next: &Qua<T>) -> Qua<T> {
// unimplemented!()
//}
/// The squared magnitude of a quaternion `q`.
pub fn quat_length2<T: RealField>(q: &Qua<T>) -> T {
pub fn quat_length2<T: RealNumber>(q: &Qua<T>) -> T {
q.norm_squared()
}
/// The squared magnitude of a quaternion `q`.
pub fn quat_magnitude2<T: RealField>(q: &Qua<T>) -> T {
pub fn quat_magnitude2<T: RealNumber>(q: &Qua<T>) -> T {
q.norm_squared()
}
/// The quaternion representing the identity rotation.
pub fn quat_identity<T: RealField>() -> Qua<T> {
pub fn quat_identity<T: RealNumber>() -> Qua<T> {
UnitQuaternion::identity().into_inner()
}
/// Rotates a vector by a quaternion assumed to be normalized.
pub fn quat_rotate_vec3<T: RealField>(q: &Qua<T>, v: &TVec3<T>) -> TVec3<T> {
pub fn quat_rotate_vec3<T: RealNumber>(q: &Qua<T>, v: &TVec3<T>) -> TVec3<T> {
UnitQuaternion::new_unchecked(*q) * v
}
/// Rotates a vector in homogeneous coordinates by a quaternion assumed to be normalized.
pub fn quat_rotate_vec<T: RealField>(q: &Qua<T>, v: &TVec4<T>) -> TVec4<T> {
pub fn quat_rotate_vec<T: RealNumber>(q: &Qua<T>, v: &TVec4<T>) -> TVec4<T> {
let rotated = Unit::new_unchecked(*q) * v.fixed_rows::<3>(0);
TVec4::new(rotated.x, rotated.y, rotated.z, v.w)
}
/// The rotation required to align `orig` to `dest`.
pub fn quat_rotation<T: RealField>(orig: &TVec3<T>, dest: &TVec3<T>) -> Qua<T> {
pub fn quat_rotation<T: RealNumber>(orig: &TVec3<T>, dest: &TVec3<T>) -> Qua<T> {
UnitQuaternion::rotation_between(orig, dest)
.unwrap_or_else(UnitQuaternion::identity)
.into_inner()
}
/// The spherical linear interpolation between two quaternions.
pub fn quat_short_mix<T: RealField>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
pub fn quat_short_mix<T: RealNumber>(x: &Qua<T>, y: &Qua<T>, a: T) -> Qua<T> {
Unit::new_normalize(*x)
.slerp(&Unit::new_normalize(*y), a)
.into_inner()
}
//pub fn quat_squad<T: RealField>(q1: &Qua<T>, q2: &Qua<T>, s1: &Qua<T>, s2: &Qua<T>, h: T) -> Qua<T> {
//pub fn quat_squad<T: RealNumber>(q1: &Qua<T>, q2: &Qua<T>, s1: &Qua<T>, s2: &Qua<T>, h: T) -> Qua<T> {
// unimplemented!()
//}
/// Converts a quaternion to a rotation matrix.
pub fn quat_to_mat3<T: RealField>(x: &Qua<T>) -> TMat3<T> {
pub fn quat_to_mat3<T: RealNumber>(x: &Qua<T>) -> TMat3<T> {
UnitQuaternion::new_unchecked(*x)
.to_rotation_matrix()
.into_inner()
}
/// Converts a quaternion to a rotation matrix in homogenous coordinates.
pub fn quat_to_mat4<T: RealField>(x: &Qua<T>) -> TMat4<T> {
pub fn quat_to_mat4<T: RealNumber>(x: &Qua<T>) -> TMat4<T> {
UnitQuaternion::new_unchecked(*x).to_homogeneous()
}
/// Converts a rotation matrix to a quaternion.
pub fn mat3_to_quat<T: RealField>(x: &TMat3<T>) -> Qua<T> {
pub fn mat3_to_quat<T: RealNumber>(x: &TMat3<T>) -> Qua<T> {
let r = Rotation3::from_matrix_unchecked(*x);
UnitQuaternion::from_rotation_matrix(&r).into_inner()
}
/// Converts a rotation matrix in homogeneous coordinates to a quaternion.
pub fn to_quat<T: RealField>(x: &TMat4<T>) -> Qua<T> {
pub fn to_quat<T: RealNumber>(x: &TMat4<T>) -> Qua<T> {
let rot = x.fixed_slice::<3, 3>(0, 0).into_owned();
mat3_to_quat(&rot)
}

View File

@ -1,6 +1,7 @@
use na::{RealField, Rotation3, Unit, UnitQuaternion};
use na::{Rotation3, Unit, UnitQuaternion};
use crate::aliases::{Qua, TMat4, TVec3};
use crate::RealNumber;
/// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle.
///
@ -9,7 +10,7 @@ use crate::aliases::{Qua, TMat4, TVec3};
/// * `m` - Input matrix multiplied by this rotation matrix.
/// * `angle` - Rotation angle expressed in radians.
/// * `axis` - Rotation axis, must be normalized.
pub fn rotate_normalized_axis<T: RealField>(m: &TMat4<T>, angle: T, axis: &TVec3<T>) -> TMat4<T> {
pub fn rotate_normalized_axis<T: RealNumber>(m: &TMat4<T>, angle: T, axis: &TVec3<T>) -> TMat4<T> {
m * Rotation3::from_axis_angle(&Unit::new_unchecked(*axis), angle).to_homogeneous()
}
@ -20,6 +21,6 @@ pub fn rotate_normalized_axis<T: RealField>(m: &TMat4<T>, angle: T, axis: &TVec3
/// * `q` - Source orientation.
/// * `angle` - Angle expressed in radians.
/// * `axis` - Normalized axis of the rotation, must be normalized.
pub fn quat_rotate_normalized_axis<T: RealField>(q: &Qua<T>, angle: T, axis: &TVec3<T>) -> Qua<T> {
pub fn quat_rotate_normalized_axis<T: RealNumber>(q: &Qua<T>, angle: T, axis: &TVec3<T>) -> Qua<T> {
q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).into_inner()
}

View File

@ -1,9 +1,10 @@
use na::{RealField, Rotation3, Unit, UnitComplex};
use na::{Rotation3, Unit, UnitComplex};
use crate::aliases::{TMat4, TVec2, TVec3, TVec4};
use crate::RealNumber;
/// Build the rotation matrix needed to align `normal` and `up`.
pub fn orientation<T: RealField>(normal: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
pub fn orientation<T: RealNumber>(normal: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
if let Some(r) = Rotation3::rotation_between(normal, up) {
r.to_homogeneous()
} else {
@ -12,52 +13,52 @@ pub fn orientation<T: RealField>(normal: &TVec3<T>, up: &TVec3<T>) -> TMat4<T> {
}
/// Rotate a two dimensional vector.
pub fn rotate_vec2<T: RealField>(v: &TVec2<T>, angle: T) -> TVec2<T> {
pub fn rotate_vec2<T: RealNumber>(v: &TVec2<T>, angle: T) -> TVec2<T> {
UnitComplex::new(angle) * v
}
/// Rotate a three dimensional vector around an axis.
pub fn rotate_vec3<T: RealField>(v: &TVec3<T>, angle: T, normal: &TVec3<T>) -> TVec3<T> {
pub fn rotate_vec3<T: RealNumber>(v: &TVec3<T>, angle: T, normal: &TVec3<T>) -> TVec3<T> {
Rotation3::from_axis_angle(&Unit::new_normalize(*normal), angle) * v
}
/// Rotate a thee dimensional vector in homogeneous coordinates around an axis.
pub fn rotate_vec4<T: RealField>(v: &TVec4<T>, angle: T, normal: &TVec3<T>) -> TVec4<T> {
pub fn rotate_vec4<T: RealNumber>(v: &TVec4<T>, angle: T, normal: &TVec3<T>) -> TVec4<T> {
Rotation3::from_axis_angle(&Unit::new_normalize(*normal), angle).to_homogeneous() * v
}
/// Rotate a three dimensional vector around the `X` axis.
pub fn rotate_x_vec3<T: RealField>(v: &TVec3<T>, angle: T) -> TVec3<T> {
pub fn rotate_x_vec3<T: RealNumber>(v: &TVec3<T>, angle: T) -> TVec3<T> {
Rotation3::from_axis_angle(&TVec3::x_axis(), angle) * v
}
/// Rotate a three dimensional vector in homogeneous coordinates around the `X` axis.
pub fn rotate_x_vec4<T: RealField>(v: &TVec4<T>, angle: T) -> TVec4<T> {
pub fn rotate_x_vec4<T: RealNumber>(v: &TVec4<T>, angle: T) -> TVec4<T> {
Rotation3::from_axis_angle(&TVec3::x_axis(), angle).to_homogeneous() * v
}
/// Rotate a three dimensional vector around the `Y` axis.
pub fn rotate_y_vec3<T: RealField>(v: &TVec3<T>, angle: T) -> TVec3<T> {
pub fn rotate_y_vec3<T: RealNumber>(v: &TVec3<T>, angle: T) -> TVec3<T> {
Rotation3::from_axis_angle(&TVec3::y_axis(), angle) * v
}
/// Rotate a three dimensional vector in homogeneous coordinates around the `Y` axis.
pub fn rotate_y_vec4<T: RealField>(v: &TVec4<T>, angle: T) -> TVec4<T> {
pub fn rotate_y_vec4<T: RealNumber>(v: &TVec4<T>, angle: T) -> TVec4<T> {
Rotation3::from_axis_angle(&TVec3::y_axis(), angle).to_homogeneous() * v
}
/// Rotate a three dimensional vector around the `Z` axis.
pub fn rotate_z_vec3<T: RealField>(v: &TVec3<T>, angle: T) -> TVec3<T> {
pub fn rotate_z_vec3<T: RealNumber>(v: &TVec3<T>, angle: T) -> TVec3<T> {
Rotation3::from_axis_angle(&TVec3::z_axis(), angle) * v
}
/// Rotate a three dimensional vector in homogeneous coordinates around the `Z` axis.
pub fn rotate_z_vec4<T: RealField>(v: &TVec4<T>, angle: T) -> TVec4<T> {
pub fn rotate_z_vec4<T: RealNumber>(v: &TVec4<T>, angle: T) -> TVec4<T> {
Rotation3::from_axis_angle(&TVec3::z_axis(), angle).to_homogeneous() * v
}
/// Computes a spherical linear interpolation between the vectors `x` and `y` assumed to be normalized.
pub fn slerp<T: RealField>(x: &TVec3<T>, y: &TVec3<T>, a: T) -> TVec3<T> {
pub fn slerp<T: RealNumber>(x: &TVec3<T>, y: &TVec3<T>, a: T) -> TVec3<T> {
Unit::new_unchecked(*x)
.slerp(&Unit::new_unchecked(*y), a)
.into_inner()

View File

@ -1,7 +1,7 @@
use na::{RealField, Rotation2, Rotation3, Unit};
use na::{Rotation2, Rotation3, Unit};
use crate::aliases::{TMat3, TMat4, TVec2, TVec3};
use crate::traits::Number;
use crate::traits::{Number, RealNumber};
/// A rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians.
///
@ -12,7 +12,7 @@ use crate::traits::Number;
/// * [`rotation2d`](fn.rotation2d.html)
/// * [`scaling2d`](fn.scaling2d.html)
/// * [`translation2d`](fn.translation2d.html)
pub fn rotation<T: RealField>(angle: T, v: &TVec3<T>) -> TMat4<T> {
pub fn rotation<T: RealNumber>(angle: T, v: &TVec3<T>) -> TMat4<T> {
Rotation3::from_axis_angle(&Unit::new_normalize(*v), angle).to_homogeneous()
}
@ -51,7 +51,7 @@ pub fn translation<T: Number>(v: &TVec3<T>) -> TMat4<T> {
/// * [`translation`](fn.translation.html)
/// * [`scaling2d`](fn.scaling2d.html)
/// * [`translation2d`](fn.translation2d.html)
pub fn rotation2d<T: RealField>(angle: T) -> TMat3<T> {
pub fn rotation2d<T: RealNumber>(angle: T) -> TMat3<T> {
Rotation2::new(angle).to_homogeneous()
}

View File

@ -1,5 +1,6 @@
use crate::aliases::{TMat3, TMat4, TVec2, TVec3};
use crate::traits::Number;
use crate::RealNumber;
/// Build planar projection matrix along normal axis and right-multiply it to `m`.
pub fn proj2d<T: Number>(m: &TMat3<T>, normal: &TVec2<T>) -> TMat3<T> {
@ -26,24 +27,24 @@ pub fn proj<T: Number>(m: &TMat4<T>, normal: &TVec3<T>) -> TMat4<T> {
}
/// Builds a reflection matrix and right-multiply it to `m`.
pub fn reflect2d<T: Number>(m: &TMat3<T>, normal: &TVec2<T>) -> TMat3<T> {
pub fn reflect2d<T: RealNumber>(m: &TMat3<T>, normal: &TVec2<T>) -> TMat3<T> {
let mut res = TMat3::identity();
{
let mut part = res.fixed_slice_mut::<2, 2>(0, 0);
part -= (normal * T::from_f64(2.0).unwrap()) * normal.transpose();
part -= (normal * T::from_subset(&2.0)) * normal.transpose();
}
m * res
}
/// Builds a reflection matrix, and right-multiply it to `m`.
pub fn reflect<T: Number>(m: &TMat4<T>, normal: &TVec3<T>) -> TMat4<T> {
pub fn reflect<T: RealNumber>(m: &TMat4<T>, normal: &TVec3<T>) -> TMat4<T> {
let mut res = TMat4::identity();
{
let mut part = res.fixed_slice_mut::<3, 3>(0, 0);
part -= (normal * T::from_f64(2.0).unwrap()) * normal.transpose();
part -= (normal * T::from_subset(&2.0)) * normal.transpose();
}
m * res

View File

@ -1,7 +1,7 @@
use na::{RealField, UnitComplex};
use na::UnitComplex;
use crate::aliases::{TMat3, TVec2};
use crate::traits::Number;
use crate::traits::{Number, RealNumber};
/// Builds a 2D rotation matrix from an angle and right-multiply it to `m`.
///
@ -12,7 +12,7 @@ use crate::traits::Number;
/// * [`scaling2d`](fn.scaling2d.html)
/// * [`translate2d`](fn.translate2d.html)
/// * [`translation2d`](fn.translation2d.html)
pub fn rotate2d<T: RealField>(m: &TMat3<T>, angle: T) -> TMat3<T> {
pub fn rotate2d<T: RealNumber>(m: &TMat3<T>, angle: T) -> TMat3<T> {
m * UnitComplex::new(angle).to_homogeneous()
}

View File

@ -1,16 +1,16 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::TVec;
/// The angle between two vectors.
pub fn angle<T: RealField, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
pub fn angle<T: RealNumber, const D: usize>(x: &TVec<T, D>, y: &TVec<T, D>) -> T {
x.angle(y)
}
//pub fn oriented_angle<T: RealField>(x: &TVec2<T>, y: &TVec2<T>) -> T {
//pub fn oriented_angle<T: RealNumber>(x: &TVec2<T>, y: &TVec2<T>) -> T {
// unimplemented!()
//}
//
//pub fn oriented_angle_ref<T: RealField>(x: &TVec3<T>, y: &TVec3<T>, refv: &TVec3<T>) -> T {
//pub fn oriented_angle_ref<T: RealNumber>(x: &TVec3<T>, y: &TVec3<T>, refv: &TVec3<T>) -> T {
// unimplemented!()
//}

View File

@ -1,4 +1,4 @@
use na::RealField;
use crate::RealNumber;
use crate::aliases::{TVec, TVec2, TVec3};
use crate::traits::Number;
@ -40,7 +40,7 @@ pub fn is_comp_null<T: Number, const D: usize>(v: &TVec<T, D>, epsilon: T) -> TV
}
/// Returns `true` if `v` has a magnitude of 1 (up to an epsilon).
pub fn is_normalized<T: RealField, const D: usize>(v: &TVec<T, D>, epsilon: T) -> bool {
pub fn is_normalized<T: RealNumber, const D: usize>(v: &TVec<T, D>, epsilon: T) -> bool {
abs_diff_eq!(v.norm_squared(), T::one(), epsilon = epsilon * epsilon)
}

View File

@ -1,4 +1,4 @@
use na::{DefaultAllocator, RealField, Scalar, U3};
use na::{DefaultAllocator, RealNumber, Scalar, U3};
use crate::aliases::TVec;
use crate::traits::{Alloc, Dimension, Number};

View File

@ -110,6 +110,16 @@
and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)).
*/
#![deny(
nonstandard_style,
unused,
missing_docs,
rust_2018_idioms,
rust_2018_compatibility,
future_incompatible,
missing_copy_implementations,
missing_debug_implementations
)]
#![doc(html_favicon_url = "https://nalgebra.org/img/favicon.ico")]
#![cfg_attr(not(feature = "std"), no_std)]
@ -119,7 +129,7 @@ extern crate approx;
extern crate nalgebra as na;
pub use crate::aliases::*;
pub use crate::traits::Number;
pub use crate::traits::{Number, RealNumber};
pub use common::{
abs, ceil, clamp, clamp_scalar, clamp_vec, float_bits_to_int, float_bits_to_int_vec,
float_bits_to_uint, float_bits_to_uint_vec, floor, fract, int_bits_to_float,
@ -191,7 +201,7 @@ pub use gtx::{
pub use na::{
convert, convert_ref, convert_ref_unchecked, convert_unchecked, try_convert, try_convert_ref,
};
pub use na::{DefaultAllocator, RealField, Scalar, U1, U2, U3, U4};
pub use na::{DefaultAllocator, Scalar, U1, U2, U3, U4};
mod aliases;
mod common;

View File

@ -1,10 +1,10 @@
use na::{Const, DimMin, RealField, Scalar};
use na::{Const, DimMin, Scalar};
use crate::aliases::{TMat, TVec};
use crate::traits::Number;
use crate::traits::{Number, RealNumber};
/// The determinant of the matrix `m`.
pub fn determinant<T: RealField, const D: usize>(m: &TMat<T, D, D>) -> T
pub fn determinant<T: RealNumber, const D: usize>(m: &TMat<T, D, D>) -> T
where
Const<D>: DimMin<Const<D>, Output = Const<D>>,
{
@ -12,7 +12,7 @@ where
}
/// The inverse of the matrix `m`.
pub fn inverse<T: RealField, const D: usize>(m: &TMat<T, D, D>) -> TMat<T, D, D> {
pub fn inverse<T: RealNumber, const D: usize>(m: &TMat<T, D, D>) -> TMat<T, D, D> {
m.clone()
.try_inverse()
.unwrap_or_else(TMat::<T, D, D>::zeros)

View File

@ -1,8 +1,8 @@
use approx::AbsDiffEq;
use num::{Bounded, FromPrimitive, Signed};
use num::{Bounded, Signed};
use na::Scalar;
use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub};
use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, RealField};
use std::cmp::PartialOrd;
/// A number that can either be an integer or a float.
@ -15,7 +15,6 @@ pub trait Number:
+ ClosedMul
+ AbsDiffEq<Epsilon = Self>
+ Signed
+ FromPrimitive
+ Bounded
{
}
@ -29,8 +28,12 @@ impl<
+ ClosedMul
+ AbsDiffEq<Epsilon = Self>
+ Signed
+ FromPrimitive
+ Bounded,
> Number for T
{
}
/// A number that can be any float type.
pub trait RealNumber: Number + RealField {}
impl<T: Number + RealField> RealNumber for T {}

View File

@ -1,78 +1,79 @@
use na::{self, RealField};
use na;
use crate::aliases::TVec;
use crate::RealNumber;
/// Component-wise arc-cosinus.
pub fn acos<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn acos<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|e| e.acos())
}
/// Component-wise hyperbolic arc-cosinus.
pub fn acosh<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn acosh<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|e| e.acosh())
}
/// Component-wise arc-sinus.
pub fn asin<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn asin<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|e| e.asin())
}
/// Component-wise hyperbolic arc-sinus.
pub fn asinh<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn asinh<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|e| e.asinh())
}
/// Component-wise arc-tangent of `y / x`.
pub fn atan2<T: RealField, const D: usize>(y: &TVec<T, D>, x: &TVec<T, D>) -> TVec<T, D> {
pub fn atan2<T: RealNumber, const D: usize>(y: &TVec<T, D>, x: &TVec<T, D>) -> TVec<T, D> {
y.zip_map(x, |y, x| y.atan2(x))
}
/// Component-wise arc-tangent.
pub fn atan<T: RealField, const D: usize>(y_over_x: &TVec<T, D>) -> TVec<T, D> {
pub fn atan<T: RealNumber, const D: usize>(y_over_x: &TVec<T, D>) -> TVec<T, D> {
y_over_x.map(|e| e.atan())
}
/// Component-wise hyperbolic arc-tangent.
pub fn atanh<T: RealField, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
pub fn atanh<T: RealNumber, const D: usize>(x: &TVec<T, D>) -> TVec<T, D> {
x.map(|e| e.atanh())
}
/// Component-wise cosinus.
pub fn cos<T: RealField, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
pub fn cos<T: RealNumber, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
angle.map(|e| e.cos())
}
/// Component-wise hyperbolic cosinus.
pub fn cosh<T: RealField, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
pub fn cosh<T: RealNumber, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
angle.map(|e| e.cosh())
}
/// Component-wise conversion from radians to degrees.
pub fn degrees<T: RealField, const D: usize>(radians: &TVec<T, D>) -> TVec<T, D> {
pub fn degrees<T: RealNumber, const D: usize>(radians: &TVec<T, D>) -> TVec<T, D> {
radians.map(|e| e * na::convert(180.0) / T::pi())
}
/// Component-wise conversion fro degrees to radians.
pub fn radians<T: RealField, const D: usize>(degrees: &TVec<T, D>) -> TVec<T, D> {
pub fn radians<T: RealNumber, const D: usize>(degrees: &TVec<T, D>) -> TVec<T, D> {
degrees.map(|e| e * T::pi() / na::convert(180.0))
}
/// Component-wise sinus.
pub fn sin<T: RealField, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
pub fn sin<T: RealNumber, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
angle.map(|e| e.sin())
}
/// Component-wise hyperbolic sinus.
pub fn sinh<T: RealField, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
pub fn sinh<T: RealNumber, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
angle.map(|e| e.sinh())
}
/// Component-wise tangent.
pub fn tan<T: RealField, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
pub fn tan<T: RealNumber, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
angle.map(|e| e.tan())
}
/// Component-wise hyperbolic tangent.
pub fn tanh<T: RealField, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
pub fn tanh<T: RealNumber, const D: usize>(angle: &TVec<T, D>) -> TVec<T, D> {
angle.map(|e| e.tanh())
}

View File

@ -29,7 +29,7 @@ accelerate = ["lapack-src/accelerate"]
intel-mkl = ["lapack-src/intel-mkl"]
[dependencies]
nalgebra = { version = "0.28", path = ".." }
nalgebra = { version = "0.29", path = ".." }
num-traits = "0.2"
num-complex = { version = "0.4", default-features = false }
simba = "0.5"
@ -39,7 +39,7 @@ lapack-src = { version = "0.8", default-features = false }
# clippy = "*"
[dev-dependencies]
nalgebra = { version = "0.28", features = [ "arbitrary", "rand" ], path = ".." }
nalgebra = { version = "0.29", features = [ "arbitrary", "rand" ], path = ".." }
proptest = { version = "1", default-features = false, features = ["std"] }
quickcheck = "1"
approx = "0.5"

View File

@ -9,7 +9,6 @@ use simba::scalar::RealField;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim};
use na::storage::Storage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -73,14 +72,15 @@ where
let ljob = if left_eigenvectors { b'V' } else { b'T' };
let rjob = if eigenvectors { b'V' } else { b'T' };
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let n = nrows.value();
let lda = n as i32;
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
// TODO: avoid the initialization?
let mut wr = Matrix::zeros_generic(nrows, Const::<1>);
// TODO: Tap into the workspace.
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut wi = Matrix::zeros_generic(nrows, Const::<1>);
let mut info = 0;
let mut placeholder1 = [T::zero()];
@ -103,14 +103,13 @@ where
lapack_check!(info);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
match (left_eigenvectors, eigenvectors) {
(true, true) => {
let mut vl =
unsafe { Matrix::new_uninitialized_generic(nrows, ncols).assume_init() };
let mut vr =
unsafe { Matrix::new_uninitialized_generic(nrows, ncols).assume_init() };
// TODO: avoid the initializations?
let mut vl = Matrix::zeros_generic(nrows, ncols);
let mut vr = Matrix::zeros_generic(nrows, ncols);
T::xgeev(
ljob,
@ -139,8 +138,8 @@ where
}
}
(true, false) => {
let mut vl =
unsafe { Matrix::new_uninitialized_generic(nrows, ncols).assume_init() };
// TODO: avoid the initialization?
let mut vl = Matrix::zeros_generic(nrows, ncols);
T::xgeev(
ljob,
@ -169,8 +168,8 @@ where
}
}
(false, true) => {
let mut vr =
unsafe { Matrix::new_uninitialized_generic(nrows, ncols).assume_init() };
// TODO: avoid the initialization?
let mut vr = Matrix::zeros_generic(nrows, ncols);
T::xgeev(
ljob,
@ -242,13 +241,14 @@ where
"Unable to compute the eigenvalue decomposition of a non-square matrix."
);
let nrows = m.data.shape().0;
let nrows = m.shape_generic().0;
let n = nrows.value();
let lda = n as i32;
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
// 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()];
@ -271,7 +271,7 @@ where
lapack_panic!(info);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
T::xgeev(
b'T',
@ -291,7 +291,7 @@ where
);
lapack_panic!(info);
let mut res = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut res = Matrix::zeros_generic(nrows, Const::<1>);
for i in 0..res.len() {
res[i] = Complex::new(wr[i], wi[i]);

View File

@ -4,7 +4,6 @@ use num_complex::Complex;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, DimDiff, DimSub, U1};
use na::storage::Storage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -48,7 +47,7 @@ where
{
/// Computes the hessenberg decomposition of the matrix `m`.
pub fn new(mut m: OMatrix<T, D, D>) -> Self {
let nrows = m.data.shape().0;
let nrows = m.shape_generic().0;
let n = nrows.value() as i32;
assert!(
@ -60,14 +59,12 @@ where
"Unable to compute the hessenberg decomposition of an empty matrix."
);
let mut tau = unsafe {
Matrix::new_uninitialized_generic(nrows.sub(Const::<1>), Const::<1>).assume_init()
};
let mut tau = Matrix::zeros_generic(nrows.sub(Const::<1>), Const::<1>);
let mut info = 0;
let lwork =
T::xgehrd_work_size(n, 1, n, m.as_mut_slice(), n, tau.as_mut_slice(), &mut info);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
lapack_panic!(info);
@ -84,7 +81,7 @@ where
);
lapack_panic!(info);
Self { h: m, tau: tau }
Self { h: m, tau }
}
/// Computes the hessenberg matrix of this decomposition.

View File

@ -139,10 +139,3 @@ impl ComplexHelper for Complex<f64> {
self.re
}
}
unsafe fn uninitialized_vec<T: Copy>(n: usize) -> Vec<T> {
let mut res = Vec::new();
res.reserve_exact(n);
res.set_len(n);
res
}

View File

@ -61,7 +61,7 @@ where
{
/// Computes the LU decomposition with partial (row) pivoting of `matrix`.
pub fn new(mut m: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let min_nrows_ncols = nrows.min(ncols);
let nrows = nrows.value() as i32;
let ncols = ncols.value() as i32;
@ -87,7 +87,7 @@ where
#[inline]
#[must_use]
pub fn l(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
let (nrows, ncols) = self.lu.data.shape();
let (nrows, ncols) = self.lu.shape_generic();
let mut res = self.lu.columns_generic(0, nrows.min(ncols)).into_owned();
res.fill_upper_triangle(Zero::zero(), 1);
@ -100,7 +100,7 @@ where
#[inline]
#[must_use]
pub fn u(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
let (nrows, ncols) = self.lu.data.shape();
let (nrows, ncols) = self.lu.shape_generic();
let mut res = self.lu.rows_generic(0, nrows.min(ncols)).into_owned();
res.fill_lower_triangle(Zero::zero(), 1);
@ -115,7 +115,7 @@ where
#[inline]
#[must_use]
pub fn p(&self) -> OMatrix<T, R, R> {
let (dim, _) = self.lu.data.shape();
let (dim, _) = self.lu.shape_generic();
let mut id = Matrix::identity_generic(dim, dim);
self.permute(&mut id);
@ -290,7 +290,7 @@ where
);
lapack_check!(info);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
T::xgetri(
dim,

View File

@ -7,7 +7,6 @@ use num_complex::Complex;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum};
use na::storage::Storage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -54,15 +53,13 @@ where
{
/// Computes the QR decomposition of the matrix `m`.
pub fn new(mut m: OMatrix<T, R, C>) -> Self {
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let mut info = 0;
let mut tau = unsafe {
Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init()
};
let mut tau = Matrix::zeros_generic(nrows.min(ncols), Const::<1>);
if nrows.value() == 0 || ncols.value() == 0 {
return Self { qr: m, tau: tau };
return Self { qr: m, tau };
}
let lwork = T::xgeqrf_work_size(
@ -74,7 +71,7 @@ where
&mut info,
);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
T::xgeqrf(
nrows.value() as i32,
@ -87,14 +84,14 @@ where
&mut info,
);
Self { qr: m, tau: tau }
Self { qr: m, tau }
}
/// Retrieves the upper trapezoidal submatrix `R` of this decomposition.
#[inline]
#[must_use]
pub fn r(&self) -> OMatrix<T, DimMinimum<R, C>, C> {
let (nrows, ncols) = self.qr.data.shape();
let (nrows, ncols) = self.qr.shape_generic();
self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle()
}
}
@ -120,7 +117,7 @@ where
#[inline]
#[must_use]
pub fn q(&self) -> OMatrix<T, R, DimMinimum<R, C>> {
let (nrows, ncols) = self.qr.data.shape();
let (nrows, ncols) = self.qr.shape_generic();
let min_nrows_ncols = nrows.min(ncols);
if min_nrows_ncols.value() == 0 {

View File

@ -9,7 +9,6 @@ use simba::scalar::RealField;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim};
use na::storage::Storage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -71,16 +70,16 @@ where
"Unable to compute the eigenvalue decomposition of a non-square matrix."
);
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let n = nrows.value();
let lda = n as i32;
let mut info = 0;
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut q = unsafe { Matrix::new_uninitialized_generic(nrows, ncols).assume_init() };
let mut wr = Matrix::zeros_generic(nrows, Const::<1>);
let mut wi = Matrix::zeros_generic(nrows, Const::<1>);
let mut q = Matrix::zeros_generic(nrows, ncols);
// Placeholders:
let mut bwork = [0i32];
let mut unused = 0;
@ -101,7 +100,7 @@ where
);
lapack_check!(info);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
T::xgees(
b'V',
@ -125,7 +124,7 @@ where
re: wr,
im: wi,
t: m,
q: q,
q,
})
}
@ -153,9 +152,7 @@ where
where
DefaultAllocator: Allocator<Complex<T>, D>,
{
let mut out = unsafe {
OVector::new_uninitialized_generic(self.t.data.shape().0, Const::<1>).assume_init()
};
let mut out = Matrix::zeros_generic(self.t.shape_generic().0, Const::<1>);
for i in 0..out.len() {
out[i] = Complex::new(self.re[i], self.im[i])

View File

@ -6,7 +6,6 @@ use std::cmp;
use na::allocator::Allocator;
use na::dimension::{Const, Dim, DimMin, DimMinimum, U1};
use na::storage::Storage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -89,7 +88,7 @@ macro_rules! svd_impl(
Allocator<$t, DimMinimum<R, C>> {
fn compute(mut m: OMatrix<$t, R, C>) -> Option<SVD<$t, R, C>> {
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
if nrows.value() == 0 || ncols.value() == 0 {
return None;
@ -99,9 +98,9 @@ macro_rules! svd_impl(
let lda = nrows.value() as i32;
let mut u = unsafe { Matrix::new_uninitialized_generic(nrows, nrows).assume_init() };
let mut s = unsafe { Matrix::new_uninitialized_generic(nrows.min(ncols), Const::<1>).assume_init() };
let mut vt = unsafe { Matrix::new_uninitialized_generic(ncols, ncols).assume_init() };
let mut u = Matrix::zeros_generic(nrows, nrows);
let mut s = Matrix::zeros_generic(nrows.min(ncols), Const::<1>);
let mut vt = Matrix::zeros_generic(ncols, ncols);
let ldu = nrows.value();
let ldvt = ncols.value();
@ -109,7 +108,7 @@ macro_rules! svd_impl(
let mut work = [ 0.0 ];
let mut lwork = -1 as i32;
let mut info = 0;
let mut iwork = unsafe { crate::uninitialized_vec(8 * cmp::min(nrows.value(), ncols.value())) };
let mut iwork = vec![0; 8 * cmp::min(nrows.value(), ncols.value())];
unsafe {
$lapack_func(job, nrows.value() as i32, ncols.value() as i32, m.as_mut_slice(),
@ -119,7 +118,7 @@ macro_rules! svd_impl(
lapack_check!(info);
lwork = work[0] as i32;
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![0.0; lwork as usize];
unsafe {
$lapack_func(job, nrows.value() as i32, ncols.value() as i32, m.as_mut_slice(),
@ -151,8 +150,8 @@ macro_rules! svd_impl(
/// been manually changed by the user.
#[inline]
pub fn recompose(self) -> OMatrix<$t, R, C> {
let nrows = self.u.data.shape().0;
let ncols = self.vt.data.shape().1;
let nrows = self.u.shape_generic().0;
let ncols = self.vt.shape_generic().1;
let min_nrows_ncols = nrows.min(ncols);
let mut res: OMatrix<_, R, C> = Matrix::zeros_generic(nrows, ncols);
@ -177,8 +176,8 @@ macro_rules! svd_impl(
#[inline]
#[must_use]
pub fn pseudo_inverse(&self, epsilon: $t) -> OMatrix<$t, C, R> {
let nrows = self.u.data.shape().0;
let ncols = self.vt.data.shape().1;
let nrows = self.u.shape_generic().0;
let ncols = self.vt.shape_generic().1;
let min_nrows_ncols = nrows.min(ncols);
let mut res: OMatrix<_, C, R> = Matrix::zeros_generic(ncols, nrows);
@ -241,7 +240,7 @@ macro_rules! svd_complex_impl(
Allocator<Complex<$t>, R, R> +
Allocator<Complex<$t>, C, C> +
Allocator<$t, DimMinimum<R, C>> {
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
if nrows.value() == 0 || ncols.value() == 0 {
return None;
@ -254,9 +253,9 @@ macro_rules! svd_complex_impl(
let min_nrows_ncols = nrows.min(ncols);
let mut u = unsafe { Matrix::new_uninitialized_generic(nrows, nrows) };
let mut s = unsafe { Matrix::new_uninitialized_generic(min_nrows_ncols, U1) };
let mut vt = unsafe { Matrix::new_uninitialized_generic(ncols, ncols) };
let mut u = Matrix::zeros_generic(nrows, nrows);
let mut s = Matrix::zeros_generic(min_nrows_ncols, U1);
let mut vt = Matrix::zeros_generic(ncols, ncols);
let ldu = nrows.value();
let ldvt = ncols.value();

View File

@ -9,7 +9,6 @@ use simba::scalar::RealField;
use crate::ComplexHelper;
use na::allocator::Allocator;
use na::dimension::{Const, Dim};
use na::storage::Storage;
use na::{DefaultAllocator, Matrix, OMatrix, OVector, Scalar};
use lapack;
@ -89,19 +88,18 @@ where
let jobz = if eigenvectors { b'V' } else { b'T' };
let nrows = m.data.shape().0;
let nrows = m.shape_generic().0;
let n = nrows.value();
let lda = n as i32;
let mut values =
unsafe { Matrix::new_uninitialized_generic(nrows, Const::<1>).assume_init() };
let mut values = Matrix::zeros_generic(nrows, Const::<1>);
let mut info = 0;
let lwork = T::xsyev_work_size(jobz, b'L', n as i32, m.as_mut_slice(), lda, &mut info);
lapack_check!(info);
let mut work = unsafe { crate::uninitialized_vec(lwork as usize) };
let mut work = vec![T::zero(); lwork as usize];
T::xsyev(
jobz,

View File

@ -21,5 +21,5 @@ quote = "1.0"
proc-macro2 = "1.0"
[dev-dependencies]
nalgebra = { version = "0.28.0", path = ".." }
nalgebra = { version = "0.29.0", path = ".." }
trybuild = "1.0.42"

View File

@ -3,7 +3,18 @@
//! This crate is not intended for direct consumption. Instead, the macros are re-exported by
//! `nalgebra` if the `macros` feature is enabled (enabled by default).
extern crate proc_macro;
#![deny(
nonstandard_style,
unused,
missing_docs,
rust_2018_idioms,
rust_2018_compatibility,
future_incompatible,
missing_copy_implementations,
missing_debug_implementations,
clippy::all,
clippy::pedantic
)]
use proc_macro::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
@ -60,7 +71,7 @@ impl Matrix {
type MatrixRowSyntax = Punctuated<Expr, Token![,]>;
impl Parse for Matrix {
fn parse(input: ParseStream) -> Result<Self> {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut rows = Vec::new();
let mut ncols = None;
@ -205,7 +216,7 @@ impl Vector {
}
impl Parse for Vector {
fn parse(input: ParseStream) -> Result<Self> {
fn parse(input: ParseStream<'_>) -> Result<Self> {
// The syntax of a vector is just the syntax of a single matrix row
if input.is_empty() {
Ok(Self {

View File

@ -20,7 +20,7 @@ compare = [ "matrixcompare-core" ]
slow-tests = []
[dependencies]
nalgebra = { version="0.28", path = "../" }
nalgebra = { version="0.29", path = "../" }
num-traits = { version = "0.2", default-features = false }
proptest = { version = "1.0", optional = true }
matrixcompare-core = { version = "0.1.0", optional = true }
@ -28,7 +28,7 @@ matrixcompare-core = { version = "0.1.0", optional = true }
[dev-dependencies]
itertools = "0.10"
matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] }
nalgebra = { version="0.28", path = "../", features = ["compare"] }
nalgebra = { version="0.29", path = "../", features = ["compare"] }
[package.metadata.docs.rs]
# Enable certain features when building docs for docs.rs

View File

@ -2,7 +2,7 @@ use crate::convert::serial::*;
use crate::coo::CooMatrix;
use crate::csc::CscMatrix;
use crate::csr::CsrMatrix;
use nalgebra::storage::Storage;
use nalgebra::storage::RawStorage;
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
use num_traits::Zero;
@ -11,7 +11,7 @@ where
T: Scalar + Zero,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_coo(matrix)
@ -50,7 +50,7 @@ where
T: Scalar + Zero,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_csr(matrix)
@ -89,7 +89,7 @@ where
T: Scalar + Zero,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
fn from(matrix: &'a Matrix<T, R, C, S>) -> Self {
convert_dense_csc(matrix)

View File

@ -7,7 +7,7 @@ use std::ops::Add;
use num_traits::Zero;
use nalgebra::storage::Storage;
use nalgebra::storage::RawStorage;
use nalgebra::{ClosedAdd, DMatrix, Dim, Matrix, Scalar};
use crate::coo::CooMatrix;
@ -21,7 +21,7 @@ where
T: Scalar + Zero,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
let mut coo = CooMatrix::new(dense.nrows(), dense.ncols());
@ -30,7 +30,7 @@ where
// We use the fact that matrix iteration is guaranteed to be column-major
let i = index % dense.nrows();
let j = index / dense.nrows();
coo.push(i, j, v.inlined_clone());
coo.push(i, j, v.clone());
}
}
@ -44,7 +44,7 @@ where
{
let mut output = DMatrix::repeat(coo.nrows(), coo.ncols(), T::zero());
for (i, j, v) in coo.triplet_iter() {
output[(i, j)] += v.inlined_clone();
output[(i, j)] += v.clone();
}
output
}
@ -71,7 +71,7 @@ where
pub fn convert_csr_coo<T: Scalar>(csr: &CsrMatrix<T>) -> CooMatrix<T> {
let mut result = CooMatrix::new(csr.nrows(), csr.ncols());
for (i, j, v) in csr.triplet_iter() {
result.push(i, j, v.inlined_clone());
result.push(i, j, v.clone());
}
result
}
@ -84,7 +84,7 @@ where
let mut output = DMatrix::zeros(csr.nrows(), csr.ncols());
for (i, j, v) in csr.triplet_iter() {
output[(i, j)] += v.inlined_clone();
output[(i, j)] += v.clone();
}
output
@ -96,7 +96,7 @@ where
T: Scalar + Zero,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
let mut row_offsets = Vec::with_capacity(dense.nrows() + 1);
let mut col_idx = Vec::new();
@ -111,7 +111,7 @@ where
let v = dense.index((i, j));
if v != &T::zero() {
col_idx.push(j);
values.push(v.inlined_clone());
values.push(v.clone());
}
}
row_offsets.push(col_idx.len());
@ -148,7 +148,7 @@ where
{
let mut coo = CooMatrix::new(csc.nrows(), csc.ncols());
for (i, j, v) in csc.triplet_iter() {
coo.push(i, j, v.inlined_clone());
coo.push(i, j, v.clone());
}
coo
}
@ -161,7 +161,7 @@ where
let mut output = DMatrix::zeros(csc.nrows(), csc.ncols());
for (i, j, v) in csc.triplet_iter() {
output[(i, j)] += v.inlined_clone();
output[(i, j)] += v.clone();
}
output
@ -173,7 +173,7 @@ where
T: Scalar + Zero,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
let mut col_offsets = Vec::with_capacity(dense.ncols() + 1);
let mut row_idx = Vec::new();
@ -185,7 +185,7 @@ where
let v = dense.index((i, j));
if v != &T::zero() {
row_idx.push(i);
values.push(v.inlined_clone());
values.push(v.clone());
}
}
col_offsets.push(row_idx.len());

View File

@ -57,7 +57,7 @@ impl<T: na::Scalar> CooMatrix<T> {
/// Panics if any part of the dense matrix is out of bounds of the sparse matrix
/// when inserted at `(r, c)`.
#[inline]
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::Storage<T, R, C>>(
pub fn push_matrix<R: na::Dim, C: na::Dim, S: nalgebra::storage::RawStorage<T, R, C>>(
&mut self,
r: usize,
c: usize,

View File

@ -116,7 +116,7 @@ impl<T> CsMatrix<T> {
/// Returns an entry for the given major/minor indices, or `None` if the indices are out
/// of bounds.
#[must_use]
pub fn get_entry(&self, major_index: usize, minor_index: usize) -> Option<SparseEntry<T>> {
pub fn get_entry(&self, major_index: usize, minor_index: usize) -> Option<SparseEntry<'_, T>> {
let row_range = self.get_index_range(major_index)?;
let (_, minor_indices, values) = self.cs_data();
let minor_indices = &minor_indices[row_range.clone()];
@ -135,7 +135,7 @@ impl<T> CsMatrix<T> {
&mut self,
major_index: usize,
minor_index: usize,
) -> Option<SparseEntryMut<T>> {
) -> Option<SparseEntryMut<'_, T>> {
let row_range = self.get_index_range(major_index)?;
let minor_dim = self.pattern().minor_dim();
let (_, minor_indices, values) = self.cs_data_mut();
@ -145,7 +145,7 @@ impl<T> CsMatrix<T> {
}
#[must_use]
pub fn get_lane(&self, index: usize) -> Option<CsLane<T>> {
pub fn get_lane(&self, index: usize) -> Option<CsLane<'_, T>> {
let range = self.get_index_range(index)?;
let (_, minor_indices, values) = self.cs_data();
Some(CsLane {
@ -157,7 +157,7 @@ impl<T> CsMatrix<T> {
#[inline]
#[must_use]
pub fn get_lane_mut(&mut self, index: usize) -> Option<CsLaneMut<T>> {
pub fn get_lane_mut(&mut self, index: usize) -> Option<CsLaneMut<'_, T>> {
let range = self.get_index_range(index)?;
let minor_dim = self.pattern().minor_dim();
let (_, minor_indices, values) = self.cs_data_mut();
@ -169,12 +169,12 @@ impl<T> CsMatrix<T> {
}
#[inline]
pub fn lane_iter(&self) -> CsLaneIter<T> {
pub fn lane_iter(&self) -> CsLaneIter<'_, T> {
CsLaneIter::new(self.pattern(), self.values())
}
#[inline]
pub fn lane_iter_mut(&mut self) -> CsLaneIterMut<T> {
pub fn lane_iter_mut(&mut self) -> CsLaneIterMut<'_, T> {
CsLaneIterMut::new(&self.sparsity_pattern, &mut self.values)
}
@ -406,7 +406,7 @@ macro_rules! impl_cs_lane_common_methods {
#[inline]
#[must_use]
pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<T>> {
pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<'_, T>> {
get_entry_from_slices(
self.minor_dim,
self.minor_indices,
@ -431,7 +431,7 @@ impl<'a, T> CsLaneMut<'a, T> {
}
#[must_use]
pub fn get_entry_mut(&mut self, global_minor_index: usize) -> Option<SparseEntryMut<T>> {
pub fn get_entry_mut(&mut self, global_minor_index: usize) -> Option<SparseEntryMut<'_, T>> {
get_mut_entry_from_slices(
self.minor_dim,
self.minor_indices,
@ -522,7 +522,7 @@ where
let entry_offset = target_offsets[source_minor_idx] + *target_lane_count;
target_indices[entry_offset] = source_major_idx;
unsafe {
target_values.set(entry_offset, val.inlined_clone());
target_values.set(entry_offset, val.clone());
}
*target_lane_count += 1;
}

View File

@ -260,7 +260,7 @@ impl<T> CscMatrix<T> {
/// let triplets: Vec<_> = csc.triplet_iter().map(|(i, j, v)| (i, j, *v)).collect();
/// assert_eq!(triplets, vec![(0, 0, 1), (2, 0, 3), (1, 1, 2), (0, 2, 4)]);
/// ```
pub fn triplet_iter(&self) -> CscTripletIter<T> {
pub fn triplet_iter(&self) -> CscTripletIter<'_, T> {
CscTripletIter {
pattern_iter: self.pattern().entries(),
values_iter: self.values().iter(),
@ -290,7 +290,7 @@ impl<T> CscMatrix<T> {
/// let triplets: Vec<_> = csc.triplet_iter().map(|(i, j, v)| (i, j, *v)).collect();
/// assert_eq!(triplets, vec![(0, 0, 1), (2, 0, 0), (1, 1, 2), (0, 2, 4)]);
/// ```
pub fn triplet_iter_mut(&mut self) -> CscTripletIterMut<T> {
pub fn triplet_iter_mut(&mut self) -> CscTripletIterMut<'_, T> {
let (pattern, values) = self.cs.pattern_and_values_mut();
CscTripletIterMut {
pattern_iter: pattern.entries(),
@ -305,7 +305,7 @@ impl<T> CscMatrix<T> {
/// Panics if column index is out of bounds.
#[inline]
#[must_use]
pub fn col(&self, index: usize) -> CscCol<T> {
pub fn col(&self, index: usize) -> CscCol<'_, T> {
self.get_col(index).expect("Row index must be in bounds")
}
@ -315,7 +315,7 @@ impl<T> CscMatrix<T> {
/// ------
/// Panics if column index is out of bounds.
#[inline]
pub fn col_mut(&mut self, index: usize) -> CscColMut<T> {
pub fn col_mut(&mut self, index: usize) -> CscColMut<'_, T> {
self.get_col_mut(index)
.expect("Row index must be in bounds")
}
@ -323,26 +323,26 @@ impl<T> CscMatrix<T> {
/// Return the column at the given column index, or `None` if out of bounds.
#[inline]
#[must_use]
pub fn get_col(&self, index: usize) -> Option<CscCol<T>> {
pub fn get_col(&self, index: usize) -> Option<CscCol<'_, T>> {
self.cs.get_lane(index).map(|lane| CscCol { lane })
}
/// Mutable column access for the given column index, or `None` if out of bounds.
#[inline]
#[must_use]
pub fn get_col_mut(&mut self, index: usize) -> Option<CscColMut<T>> {
pub fn get_col_mut(&mut self, index: usize) -> Option<CscColMut<'_, T>> {
self.cs.get_lane_mut(index).map(|lane| CscColMut { lane })
}
/// An iterator over columns in the matrix.
pub fn col_iter(&self) -> CscColIter<T> {
pub fn col_iter(&self) -> CscColIter<'_, T> {
CscColIter {
lane_iter: CsLaneIter::new(self.pattern(), self.values()),
}
}
/// A mutable iterator over columns in the matrix.
pub fn col_iter_mut(&mut self) -> CscColIterMut<T> {
pub fn col_iter_mut(&mut self) -> CscColIterMut<'_, T> {
let (pattern, values) = self.cs.pattern_and_values_mut();
CscColIterMut {
lane_iter: CsLaneIterMut::new(pattern, values),
@ -408,7 +408,7 @@ impl<T> CscMatrix<T> {
/// Each call to this function incurs the cost of a binary search among the explicitly
/// stored row entries for the given column.
#[must_use]
pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<T>> {
pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<'_, T>> {
self.cs.get_entry(col_index, row_index)
}
@ -421,7 +421,7 @@ impl<T> CscMatrix<T> {
&mut self,
row_index: usize,
col_index: usize,
) -> Option<SparseEntryMut<T>> {
) -> Option<SparseEntryMut<'_, T>> {
self.cs.get_entry_mut(col_index, row_index)
}
@ -434,7 +434,7 @@ impl<T> CscMatrix<T> {
/// ------
/// Panics if `row_index` or `col_index` is out of bounds.
#[must_use]
pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<T> {
pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<'_, T> {
self.get_entry(row_index, col_index)
.expect("Out of bounds matrix indices encountered")
}
@ -447,7 +447,7 @@ impl<T> CscMatrix<T> {
/// Panics
/// ------
/// Panics if `row_index` or `col_index` is out of bounds.
pub fn index_entry_mut(&mut self, row_index: usize, col_index: usize) -> SparseEntryMut<T> {
pub fn index_entry_mut(&mut self, row_index: usize, col_index: usize) -> SparseEntryMut<'_, T> {
self.get_entry_mut(row_index, col_index)
.expect("Out of bounds matrix indices encountered")
}
@ -666,7 +666,7 @@ macro_rules! impl_csc_col_common_methods {
/// Each call to this function incurs the cost of a binary search among the explicitly
/// stored row entries.
#[must_use]
pub fn get_entry(&self, global_row_index: usize) -> Option<SparseEntry<T>> {
pub fn get_entry(&self, global_row_index: usize) -> Option<SparseEntry<'_, T>> {
self.lane.get_entry(global_row_index)
}
}
@ -693,7 +693,7 @@ impl<'a, T> CscColMut<'a, T> {
/// Returns a mutable entry for the given global row index.
#[must_use]
pub fn get_entry_mut(&mut self, global_row_index: usize) -> Option<SparseEntryMut<T>> {
pub fn get_entry_mut(&mut self, global_row_index: usize) -> Option<SparseEntryMut<'_, T>> {
self.lane.get_entry_mut(global_row_index)
}
}

View File

@ -262,7 +262,7 @@ impl<T> CsrMatrix<T> {
/// let triplets: Vec<_> = csr.triplet_iter().map(|(i, j, v)| (i, j, *v)).collect();
/// assert_eq!(triplets, vec![(0, 0, 1), (0, 2, 2), (1, 1, 3), (2, 0, 4)]);
/// ```
pub fn triplet_iter(&self) -> CsrTripletIter<T> {
pub fn triplet_iter(&self) -> CsrTripletIter<'_, T> {
CsrTripletIter {
pattern_iter: self.pattern().entries(),
values_iter: self.values().iter(),
@ -292,7 +292,7 @@ impl<T> CsrMatrix<T> {
/// let triplets: Vec<_> = csr.triplet_iter().map(|(i, j, v)| (i, j, *v)).collect();
/// assert_eq!(triplets, vec![(0, 0, 1), (0, 2, 2), (1, 1, 3), (2, 0, 0)]);
/// ```
pub fn triplet_iter_mut(&mut self) -> CsrTripletIterMut<T> {
pub fn triplet_iter_mut(&mut self) -> CsrTripletIterMut<'_, T> {
let (pattern, values) = self.cs.pattern_and_values_mut();
CsrTripletIterMut {
pattern_iter: pattern.entries(),
@ -307,7 +307,7 @@ impl<T> CsrMatrix<T> {
/// Panics if row index is out of bounds.
#[inline]
#[must_use]
pub fn row(&self, index: usize) -> CsrRow<T> {
pub fn row(&self, index: usize) -> CsrRow<'_, T> {
self.get_row(index).expect("Row index must be in bounds")
}
@ -317,7 +317,7 @@ impl<T> CsrMatrix<T> {
/// ------
/// Panics if row index is out of bounds.
#[inline]
pub fn row_mut(&mut self, index: usize) -> CsrRowMut<T> {
pub fn row_mut(&mut self, index: usize) -> CsrRowMut<'_, T> {
self.get_row_mut(index)
.expect("Row index must be in bounds")
}
@ -325,26 +325,26 @@ impl<T> CsrMatrix<T> {
/// Return the row at the given row index, or `None` if out of bounds.
#[inline]
#[must_use]
pub fn get_row(&self, index: usize) -> Option<CsrRow<T>> {
pub fn get_row(&self, index: usize) -> Option<CsrRow<'_, T>> {
self.cs.get_lane(index).map(|lane| CsrRow { lane })
}
/// Mutable row access for the given row index, or `None` if out of bounds.
#[inline]
#[must_use]
pub fn get_row_mut(&mut self, index: usize) -> Option<CsrRowMut<T>> {
pub fn get_row_mut(&mut self, index: usize) -> Option<CsrRowMut<'_, T>> {
self.cs.get_lane_mut(index).map(|lane| CsrRowMut { lane })
}
/// An iterator over rows in the matrix.
pub fn row_iter(&self) -> CsrRowIter<T> {
pub fn row_iter(&self) -> CsrRowIter<'_, T> {
CsrRowIter {
lane_iter: CsLaneIter::new(self.pattern(), self.values()),
}
}
/// A mutable iterator over rows in the matrix.
pub fn row_iter_mut(&mut self) -> CsrRowIterMut<T> {
pub fn row_iter_mut(&mut self) -> CsrRowIterMut<'_, T> {
let (pattern, values) = self.cs.pattern_and_values_mut();
CsrRowIterMut {
lane_iter: CsLaneIterMut::new(pattern, values),
@ -410,7 +410,7 @@ impl<T> CsrMatrix<T> {
/// Each call to this function incurs the cost of a binary search among the explicitly
/// stored column entries for the given row.
#[must_use]
pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<T>> {
pub fn get_entry(&self, row_index: usize, col_index: usize) -> Option<SparseEntry<'_, T>> {
self.cs.get_entry(row_index, col_index)
}
@ -423,7 +423,7 @@ impl<T> CsrMatrix<T> {
&mut self,
row_index: usize,
col_index: usize,
) -> Option<SparseEntryMut<T>> {
) -> Option<SparseEntryMut<'_, T>> {
self.cs.get_entry_mut(row_index, col_index)
}
@ -436,7 +436,7 @@ impl<T> CsrMatrix<T> {
/// ------
/// Panics if `row_index` or `col_index` is out of bounds.
#[must_use]
pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<T> {
pub fn index_entry(&self, row_index: usize, col_index: usize) -> SparseEntry<'_, T> {
self.get_entry(row_index, col_index)
.expect("Out of bounds matrix indices encountered")
}
@ -449,7 +449,7 @@ impl<T> CsrMatrix<T> {
/// Panics
/// ------
/// Panics if `row_index` or `col_index` is out of bounds.
pub fn index_entry_mut(&mut self, row_index: usize, col_index: usize) -> SparseEntryMut<T> {
pub fn index_entry_mut(&mut self, row_index: usize, col_index: usize) -> SparseEntryMut<'_, T> {
self.get_entry_mut(row_index, col_index)
.expect("Out of bounds matrix indices encountered")
}
@ -667,7 +667,7 @@ macro_rules! impl_csr_row_common_methods {
/// stored column entries.
#[inline]
#[must_use]
pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<T>> {
pub fn get_entry(&self, global_col_index: usize) -> Option<SparseEntry<'_, T>> {
self.lane.get_entry(global_col_index)
}
}
@ -697,7 +697,7 @@ impl<'a, T> CsrRowMut<'a, T> {
/// Returns a mutable entry for the given global column index.
#[inline]
#[must_use]
pub fn get_entry_mut(&mut self, global_col_index: usize) -> Option<SparseEntryMut<T>> {
pub fn get_entry_mut(&mut self, global_col_index: usize) -> Option<SparseEntryMut<'_, T>> {
self.lane.get_entry_mut(global_col_index)
}
}

View File

@ -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, Scalar};
use nalgebra::{DMatrix, DMatrixSlice, DMatrixSliceMut, RealField};
use std::fmt::{Display, Formatter};
/// A symbolic sparse Cholesky factorization of a CSC matrix.
@ -72,7 +72,7 @@ pub struct CscCholesky<T> {
work_c: Vec<usize>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[non_exhaustive]
/// Possible errors produced by the Cholesky factorization.
pub enum CholeskyError {
@ -209,15 +209,16 @@ impl<T: RealField> CscCholesky<T> {
let irow = *self.m_pattern.minor_indices().get_unchecked(p);
if irow >= k {
*self.work_x.get_unchecked_mut(irow) = *values.get_unchecked(p);
*self.work_x.get_unchecked_mut(irow) = values.get_unchecked(p).clone();
}
}
for &j in self.u_pattern.lane(k) {
let factor = -*self
let factor = -self
.l_factor
.values()
.get_unchecked(*self.work_c.get_unchecked(j));
.get_unchecked(*self.work_c.get_unchecked(j))
.clone();
*self.work_c.get_unchecked_mut(j) += 1;
if j < k {
@ -225,27 +226,27 @@ impl<T: RealField> CscCholesky<T> {
let col_j_entries = col_j.row_indices().iter().zip(col_j.values());
for (&z, val) in col_j_entries {
if z >= k {
*self.work_x.get_unchecked_mut(z) += val.inlined_clone() * factor;
*self.work_x.get_unchecked_mut(z) += val.clone() * factor.clone();
}
}
}
}
let diag = *self.work_x.get_unchecked(k);
let diag = self.work_x.get_unchecked(k).clone();
if diag > T::zero() {
let denom = diag.sqrt();
{
let (offsets, _, values) = self.l_factor.csc_data_mut();
*values.get_unchecked_mut(*offsets.get_unchecked(k)) = denom;
*values.get_unchecked_mut(*offsets.get_unchecked(k)) = denom.clone();
}
let mut col_k = self.l_factor.col_mut(k);
let (col_k_rows, col_k_values) = col_k.rows_and_values_mut();
let col_k_entries = col_k_rows.iter().zip(col_k_values);
for (&p, val) in col_k_entries {
*val = *self.work_x.get_unchecked(p) / denom;
*val = self.work_x.get_unchecked(p).clone() / denom.clone();
*self.work_x.get_unchecked_mut(p) = T::zero();
}
} else {

View File

@ -131,12 +131,15 @@
//! assert_matrix_eq!(y, y_expected, comp = abs, tol = 1e-9);
//! }
//! ```
#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(unused_results)]
#![deny(missing_docs)]
#![deny(
nonstandard_style,
unused,
missing_docs,
rust_2018_idioms,
rust_2018_compatibility,
future_incompatible,
missing_copy_implementations
)]
pub extern crate nalgebra as na;
pub mod convert;
@ -190,7 +193,7 @@ impl SparseFormatError {
/// The type of format error described by a [SparseFormatError](struct.SparseFormatError.html).
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SparseFormatErrorKind {
/// Indicates that the index data associated with the format contains at least one index
/// out of bounds.
@ -208,7 +211,7 @@ pub enum SparseFormatErrorKind {
}
impl fmt::Display for SparseFormatError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.error)
}
}

View File

@ -28,7 +28,7 @@ macro_rules! impl_matrix_for_csr_csc {
self.ncols()
}
fn access(&self) -> Access<T> {
fn access(&self) -> Access<'_, T> {
Access::Sparse(self)
}
}
@ -59,7 +59,7 @@ impl<T: Clone> matrixcompare_core::Matrix<T> for CooMatrix<T> {
self.ncols()
}
fn access(&self) -> Access<T> {
fn access(&self) -> Access<'_, T> {
Access::Sparse(self)
}
}

View File

@ -7,7 +7,7 @@ use crate::ops::serial::{
};
use crate::ops::Op;
use nalgebra::allocator::Allocator;
use nalgebra::base::storage::Storage;
use nalgebra::base::storage::RawStorage;
use nalgebra::constraint::{DimEq, ShapeConstraint};
use nalgebra::{
ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, DefaultAllocator, Dim, Dynamic, Matrix, OMatrix,
@ -141,7 +141,7 @@ macro_rules! impl_scalar_mul {
impl_mul!(<'a, T>(a: &'a $matrix_type<T>, b: &'a T) -> $matrix_type<T> {
let values: Vec<_> = a.values()
.iter()
.map(|v_i| v_i.inlined_clone() * b.inlined_clone())
.map(|v_i| v_i.clone() * b.clone())
.collect();
$matrix_type::try_from_pattern_and_values(a.pattern().clone(), values).unwrap()
});
@ -151,7 +151,7 @@ macro_rules! impl_scalar_mul {
impl_mul!(<'a, T>(a: $matrix_type<T>, b: &'a T) -> $matrix_type<T> {
let mut a = a;
for value in a.values_mut() {
*value = b.inlined_clone() * value.inlined_clone();
*value = b.clone() * value.clone();
}
a
});
@ -168,7 +168,7 @@ macro_rules! impl_scalar_mul {
{
fn mul_assign(&mut self, scalar: T) {
for val in self.values_mut() {
*val *= scalar.inlined_clone();
*val *= scalar.clone();
}
}
}
@ -179,7 +179,7 @@ macro_rules! impl_scalar_mul {
{
fn mul_assign(&mut self, scalar: &'a T) {
for val in self.values_mut() {
*val *= scalar.inlined_clone();
*val *= scalar.clone();
}
}
}
@ -199,7 +199,7 @@ macro_rules! impl_neg {
fn neg(mut self) -> Self::Output {
for v_i in self.values_mut() {
*v_i = -v_i.inlined_clone();
*v_i = -v_i.clone();
}
self
}
@ -233,25 +233,25 @@ macro_rules! impl_div {
matrix
});
impl_bin_op!(Div, div, <'a, T: ClosedDiv>(matrix: $matrix_type<T>, scalar: &T) -> $matrix_type<T> {
matrix / scalar.inlined_clone()
matrix / scalar.clone()
});
impl_bin_op!(Div, div, <'a, T: ClosedDiv>(matrix: &'a $matrix_type<T>, scalar: T) -> $matrix_type<T> {
let new_values = matrix.values()
.iter()
.map(|v_i| v_i.inlined_clone() / scalar.inlined_clone())
.map(|v_i| v_i.clone() / scalar.clone())
.collect();
$matrix_type::try_from_pattern_and_values(matrix.pattern().clone(), new_values)
.unwrap()
});
impl_bin_op!(Div, div, <'a, T: ClosedDiv>(matrix: &'a $matrix_type<T>, scalar: &'a T) -> $matrix_type<T> {
matrix / scalar.inlined_clone()
matrix / scalar.clone()
});
impl<T> DivAssign<T> for $matrix_type<T>
where T : Scalar + ClosedAdd + ClosedMul + ClosedDiv + Zero + One
{
fn div_assign(&mut self, scalar: T) {
self.values_mut().iter_mut().for_each(|v_i| *v_i /= scalar.inlined_clone());
self.values_mut().iter_mut().for_each(|v_i| *v_i /= scalar.clone());
}
}
@ -259,7 +259,7 @@ macro_rules! impl_div {
where T : Scalar + ClosedAdd + ClosedMul + ClosedDiv + Zero + One
{
fn div_assign(&mut self, scalar: &'a T) {
*self /= scalar.inlined_clone();
*self /= scalar.clone();
}
}
}
@ -272,7 +272,7 @@ macro_rules! impl_spmm_cs_dense {
($matrix_type_name:ident, $spmm_fn:ident) => {
// Implement ref-ref
impl_spmm_cs_dense!(&'a $matrix_type_name<T>, &'a Matrix<T, R, C, S>, $spmm_fn, |lhs, rhs| {
let (_, ncols) = rhs.data.shape();
let (_, ncols) = rhs.shape_generic();
let nrows = Dynamic::new(lhs.nrows());
let mut result = OMatrix::<T, Dynamic, C>::zeros_generic(nrows, ncols);
$spmm_fn(T::zero(), &mut result, T::one(), Op::NoOp(lhs), Op::NoOp(rhs));
@ -301,14 +301,14 @@ macro_rules! impl_spmm_cs_dense {
T: Scalar + ClosedMul + ClosedAdd + ClosedSub + ClosedDiv + Neg + Zero + One,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
DefaultAllocator: Allocator<T, Dynamic, C>,
// TODO: Is it possible to simplify these bounds?
ShapeConstraint:
// Bounds so that we can turn OMatrix<T, Dynamic, C> into a DMatrixSliceMut
DimEq<U1, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as Storage<T, Dynamic, C>>::RStride>
DimEq<U1, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as RawStorage<T, Dynamic, C>>::RStride>
+ DimEq<C, Dynamic>
+ DimEq<Dynamic, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as Storage<T, Dynamic, C>>::CStride>
+ DimEq<Dynamic, <<DefaultAllocator as Allocator<T, Dynamic, C>>::Buffer as RawStorage<T, Dynamic, C>>::CStride>
// Bounds so that we can turn &Matrix<T, R, C, S> into a DMatrixSlice
+ DimEq<U1, S::RStride>
+ DimEq<R, Dynamic>

View File

@ -34,13 +34,13 @@ where
let a_lane_i = a.get_lane(i).unwrap();
let mut c_lane_i = c.get_lane_mut(i).unwrap();
for c_ij in c_lane_i.values_mut() {
*c_ij = beta.inlined_clone() * c_ij.inlined_clone();
*c_ij = beta.clone() * c_ij.clone();
}
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 (mut c_lane_i_cols, mut c_lane_i_values) = c_lane_i.indices_and_values_mut();
let alpha_aik = alpha.inlined_clone() * a_ik.inlined_clone();
let alpha_aik = alpha.clone() * a_ik.clone();
for (j, b_kj) in b_lane_k.minor_indices().iter().zip(b_lane_k.values()) {
// Determine the location in C to append the value
let (c_local_idx, _) = c_lane_i_cols
@ -49,7 +49,7 @@ where
.find(|(_, c_col)| *c_col == j)
.ok_or_else(spmm_cs_unexpected_entry)?;
c_lane_i_values[c_local_idx] += alpha_aik.inlined_clone() * b_kj.inlined_clone();
c_lane_i_values[c_local_idx] += alpha_aik.clone() * b_kj.clone();
c_lane_i_cols = &c_lane_i_cols[c_local_idx..];
c_lane_i_values = &mut c_lane_i_values[c_local_idx..];
}
@ -81,7 +81,7 @@ where
for (mut c_lane_i, a_lane_i) in c.lane_iter_mut().zip(a.lane_iter()) {
if beta != T::one() {
for c_ij in c_lane_i.values_mut() {
*c_ij *= beta.inlined_clone();
*c_ij *= beta.clone();
}
}
@ -97,7 +97,7 @@ where
.enumerate()
.find(|(_, c_col)| *c_col == a_col)
.ok_or_else(spadd_cs_unexpected_entry)?;
c_vals[c_idx] += alpha.inlined_clone() * a_val.inlined_clone();
c_vals[c_idx] += alpha.clone() * a_val.clone();
c_minors = &c_minors[c_idx..];
c_vals = &mut c_vals[c_idx..];
}
@ -106,14 +106,14 @@ where
Op::Transpose(a) => {
if beta != T::one() {
for c_ij in c.values_mut() {
*c_ij *= beta.inlined_clone();
*c_ij *= beta.clone();
}
}
for (i, a_lane_i) in a.lane_iter().enumerate() {
for (&j, a_val) in a_lane_i.minor_indices().iter().zip(a_lane_i.values()) {
let a_val = a_val.inlined_clone();
let alpha = alpha.inlined_clone();
let a_val = a_val.clone();
let alpha = alpha.clone();
match c.get_entry_mut(j, i).unwrap() {
SparseEntryMut::NonZero(c_ji) => *c_ji += alpha * a_val,
SparseEntryMut::Zero => return Err(spadd_cs_unexpected_entry()),
@ -131,10 +131,10 @@ where
/// the transposed operation must be specified for the CSC matrix.
pub fn spmm_cs_dense<T>(
beta: T,
mut c: DMatrixSliceMut<T>,
mut c: DMatrixSliceMut<'_, T>,
alpha: T,
a: Op<&CsMatrix<T>>,
b: Op<DMatrixSlice<T>>,
b: Op<DMatrixSlice<'_, T>>,
) where
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{
@ -149,10 +149,9 @@ pub fn spmm_cs_dense<T>(
Op::NoOp(ref b) => b.index((k, j)),
Op::Transpose(ref b) => b.index((j, k)),
};
dot_ij += a_ik.inlined_clone() * b_contrib.inlined_clone();
dot_ij += a_ik.clone() * b_contrib.clone();
}
*c_ij = beta.inlined_clone() * c_ij.inlined_clone()
+ alpha.inlined_clone() * dot_ij;
*c_ij = beta.clone() * c_ij.clone() + alpha.clone() * dot_ij;
}
}
}
@ -163,19 +162,19 @@ pub fn spmm_cs_dense<T>(
for k in 0..a.pattern().major_dim() {
let a_row_k = a.get_lane(k).unwrap();
for (&i, a_ki) in a_row_k.minor_indices().iter().zip(a_row_k.values()) {
let gamma_ki = alpha.inlined_clone() * a_ki.inlined_clone();
let gamma_ki = alpha.clone() * a_ki.clone();
let mut c_row_i = c.row_mut(i);
match b {
Op::NoOp(ref b) => {
let b_row_k = b.row(k);
for (c_ij, b_kj) in c_row_i.iter_mut().zip(b_row_k.iter()) {
*c_ij += gamma_ki.inlined_clone() * b_kj.inlined_clone();
*c_ij += gamma_ki.clone() * b_kj.clone();
}
}
Op::Transpose(ref b) => {
let b_col_k = b.column(k);
for (c_ij, b_jk) in c_row_i.iter_mut().zip(b_col_k.iter()) {
*c_ij += gamma_ki.inlined_clone() * b_jk.inlined_clone();
*c_ij += gamma_ki.clone() * b_jk.clone();
}
}
}

View File

@ -27,10 +27,10 @@ pub fn spmm_csc_dense<'a, T>(
fn spmm_csc_dense_<T>(
beta: T,
c: DMatrixSliceMut<T>,
c: DMatrixSliceMut<'_, T>,
alpha: T,
a: Op<&CscMatrix<T>>,
b: Op<DMatrixSlice<T>>,
b: Op<DMatrixSlice<'_, T>>,
) where
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{
@ -147,7 +147,7 @@ pub fn spsolve_csc_lower_triangular<'a, T: RealField>(
fn spsolve_csc_lower_triangular_no_transpose<T: RealField>(
l: &CscMatrix<T>,
b: DMatrixSliceMut<T>,
b: DMatrixSliceMut<'_, T>,
) -> Result<(), OperationError> {
let mut x = b;
@ -165,13 +165,13 @@ fn spsolve_csc_lower_triangular_no_transpose<T: RealField>(
// a severe penalty)
let diag_csc_index = l_col_k.row_indices().iter().position(|&i| i == k);
if let Some(diag_csc_index) = diag_csc_index {
let l_kk = l_col_k.values()[diag_csc_index];
let l_kk = l_col_k.values()[diag_csc_index].clone();
if l_kk != T::zero() {
// Update entry associated with diagonal
x_col_j[k] /= l_kk;
// Copy value after updating (so we don't run into the borrow checker)
let x_kj = x_col_j[k];
let x_kj = x_col_j[k].clone();
let row_indices = &l_col_k.row_indices()[(diag_csc_index + 1)..];
let l_values = &l_col_k.values()[(diag_csc_index + 1)..];
@ -179,7 +179,7 @@ fn spsolve_csc_lower_triangular_no_transpose<T: RealField>(
// Note: The remaining entries are below the diagonal
for (&i, l_ik) in row_indices.iter().zip(l_values) {
let x_ij = &mut x_col_j[i];
*x_ij -= l_ik.inlined_clone() * x_kj;
*x_ij -= l_ik.clone() * x_kj.clone();
}
x_col_j[k] = x_kj;
@ -205,7 +205,7 @@ fn spsolve_encountered_zero_diagonal() -> Result<(), OperationError> {
fn spsolve_csc_lower_triangular_transpose<T: RealField>(
l: &CscMatrix<T>,
b: DMatrixSliceMut<T>,
b: DMatrixSliceMut<'_, T>,
) -> Result<(), OperationError> {
let mut x = b;
@ -223,22 +223,22 @@ fn spsolve_csc_lower_triangular_transpose<T: RealField>(
// TODO: Can use exponential search here to quickly skip entries
let diag_csc_index = l_col_i.row_indices().iter().position(|&k| i == k);
if let Some(diag_csc_index) = diag_csc_index {
let l_ii = l_col_i.values()[diag_csc_index];
let l_ii = l_col_i.values()[diag_csc_index].clone();
if l_ii != T::zero() {
// // Update entry associated with diagonal
// x_col_j[k] /= a_kk;
// Copy value after updating (so we don't run into the borrow checker)
let mut x_ii = x_col_j[i];
let mut x_ii = x_col_j[i].clone();
let row_indices = &l_col_i.row_indices()[(diag_csc_index + 1)..];
let a_values = &l_col_i.values()[(diag_csc_index + 1)..];
// Note: The remaining entries are below the diagonal
for (&k, &l_ki) in row_indices.iter().zip(a_values) {
let x_kj = x_col_j[k];
x_ii -= l_ki * x_kj;
for (k, l_ki) in row_indices.iter().zip(a_values) {
let x_kj = x_col_j[*k].clone();
x_ii -= l_ki.clone() * x_kj;
}
x_col_j[i] = x_ii / l_ii;

View File

@ -22,10 +22,10 @@ pub fn spmm_csr_dense<'a, T>(
fn spmm_csr_dense_<T>(
beta: T,
c: DMatrixSliceMut<T>,
c: DMatrixSliceMut<'_, T>,
alpha: T,
a: Op<&CsrMatrix<T>>,
b: Op<DMatrixSlice<T>>,
b: Op<DMatrixSlice<'_, T>>,
) where
T: Scalar + ClosedAdd + ClosedMul + Zero + One,
{

View File

@ -8,7 +8,6 @@
//! some operations which will be able to dynamically adapt the output pattern to fit the
//! result, but these have yet to be implemented.
#[macro_use]
macro_rules! assert_compatible_spmm_dims {
($c:expr, $a:expr, $b:expr) => {{
use crate::ops::Op::{NoOp, Transpose};
@ -37,7 +36,6 @@ macro_rules! assert_compatible_spmm_dims {
}};
}
#[macro_use]
macro_rules! assert_compatible_spadd_dims {
($c:expr, $a:expr) => {
use crate::ops::Op;
@ -74,7 +72,7 @@ pub struct OperationError {
/// The different kinds of operation errors that may occur.
#[non_exhaustive]
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum OperationErrorKind {
/// Indicates that one or more sparsity patterns involved in the operation violate the
/// expectations of the routine.

View File

@ -205,7 +205,7 @@ impl SparsityPattern {
/// ```
///
#[must_use]
pub fn entries(&self) -> SparsityPatternIter {
pub fn entries(&self) -> SparsityPatternIter<'_> {
SparsityPatternIter::from_pattern(self)
}
@ -260,7 +260,7 @@ impl SparsityPattern {
/// Error type for `SparsityPattern` format errors.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SparsityPatternFormatError {
/// Indicates an invalid number of offsets.
///

View File

@ -0,0 +1,3 @@
edition = "2018"
use_try_shorthand = true
use_field_init_shorthand = true

View File

@ -5,6 +5,8 @@ use crate::base::storage::Owned;
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::vec_storage::VecStorage;
use crate::base::{ArrayStorage, Const, Matrix, Unit};
use crate::storage::OwnedUninit;
use std::mem::MaybeUninit;
/*
*
@ -19,6 +21,9 @@ use crate::base::{ArrayStorage, Const, Matrix, Unit};
/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.**
pub type OMatrix<T, R, C> = Matrix<T, R, C, Owned<T, R, C>>;
/// An owned matrix with uninitialized data.
pub type UninitMatrix<T, R, C> = Matrix<MaybeUninit<T>, R, C, OwnedUninit<T, R, C>>;
/// An owned matrix column-major matrix 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.**
@ -278,6 +283,9 @@ pub type OVector<T, D> = Matrix<T, D, U1, Owned<T, D, U1>>;
/// A statically sized D-dimensional column vector.
pub type SVector<T, const D: usize> = Matrix<T, Const<D>, U1, ArrayStorage<T, D, 1>>; // Owned<T, Const<D>, U1>>;
/// An owned matrix with uninitialized data.
pub type UninitVector<T, D> = Matrix<MaybeUninit<T>, D, U1, OwnedUninit<T, D, U1>>;
/// An owned matrix column-major matrix 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.**

View File

@ -1,12 +1,14 @@
//! Abstract definition of a matrix data storage allocator.
use std::any::Any;
use std::mem;
use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint};
use crate::base::dimension::{Dim, U1};
use crate::base::storage::ContiguousStorageMut;
use crate::base::{DefaultAllocator, Scalar};
use crate::storage::{IsContiguous, RawStorageMut};
use crate::StorageMut;
use std::fmt::Debug;
use std::mem::MaybeUninit;
/// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()`
/// elements of type `T`.
@ -17,12 +19,21 @@ use crate::base::{DefaultAllocator, Scalar};
///
/// Every allocator must be both static and dynamic. Though not all implementations may share the
/// same `Buffer` type.
pub trait Allocator<T: Scalar, R: Dim, C: Dim = U1>: Any + Sized {
pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
/// The type of buffer this allocator can instanciate.
type Buffer: ContiguousStorageMut<T, R, C> + Clone;
type Buffer: StorageMut<T, R, C> + IsContiguous + Clone + Debug;
/// The type of buffer with uninitialized components this allocator can instanciate.
type BufferUninit: RawStorageMut<MaybeUninit<T>, R, C> + IsContiguous;
/// Allocates a buffer with the given number of rows and columns without initializing its content.
unsafe fn allocate_uninitialized(nrows: R, ncols: C) -> mem::MaybeUninit<Self::Buffer>;
fn allocate_uninit(nrows: R, ncols: C) -> Self::BufferUninit;
/// Assumes a data buffer to be initialized.
///
/// # Safety
/// The user must make sure that every single entry of the buffer has been initialized,
/// or Undefined Behavior will immediately occur.
unsafe fn assume_init(uninit: Self::BufferUninit) -> Self::Buffer;
/// Allocates a buffer initialized with the content of the given iterator.
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
@ -32,8 +43,8 @@ pub trait Allocator<T: Scalar, R: Dim, C: Dim = U1>: Any + Sized {
) -> Self::Buffer;
}
/// A matrix reallocator. Changes the size of the memory buffer that initially contains (RFrom ×
/// CFrom) elements to a smaller or larger size (RTo, CTo).
/// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` ×
/// `CFrom`) elements to a smaller or larger size (`RTo`, `CTo`).
pub trait Reallocator<T: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
Allocator<T, RFrom, CFrom> + Allocator<T, RTo, CTo>
{
@ -41,15 +52,15 @@ pub trait Reallocator<T: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
/// `buf`. Data stored by `buf` are linearly copied to the output:
///
/// # Safety
/// * The copy is performed as if both were just arrays (without a matrix structure).
/// * If `buf` is larger than the output size, then extra elements of `buf` are truncated.
/// * If `buf` is smaller than the output size, then extra elements of the output are left
/// uninitialized.
/// The following invariants must be respected by the implementors of this method:
/// * The copy is performed as if both were just arrays (without taking into account the matrix structure).
/// * If the underlying buffer is being shrunk, the removed elements must **not** be dropped
/// by this method. Dropping them is the responsibility of the caller.
unsafe fn reallocate_copy(
nrows: RTo,
ncols: CTo,
buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> <Self as Allocator<T, RTo, CTo>>::Buffer;
) -> <Self as Allocator<T, RTo, CTo>>::BufferUninit;
}
/// The number of rows of the result of a componentwise operation on two matrices.
@ -67,7 +78,6 @@ where
R2: Dim,
C1: Dim,
C2: Dim,
T: Scalar,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{
}
@ -78,7 +88,6 @@ where
R2: Dim,
C1: Dim,
C2: Dim,
T: Scalar,
DefaultAllocator: Allocator<T, R1, C1> + Allocator<T, SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{
@ -91,7 +100,6 @@ pub trait SameShapeVectorAllocator<T, R1, R2>:
where
R1: Dim,
R2: Dim,
T: Scalar,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
}
@ -100,7 +108,6 @@ impl<T, R1, R2> SameShapeVectorAllocator<T, R1, R2> for DefaultAllocator
where
R1: Dim,
R2: Dim,
T: Scalar,
DefaultAllocator: Allocator<T, R1, U1> + Allocator<T, SameShapeR<R1, R2>>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{

View File

@ -12,8 +12,6 @@ use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde-serialize-no-std")]
use std::marker::PhantomData;
#[cfg(feature = "serde-serialize-no-std")]
use std::mem;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
@ -21,21 +19,37 @@ use abomonation::Abomonation;
use crate::base::allocator::Allocator;
use crate::base::default_allocator::DefaultAllocator;
use crate::base::dimension::{Const, ToTypenum};
use crate::base::storage::{
ContiguousStorage, ContiguousStorageMut, Owned, ReshapableStorage, Storage, StorageMut,
};
use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage};
use crate::base::Scalar;
use crate::Storage;
use std::mem;
/*
*
* Static Storage.
* Static RawStorage.
*
*/
/// A array-based statically sized matrix data storage.
#[repr(C)]
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArrayStorage<T, const R: usize, const C: usize>(pub [[T; R]; C]);
impl<T, const R: usize, const C: usize> ArrayStorage<T, R, C> {
/// Converts this array storage to a slice.
#[inline]
pub fn as_slice(&self) -> &[T] {
// SAFETY: this is OK because ArrayStorage is contiguous.
unsafe { self.as_slice_unchecked() }
}
/// Converts this array storage to a mutable slice.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: this is OK because ArrayStorage is contiguous.
unsafe { self.as_mut_slice_unchecked() }
}
}
// TODO: remove this once the stdlib implements Default for arrays.
impl<T: Default, const R: usize, const C: usize> Default for ArrayStorage<T, R, C>
where
@ -49,16 +63,13 @@ where
impl<T: Debug, const R: usize, const C: usize> Debug for ArrayStorage<T, R, C> {
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(fmt)
}
}
unsafe impl<T, const R: usize, const C: usize> Storage<T, Const<R>, Const<C>>
unsafe impl<T, const R: usize, const C: usize> RawStorage<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
where
T: Scalar,
DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
{
type RStride = Const<1>;
type CStride = Const<R>;
@ -83,6 +94,17 @@ where
true
}
#[inline]
unsafe fn as_slice_unchecked(&self) -> &[T] {
std::slice::from_raw_parts(self.ptr(), R * C)
}
}
unsafe impl<T: Scalar, const R: usize, const C: usize> Storage<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
where
DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
{
#[inline]
fn into_owned(self) -> Owned<T, Const<R>, Const<C>>
where
@ -96,21 +118,12 @@ where
where
DefaultAllocator: Allocator<T, Const<R>, Const<C>>,
{
let it = self.as_slice().iter().cloned();
DefaultAllocator::allocate_from_iterator(self.shape().0, self.shape().1, it)
}
#[inline]
unsafe fn as_slice_unchecked(&self) -> &[T] {
std::slice::from_raw_parts(self.ptr(), R * C)
self.clone()
}
}
unsafe impl<T, const R: usize, const C: usize> StorageMut<T, Const<R>, Const<C>>
unsafe impl<T, const R: usize, const C: usize> RawStorageMut<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
where
T: Scalar,
DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
{
#[inline]
fn ptr_mut(&mut self) -> *mut T {
@ -123,21 +136,7 @@ where
}
}
unsafe impl<T, const R: usize, const C: usize> ContiguousStorage<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
where
T: Scalar,
DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
{
}
unsafe impl<T, const R: usize, const C: usize> ContiguousStorageMut<T, Const<R>, Const<C>>
for ArrayStorage<T, R, C>
where
T: Scalar,
DefaultAllocator: Allocator<T, Const<R>, Const<C>, Buffer = Self>,
{
}
unsafe impl<T, const R: usize, const C: usize> IsContiguous for ArrayStorage<T, R, C> {}
impl<T, const R1: usize, const C1: usize, const R2: usize, const C2: usize>
ReshapableStorage<T, Const<R1>, Const<C1>, Const<R2>, Const<C2>> for ArrayStorage<T, R1, C1>
@ -160,8 +159,8 @@ where
fn reshape_generic(self, _: Const<R2>, _: Const<C2>) -> Self::Output {
unsafe {
let data: [[T; R2]; C2] = std::mem::transmute_copy(&self.0);
std::mem::forget(self.0);
let data: [[T; R2]; C2] = mem::transmute_copy(&self.0);
mem::forget(self.0);
ArrayStorage(data)
}
}
@ -231,7 +230,7 @@ where
{
type Value = ArrayStorage<T, R, C>;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("a matrix array")
}
@ -240,19 +239,28 @@ where
where
V: SeqAccess<'a>,
{
let mut out: Self::Value = unsafe { mem::MaybeUninit::uninit().assume_init() };
let mut out: ArrayStorage<core::mem::MaybeUninit<T>, R, C> =
DefaultAllocator::allocate_uninit(Const::<R>, Const::<C>);
let mut curr = 0;
while let Some(value) = visitor.next_element()? {
*out.as_mut_slice()
.get_mut(curr)
.ok_or_else(|| V::Error::invalid_length(curr, &self))? = value;
.ok_or_else(|| V::Error::invalid_length(curr, &self))? =
core::mem::MaybeUninit::new(value);
curr += 1;
}
if curr == R * C {
Ok(out)
// Safety: all the elements have been initialized.
unsafe { Ok(<DefaultAllocator as Allocator<T, Const<R>, Const<C>>>::assume_init(out)) }
} else {
for i in 0..curr {
// Safety:
// - We couldnt initialize the whole storage. Drop the ones we initialized.
unsafe { std::ptr::drop_in_place(out.as_mut_slice()[i].as_mut_ptr()) };
}
Err(V::Error::invalid_length(curr, &self))
}
}

View File

@ -1,23 +1,21 @@
use crate::SimdComplexField;
#[cfg(feature = "std")]
use matrixmultiply;
use crate::{RawStorage, SimdComplexField};
use num::{One, Zero};
use simba::scalar::{ClosedAdd, ClosedMul};
#[cfg(feature = "std")]
use std::mem;
use crate::base::allocator::Allocator;
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::storage::{Storage, StorageMut};
use crate::base::uninit::Init;
use crate::base::{
DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSlice,
};
/// # Dot/scalar product
impl<T, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S>
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S>
where
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
@ -28,7 +26,7 @@ where
conjugate: impl Fn(T) -> T,
) -> T
where
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{
assert!(
@ -49,36 +47,36 @@ where
// because the `for` loop below won't be very efficient on those.
if (R::is::<U2>() || R2::is::<U2>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe {
let a = conjugate(self.get_unchecked((0, 0)).inlined_clone())
* rhs.get_unchecked((0, 0)).inlined_clone();
let b = conjugate(self.get_unchecked((1, 0)).inlined_clone())
* rhs.get_unchecked((1, 0)).inlined_clone();
let a = conjugate(self.get_unchecked((0, 0)).clone())
* rhs.get_unchecked((0, 0)).clone();
let b = conjugate(self.get_unchecked((1, 0)).clone())
* rhs.get_unchecked((1, 0)).clone();
return a + b;
}
}
if (R::is::<U3>() || R2::is::<U3>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe {
let a = conjugate(self.get_unchecked((0, 0)).inlined_clone())
* rhs.get_unchecked((0, 0)).inlined_clone();
let b = conjugate(self.get_unchecked((1, 0)).inlined_clone())
* rhs.get_unchecked((1, 0)).inlined_clone();
let c = conjugate(self.get_unchecked((2, 0)).inlined_clone())
* rhs.get_unchecked((2, 0)).inlined_clone();
let a = conjugate(self.get_unchecked((0, 0)).clone())
* rhs.get_unchecked((0, 0)).clone();
let b = conjugate(self.get_unchecked((1, 0)).clone())
* rhs.get_unchecked((1, 0)).clone();
let c = conjugate(self.get_unchecked((2, 0)).clone())
* rhs.get_unchecked((2, 0)).clone();
return a + b + c;
}
}
if (R::is::<U4>() || R2::is::<U4>()) && (C::is::<U1>() || C2::is::<U1>()) {
unsafe {
let mut a = conjugate(self.get_unchecked((0, 0)).inlined_clone())
* rhs.get_unchecked((0, 0)).inlined_clone();
let mut b = conjugate(self.get_unchecked((1, 0)).inlined_clone())
* rhs.get_unchecked((1, 0)).inlined_clone();
let c = conjugate(self.get_unchecked((2, 0)).inlined_clone())
* rhs.get_unchecked((2, 0)).inlined_clone();
let d = conjugate(self.get_unchecked((3, 0)).inlined_clone())
* rhs.get_unchecked((3, 0)).inlined_clone();
let mut a = conjugate(self.get_unchecked((0, 0)).clone())
* rhs.get_unchecked((0, 0)).clone();
let mut b = conjugate(self.get_unchecked((1, 0)).clone())
* rhs.get_unchecked((1, 0)).clone();
let c = conjugate(self.get_unchecked((2, 0)).clone())
* rhs.get_unchecked((2, 0)).clone();
let d = conjugate(self.get_unchecked((3, 0)).clone())
* rhs.get_unchecked((3, 0)).clone();
a += c;
b += d;
@ -119,36 +117,36 @@ where
while self.nrows() - i >= 8 {
acc0 += unsafe {
conjugate(self.get_unchecked((i, j)).inlined_clone())
* rhs.get_unchecked((i, j)).inlined_clone()
conjugate(self.get_unchecked((i, j)).clone())
* rhs.get_unchecked((i, j)).clone()
};
acc1 += unsafe {
conjugate(self.get_unchecked((i + 1, j)).inlined_clone())
* rhs.get_unchecked((i + 1, j)).inlined_clone()
conjugate(self.get_unchecked((i + 1, j)).clone())
* rhs.get_unchecked((i + 1, j)).clone()
};
acc2 += unsafe {
conjugate(self.get_unchecked((i + 2, j)).inlined_clone())
* rhs.get_unchecked((i + 2, j)).inlined_clone()
conjugate(self.get_unchecked((i + 2, j)).clone())
* rhs.get_unchecked((i + 2, j)).clone()
};
acc3 += unsafe {
conjugate(self.get_unchecked((i + 3, j)).inlined_clone())
* rhs.get_unchecked((i + 3, j)).inlined_clone()
conjugate(self.get_unchecked((i + 3, j)).clone())
* rhs.get_unchecked((i + 3, j)).clone()
};
acc4 += unsafe {
conjugate(self.get_unchecked((i + 4, j)).inlined_clone())
* rhs.get_unchecked((i + 4, j)).inlined_clone()
conjugate(self.get_unchecked((i + 4, j)).clone())
* rhs.get_unchecked((i + 4, j)).clone()
};
acc5 += unsafe {
conjugate(self.get_unchecked((i + 5, j)).inlined_clone())
* rhs.get_unchecked((i + 5, j)).inlined_clone()
conjugate(self.get_unchecked((i + 5, j)).clone())
* rhs.get_unchecked((i + 5, j)).clone()
};
acc6 += unsafe {
conjugate(self.get_unchecked((i + 6, j)).inlined_clone())
* rhs.get_unchecked((i + 6, j)).inlined_clone()
conjugate(self.get_unchecked((i + 6, j)).clone())
* rhs.get_unchecked((i + 6, j)).clone()
};
acc7 += unsafe {
conjugate(self.get_unchecked((i + 7, j)).inlined_clone())
* rhs.get_unchecked((i + 7, j)).inlined_clone()
conjugate(self.get_unchecked((i + 7, j)).clone())
* rhs.get_unchecked((i + 7, j)).clone()
};
i += 8;
}
@ -160,8 +158,8 @@ where
for k in i..self.nrows() {
res += unsafe {
conjugate(self.get_unchecked((k, j)).inlined_clone())
* rhs.get_unchecked((k, j)).inlined_clone()
conjugate(self.get_unchecked((k, j)).clone())
* rhs.get_unchecked((k, j)).clone()
}
}
}
@ -196,7 +194,7 @@ where
#[must_use]
pub fn dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{
self.dotx(rhs, |e| e)
@ -226,7 +224,7 @@ where
pub fn dotc<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where
T: SimdComplexField,
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<R, R2> + DimEq<C, C2>,
{
self.dotx(rhs, T::simd_conjugate)
@ -253,7 +251,7 @@ where
#[must_use]
pub fn tr_dot<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> T
where
SB: Storage<T, R2, C2>,
SB: RawStorage<T, R2, C2>,
ShapeConstraint: DimEq<C, R2> + DimEq<R, C2>,
{
let (nrows, ncols) = self.shape();
@ -268,8 +266,7 @@ where
for j in 0..self.nrows() {
for i in 0..self.ncols() {
res += unsafe {
self.get_unchecked((j, i)).inlined_clone()
* rhs.get_unchecked((i, j)).inlined_clone()
self.get_unchecked((j, i)).clone() * rhs.get_unchecked((i, j)).clone()
}
}
}
@ -278,43 +275,6 @@ where
}
}
#[allow(clippy::too_many_arguments)]
fn array_axcpy<T>(
y: &mut [T],
a: T,
x: &[T],
c: T,
beta: T,
stride1: usize,
stride2: usize,
len: usize,
) where
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
for i in 0..len {
unsafe {
let y = y.get_unchecked_mut(i * stride1);
*y = a.inlined_clone()
* x.get_unchecked(i * stride2).inlined_clone()
* c.inlined_clone()
+ beta.inlined_clone() * y.inlined_clone();
}
}
}
fn array_axc<T>(y: &mut [T], a: T, x: &[T], c: T, stride1: usize, stride2: usize, len: usize)
where
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
for i in 0..len {
unsafe {
*y.get_unchecked_mut(i * stride1) = a.inlined_clone()
* x.get_unchecked(i * stride2).inlined_clone()
* c.inlined_clone();
}
}
}
/// # BLAS functions
impl<T, D: Dim, S> Vector<T, D, S>
where
@ -341,23 +301,7 @@ where
SB: Storage<T, D2>,
ShapeConstraint: DimEq<D, D2>,
{
assert_eq!(self.nrows(), x.nrows(), "Axcpy: mismatched vector shapes.");
let rstride1 = self.strides().0;
let rstride2 = x.strides().0;
unsafe {
// SAFETY: the conversion to slices is OK because we access the
// elements taking the strides into account.
let y = self.data.as_mut_slice_unchecked();
let x = x.data.as_slice_unchecked();
if !b.is_zero() {
array_axcpy(y, a, x, c, b, rstride1, rstride2, x.len());
} else {
array_axc(y, a, x, c, rstride1, rstride2, x.len());
}
}
unsafe { axcpy_uninit(Init, self, a, x, c, b) };
}
/// Computes `self = a * x + b * self`.
@ -413,38 +357,8 @@ where
SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, R2> + AreMultipliable<R2, C2, D3, U1>,
{
let dim1 = self.nrows();
let (nrows2, ncols2) = a.shape();
let dim3 = x.nrows();
assert!(
ncols2 == dim3 && dim1 == nrows2,
"Gemv: dimensions mismatch."
);
if ncols2 == 0 {
// NOTE: we can't just always multiply by beta
// because we documented the guaranty that `self` is
// never read if `beta` is zero.
if beta.is_zero() {
self.fill(T::zero());
} else {
*self *= beta;
}
return;
}
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
self.axcpy(alpha.inlined_clone(), &col2, val, beta);
for j in 1..ncols2 {
let col2 = a.column(j);
let val = unsafe { x.vget_unchecked(j).inlined_clone() };
self.axcpy(alpha.inlined_clone(), &col2, val, T::one());
}
// Safety: this is safe because we are passing Status == Init.
unsafe { gemv_uninit(Init, self, alpha, a, x, beta) }
}
#[inline(always)]
@ -455,8 +369,8 @@ where
x: &Vector<T, D3, SC>,
beta: T,
dot: impl Fn(
&DVectorSlice<T, SB::RStride, SB::CStride>,
&DVectorSlice<T, SC::RStride, SC::CStride>,
&DVectorSlice<'_, T, SB::RStride, SB::CStride>,
&DVectorSlice<'_, T, SC::RStride, SC::CStride>,
) -> T,
) where
T: One,
@ -483,9 +397,9 @@ where
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = unsafe { x.vget_unchecked(0).inlined_clone() };
self.axpy(alpha.inlined_clone() * val, &col2, beta);
self[0] += alpha.inlined_clone() * dot(&a.slice_range(1.., 0), &x.rows_range(1..));
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..));
for j in 1..dim2 {
let col2 = a.column(j);
@ -493,36 +407,17 @@ where
let val;
unsafe {
val = x.vget_unchecked(j).inlined_clone();
*self.vget_unchecked_mut(j) += alpha.inlined_clone() * dot;
val = x.vget_unchecked(j).clone();
*self.vget_unchecked_mut(j) += alpha.clone() * dot;
}
self.rows_range_mut(j + 1..).axpy(
alpha.inlined_clone() * val,
alpha.clone() * val,
&col2.rows_range(j + 1..),
T::one(),
);
}
}
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
/// vector, and `alpha, beta` two scalars. DEPRECATED: use `sygemv` instead.
#[inline]
#[deprecated(note = "This is renamed `sygemv` to match the original BLAS terminology.")]
pub fn gemv_symm<D2: Dim, D3: Dim, SB, SC>(
&mut self,
alpha: T,
a: &SquareMatrix<T, D2, SB>,
x: &Vector<T, D3, SC>,
beta: T,
) where
T: One,
SB: Storage<T, D2, D2>,
SC: Storage<T, D3>,
ShapeConstraint: DimEq<D, D2> + AreMultipliable<D2, D2, D3, U1>,
{
self.sygemv(alpha, a, x, beta)
}
/// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a
/// vector, and `alpha, beta` two scalars.
///
@ -619,7 +514,7 @@ where
a: &Matrix<T, R2, C2, SB>,
x: &Vector<T, D3, SC>,
beta: T,
dot: impl Fn(&VectorSlice<T, R2, SB::RStride, SB::CStride>, &Vector<T, D3, SC>) -> T,
dot: impl Fn(&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>, &Vector<T, D3, SC>) -> T,
) where
T: One,
SB: Storage<T, R2, C2>,
@ -642,13 +537,12 @@ where
if beta.is_zero() {
for j in 0..ncols2 {
let val = unsafe { self.vget_unchecked_mut(j) };
*val = alpha.inlined_clone() * dot(&a.column(j), x)
*val = alpha.clone() * dot(&a.column(j), x)
}
} else {
for j in 0..ncols2 {
let val = unsafe { self.vget_unchecked_mut(j) };
*val = alpha.inlined_clone() * dot(&a.column(j), x)
+ beta.inlined_clone() * val.inlined_clone();
*val = alpha.clone() * dot(&a.column(j), x) + beta.clone() * val.clone();
}
}
}
@ -752,9 +646,9 @@ where
for j in 0..ncols1 {
// TODO: avoid bound checks.
let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) };
let val = unsafe { conjugate(y.vget_unchecked(j).clone()) };
self.column_mut(j)
.axpy(alpha.inlined_clone() * val, x, beta.inlined_clone());
.axpy(alpha.clone() * val, x, beta.clone());
}
}
@ -859,122 +753,9 @@ where
+ SameNumberOfColumns<C1, C3>
+ AreMultipliable<R2, C2, R3, C3>,
{
let ncols1 = self.ncols();
#[cfg(feature = "std")]
{
// We assume large matrices will be Dynamic 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::<Dynamic>()
|| C1::is::<Dynamic>()
|| R2::is::<Dynamic>()
|| C2::is::<Dynamic>()
|| R3::is::<Dynamic>()
|| C3::is::<Dynamic>()
{
// matrixmultiply can be used only if the std feature is available.
let nrows1 = self.nrows();
let (nrows2, ncols2) = a.shape();
let (nrows3, ncols3) = b.shape();
// Threshold determined empirically.
const SMALL_DIM: usize = 5;
if nrows1 > SMALL_DIM
&& ncols1 > SMALL_DIM
&& nrows2 > SMALL_DIM
&& ncols2 > SMALL_DIM
{
assert_eq!(
ncols2, nrows3,
"gemm: dimensions mismatch for multiplication."
);
assert_eq!(
(nrows1, ncols1),
(nrows2, ncols3),
"gemm: dimensions mismatch for addition."
);
// NOTE: this case should never happen because we enter this
// codepath only when ncols2 > SMALL_DIM. Though we keep this
// here just in case if in the future we change the conditions to
// enter this codepath.
if ncols2 == 0 {
// NOTE: we can't just always multiply by beta
// because we documented the guaranty that `self` is
// never read if `beta` is zero.
if beta.is_zero() {
self.fill(T::zero());
} else {
*self *= beta;
}
return;
}
if T::is::<f32>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = self.strides();
unsafe {
matrixmultiply::sgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f32,
rsa as isize,
csa as isize,
b.data.ptr() as *const f32,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
self.data.ptr_mut() as *mut f32,
rsc as isize,
csc as isize,
);
}
return;
} else if T::is::<f64>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = self.strides();
unsafe {
matrixmultiply::dgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f64,
rsa as isize,
csa as isize,
b.data.ptr() as *const f64,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
self.data.ptr_mut() as *mut f64,
rsc as isize,
csc as isize,
);
}
return;
}
}
}
}
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
self.column_mut(j1).gemv(
alpha.inlined_clone(),
a,
&b.column(j1),
beta.inlined_clone(),
);
}
// SAFETY: this is valid because our matrices are initialized and
// we are using status = Init.
unsafe { gemm_uninit(Init, self, alpha, a, b, beta) }
}
/// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices.
@ -1030,12 +811,8 @@ where
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
self.column_mut(j1).gemv_tr(
alpha.inlined_clone(),
a,
&b.column(j1),
beta.inlined_clone(),
);
self.column_mut(j1)
.gemv_tr(alpha.clone(), a, &b.column(j1), beta.clone());
}
}
@ -1092,7 +869,8 @@ where
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
self.column_mut(j1).gemv_ad(alpha, a, &b.column(j1), beta);
self.column_mut(j1)
.gemv_ad(alpha.clone(), a, &b.column(j1), beta.clone());
}
}
}
@ -1126,13 +904,13 @@ where
assert!(dim1 == dim2 && dim1 == dim3, "ger: dimensions mismatch.");
for j in 0..dim1 {
let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) };
let val = unsafe { conjugate(y.vget_unchecked(j).clone()) };
let subdim = Dynamic::new(dim1 - j);
// TODO: avoid bound checks.
self.generic_slice_mut((j, j), (subdim, Const::<1>)).axpy(
alpha.inlined_clone() * val,
alpha.clone() * val,
&x.rows_range(j..),
beta.inlined_clone(),
beta.clone(),
);
}
}
@ -1293,11 +1071,11 @@ where
ShapeConstraint: DimEq<D1, D2> + DimEq<D1, R3> + DimEq<D2, R3> + DimEq<C3, D4>,
{
work.gemv(T::one(), lhs, &mid.column(0), T::zero());
self.ger(alpha.inlined_clone(), work, &lhs.column(0), beta);
self.ger(alpha.clone(), work, &lhs.column(0), beta);
for j in 1..mid.ncols() {
work.gemv(T::one(), lhs, &mid.column(j), T::zero());
self.ger(alpha.inlined_clone(), work, &lhs.column(j), T::one());
self.ger(alpha.clone(), work, &lhs.column(j), T::one());
}
}
@ -1337,9 +1115,8 @@ where
ShapeConstraint: DimEq<D1, D1> + DimEq<D1, R3> + DimEq<C3, D4>,
DefaultAllocator: Allocator<T, D1>,
{
let mut work = unsafe {
crate::unimplemented_or_uninitialized_generic!(self.data.shape().0, Const::<1>)
};
// TODO: would it be useful to avoid the zero-initialization of the workspace data?
let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>);
self.quadform_tr_with_workspace(&mut work, alpha, lhs, mid, beta)
}
@ -1388,12 +1165,12 @@ where
{
work.gemv(T::one(), mid, &rhs.column(0), T::zero());
self.column_mut(0)
.gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
.gemv_tr(alpha.clone(), rhs, work, beta.clone());
for j in 1..rhs.ncols() {
work.gemv(T::one(), mid, &rhs.column(j), T::zero());
self.column_mut(j)
.gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone());
.gemv_tr(alpha.clone(), rhs, work, beta.clone());
}
}
@ -1432,9 +1209,8 @@ where
ShapeConstraint: DimEq<D2, R3> + DimEq<D1, C3> + AreMultipliable<C3, R3, D2, U1>,
DefaultAllocator: Allocator<T, D2>,
{
let mut work = unsafe {
crate::unimplemented_or_uninitialized_generic!(mid.data.shape().0, Const::<1>)
};
// TODO: would it be useful to avoid the zero-initialization of the workspace data?
let mut work = Vector::zeros_generic(mid.shape_generic().0, Const::<1>);
self.quadform_with_workspace(&mut work, alpha, mid, rhs, beta)
}
}

321
src/base/blas_uninit.rs Normal file
View File

@ -0,0 +1,321 @@
/*
* This file implements some BLAS operations in such a way that they work
* even if the first argument (the output parameter) is an uninitialized matrix.
*
* Because doing this makes the code harder to read, we only implemented the operations that we
* know would benefit from this performance-wise, namely, GEMM (which we use for our matrix
* multiplication code). If we identify other operations like that in the future, we could add
* them here.
*/
#[cfg(feature = "std")]
use matrixmultiply;
use num::{One, Zero};
use simba::scalar::{ClosedAdd, ClosedMul};
#[cfg(feature = "std")]
use std::mem;
use crate::base::constraint::{
AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
};
use crate::base::dimension::{Dim, Dynamic, 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
// `Status::assume_init_mut` is sound.
#[allow(clippy::too_many_arguments)]
unsafe fn array_axcpy<Status, T>(
_: Status,
y: &mut [Status::Value],
a: T,
x: &[T],
c: T,
beta: T,
stride1: usize,
stride2: usize,
len: usize,
) where
Status: InitStatus<T>,
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
for i in 0..len {
let y = Status::assume_init_mut(y.get_unchecked_mut(i * stride1));
*y =
a.clone() * x.get_unchecked(i * stride2).clone() * c.clone() + beta.clone() * y.clone();
}
}
fn array_axc<Status, T>(
_: Status,
y: &mut [Status::Value],
a: T,
x: &[T],
c: T,
stride1: usize,
stride2: usize,
len: usize,
) where
Status: InitStatus<T>,
T: Scalar + Zero + ClosedAdd + ClosedMul,
{
for i in 0..len {
unsafe {
Status::init(
y.get_unchecked_mut(i * stride1),
a.clone() * x.get_unchecked(i * stride2).clone() * c.clone(),
);
}
}
}
/// Computes `y = a * x * c + b * y`.
///
/// If `b` is zero, `y` is never read from and may be uninitialized.
///
/// # Safety
/// This is UB if b != 0 and any component of `y` is uninitialized.
#[inline(always)]
#[allow(clippy::many_single_char_names)]
pub unsafe fn axcpy_uninit<Status, T, D1: Dim, D2: Dim, SA, SB>(
status: Status,
y: &mut Vector<Status::Value, D1, SA>,
a: T,
x: &Vector<T, D2, SB>,
c: T,
b: T,
) where
T: Scalar + Zero + ClosedAdd + ClosedMul,
SA: RawStorageMut<Status::Value, D1>,
SB: RawStorage<T, D2>,
ShapeConstraint: DimEq<D1, D2>,
Status: InitStatus<T>,
{
assert_eq!(y.nrows(), x.nrows(), "Axcpy: mismatched vector shapes.");
let rstride1 = y.strides().0;
let rstride2 = x.strides().0;
// SAFETY: the conversion to slices is OK because we access the
// elements taking the strides into account.
let y = y.data.as_mut_slice_unchecked();
let x = x.data.as_slice_unchecked();
if !b.is_zero() {
array_axcpy(status, y, a, x, c, b, rstride1, rstride2, x.len());
} else {
array_axc(status, y, a, x, c, rstride1, rstride2, x.len());
}
}
/// Computes `y = alpha * a * x + beta * y`, where `a` is a matrix, `x` a vector, and
/// `alpha, beta` two scalars.
///
/// If `beta` is zero, `y` is never read from and may be uninitialized.
///
/// # Safety
/// This is UB if beta != 0 and any component of `y` is uninitialized.
#[inline(always)]
pub unsafe fn gemv_uninit<Status, T, D1: Dim, R2: Dim, C2: Dim, D3: Dim, SA, SB, SC>(
status: Status,
y: &mut Vector<Status::Value, D1, SA>,
alpha: T,
a: &Matrix<T, R2, C2, SB>,
x: &Vector<T, D3, SC>,
beta: T,
) where
Status: InitStatus<T>,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SA: RawStorageMut<Status::Value, D1>,
SB: RawStorage<T, R2, C2>,
SC: RawStorage<T, D3>,
ShapeConstraint: DimEq<D1, R2> + AreMultipliable<R2, C2, D3, U1>,
{
let dim1 = y.nrows();
let (nrows2, ncols2) = a.shape();
let dim3 = x.nrows();
assert!(
ncols2 == dim3 && dim1 == nrows2,
"Gemv: dimensions mismatch."
);
if ncols2 == 0 {
if beta.is_zero() {
y.apply(|e| Status::init(e, T::zero()));
} else {
// SAFETY: this is UB if y is uninitialized.
y.apply(|e| *Status::assume_init_mut(e) *= beta.clone());
}
return;
}
// TODO: avoid bound checks.
let col2 = a.column(0);
let val = x.vget_unchecked(0).clone();
// SAFETY: this is the call that makes this method unsafe: it is UB if Status = Uninit and beta != 0.
axcpy_uninit(status, y, alpha.clone(), &col2, val, beta);
for j in 1..ncols2 {
let col2 = a.column(j);
let val = x.vget_unchecked(j).clone();
// SAFETY: safe because y was initialized above.
axcpy_uninit(status, y, alpha.clone(), &col2, val, T::one());
}
}
/// Computes `y = alpha * a * b + beta * y`, where `a, b, y` are matrices.
/// `alpha` and `beta` are scalar.
///
/// If `beta` is zero, `y` is never read from and may be uninitialized.
///
/// # Safety
/// This is UB if beta != 0 and any component of `y` is uninitialized.
#[inline(always)]
pub unsafe fn gemm_uninit<
Status,
T,
R1: Dim,
C1: Dim,
R2: Dim,
C2: Dim,
R3: Dim,
C3: Dim,
SA,
SB,
SC,
>(
status: Status,
y: &mut Matrix<Status::Value, R1, C1, SA>,
alpha: T,
a: &Matrix<T, R2, C2, SB>,
b: &Matrix<T, R3, C3, SC>,
beta: T,
) where
Status: InitStatus<T>,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SA: RawStorageMut<Status::Value, R1, C1>,
SB: RawStorage<T, R2, C2>,
SC: RawStorage<T, R3, C3>,
ShapeConstraint:
SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C3> + AreMultipliable<R2, C2, R3, C3>,
{
let ncols1 = y.ncols();
#[cfg(feature = "std")]
{
// We assume large matrices will be Dynamic 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::<Dynamic>()
|| C1::is::<Dynamic>()
|| R2::is::<Dynamic>()
|| C2::is::<Dynamic>()
|| R3::is::<Dynamic>()
|| C3::is::<Dynamic>()
{
// matrixmultiply can be used only if the std feature is available.
let nrows1 = y.nrows();
let (nrows2, ncols2) = a.shape();
let (nrows3, ncols3) = b.shape();
// Threshold determined empirically.
const SMALL_DIM: usize = 5;
if nrows1 > SMALL_DIM && ncols1 > SMALL_DIM && nrows2 > SMALL_DIM && ncols2 > SMALL_DIM
{
assert_eq!(
ncols2, nrows3,
"gemm: dimensions mismatch for multiplication."
);
assert_eq!(
(nrows1, ncols1),
(nrows2, ncols3),
"gemm: dimensions mismatch for addition."
);
// NOTE: this case should never happen because we enter this
// codepath only when ncols2 > SMALL_DIM. Though we keep this
// here just in case if in the future we change the conditions to
// enter this codepath.
if ncols2 == 0 {
// NOTE: we can't just always multiply by beta
// because we documented the guaranty that `self` is
// never read if `beta` is zero.
if beta.is_zero() {
y.apply(|e| Status::init(e, T::zero()));
} else {
// SAFETY: this is UB if Status = Uninit
y.apply(|e| *Status::assume_init_mut(e) *= beta.clone());
}
return;
}
if TypeId::of::<T>() == TypeId::of::<f32>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = y.strides();
matrixmultiply::sgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f32,
rsa as isize,
csa as isize,
b.data.ptr() as *const f32,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
y.data.ptr_mut() as *mut f32,
rsc as isize,
csc as isize,
);
return;
} else if TypeId::of::<T>() == TypeId::of::<f64>() {
let (rsa, csa) = a.strides();
let (rsb, csb) = b.strides();
let (rsc, csc) = y.strides();
matrixmultiply::dgemm(
nrows2,
ncols2,
ncols3,
mem::transmute_copy(&alpha),
a.data.ptr() as *const f64,
rsa as isize,
csa as isize,
b.data.ptr() as *const f64,
rsb as isize,
csb as isize,
mem::transmute_copy(&beta),
y.data.ptr_mut() as *mut f64,
rsc as isize,
csc as isize,
);
return;
}
}
}
}
for j1 in 0..ncols1 {
// TODO: avoid bound checks.
// SAFETY: this is UB if Status = Uninit && beta != 0
gemv_uninit(
status,
&mut y.column_mut(j1),
alpha.clone(),
a,
&b.column(j1),
beta.clone(),
);
}
}

View File

@ -45,7 +45,7 @@ where
{
let mut res = Self::identity();
for i in 0..scaling.len() {
res[(i, i)] = scaling[i].inlined_clone();
res[(i, i)] = scaling[i].clone();
}
res
@ -79,19 +79,19 @@ impl<T: RealField> Matrix3<T> {
/// Creates a new homogeneous matrix that applies a scaling factor for each dimension with respect to point.
///
/// Can be used to implement "zoom_to" functionality.
/// Can be used to implement `zoom_to` functionality.
#[inline]
pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector2<T>, pt: &Point2<T>) -> Self {
let zero = T::zero();
let one = T::one();
Matrix3::new(
scaling.x,
zero,
pt.x - pt.x * scaling.x,
zero,
scaling.y,
pt.y - pt.y * scaling.y,
zero,
scaling.x.clone(),
zero.clone(),
pt.x.clone() - pt.x.clone() * scaling.x.clone(),
zero.clone(),
scaling.y.clone(),
pt.y.clone() - pt.y.clone() * scaling.y.clone(),
zero.clone(),
zero,
one,
)
@ -119,26 +119,26 @@ impl<T: RealField> Matrix4<T> {
/// Creates a new homogeneous matrix that applies a scaling factor for each dimension with respect to point.
///
/// Can be used to implement "zoom_to" functionality.
/// Can be used to implement `zoom_to` functionality.
#[inline]
pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector3<T>, pt: &Point3<T>) -> Self {
let zero = T::zero();
let one = T::one();
Matrix4::new(
scaling.x,
zero,
zero,
pt.x - pt.x * scaling.x,
zero,
scaling.y,
zero,
pt.y - pt.y * scaling.y,
zero,
zero,
scaling.z,
pt.z - pt.z * scaling.z,
zero,
zero,
scaling.x.clone(),
zero.clone(),
zero.clone(),
pt.x.clone() - pt.x.clone() * scaling.x.clone(),
zero.clone(),
scaling.y.clone(),
zero.clone(),
pt.y.clone() - pt.y.clone() * scaling.y.clone(),
zero.clone(),
zero.clone(),
scaling.z.clone(),
pt.z.clone() - pt.z.clone() * scaling.z.clone(),
zero.clone(),
zero.clone(),
zero,
one,
)
@ -187,7 +187,7 @@ impl<T: RealField> Matrix4<T> {
IsometryMatrix3::face_towards(eye, target, up).to_homogeneous()
}
/// Deprecated: Use [Matrix4::face_towards] instead.
/// Deprecated: Use [`Matrix4::face_towards`] instead.
#[deprecated(note = "renamed to `face_towards`")]
pub fn new_observer_frame(eye: &Point3<T>, target: &Point3<T>, up: &Vector3<T>) -> Self {
Matrix4::face_towards(eye, target, up)
@ -336,7 +336,7 @@ impl<T: Scalar + Zero + One + ClosedMul + ClosedAdd, D: DimName, S: Storage<T, D
{
for i in 0..scaling.len() {
let mut to_scale = self.fixed_rows_mut::<1>(i);
to_scale *= scaling[i].inlined_clone();
to_scale *= scaling[i].clone();
}
}
@ -352,7 +352,7 @@ impl<T: Scalar + Zero + One + ClosedMul + ClosedAdd, D: DimName, S: Storage<T, D
{
for i in 0..scaling.len() {
let mut to_scale = self.fixed_columns_mut::<1>(i);
to_scale *= scaling[i].inlined_clone();
to_scale *= scaling[i].clone();
}
}
@ -366,7 +366,7 @@ impl<T: Scalar + Zero + One + ClosedMul + ClosedAdd, D: DimName, S: Storage<T, D
{
for i in 0..D::dim() {
for j in 0..D::dim() - 1 {
let add = shift[j].inlined_clone() * self[(D::dim() - 1, i)].inlined_clone();
let add = shift[j].clone() * self[(D::dim() - 1, i)].clone();
self[(j, i)] += add;
}
}
@ -440,7 +440,7 @@ impl<T: RealField, S: Storage<T, Const<3>, Const<3>>> SquareMatrix<T, Const<3>,
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 n = normalizer.tr_dot(&pt.coords) + unsafe { *self.get_unchecked((2, 2)) };
let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((2, 2)).clone() };
if !n.is_zero() {
(transform * pt + translation) / n
@ -457,7 +457,7 @@ impl<T: RealField, S: Storage<T, Const<4>, Const<4>>> SquareMatrix<T, Const<4>,
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 n = normalizer.tr_dot(&pt.coords) + unsafe { *self.get_unchecked((3, 3)) };
let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((3, 3)).clone() };
if !n.is_zero() {
(transform * pt + translation) / n

View File

@ -64,7 +64,7 @@ macro_rules! component_binop_impl(
for j in 0 .. res.ncols() {
for i in 0 .. res.nrows() {
unsafe {
res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone());
res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).clone());
}
}
}
@ -91,7 +91,7 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone());
let res = alpha.clone() * a.get_unchecked((i, j)).clone().$op(b.get_unchecked((i, j)).clone());
*self.get_unchecked_mut((i, j)) = res;
}
}
@ -101,8 +101,8 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
let res = alpha.inlined_clone() * a.get_unchecked((i, j)).inlined_clone().$op(b.get_unchecked((i, j)).inlined_clone());
*self.get_unchecked_mut((i, j)) = beta.inlined_clone() * self.get_unchecked((i, j)).inlined_clone() + res;
let res = alpha.clone() * a.get_unchecked((i, j)).clone().$op(b.get_unchecked((i, j)).clone());
*self.get_unchecked_mut((i, j)) = beta.clone() * self.get_unchecked((i, j)).clone() + res;
}
}
}
@ -124,7 +124,7 @@ macro_rules! component_binop_impl(
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe {
self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).inlined_clone());
self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).clone());
}
}
}
@ -347,7 +347,7 @@ impl<T: Scalar, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
SA: StorageMut<T, R1, C1>,
{
for e in self.iter_mut() {
*e += rhs.inlined_clone()
*e += rhs.clone()
}
}
}

View File

@ -3,6 +3,7 @@
use crate::base::dimension::{Dim, DimName, Dynamic};
/// A type used in `where` clauses for enforcing constraints.
#[derive(Copy, Clone, Debug)]
pub struct ShapeConstraint;
/// Constraints `C1` and `R2` to be equivalent.

View File

@ -14,33 +14,32 @@ use rand::{
};
use std::iter;
use std::mem;
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::storage::Storage;
use crate::base::storage::RawStorage;
use crate::base::{
ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector,
};
use crate::UninitMatrix;
use std::mem::MaybeUninit;
/// When "no_unsound_assume_init" is enabled, expands to `unimplemented!()` instead of `new_uninitialized_generic().assume_init()`.
/// Intended as a placeholder, each callsite should be refactored to use uninitialized memory soundly
#[macro_export]
macro_rules! unimplemented_or_uninitialized_generic {
($nrows:expr, $ncols:expr) => {{
#[cfg(feature="no_unsound_assume_init")] {
// Some of the call sites need the number of rows and columns from this to infer a type, so
// uninitialized memory is used to infer the type, as `T: Zero` isn't available at all callsites.
// This may technically still be UB even though the assume_init is dead code, but all callsites should be fixed before #556 is closed.
let typeinference_helper = crate::base::Matrix::new_uninitialized_generic($nrows, $ncols);
unimplemented!();
typeinference_helper.assume_init()
impl<T: Scalar, R: Dim, C: Dim> UninitMatrix<T, R, C>
where
DefaultAllocator: Allocator<T, R, C>,
{
/// Builds a matrix with uninitialized elements of type `MaybeUninit<T>`.
#[inline(always)]
pub fn uninit(nrows: R, ncols: C) -> Self {
// SAFETY: this is OK because the dimension automatically match the storage
// because we are building an owned storage.
unsafe {
Self::from_data_statically_unchecked(DefaultAllocator::allocate_uninit(nrows, ncols))
}
#[cfg(not(feature="no_unsound_assume_init"))] { crate::base::Matrix::new_uninitialized_generic($nrows, $ncols).assume_init() }
}}
}
}
/// # Generic constructors
@ -53,16 +52,6 @@ impl<T: Scalar, R: Dim, C: Dim> OMatrix<T, R, C>
where
DefaultAllocator: Allocator<T, R, C>,
{
/// Creates a new uninitialized matrix.
///
/// # Safety
/// If the matrix has a compile-time dimension, this panics
/// if `nrows != R::to_usize()` or `ncols != C::to_usize()`.
#[inline]
pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> mem::MaybeUninit<Self> {
Self::from_uninitialized_data(DefaultAllocator::allocate_uninitialized(nrows, ncols))
}
/// Creates a matrix with all its elements set to `elem`.
#[inline]
pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self {
@ -109,16 +98,19 @@ where
"Matrix init. error: the slice did not contain the right number of elements."
);
let mut res = unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = Matrix::uninit(nrows, ncols);
let mut iter = slice.iter();
for i in 0..nrows.value() {
for j in 0..ncols.value() {
unsafe { *res.get_unchecked_mut((i, j)) = iter.next().unwrap().inlined_clone() }
unsafe {
for i in 0..nrows.value() {
for j in 0..ncols.value() {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(iter.next().unwrap().clone())
}
}
}
res
// SAFETY: the result has been fully initialized above.
res.assume_init()
}
}
/// Creates a matrix with its elements filled with the components provided by a slice. The
@ -135,15 +127,18 @@ where
where
F: FnMut(usize, usize) -> T,
{
let mut res: Self = unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
let mut res = Matrix::uninit(nrows, ncols);
for j in 0..ncols.value() {
for i in 0..nrows.value() {
unsafe { *res.get_unchecked_mut((i, j)) = f(i, j) }
unsafe {
for j in 0..ncols.value() {
for i in 0..nrows.value() {
*res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j));
}
}
}
res
// SAFETY: the result has been fully initialized above.
res.assume_init()
}
}
/// Creates a new identity matrix.
@ -170,7 +165,7 @@ where
let mut res = Self::zeros_generic(nrows, ncols);
for i in 0..crate::min(nrows.value(), ncols.value()) {
unsafe { *res.get_unchecked_mut((i, i)) = elt.inlined_clone() }
unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() }
}
res
@ -192,7 +187,7 @@ where
);
for (i, elt) in elts.iter().enumerate() {
unsafe { *res.get_unchecked_mut((i, i)) = elt.inlined_clone() }
unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() }
}
res
@ -217,7 +212,7 @@ where
#[inline]
pub fn from_rows<SB>(rows: &[Matrix<T, Const<1>, C, SB>]) -> Self
where
SB: Storage<T, Const<1>, C>,
SB: RawStorage<T, Const<1>, C>,
{
assert!(!rows.is_empty(), "At least one row must be given.");
let nrows = R::try_to_usize().unwrap_or_else(|| rows.len());
@ -236,7 +231,7 @@ where
// TODO: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
rows[i][(0, j)].inlined_clone()
rows[i][(0, j)].clone()
})
}
@ -259,7 +254,7 @@ where
#[inline]
pub fn from_columns<SB>(columns: &[Vector<T, R, SB>]) -> Self
where
SB: Storage<T, R>,
SB: RawStorage<T, R>,
{
assert!(!columns.is_empty(), "At least one column must be given.");
let ncols = C::try_to_usize().unwrap_or_else(|| columns.len());
@ -278,7 +273,7 @@ where
// TODO: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| {
columns[j][i].inlined_clone()
columns[j][i].clone()
})
}
@ -353,16 +348,16 @@ where
/// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0);
/// ```
#[inline]
pub fn from_diagonal<SB: Storage<T, D>>(diag: &Vector<T, D, SB>) -> Self
pub fn from_diagonal<SB: RawStorage<T, D>>(diag: &Vector<T, D, SB>) -> Self
where
T: Zero,
{
let (dim, _) = diag.data.shape();
let (dim, _) = diag.shape_generic();
let mut res = Self::zeros_generic(dim, dim);
for i in 0..diag.len() {
unsafe {
*res.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).inlined_clone();
*res.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone();
}
}
@ -377,12 +372,6 @@ where
*/
macro_rules! impl_constructors(
($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
/// Creates a new uninitialized matrix or vector.
#[inline]
pub unsafe fn new_uninitialized($($args: usize),*) -> mem::MaybeUninit<Self> {
Self::new_uninitialized_generic($($gargs),*)
}
/// Creates a matrix or vector with all its elements set to `elem`.
///
/// # Example
@ -888,19 +877,19 @@ macro_rules! transpose_array(
[$([$a]),*]
};
[$($a: ident),*; $($b: ident),*;] => {
[$([$a, $b]),*];
[$([$a, $b]),*]
};
[$($a: ident),*; $($b: ident),*; $($c: ident),*;] => {
[$([$a, $b, $c]),*];
[$([$a, $b, $c]),*]
};
[$($a: ident),*; $($b: ident),*; $($c: ident),*; $($d: ident),*;] => {
[$([$a, $b, $c, $d]),*];
[$([$a, $b, $c, $d]),*]
};
[$($a: ident),*; $($b: ident),*; $($c: ident),*; $($d: ident),*; $($e: ident),*;] => {
[$([$a, $b, $c, $d, $e]),*];
[$([$a, $b, $c, $d, $e]),*]
};
[$($a: ident),*; $($b: ident),*; $($c: ident),*; $($d: ident),*; $($e: ident),*; $($f: ident),*;] => {
[$([$a, $b, $c, $d, $e, $f]),*];
[$([$a, $b, $c, $d, $e, $f]),*]
};
);

View File

@ -14,7 +14,7 @@ use crate::base::dimension::{
Const, Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9,
};
use crate::base::iter::{MatrixIter, MatrixIterMut};
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut};
use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
use crate::base::{
ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixSlice,
MatrixSliceMut, OMatrix, Scalar,
@ -24,6 +24,7 @@ use crate::base::{DVector, VecStorage};
use crate::base::{SliceStorage, SliceStorageMut};
use crate::constraint::DimEq;
use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector};
use std::mem::MaybeUninit;
// TODO: too bad this won't work for slice conversions.
impl<T1, T2, R1, C1, R2, C2> SubsetOf<OMatrix<T2, R2, C2>> for OMatrix<T1, R1, C1>
@ -43,18 +44,20 @@ where
let (nrows, ncols) = self.shape();
let nrows2 = R2::from_usize(nrows);
let ncols2 = C2::from_usize(ncols);
let mut res = Matrix::uninit(nrows2, ncols2);
let mut res: OMatrix<T2, R2, C2> =
unsafe { crate::unimplemented_or_uninitialized_generic!(nrows2, ncols2) };
for i in 0..nrows {
for j in 0..ncols {
// Safety: all indices are in range.
unsafe {
*res.get_unchecked_mut((i, j)) = T2::from_subset(self.get_unchecked((i, j)))
*res.get_unchecked_mut((i, j)) =
MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j))));
}
}
}
res
// Safety: res is now fully initialized.
unsafe { res.assume_init() }
}
#[inline]
@ -67,21 +70,25 @@ where
let (nrows2, ncols2) = m.shape();
let nrows = R1::from_usize(nrows2);
let ncols = C1::from_usize(ncols2);
let mut res = Matrix::uninit(nrows, ncols);
let mut res: Self = unsafe { crate::unimplemented_or_uninitialized_generic!(nrows, ncols) };
for i in 0..nrows2 {
for j in 0..ncols2 {
// Safety: all indices are in range.
unsafe {
*res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked()
*res.get_unchecked_mut((i, j)) =
MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked())
}
}
}
res
unsafe { res.assume_init() }
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> IntoIterator for &'a Matrix<T, R, C, S> {
impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> IntoIterator
for &'a Matrix<T, R, C, S>
{
type Item = &'a T;
type IntoIter = MatrixIter<'a, T, R, C, S>;
@ -91,7 +98,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> IntoIterator for &'a Ma
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> IntoIterator
impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IntoIterator
for &'a mut Matrix<T, R, C, S>
{
type Item = &'a mut T;
@ -142,9 +149,10 @@ macro_rules! impl_from_into_asref_1D(
($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$(
impl<T, S> AsRef<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
where T: Scalar,
S: ContiguousStorage<T, $NRows, $NCols> {
S: RawStorage<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn as_ref(&self) -> &[T; $SZ] {
// Safety: this is OK thanks to the IsContiguous trait.
unsafe {
&*(self.data.ptr() as *const [T; $SZ])
}
@ -153,9 +161,10 @@ macro_rules! impl_from_into_asref_1D(
impl<T, S> AsMut<[T; $SZ]> for Matrix<T, $NRows, $NCols, S>
where T: Scalar,
S: ContiguousStorageMut<T, $NRows, $NCols> {
S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn as_mut(&mut self) -> &mut [T; $SZ] {
// Safety: this is OK thanks to the IsContiguous trait.
unsafe {
&mut *(self.data.ptr_mut() as *mut [T; $SZ])
}
@ -201,9 +210,10 @@ macro_rules! impl_from_into_asref_borrow_2D(
$Ref:ident.$ref:ident(), $Mut:ident.$mut:ident()
) => {
impl<T: Scalar, S> $Ref<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorage<T, $NRows, $NCols> {
where S: RawStorage<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn $ref(&self) -> &[[T; $SZRows]; $SZCols] {
// Safety: OK thanks to the IsContiguous trait.
unsafe {
&*(self.data.ptr() as *const [[T; $SZRows]; $SZCols])
}
@ -211,9 +221,10 @@ macro_rules! impl_from_into_asref_borrow_2D(
}
impl<T: Scalar, S> $Mut<[[T; $SZRows]; $SZCols]> for Matrix<T, $NRows, $NCols, S>
where S: ContiguousStorageMut<T, $NRows, $NCols> {
where S: RawStorageMut<T, $NRows, $NCols> + IsContiguous {
#[inline]
fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] {
// Safety: OK thanks to the IsContiguous trait.
unsafe {
&mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols])
}
@ -333,14 +344,14 @@ where
CSlice: Dim,
RStride: Dim,
CStride: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
ShapeConstraint: DimEq<R, RSlice>
+ DimEq<C, CSlice>
+ DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>,
{
fn from(m: &'a Matrix<T, R, C, S>) -> Self {
let (row, col) = m.data.shape();
let (row, col) = m.shape_generic();
let row_slice = RSlice::from_usize(row.value());
let col_slice = CSlice::from_usize(col.value());
@ -370,14 +381,14 @@ where
CSlice: Dim,
RStride: Dim,
CStride: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
ShapeConstraint: DimEq<R, RSlice>
+ DimEq<C, CSlice>
+ DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>,
{
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
let (row, col) = m.data.shape();
let (row, col) = m.shape_generic();
let row_slice = RSlice::from_usize(row.value());
let col_slice = CSlice::from_usize(col.value());
@ -407,14 +418,14 @@ where
CSlice: Dim,
RStride: Dim,
CStride: Dim,
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
ShapeConstraint: DimEq<R, RSlice>
+ DimEq<C, CSlice>
+ DimEq<RStride, S::RStride>
+ DimEq<CStride, S::CStride>,
{
fn from(m: &'a mut Matrix<T, R, C, S>) -> Self {
let (row, col) = m.data.shape();
let (row, col) = m.shape_generic();
let row_slice = RSlice::from_usize(row.value());
let col_slice = CSlice::from_usize(col.value());
@ -442,7 +453,7 @@ impl<'a, T: Scalar> From<Vec<T>> for DVector<T> {
}
}
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>>
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorage<T, R, C> + IsContiguous>
From<&'a Matrix<T, R, C, S>> for &'a [T]
{
#[inline]
@ -451,7 +462,7 @@ impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorage<T, R, C>>
}
}
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorageMut<T, R, C>>
impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut<T, R, C> + IsContiguous>
From<&'a mut Matrix<T, R, C, S>> for &'a mut [T]
{
#[inline]
@ -495,14 +506,10 @@ where
{
#[inline]
fn from(arr: [OMatrix<T::Element, R, C>; 2]) -> Self {
let (nrows, ncols) = arr[0].data.shape();
let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| {
[
arr[0][(i, j)].inlined_clone(),
arr[1][(i, j)].inlined_clone(),
]
.into()
[arr[0][(i, j)].clone(), arr[1][(i, j)].clone()].into()
})
}
}
@ -516,14 +523,14 @@ where
{
#[inline]
fn from(arr: [OMatrix<T::Element, R, C>; 4]) -> Self {
let (nrows, ncols) = arr[0].data.shape();
let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| {
[
arr[0][(i, j)].inlined_clone(),
arr[1][(i, j)].inlined_clone(),
arr[2][(i, j)].inlined_clone(),
arr[3][(i, j)].inlined_clone(),
arr[0][(i, j)].clone(),
arr[1][(i, j)].clone(),
arr[2][(i, j)].clone(),
arr[3][(i, j)].clone(),
]
.into()
})
@ -539,18 +546,18 @@ where
{
#[inline]
fn from(arr: [OMatrix<T::Element, R, C>; 8]) -> Self {
let (nrows, ncols) = arr[0].data.shape();
let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| {
[
arr[0][(i, j)].inlined_clone(),
arr[1][(i, j)].inlined_clone(),
arr[2][(i, j)].inlined_clone(),
arr[3][(i, j)].inlined_clone(),
arr[4][(i, j)].inlined_clone(),
arr[5][(i, j)].inlined_clone(),
arr[6][(i, j)].inlined_clone(),
arr[7][(i, j)].inlined_clone(),
arr[0][(i, j)].clone(),
arr[1][(i, j)].clone(),
arr[2][(i, j)].clone(),
arr[3][(i, j)].clone(),
arr[4][(i, j)].clone(),
arr[5][(i, j)].clone(),
arr[6][(i, j)].clone(),
arr[7][(i, j)].clone(),
]
.into()
})
@ -565,26 +572,26 @@ where
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{
fn from(arr: [OMatrix<T::Element, R, C>; 16]) -> Self {
let (nrows, ncols) = arr[0].data.shape();
let (nrows, ncols) = arr[0].shape_generic();
Self::from_fn_generic(nrows, ncols, |i, j| {
[
arr[0][(i, j)].inlined_clone(),
arr[1][(i, j)].inlined_clone(),
arr[2][(i, j)].inlined_clone(),
arr[3][(i, j)].inlined_clone(),
arr[4][(i, j)].inlined_clone(),
arr[5][(i, j)].inlined_clone(),
arr[6][(i, j)].inlined_clone(),
arr[7][(i, j)].inlined_clone(),
arr[8][(i, j)].inlined_clone(),
arr[9][(i, j)].inlined_clone(),
arr[10][(i, j)].inlined_clone(),
arr[11][(i, j)].inlined_clone(),
arr[12][(i, j)].inlined_clone(),
arr[13][(i, j)].inlined_clone(),
arr[14][(i, j)].inlined_clone(),
arr[15][(i, j)].inlined_clone(),
arr[0][(i, j)].clone(),
arr[1][(i, j)].clone(),
arr[2][(i, j)].clone(),
arr[3][(i, j)].clone(),
arr[4][(i, j)].clone(),
arr[5][(i, j)].clone(),
arr[6][(i, j)].clone(),
arr[7][(i, j)].clone(),
arr[8][(i, j)].clone(),
arr[9][(i, j)].clone(),
arr[10][(i, j)].clone(),
arr[11][(i, j)].clone(),
arr[12][(i, j)].clone(),
arr[13][(i, j)].clone(),
arr[14][(i, j)].clone(),
arr[15][(i, j)].clone(),
]
.into()
})

View File

@ -7,7 +7,7 @@
use std::ops::{Deref, DerefMut};
use crate::base::dimension::{U1, U2, U3, U4, U5, U6};
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut};
use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut};
use crate::base::{Matrix, Scalar};
/*
@ -32,19 +32,21 @@ macro_rules! coords_impl(
macro_rules! deref_impl(
($R: ty, $C: ty; $Target: ident) => {
impl<T: Scalar, S> Deref for Matrix<T, $R, $C, S>
where S: ContiguousStorage<T, $R, $C> {
where S: RawStorage<T, $R, $C> + IsContiguous {
type Target = $Target<T>;
#[inline]
fn deref(&self) -> &Self::Target {
// Safety: this is OK because of the IsContiguous trait.
unsafe { &*(self.data.ptr() as *const Self::Target) }
}
}
impl<T: Scalar, S> DerefMut for Matrix<T, $R, $C, S>
where S: ContiguousStorageMut<T, $R, $C> {
where S: RawStorageMut<T, $R, $C> + IsContiguous {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
// Safety: this is OK because of the IsContiguous trait.
unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) }
}
}

View File

@ -4,7 +4,6 @@
//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
use std::cmp;
use std::mem;
use std::ptr;
#[cfg(all(feature = "alloc", not(feature = "std")))]
@ -16,10 +15,11 @@ use crate::base::array_storage::ArrayStorage;
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::base::dimension::Dynamic;
use crate::base::dimension::{Dim, DimName};
use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut};
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};
/*
*
@ -28,6 +28,7 @@ use crate::base::Scalar;
*/
/// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized
/// matrices respectively.
#[derive(Copy, Clone, Debug)]
pub struct DefaultAllocator;
// Static - Static
@ -35,10 +36,23 @@ impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
for DefaultAllocator
{
type Buffer = ArrayStorage<T, R, C>;
type BufferUninit = ArrayStorage<MaybeUninit<T>, R, C>;
#[inline]
unsafe fn allocate_uninitialized(_: Const<R>, _: Const<C>) -> mem::MaybeUninit<Self::Buffer> {
mem::MaybeUninit::<Self::Buffer>::uninit()
#[inline(always)]
fn allocate_uninit(_: Const<R>, _: Const<C>) -> ArrayStorage<MaybeUninit<T>, R, C> {
// SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
let array: [[MaybeUninit<T>; R]; C] = unsafe { MaybeUninit::uninit().assume_init() };
ArrayStorage(array)
}
#[inline(always)]
unsafe fn assume_init(uninit: ArrayStorage<MaybeUninit<T>, R, C>) -> ArrayStorage<T, R, C> {
// Safety:
// * The caller guarantees that all elements of the array are initialized
// * `MaybeUninit<T>` and T are guaranteed to have the same layout
// * `MaybeUninit` does not drop, so there are no double-frees
// And thus the conversion is safe
ArrayStorage((&uninit as *const _ as *const [_; C]).read())
}
#[inline]
@ -47,14 +61,13 @@ impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
ncols: Const<C>,
iter: I,
) -> Self::Buffer {
#[cfg(feature = "no_unsound_assume_init")]
let mut res: Self::Buffer = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols).assume_init() };
let mut res = Self::allocate_uninit(nrows, ncols);
let mut count = 0;
for (res, e) in res.as_mut_slice().iter_mut().zip(iter.into_iter()) {
*res = e;
// Safety: conversion to a slice is OK because the Buffer is known to be contiguous.
let res_slice = unsafe { res.as_mut_slice_unchecked() };
for (res, e) in res_slice.iter_mut().zip(iter.into_iter()) {
*res = MaybeUninit::new(e);
count += 1;
}
@ -63,7 +76,9 @@ impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
"Matrix init. from iterator: iterator not long enough."
);
res
// Safety: the assertion above made sure that the iterator
// yielded enough elements to initialize our matrix.
unsafe { <Self as Allocator<T, Const<R>, Const<C>>>::assume_init(res) }
}
}
@ -72,15 +87,32 @@ impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Scalar, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
type Buffer = VecStorage<T, Dynamic, C>;
type BufferUninit = VecStorage<MaybeUninit<T>, Dynamic, C>;
#[inline]
unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> mem::MaybeUninit<Self::Buffer> {
let mut res = Vec::new();
fn allocate_uninit(nrows: Dynamic, ncols: C) -> VecStorage<MaybeUninit<T>, Dynamic, C> {
let mut data = Vec::new();
let length = nrows.value() * ncols.value();
res.reserve_exact(length);
res.set_len(length);
data.reserve_exact(length);
data.resize_with(length, MaybeUninit::uninit);
VecStorage::new(nrows, ncols, data)
}
mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
#[inline]
unsafe fn assume_init(
uninit: VecStorage<MaybeUninit<T>, Dynamic, C>,
) -> VecStorage<T, Dynamic, C> {
// Avoids a double-drop.
let (nrows, ncols) = uninit.shape();
let vec: Vec<_> = uninit.into();
let mut md = ManuallyDrop::new(vec);
// Safety:
// - MaybeUninit<T> has the same alignment and layout as T.
// - The length and capacity come from a valid vector.
let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity());
VecStorage::new(nrows, ncols, new_data)
}
#[inline]
@ -102,15 +134,33 @@ impl<T: Scalar, C: Dim> Allocator<T, Dynamic, C> for DefaultAllocator {
#[cfg(any(feature = "std", feature = "alloc"))]
impl<T: Scalar, R: DimName> Allocator<T, R, Dynamic> for DefaultAllocator {
type Buffer = VecStorage<T, R, Dynamic>;
type BufferUninit = VecStorage<MaybeUninit<T>, R, Dynamic>;
#[inline]
unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> mem::MaybeUninit<Self::Buffer> {
let mut res = Vec::new();
fn allocate_uninit(nrows: R, ncols: Dynamic) -> VecStorage<MaybeUninit<T>, R, Dynamic> {
let mut data = Vec::new();
let length = nrows.value() * ncols.value();
res.reserve_exact(length);
res.set_len(length);
data.reserve_exact(length);
data.resize_with(length, MaybeUninit::uninit);
mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res))
VecStorage::new(nrows, ncols, data)
}
#[inline]
unsafe fn assume_init(
uninit: VecStorage<MaybeUninit<T>, R, Dynamic>,
) -> VecStorage<T, R, Dynamic> {
// Avoids a double-drop.
let (nrows, ncols) = uninit.shape();
let vec: Vec<_> = uninit.into();
let mut md = ManuallyDrop::new(vec);
// Safety:
// - MaybeUninit<T> has the same alignment and layout as T.
// - The length and capacity come from a valid vector.
let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity());
VecStorage::new(nrows, ncols, new_data)
}
#[inline]
@ -145,20 +195,21 @@ where
unsafe fn reallocate_copy(
rto: Const<RTO>,
cto: Const<CTO>,
buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> ArrayStorage<T, RTO, CTO> {
#[cfg(feature = "no_unsound_assume_init")]
let mut res: ArrayStorage<T, RTO, CTO> = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res =
<Self as Allocator<T, Const<RTO>, Const<CTO>>>::allocate_uninitialized(rto, cto)
.assume_init();
mut buf: <Self as Allocator<T, RFrom, CFrom>>::Buffer,
) -> ArrayStorage<MaybeUninit<T>, RTO, CTO> {
let mut res = <Self as Allocator<T, Const<RTO>, Const<CTO>>>::allocate_uninit(rto, cto);
let (rfrom, cfrom) = buf.shape();
let len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
let len_copied = cmp::min(len_from, len_to);
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied);
// Safety:
// - We dont care about dropping elements because the caller is responsible for dropping things.
// - We forget `buf` so that we dont drop the other elements.
std::mem::forget(buf);
res
}
@ -175,19 +226,21 @@ where
unsafe fn reallocate_copy(
rto: Dynamic,
cto: CTo,
buf: ArrayStorage<T, RFROM, CFROM>,
) -> VecStorage<T, Dynamic, CTo> {
#[cfg(feature = "no_unsound_assume_init")]
let mut res: VecStorage<T, Dynamic, CTo> = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res =
<Self as Allocator<T, Dynamic, CTo>>::allocate_uninitialized(rto, cto).assume_init();
mut buf: ArrayStorage<T, RFROM, CFROM>,
) -> VecStorage<MaybeUninit<T>, Dynamic, CTo> {
let mut res = <Self as Allocator<T, Dynamic, CTo>>::allocate_uninit(rto, cto);
let (rfrom, cfrom) = buf.shape();
let len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
let len_copied = cmp::min(len_from, len_to);
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied);
// Safety:
// - We dont care about dropping elements because the caller is responsible for dropping things.
// - We forget `buf` so that we dont drop the other elements.
std::mem::forget(buf);
res
}
@ -204,19 +257,21 @@ where
unsafe fn reallocate_copy(
rto: RTo,
cto: Dynamic,
buf: ArrayStorage<T, RFROM, CFROM>,
) -> VecStorage<T, RTo, Dynamic> {
#[cfg(feature = "no_unsound_assume_init")]
let mut res: VecStorage<T, RTo, Dynamic> = unimplemented!();
#[cfg(not(feature = "no_unsound_assume_init"))]
let mut res =
<Self as Allocator<T, RTo, Dynamic>>::allocate_uninitialized(rto, cto).assume_init();
mut buf: ArrayStorage<T, RFROM, CFROM>,
) -> VecStorage<MaybeUninit<T>, RTo, Dynamic> {
let mut res = <Self as Allocator<T, RTo, Dynamic>>::allocate_uninit(rto, cto);
let (rfrom, cfrom) = buf.shape();
let len_from = rfrom.value() * cfrom.value();
let len_to = rto.value() * cto.value();
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to));
let len_copied = cmp::min(len_from, len_to);
ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied);
// Safety:
// - We dont care about dropping elements because the caller is responsible for dropping things.
// - We forget `buf` so that we dont drop the other elements.
std::mem::forget(buf);
res
}
@ -232,7 +287,7 @@ impl<T: Scalar, CFrom: Dim, CTo: Dim> Reallocator<T, Dynamic, CFrom, Dynamic, CT
rto: Dynamic,
cto: CTo,
buf: VecStorage<T, Dynamic, CFrom>,
) -> VecStorage<T, Dynamic, CTo> {
) -> VecStorage<MaybeUninit<T>, Dynamic, CTo> {
let new_buf = buf.resize(rto.value() * cto.value());
VecStorage::new(rto, cto, new_buf)
}
@ -247,7 +302,7 @@ impl<T: Scalar, CFrom: Dim, RTo: DimName> Reallocator<T, Dynamic, CFrom, RTo, Dy
rto: RTo,
cto: Dynamic,
buf: VecStorage<T, Dynamic, CFrom>,
) -> VecStorage<T, RTo, Dynamic> {
) -> VecStorage<MaybeUninit<T>, RTo, Dynamic> {
let new_buf = buf.resize(rto.value() * cto.value());
VecStorage::new(rto, cto, new_buf)
}
@ -262,7 +317,7 @@ impl<T: Scalar, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dynamic, Dynamic
rto: Dynamic,
cto: CTo,
buf: VecStorage<T, RFrom, Dynamic>,
) -> VecStorage<T, Dynamic, CTo> {
) -> VecStorage<MaybeUninit<T>, Dynamic, CTo> {
let new_buf = buf.resize(rto.value() * cto.value());
VecStorage::new(rto, cto, new_buf)
}
@ -277,7 +332,7 @@ impl<T: Scalar, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dynamic, RTo
rto: RTo,
cto: Dynamic,
buf: VecStorage<T, RFrom, Dynamic>,
) -> VecStorage<T, RTo, Dynamic> {
) -> VecStorage<MaybeUninit<T>, RTo, Dynamic> {
let new_buf = buf.resize(rto.value() * cto.value());
VecStorage::new(rto, cto, new_buf)
}

View File

@ -2,8 +2,6 @@ use num::{One, Zero};
use std::cmp;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::iter::ExactSizeIterator;
#[cfg(any(feature = "std", feature = "alloc"))]
use std::mem;
use std::ptr;
use crate::base::allocator::{Allocator, Reallocator};
@ -11,8 +9,10 @@ use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, Shap
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::base::dimension::Dynamic;
use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1};
use crate::base::storage::{ContiguousStorageMut, ReshapableStorage, Storage, StorageMut};
use crate::base::storage::{RawStorage, RawStorageMut, ReshapableStorage};
use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector};
use crate::{Storage, UninitMatrix};
use std::mem::MaybeUninit;
/// # Rows and columns extraction
impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
@ -52,10 +52,8 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, Dynamic, C>,
{
let irows = irows.into_iter();
let ncols = self.data.shape().1;
let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!(Dynamic::new(irows.len()), ncols)
};
let ncols = self.shape_generic().1;
let mut res = Matrix::uninit(Dynamic::new(irows.len()), ncols);
// First, check that all the indices from irows are valid.
// This will allow us to use unchecked access in the inner loop.
@ -69,14 +67,16 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
let src = self.column(j);
for (destination, source) in irows.clone().enumerate() {
// Safety: all indices are in range.
unsafe {
*res.vget_unchecked_mut(destination) =
src.vget_unchecked(*source).inlined_clone()
MaybeUninit::new(src.vget_unchecked(*source).clone());
}
}
}
res
// Safety: res is now fully initialized.
unsafe { res.assume_init() }
}
/// Creates a new matrix by extracting the given set of columns from `self`.
@ -89,27 +89,30 @@ impl<T: Scalar + Zero, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, R, Dynamic>,
{
let icols = icols.into_iter();
let nrows = self.data.shape().0;
let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!(nrows, Dynamic::new(icols.len()))
};
let nrows = self.shape_generic().0;
let mut res = Matrix::uninit(nrows, Dynamic::new(icols.len()));
for (destination, source) in icols.enumerate() {
res.column_mut(destination).copy_from(&self.column(*source))
// NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit.
res.column_mut(destination)
.zip_apply(&self.column(*source), |out, e| {
*out = MaybeUninit::new(e.clone())
});
}
res
// Safety: res is now fully initialized.
unsafe { res.assume_init() }
}
}
/// # Set rows, columns, and diagonal
impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Fills the diagonal of this matrix with the content of the given vector.
#[inline]
pub fn set_diagonal<R2: Dim, S2>(&mut self, diag: &Vector<T, R2, S2>)
where
R: DimMin<C>,
S2: Storage<T, R2>,
S2: RawStorage<T, R2>,
ShapeConstraint: DimEq<DimMinimum<R, C>, R2>,
{
let (nrows, ncols) = self.shape();
@ -117,7 +120,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions.");
for i in 0..min_nrows_ncols {
unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).inlined_clone() }
unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone() }
}
}
@ -140,7 +143,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline]
pub fn set_row<C2: Dim, S2>(&mut self, i: usize, row: &RowVector<T, C2, S2>)
where
S2: Storage<T, U1, C2>,
S2: RawStorage<T, U1, C2>,
ShapeConstraint: SameNumberOfColumns<C, C2>,
{
self.row_mut(i).copy_from(row);
@ -150,7 +153,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline]
pub fn set_column<R2: Dim, S2>(&mut self, i: usize, column: &Vector<T, R2, S2>)
where
S2: Storage<T, R2, U1>,
S2: RawStorage<T, R2, U1>,
ShapeConstraint: SameNumberOfRows<R, R2>,
{
self.column_mut(i).copy_from(column);
@ -158,12 +161,23 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
}
/// # In-place filling
impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Sets all the elements of this matrix to the value returned by the closure.
#[inline]
pub fn fill_with(&mut self, val: impl Fn() -> T) {
for e in self.iter_mut() {
*e = val()
}
}
/// Sets all the elements of this matrix to `val`.
#[inline]
pub fn fill(&mut self, val: T) {
pub fn fill(&mut self, val: T)
where
T: Scalar,
{
for e in self.iter_mut() {
*e = val.inlined_clone()
*e = val.clone()
}
}
@ -171,7 +185,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
#[inline]
pub fn fill_with_identity(&mut self)
where
T: Zero + One,
T: Scalar + Zero + One,
{
self.fill(T::zero());
self.fill_diagonal(T::one());
@ -179,30 +193,39 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Sets all the diagonal elements of this matrix to `val`.
#[inline]
pub fn fill_diagonal(&mut self, val: T) {
pub fn fill_diagonal(&mut self, val: T)
where
T: Scalar,
{
let (nrows, ncols) = self.shape();
let n = cmp::min(nrows, ncols);
for i in 0..n {
unsafe { *self.get_unchecked_mut((i, i)) = val.inlined_clone() }
unsafe { *self.get_unchecked_mut((i, i)) = val.clone() }
}
}
/// Sets all the elements of the selected row to `val`.
#[inline]
pub fn fill_row(&mut self, i: usize, val: T) {
pub fn fill_row(&mut self, i: usize, val: T)
where
T: Scalar,
{
assert!(i < self.nrows(), "Row index out of bounds.");
for j in 0..self.ncols() {
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
}
}
/// Sets all the elements of the selected column to `val`.
#[inline]
pub fn fill_column(&mut self, j: usize, val: T) {
pub fn fill_column(&mut self, j: usize, val: T)
where
T: Scalar,
{
assert!(j < self.ncols(), "Row index out of bounds.");
for i in 0..self.nrows() {
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
}
}
@ -214,10 +237,13 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
/// * If `shift > 1`, then the diagonal and the first `shift - 1` subdiagonals are left
/// untouched.
#[inline]
pub fn fill_lower_triangle(&mut self, val: T, shift: usize) {
pub fn fill_lower_triangle(&mut self, val: T, shift: usize)
where
T: Scalar,
{
for j in 0..self.ncols() {
for i in (j + shift)..self.nrows() {
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
}
}
}
@ -230,18 +256,21 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
/// * If `shift > 1`, then the diagonal and the first `shift - 1` superdiagonals are left
/// untouched.
#[inline]
pub fn fill_upper_triangle(&mut self, val: T, shift: usize) {
pub fn fill_upper_triangle(&mut self, val: T, shift: usize)
where
T: Scalar,
{
for j in shift..self.ncols() {
// TODO: is there a more efficient way to avoid the min ?
// (necessary for rectangular matrices)
for i in 0..cmp::min(j + 1 - shift, self.nrows()) {
unsafe { *self.get_unchecked_mut((i, j)) = val.inlined_clone() }
unsafe { *self.get_unchecked_mut((i, j)) = val.clone() }
}
}
}
}
impl<T: Scalar, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
impl<T: Scalar, D: Dim, S: RawStorageMut<T, D, D>> Matrix<T, D, D, S> {
/// Copies the upper-triangle of this matrix to its lower-triangular part.
///
/// This makes the matrix symmetric. Panics if the matrix is not square.
@ -252,7 +281,7 @@ impl<T: Scalar, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
for j in 0..dim {
for i in j + 1..dim {
unsafe {
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).inlined_clone();
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone();
}
}
}
@ -267,7 +296,7 @@ impl<T: Scalar, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
for j in 1..self.ncols() {
for i in 0..j {
unsafe {
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).inlined_clone();
*self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone();
}
}
}
@ -275,7 +304,7 @@ impl<T: Scalar, D: Dim, S: StorageMut<T, D, D>> Matrix<T, D, D, S> {
}
/// # In-place swapping
impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// Swaps two rows in-place.
#[inline]
pub fn swap_rows(&mut self, irow1: usize, irow2: usize) {
@ -335,29 +364,46 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
{
let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let mut offset: usize = 0;
let mut target: usize = 0;
while offset + target < ncols.value() {
if indices.contains(&(target + offset)) {
// Safety: the resulting pointer is within range.
let col_ptr = unsafe { m.data.ptr_mut().add((target + offset) * nrows.value()) };
// Drop every element in the column we are about to overwrite.
// We use the a similar technique as in `Vec::truncate`.
let s = ptr::slice_from_raw_parts_mut(col_ptr, nrows.value());
// Safety: we drop the column in-place, which is OK because we will overwrite these
// entries later in the loop, or discard them with the `reallocate_copy`
// afterwards.
unsafe { ptr::drop_in_place(s) };
offset += 1;
} else {
unsafe {
let ptr_source = m.data.ptr().add((target + offset) * nrows.value());
let ptr_target = m.data.ptr_mut().add(target * nrows.value());
// Copy the data, overwriting what we dropped.
ptr::copy(ptr_source, ptr_target, nrows.value());
target += 1;
}
}
}
// Safety: The new size is smaller than the old size, so
// DefaultAllocator::reallocate_copy will initialize
// every element of the new matrix which can then
// be assumed to be initialized.
unsafe {
Matrix::from_data(DefaultAllocator::reallocate_copy(
let new_data = DefaultAllocator::reallocate_copy(
nrows,
ncols.sub(Dynamic::from_usize(offset)),
m.data,
))
);
Matrix::from_data(new_data).assume_init()
}
}
@ -369,29 +415,44 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
{
let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let mut offset: usize = 0;
let mut target: usize = 0;
while offset + target < nrows.value() * ncols.value() {
if indices.contains(&((target + offset) % nrows.value())) {
// Safety: the resulting pointer is within range.
unsafe {
let elt_ptr = m.data.ptr_mut().add(target + offset);
// Safety: we drop the component in-place, which is OK because we will overwrite these
// entries later in the loop, or discard them with the `reallocate_copy`
// afterwards.
ptr::drop_in_place(elt_ptr)
};
offset += 1;
} else {
unsafe {
let ptr_source = m.data.ptr().add(target + offset);
let ptr_target = m.data.ptr_mut().add(target);
// Copy the data, overwriting what we dropped in the previous iterations.
ptr::copy(ptr_source, ptr_target, 1);
target += 1;
}
}
}
// Safety: The new size is smaller than the old size, so
// DefaultAllocator::reallocate_copy will initialize
// every element of the new matrix which can then
// be assumed to be initialized.
unsafe {
Matrix::from_data(DefaultAllocator::reallocate_copy(
let new_data = DefaultAllocator::reallocate_copy(
nrows.sub(Dynamic::from_usize(offset / ncols.value())),
ncols,
m.data,
))
);
Matrix::from_data(new_data).assume_init()
}
}
@ -432,13 +493,14 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, DimDiff<C, D>>,
{
let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
assert!(
i + nremove.value() <= ncols.value(),
"Column index out of range."
);
if nremove.value() != 0 && i + nremove.value() < ncols.value() {
let need_column_shifts = nremove.value() != 0 && i + nremove.value() < ncols.value();
if need_column_shifts {
// The first `deleted_i * nrows` are left untouched.
let copied_value_start = i + nremove.value();
@ -446,20 +508,35 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
let ptr_in = m.data.ptr().add(copied_value_start * nrows.value());
let ptr_out = m.data.ptr_mut().add(i * nrows.value());
// Drop all the elements of the columns we are about to overwrite.
// We use the a similar technique as in `Vec::truncate`.
let s = ptr::slice_from_raw_parts_mut(ptr_out, nremove.value() * nrows.value());
// Safety: we drop the column in-place, which is OK because we will overwrite these
// entries with `ptr::copy` afterward.
ptr::drop_in_place(s);
ptr::copy(
ptr_in,
ptr_out,
(ncols.value() - copied_value_start) * nrows.value(),
);
}
} else {
// All the columns to remove are at the end of the buffer. Drop them.
unsafe {
let ptr = m.data.ptr_mut().add(i * nrows.value());
let s = ptr::slice_from_raw_parts_mut(ptr, nremove.value() * nrows.value());
ptr::drop_in_place(s)
};
}
// Safety: The new size is smaller than the old size, so
// DefaultAllocator::reallocate_copy will initialize
// every element of the new matrix which can then
// be assumed to be initialized.
unsafe {
Matrix::from_data(DefaultAllocator::reallocate_copy(
nrows,
ncols.sub(nremove),
m.data,
))
let new_data = DefaultAllocator::reallocate_copy(nrows, ncols.sub(nremove), m.data);
Matrix::from_data(new_data).assume_init()
}
}
@ -511,7 +588,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, DimDiff<R, D>, C>,
{
let mut m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
assert!(
i + nremove.value() <= nrows.value(),
"Row index out of range."
@ -520,7 +597,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
if nremove.value() != 0 {
unsafe {
compress_rows(
&mut m.data.as_mut_slice(),
&mut m.as_mut_slice(),
nrows.value(),
ncols.value(),
i,
@ -529,12 +606,13 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
}
}
// Safety: The new size is smaller than the old size, so
// DefaultAllocator::reallocate_copy will initialize
// every element of the new matrix which can then
// be assumed to be initialized.
unsafe {
Matrix::from_data(DefaultAllocator::reallocate_copy(
nrows.sub(nremove),
ncols,
m.data,
))
let new_data = DefaultAllocator::reallocate_copy(nrows.sub(nremove), ncols, m.data);
Matrix::from_data(new_data).assume_init()
}
}
}
@ -568,8 +646,13 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, Const<D>>>,
{
let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Const::<D>) };
res.fixed_columns_mut::<D>(i).fill(val);
res
res.fixed_columns_mut::<D>(i)
.fill_with(|| MaybeUninit::new(val.clone()));
// Safety: the result is now fully initialized. The added columns have
// been initialized by the `fill_with` above, and the rest have
// been initialized by `insert_columns_generic_uninitialized`.
unsafe { res.assume_init() }
}
/// Inserts `n` columns filled with `val` starting at the `i-th` position.
@ -581,27 +664,33 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
{
let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dynamic::new(n)) };
res.columns_mut(i, n).fill(val);
res
res.columns_mut(i, n)
.fill_with(|| MaybeUninit::new(val.clone()));
// Safety: the result is now fully initialized. The added columns have
// been initialized by the `fill_with` above, and the rest have
// been initialized by `insert_columns_generic_uninitialized`.
unsafe { res.assume_init() }
}
/// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix.
///
/// # Safety
/// The added column values are not initialized.
/// The output matrix has all its elements initialized except for the the components of the
/// added columns.
#[inline]
pub unsafe fn insert_columns_generic_uninitialized<D>(
self,
i: usize,
ninsert: D,
) -> OMatrix<T, R, DimSum<C, D>>
) -> UninitMatrix<T, R, DimSum<C, D>>
where
D: Dim,
C: DimAdd<D>,
DefaultAllocator: Reallocator<T, R, C, R, DimSum<C, D>>,
{
let m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
nrows,
ncols.add(ninsert),
@ -650,8 +739,13 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, DimSum<R, Const<D>>, C>,
{
let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Const::<D>) };
res.fixed_rows_mut::<D>(i).fill(val);
res
res.fixed_rows_mut::<D>(i)
.fill_with(|| MaybeUninit::new(val.clone()));
// Safety: the result is now fully initialized. The added rows have
// been initialized by the `fill_with` above, and the rest have
// been initialized by `insert_rows_generic_uninitialized`.
unsafe { res.assume_init() }
}
/// Inserts `n` rows filled with `val` starting at the `i-th` position.
@ -663,8 +757,13 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
{
let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dynamic::new(n)) };
res.rows_mut(i, n).fill(val);
res
res.rows_mut(i, n)
.fill_with(|| MaybeUninit::new(val.clone()));
// Safety: the result is now fully initialized. The added rows have
// been initialized by the `fill_with` above, and the rest have
// been initialized by `insert_rows_generic_uninitialized`.
unsafe { res.assume_init() }
}
/// Inserts `ninsert.value()` rows at the `i-th` place of this matrix.
@ -678,14 +777,14 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
self,
i: usize,
ninsert: D,
) -> OMatrix<T, DimSum<R, D>, C>
) -> UninitMatrix<T, DimSum<R, D>, C>
where
D: Dim,
R: DimAdd<D>,
DefaultAllocator: Reallocator<T, R, C, DimSum<R, D>, C>,
{
let m = self.into_owned();
let (nrows, ncols) = m.data.shape();
let (nrows, ncols) = m.shape_generic();
let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy(
nrows.add(ninsert),
ncols,
@ -696,7 +795,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
if ninsert.value() != 0 {
extend_rows(
&mut res.data.as_mut_slice(),
&mut res.as_mut_slice(),
nrows.value(),
ncols.value(),
i,
@ -731,7 +830,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where
DefaultAllocator: Reallocator<T, R, C, Dynamic, C>,
{
let ncols = self.data.shape().1;
let ncols = self.shape_generic().1;
self.resize_generic(Dynamic::new(new_nrows), ncols, val)
}
@ -744,7 +843,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where
DefaultAllocator: Reallocator<T, R, C, R, Dynamic>,
{
let nrows = self.data.shape().0;
let nrows = self.shape_generic().0;
self.resize_generic(nrows, Dynamic::new(new_ncols), val)
}
@ -777,16 +876,32 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Reallocator<T, R, C, R2, C2>,
{
let (nrows, ncols) = self.shape();
let mut data = self.data.into_owned();
let mut data = self.into_owned();
if new_nrows.value() == nrows {
let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data) };
let mut res = Matrix::from_data(res);
if new_ncols.value() > ncols {
res.columns_range_mut(ncols..).fill(val);
if new_ncols.value() < ncols {
unsafe {
let num_cols_to_delete = ncols - new_ncols.value();
let col_ptr = data.data.ptr_mut().add(new_ncols.value() * nrows);
let s = ptr::slice_from_raw_parts_mut(col_ptr, num_cols_to_delete * nrows);
// Safety: drop the elements of the deleted columns.
// these are the elements that will be truncated
// by the `reallocate_copy` afterward.
ptr::drop_in_place(s)
};
}
res
let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.data) };
let mut res = Matrix::from_data(res);
if new_ncols.value() > ncols {
res.columns_range_mut(ncols..)
.fill_with(|| MaybeUninit::new(val.clone()));
}
// Safety: the result is now fully initialized by `reallocate_copy` and
// `fill_with` (if the output has more columns than the input).
unsafe { res.assume_init() }
} else {
let mut res;
@ -800,14 +915,14 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
nrows - new_nrows.value(),
);
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
new_nrows, new_ncols, data,
new_nrows, new_ncols, data.data,
));
} else {
res = Matrix::from_data(DefaultAllocator::reallocate_copy(
new_nrows, new_ncols, data,
new_nrows, new_ncols, data.data,
));
extend_rows(
&mut res.data.as_mut_slice(),
&mut res.as_mut_slice(),
nrows,
new_ncols.value(),
nrows,
@ -817,15 +932,18 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
}
if new_ncols.value() > ncols {
res.columns_range_mut(ncols..).fill(val.inlined_clone());
res.columns_range_mut(ncols..)
.fill_with(|| MaybeUninit::new(val.clone()));
}
if new_nrows.value() > nrows {
res.slice_range_mut(nrows.., ..cmp::min(ncols, new_ncols.value()))
.fill(val);
.fill_with(|| MaybeUninit::new(val.clone()));
}
res
// Safety: the result is now fully initialized by `reallocate_copy` and
// `fill_with` (whenever applicable).
unsafe { res.assume_init() }
}
}
@ -910,12 +1028,8 @@ impl<T: Scalar> OMatrix<T, Dynamic, Dynamic> {
where
DefaultAllocator: Reallocator<T, Dynamic, Dynamic, Dynamic, Dynamic>,
{
let placeholder = unsafe {
crate::unimplemented_or_uninitialized_generic!(Dynamic::new(0), Dynamic::new(0))
};
let old = mem::replace(self, placeholder);
let new = old.resize(new_nrows, new_ncols, val);
let _ = mem::replace(self, new);
// TODO: avoid the clone.
*self = self.clone().resize(new_nrows, new_ncols, val);
}
}
@ -935,12 +1049,8 @@ where
where
DefaultAllocator: Reallocator<T, Dynamic, C, Dynamic, C>,
{
let placeholder = unsafe {
crate::unimplemented_or_uninitialized_generic!(Dynamic::new(0), self.data.shape().1)
};
let old = mem::replace(self, placeholder);
let new = old.resize_vertically(new_nrows, val);
let _ = mem::replace(self, new);
// TODO: avoid the clone.
*self = self.clone().resize_vertically(new_nrows, val);
}
}
@ -960,15 +1070,15 @@ where
where
DefaultAllocator: Reallocator<T, R, Dynamic, R, Dynamic>,
{
let placeholder = unsafe {
crate::unimplemented_or_uninitialized_generic!(self.data.shape().0, Dynamic::new(0))
};
let old = mem::replace(self, placeholder);
let new = old.resize_horizontally(new_ncols, val);
let _ = mem::replace(self, new);
// TODO: avoid the clone.
*self = self.clone().resize_horizontally(new_ncols, val);
}
}
// Move the elements of `data` in such a way that the matrix with
// the rows `[i, i + nremove[` deleted is represented in a contigous
// way in `data` after this method completes.
// Every deleted element are manually dropped by this method.
unsafe fn compress_rows<T: Scalar>(
data: &mut [T],
nrows: usize,
@ -978,16 +1088,28 @@ unsafe fn compress_rows<T: Scalar>(
) {
let new_nrows = nrows - nremove;
if new_nrows == 0 || ncols == 0 {
return; // Nothing to do as the output matrix is empty.
if nremove == 0 {
return; // Nothing to remove or drop.
}
if new_nrows == 0 || ncols == 0 {
// The output matrix is empty, drop everything.
ptr::drop_in_place(data.as_mut());
return;
}
// Safety: because `nremove != 0`, the pointers given to `ptr::copy`
// wont alias.
let ptr_in = data.as_ptr();
let ptr_out = data.as_mut_ptr();
let mut curr_i = i;
for k in 0..ncols - 1 {
// Safety: we drop the row elements in-place because we will overwrite these
// entries later with the `ptr::copy`.
let s = ptr::slice_from_raw_parts_mut(ptr_out.add(curr_i), nremove);
ptr::drop_in_place(s);
ptr::copy(
ptr_in.add(curr_i + (k + 1) * nremove),
ptr_out.add(curr_i),
@ -997,7 +1119,13 @@ unsafe fn compress_rows<T: Scalar>(
curr_i += new_nrows;
}
// Deal with the last column from which less values have to be copied.
/*
* Deal with the last column from which less values have to be copied.
*/
// Safety: we drop the row elements in-place because we will overwrite these
// entries later with the `ptr::copy`.
let s = ptr::slice_from_raw_parts_mut(ptr_out.add(curr_i), nremove);
ptr::drop_in_place(s);
let remaining_len = nrows - i - nremove;
ptr::copy(
ptr_in.add(nrows * ncols - remaining_len),
@ -1006,15 +1134,9 @@ unsafe fn compress_rows<T: Scalar>(
);
}
// Moves entries of a matrix buffer to make place for `ninsert` emty rows starting at the `i-th` row index.
// Moves entries of a matrix buffer to make place for `ninsert` empty rows starting at the `i-th` row index.
// The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements.
unsafe fn extend_rows<T: Scalar>(
data: &mut [T],
nrows: usize,
ncols: usize,
i: usize,
ninsert: usize,
) {
unsafe fn extend_rows<T>(data: &mut [T], nrows: usize, ncols: usize, i: usize, ninsert: usize) {
let new_nrows = nrows + ninsert;
if new_nrows == 0 || ncols == 0 {
@ -1119,7 +1241,7 @@ where
R: Dim,
S: Extend<Vector<T, RV, SV>>,
RV: Dim,
SV: Storage<T, RV>,
SV: RawStorage<T, RV>,
ShapeConstraint: SameNumberOfRows<R, RV>,
{
/// Extends the number of columns of a `Matrix` with `Vector`s

View File

@ -1,6 +1,6 @@
//! Indexing
use crate::base::storage::{Storage, StorageMut};
use crate::base::storage::{RawStorage, RawStorageMut};
use crate::base::{
Const, Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1,
};
@ -310,7 +310,7 @@ fn dimrange_rangetoinclusive_usize() {
}
/// A helper trait used for indexing operations.
pub trait MatrixIndex<'a, T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>>: Sized {
pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>>: Sized {
/// The output type returned by methods.
type Output: 'a;
@ -345,7 +345,7 @@ pub trait MatrixIndex<'a, T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>>: Sized
}
/// A helper trait used for indexing operations.
pub trait MatrixIndexMut<'a, T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>>:
pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>>:
MatrixIndex<'a, T, R, C, S>
{
/// The output type returned by methods.
@ -476,7 +476,7 @@ pub trait MatrixIndexMut<'a, T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>>:
/// 4, 7,
/// 5, 8)));
/// ```
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Produces a view of the data at the given index, or
/// `None` if the index is out of bounds.
#[inline]
@ -494,7 +494,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use]
pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<I::OutputMut>
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>,
{
index.get_mut(self)
@ -516,7 +516,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[inline]
pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>,
{
index.index_mut(self)
@ -539,7 +539,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use]
pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
I: MatrixIndexMut<'a, T, R, C, S>,
{
index.get_unchecked_mut(self)
@ -553,7 +553,7 @@ where
T: Scalar,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
type Output = &'a T;
@ -575,7 +575,7 @@ where
T: Scalar,
R: Dim,
C: Dim,
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
{
type OutputMut = &'a mut T;
@ -583,7 +583,7 @@ where
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
{
matrix.data.get_unchecked_linear_mut(self)
}
@ -591,12 +591,11 @@ where
// EXTRACT A SINGLE ELEMENT BY 2D COORDINATES
impl<'a, T, R, C, S> MatrixIndex<'a, T, R, C, S> for (usize, usize)
impl<'a, T: 'a, R, C, S> MatrixIndex<'a, T, R, C, S> for (usize, usize)
where
T: Scalar,
R: Dim,
C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
{
type Output = &'a T;
@ -604,7 +603,7 @@ where
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<T, R, C, S>) -> bool {
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let (nrows, ncols) = matrix.shape_generic();
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
}
@ -616,12 +615,11 @@ where
}
}
impl<'a, T, R, C, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize)
impl<'a, T: 'a, R, C, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize)
where
T: Scalar,
R: Dim,
C: Dim,
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
{
type OutputMut = &'a mut T;
@ -629,7 +627,7 @@ where
#[inline(always)]
unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix<T, R, C, S>) -> Self::OutputMut
where
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
{
let (row, col) = self;
matrix.data.get_unchecked_mut(row, col)
@ -660,7 +658,7 @@ macro_rules! impl_index_pair {
T: Scalar,
$R: Dim,
$C: Dim,
S: Storage<T, R, C>,
S: RawStorage<T, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{
@ -670,7 +668,7 @@ macro_rules! impl_index_pair {
#[inline(always)]
fn contained_by(&self, matrix: &Matrix<T, $R, $C, S>) -> bool {
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let (nrows, ncols) = matrix.shape_generic();
DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols)
}
@ -680,7 +678,7 @@ macro_rules! impl_index_pair {
use crate::base::SliceStorage;
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let (nrows, ncols) = matrix.shape_generic();
let data =
SliceStorage::new_unchecked(&matrix.data,
@ -696,7 +694,7 @@ macro_rules! impl_index_pair {
T: Scalar,
$R: Dim,
$C: Dim,
S: StorageMut<T, R, C>,
S: RawStorageMut<T, R, C>,
$( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)*
$( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),*
{
@ -708,7 +706,7 @@ macro_rules! impl_index_pair {
use crate::base::SliceStorageMut;
let (rows, cols) = self;
let (nrows, ncols) = matrix.data.shape();
let (nrows, ncols) = matrix.shape_generic();
let data =
SliceStorageMut::new_unchecked(&mut matrix.data,

View File

@ -26,7 +26,7 @@ impl<T: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Stor
DefaultAllocator: Allocator<T, D>,
{
let mut res = self.clone_owned();
res.axpy(t.inlined_clone(), rhs, T::one() - t);
res.axpy(t.clone(), rhs, T::one() - t);
res
}
@ -109,14 +109,14 @@ impl<T: RealField, D: Dim, S: Storage<T, D>> Unit<Vector<T, D, S>> {
return Some(Unit::new_unchecked(self.clone_owned()));
}
let hang = c_hang.acos();
let s_hang = (T::one() - c_hang * c_hang).sqrt();
let hang = c_hang.clone().acos();
let s_hang = (T::one() - c_hang.clone() * c_hang).sqrt();
// TODO: what if s_hang is 0.0 ? The result is not well-defined.
if relative_eq!(s_hang, T::zero(), epsilon = epsilon) {
None
} else {
let ta = ((T::one() - t) * hang).sin() / s_hang;
let ta = ((T::one() - t.clone()) * hang.clone()).sin() / s_hang.clone();
let tb = (t * hang).sin() / s_hang;
let mut res = self.scale(ta);
res.axpy(tb, &**rhs, T::one());

View File

@ -5,13 +5,14 @@ use std::marker::PhantomData;
use std::mem;
use crate::base::dimension::{Dim, U1};
use crate::base::storage::{Storage, StorageMut};
use crate::base::storage::{RawStorage, RawStorageMut};
use crate::base::{Matrix, MatrixSlice, MatrixSliceMut, Scalar};
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.
pub struct $Name<'a, T: Scalar, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> {
#[derive(Debug)]
pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> {
ptr: $Ptr,
inner_ptr: $Ptr,
inner_end: $Ptr,
@ -22,7 +23,7 @@ macro_rules! iterator {
// 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: Scalar, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> $Name<'a, T, R, C, S> {
impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> $Name<'a, T, R, C, S> {
/// Creates a new iterator for the given matrix storage.
pub fn new(storage: $SRef) -> $Name<'a, T, R, C, S> {
let shape = storage.shape();
@ -59,9 +60,7 @@ macro_rules! iterator {
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> Iterator
for $Name<'a, T, R, C, S>
{
impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> Iterator for $Name<'a, T, R, C, S> {
type Item = $Ref;
#[inline]
@ -116,7 +115,7 @@ macro_rules! iterator {
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> DoubleEndedIterator
impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> DoubleEndedIterator
for $Name<'a, T, R, C, S>
{
#[inline]
@ -156,7 +155,7 @@ macro_rules! iterator {
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> ExactSizeIterator
impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> ExactSizeIterator
for $Name<'a, T, R, C, S>
{
#[inline]
@ -165,35 +164,35 @@ macro_rules! iterator {
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> FusedIterator
impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage<T, R, C>> FusedIterator
for $Name<'a, T, R, C, S>
{
}
};
}
iterator!(struct MatrixIter for Storage.ptr -> *const T, &'a T, &'a S);
iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S);
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);
/*
*
* Row iterators.
*
*/
#[derive(Clone)]
#[derive(Clone, Debug)]
/// An iterator through the rows of a matrix.
pub struct RowIter<'a, T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> {
pub struct RowIter<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>> {
mat: &'a Matrix<T, R, C, S>,
curr: usize,
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> RowIter<'a, T, R, C, S> {
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> RowIter<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
RowIter { mat, curr: 0 }
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for RowIter<'a, T, R, C, S> {
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> Iterator for RowIter<'a, T, R, C, S> {
type Item = MatrixSlice<'a, T, U1, C, S::RStride, S::CStride>;
#[inline]
@ -221,7 +220,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator for RowIt
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ExactSizeIterator
for RowIter<'a, T, R, C, S>
{
#[inline]
@ -231,13 +230,14 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
}
/// An iterator through the mutable rows of a matrix.
pub struct RowIterMut<'a, T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> {
#[derive(Debug)]
pub struct RowIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> {
mat: *mut Matrix<T, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> RowIterMut<'a, T, R, C, S> {
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> RowIterMut<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
RowIterMut {
mat,
@ -251,7 +251,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> RowIterMut<'a,
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> Iterator
for RowIterMut<'a, T, R, C, S>
{
type Item = MatrixSliceMut<'a, T, U1, C, S::RStride, S::CStride>;
@ -278,7 +278,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ExactSizeIterator
for RowIterMut<'a, T, R, C, S>
{
#[inline]
@ -292,22 +292,20 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterat
* Column iterators.
*
*/
#[derive(Clone)]
#[derive(Clone, Debug)]
/// An iterator through the columns of a matrix.
pub struct ColumnIter<'a, T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> {
pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage<T, R, C>> {
mat: &'a Matrix<T, R, C, S>,
curr: usize,
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ColumnIter<'a, T, R, C, S> {
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ColumnIter<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a Matrix<T, R, C, S>) -> Self {
ColumnIter { mat, curr: 0 }
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator
for ColumnIter<'a, T, R, C, S>
{
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> Iterator for ColumnIter<'a, T, R, C, S> {
type Item = MatrixSlice<'a, T, R, U1, S::RStride, S::CStride>;
#[inline]
@ -335,7 +333,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> Iterator
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage<T, R, C>> ExactSizeIterator
for ColumnIter<'a, T, R, C, S>
{
#[inline]
@ -345,13 +343,14 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + Storage<T, R, C>> ExactSizeIterator
}
/// An iterator through the mutable columns of a matrix.
pub struct ColumnIterMut<'a, T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> {
#[derive(Debug)]
pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> {
mat: *mut Matrix<T, R, C, S>,
curr: usize,
phantom: PhantomData<&'a mut Matrix<T, R, C, S>>,
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ColumnIterMut<'a, T, R, C, S> {
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ColumnIterMut<'a, T, R, C, S> {
pub(crate) fn new(mat: &'a mut Matrix<T, R, C, S>) -> Self {
ColumnIterMut {
mat,
@ -365,7 +364,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ColumnIterMut<'
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> Iterator
for ColumnIterMut<'a, T, R, C, S>
{
type Item = MatrixSliceMut<'a, T, R, U1, S::RStride, S::CStride>;
@ -392,7 +391,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> Iterator
}
}
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + StorageMut<T, R, C>> ExactSizeIterator
impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut<T, R, C>> ExactSizeIterator
for ColumnIterMut<'a, T, R, C, S>
{
#[inline]

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,6 @@ where
fn replace(&mut self, i: usize, val: Self::Element) {
self.zip_apply(&val, |mut a, b| {
a.replace(i, b);
a
})
}
@ -52,7 +51,6 @@ where
unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
self.zip_apply(&val, |mut a, b| {
a.replace_unchecked(i, b);
a
})
}

View File

@ -6,29 +6,29 @@ 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::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
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: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> {
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: Scalar + Send, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Send
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: Scalar + Sync, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Sync
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: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> $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,
@ -48,7 +48,7 @@ macro_rules! slice_storage_impl(
}
// Dynamic is arbitrary. It's just to be able to call the constructors with `Slice::`
impl<'a, T: Scalar, R: Dim, C: Dim> $T<'a, T, R, C, Dynamic, Dynamic> {
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<RStor, CStor, S>(storage: $SRef, start: (usize, usize), shape: (R, C))
@ -78,10 +78,10 @@ macro_rules! slice_storage_impl(
}
}
impl <'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
$T<'a, T, R, C, RStride, CStride>
where
Self: ContiguousStorage<T, R, C>
Self: RawStorage<T, R, C> + IsContiguous
{
/// Extracts the original slice from this storage
pub fn into_slice(self) -> &'a [T] {
@ -99,11 +99,11 @@ macro_rules! slice_storage_impl(
slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \
to another matrix data storage.";
Storage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T));
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.";
StorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T)
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
@ -128,7 +128,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
SliceStorageMut<'a, T, R, C, RStride, CStride>
where
Self: ContiguousStorageMut<T, R, C>,
Self: RawStorageMut<T, R, C> + IsContiguous,
{
/// Extracts the original slice from this storage
pub fn into_slice_mut(self) -> &'a mut [T] {
@ -144,7 +144,7 @@ where
macro_rules! storage_impl(
($($T: ident),* $(,)*) => {$(
unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C>
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage<T, R, C>
for $T<'a, T, R, C, RStride, CStride> {
type RStride = RStride;
@ -181,6 +181,21 @@ macro_rules! storage_impl(
}
}
#[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<T, R, C>
for $T<'a, T, R, C, RStride, CStride> {
#[inline]
fn into_owned(self) -> Owned<T, R, C>
where DefaultAllocator: Allocator<T, R, C> {
@ -194,25 +209,13 @@ macro_rules! storage_impl(
let it = MatrixIter::new(self).cloned();
DefaultAllocator::allocate_from_iterator(nrows, ncols, it)
}
#[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)
}
}
}
)*}
);
storage_impl!(SliceStorage, SliceStorageMut);
unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMut<T, R, C>
unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut<T, R, C>
for SliceStorageMut<'a, T, R, C, RStride, CStride>
{
#[inline]
@ -232,33 +235,22 @@ unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMu
}
}
unsafe impl<'a, T: Scalar, R: Dim, CStride: Dim> ContiguousStorage<T, R, U1>
for SliceStorage<'a, T, R, U1, U1, CStride>
{
}
unsafe impl<'a, T: Scalar, R: Dim, CStride: Dim> ContiguousStorage<T, R, U1>
for SliceStorageMut<'a, T, R, U1, U1, CStride>
{
}
unsafe impl<'a, T: Scalar, R: Dim, CStride: Dim> ContiguousStorageMut<T, R, U1>
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: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
for SliceStorage<'a, T, R, C, U1, R>
{
}
unsafe impl<'a, T: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage<T, R, C>
for SliceStorageMut<'a, T, R, C, U1, R>
{
}
unsafe impl<'a, T: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut<T, R, C>
unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
for SliceStorageMut<'a, T, R, C, U1, R>
{
}
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
#[inline]
fn assert_slice_index(
&self,
@ -315,20 +307,20 @@ macro_rules! matrix_slice_impl(
*/
/// 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> {
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> {
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> {
-> $MatrixSlice<'_, T, Dynamic, C, S::RStride, S::CStride> {
$me.$rows_generic(first_row, Dynamic::new(nrows))
}
@ -336,7 +328,7 @@ macro_rules! matrix_slice_impl(
/// 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> {
-> $MatrixSlice<'_, T, Dynamic, C, Dynamic, S::CStride> {
$me.$rows_generic_with_step(first_row, Dynamic::new(nrows), step)
}
@ -344,7 +336,7 @@ macro_rules! matrix_slice_impl(
/// Extracts a compile-time number of consecutive rows from this matrix.
#[inline]
pub fn $fixed_rows<const RSLICE: usize>($me: $Me, first_row: usize)
-> $MatrixSlice<T, Const<RSLICE>, C, S::RStride, S::CStride> {
-> $MatrixSlice<'_, T, Const<RSLICE>, C, S::RStride, S::CStride> {
$me.$rows_generic(first_row, Const::<RSLICE>)
}
@ -353,7 +345,7 @@ macro_rules! matrix_slice_impl(
/// rows.
#[inline]
pub fn $fixed_rows_with_step<const RSLICE: usize>($me: $Me, first_row: usize, step: usize)
-> $MatrixSlice<T, Const<RSLICE>, C, Dynamic, S::CStride> {
-> $MatrixSlice<'_, T, Const<RSLICE>, C, Dynamic, S::CStride> {
$me.$rows_generic_with_step(first_row, Const::<RSLICE>, step)
}
@ -362,9 +354,9 @@ macro_rules! matrix_slice_impl(
/// argument may or may not be values known at compile-time.
#[inline]
pub fn $rows_generic<RSlice: Dim>($me: $Me, row_start: usize, nrows: RSlice)
-> $MatrixSlice<T, RSlice, C, S::RStride, S::CStride> {
-> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> {
let my_shape = $me.data.shape();
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);
@ -379,10 +371,10 @@ macro_rules! matrix_slice_impl(
/// argument may or may not be values known at compile-time.
#[inline]
pub fn $rows_generic_with_step<RSlice>($me: $Me, row_start: usize, nrows: RSlice, step: usize)
-> $MatrixSlice<T, RSlice, C, Dynamic, S::CStride>
-> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride>
where RSlice: Dim {
let my_shape = $me.data.shape();
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));
@ -402,20 +394,20 @@ macro_rules! matrix_slice_impl(
*/
/// 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> {
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> {
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> {
-> $MatrixSlice<'_, T, R, Dynamic, S::RStride, S::CStride> {
$me.$columns_generic(first_col, Dynamic::new(ncols))
}
@ -424,7 +416,7 @@ macro_rules! matrix_slice_impl(
/// columns.
#[inline]
pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize)
-> $MatrixSlice<T, R, Dynamic, S::RStride, Dynamic> {
-> $MatrixSlice<'_, T, R, Dynamic, S::RStride, Dynamic> {
$me.$columns_generic_with_step(first_col, Dynamic::new(ncols), step)
}
@ -432,7 +424,7 @@ macro_rules! matrix_slice_impl(
/// Extracts a compile-time number of consecutive columns from this matrix.
#[inline]
pub fn $fixed_columns<const CSLICE: usize>($me: $Me, first_col: usize)
-> $MatrixSlice<T, R, Const<CSLICE>, S::RStride, S::CStride> {
-> $MatrixSlice<'_, T, R, Const<CSLICE>, S::RStride, S::CStride> {
$me.$columns_generic(first_col, Const::<CSLICE>)
}
@ -441,7 +433,7 @@ macro_rules! matrix_slice_impl(
/// `step` columns.
#[inline]
pub fn $fixed_columns_with_step<const CSLICE: usize>($me: $Me, first_col: usize, step: usize)
-> $MatrixSlice<T, R, Const<CSLICE>, S::RStride, Dynamic> {
-> $MatrixSlice<'_, T, R, Const<CSLICE>, S::RStride, Dynamic> {
$me.$columns_generic_with_step(first_col, Const::<CSLICE>, step)
}
@ -450,9 +442,9 @@ macro_rules! matrix_slice_impl(
/// known at compile-time.
#[inline]
pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice)
-> $MatrixSlice<T, R, CSlice, S::RStride, S::CStride> {
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> {
let my_shape = $me.data.shape();
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);
@ -467,9 +459,9 @@ macro_rules! matrix_slice_impl(
/// or may not be values known at compile-time.
#[inline]
pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize)
-> $MatrixSlice<T, R, CSlice, S::RStride, Dynamic> {
-> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> {
let my_shape = $me.data.shape();
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));
@ -492,7 +484,7 @@ macro_rules! matrix_slice_impl(
/// consecutive elements.
#[inline]
pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize))
-> $MatrixSlice<T, Dynamic, Dynamic, S::RStride, S::CStride> {
-> $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));
@ -510,7 +502,7 @@ macro_rules! matrix_slice_impl(
/// 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> {
-> $MatrixSlice<'_, T, Dynamic, Dynamic, Dynamic, Dynamic> {
let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1));
$me.$generic_slice_with_steps(start, shape, steps)
@ -520,7 +512,7 @@ macro_rules! matrix_slice_impl(
/// CSlice::dim())` consecutive components.
#[inline]
pub fn $fixed_slice<const RSLICE: usize, const CSLICE: usize>($me: $Me, irow: usize, icol: usize)
-> $MatrixSlice<T, Const<RSLICE>, Const<CSLICE>, S::RStride, S::CStride> {
-> $MatrixSlice<'_, T, Const<RSLICE>, Const<CSLICE>, S::RStride, S::CStride> {
$me.assert_slice_index((irow, icol), (RSLICE, CSLICE), (0, 0));
let shape = (Const::<RSLICE>, Const::<CSLICE>);
@ -537,7 +529,7 @@ macro_rules! matrix_slice_impl(
/// the original matrix.
#[inline]
pub fn $fixed_slice_with_steps<const RSLICE: usize, const CSLICE: usize>($me: $Me, start: (usize, usize), steps: (usize, usize))
-> $MatrixSlice<T, Const<RSLICE>, Const<CSLICE>, Dynamic, Dynamic> {
-> $MatrixSlice<'_, T, Const<RSLICE>, Const<CSLICE>, Dynamic, Dynamic> {
let shape = (Const::<RSLICE>, Const::<CSLICE>);
$me.$generic_slice_with_steps(start, shape, steps)
}
@ -545,7 +537,7 @@ macro_rules! matrix_slice_impl(
/// Creates a slice that may or may not have a fixed size and stride.
#[inline]
pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
-> $MatrixSlice<T, RSlice, CSlice, S::RStride, S::CStride>
-> $MatrixSlice<'_, T, RSlice, CSlice, S::RStride, S::CStride>
where RSlice: Dim,
CSlice: Dim {
@ -563,7 +555,7 @@ macro_rules! matrix_slice_impl(
start: (usize, usize),
shape: (RSlice, CSlice),
steps: (usize, usize))
-> $MatrixSlice<T, RSlice, CSlice, Dynamic, Dynamic>
-> $MatrixSlice<'_, T, RSlice, CSlice, Dynamic, Dynamic>
where RSlice: Dim,
CSlice: Dim {
@ -584,15 +576,15 @@ macro_rules! matrix_slice_impl(
* Splitting.
*
*/
/// Splits this NxM matrix into two parts delimited by two ranges.
/// 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<Range1: SliceRange<R>, Range2: SliceRange<R>>($me: $Me, r1: Range1, r2: Range2)
-> ($MatrixSlice<T, Range1::Size, C, S::RStride, S::CStride>,
$MatrixSlice<T, Range2::Size, C, S::RStride, S::CStride>) {
-> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>,
$MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) {
let (nrows, ncols) = $me.data.shape();
let (nrows, ncols) = $me.shape_generic();
let strides = $me.data.strides();
let start1 = r1.begin(nrows);
@ -620,15 +612,15 @@ macro_rules! matrix_slice_impl(
}
}
/// Splits this NxM matrix into two parts delimited by two ranges.
/// 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<Range1: SliceRange<C>, Range2: SliceRange<C>>($me: $Me, r1: Range1, r2: Range2)
-> ($MatrixSlice<T, R, Range1::Size, S::RStride, S::CStride>,
$MatrixSlice<T, R, Range2::Size, S::RStride, S::CStride>) {
-> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>,
$MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) {
let (nrows, ncols) = $me.data.shape();
let (nrows, ncols) = $me.shape_generic();
let strides = $me.data.strides();
let start1 = r1.begin(ncols);
@ -666,9 +658,9 @@ pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> =
Matrix<T, R, C, SliceStorageMut<'a, T, R, C, RStride, CStride>>;
/// # Slicing based on index and length
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
matrix_slice_impl!(
self: &Self, MatrixSlice, SliceStorage, Storage.get_address_unchecked(), &self.data;
self: &Self, MatrixSlice, SliceStorage, RawStorage.get_address_unchecked(), &self.data;
row,
row_part,
rows,
@ -696,9 +688,9 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
}
/// # Mutable slicing based on index and length
impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
matrix_slice_impl!(
self: &mut Self, MatrixSliceMut, SliceStorageMut, StorageMut.get_address_unchecked_mut(), &mut self.data;
self: &mut Self, MatrixSliceMut, SliceStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data;
row_mut,
row_part_mut,
rows_mut,
@ -861,7 +853,7 @@ impl<D: Dim> SliceRange<D> for RangeInclusive<usize> {
// TODO: see how much of this overlaps with the general indexing
// methods from indexing.rs.
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed
/// by the range `cols`.
#[inline]
@ -870,12 +862,12 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
&self,
rows: RowRange,
cols: ColRange,
) -> MatrixSlice<T, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
) -> MatrixSlice<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
where
RowRange: SliceRange<R>,
ColRange: SliceRange<C>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
self.generic_slice(
(rows.begin(nrows), cols.begin(ncols)),
(rows.size(nrows), cols.size(ncols)),
@ -888,7 +880,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
pub fn rows_range<RowRange: SliceRange<R>>(
&self,
rows: RowRange,
) -> MatrixSlice<T, RowRange::Size, C, S::RStride, S::CStride> {
) -> MatrixSlice<'_, T, RowRange::Size, C, S::RStride, S::CStride> {
self.slice_range(rows, ..)
}
@ -898,26 +890,26 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
pub fn columns_range<ColRange: SliceRange<C>>(
&self,
cols: ColRange,
) -> MatrixSlice<T, R, ColRange::Size, S::RStride, S::CStride> {
) -> 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<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
/// 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<RowRange, ColRange>(
&mut self,
rows: RowRange,
cols: ColRange,
) -> MatrixSliceMut<T, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
) -> MatrixSliceMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
where
RowRange: SliceRange<R>,
ColRange: SliceRange<C>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
self.generic_slice_mut(
(rows.begin(nrows), cols.begin(ncols)),
(rows.size(nrows), cols.size(ncols)),
@ -929,7 +921,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
pub fn rows_range_mut<RowRange: SliceRange<R>>(
&mut self,
rows: RowRange,
) -> MatrixSliceMut<T, RowRange::Size, C, S::RStride, S::CStride> {
) -> MatrixSliceMut<'_, T, RowRange::Size, C, S::RStride, S::CStride> {
self.slice_range_mut(rows, ..)
}
@ -938,7 +930,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
pub fn columns_range_mut<ColRange: SliceRange<C>>(
&mut self,
cols: ColRange,
) -> MatrixSliceMut<T, R, ColRange::Size, S::RStride, S::CStride> {
) -> MatrixSliceMut<'_, T, R, ColRange::Size, S::RStride, S::CStride> {
self.slice_range_mut(.., cols)
}
}
@ -946,7 +938,6 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
impl<'a, T, R, C, RStride, CStride> From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
for MatrixSlice<'a, T, R, C, RStride, CStride>
where
T: Scalar,
R: Dim,
C: Dim,
RStride: Dim,

View File

@ -1,10 +1,10 @@
use crate::storage::Storage;
use crate::storage::RawStorage;
use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector};
use num::{Signed, Zero};
use simba::simd::SimdSigned;
/// # Find the min and max components
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Returns the absolute value of the component with the largest absolute value.
/// # Example
/// ```
@ -40,8 +40,8 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: SimdComplexField,
{
self.fold_with(
|e| e.unwrap_or(&T::zero()).simd_norm1(),
|a, b| a.simd_max(b.simd_norm1()),
|e| e.unwrap_or(&T::zero()).clone().simd_norm1(),
|a, b| a.simd_max(b.clone().simd_norm1()),
)
}
@ -60,8 +60,8 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: SimdPartialOrd + Zero,
{
self.fold_with(
|e| e.map(|e| e.inlined_clone()).unwrap_or_else(T::zero),
|a, b| a.simd_max(b.inlined_clone()),
|e| e.map(|e| e.clone()).unwrap_or_else(T::zero),
|a, b| a.simd_max(b.clone()),
)
}
@ -101,10 +101,10 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
{
self.fold_with(
|e| {
e.map(|e| e.simd_norm1())
e.map(|e| e.clone().simd_norm1())
.unwrap_or_else(T::SimdRealField::zero)
},
|a, b| a.simd_min(b.simd_norm1()),
|a, b| a.simd_min(b.clone().simd_norm1()),
)
}
@ -123,8 +123,8 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: SimdPartialOrd + Zero,
{
self.fold_with(
|e| e.map(|e| e.inlined_clone()).unwrap_or_else(T::zero),
|a, b| a.simd_min(b.inlined_clone()),
|e| e.map(|e| e.clone()).unwrap_or_else(T::zero),
|a, b| a.simd_min(b.clone()),
)
}
@ -149,12 +149,12 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
{
assert!(!self.is_empty(), "The input matrix must not be empty.");
let mut the_max = unsafe { self.get_unchecked((0, 0)).norm1() };
let mut the_max = unsafe { self.get_unchecked((0, 0)).clone().norm1() };
let mut the_ij = (0, 0);
for j in 0..self.ncols() {
for i in 0..self.nrows() {
let val = unsafe { self.get_unchecked((i, j)).norm1() };
let val = unsafe { self.get_unchecked((i, j)).clone().norm1() };
if val > the_max {
the_max = val;
@ -167,7 +167,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
}
}
impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Computes the index of the matrix component with the largest absolute value.
///
/// # Examples:
@ -203,7 +203,7 @@ impl<T: Scalar + PartialOrd + Signed, R: Dim, C: Dim, S: Storage<T, R, C>> Matri
// TODO: find a way to avoid code duplication just for complex number support.
/// # Find the min and max components (vector-specific methods)
impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
impl<T: Scalar, D: Dim, S: RawStorage<T, D>> Vector<T, D, S> {
/// Computes the index of the vector component with the largest complex or real absolute value.
///
/// # Examples:
@ -224,11 +224,11 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
{
assert!(!self.is_empty(), "The input vector must not be empty.");
let mut the_max = unsafe { self.vget_unchecked(0).norm1() };
let mut the_max = unsafe { self.vget_unchecked(0).clone().norm1() };
let mut the_i = 0;
for i in 1..self.nrows() {
let val = unsafe { self.vget_unchecked(i).norm1() };
let val = unsafe { self.vget_unchecked(i).clone().norm1() };
if val > the_max {
the_max = val;
@ -268,7 +268,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
}
}
(the_i, the_max.inlined_clone())
(the_i, the_max.clone())
}
/// Computes the index of the vector component with the largest value.
@ -350,7 +350,7 @@ impl<T: Scalar, D: Dim, S: Storage<T, D>> Vector<T, D, S> {
}
}
(the_i, the_min.inlined_clone())
(the_i, the_min.clone())
}
/// Computes the index of the vector component with the smallest value.

View File

@ -33,10 +33,13 @@ mod unit;
#[cfg(any(feature = "std", feature = "alloc"))]
mod vec_storage;
mod blas_uninit;
#[doc(hidden)]
pub mod helper;
mod interpolation;
mod min_max;
/// Mechanisms for working with values that may not be initialized.
pub mod uninit;
pub use self::matrix::*;
pub use self::norm::*;
@ -50,5 +53,6 @@ pub use self::alias::*;
pub use self::alias_slice::*;
pub use self::array_storage::*;
pub use self::matrix_slice::*;
pub use self::storage::*;
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::vec_storage::*;

View File

@ -40,10 +40,13 @@ pub trait Norm<T: SimdComplexField> {
}
/// Euclidean norm.
#[derive(Copy, Clone, Debug)]
pub struct EuclideanNorm;
/// Lp norm.
#[derive(Copy, Clone, Debug)]
pub struct LpNorm(pub i32);
/// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm.
#[derive(Copy, Clone, Debug)]
pub struct UniformNorm;
impl<T: SimdComplexField> Norm<T> for EuclideanNorm {
@ -325,7 +328,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{
let n = self.norm();
let le = n.simd_le(min_norm);
let le = n.clone().simd_le(min_norm);
let val = self.unscale(n);
SimdOption::new(val, le)
}
@ -374,7 +377,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{
let n = self.norm();
let scaled = self.scale(max / n);
let scaled = self.scale(max.clone() / n.clone());
let use_scaled = n.simd_gt(max);
scaled.select(use_scaled, self.clone_owned())
}
@ -410,7 +413,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
T: SimdComplexField,
{
let n = self.norm();
self.unscale_mut(n);
self.unscale_mut(n.clone());
n
}
@ -430,8 +433,13 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
DefaultAllocator: Allocator<T, R, C> + Allocator<T::Element, R, C>,
{
let n = self.norm();
let le = n.simd_le(min_norm);
self.apply(|e| e.simd_unscale(n).select(le, e));
let le = n.clone().simd_le(min_norm);
self.apply(|e| {
*e = e
.clone()
.simd_unscale(n.clone())
.select(le.clone(), e.clone())
});
SimdOption::new(n, le)
}
@ -448,7 +456,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> Matrix<T, R, C, S> {
if n <= min_norm {
None
} else {
self.unscale_mut(n);
self.unscale_mut(n.clone());
Some(n)
}
}
@ -505,13 +513,8 @@ where
/// The i-the canonical basis element.
#[inline]
fn canonical_basis_element(i: usize) -> Self {
assert!(i < D::dim(), "Index out of bound.");
let mut res = Self::zero();
unsafe {
*res.data.get_unchecked_linear_mut(i) = T::one();
}
res[i] = T::one();
res
}
@ -574,7 +577,7 @@ where
&& f(&Self::canonical_basis_element(1));
} else if vs.len() == 1 {
let v = &vs[0];
let res = Self::from_column_slice(&[-v[1], v[0]]);
let res = Self::from_column_slice(&[-v[1].clone(), v[0].clone()]);
let _ = f(&res.normalize());
}
@ -590,10 +593,10 @@ where
let v = &vs[0];
let mut a;
if v[0].norm1() > v[1].norm1() {
a = Self::from_column_slice(&[v[2], T::zero(), -v[0]]);
if v[0].clone().norm1() > v[1].clone().norm1() {
a = Self::from_column_slice(&[v[2].clone(), T::zero(), -v[0].clone()]);
} else {
a = Self::from_column_slice(&[T::zero(), -v[2], v[1]]);
a = Self::from_column_slice(&[T::zero(), -v[2].clone(), v[1].clone()]);
};
let _ = a.normalize_mut();

View File

@ -7,20 +7,25 @@ use std::ops::{
use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub};
use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
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::storage::{ContiguousStorageMut, Storage, StorageMut};
use crate::base::storage::{Storage, StorageMut};
use crate::base::uninit::Uninit;
use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorSlice};
use crate::SimdComplexField;
use crate::storage::IsContiguous;
use crate::uninit::{Init, InitStatus};
use crate::{RawStorage, RawStorageMut, SimdComplexField};
use std::mem::MaybeUninit;
/*
*
* Indexing.
*
*/
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Index<usize> for Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<usize> for Matrix<T, R, C, S> {
type Output = T;
#[inline]
@ -30,11 +35,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Index<usize> for Matrix<T,
}
}
impl<T, R: Dim, C: Dim, S> Index<(usize, usize)> for Matrix<T, R, C, S>
where
T: Scalar,
S: Storage<T, R, C>,
{
impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<(usize, usize)> for Matrix<T, R, C, S> {
type Output = T;
#[inline]
@ -50,7 +51,7 @@ where
}
// Mutable versions.
impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> {
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> {
#[inline]
fn index_mut(&mut self, i: usize) -> &mut T {
let ij = self.vector_to_matrix_index(i);
@ -58,11 +59,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: StorageMut<T, R, C>> IndexMut<usize> for Matr
}
}
impl<T, R: Dim, C: Dim, S> IndexMut<(usize, usize)> for Matrix<T, R, C, S>
where
T: Scalar,
S: StorageMut<T, R, C>,
{
impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<(usize, usize)> for Matrix<T, R, C, S> {
#[inline]
fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
let shape = self.shape();
@ -119,7 +116,7 @@ where
#[inline]
pub fn neg_mut(&mut self) {
for e in self.iter_mut() {
*e = -e.inlined_clone()
*e = -e.clone()
}
}
}
@ -134,7 +131,7 @@ macro_rules! componentwise_binop_impl(
($Trait: ident, $method: ident, $bound: ident;
$TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident,
$method_assign_statically_unchecked_rhs: ident;
$method_to: ident, $method_to_statically_unchecked: ident) => {
$method_to: ident, $method_to_statically_unchecked_uninit: ident) => {
impl<T, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
where T: Scalar + $bound {
@ -147,12 +144,14 @@ macro_rules! componentwise_binop_impl(
*
*/
#[inline]
fn $method_to_statically_unchecked<R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
fn $method_to_statically_unchecked_uninit<Status, R2: Dim, C2: Dim, SB,
R3: Dim, C3: Dim, SC>(&self,
status: Status,
rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<T, R3, C3, SC>)
where SB: Storage<T, R2, C2>,
SC: StorageMut<T, R3, C3> {
out: &mut Matrix<Status::Value, R3, C3, SC>)
where Status: InitStatus<T>,
SB: RawStorage<T, R2, C2>,
SC: RawStorageMut<Status::Value, R3, C3> {
assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch.");
@ -164,13 +163,13 @@ macro_rules! componentwise_binop_impl(
let arr2 = rhs.data.as_slice_unchecked();
let out = out.data.as_mut_slice_unchecked();
for i in 0 .. arr1.len() {
*out.get_unchecked_mut(i) = arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone());
Status::init(out.get_unchecked_mut(i), arr1.get_unchecked(i).clone().$method(arr2.get_unchecked(i).clone()));
}
} else {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
let val = self.get_unchecked((i, j)).inlined_clone().$method(rhs.get_unchecked((i, j)).inlined_clone());
*out.get_unchecked_mut((i, j)) = val;
let val = self.get_unchecked((i, j)).clone().$method(rhs.get_unchecked((i, j)).clone());
Status::init(out.get_unchecked_mut((i, j)), val);
}
}
}
@ -194,12 +193,12 @@ macro_rules! componentwise_binop_impl(
let arr2 = rhs.data.as_slice_unchecked();
for i in 0 .. arr2.len() {
arr1.get_unchecked_mut(i).$method_assign(arr2.get_unchecked(i).inlined_clone());
arr1.get_unchecked_mut(i).$method_assign(arr2.get_unchecked(i).clone());
}
} else {
for j in 0 .. rhs.ncols() {
for i in 0 .. rhs.nrows() {
self.get_unchecked_mut((i, j)).$method_assign(rhs.get_unchecked((i, j)).inlined_clone())
self.get_unchecked_mut((i, j)).$method_assign(rhs.get_unchecked((i, j)).clone())
}
}
}
@ -222,14 +221,14 @@ macro_rules! componentwise_binop_impl(
let arr2 = rhs.data.as_mut_slice_unchecked();
for i in 0 .. arr1.len() {
let res = arr1.get_unchecked(i).inlined_clone().$method(arr2.get_unchecked(i).inlined_clone());
let res = arr1.get_unchecked(i).clone().$method(arr2.get_unchecked(i).clone());
*arr2.get_unchecked_mut(i) = res;
}
} else {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
let r = rhs.get_unchecked_mut((i, j));
*r = self.get_unchecked((i, j)).inlined_clone().$method(r.inlined_clone())
*r = self.get_unchecked((i, j)).clone().$method(r.clone())
}
}
}
@ -254,7 +253,7 @@ macro_rules! componentwise_binop_impl(
SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
self.$method_to_statically_unchecked(rhs, out)
self.$method_to_statically_unchecked_uninit(Init, rhs, out)
}
}
@ -320,15 +319,13 @@ macro_rules! componentwise_binop_impl(
#[inline]
fn $method(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
let mut res = unsafe {
let (nrows, ncols) = self.shape();
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
crate::unimplemented_or_uninitialized_generic!(nrows, ncols)
};
self.$method_to_statically_unchecked(rhs, &mut res);
res
let (nrows, ncols) = self.shape();
let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
let mut res = Matrix::uninit(nrows, ncols);
self.$method_to_statically_unchecked_uninit(Uninit, rhs, &mut res);
// SAFETY: the output has been initialized above.
unsafe { res.assume_init() }
}
}
@ -362,10 +359,10 @@ macro_rules! componentwise_binop_impl(
componentwise_binop_impl!(Add, add, ClosedAdd;
AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut;
add_to, add_to_statically_unchecked);
add_to, add_to_statically_unchecked_uninit);
componentwise_binop_impl!(Sub, sub, ClosedSub;
SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut;
sub_to, sub_to_statically_unchecked);
sub_to, sub_to_statically_unchecked_uninit);
impl<T, R: DimName, C: DimName> iter::Sum for OMatrix<T, R, C>
where
@ -475,7 +472,7 @@ macro_rules! componentwise_scalarop_impl(
// for left in res.iter_mut() {
for left in res.as_mut_slice().iter_mut() {
*left = left.inlined_clone().$method(rhs.inlined_clone())
*left = left.clone().$method(rhs.clone())
}
res
@ -501,7 +498,7 @@ macro_rules! componentwise_scalarop_impl(
fn $method_assign(&mut self, rhs: T) {
for j in 0 .. self.ncols() {
for i in 0 .. self.nrows() {
unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs.inlined_clone()) };
unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs.clone()) };
}
}
}
@ -564,11 +561,12 @@ where
#[inline]
fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!(self.data.shape().0, rhs.data.shape().1)
};
self.mul_to(rhs, &mut res);
res
let mut res = Matrix::uninit(self.shape_generic().0, rhs.shape_generic().1);
unsafe {
// SAFETY: this is OK because status = Uninit && bevy == 0
gemm_uninit(Uninit, &mut res, T::one(), self, rhs, T::zero());
res.assume_init()
}
}
}
@ -633,7 +631,7 @@ where
R2: Dim,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<T, R2, C1>,
SA: ContiguousStorageMut<T, R1, C1> + Clone,
SA: StorageMut<T, R1, C1> + IsContiguous + Clone, // TODO: get rid of the IsContiguous
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
{
@ -650,7 +648,7 @@ where
R2: Dim,
T: Scalar + Zero + One + ClosedAdd + ClosedMul,
SB: Storage<T, R2, C1>,
SA: ContiguousStorageMut<T, R1, C1> + Clone,
SA: StorageMut<T, R1, C1> + IsContiguous + Clone, // TODO: get rid of the IsContiguous
ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
// TODO: this is too restrictive. See comments for the non-ref version.
DefaultAllocator: Allocator<T, R1, C1, Buffer = SA>,
@ -676,12 +674,10 @@ where
DefaultAllocator: Allocator<T, C1, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!(self.data.shape().1, rhs.data.shape().1)
};
self.tr_mul_to(rhs, &mut res);
res
let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dot(b));
// SAFETY: this is OK because the result is now initialized.
unsafe { res.assume_init() }
}
/// Equivalent to `self.adjoint() * rhs`.
@ -694,26 +690,26 @@ where
DefaultAllocator: Allocator<T, C1, C2>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!(self.data.shape().1, rhs.data.shape().1)
};
self.ad_mul_to(rhs, &mut res);
res
let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dotc(b));
// SAFETY: this is OK because the result is now initialized.
unsafe { res.assume_init() }
}
#[inline(always)]
fn xx_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
fn xx_mul_to_uninit<Status, R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
&self,
status: Status,
rhs: &Matrix<T, R2, C2, SB>,
out: &mut Matrix<T, R3, C3, SC>,
out: &mut Matrix<Status::Value, R3, C3, SC>,
dot: impl Fn(
&VectorSlice<T, R1, SA::RStride, SA::CStride>,
&VectorSlice<T, R2, SB::RStride, SB::CStride>,
&VectorSlice<'_, T, R1, SA::RStride, SA::CStride>,
&VectorSlice<'_, T, R2, SB::RStride, SB::CStride>,
) -> T,
) where
SB: Storage<T, R2, C2>,
SC: StorageMut<T, R3, C3>,
Status: InitStatus<T>,
SB: RawStorage<T, R2, C2>,
SC: RawStorageMut<Status::Value, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{
let (nrows1, ncols1) = self.shape();
@ -742,7 +738,8 @@ where
for i in 0..ncols1 {
for j in 0..ncols2 {
let dot = dot(&self.column(i), &rhs.column(j));
unsafe { *out.get_unchecked_mut((i, j)) = dot };
let elt = unsafe { out.get_unchecked_mut((i, j)) };
Status::init(elt, dot);
}
}
}
@ -759,7 +756,7 @@ where
SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{
self.xx_mul_to(rhs, out, |a, b| a.dot(b))
self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dot(b))
}
/// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid
@ -775,7 +772,7 @@ where
SC: StorageMut<T, R3, C3>,
ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
{
self.xx_mul_to(rhs, out, |a, b| a.dotc(b))
self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dotc(b))
}
/// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations.
@ -808,34 +805,31 @@ where
SB: Storage<T, R2, C2>,
DefaultAllocator: Allocator<T, DimProd<R1, R2>, DimProd<C1, C2>>,
{
let (nrows1, ncols1) = self.data.shape();
let (nrows2, ncols2) = rhs.data.shape();
let (nrows1, ncols1) = self.shape_generic();
let (nrows2, ncols2) = rhs.shape_generic();
let mut res = unsafe {
crate::unimplemented_or_uninitialized_generic!(nrows1.mul(nrows2), ncols1.mul(ncols2))
};
{
let mut data_res = res.data.ptr_mut();
let mut res = Matrix::uninit(nrows1.mul(nrows2), ncols1.mul(ncols2));
let mut data_res = res.data.ptr_mut();
unsafe {
for j1 in 0..ncols1.value() {
for j2 in 0..ncols2.value() {
for i1 in 0..nrows1.value() {
unsafe {
let coeff = self.get_unchecked((i1, j1)).inlined_clone();
let coeff = self.get_unchecked((i1, j1)).clone();
for i2 in 0..nrows2.value() {
*data_res = coeff.inlined_clone()
* rhs.get_unchecked((i2, j2)).inlined_clone();
data_res = data_res.offset(1);
}
for i2 in 0..nrows2.value() {
*data_res = MaybeUninit::new(
coeff.clone() * rhs.get_unchecked((i2, j2)).clone(),
);
data_res = data_res.offset(1);
}
}
}
}
}
res
// SAFETY: the result matrix has been initialized by the loop above.
res.assume_init()
}
}
}

View File

@ -8,8 +8,9 @@ use crate::base::allocator::Allocator;
use crate::base::dimension::{Dim, DimMin};
use crate::base::storage::Storage;
use crate::base::{DefaultAllocator, Matrix, Scalar, SquareMatrix};
use crate::RawStorage;
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// The total number of elements of this matrix.
///
/// # Examples:
@ -59,7 +60,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
pub fn is_identity(&self, eps: T::Epsilon) -> bool
where
T: Zero + One + RelativeEq,
T::Epsilon: Copy,
T::Epsilon: Clone,
{
let (nrows, ncols) = self.shape();
let d;
@ -69,7 +70,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
for i in d..nrows {
for j in 0..ncols {
if !relative_eq!(self[(i, j)], T::zero(), epsilon = eps) {
if !relative_eq!(self[(i, j)], T::zero(), epsilon = eps.clone()) {
return false;
}
}
@ -80,7 +81,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
for i in 0..nrows {
for j in d..ncols {
if !relative_eq!(self[(i, j)], T::zero(), epsilon = eps) {
if !relative_eq!(self[(i, j)], T::zero(), epsilon = eps.clone()) {
return false;
}
}
@ -91,8 +92,8 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
for i in 1..d {
for j in 0..i {
// TODO: use unsafe indexing.
if !relative_eq!(self[(i, j)], T::zero(), epsilon = eps)
|| !relative_eq!(self[(j, i)], T::zero(), epsilon = eps)
if !relative_eq!(self[(i, j)], T::zero(), epsilon = eps.clone())
|| !relative_eq!(self[(j, i)], T::zero(), epsilon = eps.clone())
{
return false;
}
@ -101,7 +102,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
// Diagonal elements of the sub-square matrix.
for i in 0..d {
if !relative_eq!(self[(i, i)], T::one(), epsilon = eps) {
if !relative_eq!(self[(i, i)], T::one(), epsilon = eps.clone()) {
return false;
}
}
@ -121,7 +122,7 @@ impl<T: ComplexField, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
where
T: Zero + One + ClosedAdd + ClosedMul + RelativeEq,
S: Storage<T, R, C>,
T::Epsilon: Copy,
T::Epsilon: Clone,
DefaultAllocator: Allocator<T, R, C> + Allocator<T, C, C>,
{
(self.ad_mul(self)).is_identity(eps)

View File

@ -1,29 +1,8 @@
use std::any::Any;
use std::any::TypeId;
use std::fmt::Debug;
/// The basic scalar type for all structures of `nalgebra`.
///
/// This does not make any assumption on the algebraic properties of `Self`.
pub trait Scalar: Clone + PartialEq + Debug + Any {
#[inline]
/// Tests if `Self` the same as the type `T`
///
/// Typically used to test of `Self` is a f32 or a f64 with `T::is::<f32>()`.
fn is<T: Scalar>() -> bool {
TypeId::of::<Self>() == TypeId::of::<T>()
}
pub trait Scalar: 'static + Clone + PartialEq + Debug {}
#[inline(always)]
/// Performance hack: Clone doesn't get inlined for Copy types in debug mode, so make it inline anyway.
fn inlined_clone(&self) -> Self {
self.clone()
}
}
impl<T: Copy + PartialEq + Debug + Any> Scalar for T {
#[inline(always)]
fn inlined_clone(&self) -> T {
*self
}
}
impl<T: 'static + Clone + PartialEq + Debug> Scalar for T {}

View File

@ -1,34 +1,36 @@
use crate::allocator::Allocator;
use crate::storage::Storage;
use crate::storage::RawStorage;
use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorSlice, U1};
use num::Zero;
use simba::scalar::{ClosedAdd, Field, SupersetOf};
use std::mem::MaybeUninit;
/// # Folding on columns and rows
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/// Returns a row vector where each element is the result of the application of `f` on the
/// corresponding column of the original matrix.
#[inline]
#[must_use]
pub fn compress_rows(
&self,
f: impl Fn(VectorSlice<T, R, S::RStride, S::CStride>) -> T,
f: impl Fn(VectorSlice<'_, T, R, S::RStride, S::CStride>) -> T,
) -> RowOVector<T, C>
where
DefaultAllocator: Allocator<T, U1, C>,
{
let ncols = self.data.shape().1;
let mut res: RowOVector<T, C> =
unsafe { crate::unimplemented_or_uninitialized_generic!(Const::<1>, ncols) };
let ncols = self.shape_generic().1;
let mut res = Matrix::uninit(Const::<1>, ncols);
for i in 0..ncols.value() {
// TODO: avoid bound checking of column.
// Safety: all indices are in range.
unsafe {
*res.get_unchecked_mut((0, i)) = f(self.column(i));
*res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i)));
}
}
res
// Safety: res is now fully initialized.
unsafe { res.assume_init() }
}
/// Returns a column vector where each element is the result of the application of `f` on the
@ -39,23 +41,24 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
#[must_use]
pub fn compress_rows_tr(
&self,
f: impl Fn(VectorSlice<T, R, S::RStride, S::CStride>) -> T,
f: impl Fn(VectorSlice<'_, T, R, S::RStride, S::CStride>) -> T,
) -> OVector<T, C>
where
DefaultAllocator: Allocator<T, C>,
{
let ncols = self.data.shape().1;
let mut res: OVector<T, C> =
unsafe { crate::unimplemented_or_uninitialized_generic!(ncols, Const::<1>) };
let ncols = self.shape_generic().1;
let mut res = Matrix::uninit(ncols, Const::<1>);
for i in 0..ncols.value() {
// TODO: avoid bound checking of column.
// Safety: all indices are in range.
unsafe {
*res.vget_unchecked_mut(i) = f(self.column(i));
*res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i)));
}
}
res
// Safety: res is now fully initialized.
unsafe { res.assume_init() }
}
/// Returns a column vector resulting from the folding of `f` on each column of this matrix.
@ -64,7 +67,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
pub fn compress_columns(
&self,
init: OVector<T, R>,
f: impl Fn(&mut OVector<T, R>, VectorSlice<T, R, S::RStride, S::CStride>),
f: impl Fn(&mut OVector<T, R>, VectorSlice<'_, T, R, S::RStride, S::CStride>),
) -> OVector<T, R>
where
DefaultAllocator: Allocator<T, R>,
@ -80,7 +83,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
}
/// # Common statistics operations
impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
impl<T: Scalar, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
/*
*
* Sum computation.
@ -108,7 +111,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
/// The sum of all the rows of this matrix.
///
/// Use `.row_variance_tr` if you need the result in a column vector instead.
/// Use `.row_sum_tr` if you need the result in a column vector instead.
///
/// # Example
///
@ -180,7 +183,7 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: ClosedAdd + Zero,
DefaultAllocator: Allocator<T, R>,
{
let nrows = self.data.shape().0;
let nrows = self.shape_generic().0;
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
*out += col;
})
@ -213,11 +216,11 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T::zero()
} else {
let val = self.iter().cloned().fold((T::zero(), T::zero()), |a, b| {
(a.0 + b.inlined_clone() * b.inlined_clone(), a.1 + 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.inlined_clone();
val.0 * denom - vd.inlined_clone() * vd
let vd = val.1 * denom.clone();
val.0 * denom - vd.clone() * vd
}
}
@ -283,18 +286,17 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: Field + SupersetOf<f64>,
DefaultAllocator: Allocator<T, R>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
let mut mean = self.column_mean();
mean.apply(|e| -(e.inlined_clone() * e));
mean.apply(|e| *e = -(e.clone() * e.clone()));
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
self.compress_columns(mean, |out, col| {
for i in 0..nrows.value() {
unsafe {
let val = col.vget_unchecked(i);
*out.vget_unchecked_mut(i) +=
denom.inlined_clone() * val.inlined_clone() * val.inlined_clone()
*out.vget_unchecked_mut(i) += denom.clone() * val.clone() * val.clone()
}
}
})
@ -391,10 +393,10 @@ impl<T: Scalar, R: Dim, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S> {
T: Field + SupersetOf<f64>,
DefaultAllocator: Allocator<T, R>,
{
let (nrows, ncols) = self.data.shape();
let (nrows, ncols) = self.shape_generic();
let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64);
self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| {
out.axpy(denom.inlined_clone(), &col, T::one())
out.axpy(denom.clone(), &col, T::one())
})
}
}

View File

@ -1,6 +1,5 @@
//! Abstract definition of a matrix data storage.
use std::fmt::Debug;
use std::ptr;
use crate::base::allocator::{Allocator, SameShapeC, SameShapeR};
@ -19,24 +18,30 @@ pub type SameShapeStorage<T, R1, C1, R2, C2> =
/// The owned data storage that can be allocated from `S`.
pub type Owned<T, R, C = U1> = <DefaultAllocator as Allocator<T, R, C>>::Buffer;
/// The owned data storage that can be allocated from `S`.
pub type OwnedUninit<T, R, C = U1> = <DefaultAllocator as Allocator<T, R, C>>::BufferUninit;
/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`.
pub type RStride<T, R, C = U1> =
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as Storage<T, R, C>>::RStride;
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as RawStorage<T, R, C>>::RStride;
/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`.
pub type CStride<T, R, C = U1> =
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as Storage<T, R, C>>::CStride;
<<DefaultAllocator as Allocator<T, R, C>>::Buffer as RawStorage<T, R, C>>::CStride;
/// The trait shared by all matrix data storage.
///
/// TODO: doc
/// 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<T>` elements.
///
/// 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<T: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
pub unsafe trait RawStorage<T, R: Dim, C: Dim = U1>: Sized {
/// The static stride of this storage's rows.
type RStride: Dim;
@ -121,7 +126,10 @@ pub unsafe trait Storage<T: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
///
/// Call the safe alternative `matrix.as_slice()` instead.
unsafe fn as_slice_unchecked(&self) -> &[T];
}
/// Trait shared by all matrix data storage that dont contain any uninitialized elements.
pub unsafe trait Storage<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
/// Builds a matrix data storage that does not contain any reference.
fn into_owned(self) -> Owned<T, R, C>
where
@ -135,10 +143,14 @@ pub unsafe trait Storage<T: Scalar, R: Dim, C: Dim = U1>: Debug + Sized {
/// Trait implemented by matrix data storage that can provide a mutable access to its elements.
///
/// 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<T>` 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
/// contains only an internal reference to them).
pub unsafe trait StorageMut<T: Scalar, R: Dim, C: Dim = U1>: Storage<T, R, C> {
pub unsafe trait RawStorageMut<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
/// The matrix mutable data pointer.
fn ptr_mut(&mut self) -> *mut T;
@ -213,40 +225,29 @@ pub unsafe trait StorageMut<T: Scalar, R: Dim, C: Dim = U1>: Storage<T, R, C> {
unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T];
}
/// A matrix storage that is stored contiguously in memory.
///
/// 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.
pub unsafe trait ContiguousStorage<T: Scalar, R: Dim, C: Dim = U1>:
Storage<T, R, C>
/// Trait shared by all mutable matrix data storage that dont contain any uninitialized elements.
pub unsafe trait StorageMut<T, R: Dim, C: Dim = U1>:
Storage<T, R, C> + RawStorageMut<T, R, C>
{
/// Converts this data storage to a contiguous slice.
fn as_slice(&self) -> &[T] {
// SAFETY: this is safe because this trait guarantees the fact
// that the data is stored contiguously.
unsafe { self.as_slice_unchecked() }
}
}
/// A mutable matrix storage that is stored contiguously in memory.
unsafe impl<S, T, R, C> StorageMut<T, R, C> for S
where
R: Dim,
C: Dim,
S: Storage<T, R, C> + RawStorageMut<T, R, C>,
{
}
/// Marker trait indicating that a storage is stored contiguously in memory.
///
/// 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.
pub unsafe trait ContiguousStorageMut<T: Scalar, R: Dim, C: Dim = U1>:
ContiguousStorage<T, R, C> + StorageMut<T, R, C>
{
/// Converts this data storage to a contiguous mutable slice.
fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: this is safe because this trait guarantees the fact
// that the data is stored contiguously.
unsafe { self.as_mut_slice_unchecked() }
}
}
pub unsafe trait IsContiguous {}
/// A matrix storage that can be reshaped in-place.
pub trait ReshapableStorage<T, R1, C1, R2, C2>: Storage<T, R1, C1>
pub trait ReshapableStorage<T, R1, C1, R2, C2>: RawStorage<T, R1, C1>
where
T: Scalar,
R1: Dim,
@ -255,7 +256,7 @@ where
C2: Dim,
{
/// The reshaped storage type.
type Output: Storage<T, R2, C2>;
type Output: RawStorage<T, R2, C2>;
/// Reshapes the storage into the output storage type.
fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output;

View File

@ -1,5 +1,5 @@
use crate::base::{DimName, Scalar, ToTypenum, Vector, Vector2, Vector3};
use crate::storage::Storage;
use crate::storage::RawStorage;
use typenum::{self, Cmp, Greater};
macro_rules! impl_swizzle {
@ -11,7 +11,7 @@ macro_rules! impl_swizzle {
#[must_use]
pub fn $name(&self) -> $Result<T>
where D::Typenum: Cmp<typenum::$BaseDim, Output=Greater> {
$Result::new($(self[$i].inlined_clone()),*)
$Result::new($(self[$i].clone()),*)
}
)*
)*
@ -19,7 +19,7 @@ macro_rules! impl_swizzle {
}
/// # Swizzling
impl<T: Scalar, D, S: Storage<T, D>> Vector<T, D, S>
impl<T: Scalar, D, S: RawStorage<T, D>> Vector<T, D, S>
where
D: DimName + ToTypenum,
{

76
src/base/uninit.rs Normal file
View File

@ -0,0 +1,76 @@
use std::mem::MaybeUninit;
/// This trait is used to write code that may work on matrices that may or may not
/// be initialized.
///
/// This trait is used to describe how a value must be accessed to initialize it or
/// to retrieve a reference or mutable reference. Typically, a function accepting
/// both initialized and uninitialized inputs should have a `Status: InitStatus<T>`
/// type parameter. Then the methods of the `Status` can be used to access the element.
///
/// # Safety
/// This trait must not be implemented outside of this crate.
pub unsafe trait InitStatus<T>: Copy {
/// The type of the values with the initialization status described by `Self`.
type Value;
/// Initialize the given element.
fn init(out: &mut Self::Value, t: T);
/// Retrieve a reference to the element, assuming that it is initialized.
///
/// # Safety
/// This is unsound if the referenced value isnt initialized.
unsafe fn assume_init_ref(t: &Self::Value) -> &T;
/// Retrieve a mutable reference to the element, assuming that it is initialized.
///
/// # Safety
/// This is unsound if the referenced value isnt initialized.
unsafe fn assume_init_mut(t: &mut Self::Value) -> &mut T;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// 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.
pub struct Uninit;
unsafe impl<T> InitStatus<T> for Init {
type Value = T;
#[inline(always)]
fn init(out: &mut T, t: T) {
*out = t;
}
#[inline(always)]
unsafe fn assume_init_ref(t: &T) -> &T {
t
}
#[inline(always)]
unsafe fn assume_init_mut(t: &mut T) -> &mut T {
t
}
}
unsafe impl<T> InitStatus<T> for Uninit {
type Value = MaybeUninit<T>;
#[inline(always)]
fn init(out: &mut MaybeUninit<T>, t: T) {
*out = MaybeUninit::new(t);
}
#[inline(always)]
unsafe fn assume_init_ref(t: &MaybeUninit<T>) -> &T {
std::mem::transmute(t.as_ptr()) // TODO: use t.assume_init_ref()
}
#[inline(always)]
unsafe fn assume_init_mut(t: &mut MaybeUninit<T>) -> &mut T {
std::mem::transmute(t.as_mut_ptr()) // TODO: use t.assume_init_mut()
}
}

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