commit
fef43a6146
29
CHANGELOG.md
29
CHANGELOG.md
@ -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`.
|
||||
|
15
Cargo.toml
15
Cargo.toml
@ -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
2
clippy.toml
Normal file
@ -0,0 +1,2 @@
|
||||
too-many-arguments-threshold = 8
|
||||
type-complexity-threshold = 675
|
@ -4,7 +4,7 @@ version = "0.0.0"
|
||||
authors = [ "You" ]
|
||||
|
||||
[dependencies]
|
||||
nalgebra = "0.28.0"
|
||||
nalgebra = "0.29.0"
|
||||
|
||||
[[bin]]
|
||||
name = "example"
|
||||
|
@ -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 }
|
||||
|
@ -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>;
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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!()
|
||||
//}
|
||||
|
@ -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>,
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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!()
|
||||
//}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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.
|
||||
|
@ -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!()
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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!()
|
||||
//}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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!()
|
||||
//}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 {}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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]);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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])
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -0,0 +1,3 @@
|
||||
edition = "2018"
|
||||
use_try_shorthand = true
|
||||
use_field_init_shorthand = true
|
@ -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.**
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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 couldn’t 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))
|
||||
}
|
||||
}
|
||||
|
382
src/base/blas.rs
382
src/base/blas.rs
@ -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
321
src/base/blas_uninit.rs
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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]),*]
|
||||
};
|
||||
);
|
||||
|
||||
|
@ -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()
|
||||
})
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -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 don’t care about dropping elements because the caller is responsible for dropping things.
|
||||
// - We forget `buf` so that we don’t 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 don’t care about dropping elements because the caller is responsible for dropping things.
|
||||
// - We forget `buf` so that we don’t 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 don’t care about dropping elements because the caller is responsible for dropping things.
|
||||
// - We forget `buf` so that we don’t 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)
|
||||
}
|
||||
|
@ -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`
|
||||
// won’t 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
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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::*;
|
||||
|
@ -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();
|
||||
|
168
src/base/ops.rs
168
src/base/ops.rs
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 {}
|
||||
|
@ -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())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 don’t 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 don’t 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;
|
||||
|
@ -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
76
src/base/uninit.rs
Normal 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 isn’t 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 isn’t 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
Loading…
Reference in New Issue
Block a user