diff --git a/.circleci/Xargo.toml b/.circleci/Xargo.toml new file mode 100644 index 00000000..6bdef96d --- /dev/null +++ b/.circleci/Xargo.toml @@ -0,0 +1,2 @@ +[target.x86_64-unknown-linux-gnu.dependencies] +alloc = {} \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..ee64d771 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,108 @@ +version: 2.1 + +executors: + rust-nightly-executor: + docker: + - image: rustlang/rust:nightly + rust-executor: + docker: + - image: rust:latest + + +jobs: + check-fmt: + executor: rust-executor + steps: + - checkout + - run: + name: install rustfmt + command: rustup component add rustfmt + - run: + name: check formatting + command: cargo fmt -- --check + build-native: + executor: rust-executor + steps: + - checkout + - run: apt-get update + - run: apt-get install -y cmake gfortran libblas-dev liblapack-dev + - run: + name: build --no-default-feature + command: cargo build --no-default-features; + - run: + name: build (default features) + command: cargo build; + - run: + name: build --all-features + command: cargo build --all-features + - run: + name: build nalgebra-glm + command: cargo build -p nalgebra-glm --all-features + - run: + name: build nalgebra-lapack + command: cd nalgebra-lapack; cargo build + test-native: + executor: rust-executor + steps: + - checkout + - run: + name: test + command: cargo test --all-features + - run: + name: test nalgebra-glm + command: cargo test -p nalgebra-glm --all-features + build-wasm: + executor: rust-executor + steps: + - checkout + - run: + name: install cargo-web + command: cargo install -f cargo-web; + - run: + name: build --all-features + command: cargo web build --verbose --target wasm32-unknown-unknown; + - run: + name: build nalgebra-glm + command: cargo build -p nalgebra-glm --all-features + build-no-std: + executor: rust-nightly-executor + steps: + - checkout + - run: + name: install xargo + command: cp .circleci/Xargo.toml .; rustup component add rust-src; cargo install -f xargo; + - run: + name: build + command: xargo build --verbose --no-default-features --target=x86_64-unknown-linux-gnu; + - run: + name: build --features alloc + command: xargo build --verbose --no-default-features --features alloc --target=x86_64-unknown-linux-gnu; + build-nightly: + executor: rust-nightly-executor + steps: + - checkout + - run: + name: build --all-features + command: cargo build --all-features + + +workflows: + version: 2 + build: + jobs: + - check-fmt + - build-native: + requires: + - check-fmt + - build-wasm: + requires: + - check-fmt + - build-no-std: + requires: + - check-fmt + - build-nightly: + requires: + - check-fmt + - test-native: + requires: + - build-native diff --git a/CHANGELOG.md b/CHANGELOG.md index 8be48e79..7487b236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,52 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.19.0] - WIP + +## [0.21.0] +In this release, we are no longer relying on traits from the __alga__ crate for our generic code. +Instead, we use traits from the new [simba](https://crates.io/crates/simba) crate which are both +simpler, and allow for significant optimizations like AoSoA SIMD. + +Refer to the [monthly Rustsim blogpost](https://www.rustsim.org/blog/2020/04/01/this-month-in-rustsim/) +for details about this switch and its benefits. + +### Added + * It is now possible to use SIMD types like `simba::f32x4` as scalar types for nalgebra's matrices and + geometric types. +### Modified + * Use of traits like `alga::general::{RealField, ComplexField}` have now been replaced by + `simba::scalar::{RealField, ComplexField}`. + * The implementation of traits from the __alga__ crate (and well as the dependency to _alga__) are now + omitted unless the `alga` cargo feature is activated. +### Removed + * The `Neg` unary operator is no longer implemented for `UnitComplex` and `UnitQuaternion`. This caused + hard-to-track errors when we mistakenly write, e.g., `-q * v` instead of `-(q * v)`. + * The `na::convert_unchecked` is no longer marked as unsafe. + +## [0.20.0] +### Added + * `cholesky.rank_one_update(...)` which performs a rank-one update on the cholesky decomposition of a matrix. + * `From<&Matrix>` is now implemented for matrix slices. + * `.try_set_magnitude(...)` which sets the magnitude of a vector, while keeping its direction. + * Implementations of `From` and `Into` for the conversion between matrix slices and standard (`&[N]` `&mut [N]`) slices. + +### Modified + * We started some major changes in order to allow non-Copy types to be used as scalar types inside of matrices/vectors. + +## [0.19.0] ### Added * `.remove_rows_at` and `remove_columns_at` which removes a set of rows or columns (specified by indices) from a matrix. + * Several formatting traits have been implemented for all matrices/vectors: `LowerExp`, `UpperExp`, `Octal`, `LowerHex`, + `UpperHex`, `Binary`, `Pointer`. + * `UnitQuaternion::quaternions_mean(...)` which computes the mean rotation of a set of unit quaternions. This implements + the algorithm from _Oshman, Yaakov, and Avishy Carmi, "Attitude estimation from vector observations using a genetic-algorithm-embedded quaternion particle filter." + +### Modified + * It is now possible to get the `min/max` element of unsigned integer matrices. + +### Added to nalgebra-glm + * Some infinite and reversed perspectives: `::infinite_perspective_rh_no`, `::infinite_perspective_rh_zo`, + `::reversed_perspective_rh_zo`, and `::reversed_infinite_perspective_rh_zo`. ## [0.18.0] This release adds full complex number support to nalgebra. This includes all common vector/matrix operations as well diff --git a/Cargo.toml b/Cargo.toml index f25718e3..21a365e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.20.0" +version = "0.21.0" authors = [ "Sébastien Crozet " ] description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices." @@ -21,7 +21,7 @@ path = "src/lib.rs" [features] default = [ "std" ] -std = [ "matrixmultiply", "rand/std", "rand_distr", "alga/std" ] +std = [ "matrixmultiply", "rand/std", "rand_distr", "simba/std" ] stdweb = [ "rand/stdweb" ] arbitrary = [ "quickcheck" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] @@ -39,7 +39,8 @@ num-traits = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false } num-rational = { version = "0.2", default-features = false } approx = { version = "0.3", default-features = false } -alga = { version = "0.9", default-features = false } +simba = { version = "0.1", default-features = false } +alga = { version = "0.9", default-features = false, optional = true } rand_distr = { version = "0.2", optional = true } matrixmultiply = { version = "0.2", optional = true } serde = { version = "1.0", optional = true } @@ -50,9 +51,6 @@ quickcheck = { version = "0.9", optional = true } pest = { version = "2.0", optional = true } pest_derive = { version = "2.0", optional = true } -#[patch.crates-io] -#alga = { git = "https://github.com/rustsim/alga", branch = "dev" } - [dev-dependencies] serde_json = "1.0" rand_xorshift = "0.2" @@ -73,3 +71,6 @@ path = "benches/lib.rs" [profile.bench] lto = true + +#[patch.crates-io] +#simba = { path = "../simba" } \ No newline at end of file diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs index ac983ff4..7b4f85bd 100644 --- a/benches/core/matrix.rs +++ b/benches/core/matrix.rs @@ -50,11 +50,13 @@ fn mat_div_scalar(b: &mut criterion::Criterion) { let a = DMatrix::from_row_slice(1000, 1000, &vec![2.0; 1000000]); let n = 42.0; - b.bench_function("mat_div_scalar", move |bh| bh.iter(|| { - let mut aa = a.clone(); - let mut b = aa.slice_mut((0, 0), (1000, 1000)); - b /= n - })); + b.bench_function("mat_div_scalar", move |bh| { + bh.iter(|| { + let mut aa = a.clone(); + let mut b = aa.slice_mut((0, 0), (1000, 1000)); + b /= n + }) + }); } fn mat100_add_mat100(bench: &mut criterion::Criterion) { @@ -138,9 +140,11 @@ fn copy_from(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(1000, 1000); let mut b = DMatrix::::new_random(1000, 1000); - bench.bench_function("copy_from", move |bh| bh.iter(|| { - b.copy_from(&a); - })); + bench.bench_function("copy_from", move |bh| { + bh.iter(|| { + b.copy_from(&a); + }) + }); } fn axpy(bench: &mut criterion::Criterion) { @@ -148,9 +152,11 @@ fn axpy(bench: &mut criterion::Criterion) { let mut y = DVector::::from_element(100000, 3.0); let a = 42.0; - bench.bench_function("axpy", move |bh| bh.iter(|| { - y.axpy(a, &x, 1.0); - })); + bench.bench_function("axpy", move |bh| { + bh.iter(|| { + y.axpy(a, &x, 1.0); + }) + }); } fn tr_mul_to(bench: &mut criterion::Criterion) { @@ -166,60 +172,57 @@ fn mat_mul_mat(bench: &mut criterion::Criterion) { let b = DMatrix::::new_random(100, 100); let mut ab = DMatrix::::from_element(100, 100, 0.0); - bench.bench_function("mat_mul_mat", move |bh| bh.iter(|| { - test::black_box(a.mul_to(&b, &mut ab)); - })); + bench.bench_function("mat_mul_mat", move |bh| { + bh.iter(|| { + test::black_box(a.mul_to(&b, &mut ab)); + }) + }); } fn mat100_from_fn(bench: &mut criterion::Criterion) { - bench.bench_function("mat100_from_fn", move |bh| bh.iter(|| DMatrix::from_fn(100, 100, |a, b| a + b))); + bench.bench_function("mat100_from_fn", move |bh| { + bh.iter(|| DMatrix::from_fn(100, 100, |a, b| a + b)) + }); } fn mat500_from_fn(bench: &mut criterion::Criterion) { - bench.bench_function("mat500_from_fn", move |bh| bh.iter(|| DMatrix::from_fn(500, 500, |a, b| a + b))); + bench.bench_function("mat500_from_fn", move |bh| { + bh.iter(|| DMatrix::from_fn(500, 500, |a, b| a + b)) + }); } -criterion_group!(matrix, +criterion_group!( + matrix, mat2_mul_m, mat3_mul_m, mat4_mul_m, - mat2_tr_mul_m, mat3_tr_mul_m, mat4_tr_mul_m, - mat2_add_m, mat3_add_m, mat4_add_m, - mat2_sub_m, mat3_sub_m, mat4_sub_m, - mat2_mul_v, mat3_mul_v, mat4_mul_v, - mat2_tr_mul_v, mat3_tr_mul_v, mat4_tr_mul_v, - mat2_mul_s, mat3_mul_s, mat4_mul_s, - mat2_div_s, mat3_div_s, mat4_div_s, - mat2_inv, mat3_inv, mat4_inv, - mat2_transpose, mat3_transpose, mat4_transpose, - mat_div_scalar, mat100_add_mat100, mat4_mul_mat4, diff --git a/benches/core/vector.rs b/benches/core/vector.rs index fd44aedc..2806d034 100644 --- a/benches/core/vector.rs +++ b/benches/core/vector.rs @@ -55,7 +55,9 @@ fn vec10000_axpy_f64(bh: &mut criterion::Criterion) { let b = DVector::new_random(10000); let n = rng.gen::(); - bh.bench_function("vec10000_axpy_f64", move |bh| bh.iter(|| a.axpy(n, &b, 1.0))); + bh.bench_function("vec10000_axpy_f64", move |bh| { + bh.iter(|| a.axpy(n, &b, 1.0)) + }); } fn vec10000_axpy_beta_f64(bh: &mut criterion::Criterion) { @@ -66,7 +68,9 @@ fn vec10000_axpy_beta_f64(bh: &mut criterion::Criterion) { let n = rng.gen::(); let beta = rng.gen::(); - bh.bench_function("vec10000_axpy_beta_f64", move |bh| bh.iter(|| a.axpy(n, &b, beta))); + bh.bench_function("vec10000_axpy_beta_f64", move |bh| { + bh.iter(|| a.axpy(n, &b, beta)) + }); } fn vec10000_axpy_f64_slice(bh: &mut criterion::Criterion) { @@ -76,12 +80,14 @@ fn vec10000_axpy_f64_slice(bh: &mut criterion::Criterion) { let b = DVector::new_random(10000); let n = rng.gen::(); - bh.bench_function("vec10000_axpy_f64_slice", move |bh| bh.iter(|| { - let mut a = a.fixed_rows_mut::(0); - let b = b.fixed_rows::(0); + bh.bench_function("vec10000_axpy_f64_slice", move |bh| { + bh.iter(|| { + let mut a = a.fixed_rows_mut::(0); + let b = b.fixed_rows::(0); - a.axpy(n, &b, 1.0) - })); + a.axpy(n, &b, 1.0) + }) + }); } fn vec10000_axpy_f64_static(bh: &mut criterion::Criterion) { @@ -92,7 +98,9 @@ fn vec10000_axpy_f64_static(bh: &mut criterion::Criterion) { let n = rng.gen::(); // NOTE: for some reasons, it is much faster if the arument are boxed (Box::new(VectorN...)). - bh.bench_function("vec10000_axpy_f64_static", move |bh| bh.iter(|| a.axpy(n, &b, 1.0))); + bh.bench_function("vec10000_axpy_f64_static", move |bh| { + bh.iter(|| a.axpy(n, &b, 1.0)) + }); } fn vec10000_axpy_f32(bh: &mut criterion::Criterion) { @@ -102,7 +110,9 @@ fn vec10000_axpy_f32(bh: &mut criterion::Criterion) { let b = DVector::new_random(10000); let n = rng.gen::(); - bh.bench_function("vec10000_axpy_f32", move |bh| bh.iter(|| a.axpy(n, &b, 1.0))); + bh.bench_function("vec10000_axpy_f32", move |bh| { + bh.iter(|| a.axpy(n, &b, 1.0)) + }); } fn vec10000_axpy_beta_f32(bh: &mut criterion::Criterion) { @@ -113,51 +123,43 @@ fn vec10000_axpy_beta_f32(bh: &mut criterion::Criterion) { let n = rng.gen::(); let beta = rng.gen::(); - bh.bench_function("vec10000_axpy_beta_f32", move |bh| bh.iter(|| a.axpy(n, &b, beta))); + bh.bench_function("vec10000_axpy_beta_f32", move |bh| { + bh.iter(|| a.axpy(n, &b, beta)) + }); } -criterion_group!(vector, +criterion_group!( + vector, vec2_add_v_f32, vec3_add_v_f32, vec4_add_v_f32, - vec2_add_v_f64, vec3_add_v_f64, vec4_add_v_f64, - vec2_sub_v, vec3_sub_v, vec4_sub_v, - vec2_mul_s, vec3_mul_s, vec4_mul_s, - vec2_div_s, vec3_div_s, vec4_div_s, - vec2_dot_f32, vec3_dot_f32, vec4_dot_f32, - vec2_dot_f64, vec3_dot_f64, vec4_dot_f64, - vec3_cross, - vec2_norm, vec3_norm, vec4_norm, - vec2_normalize, vec3_normalize, vec4_normalize, - vec10000_dot_f64, vec10000_dot_f32, - vec10000_axpy_f64, vec10000_axpy_beta_f64, vec10000_axpy_f64_slice, diff --git a/benches/geometry/quaternion.rs b/benches/geometry/quaternion.rs index 326872f3..37c29c01 100644 --- a/benches/geometry/quaternion.rs +++ b/benches/geometry/quaternion.rs @@ -26,7 +26,8 @@ bench_unop!(unit_quaternion_inv, UnitQuaternion, inverse); // bench_unop_self!(quaternion_conjugate, Quaternion, conjugate); // bench_unop!(quaternion_normalize, Quaternion, normalize); -criterion_group!(quaternion, +criterion_group!( + quaternion, quaternion_add_q, quaternion_sub_q, quaternion_mul_q, diff --git a/benches/linalg/bidiagonal.rs b/benches/linalg/bidiagonal.rs index ed126205..ad875264 100644 --- a/benches/linalg/bidiagonal.rs +++ b/benches/linalg/bidiagonal.rs @@ -6,70 +6,89 @@ mod macros; // Without unpack. fn bidiagonalize_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("bidiagonalize_100x100", move |bh| bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))); + bh.bench_function("bidiagonalize_100x100", move |bh| { + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) + }); } fn bidiagonalize_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - bh.bench_function("bidiagonalize_100x500", move |bh| bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))); + bh.bench_function("bidiagonalize_100x500", move |bh| { + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) + }); } fn bidiagonalize_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("bidiagonalize_4x4", move |bh| bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))); + bh.bench_function("bidiagonalize_4x4", move |bh| { + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) + }); } fn bidiagonalize_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - bh.bench_function("bidiagonalize_500x100", move |bh| bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))); + bh.bench_function("bidiagonalize_500x100", move |bh| { + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) + }); } fn bidiagonalize_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("bidiagonalize_500x500", move |bh| bh.iter(|| test::black_box(Bidiagonal::new(m.clone())))); + bh.bench_function("bidiagonalize_500x500", move |bh| { + bh.iter(|| test::black_box(Bidiagonal::new(m.clone()))) + }); } // With unpack. fn bidiagonalize_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("bidiagonalize_unpack_100x100", move |bh| bh.iter(|| { - let bidiag = Bidiagonal::new(m.clone()); - let _ = bidiag.unpack(); - })); + bh.bench_function("bidiagonalize_unpack_100x100", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); } fn bidiagonalize_unpack_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - bh.bench_function("bidiagonalize_unpack_100x500", move |bh| bh.iter(|| { - let bidiag = Bidiagonal::new(m.clone()); - let _ = bidiag.unpack(); - })); + bh.bench_function("bidiagonalize_unpack_100x500", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); } fn bidiagonalize_unpack_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - bh.bench_function("bidiagonalize_unpack_500x100", move |bh| bh.iter(|| { - let bidiag = Bidiagonal::new(m.clone()); - let _ = bidiag.unpack(); - })); + bh.bench_function("bidiagonalize_unpack_500x100", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); } fn bidiagonalize_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("bidiagonalize_unpack_500x500", move |bh| bh.iter(|| { - let bidiag = Bidiagonal::new(m.clone()); - let _ = bidiag.unpack(); - })); + bh.bench_function("bidiagonalize_unpack_500x500", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); } -criterion_group!(bidiagonal, +criterion_group!( + bidiagonal, bidiagonalize_100x100, bidiagonalize_100x500, bidiagonalize_4x4, bidiagonalize_500x100, -// bidiagonalize_500x500, // too long + // bidiagonalize_500x500, // too long bidiagonalize_unpack_100x100, bidiagonalize_unpack_100x500, bidiagonalize_unpack_500x100, -// bidiagonalize_unpack_500x500 // too long -); \ No newline at end of file + // bidiagonalize_unpack_500x500 // too long +); diff --git a/benches/linalg/cholesky.rs b/benches/linalg/cholesky.rs index 40ca9821..a03888f5 100644 --- a/benches/linalg/cholesky.rs +++ b/benches/linalg/cholesky.rs @@ -4,14 +4,18 @@ fn cholesky_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let m = &m * m.transpose(); - bh.bench_function("cholesky_100x100", move |bh| bh.iter(|| test::black_box(Cholesky::new(m.clone())))); + bh.bench_function("cholesky_100x100", move |bh| { + bh.iter(|| test::black_box(Cholesky::new(m.clone()))) + }); } fn cholesky_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let m = &m * m.transpose(); - bh.bench_function("cholesky_500x500", move |bh| bh.iter(|| test::black_box(Cholesky::new(m.clone())))); + bh.bench_function("cholesky_500x500", move |bh| { + bh.iter(|| test::black_box(Cholesky::new(m.clone()))) + }); } // With unpack. @@ -19,19 +23,23 @@ fn cholesky_decompose_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let m = &m * m.transpose(); - bh.bench_function("cholesky_decompose_unpack_100x100", move |bh| bh.iter(|| { - let chol = Cholesky::new(m.clone()).unwrap(); - let _ = chol.unpack(); - })); + bh.bench_function("cholesky_decompose_unpack_100x100", move |bh| { + bh.iter(|| { + let chol = Cholesky::new(m.clone()).unwrap(); + let _ = chol.unpack(); + }) + }); } fn cholesky_decompose_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let m = &m * m.transpose(); - bh.bench_function("cholesky_decompose_unpack_500x500", move |bh| bh.iter(|| { - let chol = Cholesky::new(m.clone()).unwrap(); - let _ = chol.unpack(); - })); + bh.bench_function("cholesky_decompose_unpack_500x500", move |bh| { + bh.iter(|| { + let chol = Cholesky::new(m.clone()).unwrap(); + let _ = chol.unpack(); + }) + }); } fn cholesky_solve_10x10(bh: &mut criterion::Criterion) { @@ -40,9 +48,11 @@ fn cholesky_solve_10x10(bh: &mut criterion::Criterion) { let v = DVector::::new_random(10); let chol = Cholesky::new(m.clone()).unwrap(); - bh.bench_function("cholesky_solve_10x10", move |bh| bh.iter(|| { - let _ = chol.solve(&v); - })); + bh.bench_function("cholesky_solve_10x10", move |bh| { + bh.iter(|| { + let _ = chol.solve(&v); + }) + }); } fn cholesky_solve_100x100(bh: &mut criterion::Criterion) { @@ -51,9 +61,11 @@ fn cholesky_solve_100x100(bh: &mut criterion::Criterion) { let v = DVector::::new_random(100); let chol = Cholesky::new(m.clone()).unwrap(); - bh.bench_function("cholesky_solve_100x100", move |bh| bh.iter(|| { - let _ = chol.solve(&v); - })); + bh.bench_function("cholesky_solve_100x100", move |bh| { + bh.iter(|| { + let _ = chol.solve(&v); + }) + }); } fn cholesky_solve_500x500(bh: &mut criterion::Criterion) { @@ -62,20 +74,23 @@ fn cholesky_solve_500x500(bh: &mut criterion::Criterion) { let v = DVector::::new_random(500); let chol = Cholesky::new(m.clone()).unwrap(); - bh.bench_function("cholesky_solve_500x500", move |bh| bh.iter(|| { - let _ = chol.solve(&v); - })); + bh.bench_function("cholesky_solve_500x500", move |bh| { + bh.iter(|| { + let _ = chol.solve(&v); + }) + }); } - fn cholesky_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let m = &m * m.transpose(); let chol = Cholesky::new(m.clone()).unwrap(); - bh.bench_function("cholesky_inverse_10x10", move |bh| bh.iter(|| { - let _ = chol.inverse(); - })); + bh.bench_function("cholesky_inverse_10x10", move |bh| { + bh.iter(|| { + let _ = chol.inverse(); + }) + }); } fn cholesky_inverse_100x100(bh: &mut criterion::Criterion) { @@ -83,9 +98,11 @@ fn cholesky_inverse_100x100(bh: &mut criterion::Criterion) { let m = &m * m.transpose(); let chol = Cholesky::new(m.clone()).unwrap(); - bh.bench_function("cholesky_inverse_100x100", move |bh| bh.iter(|| { - let _ = chol.inverse(); - })); + bh.bench_function("cholesky_inverse_100x100", move |bh| { + bh.iter(|| { + let _ = chol.inverse(); + }) + }); } fn cholesky_inverse_500x500(bh: &mut criterion::Criterion) { @@ -93,12 +110,15 @@ fn cholesky_inverse_500x500(bh: &mut criterion::Criterion) { let m = &m * m.transpose(); let chol = Cholesky::new(m.clone()).unwrap(); - bh.bench_function("cholesky_inverse_500x500", move |bh| bh.iter(|| { - let _ = chol.inverse(); - })); + bh.bench_function("cholesky_inverse_500x500", move |bh| { + bh.iter(|| { + let _ = chol.inverse(); + }) + }); } -criterion_group!(cholesky, +criterion_group!( + cholesky, cholesky_100x100, cholesky_500x500, cholesky_decompose_unpack_100x100, @@ -109,4 +129,4 @@ criterion_group!(cholesky, cholesky_inverse_10x10, cholesky_inverse_100x100, cholesky_inverse_500x500 -); \ No newline at end of file +); diff --git a/benches/linalg/full_piv_lu.rs b/benches/linalg/full_piv_lu.rs index 6c7b1fa6..dfd176da 100644 --- a/benches/linalg/full_piv_lu.rs +++ b/benches/linalg/full_piv_lu.rs @@ -3,103 +3,127 @@ use na::{DMatrix, DVector, FullPivLU}; // Without unpack. fn full_piv_lu_decompose_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); - bh.bench_function("full_piv_lu_decompose_10x10", move |bh| bh.iter(|| test::black_box(FullPivLU::new(m.clone())))); + bh.bench_function("full_piv_lu_decompose_10x10", move |bh| { + bh.iter(|| test::black_box(FullPivLU::new(m.clone()))) + }); } fn full_piv_lu_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("full_piv_lu_decompose_100x100", move |bh| bh.iter(|| test::black_box(FullPivLU::new(m.clone())))); + bh.bench_function("full_piv_lu_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(FullPivLU::new(m.clone()))) + }); } fn full_piv_lu_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("full_piv_lu_decompose_500x500", move |bh| bh.iter(|| test::black_box(FullPivLU::new(m.clone())))); + bh.bench_function("full_piv_lu_decompose_500x500", move |bh| { + bh.iter(|| test::black_box(FullPivLU::new(m.clone()))) + }); } fn full_piv_lu_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_solve_10x10", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(10, 1.0); - lu.solve(&mut b); - })); + bh.bench_function("full_piv_lu_solve_10x10", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + lu.solve(&mut b); + }) + }); } fn full_piv_lu_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_solve_100x100", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(100, 1.0); - lu.solve(&mut b); - })); + bh.bench_function("full_piv_lu_solve_100x100", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + lu.solve(&mut b); + }) + }); } fn full_piv_lu_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_solve_500x500", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(500, 1.0); - lu.solve(&mut b); - })); + bh.bench_function("full_piv_lu_solve_500x500", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + lu.solve(&mut b); + }) + }); } fn full_piv_lu_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_inverse_10x10", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); + bh.bench_function("full_piv_lu_inverse_10x10", move |bh| { + bh.iter(|| test::black_box(lu.try_inverse())) + }); } fn full_piv_lu_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_inverse_100x100", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); + bh.bench_function("full_piv_lu_inverse_100x100", move |bh| { + bh.iter(|| test::black_box(lu.try_inverse())) + }); } fn full_piv_lu_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_inverse_500x500", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); + bh.bench_function("full_piv_lu_inverse_500x500", move |bh| { + bh.iter(|| test::black_box(lu.try_inverse())) + }); } fn full_piv_lu_determinant_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_determinant_10x10", move |bh| bh.iter(|| test::black_box(lu.determinant()))); + bh.bench_function("full_piv_lu_determinant_10x10", move |bh| { + bh.iter(|| test::black_box(lu.determinant())) + }); } - fn full_piv_lu_determinant_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_determinant_100x100", move |bh| bh.iter(|| test::black_box(lu.determinant()))); + bh.bench_function("full_piv_lu_determinant_100x100", move |bh| { + bh.iter(|| test::black_box(lu.determinant())) + }); } fn full_piv_lu_determinant_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = FullPivLU::new(m.clone()); - bh.bench_function("full_piv_lu_determinant_500x500", move |bh| bh.iter(|| test::black_box(lu.determinant()))); + bh.bench_function("full_piv_lu_determinant_500x500", move |bh| { + bh.iter(|| test::black_box(lu.determinant())) + }); } -criterion_group!(full_piv_lu, +criterion_group!( + full_piv_lu, full_piv_lu_decompose_10x10, full_piv_lu_decompose_100x100, -// full_piv_lu_decompose_500x500, + // full_piv_lu_decompose_500x500, full_piv_lu_solve_10x10, full_piv_lu_solve_100x100, -// full_piv_lu_solve_500x500, + // full_piv_lu_solve_500x500, full_piv_lu_inverse_10x10, full_piv_lu_inverse_100x100, -// full_piv_lu_inverse_500x500, + // full_piv_lu_inverse_500x500, full_piv_lu_determinant_10x10, full_piv_lu_determinant_100x100, -// full_piv_lu_determinant_500x500 -); \ No newline at end of file + // full_piv_lu_determinant_500x500 +); diff --git a/benches/linalg/hessenberg.rs b/benches/linalg/hessenberg.rs index 3340c3ef..a989616c 100644 --- a/benches/linalg/hessenberg.rs +++ b/benches/linalg/hessenberg.rs @@ -6,55 +6,70 @@ mod macros; // Without unpack. fn hessenberg_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("hessenberg_decompose_4x4", move |bh| bh.iter(|| test::black_box(Hessenberg::new(m.clone())))); + bh.bench_function("hessenberg_decompose_4x4", move |bh| { + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) + }); } fn hessenberg_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("hessenberg_decompose_100x100", move |bh| bh.iter(|| test::black_box(Hessenberg::new(m.clone())))); + bh.bench_function("hessenberg_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) + }); } fn hessenberg_decompose_200x200(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(200, 200); - bh.bench_function("hessenberg_decompose_200x200", move |bh| bh.iter(|| test::black_box(Hessenberg::new(m.clone())))); + bh.bench_function("hessenberg_decompose_200x200", move |bh| { + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) + }); } fn hessenberg_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("hessenberg_decompose_500x500", move |bh| bh.iter(|| test::black_box(Hessenberg::new(m.clone())))); + bh.bench_function("hessenberg_decompose_500x500", move |bh| { + bh.iter(|| test::black_box(Hessenberg::new(m.clone()))) + }); } // With unpack. fn hessenberg_decompose_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("hessenberg_decompose_unpack_100x100", move |bh| bh.iter(|| { - let hess = Hessenberg::new(m.clone()); - let _ = hess.unpack(); - })); + bh.bench_function("hessenberg_decompose_unpack_100x100", move |bh| { + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) + }); } fn hessenberg_decompose_unpack_200x200(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(200, 200); - bh.bench_function("hessenberg_decompose_unpack_200x200", move |bh| bh.iter(|| { - let hess = Hessenberg::new(m.clone()); - let _ = hess.unpack(); - })); + bh.bench_function("hessenberg_decompose_unpack_200x200", move |bh| { + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) + }); } fn hessenberg_decompose_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("hessenberg_decompose_unpack_500x500", move |bh| bh.iter(|| { - let hess = Hessenberg::new(m.clone()); - let _ = hess.unpack(); - })); + bh.bench_function("hessenberg_decompose_unpack_500x500", move |bh| { + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) + }); } -criterion_group!(hessenberg, +criterion_group!( + hessenberg, hessenberg_decompose_4x4, hessenberg_decompose_100x100, hessenberg_decompose_200x200, -// hessenberg_decompose_500x500, + // hessenberg_decompose_500x500, hessenberg_decompose_unpack_100x100, hessenberg_decompose_unpack_200x200, -// hessenberg_decompose_unpack_500x500 -); \ No newline at end of file + // hessenberg_decompose_unpack_500x500 +); diff --git a/benches/linalg/lu.rs b/benches/linalg/lu.rs index e37cfe75..c42cd499 100644 --- a/benches/linalg/lu.rs +++ b/benches/linalg/lu.rs @@ -3,82 +3,104 @@ use na::{DMatrix, DVector, LU}; // Without unpack. fn lu_decompose_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); - bh.bench_function("lu_decompose_10x10", move |bh| bh.iter(|| test::black_box(LU::new(m.clone())))); + bh.bench_function("lu_decompose_10x10", move |bh| { + bh.iter(|| test::black_box(LU::new(m.clone()))) + }); } fn lu_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("lu_decompose_100x100", move |bh| bh.iter(|| test::black_box(LU::new(m.clone())))); + bh.bench_function("lu_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(LU::new(m.clone()))) + }); } fn lu_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("lu_decompose_500x500", move |bh| bh.iter(|| test::black_box(LU::new(m.clone())))); + bh.bench_function("lu_decompose_500x500", move |bh| { + bh.iter(|| test::black_box(LU::new(m.clone()))) + }); } fn lu_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = LU::new(m.clone()); - bh.bench_function("lu_solve_10x10", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(10, 1.0); - lu.solve(&mut b); - })); + bh.bench_function("lu_solve_10x10", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + lu.solve(&mut b); + }) + }); } fn lu_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = LU::new(m.clone()); - bh.bench_function("lu_solve_100x100", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(100, 1.0); - lu.solve(&mut b); - })); + bh.bench_function("lu_solve_100x100", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + lu.solve(&mut b); + }) + }); } fn lu_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = LU::new(m.clone()); - bh.bench_function("", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(500, 1.0); - lu.solve(&mut b); - })); + bh.bench_function("", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + lu.solve(&mut b); + }) + }); } fn lu_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = LU::new(m.clone()); - bh.bench_function("lu_inverse_10x10", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); + bh.bench_function("lu_inverse_10x10", move |bh| { + bh.iter(|| test::black_box(lu.try_inverse())) + }); } fn lu_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = LU::new(m.clone()); - bh.bench_function("lu_inverse_100x100", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); + bh.bench_function("lu_inverse_100x100", move |bh| { + bh.iter(|| test::black_box(lu.try_inverse())) + }); } fn lu_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = LU::new(m.clone()); - bh.bench_function("lu_inverse_500x500", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); + bh.bench_function("lu_inverse_500x500", move |bh| { + bh.iter(|| test::black_box(lu.try_inverse())) + }); } fn lu_determinant_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = LU::new(m.clone()); - bh.bench_function("lu_determinant_10x10", move |bh| bh.iter(|| test::black_box(lu.determinant()))); + bh.bench_function("lu_determinant_10x10", move |bh| { + bh.iter(|| test::black_box(lu.determinant())) + }); } fn lu_determinant_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = LU::new(m.clone()); - bh.bench_function("lu_determinant_100x100", move |bh| bh.iter(|| test::black_box(lu.determinant()))); + bh.bench_function("lu_determinant_100x100", move |bh| { + bh.iter(|| test::black_box(lu.determinant())) + }); } fn lu_determinant_500x500(bh: &mut criterion::Criterion) { @@ -88,15 +110,16 @@ fn lu_determinant_500x500(bh: &mut criterion::Criterion) { bh.bench_function("", move |bh| bh.iter(|| test::black_box(lu.determinant()))); } -criterion_group!(lu, +criterion_group!( + lu, lu_decompose_10x10, lu_decompose_100x100, -// lu_decompose_500x500, + // lu_decompose_500x500, lu_solve_10x10, lu_solve_100x100, lu_inverse_10x10, lu_inverse_100x100, -// lu_inverse_500x500, + // lu_inverse_500x500, lu_determinant_10x10, lu_determinant_100x100 -); \ No newline at end of file +); diff --git a/benches/linalg/mod.rs b/benches/linalg/mod.rs index a6e7a8ef..cbd4df4a 100644 --- a/benches/linalg/mod.rs +++ b/benches/linalg/mod.rs @@ -19,4 +19,4 @@ mod schur; mod solve; mod svd; mod symmetric_eigen; -// mod eigen; \ No newline at end of file +// mod eigen; diff --git a/benches/linalg/qr.rs b/benches/linalg/qr.rs index 8283c5e9..d896f978 100644 --- a/benches/linalg/qr.rs +++ b/benches/linalg/qr.rs @@ -6,128 +6,158 @@ mod macros; // Without unpack. fn qr_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("qr_decompose_100x100", move |bh| bh.iter(|| test::black_box(QR::new(m.clone())))); + bh.bench_function("qr_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(QR::new(m.clone()))) + }); } fn qr_decompose_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - bh.bench_function("qr_decompose_100x500", move |bh| bh.iter(|| test::black_box(QR::new(m.clone())))); + bh.bench_function("qr_decompose_100x500", move |bh| { + bh.iter(|| test::black_box(QR::new(m.clone()))) + }); } fn qr_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("qr_decompose_4x4", move |bh| bh.iter(|| test::black_box(QR::new(m.clone())))); + bh.bench_function("qr_decompose_4x4", move |bh| { + bh.iter(|| test::black_box(QR::new(m.clone()))) + }); } fn qr_decompose_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - bh.bench_function("qr_decompose_500x100", move |bh| bh.iter(|| test::black_box(QR::new(m.clone())))); + bh.bench_function("qr_decompose_500x100", move |bh| { + bh.iter(|| test::black_box(QR::new(m.clone()))) + }); } fn qr_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("qr_decompose_500x500", move |bh| bh.iter(|| test::black_box(QR::new(m.clone())))); + bh.bench_function("qr_decompose_500x500", move |bh| { + bh.iter(|| test::black_box(QR::new(m.clone()))) + }); } // With unpack. fn qr_decompose_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.bench_function("qr_decompose_unpack_100x100", move |bh| bh.iter(|| { - let qr = QR::new(m.clone()); - let _ = qr.unpack(); - })); + bh.bench_function("qr_decompose_unpack_100x100", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); } fn qr_decompose_unpack_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - bh.bench_function("qr_decompose_unpack_100x500", move |bh| bh.iter(|| { - let qr = QR::new(m.clone()); - let _ = qr.unpack(); - })); + bh.bench_function("qr_decompose_unpack_100x500", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); } fn qr_decompose_unpack_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - bh.bench_function("qr_decompose_unpack_500x100", move |bh| bh.iter(|| { - let qr = QR::new(m.clone()); - let _ = qr.unpack(); - })); + bh.bench_function("qr_decompose_unpack_500x100", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); } fn qr_decompose_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.bench_function("qr_decompose_unpack_500x500", move |bh| bh.iter(|| { - let qr = QR::new(m.clone()); - let _ = qr.unpack(); - })); + bh.bench_function("qr_decompose_unpack_500x500", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); } fn qr_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let qr = QR::new(m.clone()); - bh.bench_function("qr_solve_10x10", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(10, 1.0); - qr.solve(&mut b); - })); + bh.bench_function("qr_solve_10x10", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + qr.solve(&mut b); + }) + }); } fn qr_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let qr = QR::new(m.clone()); - bh.bench_function("qr_solve_100x100", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(100, 1.0); - qr.solve(&mut b); - })); + bh.bench_function("qr_solve_100x100", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + qr.solve(&mut b); + }) + }); } fn qr_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let qr = QR::new(m.clone()); - bh.bench_function("qr_solve_500x500", move |bh| bh.iter(|| { - let mut b = DVector::::from_element(500, 1.0); - qr.solve(&mut b); - })); + bh.bench_function("qr_solve_500x500", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + qr.solve(&mut b); + }) + }); } fn qr_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let qr = QR::new(m.clone()); - bh.bench_function("qr_inverse_10x10", move |bh| bh.iter(|| test::black_box(qr.try_inverse()))); + bh.bench_function("qr_inverse_10x10", move |bh| { + bh.iter(|| test::black_box(qr.try_inverse())) + }); } fn qr_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let qr = QR::new(m.clone()); - bh.bench_function("qr_inverse_100x100", move |bh| bh.iter(|| test::black_box(qr.try_inverse()))); + bh.bench_function("qr_inverse_100x100", move |bh| { + bh.iter(|| test::black_box(qr.try_inverse())) + }); } fn qr_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let qr = QR::new(m.clone()); - bh.bench_function("qr_inverse_500x500", move |bh| bh.iter(|| test::black_box(qr.try_inverse()))); + bh.bench_function("qr_inverse_500x500", move |bh| { + bh.iter(|| test::black_box(qr.try_inverse())) + }); } - -criterion_group!(qr, +criterion_group!( + qr, qr_decompose_100x100, qr_decompose_100x500, qr_decompose_4x4, qr_decompose_500x100, -// qr_decompose_500x500, + // qr_decompose_500x500, qr_decompose_unpack_100x100, qr_decompose_unpack_100x500, qr_decompose_unpack_500x100, -// qr_decompose_unpack_500x500, + // qr_decompose_unpack_500x500, qr_solve_10x10, qr_solve_100x100, -// qr_solve_500x500, + // qr_solve_500x500, qr_inverse_10x10, qr_inverse_100x100, -// qr_inverse_500x500 -); \ No newline at end of file + // qr_inverse_500x500 +); diff --git a/benches/linalg/schur.rs b/benches/linalg/schur.rs index ffabc539..e4193a25 100644 --- a/benches/linalg/schur.rs +++ b/benches/linalg/schur.rs @@ -2,45 +2,62 @@ use na::{Matrix4, Schur}; fn schur_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("schur_decompose_4x4", move |bh| bh.iter(|| test::black_box(Schur::new(m.clone())))); + bh.bench_function("schur_decompose_4x4", move |bh| { + bh.iter(|| test::black_box(Schur::new(m.clone()))) + }); } fn schur_decompose_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("schur_decompose_10x10", move |bh| bh.iter(|| test::black_box(Schur::new(m.clone())))); + bh.bench_function("schur_decompose_10x10", move |bh| { + bh.iter(|| test::black_box(Schur::new(m.clone()))) + }); } fn schur_decompose_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("schur_decompose_100x100", move |bh| bh.iter(|| test::black_box(Schur::new(m.clone())))); + bh.bench_function("schur_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(Schur::new(m.clone()))) + }); } fn schur_decompose_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("schur_decompose_200x200", move |bh| bh.iter(|| test::black_box(Schur::new(m.clone())))); + bh.bench_function("schur_decompose_200x200", move |bh| { + bh.iter(|| test::black_box(Schur::new(m.clone()))) + }); } fn eigenvalues_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("eigenvalues_4x4", move |bh| bh.iter(|| test::black_box(m.complex_eigenvalues()))); + bh.bench_function("eigenvalues_4x4", move |bh| { + bh.iter(|| test::black_box(m.complex_eigenvalues())) + }); } fn eigenvalues_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("eigenvalues_10x10", move |bh| bh.iter(|| test::black_box(m.complex_eigenvalues()))); + bh.bench_function("eigenvalues_10x10", move |bh| { + bh.iter(|| test::black_box(m.complex_eigenvalues())) + }); } fn eigenvalues_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("eigenvalues_100x100", move |bh| bh.iter(|| test::black_box(m.complex_eigenvalues()))); + bh.bench_function("eigenvalues_100x100", move |bh| { + bh.iter(|| test::black_box(m.complex_eigenvalues())) + }); } fn eigenvalues_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("eigenvalues_200x200", move |bh| bh.iter(|| test::black_box(m.complex_eigenvalues()))); + bh.bench_function("eigenvalues_200x200", move |bh| { + bh.iter(|| test::black_box(m.complex_eigenvalues())) + }); } -criterion_group!(schur, +criterion_group!( + schur, schur_decompose_4x4, schur_decompose_10x10, schur_decompose_100x100, @@ -49,4 +66,4 @@ criterion_group!(schur, eigenvalues_10x10, eigenvalues_100x100, eigenvalues_200x200 -); \ No newline at end of file +); diff --git a/benches/linalg/solve.rs b/benches/linalg/solve.rs index 51c6db59..82545cd1 100644 --- a/benches/linalg/solve.rs +++ b/benches/linalg/solve.rs @@ -4,76 +4,92 @@ fn solve_l_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.bench_function("solve_l_triangular_100x100", move |bh| bh.iter(|| { - let _ = m.solve_lower_triangular(&v); - })); + bh.bench_function("solve_l_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.solve_lower_triangular(&v); + }) + }); } fn solve_l_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.bench_function("solve_l_triangular_1000x1000", move |bh| bh.iter(|| { - let _ = m.solve_lower_triangular(&v); - })); + bh.bench_function("solve_l_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.solve_lower_triangular(&v); + }) + }); } fn tr_solve_l_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.bench_function("tr_solve_l_triangular_100x100", move |bh| bh.iter(|| { - let _ = m.tr_solve_lower_triangular(&v); - })); + bh.bench_function("tr_solve_l_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_lower_triangular(&v); + }) + }); } fn tr_solve_l_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.bench_function("tr_solve_l_triangular_1000x1000", move |bh| bh.iter(|| { - let _ = m.tr_solve_lower_triangular(&v); - })); + bh.bench_function("tr_solve_l_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_lower_triangular(&v); + }) + }); } fn solve_u_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.bench_function("solve_u_triangular_100x100", move |bh| bh.iter(|| { - let _ = m.solve_upper_triangular(&v); - })); + bh.bench_function("solve_u_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.solve_upper_triangular(&v); + }) + }); } fn solve_u_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.bench_function("solve_u_triangular_1000x1000", move |bh| bh.iter(|| { - let _ = m.solve_upper_triangular(&v); - })); + bh.bench_function("solve_u_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.solve_upper_triangular(&v); + }) + }); } fn tr_solve_u_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.bench_function("tr_solve_u_triangular_100x100", move |bh| bh.iter(|| { - let _ = m.tr_solve_upper_triangular(&v); - })); + bh.bench_function("tr_solve_u_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_upper_triangular(&v); + }) + }); } fn tr_solve_u_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.bench_function("tr_solve_u_triangular_1000x1000", move |bh| bh.iter(|| { - let _ = m.tr_solve_upper_triangular(&v); - })); + bh.bench_function("tr_solve_u_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_upper_triangular(&v); + }) + }); } - -criterion_group!(solve, +criterion_group!( + solve, solve_l_triangular_100x100, solve_l_triangular_1000x1000, tr_solve_l_triangular_100x100, @@ -82,4 +98,4 @@ criterion_group!(solve, solve_u_triangular_1000x1000, tr_solve_u_triangular_100x100, tr_solve_u_triangular_1000x1000 -); \ No newline at end of file +); diff --git a/benches/linalg/svd.rs b/benches/linalg/svd.rs index 6804147c..aec18fd8 100644 --- a/benches/linalg/svd.rs +++ b/benches/linalg/svd.rs @@ -2,86 +2,118 @@ use na::{Matrix4, SVD}; fn svd_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("svd_decompose_4x4", move |bh| bh.iter(|| test::black_box(SVD::new(m.clone(), true, true)))); + bh.bench_function("svd_decompose_4x4", move |bh| { + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) + }); } fn svd_decompose_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("svd_decompose_10x10", move |bh| bh.iter(|| test::black_box(SVD::new(m.clone(), true, true)))); + bh.bench_function("svd_decompose_10x10", move |bh| { + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) + }); } fn svd_decompose_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("svd_decompose_100x100", move |bh| bh.iter(|| test::black_box(SVD::new(m.clone(), true, true)))); + bh.bench_function("svd_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) + }); } fn svd_decompose_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("svd_decompose_200x200", move |bh| bh.iter(|| test::black_box(SVD::new(m.clone(), true, true)))); + bh.bench_function("svd_decompose_200x200", move |bh| { + bh.iter(|| test::black_box(SVD::new(m.clone(), true, true))) + }); } fn rank_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("rank_4x4", move |bh| bh.iter(|| test::black_box(m.rank(1.0e-10)))); + bh.bench_function("rank_4x4", move |bh| { + bh.iter(|| test::black_box(m.rank(1.0e-10))) + }); } fn rank_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("rank_10x10", move |bh| bh.iter(|| test::black_box(m.rank(1.0e-10)))); + bh.bench_function("rank_10x10", move |bh| { + bh.iter(|| test::black_box(m.rank(1.0e-10))) + }); } fn rank_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("rank_100x100", move |bh| bh.iter(|| test::black_box(m.rank(1.0e-10)))); + bh.bench_function("rank_100x100", move |bh| { + bh.iter(|| test::black_box(m.rank(1.0e-10))) + }); } fn rank_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("rank_200x200", move |bh| bh.iter(|| test::black_box(m.rank(1.0e-10)))); + bh.bench_function("rank_200x200", move |bh| { + bh.iter(|| test::black_box(m.rank(1.0e-10))) + }); } fn singular_values_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("singular_values_4x4", move |bh| bh.iter(|| test::black_box(m.singular_values()))); + bh.bench_function("singular_values_4x4", move |bh| { + bh.iter(|| test::black_box(m.singular_values())) + }); } fn singular_values_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("singular_values_10x10", move |bh| bh.iter(|| test::black_box(m.singular_values()))); + bh.bench_function("singular_values_10x10", move |bh| { + bh.iter(|| test::black_box(m.singular_values())) + }); } fn singular_values_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("singular_values_100x100", move |bh| bh.iter(|| test::black_box(m.singular_values()))); + bh.bench_function("singular_values_100x100", move |bh| { + bh.iter(|| test::black_box(m.singular_values())) + }); } fn singular_values_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("singular_values_200x200", move |bh| bh.iter(|| test::black_box(m.singular_values()))); + bh.bench_function("singular_values_200x200", move |bh| { + bh.iter(|| test::black_box(m.singular_values())) + }); } fn pseudo_inverse_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("pseudo_inverse_4x4", move |bh| bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10)))); + bh.bench_function("pseudo_inverse_4x4", move |bh| { + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); } fn pseudo_inverse_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("pseudo_inverse_10x10", move |bh| bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10)))); + bh.bench_function("pseudo_inverse_10x10", move |bh| { + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); } fn pseudo_inverse_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("pseudo_inverse_100x100", move |bh| bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10)))); + bh.bench_function("pseudo_inverse_100x100", move |bh| { + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); } fn pseudo_inverse_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("pseudo_inverse_200x200", move |bh| bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10)))); + bh.bench_function("pseudo_inverse_200x200", move |bh| { + bh.iter(|| test::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); } - -criterion_group!(svd, +criterion_group!( + svd, svd_decompose_4x4, svd_decompose_10x10, svd_decompose_100x100, @@ -98,4 +130,4 @@ criterion_group!(svd, pseudo_inverse_10x10, pseudo_inverse_100x100, pseudo_inverse_200x200 -); \ No newline at end of file +); diff --git a/benches/linalg/symmetric_eigen.rs b/benches/linalg/symmetric_eigen.rs index 822ea30e..3b52ba5c 100644 --- a/benches/linalg/symmetric_eigen.rs +++ b/benches/linalg/symmetric_eigen.rs @@ -2,25 +2,34 @@ use na::{Matrix4, SymmetricEigen}; fn symmetric_eigen_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.bench_function("symmetric_eigen_decompose_4x4", move |bh| bh.iter(|| test::black_box(SymmetricEigen::new(m.clone())))); + bh.bench_function("symmetric_eigen_decompose_4x4", move |bh| { + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) + }); } fn symmetric_eigen_decompose_10x10(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(10, 10); - bh.bench_function("symmetric_eigen_decompose_10x10", move |bh| bh.iter(|| test::black_box(SymmetricEigen::new(m.clone())))); + bh.bench_function("symmetric_eigen_decompose_10x10", move |bh| { + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) + }); } fn symmetric_eigen_decompose_100x100(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(100, 100); - bh.bench_function("symmetric_eigen_decompose_100x100", move |bh| bh.iter(|| test::black_box(SymmetricEigen::new(m.clone())))); + bh.bench_function("symmetric_eigen_decompose_100x100", move |bh| { + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) + }); } fn symmetric_eigen_decompose_200x200(bh: &mut criterion::Criterion) { let m = crate::reproductible_dmatrix(200, 200); - bh.bench_function("symmetric_eigen_decompose_200x200", move |bh| bh.iter(|| test::black_box(SymmetricEigen::new(m.clone())))); + bh.bench_function("symmetric_eigen_decompose_200x200", move |bh| { + bh.iter(|| test::black_box(SymmetricEigen::new(m.clone()))) + }); } -criterion_group!(symmetric_eigen, +criterion_group!( + symmetric_eigen, symmetric_eigen_decompose_4x4, symmetric_eigen_decompose_10x10, symmetric_eigen_decompose_100x100, diff --git a/examples/cargo/Cargo.toml b/examples/cargo/Cargo.toml index 95ec21c8..91b9b72b 100644 --- a/examples/cargo/Cargo.toml +++ b/examples/cargo/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" authors = [ "You" ] [dependencies] -nalgebra = "0.20.0" +nalgebra = "0.21.0" [[bin]] name = "example" diff --git a/examples/dimensional_genericity.rs b/examples/dimensional_genericity.rs index 411a0666..00c40f14 100644 --- a/examples/dimensional_genericity.rs +++ b/examples/dimensional_genericity.rs @@ -1,18 +1,9 @@ -extern crate alga; extern crate nalgebra as na; -use alga::linear::FiniteDimInnerSpace; use na::allocator::Allocator; use na::dimension::Dim; use na::{DefaultAllocator, RealField, Unit, Vector2, Vector3, VectorN}; -/// Reflects a vector wrt. the hyperplane with normal `plane_normal`. -fn reflect_wrt_hyperplane_with_algebraic_genericity(plane_normal: &Unit, vector: &V) -> V -where V: FiniteDimInnerSpace + Copy { - let n = plane_normal.as_ref(); // Get the underlying vector of type `V`. - *vector - *n * (n.dot(vector) * na::convert(2.0)) -} - /// Reflects a vector wrt. the hyperplane with normal `plane_normal`. fn reflect_wrt_hyperplane_with_dimensional_genericity( plane_normal: &Unit>, @@ -29,7 +20,9 @@ where /// Reflects a 2D vector wrt. the 2D line with normal `plane_normal`. fn reflect_wrt_hyperplane2(plane_normal: &Unit>, vector: &Vector2) -> Vector2 -where N: RealField { +where + N: RealField, +{ let n = plane_normal.as_ref(); // Get the underlying Vector2 vector - n * (n.dot(vector) * na::convert(2.0)) } @@ -37,7 +30,9 @@ where N: RealField { /// Reflects a 3D vector wrt. the 3D plane with normal `plane_normal`. /// /!\ This is an exact replicate of `reflect_wrt_hyperplane2, but for 3D. fn reflect_wrt_hyperplane3(plane_normal: &Unit>, vector: &Vector3) -> Vector3 -where N: RealField { +where + N: RealField, +{ let n = plane_normal.as_ref(); // Get the underlying Vector3 vector - n * (n.dot(vector) * na::convert(2.0)) } @@ -50,15 +45,6 @@ fn main() { let v3 = Vector3::new(1.0, 2.0, 3.0); // 3D vector to be reflected. // We can call the same function for 2D and 3D. - assert_eq!( - reflect_wrt_hyperplane_with_algebraic_genericity(&plane2, &v2).y, - -2.0 - ); - assert_eq!( - reflect_wrt_hyperplane_with_algebraic_genericity(&plane3, &v3).y, - -2.0 - ); - assert_eq!( reflect_wrt_hyperplane_with_dimensional_genericity(&plane2, &v2).y, -2.0 diff --git a/examples/identity.rs b/examples/identity.rs deleted file mode 100644 index c20c5616..00000000 --- a/examples/identity.rs +++ /dev/null @@ -1,39 +0,0 @@ -extern crate alga; -extern crate nalgebra as na; - -use alga::linear::Transformation; -use na::{Id, Isometry3, Point3, Vector3}; - -/* - * Applies `n` times the transformation `t` to the vector `v` and sum each - * intermediate value. - */ -fn complicated_algorithm(v: &Vector3, t: &T, n: usize) -> Vector3 -where T: Transformation> { - let mut result = *v; - - // Do lots of operations involving t. - for _ in 0..n { - result = v + t.transform_vector(&result); - } - - result -} - -/* - * The two following calls are equivalent in term of result. - */ -fn main() { - let v = Vector3::new(1.0, 2.0, 3.0); - - // The specialization generated by the compiler will do vector additions only. - let result1 = complicated_algorithm(&v, &Id::new(), 100000); - - // The specialization generated by the compiler will also include matrix multiplications. - let iso = Isometry3::identity(); - let result2 = complicated_algorithm(&v, &iso, 100000); - - // They both return the same result. - assert!(result1 == Vector3::new(100001.0, 200002.0, 300003.0)); - assert!(result2 == Vector3::new(100001.0, 200002.0, 300003.0)); -} \ No newline at end of file diff --git a/examples/scalar_genericity.rs b/examples/scalar_genericity.rs index 75f6f9d4..403f9ec2 100644 --- a/examples/scalar_genericity.rs +++ b/examples/scalar_genericity.rs @@ -1,19 +1,12 @@ -extern crate alga; extern crate nalgebra as na; -use alga::general::{RealField, RingCommutative}; use na::{Scalar, Vector3}; +use simba::scalar::RealField; fn print_vector(m: &Vector3) { println!("{:?}", m) } -fn print_squared_norm(v: &Vector3) { - // NOTE: alternatively, nalgebra already defines `v.squared_norm()`. - let sqnorm = v.dot(v); - println!("{:?}", sqnorm); -} - fn print_norm(v: &Vector3) { // NOTE: alternatively, nalgebra already defines `v.norm()`. let norm = v.dot(v).sqrt(); @@ -28,6 +21,5 @@ fn main() { let v2 = Vector3::new(1.0, 2.0, 3.0); print_vector(&v1); - print_squared_norm(&v1); print_norm(&v2); } diff --git a/examples/transform_conversion.rs b/examples/transform_conversion.rs index 734a2bd7..71660a07 100644 --- a/examples/transform_conversion.rs +++ b/examples/transform_conversion.rs @@ -18,6 +18,6 @@ fn main() { assert!(iso_fail.is_none()); // Similarity -> Isometry conversion can be forced at your own risks. - let iso_forced: Isometry2 = unsafe { na::convert_unchecked(sim_with_scaling) }; + let iso_forced: Isometry2 = na::convert_unchecked(sim_with_scaling); assert_eq!(iso_success.unwrap(), iso_forced); } diff --git a/examples/transform_matrix4.rs b/examples/transform_matrix4.rs index a9e6cd6e..74649d74 100644 --- a/examples/transform_matrix4.rs +++ b/examples/transform_matrix4.rs @@ -1,4 +1,3 @@ -extern crate alga; #[macro_use] extern crate approx; extern crate nalgebra as na; diff --git a/examples/transform_vector_point3.rs b/examples/transform_vector_point3.rs index 57a189cc..cf2921a5 100644 --- a/examples/transform_vector_point3.rs +++ b/examples/transform_vector_point3.rs @@ -1,4 +1,3 @@ -extern crate alga; extern crate nalgebra as na; use na::{Matrix4, Point3, Vector3, Vector4}; diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index 7c4aacb2..b72e2988 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-glm" -version = "0.6.0" +version = "0.7.0" authors = ["sebcrozet "] description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." @@ -15,7 +15,7 @@ edition = "2018" [features] default = [ "std" ] -std = [ "nalgebra/std", "alga/std" ] +std = [ "nalgebra/std", "simba/std" ] stdweb = [ "nalgebra/stdweb" ] arbitrary = [ "nalgebra/arbitrary" ] serde-serialize = [ "nalgebra/serde-serialize" ] @@ -24,5 +24,5 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ] [dependencies] num-traits = { version = "0.2", default-features = false } approx = { version = "0.3", default-features = false } -alga = { version = "0.9", default-features = false } -nalgebra = { path = "..", version = "0.20", default-features = false } +simba = { version = "0.1", default-features = false } +nalgebra = { path = "..", version = "0.21", default-features = false } diff --git a/nalgebra-glm/src/common.rs b/nalgebra-glm/src/common.rs index eda9f295..1a5c0c2a 100644 --- a/nalgebra-glm/src/common.rs +++ b/nalgebra-glm/src/common.rs @@ -1,6 +1,6 @@ +use core::mem; use na::{self, DefaultAllocator, RealField}; use num::FromPrimitive; -use core::mem; use crate::aliases::{TMat, TVec}; use crate::traits::{Alloc, Dimension, Number}; @@ -22,7 +22,9 @@ use crate::traits::{Alloc, Dimension, Number}; /// /// * [`sign`](fn.sign.html) pub fn abs(x: &TMat) -> TMat -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.abs() } @@ -44,7 +46,9 @@ where DefaultAllocator: Alloc { /// * [`round`](fn.round.html) /// * [`trunc`](fn.trunc.html) pub fn ceil(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| x.ceil()) } @@ -94,7 +98,9 @@ pub fn clamp_scalar(x: N, min_val: N, max_val: N) -> N { /// * [`clamp_scalar`](fn.clamp_scalar.html) /// * [`clamp_vec`](fn.clamp_vec.html) pub fn clamp(x: &TVec, min_val: N, max_val: N) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| na::clamp(x, min_val, max_val)) } @@ -167,7 +173,9 @@ pub fn float_bits_to_int(v: f32) -> i32 { /// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) /// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) pub fn float_bits_to_int_vec(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(float_bits_to_int) } @@ -202,7 +210,9 @@ pub fn float_bits_to_uint(v: f32) -> u32 { /// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) /// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) pub fn float_bits_to_uint_vec(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(float_bits_to_uint) } @@ -223,7 +233,9 @@ where DefaultAllocator: Alloc { /// * [`round`](fn.round.html) /// * [`trunc`](fn.trunc.html) pub fn floor(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| x.floor()) } @@ -250,7 +262,9 @@ where DefaultAllocator: Alloc { /// * [`round`](fn.round.html) /// * [`trunc`](fn.trunc.html) pub fn fract(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| x.fract()) } @@ -293,7 +307,9 @@ pub fn int_bits_to_float(v: i32) -> f32 { /// * [`uint_bits_to_float`](fn.uint_bits_to_float.html) /// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) pub fn int_bits_to_float_vec(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(int_bits_to_float) } @@ -352,7 +368,9 @@ pub fn mix_scalar(x: N, y: N, a: N) -> N { /// * [`mix_scalar`](fn.mix_scalar.html) /// * [`mix_vec`](fn.mix_vec.html) pub fn mix(x: &TVec, y: &TVec, a: N) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x * (N::one() - a) + y * a } @@ -425,7 +443,9 @@ pub fn lerp_scalar(x: N, y: N, a: N) -> N { /// * [`lerp_scalar`](fn.lerp_scalar.html) /// * [`lerp_vec`](fn.lerp_vec.html) pub fn lerp(x: &TVec, y: &TVec, a: N) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ mix(x, y, a) } @@ -468,7 +488,9 @@ where /// /// * [`modf`](fn.modf.html) pub fn modf_vec(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.zip_map(y, |x, y| x % y) } @@ -500,7 +522,9 @@ pub fn modf(x: N, i: N) -> N { /// * [`fract`](fn.fract.html) /// * [`trunc`](fn.trunc.html) pub fn round(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| x.round()) } @@ -524,7 +548,9 @@ where DefaultAllocator: Alloc { /// * [`abs`](fn.abs.html) /// pub fn sign(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| if x.is_zero() { N::zero() } else { x.signum() }) } @@ -550,13 +576,17 @@ pub fn step_scalar(edge: N, x: N) -> N { /// Returns 0.0 if `x[i] < edge`, otherwise it returns 1.0. pub fn step(edge: N, x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| step_scalar(edge, x)) } /// Returns 0.0 if `x[i] < edge[i]`, otherwise it returns 1.0. pub fn step_vec(edge: &TVec, x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ edge.zip_map(x, step_scalar) } @@ -577,7 +607,9 @@ where DefaultAllocator: Alloc { /// * [`fract`](fn.fract.html) /// * [`round`](fn.round.html) pub fn trunc(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|x| x.trunc()) } @@ -612,6 +644,8 @@ pub fn uint_bits_to_float_scalar(v: u32) -> f32 { /// * [`int_bits_to_float_vec`](fn.int_bits_to_float_vec.html) /// * [`uint_bits_to_float_scalar`](fn.uint_bits_to_float_scalar.html) pub fn uint_bits_to_float(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(uint_bits_to_float_scalar) } diff --git a/nalgebra-glm/src/exponential.rs b/nalgebra-glm/src/exponential.rs index fd54fb34..5830704a 100644 --- a/nalgebra-glm/src/exponential.rs +++ b/nalgebra-glm/src/exponential.rs @@ -1,6 +1,6 @@ use crate::aliases::TVec; -use na::{DefaultAllocator, RealField}; use crate::traits::{Alloc, Dimension}; +use na::{DefaultAllocator, RealField}; /// Component-wise exponential. /// @@ -8,7 +8,9 @@ use crate::traits::{Alloc, Dimension}; /// /// * [`exp2`](fn.exp2.html) pub fn exp(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| x.exp()) } @@ -18,7 +20,9 @@ where DefaultAllocator: Alloc { /// /// * [`exp`](fn.exp.html) pub fn exp2(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| x.exp2()) } @@ -28,7 +32,9 @@ where DefaultAllocator: Alloc { /// /// * [`sqrt`](fn.sqrt.html) pub fn inversesqrt(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| N::one() / x.sqrt()) } @@ -38,7 +44,9 @@ where DefaultAllocator: Alloc { /// /// * [`log2`](fn.log2.html) pub fn log(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| x.ln()) } @@ -48,13 +56,17 @@ where DefaultAllocator: Alloc { /// /// * [`log`](fn.log.html) pub fn log2(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| x.log2()) } /// Component-wise power. pub fn pow(base: &TVec, exponent: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ base.zip_map(exponent, |b, e| b.powf(e)) } @@ -67,6 +79,8 @@ where DefaultAllocator: Alloc { /// * [`inversesqrt`](fn.inversesqrt.html) /// * [`pow`](fn.pow.html) pub fn sqrt(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| x.sqrt()) } diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 6b279024..260c5196 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -1,5 +1,5 @@ use crate::aliases::TMat4; -use na::{RealField}; +use na::RealField; //pub fn frustum(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() @@ -90,13 +90,20 @@ pub fn ortho_lh(left: N, right: N, bottom: N, top: N, znear: N, 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(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { - let two : N = crate::convert(2.0); - let mut mat : TMat4 = TMat4::::identity(); +pub fn ortho_lh_no( + left: N, + right: N, + bottom: N, + top: N, + znear: N, + zfar: N, +) -> TMat4 { + let two: N = crate::convert(2.0); + let mut mat: TMat4 = TMat4::::identity(); mat[(0, 0)] = two / (right - left); mat[(0, 3)] = -(right + left) / (right - left); - mat[(1, 1)] = two / (top-bottom); + mat[(1, 1)] = two / (top - bottom); mat[(1, 3)] = -(top + bottom) / (top - bottom); mat[(2, 2)] = two / (zfar - znear); mat[(2, 3)] = -(zfar + znear) / (zfar - znear); @@ -115,17 +122,24 @@ pub fn ortho_lh_no(left: N, right: N, bottom: N, top: N, znear: N, /// * `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(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { - let one : N = N::one(); - let two : N = crate::convert(2.0); - let mut mat : TMat4 = TMat4::::identity(); +pub fn ortho_lh_zo( + left: N, + right: N, + bottom: N, + top: N, + znear: N, + zfar: N, +) -> TMat4 { + let one: N = N::one(); + let two: N = crate::convert(2.0); + let mut mat: TMat4 = TMat4::::identity(); mat[(0, 0)] = two / (right - left); - mat[(0, 3)] = - (right + left) / (right - left); + mat[(0, 3)] = -(right + left) / (right - left); mat[(1, 1)] = two / (top - bottom); - mat[(1, 3)] = - (top + bottom) / (top - bottom); + mat[(1, 3)] = -(top + bottom) / (top - bottom); mat[(2, 2)] = one / (zfar - znear); - mat[(2, 3)] = - znear / (zfar - znear); + mat[(2, 3)] = -znear / (zfar - znear); mat } @@ -171,16 +185,23 @@ pub fn ortho_rh(left: N, right: N, bottom: N, top: N, znear: N, 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(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { - let two : N = crate::convert(2.0); - let mut mat : TMat4 = TMat4::::identity(); +pub fn ortho_rh_no( + left: N, + right: N, + bottom: N, + top: N, + znear: N, + zfar: N, +) -> TMat4 { + let two: N = crate::convert(2.0); + let mut mat: TMat4 = TMat4::::identity(); mat[(0, 0)] = two / (right - left); - mat[(0, 3)] = - (right + left) / (right - left); - mat[(1, 1)] = two/(top-bottom); - mat[(1, 3)] = - (top + bottom) / (top - bottom); - mat[(2, 2)] = - two / (zfar - znear); - mat[(2, 3)] = - (zfar + znear) / (zfar - znear); + mat[(0, 3)] = -(right + left) / (right - left); + mat[(1, 1)] = two / (top - bottom); + mat[(1, 3)] = -(top + bottom) / (top - bottom); + mat[(2, 2)] = -two / (zfar - znear); + mat[(2, 3)] = -(zfar + znear) / (zfar - znear); mat } @@ -196,17 +217,24 @@ pub fn ortho_rh_no(left: N, right: N, bottom: N, top: N, znear: N, /// * `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(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { - let one : N = N::one(); - let two : N = crate::convert(2.0); - let mut mat : TMat4 = TMat4::::identity(); +pub fn ortho_rh_zo( + left: N, + right: N, + bottom: N, + top: N, + znear: N, + zfar: N, +) -> TMat4 { + let one: N = N::one(); + let two: N = crate::convert(2.0); + let mut mat: TMat4 = TMat4::::identity(); mat[(0, 0)] = two / (right - left); - mat[(0, 3)] = - (right + left) / (right - left); - mat[(1, 1)] = two/(top-bottom); - mat[(1, 3)] = - (top + bottom) / (top - bottom); - mat[(2, 2)] = - one / (zfar - znear); - mat[(2, 3)] = - znear / (zfar - znear); + mat[(0, 3)] = -(right + left) / (right - left); + mat[(1, 1)] = two / (top - bottom); + mat[(1, 3)] = -(top + bottom) / (top - bottom); + mat[(2, 2)] = -one / (zfar - znear); + mat[(2, 3)] = -znear / (zfar - znear); mat } @@ -264,19 +292,16 @@ pub fn perspective_fov_lh(fov: N, width: N, height: N, near: N, 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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { - assert!( - width > N::zero(), - "The width must be greater than zero" - ); - assert!( - height > N::zero(), - "The height must be greater than zero." - ); - assert!( - fov > N::zero(), - "The fov must be greater than zero" - ); +pub fn perspective_fov_lh_no( + fov: N, + width: N, + height: N, + near: N, + far: N, +) -> TMat4 { + assert!(width > N::zero(), "The width must be greater than zero"); + assert!(height > N::zero(), "The height must be greater than zero."); + assert!(fov > N::zero(), "The fov must be greater than zero"); let mut mat = TMat4::zeros(); @@ -287,7 +312,7 @@ pub fn perspective_fov_lh_no(fov: N, width: N, height: N, near: N, mat[(0, 0)] = w; mat[(1, 1)] = h; mat[(2, 2)] = (far + near) / (far - near); - mat[(2, 3)] = - (far * near * crate::convert(2.0)) / (far - near); + mat[(2, 3)] = -(far * near * crate::convert(2.0)) / (far - near); mat[(3, 2)] = N::one(); mat @@ -303,19 +328,16 @@ pub fn perspective_fov_lh_no(fov: N, width: N, height: N, near: N, /// * `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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { - assert!( - width > N::zero(), - "The width must be greater than zero" - ); - assert!( - height > N::zero(), - "The height must be greater than zero." - ); - assert!( - fov > N::zero(), - "The fov must be greater than zero" - ); +pub fn perspective_fov_lh_zo( + fov: N, + width: N, + height: N, + near: N, + far: N, +) -> TMat4 { + assert!(width > N::zero(), "The width must be greater than zero"); + assert!(height > N::zero(), "The height must be greater than zero."); + assert!(fov > N::zero(), "The fov must be greater than zero"); let mut mat = TMat4::zeros(); @@ -370,19 +392,16 @@ pub fn perspective_fov_rh(fov: N, width: N, height: N, near: N, 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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { - assert!( - width > N::zero(), - "The width must be greater than zero" - ); - assert!( - height > N::zero(), - "The height must be greater than zero." - ); - assert!( - fov > N::zero(), - "The fov must be greater than zero" - ); +pub fn perspective_fov_rh_no( + fov: N, + width: N, + height: N, + near: N, + far: N, +) -> TMat4 { + assert!(width > N::zero(), "The width must be greater than zero"); + assert!(height > N::zero(), "The height must be greater than zero."); + assert!(fov > N::zero(), "The fov must be greater than zero"); let mut mat = TMat4::zeros(); @@ -392,8 +411,8 @@ pub fn perspective_fov_rh_no(fov: N, width: N, height: N, near: N, mat[(0, 0)] = w; mat[(1, 1)] = h; - mat[(2, 2)] = - (far + near) / (far - near); - mat[(2, 3)] = - (far * near * crate::convert(2.0)) / (far - near); + mat[(2, 2)] = -(far + near) / (far - near); + mat[(2, 3)] = -(far * near * crate::convert(2.0)) / (far - near); mat[(3, 2)] = -N::one(); mat @@ -409,19 +428,16 @@ pub fn perspective_fov_rh_no(fov: N, width: N, height: N, near: N, /// * `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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { - assert!( - width > N::zero(), - "The width must be greater than zero" - ); - assert!( - height > N::zero(), - "The height must be greater than zero." - ); - assert!( - fov > N::zero(), - "The fov must be greater than zero" - ); +pub fn perspective_fov_rh_zo( + fov: N, + width: N, + height: N, + near: N, + far: N, +) -> TMat4 { + assert!(width > N::zero(), "The width must be greater than zero"); + assert!(height > N::zero(), "The height must be greater than zero."); + assert!(fov > N::zero(), "The fov must be greater than zero"); let mut mat = TMat4::zeros(); @@ -518,8 +534,8 @@ pub fn perspective_lh_no(aspect: N, fovy: N, near: N, far: N) -> T ); let one = N::one(); - let two: N = crate::convert( 2.0); - let mut mat : TMat4 = TMat4::zeros(); + let two: N = crate::convert(2.0); + let mut mat: TMat4 = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -554,7 +570,7 @@ pub fn perspective_lh_zo(aspect: N, fovy: N, near: N, far: N) -> T ); let one = N::one(); - let two: N = crate::convert( 2.0); + let two: N = crate::convert(2.0); let mut mat: TMat4 = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -620,15 +636,15 @@ pub fn perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> T ); let negone = -N::one(); - let one = N::one(); - let two: N = crate::convert( 2.0); + let one = N::one(); + let two: N = crate::convert(2.0); let mut mat = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); mat[(0, 0)] = one / (aspect * tan_half_fovy); mat[(1, 1)] = one / tan_half_fovy; - mat[(2, 2)] = - (far + near) / (far - near); + mat[(2, 2)] = -(far + near) / (far - near); mat[(2, 3)] = -(two * far * near) / (far - near); mat[(3, 2)] = negone; @@ -657,8 +673,8 @@ pub fn perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> T ); let negone = -N::one(); - let one = N::one(); - let two = crate::convert( 2.0); + let one = N::one(); + let two = crate::convert(2.0); let mut mat = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -793,4 +809,4 @@ pub fn reversed_infinite_perspective_rh_zo(aspect: N, fovy: N, nea // //pub fn tweaked_infinite_perspective_ep(fovy: N, aspect: N, near: N, ep: N) -> TMat4 { // unimplemented!() -//} \ No newline at end of file +//} diff --git a/nalgebra-glm/src/ext/matrix_projection.rs b/nalgebra-glm/src/ext/matrix_projection.rs index 3048b77c..93c8d664 100644 --- a/nalgebra-glm/src/ext/matrix_projection.rs +++ b/nalgebra-glm/src/ext/matrix_projection.rs @@ -9,7 +9,11 @@ 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(center: &TVec2, delta: &TVec2, viewport: &TVec4) -> TMat4 { +pub fn pick_matrix( + center: &TVec2, + delta: &TVec2, + viewport: &TVec4, +) -> TMat4 { let shift = TVec3::new( (viewport.z - (center.x - viewport.x) * na::convert(2.0)) / delta.x, (viewport.w - (center.y - viewport.y) * na::convert(2.0)) / delta.y, @@ -46,8 +50,7 @@ pub fn project( model: &TMat4, proj: &TMat4, viewport: TVec4, -) -> TVec3 -{ +) -> TVec3 { project_no(obj, model, proj, viewport) } @@ -74,8 +77,7 @@ pub fn project_no( model: &TMat4, proj: &TMat4, viewport: TVec4, -) -> TVec3 -{ +) -> TVec3 { let proj = project_zo(obj, model, proj, viewport); TVec3::new(proj.x, proj.y, proj.z * na::convert(0.5) + na::convert(0.5)) } @@ -103,8 +105,7 @@ pub fn project_zo( model: &TMat4, proj: &TMat4, viewport: TVec4, -) -> TVec3 -{ +) -> TVec3 { let normalized = proj * model * TVec4::new(obj.x, obj.y, obj.z, N::one()); let scale = N::one() / normalized.w; @@ -137,8 +138,7 @@ pub fn unproject( model: &TMat4, proj: &TMat4, viewport: TVec4, -) -> TVec3 -{ +) -> TVec3 { unproject_no(win, model, proj, viewport) } @@ -165,8 +165,7 @@ pub fn unproject_no( model: &TMat4, proj: &TMat4, viewport: TVec4, -) -> TVec3 -{ +) -> TVec3 { let _2: N = na::convert(2.0); let transform = (proj * model).try_inverse().unwrap_or_else(TMat4::zeros); let pt = TVec4::new( @@ -203,8 +202,7 @@ pub fn unproject_zo( model: &TMat4, proj: &TMat4, viewport: TVec4, -) -> TVec3 -{ +) -> TVec3 { let _2: N = na::convert(2.0); let transform = (proj * model).try_inverse().unwrap_or_else(TMat4::zeros); let pt = TVec4::new( diff --git a/nalgebra-glm/src/ext/matrix_transform.rs b/nalgebra-glm/src/ext/matrix_transform.rs index c7f6b72d..df0696a4 100644 --- a/nalgebra-glm/src/ext/matrix_transform.rs +++ b/nalgebra-glm/src/ext/matrix_transform.rs @@ -5,7 +5,9 @@ use crate::traits::{Alloc, Dimension, Number}; /// The identity matrix. pub fn identity() -> TMat -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ TMat::::identity() } diff --git a/nalgebra-glm/src/ext/mod.rs b/nalgebra-glm/src/ext/mod.rs index 52aa9dc3..1923e806 100644 --- a/nalgebra-glm/src/ext/mod.rs +++ b/nalgebra-glm/src/ext/mod.rs @@ -1,19 +1,13 @@ //! (Reexported) Additional features not specified by GLSL specification pub use self::matrix_clip_space::{ - ortho, ortho_lh, ortho_lh_no, ortho_lh_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, - ortho_zo, - - perspective, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, - perspective_rh, perspective_rh_no, perspective_rh_zo, perspective_zo, - - perspective_fov, perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo, + infinite_perspective_rh_no, infinite_perspective_rh_zo, ortho, ortho_lh, ortho_lh_no, + ortho_lh_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, ortho_zo, perspective, + perspective_fov, perspective_fov_lh, perspective_fov_lh_no, perspective_fov_lh_zo, perspective_fov_no, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, - perspective_fov_zo, - - infinite_perspective_rh_no, infinite_perspective_rh_zo, - - reversed_perspective_rh_zo, reversed_infinite_perspective_rh_zo, + perspective_fov_zo, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, + perspective_rh, perspective_rh_no, perspective_rh_zo, perspective_zo, + reversed_infinite_perspective_rh_zo, reversed_perspective_rh_zo, }; pub use self::matrix_projection::{ pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo, @@ -35,7 +29,9 @@ pub use self::quaternion_relational::{ }; pub use self::quaternion_transform::{quat_exp, quat_log, quat_pow, quat_rotate}; pub use self::quaternion_trigonometric::{quat_angle, quat_angle_axis, quat_axis}; -pub use self::scalar_common::{max3_scalar, max4_scalar, min3_scalar, min4_scalar}; +pub use self::scalar_common::{ + max2_scalar, max3_scalar, max4_scalar, min2_scalar, min3_scalar, min4_scalar, +}; pub use self::scalar_constants::{epsilon, pi}; pub use self::vector_common::{max, max2, max3, max4, min, min2, min3, min4}; pub use self::vector_relational::{equal_eps, equal_eps_vec, not_equal_eps, not_equal_eps_vec}; diff --git a/nalgebra-glm/src/ext/scalar_common.rs b/nalgebra-glm/src/ext/scalar_common.rs index 11104ce2..b3bd9c13 100644 --- a/nalgebra-glm/src/ext/scalar_common.rs +++ b/nalgebra-glm/src/ext/scalar_common.rs @@ -1,7 +1,51 @@ -use na; - use crate::traits::Number; +/// Returns the maximum among two values. +/// +/// # Examples: +/// +/// ``` +/// # use nalgebra_glm as glm; +/// assert_eq!(2.0, glm::max2_scalar(1.0, 2.0)); +/// assert_eq!(1, glm::max2_scalar(0, 1)); +/// ``` +/// +/// # See also: +/// +/// * [`max4_scalar`](fn.max4_scalar.html) +/// * [`min3_scalar`](fn.min3_scalar.html) +/// * [`min4_scalar`](fn.min4_scalar.html) +pub fn max2_scalar(a: N, b: N) -> N { + if a >= b { + a + } else { + b + } +} + +/// Returns the maximum among two values. +/// +/// # Examples: +/// +/// ``` +/// # use nalgebra_glm as glm; +/// assert_eq!(1.0, glm::min2_scalar(1.0, 2.0)); +/// assert_eq!(0, glm::min2_scalar(0, 1)); +/// ``` +/// +/// # See also: +/// +/// * [`max4_scalar`](fn.max4_scalar.html) +/// * [`min3_scalar`](fn.min3_scalar.html) +/// * [`min4_scalar`](fn.min4_scalar.html) +pub fn min2_scalar(a: N, b: N) -> N { + if a <= b { + a + } else { + b + } +} + /// Returns the maximum among three values. /// /// # Examples: @@ -18,7 +62,7 @@ use crate::traits::Number; /// * [`min3_scalar`](fn.min3_scalar.html) /// * [`min4_scalar`](fn.min4_scalar.html) pub fn max3_scalar(a: N, b: N, c: N) -> N { - na::sup(&na::sup(&a, &b), &c) + max2_scalar(max2_scalar(a, b), c) } /// Returns the maximum among four values. @@ -37,7 +81,7 @@ pub fn max3_scalar(a: N, b: N, c: N) -> N { /// * [`min3_scalar`](fn.min3_scalar.html) /// * [`min4_scalar`](fn.min4_scalar.html) pub fn max4_scalar(a: N, b: N, c: N, d: N) -> N { - na::sup(&na::sup(&a, &b), &na::sup(&c, &d)) + max2_scalar(max2_scalar(a, b), max2_scalar(c, d)) } /// Returns the minimum among three values. @@ -56,7 +100,7 @@ pub fn max4_scalar(a: N, b: N, c: N, d: N) -> N { /// * [`max4_scalar`](fn.max4_scalar.html) /// * [`min4_scalar`](fn.min4_scalar.html) pub fn min3_scalar(a: N, b: N, c: N) -> N { - na::inf(&na::inf(&a, &b), &c) + min2_scalar(min2_scalar(a, b), c) } /// Returns the minimum among four values. @@ -75,5 +119,5 @@ pub fn min3_scalar(a: N, b: N, c: N) -> N { /// * [`max4_scalar`](fn.max4_scalar.html) /// * [`min3_scalar`](fn.min3_scalar.html) pub fn min4_scalar(a: N, b: N, c: N, d: N) -> N { - na::inf(&na::inf(&a, &b), &na::inf(&c, &d)) + min2_scalar(min2_scalar(a, b), min2_scalar(c, d)) } diff --git a/nalgebra-glm/src/ext/vector_common.rs b/nalgebra-glm/src/ext/vector_common.rs index a6418ef8..ff892f1e 100644 --- a/nalgebra-glm/src/ext/vector_common.rs +++ b/nalgebra-glm/src/ext/vector_common.rs @@ -17,8 +17,10 @@ use crate::traits::{Alloc, Dimension, Number}; /// * [`min3`](fn.min3.html) /// * [`min4`](fn.min4.html) pub fn max(a: &TVec, b: N) -> TVec -where DefaultAllocator: Alloc { - a.map(|a| na::sup(&a, &b)) +where + DefaultAllocator: Alloc, +{ + a.map(|a| crate::max2_scalar(a, b)) } /// Component-wise maximum between two vectors. @@ -35,8 +37,10 @@ where DefaultAllocator: Alloc { /// * [`min3`](fn.min3.html) /// * [`min4`](fn.min4.html) pub fn max2(a: &TVec, b: &TVec) -> TVec -where DefaultAllocator: Alloc { - na::sup(a, b) +where + DefaultAllocator: Alloc, +{ + a.zip_map(b, |a, b| crate::max2_scalar(a, b)) } /// Component-wise maximum between three vectors. @@ -53,7 +57,9 @@ where DefaultAllocator: Alloc { /// * [`min3`](fn.min3.html) /// * [`min4`](fn.min4.html) pub fn max3(a: &TVec, b: &TVec, c: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ max2(&max2(a, b), c) } @@ -96,8 +102,10 @@ where /// * [`min3`](fn.min3.html) /// * [`min4`](fn.min4.html) pub fn min(x: &TVec, y: N) -> TVec -where DefaultAllocator: Alloc { - x.map(|x| na::inf(&x, &y)) +where + DefaultAllocator: Alloc, +{ + x.map(|x| crate::min2_scalar(x, y)) } /// Component-wise minimum between two vectors. @@ -114,8 +122,10 @@ where DefaultAllocator: Alloc { /// * [`min3`](fn.min3.html) /// * [`min4`](fn.min4.html) pub fn min2(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { - na::inf(x, y) +where + DefaultAllocator: Alloc, +{ + x.zip_map(y, |a, b| crate::min2_scalar(a, b)) } /// Component-wise minimum between three vectors. @@ -132,7 +142,9 @@ where DefaultAllocator: Alloc { /// * [`min2`](fn.min2.html) /// * [`min4`](fn.min4.html) pub fn min3(a: &TVec, b: &TVec, c: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ min2(&min2(a, b), c) } diff --git a/nalgebra-glm/src/geometric.rs b/nalgebra-glm/src/geometric.rs index 7c1e1987..a4b0b988 100644 --- a/nalgebra-glm/src/geometric.rs +++ b/nalgebra-glm/src/geometric.rs @@ -14,13 +14,17 @@ pub fn cross(x: &TVec3, y: &TVec3) -> TVec3 { /// /// * [`distance2`](fn.distance2.html) pub fn distance(p0: &TVec, p1: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ (p1 - p0).norm() } /// The dot product of two vectors. pub fn dot(x: &TVec, y: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.dot(y) } @@ -50,7 +54,9 @@ where /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) pub fn length(x: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.norm() } @@ -64,26 +70,34 @@ where DefaultAllocator: Alloc { /// * [`magnitude2`](fn.magnitude2.html) /// * [`nalgebra::norm`](../nalgebra/fn.norm.html) pub fn magnitude(x: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.norm() } /// Normalizes a vector. pub fn normalize(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.normalize() } /// For the incident vector `i` and surface orientation `n`, returns the reflection direction : `result = i - 2.0 * dot(n, i) * n`. pub fn reflect_vec(i: &TVec, n: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ let _2 = N::one() + N::one(); i - n * (n.dot(i) * _2) } /// 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(i: &TVec, n: &TVec, eta: N) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ let ni = n.dot(i); let k = N::one() - eta * eta * (N::one() - ni * ni); diff --git a/nalgebra-glm/src/gtc/matrix_access.rs b/nalgebra-glm/src/gtc/matrix_access.rs index f61d9782..2713b8be 100644 --- a/nalgebra-glm/src/gtc/matrix_access.rs +++ b/nalgebra-glm/src/gtc/matrix_access.rs @@ -10,10 +10,7 @@ use crate::traits::{Alloc, Dimension}; /// * [`row`](fn.row.html) /// * [`set_column`](fn.set_column.html) /// * [`set_row`](fn.set_row.html) -pub fn column( - m: &TMat, - index: usize, -) -> TVec +pub fn column(m: &TMat, index: usize) -> TVec where DefaultAllocator: Alloc, { @@ -48,7 +45,9 @@ where /// * [`set_column`](fn.set_column.html) /// * [`set_row`](fn.set_row.html) pub fn row(m: &TMat, index: usize) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ m.row(index).into_owned().transpose() } diff --git a/nalgebra-glm/src/gtc/matrix_inverse.rs b/nalgebra-glm/src/gtc/matrix_inverse.rs index eab0b995..feab0daa 100644 --- a/nalgebra-glm/src/gtc/matrix_inverse.rs +++ b/nalgebra-glm/src/gtc/matrix_inverse.rs @@ -5,14 +5,18 @@ use crate::traits::{Alloc, Dimension}; /// Fast matrix inverse for affine matrix. pub fn affine_inverse(m: TMat) -> TMat -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ // FIXME: 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(m: TMat) -> TMat -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ m.try_inverse() .unwrap_or_else(TMat::<_, D, D>::zeros) .transpose() diff --git a/nalgebra-glm/src/gtc/type_ptr.rs b/nalgebra-glm/src/gtc/type_ptr.rs index 6de096ca..f8c6698b 100644 --- a/nalgebra-glm/src/gtc/type_ptr.rs +++ b/nalgebra-glm/src/gtc/type_ptr.rs @@ -76,7 +76,12 @@ pub fn mat2_to_mat3(m: &TMat2) -> TMat3 { /// Converts a 3x3 matrix to a 2x2 matrix. pub fn mat3_to_mat2(m: &TMat3) -> TMat2 { - TMat2::new(m.m11.inlined_clone(), m.m12.inlined_clone(), m.m21.inlined_clone(), m.m22.inlined_clone()) + TMat2::new( + m.m11.inlined_clone(), + m.m12.inlined_clone(), + m.m21.inlined_clone(), + m.m22.inlined_clone(), + ) } /// Converts a 3x3 matrix to a 4x4 matrix. @@ -92,9 +97,15 @@ pub fn mat3_to_mat4(m: &TMat3) -> TMat4 { /// Converts a 4x4 matrix to a 3x3 matrix. pub fn mat4_to_mat3(m: &TMat4) -> TMat3 { 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.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(), ) } @@ -110,7 +121,12 @@ pub fn mat2_to_mat4(m: &TMat2) -> TMat4 { /// Converts a 4x4 matrix to a 2x2 matrix. pub fn mat4_to_mat2(m: &TMat4) -> TMat2 { - TMat2::new(m.m11.inlined_clone(), m.m12.inlined_clone(), m.m21.inlined_clone(), m.m22.inlined_clone()) + TMat2::new( + m.m11.inlined_clone(), + m.m12.inlined_clone(), + m.m21.inlined_clone(), + m.m22.inlined_clone(), + ) } /// Creates a quaternion from a slice arranged as `[x, y, z, w]`. @@ -297,7 +313,11 @@ pub fn vec3_to_vec3(v: &TVec3) -> TVec3 { /// * [`vec3_to_vec2`](fn.vec3_to_vec2.html) /// * [`vec3_to_vec4`](fn.vec3_to_vec4.html) pub fn vec4_to_vec3(v: &TVec4) -> TVec3 { - TVec3::new(v.x.inlined_clone(), v.y.inlined_clone(), v.z.inlined_clone()) + TVec3::new( + v.x.inlined_clone(), + v.y.inlined_clone(), + v.z.inlined_clone(), + ) } /// Creates a 3D vector from another vector. @@ -386,12 +406,16 @@ pub fn make_vec4(ptr: &[N]) -> TVec4 { /// Converts a matrix or vector to a slice arranged in column-major order. pub fn value_ptr(x: &TMat) -> &[N] -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.as_slice() } /// Converts a matrix or vector to a mutable slice arranged in column-major order. pub fn value_ptr_mut(x: &mut TMat) -> &mut [N] -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.as_mut_slice() } diff --git a/nalgebra-glm/src/gtx/component_wise.rs b/nalgebra-glm/src/gtx/component_wise.rs index 7c4af7a0..cfb851f4 100644 --- a/nalgebra-glm/src/gtx/component_wise.rs +++ b/nalgebra-glm/src/gtx/component_wise.rs @@ -22,7 +22,9 @@ use crate::traits::{Alloc, Dimension, Number}; /// * [`comp_min`](fn.comp_min.html) /// * [`comp_mul`](fn.comp_mul.html) pub fn comp_add(m: &TMat) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ m.iter().fold(N::zero(), |x, y| x + *y) } @@ -49,8 +51,11 @@ where DefaultAllocator: Alloc { /// * [`max3`](fn.max3.html) /// * [`max4`](fn.max4.html) pub fn comp_max(m: &TMat) -> N -where DefaultAllocator: Alloc { - m.iter().fold(N::min_value(), |x, y| na::sup(&x, y)) +where + DefaultAllocator: Alloc, +{ + m.iter() + .fold(N::min_value(), |x, y| crate::max2_scalar(x, *y)) } /// The minimum of every component of the given matrix or vector. @@ -76,8 +81,11 @@ where DefaultAllocator: Alloc { /// * [`min3`](fn.min3.html) /// * [`min4`](fn.min4.html) pub fn comp_min(m: &TMat) -> N -where DefaultAllocator: Alloc { - m.iter().fold(N::max_value(), |x, y| na::inf(&x, y)) +where + DefaultAllocator: Alloc, +{ + m.iter() + .fold(N::max_value(), |x, y| crate::min2_scalar(x, *y)) } /// The product of every component of the given matrix or vector. @@ -99,7 +107,9 @@ where DefaultAllocator: Alloc { /// * [`comp_max`](fn.comp_max.html) /// * [`comp_min`](fn.comp_min.html) pub fn comp_mul(m: &TMat) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ m.iter().fold(N::one(), |x, y| x * *y) } diff --git a/nalgebra-glm/src/gtx/norm.rs b/nalgebra-glm/src/gtx/norm.rs index 9332c010..f6fabe97 100644 --- a/nalgebra-glm/src/gtx/norm.rs +++ b/nalgebra-glm/src/gtx/norm.rs @@ -9,7 +9,9 @@ use crate::traits::{Alloc, Dimension}; /// /// * [`distance`](fn.distance.html) pub fn distance2(p0: &TVec, p1: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ (p1 - p0).norm_squared() } @@ -21,7 +23,9 @@ where DefaultAllocator: Alloc { /// * [`l2_distance`](fn.l2_distance.html) /// * [`l2_norm`](fn.l2_norm.html) pub fn l1_distance(x: &TVec, y: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ l1_norm(&(y - x)) } @@ -36,7 +40,9 @@ where DefaultAllocator: Alloc { /// * [`l2_distance`](fn.l2_distance.html) /// * [`l2_norm`](fn.l2_norm.html) pub fn l1_norm(v: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ crate::comp_add(&v.abs()) } @@ -55,7 +61,9 @@ where DefaultAllocator: Alloc { /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) pub fn l2_distance(x: &TVec, y: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ l2_norm(&(y - x)) } @@ -76,7 +84,9 @@ where DefaultAllocator: Alloc { /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) pub fn l2_norm(x: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.norm() } @@ -92,7 +102,9 @@ where DefaultAllocator: Alloc { /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) pub fn length2(x: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.norm_squared() } @@ -108,7 +120,9 @@ where DefaultAllocator: Alloc { /// * [`magnitude`](fn.magnitude.html) /// * [`nalgebra::norm_squared`](../nalgebra/fn.norm_squared.html) pub fn magnitude2(x: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.norm_squared() } diff --git a/nalgebra-glm/src/gtx/normalize_dot.rs b/nalgebra-glm/src/gtx/normalize_dot.rs index 06ce6978..23e6a73f 100644 --- a/nalgebra-glm/src/gtx/normalize_dot.rs +++ b/nalgebra-glm/src/gtx/normalize_dot.rs @@ -11,7 +11,9 @@ use crate::traits::{Alloc, Dimension}; /// /// * [`normalize_dot`](fn.normalize_dot.html`) pub fn fast_normalize_dot(x: &TVec, y: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ // XXX: improve those. x.normalize().dot(&y.normalize()) } @@ -22,7 +24,9 @@ where DefaultAllocator: Alloc { /// /// * [`fast_normalize_dot`](fn.fast_normalize_dot.html`) pub fn normalize_dot(x: &TVec, y: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ // XXX: improve those. x.normalize().dot(&y.normalize()) } diff --git a/nalgebra-glm/src/gtx/vector_angle.rs b/nalgebra-glm/src/gtx/vector_angle.rs index 8753ccd0..e71abafb 100644 --- a/nalgebra-glm/src/gtx/vector_angle.rs +++ b/nalgebra-glm/src/gtx/vector_angle.rs @@ -5,7 +5,9 @@ use crate::traits::{Alloc, Dimension}; /// The angle between two vectors. pub fn angle(x: &TVec, y: &TVec) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.angle(y) } diff --git a/nalgebra-glm/src/gtx/vector_query.rs b/nalgebra-glm/src/gtx/vector_query.rs index 2a127f00..687d9530 100644 --- a/nalgebra-glm/src/gtx/vector_query.rs +++ b/nalgebra-glm/src/gtx/vector_query.rs @@ -22,11 +22,7 @@ pub fn are_collinear2d(v0: &TVec2, v1: &TVec2, epsilon: N) -> b } /// Returns `true` if two vectors are orthogonal (up to an epsilon). -pub fn are_orthogonal( - v0: &TVec, - v1: &TVec, - epsilon: N, -) -> bool +pub fn are_orthogonal(v0: &TVec, v1: &TVec, epsilon: N) -> bool where DefaultAllocator: Alloc, { @@ -40,18 +36,24 @@ where /// Returns `true` if all the components of `v` are zero (up to an epsilon). pub fn is_comp_null(v: &TVec, epsilon: N) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| abs_diff_eq!(x, N::zero(), epsilon = epsilon)) } /// Returns `true` if `v` has a magnitude of 1 (up to an epsilon). pub fn is_normalized(v: &TVec, epsilon: N) -> bool -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ abs_diff_eq!(v.norm_squared(), N::one(), epsilon = epsilon * epsilon) } /// Returns `true` if `v` is zero (up to an epsilon). pub fn is_null(v: &TVec, epsilon: N) -> bool -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ abs_diff_eq!(*v, TVec::::zeros(), epsilon = epsilon) } diff --git a/nalgebra-glm/src/lib.rs b/nalgebra-glm/src/lib.rs index c8f266a4..e9c64160 100644 --- a/nalgebra-glm/src/lib.rs +++ b/nalgebra-glm/src/lib.rs @@ -116,10 +116,10 @@ extern crate num_traits as num; #[macro_use] extern crate approx; -extern crate alga; extern crate nalgebra as na; pub use crate::aliases::*; +pub use crate::traits::{Alloc, Dimension, Number}; 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, @@ -133,7 +133,6 @@ pub use geometric::{ cross, distance, dot, faceforward, length, magnitude, normalize, reflect_vec, refract_vec, }; pub use matrix::{determinant, inverse, matrix_comp_mult, outer_product, transpose}; -pub use crate::traits::{Alloc, Dimension, Number}; pub use trigonometric::{ acos, acosh, asin, asinh, atan, atan2, atanh, cos, cosh, degrees, radians, sin, sinh, tan, tanh, }; @@ -143,20 +142,20 @@ pub use vector_relational::{ pub use ext::{ epsilon, equal_columns, equal_columns_eps, equal_columns_eps_vec, equal_eps, equal_eps_vec, - identity, look_at, look_at_lh, look_at_rh, max, max2, max3, max3_scalar, max4, max4_scalar, - min, min2, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps, - not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, perspective, perspective_fov, - perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo, perspective_fov_no, - perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, perspective_fov_zo, - perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, perspective_rh, - perspective_rh_no, perspective_rh_zo, perspective_zo, ortho_lh, ortho_lh_no, ortho_lh_zo, - ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, ortho_zo, pi, pick_matrix, project, project_no, - project_zo, quat_angle, quat_angle_axis, quat_axis, quat_conjugate, quat_cross, quat_dot, - quat_equal, quat_equal_eps, quat_exp, quat_inverse, quat_length, quat_lerp, quat_log, + identity, infinite_perspective_rh_no, infinite_perspective_rh_zo, look_at, look_at_lh, + look_at_rh, max, max2, max2_scalar, max3, max3_scalar, max4, max4_scalar, min, min2, + min2_scalar, min3, min3_scalar, min4, min4_scalar, not_equal_columns, not_equal_columns_eps, + not_equal_columns_eps_vec, not_equal_eps, not_equal_eps_vec, ortho, ortho_lh, ortho_lh_no, + ortho_lh_zo, ortho_no, ortho_rh, ortho_rh_no, ortho_rh_zo, ortho_zo, perspective, + perspective_fov, perspective_fov_lh, perspective_fov_lh_no, perspective_fov_lh_zo, + perspective_fov_no, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, + perspective_fov_zo, perspective_lh, perspective_lh_no, perspective_lh_zo, perspective_no, + perspective_rh, perspective_rh_no, perspective_rh_zo, perspective_zo, pi, pick_matrix, project, + project_no, project_zo, quat_angle, quat_angle_axis, quat_axis, quat_conjugate, quat_cross, + quat_dot, quat_equal, quat_equal_eps, quat_exp, quat_inverse, quat_length, quat_lerp, quat_log, quat_magnitude, quat_normalize, quat_not_equal, quat_not_equal_eps, quat_pow, quat_rotate, - quat_slerp, rotate, rotate_x, rotate_y, rotate_z, scale, translate, unproject, unproject_no, - unproject_zo, infinite_perspective_rh_no, infinite_perspective_rh_zo, - reversed_perspective_rh_zo, reversed_infinite_perspective_rh_zo, + quat_slerp, reversed_infinite_perspective_rh_zo, reversed_perspective_rh_zo, rotate, rotate_x, + rotate_y, rotate_z, scale, translate, unproject, unproject_no, unproject_zo, }; pub use gtc::{ affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose, diff --git a/nalgebra-glm/src/matrix.rs b/nalgebra-glm/src/matrix.rs index a4c4efe9..ea887cf2 100644 --- a/nalgebra-glm/src/matrix.rs +++ b/nalgebra-glm/src/matrix.rs @@ -5,13 +5,17 @@ use crate::traits::{Alloc, Dimension, Number}; /// The determinant of the matrix `m`. pub fn determinant(m: &TMat) -> N -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ m.determinant() } /// The inverse of the matrix `m`. pub fn inverse(m: &TMat) -> TMat -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ m.clone() .try_inverse() .unwrap_or_else(TMat::::zeros) @@ -41,6 +45,8 @@ where /// The transpose of the matrix `m`. pub fn transpose(x: &TMat) -> TMat -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.transpose() } diff --git a/nalgebra-glm/src/traits.rs b/nalgebra-glm/src/traits.rs index 22fd5581..24d41083 100644 --- a/nalgebra-glm/src/traits.rs +++ b/nalgebra-glm/src/traits.rs @@ -1,9 +1,10 @@ use approx::AbsDiffEq; use num::{Bounded, FromPrimitive, Signed}; -use alga::general::{Lattice, Ring}; use na::allocator::Allocator; use na::{DimMin, DimName, Scalar, U1}; +use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub}; +use std::cmp::PartialOrd; /// A type-level number representing a vector, matrix row, or matrix column, dimension. pub trait Dimension: DimName + DimMin {} @@ -11,13 +12,33 @@ impl> Dimension for D {} /// A number that can either be an integer or a float. pub trait Number: - Scalar + Copy + Ring + Lattice + AbsDiffEq + Signed + FromPrimitive + Bounded + Scalar + + Copy + + PartialOrd + + ClosedAdd + + ClosedSub + + ClosedMul + + AbsDiffEq + + Signed + + FromPrimitive + + Bounded { } -impl + Signed + FromPrimitive + Bounded> - Number for T -{} +impl< + T: Scalar + + Copy + + PartialOrd + + ClosedAdd + + ClosedSub + + ClosedMul + + AbsDiffEq + + Signed + + FromPrimitive + + Bounded, + > Number for T +{ +} #[doc(hidden)] pub trait Alloc: @@ -50,7 +71,8 @@ pub trait Alloc: { } -impl Alloc for T where T: Allocator +impl Alloc for T where + T: Allocator + Allocator + Allocator + Allocator @@ -76,4 +98,5 @@ impl Alloc for T where T: All + Allocator + Allocator<(usize, usize), R> + Allocator<(usize, usize), C> -{} +{ +} diff --git a/nalgebra-glm/src/trigonometric.rs b/nalgebra-glm/src/trigonometric.rs index 139a48da..adf1a211 100644 --- a/nalgebra-glm/src/trigonometric.rs +++ b/nalgebra-glm/src/trigonometric.rs @@ -5,90 +5,120 @@ use crate::traits::{Alloc, Dimension}; /// Component-wise arc-cosinus. pub fn acos(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|e| e.acos()) } /// Component-wise hyperbolic arc-cosinus. pub fn acosh(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|e| e.acosh()) } /// Component-wise arc-sinus. pub fn asin(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|e| e.asin()) } /// Component-wise hyperbolic arc-sinus. pub fn asinh(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|e| e.asinh()) } /// Component-wise arc-tangent of `y / x`. pub fn atan2(y: &TVec, x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ y.zip_map(x, |y, x| y.atan2(x)) } /// Component-wise arc-tangent. pub fn atan(y_over_x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ y_over_x.map(|e| e.atan()) } /// Component-wise hyperbolic arc-tangent. pub fn atanh(x: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.map(|e| e.atanh()) } /// Component-wise cosinus. pub fn cos(angle: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ angle.map(|e| e.cos()) } /// Component-wise hyperbolic cosinus. pub fn cosh(angle: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ angle.map(|e| e.cosh()) } /// Component-wise conversion from radians to degrees. pub fn degrees(radians: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ radians.map(|e| e * na::convert(180.0) / N::pi()) } /// Component-wise conversion fro degrees to radians. pub fn radians(degrees: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ degrees.map(|e| e * N::pi() / na::convert(180.0)) } /// Component-wise sinus. pub fn sin(angle: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ angle.map(|e| e.sin()) } /// Component-wise hyperbolic sinus. pub fn sinh(angle: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ angle.map(|e| e.sinh()) } /// Component-wise tangent. pub fn tan(angle: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ angle.map(|e| e.tan()) } /// Component-wise hyperbolic tangent. pub fn tanh(angle: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ angle.map(|e| e.tanh()) } diff --git a/nalgebra-glm/src/vector_relational.rs b/nalgebra-glm/src/vector_relational.rs index 844936fe..be17d247 100644 --- a/nalgebra-glm/src/vector_relational.rs +++ b/nalgebra-glm/src/vector_relational.rs @@ -21,7 +21,9 @@ use crate::traits::{Alloc, Dimension, Number}; /// * [`any`](fn.any.html) /// * [`not`](fn.not.html) pub fn all(v: &TVec) -> bool -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.iter().all(|x| *x) } @@ -46,7 +48,9 @@ where DefaultAllocator: Alloc { /// * [`all`](fn.all.html) /// * [`not`](fn.not.html) pub fn any(v: &TVec) -> bool -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.iter().any(|x| *x) } @@ -70,7 +74,9 @@ where DefaultAllocator: Alloc { /// * [`not`](fn.not.html) /// * [`not_equal`](fn.not_equal.html) pub fn equal(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.zip_map(y, |x, y| x == y) } @@ -94,7 +100,9 @@ where DefaultAllocator: Alloc { /// * [`not`](fn.not.html) /// * [`not_equal`](fn.not_equal.html) pub fn greater_than(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.zip_map(y, |x, y| x > y) } @@ -117,10 +125,7 @@ where DefaultAllocator: Alloc { /// * [`less_than_equal`](fn.less_than_equal.html) /// * [`not`](fn.not.html) /// * [`not_equal`](fn.not_equal.html) -pub fn greater_than_equal( - x: &TVec, - y: &TVec, -) -> TVec +pub fn greater_than_equal(x: &TVec, y: &TVec) -> TVec where DefaultAllocator: Alloc, { @@ -147,7 +152,9 @@ where /// * [`not`](fn.not.html) /// * [`not_equal`](fn.not_equal.html) pub fn less_than(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.zip_map(y, |x, y| x < y) } @@ -171,7 +178,9 @@ where DefaultAllocator: Alloc { /// * [`not`](fn.not.html) /// * [`not_equal`](fn.not_equal.html) pub fn less_than_equal(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.zip_map(y, |x, y| x <= y) } @@ -196,7 +205,9 @@ where DefaultAllocator: Alloc { /// * [`less_than_equal`](fn.less_than_equal.html) /// * [`not_equal`](fn.not_equal.html) pub fn not(v: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ v.map(|x| !x) } @@ -220,6 +231,8 @@ where DefaultAllocator: Alloc { /// * [`less_than_equal`](fn.less_than_equal.html) /// * [`not`](fn.not.html) pub fn not_equal(x: &TVec, y: &TVec) -> TVec -where DefaultAllocator: Alloc { +where + DefaultAllocator: Alloc, +{ x.zip_map(y, |x, y| x != y) } diff --git a/nalgebra-glm/tests/lib.rs b/nalgebra-glm/tests/lib.rs index ce95c64f..38f13fd8 100644 --- a/nalgebra-glm/tests/lib.rs +++ b/nalgebra-glm/tests/lib.rs @@ -1,36 +1,36 @@ extern crate nalgebra as na; extern crate nalgebra_glm as glm; -use na::Perspective3; -use na::Orthographic3; use glm::Mat4; use glm::Vec4; +use na::Orthographic3; +use na::Perspective3; #[test] -pub fn orthographic_glm_nalgebra_same() -{ - let na_mat : Mat4 = Orthographic3::new(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner(); - let gl_mat : Mat4 = glm::ortho(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32); +pub fn orthographic_glm_nalgebra_same() { + let na_mat: Mat4 = + Orthographic3::new(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner(); + let gl_mat: Mat4 = glm::ortho(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32); assert_eq!(na_mat, gl_mat); } #[test] -pub fn perspective_glm_nalgebra_same() -{ - let na_mat : Mat4 = Perspective3::new(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32).into_inner(); - let gl_mat : Mat4 = glm::perspective(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32); +pub fn perspective_glm_nalgebra_same() { + let na_mat: Mat4 = + Perspective3::new(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32).into_inner(); + let gl_mat: Mat4 = glm::perspective(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32); assert_eq!(na_mat, gl_mat); } #[test] -pub fn orthographic_glm_nalgebra_project_same() -{ - let point = Vec4::new(1.0,0.0,-20.0,1.0); +pub fn orthographic_glm_nalgebra_project_same() { + let point = Vec4::new(1.0, 0.0, -20.0, 1.0); - let na_mat : Mat4 = Orthographic3::new(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner(); - let gl_mat : Mat4 = glm::ortho(-100.0f32,100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32); + let na_mat: Mat4 = + Orthographic3::new(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner(); + let gl_mat: Mat4 = glm::ortho(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32); let na_pt = na_mat * point; let gl_pt = gl_mat * point; @@ -40,12 +40,12 @@ pub fn orthographic_glm_nalgebra_project_same() } #[test] -pub fn perspective_glm_nalgebra_project_same() -{ - let point = Vec4::new(1.0,0.0,-20.0,1.0); +pub fn perspective_glm_nalgebra_project_same() { + let point = Vec4::new(1.0, 0.0, -20.0, 1.0); - let na_mat : Mat4 = Perspective3::new(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32).into_inner(); - let gl_mat : Mat4 = glm::perspective(16.0f32/9.0f32, 3.14f32/2.0f32, 0.1f32, 100.0f32); + let na_mat: Mat4 = + Perspective3::new(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32).into_inner(); + let gl_mat: Mat4 = glm::perspective(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32); let na_pt = na_mat * point; let gl_pt = gl_mat * point; diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index d00b31d9..b262e8b9 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-lapack" -version = "0.12.0" +version = "0.13.0" authors = [ "Sébastien Crozet ", "Andrew Straw " ] description = "Linear algebra library with transformations and satically-sized or dynamically-sized matrices." @@ -23,10 +23,10 @@ accelerate = ["lapack-src/accelerate"] intel-mkl = ["lapack-src/intel-mkl"] [dependencies] -nalgebra = { version = "0.20", path = ".." } +nalgebra = { version = "0.21", path = ".." } num-traits = "0.2" num-complex = { version = "0.2", default-features = false } -alga = { version = "0.9", default-features = false } +simba = "0.1" serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } lapack = { version = "0.16", default-features = false } @@ -34,7 +34,7 @@ lapack-src = { version = "0.5", default-features = false } # clippy = "*" [dev-dependencies] -nalgebra = { version = "0.20", path = "..", features = [ "arbitrary" ] } +nalgebra = { version = "0.21", path = "..", features = [ "arbitrary" ] } quickcheck = "0.9" approx = "0.3" rand = "0.7" diff --git a/nalgebra-lapack/src/cholesky.rs b/nalgebra-lapack/src/cholesky.rs index e25223fa..669fa671 100644 --- a/nalgebra-lapack/src/cholesky.rs +++ b/nalgebra-lapack/src/cholesky.rs @@ -15,21 +15,18 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator, - MatrixN: Serialize" - )) + serde(bound(serialize = "DefaultAllocator: Allocator, + MatrixN: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator, - MatrixN: Deserialize<'de>" - )) + serde(bound(deserialize = "DefaultAllocator: Allocator, + MatrixN: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Cholesky -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { l: MatrixN, } @@ -38,10 +35,12 @@ impl Copy for Cholesky where DefaultAllocator: Allocator, MatrixN: Copy, -{} +{ +} impl Cholesky -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Computes the cholesky decomposition of the given symmetric-definite-positive square /// matrix. @@ -117,7 +116,9 @@ where DefaultAllocator: Allocator /// Solves in-place the symmetric-definite-positive linear system `self * x = b`, where `x` is /// the unknown to be determined. pub fn solve_mut(&self, b: &mut MatrixMN) -> bool - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let dim = self.l.nrows(); assert!( diff --git a/nalgebra-lapack/src/eigen.rs b/nalgebra-lapack/src/eigen.rs index 91bc01ac..8164c844 100644 --- a/nalgebra-lapack/src/eigen.rs +++ b/nalgebra-lapack/src/eigen.rs @@ -4,13 +4,13 @@ use serde::{Deserialize, Serialize}; use num::Zero; use num_complex::Complex; -use alga::general::RealField; +use simba::scalar::RealField; +use crate::ComplexHelper; use na::allocator::Allocator; use na::dimension::{Dim, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use crate::ComplexHelper; use lapack; @@ -18,23 +18,24 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + Allocator, + serde( + bound(serialize = "DefaultAllocator: Allocator + Allocator, VectorN: Serialize, - MatrixN: Serialize" - )) + MatrixN: Serialize") + ) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + Allocator, + serde( + bound(deserialize = "DefaultAllocator: Allocator + Allocator, VectorN: Serialize, - MatrixN: Deserialize<'de>" - )) + MatrixN: Deserialize<'de>") + ) )] #[derive(Clone, Debug)] pub struct Eigen -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// The eigenvalues of the decomposed matrix. pub eigenvalues: VectorN, @@ -49,10 +50,12 @@ where DefaultAllocator: Allocator + Allocator, VectorN: Copy, MatrixN: Copy, -{} +{ +} impl Eigen -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Computes the eigenvalues and eigenvectors of the square matrix `m`. /// @@ -61,8 +64,7 @@ where DefaultAllocator: Allocator + Allocator mut m: MatrixN, left_eigenvectors: bool, eigenvectors: bool, - ) -> Option> - { + ) -> Option> { assert!( m.is_square(), "Unable to compute the eigenvalue decomposition of a non-square matrix." @@ -228,7 +230,9 @@ where DefaultAllocator: Allocator + Allocator /// /// Panics if the eigenvalue computation does not converge. pub fn complex_eigenvalues(mut m: MatrixN) -> VectorN, D> - where DefaultAllocator: Allocator, D> { + where + DefaultAllocator: Allocator, D>, + { assert!( m.is_square(), "Unable to compute the eigenvalue decomposition of a non-square matrix." diff --git a/nalgebra-lapack/src/hessenberg.rs b/nalgebra-lapack/src/hessenberg.rs index 81e72966..b20df55e 100644 --- a/nalgebra-lapack/src/hessenberg.rs +++ b/nalgebra-lapack/src/hessenberg.rs @@ -1,11 +1,11 @@ use num::Zero; use num_complex::Complex; +use crate::ComplexHelper; use na::allocator::Allocator; use na::dimension::{DimDiff, DimSub, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use crate::ComplexHelper; use lapack; @@ -13,25 +13,22 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator>, MatrixN: Serialize, - VectorN>: Serialize" - )) + VectorN>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator>, MatrixN: Deserialize<'de>, - VectorN>: Deserialize<'de>" - )) + VectorN>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Hessenberg> -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { h: MatrixN, tau: VectorN>, @@ -42,10 +39,12 @@ where DefaultAllocator: Allocator + Allocator>, MatrixN: Copy, VectorN>: Copy, -{} +{ +} impl> Hessenberg -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { /// Computes the hessenberg decomposition of the matrix `m`. pub fn new(mut m: MatrixN) -> Self { @@ -97,7 +96,8 @@ where DefaultAllocator: Allocator + Allocator> } impl> Hessenberg -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { /// Computes the matrices `(Q, H)` of this decomposition. #[inline] diff --git a/nalgebra-lapack/src/lib.rs b/nalgebra-lapack/src/lib.rs index d58aba0b..39965a59 100644 --- a/nalgebra-lapack/src/lib.rs +++ b/nalgebra-lapack/src/lib.rs @@ -73,11 +73,7 @@ html_root_url = "https://nalgebra.org/rustdoc" )] -extern crate alga; -extern crate lapack; -extern crate lapack_src; extern crate nalgebra as na; -extern crate num_complex; extern crate num_traits as num; mod lapack_check; diff --git a/nalgebra-lapack/src/lu.rs b/nalgebra-lapack/src/lu.rs index fb4296da..0ff185d5 100644 --- a/nalgebra-lapack/src/lu.rs +++ b/nalgebra-lapack/src/lu.rs @@ -1,11 +1,11 @@ use num::{One, Zero}; use num_complex::Complex; +use crate::ComplexHelper; use na::allocator::Allocator; use na::dimension::{Dim, DimMin, DimMinimum, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar, VectorN}; -use crate::ComplexHelper; use lapack; @@ -20,25 +20,22 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator>, MatrixMN: Serialize, - PermutationSequence>: Serialize" - )) + PermutationSequence>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator>, MatrixMN: Deserialize<'de>, - PermutationSequence>: Deserialize<'de>" - )) + PermutationSequence>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct LU, C: Dim> -where DefaultAllocator: Allocator> + Allocator +where + DefaultAllocator: Allocator> + Allocator, { lu: MatrixMN, p: VectorN>, @@ -49,7 +46,8 @@ where DefaultAllocator: Allocator + Allocator>, MatrixMN: Copy, VectorN>: Copy, -{} +{ +} impl LU where @@ -133,7 +131,9 @@ where /// Applies the permutation matrix to a given matrix or vector in-place. #[inline] pub fn permute(&self, rhs: &mut MatrixMN) - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = rhs.shape(); N::xlaswp( @@ -148,7 +148,9 @@ where } fn generic_solve_mut(&self, trans: u8, b: &mut MatrixMN) -> bool - where DefaultAllocator: Allocator + Allocator { + where + DefaultAllocator: Allocator + Allocator, + { let dim = self.lu.nrows(); assert!( @@ -236,7 +238,9 @@ where /// /// Returns `false` if no solution was found (the decomposed matrix is singular). pub fn solve_mut(&self, b: &mut MatrixMN) -> bool - where DefaultAllocator: Allocator + Allocator { + where + DefaultAllocator: Allocator + Allocator, + { self.generic_solve_mut(b'N', b) } @@ -245,7 +249,9 @@ where /// /// Returns `false` if no solution was found (the decomposed matrix is singular). pub fn solve_transpose_mut(&self, b: &mut MatrixMN) -> bool - where DefaultAllocator: Allocator + Allocator { + where + DefaultAllocator: Allocator + Allocator, + { self.generic_solve_mut(b'T', b) } @@ -253,10 +259,7 @@ where /// be determined. /// /// Returns `false` if no solution was found (the decomposed matrix is singular). - pub fn solve_adjoint_mut( - &self, - b: &mut MatrixMN, - ) -> bool + pub fn solve_adjoint_mut(&self, b: &mut MatrixMN) -> bool where DefaultAllocator: Allocator + Allocator, { diff --git a/nalgebra-lapack/src/qr.rs b/nalgebra-lapack/src/qr.rs index d9d28910..ac8ad672 100644 --- a/nalgebra-lapack/src/qr.rs +++ b/nalgebra-lapack/src/qr.rs @@ -4,11 +4,11 @@ use serde::{Deserialize, Serialize}; use num::Zero; use num_complex::Complex; +use crate::ComplexHelper; use na::allocator::Allocator; use na::dimension::{Dim, DimMin, DimMinimum, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixMN, Scalar, VectorN}; -use crate::ComplexHelper; use lapack; @@ -16,25 +16,22 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator>, MatrixMN: Serialize, - VectorN>: Serialize" - )) + VectorN>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator>, MatrixMN: Deserialize<'de>, - VectorN>: Deserialize<'de>" - )) + VectorN>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct QR, C: Dim> -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { qr: MatrixMN, tau: VectorN>, @@ -45,13 +42,15 @@ where DefaultAllocator: Allocator + Allocator>, MatrixMN: Copy, VectorN>: Copy, -{} +{ +} impl, C: Dim> QR -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator + Allocator> + Allocator, C> - + Allocator> + + Allocator>, { /// Computes the QR decomposition of the matrix `m`. pub fn new(mut m: MatrixMN) -> Self { @@ -98,10 +97,11 @@ where DefaultAllocator: Allocator } impl, C: Dim> QR -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator + Allocator> + Allocator, C> - + Allocator> + + Allocator>, { /// Retrieves the matrices `(Q, R)` of this decompositions. pub fn unpack( diff --git a/nalgebra-lapack/src/schur.rs b/nalgebra-lapack/src/schur.rs index 0592acdf..5079efbf 100644 --- a/nalgebra-lapack/src/schur.rs +++ b/nalgebra-lapack/src/schur.rs @@ -4,13 +4,13 @@ use serde::{Deserialize, Serialize}; use num::Zero; use num_complex::Complex; -use alga::general::RealField; +use simba::scalar::RealField; +use crate::ComplexHelper; use na::allocator::Allocator; use na::dimension::{Dim, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use crate::ComplexHelper; use lapack; @@ -18,23 +18,24 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + Allocator, + serde( + bound(serialize = "DefaultAllocator: Allocator + Allocator, VectorN: Serialize, - MatrixN: Serialize" - )) + MatrixN: Serialize") + ) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + Allocator, + serde( + bound(deserialize = "DefaultAllocator: Allocator + Allocator, VectorN: Serialize, - MatrixN: Deserialize<'de>" - )) + MatrixN: Deserialize<'de>") + ) )] #[derive(Clone, Debug)] pub struct Schur -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { re: VectorN, im: VectorN, @@ -47,10 +48,12 @@ where DefaultAllocator: Allocator + Allocator, MatrixN: Copy, VectorN: Copy, -{} +{ +} impl Schur -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Computes the eigenvalues and real Schur form of the matrix `m`. /// @@ -145,7 +148,9 @@ where DefaultAllocator: Allocator + Allocator /// Computes the complex eigenvalues of the decomposed matrix. pub fn complex_eigenvalues(&self) -> VectorN, D> - where DefaultAllocator: Allocator, D> { + where + DefaultAllocator: Allocator, D>, + { let mut out = unsafe { VectorN::new_uninitialized_generic(self.t.data.shape().0, U1) }; for i in 0..out.len() { diff --git a/nalgebra-lapack/src/svd.rs b/nalgebra-lapack/src/svd.rs index 43bb1c20..217e8f52 100644 --- a/nalgebra-lapack/src/svd.rs +++ b/nalgebra-lapack/src/svd.rs @@ -15,29 +15,26 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator> + + serde(bound(serialize = "DefaultAllocator: Allocator> + Allocator + Allocator, MatrixN: Serialize, MatrixN: Serialize, - VectorN>: Serialize" - )) + VectorN>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator> + + serde(bound(serialize = "DefaultAllocator: Allocator> + Allocator + Allocator, MatrixN: Deserialize<'de>, MatrixN: Deserialize<'de>, - VectorN>: Deserialize<'de>" - )) + VectorN>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct SVD, C: Dim> -where DefaultAllocator: Allocator + Allocator> + Allocator +where + DefaultAllocator: Allocator + Allocator> + Allocator, { /// The left-singular vectors `U` of this SVD. pub u: MatrixN, // FIXME: should be MatrixMN> @@ -53,25 +50,28 @@ where MatrixMN: Copy, MatrixMN: Copy, VectorN>: Copy, -{} +{ +} /// Trait implemented by floats (`f32`, `f64`) and complex floats (`Complex`, `Complex`) /// supported by the Singular Value Decompotition. pub trait SVDScalar, C: Dim>: Scalar -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator + Allocator + Allocator> - + Allocator + + Allocator, { /// Computes the SVD decomposition of `m`. fn compute(m: MatrixMN) -> Option>; } impl, R: DimMin, C: Dim> SVD -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator + Allocator + Allocator> - + Allocator + + Allocator, { /// Computes the Singular Value Decomposition of `matrix`. pub fn new(m: MatrixMN) -> Option { diff --git a/nalgebra-lapack/src/symmetric_eigen.rs b/nalgebra-lapack/src/symmetric_eigen.rs index e575fdc1..93961328 100644 --- a/nalgebra-lapack/src/symmetric_eigen.rs +++ b/nalgebra-lapack/src/symmetric_eigen.rs @@ -4,13 +4,13 @@ use serde::{Deserialize, Serialize}; use num::Zero; use std::ops::MulAssign; -use alga::general::RealField; +use simba::scalar::RealField; +use crate::ComplexHelper; use na::allocator::Allocator; use na::dimension::{Dim, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use crate::ComplexHelper; use lapack; @@ -18,25 +18,22 @@ use lapack; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator, VectorN: Serialize, - MatrixN: Serialize" - )) + MatrixN: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator, VectorN: Deserialize<'de>, - MatrixN: Deserialize<'de>" - )) + MatrixN: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct SymmetricEigen -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// The eigenvectors of the decomposed matrix. pub eigenvectors: MatrixN, @@ -50,10 +47,12 @@ where DefaultAllocator: Allocator + Allocator, MatrixN: Copy, VectorN: Copy, -{} +{ +} impl SymmetricEigen -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Computes the eigenvalues and eigenvectors of the symmetric matrix `m`. /// @@ -82,8 +81,7 @@ where DefaultAllocator: Allocator + Allocator fn do_decompose( mut m: MatrixN, eigenvectors: bool, - ) -> Option<(VectorN, Option>)> - { + ) -> Option<(VectorN, Option>)> { assert!( m.is_square(), "Unable to compute the eigenvalue decomposition of a non-square matrix." diff --git a/nalgebra-lapack/tests/linalg/cholesky.rs b/nalgebra-lapack/tests/linalg/cholesky.rs index 01561532..f811726a 100644 --- a/nalgebra-lapack/tests/linalg/cholesky.rs +++ b/nalgebra-lapack/tests/linalg/cholesky.rs @@ -3,7 +3,7 @@ use std::cmp; use na::{DMatrix, DVector, Matrix3, Matrix4, Matrix4x3, Vector4}; use nl::Cholesky; -quickcheck!{ +quickcheck! { fn cholesky(m: DMatrix) -> bool { if m.len() != 0 { let m = &m * m.transpose(); diff --git a/nalgebra-lapack/tests/linalg/lu.rs b/nalgebra-lapack/tests/linalg/lu.rs index 652d1032..71293436 100644 --- a/nalgebra-lapack/tests/linalg/lu.rs +++ b/nalgebra-lapack/tests/linalg/lu.rs @@ -3,7 +3,7 @@ use std::cmp; use na::{DMatrix, DVector, Matrix3x4, Matrix4, Matrix4x3, Vector4}; use nl::LU; -quickcheck!{ +quickcheck! { fn lup(m: DMatrix) -> bool { if m.len() != 0 { let lup = LU::new(m.clone()); diff --git a/nalgebra-lapack/tests/linalg/qr.rs b/nalgebra-lapack/tests/linalg/qr.rs index ebdb9b34..1d193a86 100644 --- a/nalgebra-lapack/tests/linalg/qr.rs +++ b/nalgebra-lapack/tests/linalg/qr.rs @@ -1,7 +1,7 @@ use na::{DMatrix, Matrix4x3}; use nl::QR; -quickcheck!{ +quickcheck! { fn qr(m: DMatrix) -> bool { let qr = QR::new(m.clone()); let q = qr.q(); diff --git a/nalgebra-lapack/tests/linalg/real_eigensystem.rs b/nalgebra-lapack/tests/linalg/real_eigensystem.rs index f3130a54..a711d882 100644 --- a/nalgebra-lapack/tests/linalg/real_eigensystem.rs +++ b/nalgebra-lapack/tests/linalg/real_eigensystem.rs @@ -3,7 +3,7 @@ use std::cmp; use na::{DMatrix, Matrix4}; use nl::Eigen; -quickcheck!{ +quickcheck! { fn eigensystem(n: usize) -> bool { if n != 0 { let n = cmp::min(n, 25); diff --git a/nalgebra-lapack/tests/linalg/svd.rs b/nalgebra-lapack/tests/linalg/svd.rs index 9f15b83a..20ebd9d5 100644 --- a/nalgebra-lapack/tests/linalg/svd.rs +++ b/nalgebra-lapack/tests/linalg/svd.rs @@ -1,7 +1,7 @@ use na::{DMatrix, Matrix3x4}; use nl::SVD; -quickcheck!{ +quickcheck! { fn svd(m: DMatrix) -> bool { if m.nrows() != 0 && m.ncols() != 0 { let svd = SVD::new(m.clone()).unwrap(); diff --git a/nalgebra-lapack/tests/linalg/symmetric_eigen.rs b/nalgebra-lapack/tests/linalg/symmetric_eigen.rs index 42074ada..1d47f982 100644 --- a/nalgebra-lapack/tests/linalg/symmetric_eigen.rs +++ b/nalgebra-lapack/tests/linalg/symmetric_eigen.rs @@ -3,7 +3,7 @@ use std::cmp; use na::{DMatrix, Matrix4}; use nl::SymmetricEigen; -quickcheck!{ +quickcheck! { fn symmetric_eigen(n: usize) -> bool { let n = cmp::max(1, cmp::min(n, 10)); let m = DMatrix::::new_random(n, n); diff --git a/src/base/alias.rs b/src/base/alias.rs index a8925cf3..e798ea35 100644 --- a/src/base/alias.rs +++ b/src/base/alias.rs @@ -1,9 +1,9 @@ #[cfg(any(feature = "alloc", feature = "std"))] use crate::base::dimension::Dynamic; use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::storage::Owned; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::vec_storage::VecStorage; -use crate::base::storage::Owned; use crate::base::Matrix; /* diff --git a/src/base/alias_slice.rs b/src/base/alias_slice.rs index 3a332def..ee55f15b 100644 --- a/src/base/alias_slice.rs +++ b/src/base/alias_slice.rs @@ -179,20 +179,27 @@ pub type VectorSliceN<'a, N, D, RStride = U1, CStride = D> = Matrix>; /// A column vector slice dynamic numbers of rows and columns. -pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceN<'a, N, Dynamic, RStride, CStride>; +pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = + VectorSliceN<'a, N, Dynamic, RStride, CStride>; /// A 1D column vector slice. -pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = VectorSliceN<'a, N, U1, RStride, CStride>; +pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = + VectorSliceN<'a, N, U1, RStride, CStride>; /// A 2D column vector slice. -pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = VectorSliceN<'a, N, U2, RStride, CStride>; +pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = + VectorSliceN<'a, N, U2, RStride, CStride>; /// A 3D column vector slice. -pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = VectorSliceN<'a, N, U3, RStride, CStride>; +pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = + VectorSliceN<'a, N, U3, RStride, CStride>; /// A 4D column vector slice. -pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = VectorSliceN<'a, N, U4, RStride, CStride>; +pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = + VectorSliceN<'a, N, U4, RStride, CStride>; /// A 5D column vector slice. -pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = VectorSliceN<'a, N, U5, RStride, CStride>; +pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = + VectorSliceN<'a, N, U5, RStride, CStride>; /// A 6D column vector slice. -pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = VectorSliceN<'a, N, U6, RStride, CStride>; +pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = + VectorSliceN<'a, N, U6, RStride, CStride>; /* * @@ -371,17 +378,24 @@ pub type VectorSliceMutN<'a, N, D, RStride = U1, CStride = D> = Matrix>; /// A mutable column vector slice dynamic numbers of rows and columns. -pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = VectorSliceMutN<'a, N, Dynamic, RStride, CStride>; +pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = + VectorSliceMutN<'a, N, Dynamic, RStride, CStride>; /// A 1D mutable column vector slice. -pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = VectorSliceMutN<'a, N, U1, RStride, CStride>; +pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = + VectorSliceMutN<'a, N, U1, RStride, CStride>; /// A 2D mutable column vector slice. -pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = VectorSliceMutN<'a, N, U2, RStride, CStride>; +pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = + VectorSliceMutN<'a, N, U2, RStride, CStride>; /// A 3D mutable column vector slice. -pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = VectorSliceMutN<'a, N, U3, RStride, CStride>; +pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = + VectorSliceMutN<'a, N, U3, RStride, CStride>; /// A 4D mutable column vector slice. -pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = VectorSliceMutN<'a, N, U4, RStride, CStride>; +pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = + VectorSliceMutN<'a, N, U4, RStride, CStride>; /// A 5D mutable column vector slice. -pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = VectorSliceMutN<'a, N, U5, RStride, CStride>; +pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = + VectorSliceMutN<'a, N, U5, RStride, CStride>; /// A 6D mutable column vector slice. -pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = VectorSliceMutN<'a, N, U6, RStride, CStride>; +pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = + VectorSliceMutN<'a, N, U6, RStride, CStride>; diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 0ad30981..1b2122db 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -79,7 +79,8 @@ where N: Scalar, DefaultAllocator: Allocator + Allocator, SameShapeC>, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, -{} +{ +} // XXX: Bad name. /// Restricts the given number of rows to be equal. @@ -100,4 +101,5 @@ where N: Scalar, DefaultAllocator: Allocator + Allocator>, ShapeConstraint: SameNumberOfRows, -{} +{ +} diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index bebb8740..3ff06e89 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -44,7 +44,7 @@ where data: GenericArray>, } -#[deprecated(note="renamed to `ArrayStorage`")] +#[deprecated(note = "renamed to `ArrayStorage`")] /// Renamed to [ArrayStorage]. pub type MatrixArray = ArrayStorage; @@ -111,7 +111,8 @@ where R::Value: Mul, Prod: ArrayLength, GenericArray>: Copy, -{} +{ +} impl Clone for ArrayStorage where @@ -136,7 +137,8 @@ where C: DimName, R::Value: Mul, Prod: ArrayLength, -{} +{ +} impl PartialEq for ArrayStorage where @@ -186,13 +188,17 @@ where #[inline] fn into_owned(self) -> Owned - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self } #[inline] fn clone_owned(&self) -> Owned - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let it = self.iter().cloned(); DefaultAllocator::allocate_from_iterator(self.shape().0, self.shape().1, it) @@ -232,7 +238,8 @@ where R::Value: Mul, Prod: ArrayLength, DefaultAllocator: Allocator, -{} +{ +} unsafe impl ContiguousStorageMut for ArrayStorage where @@ -242,7 +249,8 @@ where R::Value: Mul, Prod: ArrayLength, DefaultAllocator: Allocator, -{} +{ +} /* * @@ -260,7 +268,9 @@ where Prod: ArrayLength, { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { let mut serializer = serializer.serialize_seq(Some(R::dim() * C::dim()))?; for e in self.iter() { @@ -281,7 +291,9 @@ where Prod: ArrayLength, { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'a> { + where + D: Deserializer<'a>, + { deserializer.deserialize_seq(ArrayStorageVisitor::new()) } } @@ -326,12 +338,15 @@ where #[inline] fn visit_seq(self, mut visitor: V) -> Result, V::Error> - where V: SeqAccess<'a> { + where + V: SeqAccess<'a>, + { let mut out: Self::Value = unsafe { mem::uninitialized() }; let mut curr = 0; while let Some(value) = visitor.next_element()? { - *out.get_mut(curr).ok_or_else(|| V::Error::invalid_length(curr, &self))? = value; + *out.get_mut(curr) + .ok_or_else(|| V::Error::invalid_length(curr, &self))? = value; curr += 1; } diff --git a/src/base/blas.rs b/src/base/blas.rs index d147bbcb..add17af2 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -1,7 +1,8 @@ -use alga::general::{ClosedAdd, ClosedMul, ComplexField}; +use crate::SimdComplexField; #[cfg(feature = "std")] use matrixmultiply; use num::{One, Signed, Zero}; +use simba::scalar::{ClosedAdd, ClosedMul, ComplexField}; #[cfg(feature = "std")] use std::mem; @@ -11,8 +12,9 @@ use crate::base::constraint::{ }; use crate::base::dimension::{Dim, Dynamic, U1, U2, U3, U4}; use crate::base::storage::{Storage, StorageMut}; -use crate::base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, DVectorSlice, VectorSliceN}; - +use crate::base::{ + DVectorSlice, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorSliceN, +}; // FIXME: find a way to avoid code duplication just for complex number support. impl> Vector { @@ -102,7 +104,9 @@ impl> Vector { /// ``` #[inline] pub fn iamax(&self) -> usize - where N: Signed { + where + N: Signed, + { assert!(!self.is_empty(), "The input vector must not be empty."); let mut the_max = unsafe { self.vget_unchecked(0).abs() }; @@ -173,7 +177,9 @@ impl> Vector { /// ``` #[inline] pub fn iamin(&self) -> usize - where N: Signed { + where + N: Signed, + { assert!(!self.is_empty(), "The input vector must not be empty."); let mut the_min = unsafe { self.vget_unchecked(0).abs() }; @@ -229,7 +235,6 @@ impl> Matrix { } } - impl> Matrix { /// Computes the index of the matrix component with the largest absolute value. /// @@ -264,13 +269,18 @@ impl> Matri } impl> Matrix -where N: Scalar + Zero + ClosedAdd + ClosedMul +where + N: Scalar + Zero + ClosedAdd + ClosedMul, { #[inline(always)] - fn dotx(&self, rhs: &Matrix, conjugate: impl Fn(N) -> N) -> N - where - SB: Storage, - ShapeConstraint: DimEq + DimEq, + fn dotx( + &self, + rhs: &Matrix, + conjugate: impl Fn(N) -> N, + ) -> N + where + SB: Storage, + ShapeConstraint: DimEq + DimEq, { assert!( self.nrows() == rhs.nrows(), @@ -281,27 +291,36 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul // because the `for` loop below won't be very efficient on those. if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { 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)).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(); return a + b; } } if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { 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)).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(); return a + b + c; } } if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { 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)).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(); a += c; b += d; @@ -341,14 +360,38 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul acc7 = N::zero(); while self.nrows() - i >= 8 { - acc0 += unsafe { conjugate(self.get_unchecked((i + 0, j)).inlined_clone()) * rhs.get_unchecked((i + 0, j)).inlined_clone() }; - acc1 += unsafe { conjugate(self.get_unchecked((i + 1, j)).inlined_clone()) * rhs.get_unchecked((i + 1, j)).inlined_clone() }; - acc2 += unsafe { conjugate(self.get_unchecked((i + 2, j)).inlined_clone()) * rhs.get_unchecked((i + 2, j)).inlined_clone() }; - acc3 += unsafe { conjugate(self.get_unchecked((i + 3, j)).inlined_clone()) * rhs.get_unchecked((i + 3, j)).inlined_clone() }; - acc4 += unsafe { conjugate(self.get_unchecked((i + 4, j)).inlined_clone()) * rhs.get_unchecked((i + 4, j)).inlined_clone() }; - acc5 += unsafe { conjugate(self.get_unchecked((i + 5, j)).inlined_clone()) * rhs.get_unchecked((i + 5, j)).inlined_clone() }; - acc6 += unsafe { conjugate(self.get_unchecked((i + 6, j)).inlined_clone()) * rhs.get_unchecked((i + 6, j)).inlined_clone() }; - acc7 += unsafe { conjugate(self.get_unchecked((i + 7, j)).inlined_clone()) * rhs.get_unchecked((i + 7, j)).inlined_clone() }; + acc0 += unsafe { + conjugate(self.get_unchecked((i + 0, j)).inlined_clone()) + * rhs.get_unchecked((i + 0, j)).inlined_clone() + }; + acc1 += unsafe { + conjugate(self.get_unchecked((i + 1, j)).inlined_clone()) + * rhs.get_unchecked((i + 1, j)).inlined_clone() + }; + acc2 += unsafe { + conjugate(self.get_unchecked((i + 2, j)).inlined_clone()) + * rhs.get_unchecked((i + 2, j)).inlined_clone() + }; + acc3 += unsafe { + conjugate(self.get_unchecked((i + 3, j)).inlined_clone()) + * rhs.get_unchecked((i + 3, j)).inlined_clone() + }; + acc4 += unsafe { + conjugate(self.get_unchecked((i + 4, j)).inlined_clone()) + * rhs.get_unchecked((i + 4, j)).inlined_clone() + }; + acc5 += unsafe { + conjugate(self.get_unchecked((i + 5, j)).inlined_clone()) + * rhs.get_unchecked((i + 5, j)).inlined_clone() + }; + acc6 += unsafe { + conjugate(self.get_unchecked((i + 6, j)).inlined_clone()) + * rhs.get_unchecked((i + 6, j)).inlined_clone() + }; + acc7 += unsafe { + conjugate(self.get_unchecked((i + 7, j)).inlined_clone()) + * rhs.get_unchecked((i + 7, j)).inlined_clone() + }; i += 8; } @@ -358,14 +401,16 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul res += acc3 + acc7; for k in i..self.nrows() { - res += unsafe { conjugate(self.get_unchecked((k, j)).inlined_clone()) * rhs.get_unchecked((k, j)).inlined_clone() } + res += unsafe { + conjugate(self.get_unchecked((k, j)).inlined_clone()) + * rhs.get_unchecked((k, j)).inlined_clone() + } } } res } - /// The dot product between two vectors or matrices (seen as vectors). /// /// This is equal to `self.transpose() * rhs`. For the sesquilinear complex dot product, use @@ -419,12 +464,12 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul /// ``` #[inline] pub fn dotc(&self, rhs: &Matrix) -> N - where - N: ComplexField, - SB: Storage, - ShapeConstraint: DimEq + DimEq, + where + N: SimdComplexField, + SB: Storage, + ShapeConstraint: DimEq + DimEq, { - self.dotx(rhs, ComplexField::conjugate) + self.dotx(rhs, N::simd_conjugate) } /// The dot product between the transpose of `self` and `rhs`. @@ -460,7 +505,10 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul 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() } + res += unsafe { + self.get_unchecked((j, i)).inlined_clone() + * rhs.get_unchecked((i, j)).inlined_clone() + } } } @@ -468,21 +516,38 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul } } -fn array_axcpy(y: &mut [N], a: N, x: &[N], c: N, beta: N, stride1: usize, stride2: usize, len: usize) -where N: Scalar + Zero + ClosedAdd + ClosedMul { +fn array_axcpy( + y: &mut [N], + a: N, + x: &[N], + c: N, + beta: N, + stride1: usize, + stride2: usize, + len: usize, +) where + N: 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(); + *y = a.inlined_clone() + * x.get_unchecked(i * stride2).inlined_clone() + * c.inlined_clone() + + beta.inlined_clone() * y.inlined_clone(); } } } fn array_axc(y: &mut [N], a: N, x: &[N], c: N, stride1: usize, stride2: usize, len: usize) -where N: Scalar + Zero + ClosedAdd + ClosedMul { +where + N: 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(); + *y.get_unchecked_mut(i * stride1) = a.inlined_clone() + * x.get_unchecked(i * stride2).inlined_clone() + * c.inlined_clone(); } } } @@ -613,7 +678,6 @@ where } } - #[inline(always)] fn xxgemv( &mut self, @@ -621,7 +685,10 @@ where a: &SquareMatrix, x: &Vector, beta: N, - dot: impl Fn(&DVectorSlice, &DVectorSlice) -> N, + dot: impl Fn( + &DVectorSlice, + &DVectorSlice, + ) -> N, ) where N: One, SB: Storage, @@ -660,8 +727,11 @@ where val = x.vget_unchecked(j).inlined_clone(); *self.vget_unchecked_mut(j) += alpha.inlined_clone() * dot; } - self.rows_range_mut(j + 1..) - .axpy(alpha.inlined_clone() * val, &col2.rows_range(j + 1..), N::one()); + self.rows_range_mut(j + 1..).axpy( + alpha.inlined_clone() * val, + &col2.rows_range(j + 1..), + N::one(), + ); } } @@ -765,7 +835,7 @@ where x: &Vector, beta: N, ) where - N: ComplexField, + N: SimdComplexField, SB: Storage, SC: Storage, ShapeConstraint: DimEq + AreMultipliable, @@ -773,7 +843,6 @@ where self.xxgemv(alpha, a, x, beta, |a, b| a.dotc(b)) } - #[inline(always)] fn gemv_xx( &mut self, @@ -809,12 +878,12 @@ where } 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.inlined_clone() * dot(&a.column(j), x) + + beta.inlined_clone() * val.inlined_clone(); } } } - /// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and /// `alpha, beta` two scalars. /// @@ -876,7 +945,7 @@ where x: &Vector, beta: N, ) where - N: ComplexField, + N: SimdComplexField, SB: Storage, SC: Storage, ShapeConstraint: DimEq + AreMultipliable, @@ -886,7 +955,8 @@ where } impl> Matrix -where N: Scalar + Zero + ClosedAdd + ClosedMul +where + N: Scalar + Zero + ClosedAdd + ClosedMul, { #[inline(always)] fn gerx( @@ -914,7 +984,8 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul for j in 0..ncols1 { // FIXME: avoid bound checks. let val = unsafe { conjugate(y.vget_unchecked(j).inlined_clone()) }; - self.column_mut(j).axpy(alpha.inlined_clone() * val, x, beta.inlined_clone()); + self.column_mut(j) + .axpy(alpha.inlined_clone() * val, x, beta.inlined_clone()); } } @@ -975,12 +1046,12 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul y: &Vector, beta: N, ) where - N: ComplexField, + N: SimdComplexField, SB: Storage, SC: Storage, ShapeConstraint: DimEq + DimEq, { - self.gerx(alpha, x, y, beta, ComplexField::conjugate) + self.gerx(alpha, x, y, beta, SimdComplexField::simd_conjugate) } /// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices. @@ -1032,7 +1103,8 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul || R2::is::() || C2::is::() || R3::is::() - || C3::is::() { + || C3::is::() + { // matrixmultiply can be used only if the std feature is available. let nrows1 = self.nrows(); let (nrows2, ncols2) = a.shape(); @@ -1125,10 +1197,14 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul } } - for j1 in 0..ncols1 { // FIXME: avoid bound checks. - self.column_mut(j1).gemv(alpha.inlined_clone(), a, &b.column(j1), beta.inlined_clone()); + self.column_mut(j1).gemv( + alpha.inlined_clone(), + a, + &b.column(j1), + beta.inlined_clone(), + ); } } @@ -1185,11 +1261,15 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul for j1 in 0..ncols1 { // FIXME: 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.inlined_clone(), + a, + &b.column(j1), + beta.inlined_clone(), + ); } } - /// Computes `self = alpha * a.adjoint() * b + beta * self`, where `a, b, self` are matrices. /// `alpha` and `beta` are scalar. /// @@ -1220,12 +1300,12 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul b: &Matrix, beta: N, ) where - N: ComplexField, + N: SimdComplexField, SB: Storage, SC: Storage, ShapeConstraint: SameNumberOfRows - + SameNumberOfColumns - + AreMultipliable, + + SameNumberOfColumns + + AreMultipliable, { let (nrows1, ncols1) = self.shape(); let (nrows2, ncols2) = a.shape(); @@ -1249,7 +1329,8 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul } impl> Matrix -where N: Scalar + Zero + ClosedAdd + ClosedMul +where + N: Scalar + Zero + ClosedAdd + ClosedMul, { #[inline(always)] fn xxgerx( @@ -1386,17 +1467,18 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul y: &Vector, beta: N, ) where - N: ComplexField, + N: SimdComplexField, SB: Storage, SC: Storage, ShapeConstraint: DimEq + DimEq, { - self.xxgerx(alpha, x, y, beta, ComplexField::conjugate) + self.xxgerx(alpha, x, y, beta, SimdComplexField::simd_conjugate) } } impl> SquareMatrix -where N: Scalar + Zero + One + ClosedAdd + ClosedMul +where + N: Scalar + Zero + One + ClosedAdd + ClosedMul, { /// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`. /// @@ -1534,11 +1616,13 @@ where N: Scalar + Zero + One + ClosedAdd + ClosedMul DimEq + DimEq + DimEq + AreMultipliable, { work.gemv(N::one(), mid, &rhs.column(0), N::zero()); - self.column_mut(0).gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); + self.column_mut(0) + .gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); for j in 1..rhs.ncols() { work.gemv(N::one(), mid, &rhs.column(j), N::zero()); - self.column_mut(j).gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); + self.column_mut(j) + .gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); } } diff --git a/src/base/cg.rs b/src/base/cg.rs index d999bb16..6a7db4bd 100644 --- a/src/base/cg.rs +++ b/src/base/cg.rs @@ -5,7 +5,7 @@ * */ -use num::One; +use num::{One, Zero}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameDiff, DimNameSub, U1}; @@ -18,12 +18,11 @@ use crate::geometry::{ Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point3, Rotation2, Rotation3, }; -use alga::general::{RealField, Ring}; -use alga::linear::Transformation; +use simba::scalar::{ClosedAdd, ClosedMul, RealField}; impl MatrixN where - N: Scalar + Ring, + N: Scalar + Zero + One, DefaultAllocator: Allocator, { /// Creates a new homogeneous matrix that applies the same scaling factor on each dimension. @@ -42,7 +41,7 @@ where D: DimNameSub, SB: Storage>, { - let mut res = Self::one(); + let mut res = Self::identity(); for i in 0..scaling.len() { res[(i, i)] = scaling[i].inlined_clone(); } @@ -57,7 +56,7 @@ where D: DimNameSub, SB: Storage>, { - let mut res = Self::one(); + let mut res = Self::identity(); res.fixed_slice_mut::, U1>(0, D::dim() - 1) .copy_from(translation); @@ -135,7 +134,7 @@ impl Matrix4 { } /// Deprecated: Use [Matrix4::face_towards] instead. - #[deprecated(note="renamed to `face_towards`")] + #[deprecated(note = "renamed to `face_towards`")] pub fn new_observer_frame(eye: &Point3, target: &Point3, up: &Vector3) -> Self { Matrix4::face_towards(eye, target, up) } @@ -153,7 +152,9 @@ impl Matrix4 { } } -impl> SquareMatrix { +impl> + SquareMatrix +{ /// Computes the transformation equal to `self` followed by an uniform scaling factor. #[inline] #[must_use = "Did you mean to use append_scaling_mut()?"] @@ -246,11 +247,15 @@ impl> SquareMatrix { } } -impl> SquareMatrix { +impl> + SquareMatrix +{ /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor. #[inline] pub fn append_scaling_mut(&mut self, scaling: N) - where D: DimNameSub { + where + D: DimNameSub, + { let mut to_scale = self.fixed_rows_mut::>(0); to_scale *= scaling; } @@ -258,7 +263,9 @@ impl> SquareMatrix /// Computes in-place the transformation equal to an uniform scaling factor followed by `self`. #[inline] pub fn prepend_scaling_mut(&mut self, scaling: N) - where D: DimNameSub { + where + D: DimNameSub, + { let mut to_scale = self.fixed_columns_mut::>(0); to_scale *= scaling; } @@ -328,17 +335,17 @@ impl> SquareMatrix } impl, S: Storage> SquareMatrix -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator + Allocator> - + Allocator, DimNameDiff> + + Allocator, DimNameDiff>, { /// Transforms the given vector, assuming the matrix `self` uses homogeneous coordinates. #[inline] pub fn transform_vector( &self, v: &VectorN>, - ) -> VectorN> - { + ) -> VectorN> { let transform = self.fixed_slice::, DimNameDiff>(0, 0); let normalizer = self.fixed_slice::>(D::dim() - 1, 0); let n = normalizer.tr_dot(&v); @@ -355,8 +362,7 @@ where DefaultAllocator: Allocator pub fn transform_point( &self, pt: &Point>, - ) -> Point> - { + ) -> Point> { let transform = self.fixed_slice::, DimNameDiff>(0, 0); let translation = self.fixed_slice::, U1>(0, D::dim() - 1); let normalizer = self.fixed_slice::>(D::dim() - 1, 0); @@ -370,23 +376,3 @@ where DefaultAllocator: Allocator } } } - -impl> Transformation>> for MatrixN -where DefaultAllocator: Allocator - + Allocator> - + Allocator, DimNameDiff> -{ - #[inline] - fn transform_vector( - &self, - v: &VectorN>, - ) -> VectorN> - { - self.transform_vector(v) - } - - #[inline] - fn transform_point(&self, pt: &Point>) -> Point> { - self.transform_point(pt) - } -} diff --git a/src/base/componentwise.rs b/src/base/componentwise.rs index c4ce1293..d5a57b6c 100644 --- a/src/base/componentwise.rs +++ b/src/base/componentwise.rs @@ -3,7 +3,8 @@ use num::{Signed, Zero}; use std::ops::{Add, Mul}; -use alga::general::{ClosedDiv, ClosedMul}; +use simba::scalar::{ClosedDiv, ClosedMul}; +use simba::simd::SimdPartialOrd; use crate::base::allocator::{Allocator, SameShapeAllocator}; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; @@ -235,3 +236,31 @@ component_binop_impl!( "; // FIXME: add other operators like bitshift, etc. ? ); + +/* + * inf/sup + */ +impl> Matrix +where + N: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + /// Computes the infimum (aka. componentwise min) of two matrices/vectors. + #[inline] + pub fn inf(&self, other: &Self) -> MatrixMN { + self.zip_map(other, |a, b| a.simd_min(b)) + } + + /// Computes the supremum (aka. componentwise max) of two matrices/vectors. + #[inline] + pub fn sup(&self, other: &Self) -> MatrixMN { + self.zip_map(other, |a, b| a.simd_max(b)) + } + + /// Computes the (infimum, supremum) of two matrices/vectors. + #[inline] + pub fn inf_sup(&self, other: &Self) -> (MatrixMN, MatrixMN) { + // FIXME: can this be optimized? + (self.inf(other), self.sup(other)) + } +} diff --git a/src/base/constraint.rs b/src/base/constraint.rs index 89226fe3..f681dc25 100644 --- a/src/base/constraint.rs +++ b/src/base/constraint.rs @@ -8,8 +8,10 @@ pub struct ShapeConstraint; /// Constraints `C1` and `R2` to be equivalent. pub trait AreMultipliable: DimEq {} -impl AreMultipliable for ShapeConstraint where ShapeConstraint: DimEq -{} +impl AreMultipliable for ShapeConstraint where + ShapeConstraint: DimEq +{ +} /// Constraints `D1` and `D2` to be equivalent. pub trait DimEq { diff --git a/src/base/construction.rs b/src/base/construction.rs index f6056576..ae8c10d4 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -4,18 +4,18 @@ use crate::base::storage::Owned; use quickcheck::{Arbitrary, Gen}; use num::{Bounded, One, Zero}; -use rand::distributions::{Distribution, Standard}; -use rand::Rng; #[cfg(feature = "std")] use rand; +use rand::distributions::{Distribution, Standard}; +use rand::Rng; #[cfg(feature = "std")] use rand_distr::StandardNormal; use std::iter; use typenum::{self, Cmp, Greater}; #[cfg(feature = "std")] -use alga::general::RealField; -use alga::general::{ClosedAdd, ClosedMul}; +use simba::scalar::RealField; +use simba::scalar::{ClosedAdd, ClosedMul}; use crate::base::allocator::Allocator; use crate::base::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6}; @@ -28,7 +28,8 @@ use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar, Unit, Vec * */ impl MatrixMN -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Creates a new uninitialized matrix. If the matrix has a compile-time dimension, this panics /// if `nrows != R::to_usize()` or `ncols != C::to_usize()`. @@ -56,14 +57,18 @@ where DefaultAllocator: Allocator /// Creates a matrix with all its elements set to 0. #[inline] pub fn zeros_generic(nrows: R, ncols: C) -> Self - where N: Zero { + where + N: Zero, + { Self::from_element_generic(nrows, ncols, N::zero()) } /// Creates a matrix with all its elements filled by an iterator. #[inline] pub fn from_iterator_generic(nrows: R, ncols: C, iter: I) -> Self - where I: IntoIterator { + where + I: IntoIterator, + { Self::from_data(DefaultAllocator::allocate_from_iterator(nrows, ncols, iter)) } @@ -102,7 +107,9 @@ where DefaultAllocator: Allocator /// coordinates. #[inline] pub fn from_fn_generic(nrows: R, ncols: C, mut f: F) -> Self - where F: FnMut(usize, usize) -> N { + where + F: FnMut(usize, usize) -> N, + { let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) }; for j in 0..ncols.value() { @@ -120,7 +127,9 @@ where DefaultAllocator: Allocator /// to the identity matrix. All other entries are set to zero. #[inline] pub fn identity_generic(nrows: R, ncols: C) -> Self - where N: Zero + One { + where + N: Zero + One, + { Self::from_diagonal_element_generic(nrows, ncols, N::one()) } @@ -130,7 +139,9 @@ where DefaultAllocator: Allocator /// to the identity matrix. All other entries are set to zero. #[inline] pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: N) -> Self - where N: Zero + One { + where + N: Zero + One, + { let mut res = Self::zeros_generic(nrows, ncols); for i in 0..crate::min(nrows.value(), ncols.value()) { @@ -146,7 +157,9 @@ where DefaultAllocator: Allocator /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. #[inline] pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[N]) -> Self - where N: Zero { + where + N: Zero, + { let mut res = Self::zeros_generic(nrows, ncols); assert!( elts.len() <= crate::min(nrows.value(), ncols.value()), @@ -178,7 +191,9 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn from_rows(rows: &[Matrix]) -> Self - where SB: Storage { + where + SB: Storage, + { assert!(rows.len() > 0, "At least one row must be given."); let nrows = R::try_to_usize().unwrap_or(rows.len()); let ncols = rows[0].len(); @@ -218,7 +233,9 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn from_columns(columns: &[Vector]) -> Self - where SB: Storage { + where + SB: Storage, + { assert!(columns.len() > 0, "At least one column must be given."); let ncols = C::try_to_usize().unwrap_or(columns.len()); let nrows = columns[0].len(); @@ -244,7 +261,9 @@ where DefaultAllocator: Allocator #[inline] #[cfg(feature = "std")] pub fn new_random_generic(nrows: R, ncols: C) -> Self - where Standard: Distribution { + where + Standard: Distribution, + { Self::from_fn_generic(nrows, ncols, |_, _| rand::random()) } @@ -255,8 +274,7 @@ where DefaultAllocator: Allocator ncols: C, distribution: &Distr, rng: &mut G, - ) -> Self - { + ) -> Self { Self::from_fn_generic(nrows, ncols, |_, _| distribution.sample(rng)) } @@ -309,7 +327,9 @@ where /// ``` #[inline] pub fn from_diagonal>(diag: &Vector) -> Self - where N: Zero { + where + N: Zero, + { let (dim, _) = diag.data.shape(); let mut res = Self::zeros_generic(dim, dim); @@ -576,9 +596,9 @@ macro_rules! impl_constructors( // FIXME: this is not very pretty. We could find a better call syntax. impl_constructors!(R, C; // Arguments for Matrix - => R: DimName, => C: DimName; // Type parameters for impl - R::name(), C::name(); // Arguments for `_generic` constructors. - ); // Arguments for non-generic constructors. +=> R: DimName, => C: DimName; // Type parameters for impl +R::name(), C::name(); // Arguments for `_generic` constructors. +); // Arguments for non-generic constructors. impl_constructors!(R, Dynamic; => R: DimName; @@ -693,27 +713,25 @@ macro_rules! impl_constructors_from_data( // FIXME: this is not very pretty. We could find a better call syntax. impl_constructors_from_data!(data; R, C; // Arguments for Matrix - => R: DimName, => C: DimName; // Type parameters for impl - R::name(), C::name(); // Arguments for `_generic` constructors. - ); // Arguments for non-generic constructors. +=> R: DimName, => C: DimName; // Type parameters for impl +R::name(), C::name(); // Arguments for `_generic` constructors. +); // Arguments for non-generic constructors. impl_constructors_from_data!(data; R, Dynamic; - => R: DimName; - R::name(), Dynamic::new(data.len() / R::dim()); - ); +=> R: DimName; +R::name(), Dynamic::new(data.len() / R::dim()); +); impl_constructors_from_data!(data; Dynamic, C; - => C: DimName; - Dynamic::new(data.len() / C::dim()), C::name(); - ); +=> C: DimName; +Dynamic::new(data.len() / C::dim()), C::name(); +); impl_constructors_from_data!(data; Dynamic, Dynamic; ; Dynamic::new(nrows), Dynamic::new(ncols); nrows, ncols); - - /* * * Zero, One, Rand traits. @@ -996,7 +1014,9 @@ where /// The column vector with a 1 as its first component, and zero elsewhere. #[inline] pub fn x() -> Self - where R::Value: Cmp { + where + R::Value: Cmp, + { let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(0) = N::one(); @@ -1008,7 +1028,9 @@ where /// The column vector with a 1 as its second component, and zero elsewhere. #[inline] pub fn y() -> Self - where R::Value: Cmp { + where + R::Value: Cmp, + { let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(1) = N::one(); @@ -1020,7 +1042,9 @@ where /// The column vector with a 1 as its third component, and zero elsewhere. #[inline] pub fn z() -> Self - where R::Value: Cmp { + where + R::Value: Cmp, + { let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(2) = N::one(); @@ -1032,7 +1056,9 @@ where /// The column vector with a 1 as its fourth component, and zero elsewhere. #[inline] pub fn w() -> Self - where R::Value: Cmp { + where + R::Value: Cmp, + { let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(3) = N::one(); @@ -1044,7 +1070,9 @@ where /// The column vector with a 1 as its fifth component, and zero elsewhere. #[inline] pub fn a() -> Self - where R::Value: Cmp { + where + R::Value: Cmp, + { let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(4) = N::one(); @@ -1056,7 +1084,9 @@ where /// The column vector with a 1 as its sixth component, and zero elsewhere. #[inline] pub fn b() -> Self - where R::Value: Cmp { + where + R::Value: Cmp, + { let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(5) = N::one(); @@ -1068,42 +1098,54 @@ where /// The unit column vector with a 1 as its first component, and zero elsewhere. #[inline] pub fn x_axis() -> Unit - where R::Value: Cmp { + where + R::Value: Cmp, + { Unit::new_unchecked(Self::x()) } /// The unit column vector with a 1 as its second component, and zero elsewhere. #[inline] pub fn y_axis() -> Unit - where R::Value: Cmp { + where + R::Value: Cmp, + { Unit::new_unchecked(Self::y()) } /// The unit column vector with a 1 as its third component, and zero elsewhere. #[inline] pub fn z_axis() -> Unit - where R::Value: Cmp { + where + R::Value: Cmp, + { Unit::new_unchecked(Self::z()) } /// The unit column vector with a 1 as its fourth component, and zero elsewhere. #[inline] pub fn w_axis() -> Unit - where R::Value: Cmp { + where + R::Value: Cmp, + { Unit::new_unchecked(Self::w()) } /// The unit column vector with a 1 as its fifth component, and zero elsewhere. #[inline] pub fn a_axis() -> Unit - where R::Value: Cmp { + where + R::Value: Cmp, + { Unit::new_unchecked(Self::a()) } /// The unit column vector with a 1 as its sixth component, and zero elsewhere. #[inline] pub fn b_axis() -> Unit - where R::Value: Cmp { + where + R::Value: Cmp, + { Unit::new_unchecked(Self::b()) } } diff --git a/src/base/construction_slice.rs b/src/base/construction_slice.rs index 4f745a65..d63b374b 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_slice.rs @@ -23,8 +23,7 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> ncols: C, rstride: RStride, cstride: CStride, - ) -> Self - { + ) -> Self { let data = SliceStorage::from_raw_parts( data.as_ptr().offset(start as isize), (nrows, ncols), @@ -44,8 +43,7 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> ncols: C, rstride: RStride, cstride: CStride, - ) -> Self - { + ) -> Self { // NOTE: The assertion implements the following formula, but without subtractions to avoid // underflow panics: // len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1 @@ -76,8 +74,7 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> ncols: C, rstride: RStride, cstride: CStride, - ) -> Self - { + ) -> Self { let data = SliceStorageMut::from_raw_parts( data.as_mut_ptr().offset(start as isize), (nrows, ncols), @@ -97,8 +94,7 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> ncols: C, rstride: RStride, cstride: CStride, - ) -> Self - { + ) -> Self { // NOTE: The assertion implements the following formula, but without subtractions to avoid // underflow panics: // len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1 @@ -108,24 +104,27 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> "Matrix slice: input data buffer to small." ); - assert!({ - let nrows = nrows.value(); - let ncols = ncols.value(); - let rstride = rstride.value(); - let cstride = cstride.value(); + assert!( + { + let nrows = nrows.value(); + let ncols = ncols.value(); + let rstride = rstride.value(); + let cstride = cstride.value(); - nrows * ncols <= 1 || - match (rstride, cstride) { - (0, 0) => false, // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)], - (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)], - (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)], - (_, _) => { // otherwise: matrix[(0, numer)] == index[(denom, 0)] - let ratio = Ratio::new(rstride, cstride); - nrows <= *ratio.denom() || ncols <= *ratio.numer() + nrows * ncols <= 1 + || match (rstride, cstride) { + (0, 0) => false, // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)], + (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)], + (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)], + (_, _) => { + // otherwise: matrix[(0, numer)] == index[(denom, 0)] + let ratio = Ratio::new(rstride, cstride); + nrows <= *ratio.denom() || ncols <= *ratio.numer() + } } - } }, - "Matrix slice: dimensions and strides result in aliased indices."); + "Matrix slice: dimensions and strides result in aliased indices." + ); unsafe { Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride) @@ -144,8 +143,7 @@ impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMN<'a, N, R, C> { start: usize, nrows: R, ncols: C, - ) -> Self - { + ) -> Self { Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows) } @@ -170,8 +168,7 @@ impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, N, R, C> { start: usize, nrows: R, ncols: C, - ) -> Self - { + ) -> Self { Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows) } diff --git a/src/base/conversion.rs b/src/base/conversion.rs index e52a0c5d..8a856325 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -1,6 +1,6 @@ -use alga::general::{SubsetOf, SupersetOf}; #[cfg(feature = "mint")] use mint; +use simba::scalar::{SubsetOf, SupersetOf}; use std::convert::{AsMut, AsRef, From, Into}; use std::mem; use std::ptr; @@ -9,19 +9,24 @@ use generic_array::ArrayLength; use std::ops::Mul; use typenum::Prod; +use simba::simd::{PrimitiveSimdValue, SimdValue}; + use crate::base::allocator::{Allocator, SameShapeAllocator}; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::dimension::Dynamic; use crate::base::dimension::{ Dim, DimName, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, }; -#[cfg(any(feature = "std", feature = "alloc"))] -use crate::base::dimension::Dynamic; use crate::base::iter::{MatrixIter, MatrixIterMut}; use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::VecStorage; +use crate::base::{ + ArrayStorage, DVectorSlice, DVectorSliceMut, DefaultAllocator, Matrix, MatrixMN, MatrixSlice, + MatrixSliceMut, Scalar, +}; use crate::base::{SliceStorage, SliceStorageMut}; -use crate::base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar, DVectorSlice, DVectorSliceMut}; use crate::constraint::DimEq; // FIXME: too bad this won't work allo slice conversions. @@ -46,7 +51,9 @@ where let mut res = unsafe { MatrixMN::::new_uninitialized_generic(nrows2, ncols2) }; for i in 0..nrows { for j in 0..ncols { - unsafe { *res.get_unchecked_mut((i, j)) = N2::from_subset(self.get_unchecked((i, j))) } + unsafe { + *res.get_unchecked_mut((i, j)) = N2::from_subset(self.get_unchecked((i, j))) + } } } @@ -59,15 +66,17 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &MatrixMN) -> Self { + fn from_superset_unchecked(m: &MatrixMN) -> Self { let (nrows2, ncols2) = m.shape(); let nrows = R1::from_usize(nrows2); let ncols = C1::from_usize(ncols2); - let mut res = Self::new_uninitialized_generic(nrows, ncols); + let mut res = unsafe { Self::new_uninitialized_generic(nrows, ncols) }; for i in 0..nrows2 { for j in 0..ncols2 { - *res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked() + unsafe { + *res.get_unchecked_mut((i, j)) = m.get_unchecked((i, j)).to_subset_unchecked() + } } } @@ -118,12 +127,11 @@ macro_rules! impl_from_into_asref_1D( S: ContiguousStorage { #[inline] fn into(self) -> [N; $SZ] { - unsafe { - let mut res: [N; $SZ] = mem::uninitialized(); - ptr::copy_nonoverlapping(self.data.ptr(), &mut res[0], $SZ); + let mut res = mem::MaybeUninit::<[N; $SZ]>::uninit(); - res - } + unsafe { ptr::copy_nonoverlapping(self.data.ptr(), res.as_mut_ptr() as *mut N, $SZ) }; + + unsafe { res.assume_init() } } } @@ -185,12 +193,11 @@ macro_rules! impl_from_into_asref_2D( where S: ContiguousStorage { #[inline] fn into(self) -> [[N; $SZRows]; $SZCols] { - unsafe { - let mut res: [[N; $SZRows]; $SZCols] = mem::uninitialized(); - ptr::copy_nonoverlapping(self.data.ptr(), &mut res[0][0], $SZRows * $SZCols); + let mut res = mem::MaybeUninit::<[[N; $SZRows]; $SZCols]>::uninit(); - res - } + unsafe { ptr::copy_nonoverlapping(self.data.ptr(), res.as_mut_ptr() as *mut N, $SZRows * $SZCols) }; + + unsafe { res.assume_init() } } } @@ -428,18 +435,20 @@ where } impl<'a, N, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a Matrix> -for MatrixSlice<'a, N, RSlice, CSlice, RStride, CStride> - where - N: Scalar, - R: Dim, - C: Dim, - RSlice: Dim, - CSlice: Dim, - RStride: Dim, - CStride: Dim, - S: Storage, - ShapeConstraint: DimEq + DimEq - + DimEq + DimEq + for MatrixSlice<'a, N, RSlice, CSlice, RStride, CStride> +where + N: Scalar, + R: Dim, + C: Dim, + RSlice: Dim, + CSlice: Dim, + RStride: Dim, + CStride: Dim, + S: Storage, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, { fn from(m: &'a Matrix) -> Self { let (row, col) = m.data.shape(); @@ -452,27 +461,31 @@ for MatrixSlice<'a, N, RSlice, CSlice, RStride, CStride> let cstride_slice = CStride::from_usize(cstride); unsafe { - let data = SliceStorage::from_raw_parts(m.data.ptr(), - (row_slice, col_slice), - (rstride_slice, cstride_slice)); + let data = SliceStorage::from_raw_parts( + m.data.ptr(), + (row_slice, col_slice), + (rstride_slice, cstride_slice), + ); Matrix::from_data_statically_unchecked(data) } } } impl<'a, N, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix> -for MatrixSlice<'a, N, RSlice, CSlice, RStride, CStride> - where - N: Scalar, - R: Dim, - C: Dim, - RSlice: Dim, - CSlice: Dim, - RStride: Dim, - CStride: Dim, - S: Storage, - ShapeConstraint: DimEq + DimEq - + DimEq + DimEq + for MatrixSlice<'a, N, RSlice, CSlice, RStride, CStride> +where + N: Scalar, + R: Dim, + C: Dim, + RSlice: Dim, + CSlice: Dim, + RStride: Dim, + CStride: Dim, + S: Storage, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, { fn from(m: &'a mut Matrix) -> Self { let (row, col) = m.data.shape(); @@ -485,27 +498,31 @@ for MatrixSlice<'a, N, RSlice, CSlice, RStride, CStride> let cstride_slice = CStride::from_usize(cstride); unsafe { - let data = SliceStorage::from_raw_parts(m.data.ptr(), - (row_slice, col_slice), - (rstride_slice, cstride_slice)); + let data = SliceStorage::from_raw_parts( + m.data.ptr(), + (row_slice, col_slice), + (rstride_slice, cstride_slice), + ); Matrix::from_data_statically_unchecked(data) } } } impl<'a, N, R, C, RSlice, CSlice, RStride, CStride, S> From<&'a mut Matrix> -for MatrixSliceMut<'a, N, RSlice, CSlice, RStride, CStride> - where - N: Scalar, - R: Dim, - C: Dim, - RSlice: Dim, - CSlice: Dim, - RStride: Dim, - CStride: Dim, - S: StorageMut, - ShapeConstraint: DimEq + DimEq - + DimEq + DimEq + for MatrixSliceMut<'a, N, RSlice, CSlice, RStride, CStride> +where + N: Scalar, + R: Dim, + C: Dim, + RSlice: Dim, + CSlice: Dim, + RStride: Dim, + CStride: Dim, + S: StorageMut, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, { fn from(m: &'a mut Matrix) -> Self { let (row, col) = m.data.shape(); @@ -518,29 +535,34 @@ for MatrixSliceMut<'a, N, RSlice, CSlice, RStride, CStride> let cstride_slice = CStride::from_usize(cstride); unsafe { - let data = SliceStorageMut::from_raw_parts(m.data.ptr_mut(), - (row_slice, col_slice), - (rstride_slice, cstride_slice)); + let data = SliceStorageMut::from_raw_parts( + m.data.ptr_mut(), + (row_slice, col_slice), + (rstride_slice, cstride_slice), + ); Matrix::from_data_statically_unchecked(data) } } } -impl<'a, N: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorage> Into<&'a [N]> for &'a Matrix { +impl<'a, N: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorage> Into<&'a [N]> + for &'a Matrix +{ #[inline] fn into(self) -> &'a [N] { self.as_slice() } } -impl<'a, N: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorageMut> Into<&'a mut [N]> for &'a mut Matrix { +impl<'a, N: Scalar + Copy, R: Dim, C: Dim, S: ContiguousStorageMut> Into<&'a mut [N]> + for &'a mut Matrix +{ #[inline] fn into(self) -> &'a mut [N] { self.as_mut_slice() } } - impl<'a, N: Scalar + Copy> From<&'a [N]> for DVectorSlice<'a, N> { #[inline] fn from(slice: &'a [N]) -> Self { @@ -553,4 +575,109 @@ impl<'a, N: Scalar + Copy> From<&'a mut [N]> for DVectorSliceMut<'a, N> { fn from(slice: &'a mut [N]) -> Self { Self::from_slice(slice, slice.len()) } -} \ No newline at end of file +} + +impl From<[MatrixMN; 2]> + for MatrixMN +where + N: From<[::Element; 2]>, + N::Element: Scalar + SimdValue, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [MatrixMN; 2]) -> Self { + let (nrows, ncols) = arr[0].data.shape(); + + Self::from_fn_generic(nrows, ncols, |i, j| { + [ + arr[0][(i, j)].inlined_clone(), + arr[1][(i, j)].inlined_clone(), + ] + .into() + }) + } +} + +impl From<[MatrixMN; 4]> + for MatrixMN +where + N: From<[::Element; 4]>, + N::Element: Scalar + SimdValue, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [MatrixMN; 4]) -> Self { + let (nrows, ncols) = arr[0].data.shape(); + + 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(), + ] + .into() + }) + } +} + +impl From<[MatrixMN; 8]> + for MatrixMN +where + N: From<[::Element; 8]>, + N::Element: Scalar + SimdValue, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [MatrixMN; 8]) -> Self { + let (nrows, ncols) = arr[0].data.shape(); + + 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(), + ] + .into() + }) + } +} + +impl From<[MatrixMN; 16]> + for MatrixMN +where + N: From<[::Element; 16]>, + N::Element: Scalar + SimdValue, + DefaultAllocator: Allocator + Allocator, +{ + fn from(arr: [MatrixMN; 16]) -> Self { + let (nrows, ncols) = arr[0].data.shape(); + + 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(), + ] + .into() + }) + } +} diff --git a/src/base/default_allocator.rs b/src/base/default_allocator.rs index c07c8708..bedca471 100644 --- a/src/base/default_allocator.rs +++ b/src/base/default_allocator.rs @@ -15,13 +15,13 @@ use generic_array::ArrayLength; use typenum::Prod; use crate::base::allocator::{Allocator, Reallocator}; +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::array_storage::ArrayStorage; +use crate::base::storage::{Storage, StorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::vec_storage::VecStorage; -use crate::base::storage::{Storage, StorageMut}; use crate::base::Scalar; /* @@ -46,7 +46,8 @@ where #[inline] unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer { - mem::uninitialized() + // TODO: Undefined behavior, see #556 + mem::MaybeUninit::::uninit().assume_init() } #[inline] @@ -54,8 +55,7 @@ where nrows: R, ncols: C, iter: I, - ) -> Self::Buffer - { + ) -> Self::Buffer { let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols) }; let mut count = 0; @@ -94,8 +94,7 @@ impl Allocator for DefaultAllocator { nrows: Dynamic, ncols: C, iter: I, - ) -> Self::Buffer - { + ) -> Self::Buffer { let it = iter.into_iter(); let res: Vec = it.collect(); assert!(res.len() == nrows.value() * ncols.value(), @@ -125,8 +124,7 @@ impl Allocator for DefaultAllocator { nrows: R, ncols: Dynamic, iter: I, - ) -> Self::Buffer - { + ) -> Self::Buffer { let it = iter.into_iter(); let res: Vec = it.collect(); assert!(res.len() == nrows.value() * ncols.value(), @@ -157,8 +155,7 @@ where rto: RTo, cto: CTo, buf: >::Buffer, - ) -> ArrayStorage - { + ) -> ArrayStorage { let mut res = >::allocate_uninitialized(rto, cto); let (rfrom, cfrom) = buf.shape(); @@ -186,8 +183,7 @@ where rto: Dynamic, cto: CTo, buf: ArrayStorage, - ) -> VecStorage - { + ) -> VecStorage { let mut res = >::allocate_uninitialized(rto, cto); let (rfrom, cfrom) = buf.shape(); @@ -215,8 +211,7 @@ where rto: RTo, cto: Dynamic, buf: ArrayStorage, - ) -> VecStorage - { + ) -> VecStorage { let mut res = >::allocate_uninitialized(rto, cto); let (rfrom, cfrom) = buf.shape(); @@ -239,8 +234,7 @@ impl Reallocator, - ) -> VecStorage - { + ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } @@ -255,8 +249,7 @@ impl Reallocator, - ) -> VecStorage - { + ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } @@ -271,8 +264,7 @@ impl Reallocator, - ) -> VecStorage - { + ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } @@ -287,8 +279,7 @@ impl Reallocator, - ) -> VecStorage - { + ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 112996d3..c171ff23 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -30,7 +30,9 @@ impl Dynamic { #[cfg(feature = "serde-serialize")] impl Serialize for Dynamic { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.value.serialize(serializer) } } @@ -38,7 +40,9 @@ impl Serialize for Dynamic { #[cfg(feature = "serde-serialize")] impl<'de> Deserialize<'de> for Dynamic { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { + where + D: Deserializer<'de>, + { usize::deserialize(deserializer).map(|x| Dynamic { value: x }) } } @@ -190,7 +194,6 @@ pub trait DimName: Dim { type Value: NamedDim; /// The name of this dimension, i.e., the singleton `Self`. - #[inline] fn name() -> Self; // FIXME: this is not a very idiomatic name. diff --git a/src/base/edition.rs b/src/base/edition.rs index b84a6110..b3133648 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -22,7 +22,9 @@ impl> Matrix { /// Extracts the upper triangular part of this matrix (including the diagonal). #[inline] pub fn upper_triangle(&self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let mut res = self.clone_owned(); res.fill_lower_triangle(N::zero(), 1); @@ -32,7 +34,9 @@ impl> Matrix { /// Extracts the lower triangular part of this matrix (including the diagonal). #[inline] pub fn lower_triangle(&self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let mut res = self.clone_owned(); res.fill_upper_triangle(N::zero(), 1); @@ -64,7 +68,10 @@ impl> Matrix { let src = self.column(j); for (destination, source) in irows.clone().enumerate() { - unsafe { *res.vget_unchecked_mut(destination) = src.vget_unchecked(*source).inlined_clone() } + unsafe { + *res.vget_unchecked_mut(destination) = + src.vget_unchecked(*source).inlined_clone() + } } } @@ -104,7 +111,9 @@ impl> Matrix { /// Fills `self` with the identity matrix. #[inline] pub fn fill_with_identity(&mut self) - where N: Zero + One { + where + N: Zero + One, + { self.fill(N::zero()); self.fill_diagonal(N::one()); } @@ -350,7 +359,7 @@ impl> Matrix { where R: DimSub, DefaultAllocator: Reallocator, - { + { let mut m = self.into_owned(); let (nrows, ncols) = m.data.shape(); let mut offset: usize = 0; @@ -371,7 +380,7 @@ impl> Matrix { unsafe { Matrix::from_data(DefaultAllocator::reallocate_copy( - nrows.sub(Dynamic::from_usize(offset / ncols.value ())), + nrows.sub(Dynamic::from_usize(offset / ncols.value())), ncols, m.data, )) @@ -693,7 +702,9 @@ impl> Matrix { /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize(self, new_nrows: usize, new_ncols: usize, val: N) -> DMatrix - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) } @@ -703,7 +714,9 @@ impl> Matrix { /// rows than `self`, then the extra rows are filled with `val`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_vertically(self, new_nrows: usize, val: N) -> MatrixMN - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { let ncols = self.data.shape().1; self.resize_generic(Dynamic::new(new_nrows), ncols, val) } @@ -714,7 +727,9 @@ impl> Matrix { /// columns than `self`, then the extra columns are filled with `val`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_horizontally(self, new_ncols: usize, val: N) -> MatrixMN - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { let nrows = self.data.shape().0; self.resize_generic(nrows, Dynamic::new(new_ncols), val) } @@ -724,7 +739,9 @@ impl> Matrix { /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. pub fn fixed_resize(self, val: N) -> MatrixMN - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { self.resize_generic(R2::name(), C2::name(), val) } @@ -805,7 +822,9 @@ impl DMatrix { /// /// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`. pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: N) - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { let placeholder = unsafe { Self::new_uninitialized(0, 0) }; let old = mem::replace(self, placeholder); let new = old.resize(new_nrows, new_ncols, val); @@ -815,7 +834,8 @@ impl DMatrix { #[cfg(any(feature = "std", feature = "alloc"))] impl MatrixMN -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Changes the number of rows of this matrix in-place. /// @@ -825,7 +845,9 @@ where DefaultAllocator: Allocator /// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`). #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: N) - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { let placeholder = unsafe { Self::new_uninitialized_generic(Dynamic::new(0), self.data.shape().1) }; let old = mem::replace(self, placeholder); @@ -836,7 +858,8 @@ where DefaultAllocator: Allocator #[cfg(any(feature = "std", feature = "alloc"))] impl MatrixMN -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Changes the number of column of this matrix in-place. /// @@ -846,7 +869,9 @@ where DefaultAllocator: Allocator /// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`). #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: N) - where DefaultAllocator: Reallocator { + where + DefaultAllocator: Reallocator, + { let placeholder = unsafe { Self::new_uninitialized_generic(self.data.shape().0, Dynamic::new(0)) }; let old = mem::replace(self, placeholder); @@ -861,8 +886,7 @@ unsafe fn compress_rows( ncols: usize, i: usize, nremove: usize, -) -{ +) { let new_nrows = nrows - nremove; if new_nrows == 0 || ncols == 0 { @@ -901,8 +925,7 @@ unsafe fn extend_rows( ncols: usize, i: usize, ninsert: usize, -) -{ +) { let new_nrows = nrows + ninsert; if new_nrows == 0 || ncols == 0 { diff --git a/src/base/helper.rs b/src/base/helper.rs index ef85a477..de601fb6 100644 --- a/src/base/helper.rs +++ b/src/base/helper.rs @@ -18,7 +18,9 @@ pub fn reject bool, T: Arbitrary>(g: &mut G, f: F) -> T #[doc(hidden)] #[inline] pub fn reject_rand bool, T>(g: &mut G, f: F) -> T -where Standard: Distribution { +where + Standard: Distribution, +{ use std::iter; iter::repeat(()).map(|_| g.gen()).find(f).unwrap() } diff --git a/src/base/indexing.rs b/src/base/indexing.rs index ca786530..65ba5d79 100644 --- a/src/base/indexing.rs +++ b/src/base/indexing.rs @@ -1,13 +1,14 @@ //! Indexing -use crate::base::{Dim, DimName, DimDiff, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1}; use crate::base::storage::{Storage, StorageMut}; +use crate::base::{ + Dim, DimDiff, DimName, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1, +}; use std::ops; // N.B.: Not a public trait! -trait DimRange -{ +trait DimRange { /// The number of elements indexed by this range. type Length: Dim; @@ -68,15 +69,27 @@ impl DimRange for ops::Range { #[test] fn dimrange_range_usize() { - use std::usize::MAX; use crate::base::dimension::U0; + use std::usize::MAX; assert_eq!(DimRange::contained_by(&(0..0), U0), false); assert_eq!(DimRange::contained_by(&(0..1), U0), false); assert_eq!(DimRange::contained_by(&(0..1), U1), true); - assert_eq!(DimRange::contained_by(&((MAX - 1)..MAX), Dynamic::new(MAX)), true); - assert_eq!(DimRange::length(&((MAX - 1)..MAX), Dynamic::new(MAX)), Dynamic::new(1)); - assert_eq!(DimRange::length(&(MAX..(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(0)); - assert_eq!(DimRange::length(&(MAX..MAX), Dynamic::new(MAX)), Dynamic::new(0)); + assert_eq!( + DimRange::contained_by(&((MAX - 1)..MAX), Dynamic::new(MAX)), + true + ); + assert_eq!( + DimRange::length(&((MAX - 1)..MAX), Dynamic::new(MAX)), + Dynamic::new(1) + ); + assert_eq!( + DimRange::length(&(MAX..(MAX - 1)), Dynamic::new(MAX)), + Dynamic::new(0) + ); + assert_eq!( + DimRange::length(&(MAX..MAX), Dynamic::new(MAX)), + Dynamic::new(0) + ); } impl DimRange for ops::RangeFrom { @@ -100,18 +113,28 @@ impl DimRange for ops::RangeFrom { #[test] fn dimrange_rangefrom_usize() { - use std::usize::MAX; use crate::base::dimension::U0; + use std::usize::MAX; assert_eq!(DimRange::contained_by(&(0..), U0), false); assert_eq!(DimRange::contained_by(&(0..), U0), false); assert_eq!(DimRange::contained_by(&(0..), U1), true); - assert_eq!(DimRange::contained_by(&((MAX - 1)..), Dynamic::new(MAX)), true); - assert_eq!(DimRange::length(&((MAX - 1)..), Dynamic::new(MAX)), Dynamic::new(1)); - assert_eq!(DimRange::length(&(MAX..), Dynamic::new(MAX)), Dynamic::new(0)); + assert_eq!( + DimRange::contained_by(&((MAX - 1)..), Dynamic::new(MAX)), + true + ); + assert_eq!( + DimRange::length(&((MAX - 1)..), Dynamic::new(MAX)), + Dynamic::new(1) + ); + assert_eq!( + DimRange::length(&(MAX..), Dynamic::new(MAX)), + Dynamic::new(0) + ); } impl DimRange for ops::RangeFrom -where D: DimSub +where + D: DimSub, { type Length = DimDiff; @@ -133,7 +156,7 @@ where D: DimSub #[test] fn dimrange_rangefrom_dimname() { - use crate::base::dimension::{U5, U4}; + use crate::base::dimension::{U4, U5}; assert_eq!(DimRange::length(&(U1..), U5), U4); } @@ -173,12 +196,11 @@ impl DimRange for ops::RangeInclusive { #[inline(always)] fn length(&self, _: D) -> Self::Length { - Dynamic::new( - if self.end() < self.start() { - 0 - } else { - self.end().wrapping_sub(self.start().wrapping_sub(1)) - }) + Dynamic::new(if self.end() < self.start() { + 0 + } else { + self.end().wrapping_sub(self.start().wrapping_sub(1)) + }) } #[inline(always)] @@ -189,21 +211,38 @@ impl DimRange for ops::RangeInclusive { #[test] fn dimrange_rangeinclusive_usize() { - use std::usize::MAX; use crate::base::dimension::U0; + use std::usize::MAX; assert_eq!(DimRange::contained_by(&(0..=0), U0), false); assert_eq!(DimRange::contained_by(&(0..=0), U1), true); - assert_eq!(DimRange::contained_by(&(MAX..=MAX), Dynamic::new(MAX)), false); - assert_eq!(DimRange::contained_by(&((MAX-1)..=MAX), Dynamic::new(MAX)), false); - assert_eq!(DimRange::contained_by(&((MAX-1)..=(MAX-1)), Dynamic::new(MAX)), true); + assert_eq!( + DimRange::contained_by(&(MAX..=MAX), Dynamic::new(MAX)), + false + ); + assert_eq!( + DimRange::contained_by(&((MAX - 1)..=MAX), Dynamic::new(MAX)), + false + ); + assert_eq!( + DimRange::contained_by(&((MAX - 1)..=(MAX - 1)), Dynamic::new(MAX)), + true + ); assert_eq!(DimRange::length(&(0..=0), U1), Dynamic::new(1)); - assert_eq!(DimRange::length(&((MAX - 1)..=MAX), Dynamic::new(MAX)), Dynamic::new(2)); - assert_eq!(DimRange::length(&(MAX..=(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(0)); - assert_eq!(DimRange::length(&(MAX..=MAX), Dynamic::new(MAX)), Dynamic::new(1)); + assert_eq!( + DimRange::length(&((MAX - 1)..=MAX), Dynamic::new(MAX)), + Dynamic::new(2) + ); + assert_eq!( + DimRange::length(&(MAX..=(MAX - 1)), Dynamic::new(MAX)), + Dynamic::new(0) + ); + assert_eq!( + DimRange::length(&(MAX..=MAX), Dynamic::new(MAX)), + Dynamic::new(1) + ); } -impl DimRange for ops::RangeTo -{ +impl DimRange for ops::RangeTo { type Length = Dynamic; #[inline(always)] @@ -224,18 +263,26 @@ impl DimRange for ops::RangeTo #[test] fn dimrange_rangeto_usize() { - use std::usize::MAX; use crate::base::dimension::U0; + use std::usize::MAX; assert_eq!(DimRange::contained_by(&(..0), U0), true); assert_eq!(DimRange::contained_by(&(..1), U0), false); assert_eq!(DimRange::contained_by(&(..0), U1), true); - assert_eq!(DimRange::contained_by(&(..(MAX - 1)), Dynamic::new(MAX)), true); - assert_eq!(DimRange::length(&(..(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(MAX - 1)); - assert_eq!(DimRange::length(&(..MAX), Dynamic::new(MAX)), Dynamic::new(MAX)); + assert_eq!( + DimRange::contained_by(&(..(MAX - 1)), Dynamic::new(MAX)), + true + ); + assert_eq!( + DimRange::length(&(..(MAX - 1)), Dynamic::new(MAX)), + Dynamic::new(MAX - 1) + ); + assert_eq!( + DimRange::length(&(..MAX), Dynamic::new(MAX)), + Dynamic::new(MAX) + ); } -impl DimRange for ops::RangeToInclusive -{ +impl DimRange for ops::RangeToInclusive { type Length = Dynamic; #[inline(always)] @@ -256,21 +303,29 @@ impl DimRange for ops::RangeToInclusive #[test] fn dimrange_rangetoinclusive_usize() { - use std::usize::MAX; use crate::base::dimension::U0; + use std::usize::MAX; assert_eq!(DimRange::contained_by(&(..=0), U0), false); assert_eq!(DimRange::contained_by(&(..=1), U0), false); assert_eq!(DimRange::contained_by(&(..=0), U1), true); - assert_eq!(DimRange::contained_by(&(..=(MAX)), Dynamic::new(MAX)), false); - assert_eq!(DimRange::contained_by(&(..=(MAX - 1)), Dynamic::new(MAX)), true); - assert_eq!(DimRange::length(&(..=(MAX - 1)), Dynamic::new(MAX)), Dynamic::new(MAX)); + assert_eq!( + DimRange::contained_by(&(..=(MAX)), Dynamic::new(MAX)), + false + ); + assert_eq!( + DimRange::contained_by(&(..=(MAX - 1)), Dynamic::new(MAX)), + true + ); + assert_eq!( + DimRange::length(&(..=(MAX - 1)), Dynamic::new(MAX)), + Dynamic::new(MAX) + ); } /// A helper trait used for indexing operations. pub trait MatrixIndex<'a, N: Scalar, R: Dim, C: Dim, S: Storage>: Sized { - /// The output type returned by methods. - type Output : 'a; + type Output: 'a; /// Produces true if the given matrix is contained by this index. #[doc(hidden)] @@ -282,7 +337,7 @@ pub trait MatrixIndex<'a, N: Scalar, R: Dim, C: Dim, S: Storage>: Sized #[inline(always)] fn get(self, matrix: &'a Matrix) -> Option { if self.contained_by(matrix) { - Some(unsafe{self.get_unchecked(matrix)}) + Some(unsafe { self.get_unchecked(matrix) }) } else { None } @@ -303,9 +358,11 @@ pub trait MatrixIndex<'a, N: Scalar, R: Dim, C: Dim, S: Storage>: Sized } /// A helper trait used for indexing operations. -pub trait MatrixIndexMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut>: MatrixIndex<'a, N, R, C, S> { +pub trait MatrixIndexMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut>: + MatrixIndex<'a, N, R, C, S> +{ /// The output type returned by methods. - type OutputMut : 'a; + type OutputMut: 'a; /// Produces a mutable view of the data at this location, without /// performing any bounds checking. @@ -318,7 +375,7 @@ pub trait MatrixIndexMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut>: #[inline(always)] fn get_mut(self, matrix: &'a mut Matrix) -> Option { if self.contained_by(matrix) { - Some(unsafe{self.get_unchecked_mut(matrix)}) + Some(unsafe { self.get_unchecked_mut(matrix) }) } else { None } @@ -432,14 +489,13 @@ pub trait MatrixIndexMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut>: /// 4, 7, /// 5, 8))); /// ``` -impl> Matrix -{ +impl> Matrix { /// Produces a view of the data at the given index, or /// `None` if the index is out of bounds. #[inline] pub fn get<'a, I>(&'a self, index: I) -> Option where - I: MatrixIndex<'a, N, R, C, S> + I: MatrixIndex<'a, N, R, C, S>, { index.get(self) } @@ -450,7 +506,7 @@ impl> Matrix pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option where S: StorageMut, - I: MatrixIndexMut<'a, N, R, C, S> + I: MatrixIndexMut<'a, N, R, C, S>, { index.get_mut(self) } @@ -460,7 +516,7 @@ impl> Matrix #[inline] pub fn index<'a, I>(&'a self, index: I) -> I::Output where - I: MatrixIndex<'a, N, R, C, S> + I: MatrixIndex<'a, N, R, C, S>, { index.index(self) } @@ -471,7 +527,7 @@ impl> Matrix pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut where S: StorageMut, - I: MatrixIndexMut<'a, N, R, C, S> + I: MatrixIndexMut<'a, N, R, C, S>, { index.index_mut(self) } @@ -481,7 +537,7 @@ impl> Matrix #[inline] pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::Output where - I: MatrixIndex<'a, N, R, C, S> + I: MatrixIndex<'a, N, R, C, S>, { index.get_unchecked(self) } @@ -492,7 +548,7 @@ impl> Matrix pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut where S: StorageMut, - I: MatrixIndexMut<'a, N, R, C, S> + I: MatrixIndexMut<'a, N, R, C, S>, { index.get_unchecked_mut(self) } @@ -505,7 +561,7 @@ where N: Scalar, R: Dim, C: Dim, - S: Storage + S: Storage, { type Output = &'a N; @@ -527,14 +583,15 @@ where N: Scalar, R: Dim, C: Dim, - S: StorageMut + S: StorageMut, { type OutputMut = &'a mut N; #[doc(hidden)] #[inline(always)] unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut - where S: StorageMut, + where + S: StorageMut, { matrix.data.get_unchecked_linear_mut(self) } @@ -547,7 +604,7 @@ where N: Scalar, R: Dim, C: Dim, - S: Storage + S: Storage, { type Output = &'a N; @@ -572,14 +629,15 @@ where N: Scalar, R: Dim, C: Dim, - S: StorageMut + S: StorageMut, { type OutputMut = &'a mut N; #[doc(hidden)] #[inline(always)] unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut - where S: StorageMut, + where + S: StorageMut, { let (row, col) = self; matrix.data.get_unchecked_mut(row, col) @@ -684,7 +742,7 @@ macro_rules! impl_index_pairs { } } -impl_index_pairs!{ +impl_index_pairs! { index R with { [<> usize => U1], [<> ops::Range => Dynamic], diff --git a/src/base/iter.rs b/src/base/iter.rs index 65cdb20a..ab040b08 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -5,7 +5,7 @@ use std::mem; use crate::base::dimension::{Dim, U1}; use crate::base::storage::{Storage, StorageMut}; -use crate::base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut}; +use crate::base::{Matrix, MatrixSlice, MatrixSliceMut, Scalar}; macro_rules! iterator { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { @@ -125,7 +125,6 @@ macro_rules! iterator { iterator!(struct MatrixIter for Storage.ptr -> *const N, &'a N, &'a S); iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a mut S); - /* * * Row iterators. @@ -135,18 +134,15 @@ iterator!(struct MatrixIterMut for StorageMut.ptr_mut -> *mut N, &'a mut N, &'a /// An iterator through the rows of a matrix. pub struct RowIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage> { mat: &'a Matrix, - curr: usize + curr: usize, } impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> RowIter<'a, N, R, C, S> { pub(crate) fn new(mat: &'a Matrix) -> Self { - RowIter { - mat, curr: 0 - } + RowIter { mat, curr: 0 } } } - impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator for RowIter<'a, N, R, C, S> { type Item = MatrixSlice<'a, N, U1, C, S::RStride, S::CStride>; @@ -163,7 +159,10 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator for RowIt #[inline] fn size_hint(&self) -> (usize, Option) { - (self.mat.nrows() - self.curr, Some(self.mat.nrows() - self.curr)) + ( + self.mat.nrows() - self.curr, + Some(self.mat.nrows() - self.curr), + ) } #[inline] @@ -172,19 +171,20 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator for RowIt } } -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> ExactSizeIterator for RowIter<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> ExactSizeIterator + for RowIter<'a, N, R, C, S> +{ #[inline] fn len(&self) -> usize { self.mat.nrows() - self.curr } } - /// An iterator through the mutable rows of a matrix. pub struct RowIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut> { mat: *mut Matrix, curr: usize, - phantom: PhantomData<&'a mut Matrix> + phantom: PhantomData<&'a mut Matrix>, } impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> RowIterMut<'a, N, R, C, S> { @@ -192,19 +192,18 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> RowIterMut<'a, RowIterMut { mat, curr: 0, - phantom: PhantomData + phantom: PhantomData, } } fn nrows(&self) -> usize { - unsafe { - (*self.mat).nrows() - } + unsafe { (*self.mat).nrows() } } } - -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> Iterator for RowIterMut<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> Iterator + for RowIterMut<'a, N, R, C, S> +{ type Item = MatrixSliceMut<'a, N, U1, C, S::RStride, S::CStride>; #[inline] @@ -229,14 +228,15 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> Iterator for Ro } } -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ExactSizeIterator for RowIterMut<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ExactSizeIterator + for RowIterMut<'a, N, R, C, S> +{ #[inline] fn len(&self) -> usize { self.nrows() - self.curr } } - /* * * Column iterators. @@ -246,19 +246,18 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ExactSizeIterat /// An iterator through the columns of a matrix. pub struct ColumnIter<'a, N: Scalar, R: Dim, C: Dim, S: Storage> { mat: &'a Matrix, - curr: usize + curr: usize, } impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> ColumnIter<'a, N, R, C, S> { pub(crate) fn new(mat: &'a Matrix) -> Self { - ColumnIter { - mat, curr: 0 - } + ColumnIter { mat, curr: 0 } } } - -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator for ColumnIter<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator + for ColumnIter<'a, N, R, C, S> +{ type Item = MatrixSlice<'a, N, R, U1, S::RStride, S::CStride>; #[inline] @@ -274,7 +273,10 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator for Colum #[inline] fn size_hint(&self) -> (usize, Option) { - (self.mat.ncols() - self.curr, Some(self.mat.ncols() - self.curr)) + ( + self.mat.ncols() - self.curr, + Some(self.mat.ncols() - self.curr), + ) } #[inline] @@ -283,19 +285,20 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> Iterator for Colum } } -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> ExactSizeIterator for ColumnIter<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + Storage> ExactSizeIterator + for ColumnIter<'a, N, R, C, S> +{ #[inline] fn len(&self) -> usize { self.mat.ncols() - self.curr } } - /// An iterator through the mutable columns of a matrix. pub struct ColumnIterMut<'a, N: Scalar, R: Dim, C: Dim, S: StorageMut> { mat: *mut Matrix, curr: usize, - phantom: PhantomData<&'a mut Matrix> + phantom: PhantomData<&'a mut Matrix>, } impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ColumnIterMut<'a, N, R, C, S> { @@ -303,19 +306,18 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ColumnIterMut<' ColumnIterMut { mat, curr: 0, - phantom: PhantomData + phantom: PhantomData, } } fn ncols(&self) -> usize { - unsafe { - (*self.mat).ncols() - } + unsafe { (*self.mat).ncols() } } } - -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> Iterator for ColumnIterMut<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> Iterator + for ColumnIterMut<'a, N, R, C, S> +{ type Item = MatrixSliceMut<'a, N, R, U1, S::RStride, S::CStride>; #[inline] @@ -340,10 +342,11 @@ impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> Iterator for Co } } -impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ExactSizeIterator for ColumnIterMut<'a, N, R, C, S> { +impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + StorageMut> ExactSizeIterator + for ColumnIterMut<'a, N, R, C, S> +{ #[inline] fn len(&self) -> usize { self.ncols() - self.curr } } - diff --git a/src/base/matrix.rs b/src/base/matrix.rs index b1e0653c..783f8c19 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -16,16 +16,20 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{ClosedAdd, ClosedMul, ClosedSub, RealField, Ring, ComplexField, Field}; +use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, RealField}; +use simba::simd::SimdPartialOrd; use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use crate::base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3}; -use crate::base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut}; +use crate::base::iter::{ + ColumnIter, ColumnIterMut, MatrixIter, MatrixIterMut, RowIter, RowIterMut, +}; use crate::base::storage::{ ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut, }; use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Scalar, Unit, VectorN}; +use crate::SimdComplexField; /// A square matrix. pub type SquareMatrix = Matrix; @@ -99,7 +103,9 @@ where S: Serialize, { fn serialize(&self, serializer: T) -> Result - where T: Serializer { + where + T: Serializer, + { self.data.serialize(serializer) } } @@ -113,7 +119,9 @@ where S: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { + where + D: Deserializer<'de>, + { S::deserialize(deserializer).map(|x| Matrix { data: x, _phantoms: PhantomData, @@ -279,6 +287,16 @@ impl> Matrix { /// Computes the row and column coordinates of the i-th element of this matrix seen as a /// vector. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2; + /// let m = Matrix2::new(1, 2, + /// 3, 4); + /// let i = m.vector_to_matrix_index(3); + /// assert_eq!(i, (1, 1)); + /// assert_eq!(m[i], m[3]); + /// ``` #[inline] pub fn vector_to_matrix_index(&self, i: usize) -> (usize, usize) { let (nrows, ncols) = self.shape(); @@ -298,6 +316,15 @@ impl> Matrix { /// /// If the matrix is not empty, this pointer is guaranteed to be aligned /// and non-null. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2; + /// let m = Matrix2::new(1, 2, + /// 3, 4); + /// let ptr = m.as_ptr(); + /// assert_eq!(unsafe { *ptr }, m[0]); + /// ``` #[inline] pub fn as_ptr(&self) -> *const N { self.data.ptr() @@ -344,7 +371,9 @@ impl> Matrix { /// Moves this matrix into one that owns its data. #[inline] pub fn into_owned(self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { Matrix::from_data(self.data.into_owned()) } @@ -378,7 +407,9 @@ impl> Matrix { /// Clones this matrix to one that owns its data. #[inline] pub fn clone_owned(&self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { Matrix::from_data(self.data.clone_owned()) } @@ -414,7 +445,9 @@ impl> Matrix { /// Returns a matrix containing the result of `f` applied to each of its entries. #[inline] pub fn map N2>(&self, mut f: F) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = self.data.shape(); let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, ncols) }; @@ -431,6 +464,24 @@ impl> Matrix { res } + /// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure. + /// + /// The initialization closure is given the first component of this matrix: + /// - If the matrix has no component (0 rows or 0 columns) then `init_f` is called with `None` + /// and its return value is the value returned by this method. + /// - If the matrix has has least one component, then `init_f` is called with the first component + /// to compute the initial value. Folding then continues on all the remaining components of the matrix. + #[inline] + pub fn fold_with( + &self, + init_f: impl FnOnce(Option<&N>) -> N2, + f: impl FnMut(N2, &N) -> N2, + ) -> N2 { + let mut it = self.iter(); + let init = init_f(it.next()); + it.fold(init, f) + } + /// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`, /// `f` also gets passed the row and column index, i.e. `f(row, col, value)`. #[inline] @@ -553,13 +604,18 @@ impl> Matrix { /// Folds a function `f` on each pairs of entries from `self` and `rhs`. #[inline] - pub fn zip_fold(&self, rhs: &Matrix, init: Acc, mut f: impl FnMut(Acc, N, N2) -> Acc) -> Acc - where - N2: Scalar, - R2: Dim, - C2: Dim, - S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + pub fn zip_fold( + &self, + rhs: &Matrix, + init: Acc, + mut f: impl FnMut(Acc, N, N2) -> Acc, + ) -> Acc + where + N2: Scalar, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, { let (nrows, ncols) = self.data.shape(); @@ -612,7 +668,9 @@ impl> Matrix { #[inline] #[must_use = "Did you mean to use transpose_mut()?"] pub fn transpose(&self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = self.data.shape(); unsafe { @@ -718,7 +776,8 @@ impl> Matrix { for j in 0..ncols { for i in 0..nrows { unsafe { - *self.get_unchecked_mut((i, j)) = slice.get_unchecked(i + j * nrows).inlined_clone(); + *self.get_unchecked_mut((i, j)) = + slice.get_unchecked(i + j * nrows).inlined_clone(); } } } @@ -774,7 +833,7 @@ impl> Matrix { // FIXME: rename `apply` to `apply_mut` and `apply_into` to `apply`? /// Returns `self` with each of its components replaced by the result of a closure `f` applied on it. #[inline] - pub fn apply_into N>(mut self, f: F) -> Self{ + pub fn apply_into N>(mut self, f: F) -> Self { self.apply(f); self } @@ -797,12 +856,17 @@ impl> Matrix { /// Replaces each component of `self` by the result of a closure `f` applied on its components /// joined with the components from `rhs`. #[inline] - pub fn zip_apply(&mut self, rhs: &Matrix, mut f: impl FnMut(N, N2) -> N) - where N2: Scalar, - R2: Dim, - C2: Dim, - S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + pub fn zip_apply( + &mut self, + rhs: &Matrix, + mut f: impl FnMut(N, N2) -> N, + ) where + N2: Scalar, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { let (nrows, ncols) = self.shape(); assert!( @@ -821,21 +885,26 @@ impl> Matrix { } } - /// Replaces each component of `self` by the result of a closure `f` applied on its components /// joined with the components from `b` and `c`. #[inline] - pub fn zip_zip_apply(&mut self, b: &Matrix, c: &Matrix, mut f: impl FnMut(N, N2, N3) -> N) - where N2: Scalar, - R2: Dim, - C2: Dim, - S2: Storage, - N3: Scalar, - R3: Dim, - C3: Dim, - S3: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + pub fn zip_zip_apply( + &mut self, + b: &Matrix, + c: &Matrix, + mut f: impl FnMut(N, N2, N3) -> N, + ) where + N2: Scalar, + R2: Dim, + C2: Dim, + S2: Storage, + N3: Scalar, + R3: Dim, + C3: Dim, + S3: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { let (nrows, ncols) = self.shape(); assert!( @@ -914,7 +983,7 @@ impl> Matrix { } } -impl> Matrix { +impl> Matrix { /// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`. #[inline] pub fn adjoint_to(&self, out: &mut Matrix) @@ -934,7 +1003,7 @@ impl> Matrix { for i in 0..nrows { for j in 0..ncols { unsafe { - *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conjugate(); + *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).simd_conjugate(); } } } @@ -944,7 +1013,9 @@ impl> Matrix { #[inline] #[must_use = "Did you mean to use adjoint_mut()?"] pub fn adjoint(&self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = self.data.shape(); unsafe { @@ -959,11 +1030,11 @@ impl> Matrix { #[deprecated(note = "Renamed `self.adjoint_to(out)`.")] #[inline] pub fn conjugate_transpose_to(&self, out: &mut Matrix) - where - R2: Dim, - C2: Dim, - SB: StorageMut, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + where + R2: Dim, + C2: Dim, + SB: StorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, { self.adjoint_to(out) } @@ -972,7 +1043,9 @@ impl> Matrix { #[deprecated(note = "Renamed `self.adjoint()`.")] #[inline] pub fn conjugate_transpose(&self) -> MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.adjoint() } @@ -980,48 +1053,54 @@ impl> Matrix { #[inline] #[must_use = "Did you mean to use conjugate_mut()?"] pub fn conjugate(&self) -> MatrixMN - where DefaultAllocator: Allocator { - self.map(|e| e.conjugate()) + where + DefaultAllocator: Allocator, + { + self.map(|e| e.simd_conjugate()) } /// Divides each component of the complex matrix `self` by the given real. #[inline] #[must_use = "Did you mean to use unscale_mut()?"] - pub fn unscale(&self, real: N::RealField) -> MatrixMN - where DefaultAllocator: Allocator { - self.map(|e| e.unscale(real)) + pub fn unscale(&self, real: N::SimdRealField) -> MatrixMN + where + DefaultAllocator: Allocator, + { + self.map(|e| e.simd_unscale(real)) } /// Multiplies each component of the complex matrix `self` by the given real. #[inline] #[must_use = "Did you mean to use scale_mut()?"] - pub fn scale(&self, real: N::RealField) -> MatrixMN - where DefaultAllocator: Allocator { - self.map(|e| e.scale(real)) + pub fn scale(&self, real: N::SimdRealField) -> MatrixMN + where + DefaultAllocator: Allocator, + { + self.map(|e| e.simd_scale(real)) } } -impl> Matrix { +impl> Matrix { /// The conjugate of the complex matrix `self` computed in-place. #[inline] pub fn conjugate_mut(&mut self) { - self.apply(|e| e.conjugate()) + self.apply(|e| e.simd_conjugate()) } /// Divides each component of the complex matrix `self` by the given real. #[inline] - pub fn unscale_mut(&mut self, real: N::RealField) { - self.apply(|e| e.unscale(real)) + pub fn unscale_mut(&mut self, real: N::SimdRealField) { + self.apply(|e| e.simd_unscale(real)) } /// Multiplies each component of the complex matrix `self` by the given real. #[inline] - pub fn scale_mut(&mut self, real: N::RealField) { - self.apply(|e| e.scale(real)) + pub fn scale_mut(&mut self, real: N::SimdRealField) { + self.apply(|e| e.simd_scale(real)) } } -impl> Matrix { +impl> Matrix { /// Sets `self` to its adjoint. #[deprecated(note = "Renamed to `self.adjoint_mut()`.")] pub fn conjugate_transform_mut(&mut self) { @@ -1042,8 +1121,8 @@ impl> Matrix { unsafe { let ref_ij = self.get_unchecked_mut((i, j)) as *mut N; let ref_ji = self.get_unchecked_mut((j, i)) as *mut N; - let conj_ij = (*ref_ij).conjugate(); - let conj_ji = (*ref_ji).conjugate(); + let conj_ij = (*ref_ij).simd_conjugate(); + let conj_ji = (*ref_ji).simd_conjugate(); *ref_ij = conj_ji; *ref_ji = conj_ij; } @@ -1051,7 +1130,7 @@ impl> Matrix { { let diag = unsafe { self.get_unchecked_mut((i, i)) }; - *diag = diag.conjugate(); + *diag = diag.simd_conjugate(); } } } @@ -1061,7 +1140,9 @@ impl> SquareMatrix { /// The diagonal of this matrix. #[inline] pub fn diagonal(&self) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.map_diagonal(|e| e) } @@ -1070,7 +1151,9 @@ impl> SquareMatrix { /// This is a more efficient version of `self.diagonal().map(f)` since this /// allocates only once. pub fn map_diagonal(&self, mut f: impl FnMut(N) -> N2) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { assert!( self.is_square(), "Unable to get the diagonal of a non-square matrix." @@ -1091,7 +1174,9 @@ impl> SquareMatrix { /// Computes a trace of a square matrix, i.e., the sum of its diagonal elements. #[inline] pub fn trace(&self) -> N - where N: Ring { + where + N: Scalar + Zero + ClosedAdd, + { assert!( self.is_square(), "Cannot compute the trace of non-square matrix." @@ -1108,12 +1193,17 @@ impl> SquareMatrix { } } -impl> SquareMatrix { +impl> SquareMatrix { /// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`. #[inline] pub fn symmetric_part(&self) -> MatrixMN - where DefaultAllocator: Allocator { - assert!(self.is_square(), "Cannot compute the symmetric part of a non-square matrix."); + where + DefaultAllocator: Allocator, + { + assert!( + self.is_square(), + "Cannot compute the symmetric part of a non-square matrix." + ); let mut tr = self.transpose(); tr += self; tr *= crate::convert::<_, N>(0.5); @@ -1123,8 +1213,13 @@ impl> SquareMatrix { /// The hermitian part of `self`, i.e., `0.5 * (self + self.adjoint())`. #[inline] pub fn hermitian_part(&self) -> MatrixMN - where DefaultAllocator: Allocator { - assert!(self.is_square(), "Cannot compute the hermitian part of a non-square matrix."); + where + DefaultAllocator: Allocator, + { + assert!( + self.is_square(), + "Cannot compute the hermitian part of a non-square matrix." + ); let mut tr = self.adjoint(); tr += self; @@ -1133,20 +1228,26 @@ impl> SquareMatrix { } } -impl + IsNotStaticOne, S: Storage> Matrix { - +impl + IsNotStaticOne, S: Storage> + Matrix +{ /// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and /// and setting the diagonal element to `1`. #[inline] pub fn to_homogeneous(&self) -> MatrixN> - where DefaultAllocator: Allocator, DimSum> { - assert!(self.is_square(), "Only square matrices can currently be transformed to homogeneous coordinates."); + where + DefaultAllocator: Allocator, DimSum>, + { + assert!( + self.is_square(), + "Only square matrices can currently be transformed to homogeneous coordinates." + ); let dim = DimSum::::from_usize(self.nrows() + 1); let mut res = MatrixN::identity_generic(dim, dim); - res.generic_slice_mut::((0, 0), self.data.shape()).copy_from(&self); + res.generic_slice_mut::((0, 0), self.data.shape()) + .copy_from(&self); res } - } impl, S: Storage> Vector { @@ -1154,7 +1255,9 @@ impl, S: Storage> Vector { /// coordinates. #[inline] pub fn to_homogeneous(&self) -> VectorN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { self.push(N::zero()) } @@ -1179,7 +1282,9 @@ impl, S: Storage> Vector { /// Constructs a new vector of higher dimension by appending `element` to the end of `self`. #[inline] pub fn push(&self, element: N) -> VectorN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { let len = self.len(); let hnrows = DimSum::::from_usize(len + 1); let mut res = unsafe { VectorN::::new_uninitialized_generic(hnrows, U1) }; @@ -1229,8 +1334,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.relative_eq(other, epsilon, max_relative) } } @@ -1347,7 +1451,8 @@ impl Eq for Matrix where N: Scalar + Eq, S: Storage, -{} +{ +} impl PartialEq> for Matrix where @@ -1357,7 +1462,7 @@ where R: Dim, R2: Dim, S: Storage, - S2: Storage + S2: Storage, { #[inline] fn eq(&self, right: &Matrix) -> bool { @@ -1377,7 +1482,9 @@ macro_rules! impl_fmt { #[cfg(feature = "std")] fn val_width(val: &N, f: &mut fmt::Formatter) -> usize { match f.precision() { - Some(precision) => format!($fmt_str_with_precision, val, precision).chars().count(), + Some(precision) => format!($fmt_str_with_precision, val, precision) + .chars() + .count(), None => format!($fmt_str_without_precision, val).chars().count(), } } @@ -1421,7 +1528,9 @@ macro_rules! impl_fmt { let pad = max_length_with_space - number_length; write!(f, " {:>thepad$}", "", thepad = pad)?; match f.precision() { - Some(precision) => write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)?, + Some(precision) => { + write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)? + } None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?, } } @@ -1451,16 +1560,21 @@ impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); #[test] fn lower_exp() { let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.); - assert_eq!(format!("{:e}", test), r" + assert_eq!( + format!("{:e}", test), + r" ┌ ┐ │ 1e6 2e5 │ │ 2e-5 1e0 │ └ ┘ -") +" + ) } -impl> Matrix { +impl> + Matrix +{ /// The perpendicular product between two 2D column vectors, i.e. `a.x * b.y - a.y * b.x`. #[inline] pub fn perp(&self, b: &Matrix) -> N @@ -1477,7 +1591,8 @@ impl> Matrix { unsafe { self.get_unchecked((0, 0)).inlined_clone() * b.get_unchecked((1, 0)).inlined_clone() - - self.get_unchecked((1, 0)).inlined_clone() * b.get_unchecked((0, 0)).inlined_clone() + - self.get_unchecked((1, 0)).inlined_clone() + * b.get_unchecked((0, 0)).inlined_clone() } } @@ -1520,9 +1635,12 @@ impl> Matrix { let by = b.get_unchecked((1, 0)); let bz = b.get_unchecked((2, 0)); - *res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone() - az.inlined_clone() * by.inlined_clone(); - *res.get_unchecked_mut((1, 0)) = az.inlined_clone() * bx.inlined_clone() - ax.inlined_clone() * bz.inlined_clone(); - *res.get_unchecked_mut((2, 0)) = ax.inlined_clone() * by.inlined_clone() - ay.inlined_clone() * bx.inlined_clone(); + *res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone() + - az.inlined_clone() * by.inlined_clone(); + *res.get_unchecked_mut((1, 0)) = az.inlined_clone() * bx.inlined_clone() + - ax.inlined_clone() * bz.inlined_clone(); + *res.get_unchecked_mut((2, 0)) = ax.inlined_clone() * by.inlined_clone() + - ay.inlined_clone() * bx.inlined_clone(); res } @@ -1541,9 +1659,12 @@ impl> Matrix { let by = b.get_unchecked((0, 1)); let bz = b.get_unchecked((0, 2)); - *res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone() - az.inlined_clone() * by.inlined_clone(); - *res.get_unchecked_mut((0, 1)) = az.inlined_clone() * bx.inlined_clone() - ax.inlined_clone() * bz.inlined_clone(); - *res.get_unchecked_mut((0, 2)) = ax.inlined_clone() * by.inlined_clone() - ay.inlined_clone() * bx.inlined_clone(); + *res.get_unchecked_mut((0, 0)) = ay.inlined_clone() * bz.inlined_clone() + - az.inlined_clone() * by.inlined_clone(); + *res.get_unchecked_mut((0, 1)) = az.inlined_clone() * bx.inlined_clone() + - ax.inlined_clone() * bz.inlined_clone(); + *res.get_unchecked_mut((0, 2)) = ax.inlined_clone() * by.inlined_clone() + - ay.inlined_clone() * bx.inlined_clone(); res } @@ -1552,7 +1673,8 @@ impl> Matrix { } impl> Vector -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Computes the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`. #[inline] @@ -1571,10 +1693,10 @@ where DefaultAllocator: Allocator } } -impl> Matrix { +impl> Matrix { /// The smallest angle between two vectors. #[inline] - pub fn angle(&self, other: &Matrix) -> N::RealField + pub fn angle(&self, other: &Matrix) -> N::SimdRealField where SB: Storage, ShapeConstraint: DimEq + DimEq, @@ -1584,17 +1706,11 @@ impl> Matrix { let n2 = other.norm(); if n1.is_zero() || n2.is_zero() { - N::RealField::zero() + N::SimdRealField::zero() } else { - let cang = prod.real() / (n1 * n2); - - if cang > N::RealField::one() { - N::RealField::zero() - } else if cang < -N::RealField::one() { - N::RealField::pi() - } else { - cang.acos() - } + let cang = prod.simd_real() / (n1 * n2); + cang.simd_clamp(-N::SimdRealField::one(), N::SimdRealField::one()) + .simd_acos() } } } @@ -1615,7 +1731,9 @@ impl>(&self, rhs: &Vector, t: N) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let mut res = self.clone_owned(); res.axpy(t.inlined_clone(), rhs, N::one() - t); res @@ -1723,8 +1841,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.as_ref() .relative_eq(other.as_ref(), epsilon, max_relative) } @@ -1761,7 +1878,7 @@ where for j in 0..ncols { for i in 0..nrows { unsafe { - self.get_unchecked((i, j)).hash(state); + self.get_unchecked((i, j)).hash(state); } } } diff --git a/src/base/matrix_alga.rs b/src/base/matrix_alga.rs index 76a9d7ce..18182382 100644 --- a/src/base/matrix_alga.rs +++ b/src/base/matrix_alga.rs @@ -6,8 +6,8 @@ use num::{One, Zero}; use alga::general::{ AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul, - ClosedNeg, Field, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice, Module, - Multiplicative, RingCommutative, ComplexField + ClosedNeg, ComplexField, Field, Identity, JoinSemilattice, Lattice, MeetSemilattice, Module, + Multiplicative, RingCommutative, TwoSidedInverse, }; use alga::linear::{ FiniteDimInnerSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace, VectorSpace, @@ -146,19 +146,25 @@ where } } -impl NormedSpace for MatrixMN -where DefaultAllocator: Allocator +impl< + N: ComplexField + simba::scalar::ComplexField::RealField>, + R: DimName, + C: DimName, + > NormedSpace for MatrixMN +where + ::RealField: simba::scalar::RealField, + DefaultAllocator: Allocator, { - type RealField = N::RealField; + type RealField = ::RealField; type ComplexField = N; #[inline] - fn norm_squared(&self) -> N::RealField { + fn norm_squared(&self) -> ::RealField { self.norm_squared() } #[inline] - fn norm(&self) -> N::RealField { + fn norm(&self) -> ::RealField { self.norm() } @@ -169,27 +175,36 @@ where DefaultAllocator: Allocator } #[inline] - fn normalize_mut(&mut self) -> N::RealField { + fn normalize_mut(&mut self) -> ::RealField { self.normalize_mut() } #[inline] #[must_use = "Did you mean to use try_normalize_mut()?"] - fn try_normalize(&self, min_norm: N::RealField) -> Option { + fn try_normalize(&self, min_norm: ::RealField) -> Option { self.try_normalize(min_norm) } #[inline] - fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option { + fn try_normalize_mut( + &mut self, + min_norm: ::RealField, + ) -> Option<::RealField> { self.try_normalize_mut(min_norm) } } -impl InnerSpace for MatrixMN -where DefaultAllocator: Allocator +impl< + N: ComplexField + simba::scalar::ComplexField::RealField>, + R: DimName, + C: DimName, + > InnerSpace for MatrixMN +where + ::RealField: simba::scalar::RealField, + DefaultAllocator: Allocator, { #[inline] - fn angle(&self, other: &Self) -> N::RealField { + fn angle(&self, other: &Self) -> ::RealField { self.angle(other) } @@ -203,8 +218,14 @@ where DefaultAllocator: Allocator // In particular: // − use `x()` instead of `::canonical_basis_element` // − use `::new(x, y, z)` instead of `::from_slice` -impl FiniteDimInnerSpace for MatrixMN -where DefaultAllocator: Allocator +impl< + N: ComplexField + simba::scalar::ComplexField::RealField>, + R: DimName, + C: DimName, + > FiniteDimInnerSpace for MatrixMN +where + ::RealField: simba::scalar::RealField, + DefaultAllocator: Allocator, { #[inline] fn orthonormalize(vs: &mut [Self]) -> usize { @@ -219,7 +240,10 @@ where DefaultAllocator: Allocator } } - if vs[i].try_normalize_mut(N::RealField::zero()).is_some() { + if vs[i] + .try_normalize_mut(::RealField::zero()) + .is_some() + { // FIXME: this will be efficient on dynamically-allocated vectors but for // statically-allocated ones, `.clone_from` would be better. vs.swap(nbasis_elements, i); @@ -237,7 +261,9 @@ where DefaultAllocator: Allocator #[inline] fn orthonormal_subspace_basis(vs: &[Self], mut f: F) - where F: FnMut(&Self) -> bool { + where + F: FnMut(&Self) -> bool, + { // FIXME: is this necessary? assert!( vs.len() <= Self::dimension(), @@ -272,7 +298,7 @@ where DefaultAllocator: Allocator let v = &vs[0]; let mut a; - if v[0].norm1() > v[1].norm1() { + if ComplexField::norm1(v[0]) > ComplexField::norm1(v[1]) { a = Self::from_column_slice(&[v[2], N::zero(), -v[0]]); } else { a = Self::from_column_slice(&[N::zero(), -v[2], v[1]]); @@ -304,7 +330,9 @@ where DefaultAllocator: Allocator elt -= v * elt.dot(v) } - if let Some(subsp_elt) = elt.try_normalize(N::RealField::zero()) { + if let Some(subsp_elt) = + elt.try_normalize(::RealField::zero()) + { if !f(&subsp_elt) { return; }; diff --git a/src/base/matrix_simba.rs b/src/base/matrix_simba.rs new file mode 100644 index 00000000..a23ff3fb --- /dev/null +++ b/src/base/matrix_simba.rs @@ -0,0 +1,65 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::Dim; +use crate::base::{DefaultAllocator, MatrixMN, Scalar}; + +/* + * + * Simd structures. + * + */ +impl SimdValue for MatrixMN +where + N: Scalar + SimdValue, + R: Dim, + C: Dim, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + type Element = MatrixMN; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + val.map(N::splat) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.map(|e| e.extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.map(|e| e.extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.zip_apply(&val, |mut a, b| { + a.replace(i, b); + a + }) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.zip_apply(&val, |mut a, b| { + a.replace_unchecked(i, b); + a + }) + } + + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.zip_map(&other, |a, b| a.select(cond, b)) + } +} diff --git a/src/base/matrix_slice.rs b/src/base/matrix_slice.rs index be53034a..abb11725 100644 --- a/src/base/matrix_slice.rs +++ b/src/base/matrix_slice.rs @@ -4,9 +4,9 @@ use std::slice; use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; -use crate::base::dimension::{Dim, DimName, Dynamic, U1, IsNotStaticOne}; +use crate::base::dimension::{Dim, DimName, Dynamic, IsNotStaticOne, U1}; use crate::base::iter::MatrixIter; -use crate::base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut}; +use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut}; use crate::base::{Matrix, Scalar}; macro_rules! slice_storage_impl( @@ -198,13 +198,31 @@ unsafe impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> StorageMu } } -unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage for SliceStorage<'a, N, R, U1, U1, CStride> { } -unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage for SliceStorageMut<'a, N, R, U1, U1, CStride> { } -unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorageMut for SliceStorageMut<'a, N, R, U1, U1, CStride> { } +unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage + for SliceStorage<'a, N, R, U1, U1, CStride> +{ +} +unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorage + for SliceStorageMut<'a, N, R, U1, U1, CStride> +{ +} +unsafe impl<'a, N: Scalar, R: Dim, CStride: Dim> ContiguousStorageMut + for SliceStorageMut<'a, N, R, U1, U1, CStride> +{ +} -unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage for SliceStorage<'a, N, R, C, U1, R> { } -unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage for SliceStorageMut<'a, N, R, C, U1, R> { } -unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut for SliceStorageMut<'a, N, R, C, U1, R> { } +unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage + for SliceStorage<'a, N, R, C, U1, R> +{ +} +unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorage + for SliceStorageMut<'a, N, R, C, U1, R> +{ +} +unsafe impl<'a, N: Scalar, R: DimName, C: Dim + IsNotStaticOne> ContiguousStorageMut + for SliceStorageMut<'a, N, R, C, U1, R> +{ +} impl> Matrix { #[inline] @@ -213,8 +231,7 @@ impl> Matrix { start: (usize, usize), shape: (usize, usize), steps: (usize, usize), - ) - { + ) { let my_shape = self.shape(); // NOTE: we don't do any subtraction to avoid underflow for zero-sized matrices. // @@ -811,8 +828,7 @@ impl> Matrix { pub fn rows_range>( &self, rows: RowRange, - ) -> MatrixSlice - { + ) -> MatrixSlice { self.slice_range(rows, ..) } @@ -821,8 +837,7 @@ impl> Matrix { pub fn columns_range>( &self, cols: ColRange, - ) -> MatrixSlice - { + ) -> MatrixSlice { self.slice_range(.., cols) } } @@ -851,8 +866,7 @@ impl> Matrix { pub fn rows_range_mut>( &mut self, rows: RowRange, - ) -> MatrixSliceMut - { + ) -> MatrixSliceMut { self.slice_range_mut(rows, ..) } @@ -861,30 +875,28 @@ impl> Matrix { pub fn columns_range_mut>( &mut self, cols: ColRange, - ) -> MatrixSliceMut - { + ) -> MatrixSliceMut { self.slice_range_mut(.., cols) } } - impl<'a, N, R, C, RStride, CStride> From> -for MatrixSlice<'a, N, R, C, RStride, CStride> - where - N: Scalar, - R: Dim, - C: Dim, - RStride: Dim, - CStride: Dim, + for MatrixSlice<'a, N, R, C, RStride, CStride> +where + N: Scalar, + R: Dim, + C: Dim, + RStride: Dim, + CStride: Dim, { fn from(slice_mut: MatrixSliceMut<'a, N, R, C, RStride, CStride>) -> Self { let data = SliceStorage { - ptr: slice_mut.data.ptr, - shape: slice_mut.data.shape, - strides: slice_mut.data.strides, + ptr: slice_mut.data.ptr, + shape: slice_mut.data.shape, + strides: slice_mut.data.strides, _phantoms: PhantomData, }; unsafe { Matrix::from_data_statically_unchecked(data) } } -} \ No newline at end of file +} diff --git a/src/base/mod.rs b/src/base/mod.rs index 0ec6311c..0e8ea72d 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -12,6 +12,7 @@ pub mod storage; mod alias; mod alias_slice; +mod array_storage; mod cg; mod componentwise; mod construction; @@ -20,25 +21,26 @@ mod conversion; mod edition; pub mod indexing; mod matrix; +#[cfg(feature = "alga")] mod matrix_alga; -mod array_storage; +mod matrix_simba; mod matrix_slice; -#[cfg(any(feature = "std", feature = "alloc"))] -mod vec_storage; +mod norm; mod properties; mod scalar; +mod statistics; mod swizzle; mod unit; -mod statistics; -mod norm; +#[cfg(any(feature = "std", feature = "alloc"))] +mod vec_storage; #[doc(hidden)] pub mod helper; pub use self::matrix::*; +pub use self::norm::*; pub use self::scalar::*; pub use self::unit::*; -pub use self::norm::*; pub use self::default_allocator::*; pub use self::dimension::*; diff --git a/src/base/norm.rs b/src/base/norm.rs index 675530ec..d0f593ce 100644 --- a/src/base/norm.rs +++ b/src/base/norm.rs @@ -1,25 +1,42 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + use num::Zero; +use std::ops::Neg; use crate::allocator::Allocator; -use crate::{RealField, ComplexField}; +use crate::base::{DefaultAllocator, Dim, DimName, Matrix, MatrixMN, Normed, VectorN}; +use crate::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use crate::storage::{Storage, StorageMut}; -use crate::base::{DefaultAllocator, Matrix, Dim, MatrixMN}; -use crate::constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint}; - +use crate::{ComplexField, Scalar, SimdComplexField, Unit}; +use simba::scalar::ClosedNeg; +use simba::simd::{SimdOption, SimdPartialOrd}; // FIXME: this should be be a trait on alga? /// A trait for abstract matrix norms. /// /// This may be moved to the alga crate in the future. -pub trait Norm { +pub trait Norm { /// Apply this norm to the given matrix. - fn norm(&self, m: &Matrix) -> N::RealField - where R: Dim, C: Dim, S: Storage; + fn norm(&self, m: &Matrix) -> N::SimdRealField + where + R: Dim, + C: Dim, + S: Storage; /// Use the metric induced by this norm to compute the metric distance between the two given matrices. - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N::RealField - where R1: Dim, C1: Dim, S1: Storage, - R2: Dim, C2: Dim, S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns; + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> N::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns; } /// Euclidean norm. @@ -29,81 +46,123 @@ pub struct LpNorm(pub i32); /// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm. pub struct UniformNorm; -impl Norm for EuclideanNorm { +impl Norm for EuclideanNorm { #[inline] - fn norm(&self, m: &Matrix) -> N::RealField - where R: Dim, C: Dim, S: Storage { - m.norm_squared().sqrt() + fn norm(&self, m: &Matrix) -> N::SimdRealField + where + R: Dim, + C: Dim, + S: Storage, + { + m.norm_squared().simd_sqrt() } #[inline] - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N::RealField - where R1: Dim, C1: Dim, S1: Storage, - R2: Dim, C2: Dim, S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| { + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> N::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + m1.zip_fold(m2, N::SimdRealField::zero(), |acc, a, b| { let diff = a - b; - acc + diff.modulus_squared() - }).sqrt() + acc + diff.simd_modulus_squared() + }) + .simd_sqrt() } } -impl Norm for LpNorm { +impl Norm for LpNorm { #[inline] - fn norm(&self, m: &Matrix) -> N::RealField - where R: Dim, C: Dim, S: Storage { - m.fold(N::RealField::zero(), |a, b| { - a + b.modulus().powi(self.0) - }).powf(crate::convert(1.0 / (self.0 as f64))) + fn norm(&self, m: &Matrix) -> N::SimdRealField + where + R: Dim, + C: Dim, + S: Storage, + { + m.fold(N::SimdRealField::zero(), |a, b| { + a + b.simd_modulus().simd_powi(self.0) + }) + .simd_powf(crate::convert(1.0 / (self.0 as f64))) } #[inline] - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N::RealField - where R1: Dim, C1: Dim, S1: Storage, - R2: Dim, C2: Dim, S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| { + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> N::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + m1.zip_fold(m2, N::SimdRealField::zero(), |acc, a, b| { let diff = a - b; - acc + diff.modulus().powi(self.0) - }).powf(crate::convert(1.0 / (self.0 as f64))) + acc + diff.simd_modulus().simd_powi(self.0) + }) + .simd_powf(crate::convert(1.0 / (self.0 as f64))) } } -impl Norm for UniformNorm { +impl Norm for UniformNorm { #[inline] - fn norm(&self, m: &Matrix) -> N::RealField - where R: Dim, C: Dim, S: Storage { + fn norm(&self, m: &Matrix) -> N::SimdRealField + where + R: Dim, + C: Dim, + S: Storage, + { // NOTE: we don't use `m.amax()` here because for the complex // numbers this will return the max norm1 instead of the modulus. - m.fold(N::RealField::zero(), |acc, a| acc.max(a.modulus())) + m.fold(N::SimdRealField::zero(), |acc, a| { + acc.simd_max(a.simd_modulus()) + }) } #[inline] - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N::RealField - where R1: Dim, C1: Dim, S1: Storage, - R2: Dim, C2: Dim, S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| { - let val = (a - b).modulus(); - if val > acc { - val - } else { - acc - } + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> N::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + m1.zip_fold(m2, N::SimdRealField::zero(), |acc, a, b| { + let val = (a - b).simd_modulus(); + acc.simd_max(val) }) } } - -impl> Matrix { +impl> Matrix { /// The squared L2 norm of this vector. #[inline] - pub fn norm_squared(&self) -> N::RealField { - let mut res = N::RealField::zero(); + pub fn norm_squared(&self) -> N::SimdRealField { + let mut res = N::SimdRealField::zero(); for i in 0..self.ncols() { let col = self.column(i); - res += col.dotc(&col).real() + res += col.dotc(&col).simd_real() } res @@ -113,17 +172,21 @@ impl> Matrix { /// /// Use `.apply_norm` to apply a custom norm. #[inline] - pub fn norm(&self) -> N::RealField { - self.norm_squared().sqrt() + pub fn norm(&self) -> N::SimdRealField { + self.norm_squared().simd_sqrt() } /// Compute the distance between `self` and `rhs` using the metric induced by the euclidean norm. /// /// Use `.apply_metric_distance` to apply a custom norm. #[inline] - pub fn metric_distance(&self, rhs: &Matrix) -> N::RealField - where R2: Dim, C2: Dim, S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + pub fn metric_distance(&self, rhs: &Matrix) -> N::SimdRealField + where + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { self.apply_metric_distance(rhs, &EuclideanNorm) } @@ -140,7 +203,7 @@ impl> Matrix { /// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm()); /// ``` #[inline] - pub fn apply_norm(&self, norm: &impl Norm) -> N::RealField { + pub fn apply_norm(&self, norm: &impl Norm) -> N::SimdRealField { norm.norm(self) } @@ -159,9 +222,17 @@ impl> Matrix { /// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm()); /// ``` #[inline] - pub fn apply_metric_distance(&self, rhs: &Matrix, norm: &impl Norm) -> N::RealField - where R2: Dim, C2: Dim, S2: Storage, - ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + pub fn apply_metric_distance( + &self, + rhs: &Matrix, + norm: &impl Norm, + ) -> N::SimdRealField + where + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { norm.metric_distance(self, rhs) } @@ -171,7 +242,7 @@ impl> Matrix { /// /// This function is simply implemented as a call to `norm()` #[inline] - pub fn magnitude(&self) -> N::RealField { + pub fn magnitude(&self) -> N::SimdRealField { self.norm() } @@ -181,18 +252,63 @@ impl> Matrix { /// /// This function is simply implemented as a call to `norm_squared()` #[inline] - pub fn magnitude_squared(&self) -> N::RealField { + pub fn magnitude_squared(&self) -> N::SimdRealField { self.norm_squared() } + /// Sets the magnitude of this vector. + #[inline] + pub fn set_magnitude(&mut self, magnitude: N::SimdRealField) + where + S: StorageMut, + { + let n = self.norm(); + self.scale_mut(magnitude / n) + } + /// Returns a normalized version of this matrix. + #[inline] + #[must_use = "Did you mean to use normalize_mut()?"] + pub fn normalize(&self) -> MatrixMN + where + DefaultAllocator: Allocator, + { + self.unscale(self.norm()) + } + + /// The Lp norm of this matrix. + #[inline] + pub fn lp_norm(&self, p: i32) -> N::SimdRealField { + self.apply_norm(&LpNorm(p)) + } + + /// Attempts to normalize `self`. + /// + /// The components of this matrix can be SIMD types. + #[inline] + #[must_use = "Did you mean to use simd_try_normalize_mut()?"] + pub fn simd_try_normalize(&self, min_norm: N::SimdRealField) -> SimdOption> + where + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, + { + let n = self.norm(); + let le = n.simd_le(min_norm); + let val = self.unscale(n); + SimdOption::new(val, le) + } +} + +impl> Matrix { /// Sets the magnitude of this vector unless it is smaller than `min_magnitude`. /// /// If `self.magnitude()` is smaller than `min_magnitude`, it will be left unchanged. /// Otherwise this is equivalent to: `*self = self.normalize() * magnitude. #[inline] pub fn try_set_magnitude(&mut self, magnitude: N::RealField, min_magnitude: N::RealField) - where S: StorageMut { + where + S: StorageMut, + { let n = self.norm(); if n >= min_magnitude { @@ -200,19 +316,15 @@ impl> Matrix { } } - /// Returns a normalized version of this matrix. - #[inline] - #[must_use = "Did you mean to use normalize_mut()?"] - pub fn normalize(&self) -> MatrixMN - where DefaultAllocator: Allocator { - self.unscale(self.norm()) - } - /// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`. + /// + /// The components of this matrix cannot be SIMD types (see `simd_try_normalize`) instead. #[inline] #[must_use = "Did you mean to use try_normalize_mut()?"] pub fn try_normalize(&self, min_norm: N::RealField) -> Option> - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let n = self.norm(); if n <= min_norm { @@ -221,25 +333,41 @@ impl> Matrix { Some(self.unscale(n)) } } - - /// The Lp norm of this matrix. - #[inline] - pub fn lp_norm(&self, p: i32) -> N::RealField { - self.apply_norm(&LpNorm(p)) - } } - -impl> Matrix { +impl> Matrix { /// Normalizes this matrix in-place and returns its norm. + /// + /// The components of the matrix cannot be SIMD types (see `simd_try_normalize_mut` instead). #[inline] - pub fn normalize_mut(&mut self) -> N::RealField { + pub fn normalize_mut(&mut self) -> N::SimdRealField { let n = self.norm(); self.unscale_mut(n); n } + /// Normalizes this matrix in-place and return its norm. + /// + /// The components of the matrix can be SIMD types. + #[inline] + #[must_use = "Did you mean to use simd_try_normalize_mut()?"] + pub fn simd_try_normalize_mut( + &mut self, + min_norm: N::SimdRealField, + ) -> SimdOption + where + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, + { + let n = self.norm(); + let le = n.simd_le(min_norm); + self.apply(|e| e.simd_unscale(n).select(le, e)); + SimdOption::new(n, le) + } +} + +impl> Matrix { /// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`. /// /// If the normalization succeeded, returns the old norm of this matrix. @@ -255,3 +383,189 @@ impl> Matrix } } } + +impl Normed for MatrixMN +where + DefaultAllocator: Allocator, +{ + type Norm = N::SimdRealField; + + #[inline] + fn norm(&self) -> N::SimdRealField { + self.norm() + } + + #[inline] + fn norm_squared(&self) -> N::SimdRealField { + self.norm_squared() + } + + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.scale_mut(n) + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.unscale_mut(n) + } +} + +impl Neg for Unit> +where + DefaultAllocator: Allocator, +{ + type Output = Unit>; + + #[inline] + fn neg(self) -> Self::Output { + Unit::new_unchecked(-self.value) + } +} + +// FIXME: specialization will greatly simplify this implementation in the future. +// In particular: +// − use `x()` instead of `::canonical_basis_element` +// − use `::new(x, y, z)` instead of `::from_slice` +impl VectorN +where + DefaultAllocator: Allocator, +{ + /// 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) = N::one(); + } + + res + } + + /// Orthonormalizes the given family of vectors. The largest free family of vectors is moved at + /// the beginning of the array and its size is returned. Vectors at an indices larger or equal to + /// this length can be modified to an arbitrary value. + #[inline] + pub fn orthonormalize(vs: &mut [Self]) -> usize { + let mut nbasis_elements = 0; + + for i in 0..vs.len() { + { + let (elt, basis) = vs[..i + 1].split_last_mut().unwrap(); + + for basis_element in &basis[..nbasis_elements] { + *elt -= &*basis_element * elt.dot(basis_element) + } + } + + if vs[i].try_normalize_mut(N::RealField::zero()).is_some() { + // FIXME: this will be efficient on dynamically-allocated vectors but for + // statically-allocated ones, `.clone_from` would be better. + vs.swap(nbasis_elements, i); + nbasis_elements += 1; + + // All the other vectors will be dependent. + if nbasis_elements == D::dim() { + break; + } + } + } + + nbasis_elements + } + + /// Applies the given closure to each element of the orthonormal basis of the subspace + /// orthogonal to free family of vectors `vs`. If `vs` is not a free family, the result is + /// unspecified. + // FIXME: return an iterator instead when `-> impl Iterator` will be supported by Rust. + #[inline] + pub fn orthonormal_subspace_basis(vs: &[Self], mut f: F) + where + F: FnMut(&Self) -> bool, + { + // FIXME: is this necessary? + assert!( + vs.len() <= D::dim(), + "The given set of vectors has no chance of being a free family." + ); + + match D::dim() { + 1 => { + if vs.len() == 0 { + let _ = f(&Self::canonical_basis_element(0)); + } + } + 2 => { + if vs.len() == 0 { + let _ = f(&Self::canonical_basis_element(0)) + && 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 _ = f(&res.normalize()); + } + + // Otherwise, nothing. + } + 3 => { + if vs.len() == 0 { + let _ = f(&Self::canonical_basis_element(0)) + && f(&Self::canonical_basis_element(1)) + && f(&Self::canonical_basis_element(2)); + } else if vs.len() == 1 { + let v = &vs[0]; + let mut a; + + if v[0].norm1() > v[1].norm1() { + a = Self::from_column_slice(&[v[2], N::zero(), -v[0]]); + } else { + a = Self::from_column_slice(&[N::zero(), -v[2], v[1]]); + }; + + let _ = a.normalize_mut(); + + if f(&a.cross(v)) { + let _ = f(&a); + } + } else if vs.len() == 2 { + let _ = f(&vs[0].cross(&vs[1]).normalize()); + } + } + _ => { + #[cfg(any(feature = "std", feature = "alloc"))] + { + // XXX: use a GenericArray instead. + let mut known_basis = Vec::new(); + + for v in vs.iter() { + known_basis.push(v.normalize()) + } + + for i in 0..D::dim() - vs.len() { + let mut elt = Self::canonical_basis_element(i); + + for v in &known_basis { + elt -= v * elt.dot(v) + } + + if let Some(subsp_elt) = elt.try_normalize(N::RealField::zero()) { + if !f(&subsp_elt) { + return; + }; + + known_basis.push(subsp_elt); + } + } + } + #[cfg(all(not(feature = "std"), not(feature = "alloc")))] + { + panic!("Cannot compute the orthogonal subspace basis of a vector with a dimension greater than 3 \ + if #![no_std] is enabled and the 'alloc' feature is not enabled.") + } + } + } + } +} diff --git a/src/base/ops.rs b/src/base/ops.rs index 2a861afd..12b26d1a 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -1,11 +1,11 @@ -use num::{One, Signed, Zero}; -use std::cmp::{PartialOrd, Ordering}; +use num::{One, Zero}; use std::iter; use std::ops::{ Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, }; -use alga::general::{ComplexField, ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; +use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; +use simba::simd::{SimdPartialOrd, SimdSigned}; use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; use crate::base::constraint::{ @@ -14,6 +14,7 @@ use crate::base::constraint::{ use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic}; use crate::base::storage::{ContiguousStorageMut, Storage, StorageMut}; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, MatrixSum, Scalar, VectorSliceN}; +use crate::SimdComplexField; /* * @@ -445,7 +446,9 @@ where /// # use nalgebra::DMatrix; /// iter::empty::<&DMatrix>().sum::>(); // panics! /// ``` - fn sum>>(mut iter: I) -> MatrixMN { + fn sum>>( + mut iter: I, + ) -> MatrixMN { if let Some(first) = iter.next() { iter.fold(first.clone(), |acc, x| acc + x) } else { @@ -692,11 +695,11 @@ where /// Equivalent to `self.adjoint() * rhs`. #[inline] pub fn ad_mul(&self, rhs: &Matrix) -> MatrixMN - where - N: ComplexField, - SB: Storage, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + N: SimdComplexField, + SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = unsafe { Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1) }; @@ -710,7 +713,10 @@ where &self, rhs: &Matrix, out: &mut Matrix, - dot: impl Fn(&VectorSliceN, &VectorSliceN) -> N, + dot: impl Fn( + &VectorSliceN, + &VectorSliceN, + ) -> N, ) where SB: Storage, SC: StorageMut, @@ -760,7 +766,7 @@ where rhs: &Matrix, out: &mut Matrix, ) where - N: ComplexField, + N: SimdComplexField, SB: Storage, SC: StorageMut, ShapeConstraint: SameNumberOfRows + DimEq + DimEq, @@ -813,7 +819,8 @@ where let coeff = self.get_unchecked((i1, j1)).inlined_clone(); for i2 in 0..nrows2.value() { - *data_res = coeff.inlined_clone() * rhs.get_unchecked((i2, j2)).inlined_clone(); + *data_res = coeff.inlined_clone() + * rhs.get_unchecked((i2, j2)).inlined_clone(); data_res = data_res.offset(1); } } @@ -831,7 +838,9 @@ impl> Matrix MatrixMN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let mut res = self.clone_owned(); res.add_scalar_mut(rhs); res @@ -840,7 +849,9 @@ impl> Matrix { + where + S: StorageMut, + { for e in self.iter_mut() { *e += rhs.inlined_clone() } @@ -868,23 +879,6 @@ where } impl> Matrix { - #[inline(always)] - fn xcmp(&self, abs: impl Fn(N) -> N2, ordering: Ordering) -> N2 - where N2: Scalar + PartialOrd + Zero { - let mut iter = self.iter(); - let mut max = iter.next().cloned().map_or(N2::zero(), &abs); - - for e in iter { - let ae = abs(e.inlined_clone()); - - if ae.partial_cmp(&max) == Some(ordering) { - max = ae; - } - } - - max - } - /// Returns the absolute value of the component with the largest absolute value. /// # Example /// ``` @@ -894,8 +888,13 @@ impl> Matrix { /// ``` #[inline] pub fn amax(&self) -> N - where N: PartialOrd + Signed { - self.xcmp(|e| e.abs(), Ordering::Greater) + where + N: Zero + SimdSigned + SimdPartialOrd, + { + self.fold_with( + |e| e.unwrap_or(&N::zero()).simd_abs(), + |a, b| a.simd_max(b.simd_abs()), + ) } /// Returns the the 1-norm of the complex component with the largest 1-norm. @@ -908,9 +907,14 @@ impl> Matrix { /// Complex::new(1.0, 3.0)).camax(), 5.0); /// ``` #[inline] - pub fn camax(&self) -> N::RealField - where N: ComplexField { - self.xcmp(|e| e.norm1(), Ordering::Greater) + pub fn camax(&self) -> N::SimdRealField + where + N: SimdComplexField, + { + self.fold_with( + |e| e.unwrap_or(&N::zero()).simd_norm1(), + |a, b| a.simd_max(b.simd_norm1()), + ) } /// Returns the component with the largest value. @@ -923,8 +927,13 @@ impl> Matrix { /// ``` #[inline] pub fn max(&self) -> N - where N: PartialOrd + Zero { - self.xcmp(|e| e, Ordering::Greater) + where + N: SimdPartialOrd + Zero, + { + self.fold_with( + |e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()), + |a, b| a.simd_max(b.inlined_clone()), + ) } /// Returns the absolute value of the component with the smallest absolute value. @@ -936,8 +945,13 @@ impl> Matrix { /// ``` #[inline] pub fn amin(&self) -> N - where N: PartialOrd + Signed { - self.xcmp(|e| e.abs(), Ordering::Less) + where + N: Zero + SimdPartialOrd + SimdSigned, + { + self.fold_with( + |e| e.map(|e| e.simd_abs()).unwrap_or(N::zero()), + |a, b| a.simd_min(b.simd_abs()), + ) } /// Returns the the 1-norm of the complex component with the smallest 1-norm. @@ -950,9 +964,17 @@ impl> Matrix { /// Complex::new(1.0, 3.0)).camin(), 3.0); /// ``` #[inline] - pub fn camin(&self) -> N::RealField - where N: ComplexField { - self.xcmp(|e| e.norm1(), Ordering::Less) + pub fn camin(&self) -> N::SimdRealField + where + N: SimdComplexField, + { + self.fold_with( + |e| { + e.map(|e| e.simd_norm1()) + .unwrap_or(N::SimdRealField::zero()) + }, + |a, b| a.simd_min(b.simd_norm1()), + ) } /// Returns the component with the smallest value. @@ -965,7 +987,12 @@ impl> Matrix { /// ``` #[inline] pub fn min(&self) -> N - where N: PartialOrd + Zero { - self.xcmp(|e| e, Ordering::Less) + where + N: SimdPartialOrd + Zero, + { + self.fold_with( + |e| e.map(|e| e.inlined_clone()).unwrap_or(N::zero()), + |a, b| a.simd_min(b.inlined_clone()), + ) } } diff --git a/src/base/properties.rs b/src/base/properties.rs index 8ca49568..69ca5d66 100644 --- a/src/base/properties.rs +++ b/src/base/properties.rs @@ -2,7 +2,7 @@ use approx::RelativeEq; use num::{One, Zero}; -use alga::general::{ClosedAdd, ClosedMul, RealField, ComplexField}; +use simba::scalar::{ClosedAdd, ClosedMul, ComplexField, RealField}; use crate::base::allocator::Allocator; use crate::base::dimension::{Dim, DimMin}; @@ -91,18 +91,19 @@ impl> Matrix { /// equal to `eps`. #[inline] pub fn is_orthogonal(&self, eps: N::Epsilon) -> bool - where - N: Zero + One + ClosedAdd + ClosedMul + RelativeEq, - S: Storage, - N::Epsilon: Copy, - DefaultAllocator: Allocator + Allocator, + where + N: Zero + One + ClosedAdd + ClosedMul + RelativeEq, + S: Storage, + N::Epsilon: Copy, + DefaultAllocator: Allocator + Allocator, { (self.ad_mul(self)).is_identity(eps) } } impl> SquareMatrix -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Checks that this matrix is orthogonal and has a determinant equal to 1. #[inline] diff --git a/src/base/statistics.rs b/src/base/statistics.rs index 14b47474..afd9eedd 100644 --- a/src/base/statistics.rs +++ b/src/base/statistics.rs @@ -1,21 +1,28 @@ -use crate::{Scalar, Dim, Matrix, VectorN, RowVectorN, DefaultAllocator, U1, VectorSliceN}; -use alga::general::{AdditiveMonoid, Field, SupersetOf}; -use crate::storage::Storage; use crate::allocator::Allocator; +use crate::storage::Storage; +use crate::{DefaultAllocator, Dim, Matrix, RowVectorN, Scalar, VectorN, VectorSliceN, U1}; +use num::Zero; +use simba::scalar::{ClosedAdd, Field, SupersetOf}; impl> Matrix { /// Returns a row vector where each element is the result of the application of `f` on the /// corresponding column of the original matrix. #[inline] - pub fn compress_rows(&self, f: impl Fn(VectorSliceN) -> N) -> RowVectorN - where DefaultAllocator: Allocator { - + pub fn compress_rows( + &self, + f: impl Fn(VectorSliceN) -> N, + ) -> RowVectorN + where + DefaultAllocator: Allocator, + { let ncols = self.data.shape().1; let mut res = unsafe { RowVectorN::new_uninitialized_generic(U1, ncols) }; for i in 0..ncols.value() { // FIXME: avoid bound checking of column. - unsafe { *res.get_unchecked_mut((0, i)) = f(self.column(i)); } + unsafe { + *res.get_unchecked_mut((0, i)) = f(self.column(i)); + } } res @@ -26,15 +33,21 @@ impl> Matrix { /// /// This is the same as `self.compress_rows(f).transpose()`. #[inline] - pub fn compress_rows_tr(&self, f: impl Fn(VectorSliceN) -> N) -> VectorN - where DefaultAllocator: Allocator { - + pub fn compress_rows_tr( + &self, + f: impl Fn(VectorSliceN) -> N, + ) -> VectorN + where + DefaultAllocator: Allocator, + { let ncols = self.data.shape().1; let mut res = unsafe { VectorN::new_uninitialized_generic(ncols, U1) }; for i in 0..ncols.value() { // FIXME: avoid bound checking of column. - unsafe { *res.vget_unchecked_mut(i) = f(self.column(i)); } + unsafe { + *res.vget_unchecked_mut(i) = f(self.column(i)); + } } res @@ -42,8 +55,14 @@ impl> Matrix { /// Returns a column vector resulting from the folding of `f` on each column of this matrix. #[inline] - pub fn compress_columns(&self, init: VectorN, f: impl Fn(&mut VectorN, VectorSliceN)) -> VectorN - where DefaultAllocator: Allocator { + pub fn compress_columns( + &self, + init: VectorN, + f: impl Fn(&mut VectorN, VectorSliceN), + ) -> VectorN + where + DefaultAllocator: Allocator, + { let mut res = init; for i in 0..self.ncols() { @@ -54,7 +73,7 @@ impl> Matrix { } } -impl> Matrix { +impl> Matrix { /* * * Sum computation. @@ -95,7 +114,9 @@ impl> Matrix RowVectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.compress_rows(|col| col.sum()) } @@ -116,7 +137,9 @@ impl> Matrix VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.compress_rows_tr(|col| col.sum()) } @@ -137,7 +160,9 @@ impl> Matrix VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let nrows = self.data.shape().0; self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| { *out += col; @@ -168,7 +193,9 @@ impl, R: Dim, C: Dim, S: Storage> M if self.len() == 0 { N::zero() } else { - let val = self.iter().cloned().fold((N::zero(), N::zero()), |a, b| (a.0 + b.inlined_clone() * b.inlined_clone(), a.1 + b)); + let val = self.iter().cloned().fold((N::zero(), N::zero()), |a, b| { + (a.0 + b.inlined_clone() * b.inlined_clone(), a.1 + b) + }); let denom = N::one() / crate::convert::<_, N>(self.len() as f64); let vd = val.1 * denom.inlined_clone(); val.0 * denom - vd.inlined_clone() * vd @@ -189,7 +216,9 @@ impl, R: Dim, C: Dim, S: Storage> M /// ``` #[inline] pub fn row_variance(&self) -> RowVectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.compress_rows(|col| col.variance()) } @@ -206,7 +235,9 @@ impl, R: Dim, C: Dim, S: Storage> M /// ``` #[inline] pub fn row_variance_tr(&self) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.compress_rows_tr(|col| col.variance()) } @@ -224,7 +255,9 @@ impl, R: Dim, C: Dim, S: Storage> M /// ``` #[inline] pub fn column_variance(&self) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = self.data.shape(); let mut mean = self.column_mean(); @@ -235,7 +268,8 @@ impl, R: Dim, C: Dim, S: Storage> M 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.inlined_clone() * val.inlined_clone() * val.inlined_clone() } } }) @@ -281,7 +315,9 @@ impl, R: Dim, C: Dim, S: Storage> M /// ``` #[inline] pub fn row_mean(&self) -> RowVectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.compress_rows(|col| col.mean()) } @@ -298,7 +334,9 @@ impl, R: Dim, C: Dim, S: Storage> M /// ``` #[inline] pub fn row_mean_tr(&self) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.compress_rows_tr(|col| col.mean()) } @@ -315,7 +353,9 @@ impl, R: Dim, C: Dim, S: Storage> M /// ``` #[inline] pub fn column_mean(&self) -> VectorN - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = self.data.shape(); let denom = N::one() / crate::convert::<_, N>(ncols.value() as f64); self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| { diff --git a/src/base/storage.rs b/src/base/storage.rs index e7439552..9f039ba2 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -94,22 +94,22 @@ pub unsafe trait Storage: Debug + Sized { } /// Indicates whether this data buffer stores its elements contiguously. - #[inline] fn is_contiguous(&self) -> bool; /// Retrieves the data buffer as a contiguous slice. /// /// The matrix components may not be stored in a contiguous way, depending on the strides. - #[inline] fn as_slice(&self) -> &[N]; /// Builds a matrix data storage that does not contain any reference. fn into_owned(self) -> Owned - where DefaultAllocator: Allocator; + where + DefaultAllocator: Allocator; /// Clones this data storage to one that does not contain any reference. fn clone_owned(&self) -> Owned - where DefaultAllocator: Allocator; + where + DefaultAllocator: Allocator; } /// Trait implemented by matrix data storage that can provide a mutable access to its elements. @@ -166,7 +166,6 @@ pub unsafe trait StorageMut: Storage { /// Retrieves the mutable data buffer as a contiguous slice. /// /// Matrix components may not be contiguous, depending on its strides. - #[inline] fn as_mut_slice(&mut self) -> &mut [N]; } diff --git a/src/base/unit.rs b/src/base/unit.rs index 6fe831da..f0334679 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -1,8 +1,7 @@ -use approx::RelativeEq; #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; use std::mem; -use std::ops::{Deref, Neg}; +use std::ops::Deref; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -10,8 +9,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{SubsetOf, ComplexField}; -use alga::linear::NormedSpace; +use crate::allocator::Allocator; +use crate::base::DefaultAllocator; +use crate::{Dim, MatrixMN, RealField, Scalar, SimdComplexField, SimdRealField}; /// A wrapper that ensures the underlying algebraic entity has a unit norm. /// @@ -19,13 +19,15 @@ use alga::linear::NormedSpace; #[repr(transparent)] #[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)] pub struct Unit { - value: T, + pub(crate) value: T, } #[cfg(feature = "serde-serialize")] impl Serialize for Unit { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.value.serialize(serializer) } } @@ -33,7 +35,9 @@ impl Serialize for Unit { #[cfg(feature = "serde-serialize")] impl<'de, T: Deserialize<'de>> Deserialize<'de> for Unit { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { + where + D: Deserializer<'de>, + { T::deserialize(deserializer).map(|x| Unit { value: x }) } } @@ -53,60 +57,86 @@ impl Abomonation for Unit { } } -impl Unit { - /// Normalize the given value and return it wrapped on a `Unit` structure. +/// Trait implemented by entities scan be be normalized and put in an `Unit` struct. +pub trait Normed { + /// The type of the norm. + type Norm: SimdRealField; + /// Computes the norm. + fn norm(&self) -> Self::Norm; + /// Computes the squared norm. + fn norm_squared(&self) -> Self::Norm; + /// Multiply `self` by n. + fn scale_mut(&mut self, n: Self::Norm); + /// Divides `self` by n. + fn unscale_mut(&mut self, n: Self::Norm); +} + +impl Unit { + /// Normalize the given vector and return it wrapped on a `Unit` structure. #[inline] pub fn new_normalize(value: T) -> Self { Self::new_and_get(value).0 } - /// Attempts to normalize the given value and return it wrapped on a `Unit` structure. + /// Attempts to normalize the given vector and return it wrapped on a `Unit` structure. /// /// Returns `None` if the norm was smaller or equal to `min_norm`. #[inline] - pub fn try_new(value: T, min_norm: T::RealField) -> Option { + pub fn try_new(value: T, min_norm: T::Norm) -> Option + where + T::Norm: RealField, + { Self::try_new_and_get(value, min_norm).map(|res| res.0) } - /// Normalize the given value and return it wrapped on a `Unit` structure and its norm. + /// Normalize the given vector and return it wrapped on a `Unit` structure and its norm. #[inline] - pub fn new_and_get(mut value: T) -> (Self, T::RealField) { - let n = value.normalize_mut(); - - (Unit { value: value }, n) + pub fn new_and_get(mut value: T) -> (Self, T::Norm) { + let n = value.norm(); + value.unscale_mut(n); + (Unit { value }, n) } - /// Normalize the given value and return it wrapped on a `Unit` structure and its norm. + /// Normalize the given vector and return it wrapped on a `Unit` structure and its norm. /// /// Returns `None` if the norm was smaller or equal to `min_norm`. #[inline] - pub fn try_new_and_get(mut value: T, min_norm: T::RealField) -> Option<(Self, T::RealField)> { - if let Some(n) = value.try_normalize_mut(min_norm) { - Some((Unit { value: value }, n)) + pub fn try_new_and_get(mut value: T, min_norm: T::Norm) -> Option<(Self, T::Norm)> + where + T::Norm: RealField, + { + let sq_norm = value.norm_squared(); + + if sq_norm > min_norm * min_norm { + let n = sq_norm.simd_sqrt(); + value.unscale_mut(n); + Some((Unit { value }, n)) } else { None } } - /// Normalizes this value again. This is useful when repeated computations + /// Normalizes this vector again. This is useful when repeated computations /// might cause a drift in the norm because of float inaccuracies. /// /// Returns the norm before re-normalization. See `.renormalize_fast` for a faster alternative /// that may be slightly less accurate if `self` drifted significantly from having a unit length. #[inline] - pub fn renormalize(&mut self) -> T::RealField { - self.value.normalize_mut() + pub fn renormalize(&mut self) -> T::Norm { + let n = self.norm(); + self.value.unscale_mut(n); + n } - /// Normalizes this value again using a first-order Taylor approximation. + /// Normalizes this vector again using a first-order Taylor approximation. /// This is useful when repeated computations might cause a drift in the norm /// because of float inaccuracies. #[inline] pub fn renormalize_fast(&mut self) { let sq_norm = self.value.norm_squared(); - let _3: T::RealField = crate::convert(3.0); - let _0_5: T::RealField = crate::convert(0.5); - self.value *= T::ComplexField::from_real(_0_5 * (_3 - sq_norm)); + let _3: T::Norm = crate::convert(3.0); + let _0_5: T::Norm = crate::convert(0.5); + self.value.scale_mut(_0_5 * (_3 - sq_norm)); } } @@ -114,7 +144,7 @@ impl Unit { /// Wraps the given value, assuming it is already normalized. #[inline] pub fn new_unchecked(value: T) -> Self { - Unit { value: value } + Unit { value } } /// Wraps the given reference, assuming it is already normalized. @@ -131,7 +161,7 @@ impl Unit { /// Retrieves the underlying value. /// Deprecated: use [Unit::into_inner] instead. - #[deprecated(note="use `.into_inner()` instead")] + #[deprecated(note = "use `.into_inner()` instead")] #[inline] pub fn unwrap(self) -> T { self.value @@ -153,13 +183,14 @@ impl AsRef for Unit { } } +/* /* * * Conversions. * */ impl SubsetOf for Unit -where T::Field: RelativeEq +where T::RealField: RelativeEq { #[inline] fn to_superset(&self) -> T { @@ -172,7 +203,7 @@ where T::Field: RelativeEq } #[inline] - unsafe fn from_superset_unchecked(value: &T) -> Self { + fn from_superset_unchecked(value: &T) -> Self { Unit::new_normalize(value.clone()) // We still need to re-normalize because the condition is inexact. } } @@ -205,7 +236,7 @@ where T::Field: RelativeEq // self.value.ulps_eq(&other.value, epsilon, max_ulps) // } // } - +*/ // FIXME:re-enable this impl when specialization is possible. // Currently, it is disabled so that we can have a nice output for the `UnitQuaternion` display. /* @@ -217,15 +248,6 @@ impl fmt::Display for Unit { } */ -impl Neg for Unit { - type Output = Unit; - - #[inline] - fn neg(self) -> Self::Output { - Self::Output::new_unchecked(-self.value) - } -} - impl Deref for Unit { type Target = T; @@ -234,3 +256,92 @@ impl Deref for Unit { unsafe { mem::transmute(self) } } } + +// NOTE: we can't use a generic implementation for `Unit` because +// num_complex::Complex does not implement `From[Complex<...>...]` (and can't +// because of the orphan rules). +impl + From<[Unit>; 2]> for Unit> +where + N: From<[::Element; 2]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Unit>; 2]) -> Self { + Self::new_unchecked(MatrixMN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + ])) + } +} + +impl + From<[Unit>; 4]> for Unit> +where + N: From<[::Element; 4]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Unit>; 4]) -> Self { + Self::new_unchecked(MatrixMN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + ])) + } +} + +impl + From<[Unit>; 8]> for Unit> +where + N: From<[::Element; 8]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Unit>; 8]) -> Self { + Self::new_unchecked(MatrixMN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + arr[4].clone().into_inner(), + arr[5].clone().into_inner(), + arr[6].clone().into_inner(), + arr[7].clone().into_inner(), + ])) + } +} + +impl + From<[Unit>; 16]> for Unit> +where + N: From<[::Element; 16]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Unit>; 16]) -> Self { + Self::new_unchecked(MatrixMN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + arr[4].clone().into_inner(), + arr[5].clone().into_inner(), + arr[6].clone().into_inner(), + arr[7].clone().into_inner(), + arr[8].clone().into_inner(), + arr[9].clone().into_inner(), + arr[10].clone().into_inner(), + arr[11].clone().into_inner(), + arr[12].clone().into_inner(), + arr[13].clone().into_inner(), + arr[14].clone().into_inner(), + arr[15].clone().into_inner(), + ])) + } +} diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index bbf5595f..26948693 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -5,11 +5,11 @@ use std::io::{Result as IOResult, Write}; use alloc::vec::Vec; use crate::base::allocator::Allocator; +use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::base::default_allocator::DefaultAllocator; use crate::base::dimension::{Dim, DimName, Dynamic, U1}; use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut}; use crate::base::{Scalar, Vector}; -use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -29,7 +29,7 @@ pub struct VecStorage { ncols: C, } -#[deprecated(note="renamed to `VecStorage`")] +#[deprecated(note = "renamed to `VecStorage`")] /// Renamed to [VecStorage]. pub type MatrixVec = VecStorage; @@ -89,8 +89,7 @@ impl VecStorage { } } -impl Into> for VecStorage -{ +impl Into> for VecStorage { fn into(self) -> Vec { self.data } @@ -103,7 +102,8 @@ impl Into> for VecStorage * */ unsafe impl Storage for VecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type RStride = U1; type CStride = Dynamic; @@ -130,13 +130,17 @@ where DefaultAllocator: Allocator #[inline] fn into_owned(self) -> Owned - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self } #[inline] fn clone_owned(&self) -> Owned - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.clone() } @@ -147,7 +151,8 @@ where DefaultAllocator: Allocator } unsafe impl Storage for VecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type RStride = U1; type CStride = R; @@ -174,13 +179,17 @@ where DefaultAllocator: Allocator #[inline] fn into_owned(self) -> Owned - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self } #[inline] fn clone_owned(&self) -> Owned - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { self.clone() } @@ -196,7 +205,8 @@ where DefaultAllocator: Allocator * */ unsafe impl StorageMut for VecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn ptr_mut(&mut self) -> *mut N { @@ -209,14 +219,19 @@ where DefaultAllocator: Allocator } } -unsafe impl ContiguousStorage for VecStorage where DefaultAllocator: Allocator -{} +unsafe impl ContiguousStorage for VecStorage where + DefaultAllocator: Allocator +{ +} -unsafe impl ContiguousStorageMut for VecStorage where DefaultAllocator: Allocator -{} +unsafe impl ContiguousStorageMut for VecStorage where + DefaultAllocator: Allocator +{ +} unsafe impl StorageMut for VecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn ptr_mut(&mut self) -> *mut N { @@ -244,14 +259,17 @@ impl Abomonation for VecStorage { } } -unsafe impl ContiguousStorage for VecStorage where DefaultAllocator: Allocator -{} - -unsafe impl ContiguousStorageMut for VecStorage where DefaultAllocator: Allocator -{} - -impl Extend for VecStorage +unsafe impl ContiguousStorage for VecStorage where + DefaultAllocator: Allocator { +} + +unsafe impl ContiguousStorageMut for VecStorage where + DefaultAllocator: Allocator +{ +} + +impl Extend for VecStorage { /// Extends the number of columns of the `VecStorage` with elements /// from the given iterator. /// @@ -259,8 +277,7 @@ impl Extend for VecStorage /// This function panics if the number of elements yielded by the /// given iterator is not a multiple of the number of rows of the /// `VecStorage`. - fn extend>(&mut self, iter: I) - { + fn extend>(&mut self, iter: I) { self.data.extend(iter); self.ncols = Dynamic::new(self.data.len() / self.nrows.value()); assert!(self.data.len() % self.nrows.value() == 0, @@ -268,8 +285,7 @@ impl Extend for VecStorage } } -impl<'a, N: 'a + Copy, R: Dim> Extend<&'a N> for VecStorage -{ +impl<'a, N: 'a + Copy, R: Dim> Extend<&'a N> for VecStorage { /// Extends the number of columns of the `VecStorage` with elements /// from the given iterator. /// @@ -277,8 +293,7 @@ impl<'a, N: 'a + Copy, R: Dim> Extend<&'a N> for VecStorage /// This function panics if the number of elements yielded by the /// given iterator is not a multiple of the number of rows of the /// `VecStorage`. - fn extend>(&mut self, iter: I) - { + fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().copied()) } } @@ -298,8 +313,7 @@ where /// This function panics if the number of rows of each `Vector` /// yielded by the iterator is not equal to the number of rows /// of this `VecStorage`. - fn extend>>(&mut self, iter: I) - { + fn extend>>(&mut self, iter: I) { let nrows = self.nrows.value(); let iter = iter.into_iter(); let (lower, _upper) = iter.size_hint(); @@ -312,12 +326,10 @@ where } } -impl Extend for VecStorage -{ +impl Extend for VecStorage { /// Extends the number of rows of the `VecStorage` with elements /// from the given iterator. - fn extend>(&mut self, iter: I) - { + fn extend>(&mut self, iter: I) { self.data.extend(iter); self.nrows = Dynamic::new(self.data.len()); } diff --git a/src/debug/random_orthogonal.rs b/src/debug/random_orthogonal.rs index 421b041a..de72bdb7 100644 --- a/src/debug/random_orthogonal.rs +++ b/src/debug/random_orthogonal.rs @@ -3,23 +3,25 @@ use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; -use alga::general::ComplexField; -use crate::base::Scalar; use crate::base::allocator::Allocator; use crate::base::dimension::{Dim, Dynamic, U2}; +use crate::base::Scalar; use crate::base::{DefaultAllocator, MatrixN}; use crate::linalg::givens::GivensRotation; +use simba::scalar::ComplexField; /// A random orthogonal matrix. #[derive(Clone, Debug)] pub struct RandomOrthogonal -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { m: MatrixN, } impl RandomOrthogonal -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Retrieve the generated matrix. pub fn unwrap(self) -> MatrixN { diff --git a/src/debug/random_sdp.rs b/src/debug/random_sdp.rs index 47e3ca60..b9f81859 100644 --- a/src/debug/random_sdp.rs +++ b/src/debug/random_sdp.rs @@ -3,24 +3,26 @@ use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; -use alga::general::ComplexField; -use crate::base::Scalar; use crate::base::allocator::Allocator; use crate::base::dimension::{Dim, Dynamic}; +use crate::base::Scalar; use crate::base::{DefaultAllocator, MatrixN}; +use simba::scalar::ComplexField; use crate::debug::RandomOrthogonal; /// A random, well-conditioned, symmetric definite-positive matrix. #[derive(Clone, Debug)] pub struct RandomSDP -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { m: MatrixN, } impl RandomSDP -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Retrieve the generated matrix. pub fn unwrap(self) -> MatrixN { diff --git a/src/geometry/abstract_rotation.rs b/src/geometry/abstract_rotation.rs new file mode 100644 index 00000000..ff057a09 --- /dev/null +++ b/src/geometry/abstract_rotation.rs @@ -0,0 +1,164 @@ +use crate::allocator::Allocator; +use crate::geometry::{Rotation, UnitComplex, UnitQuaternion}; +use crate::{DefaultAllocator, DimName, Point, Scalar, SimdRealField, VectorN, U2, U3}; + +use simba::scalar::ClosedMul; + +/// Trait implemented by rotations that can be used inside of an `Isometry` or `Similarity`. +pub trait AbstractRotation: PartialEq + ClosedMul + Clone { + /// The rotation identity. + fn identity() -> Self; + /// The rotation inverse. + fn inverse(&self) -> Self; + /// Change `self` to its inverse. + fn inverse_mut(&mut self); + /// Apply the rotation to the given vector. + fn transform_vector(&self, v: &VectorN) -> VectorN + where + DefaultAllocator: Allocator; + /// Apply the rotation to the given point. + fn transform_point(&self, p: &Point) -> Point + where + DefaultAllocator: Allocator; + /// Apply the inverse rotation to the given vector. + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN + where + DefaultAllocator: Allocator; + /// Apply the inverse rotation to the given point. + fn inverse_transform_point(&self, p: &Point) -> Point + where + DefaultAllocator: Allocator; +} + +impl AbstractRotation for Rotation +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } + + #[inline] + fn inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn inverse_mut(&mut self) { + self.inverse_mut() + } + + #[inline] + fn transform_vector(&self, v: &VectorN) -> VectorN + where + DefaultAllocator: Allocator, + { + self * v + } + + #[inline] + fn transform_point(&self, p: &Point) -> Point + where + DefaultAllocator: Allocator, + { + self * p + } + + #[inline] + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN + where + DefaultAllocator: Allocator, + { + self.inverse_transform_vector(v) + } + + #[inline] + fn inverse_transform_point(&self, p: &Point) -> Point + where + DefaultAllocator: Allocator, + { + self.inverse_transform_point(p) + } +} + +impl AbstractRotation for UnitQuaternion +where + N::Element: SimdRealField, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } + + #[inline] + fn inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn inverse_mut(&mut self) { + self.inverse_mut() + } + + #[inline] + fn transform_vector(&self, v: &VectorN) -> VectorN { + self * v + } + + #[inline] + fn transform_point(&self, p: &Point) -> Point { + self * p + } + + #[inline] + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { + self.inverse_transform_vector(v) + } + + #[inline] + fn inverse_transform_point(&self, p: &Point) -> Point { + self.inverse_transform_point(p) + } +} + +impl AbstractRotation for UnitComplex +where + N::Element: SimdRealField, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } + + #[inline] + fn inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn inverse_mut(&mut self) { + self.inverse_mut() + } + + #[inline] + fn transform_vector(&self, v: &VectorN) -> VectorN { + self * v + } + + #[inline] + fn transform_point(&self, p: &Point) -> Point { + self * p + } + + #[inline] + fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { + self.inverse_transform_vector(v) + } + + #[inline] + fn inverse_transform_point(&self, p: &Point) -> Point { + self.inverse_transform_point(p) + } +} diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index b68a7777..2e4b7cd5 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -3,7 +3,6 @@ use std::fmt; use std::hash; #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; -use std::marker::PhantomData; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; @@ -11,14 +10,14 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{RealField, SubsetOf}; -use alga::linear::Rotation; +use simba::scalar::{RealField, SubsetOf}; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::storage::Owned; -use crate::base::{DefaultAllocator, MatrixN, VectorN}; -use crate::geometry::{Point, Translation}; +use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use crate::geometry::{AbstractRotation, Point, Translation}; /// A direct isometry, i.e., a rotation followed by a translation, aka. a rigid-body motion, aka. an element of a Special Euclidean (SE) group. #[repr(C)] @@ -36,26 +35,20 @@ use crate::geometry::{Point, Translation}; DefaultAllocator: Allocator, Owned: Deserialize<'de>")) )] -pub struct Isometry -where DefaultAllocator: Allocator +pub struct Isometry +where + DefaultAllocator: Allocator, { /// The pure rotational part of this isometry. pub rotation: R, /// The pure translational part of this isometry. pub translation: Translation, - - // One dummy private field just to prevent explicit construction. - #[cfg_attr( - feature = "serde-serialize", - serde(skip_serializing, skip_deserializing) - )] - _noconstruct: PhantomData, } #[cfg(feature = "abomonation-serialize")] impl Abomonation for Isometry where - N: RealField, + N: SimdRealField, D: DimName, R: Abomonation, Translation: Abomonation, @@ -77,7 +70,8 @@ where } } -impl hash::Hash for Isometry +impl hash::Hash + for Isometry where DefaultAllocator: Allocator, Owned: hash::Hash, @@ -88,15 +82,17 @@ where } } -impl> + Copy> Copy for Isometry +impl + Copy> Copy + for Isometry where DefaultAllocator: Allocator, Owned: Copy, { } -impl> + Clone> Clone for Isometry -where DefaultAllocator: Allocator +impl + Clone> Clone for Isometry +where + DefaultAllocator: Allocator, { #[inline] fn clone(&self) -> Self { @@ -104,8 +100,9 @@ where DefaultAllocator: Allocator } } -impl>> Isometry -where DefaultAllocator: Allocator +impl> Isometry +where + DefaultAllocator: Allocator, { /// Creates a new isometry from its rotational and translational parts. /// @@ -124,12 +121,17 @@ where DefaultAllocator: Allocator #[inline] pub fn from_parts(translation: Translation, rotation: R) -> Self { Self { - rotation: rotation, - translation: translation, - _noconstruct: PhantomData, + rotation, + translation, } } +} +impl> Isometry +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, +{ /// Inverts `self`. /// /// # Example @@ -167,7 +169,7 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn inverse_mut(&mut self) { - self.rotation.two_sided_inverse_mut(); + self.rotation.inverse_mut(); self.translation.inverse_mut(); self.translation.vector = self.rotation.transform_vector(&self.translation.vector); } @@ -208,7 +210,7 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn append_rotation_mut(&mut self, r: &R) { - self.rotation = self.rotation.append_rotation(&r); + self.rotation = r.clone() * self.rotation.clone(); self.translation.vector = r.transform_vector(&self.translation.vector); } @@ -253,7 +255,7 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { - self.rotation = self.rotation.append_rotation(r); + self.rotation = r.clone() * self.rotation.clone(); } /// Transform the given point by this isometry. @@ -352,8 +354,9 @@ where DefaultAllocator: Allocator // and makes it hard to use it, e.g., for Transform × Isometry implementation. // This is OK since all constructors of the isometry enforce the Rotation bound already (and // explicit struct construction is prevented by the dummy ZST field). -impl Isometry -where DefaultAllocator: Allocator +impl Isometry +where + DefaultAllocator: Allocator, { /// Converts this isometry into its equivalent homogeneous transformation matrix. /// @@ -385,16 +388,16 @@ where DefaultAllocator: Allocator } } -impl Eq for Isometry +impl Eq for Isometry where - R: Rotation> + Eq, + R: AbstractRotation + Eq, DefaultAllocator: Allocator, { } -impl PartialEq for Isometry +impl PartialEq for Isometry where - R: Rotation> + PartialEq, + R: AbstractRotation + PartialEq, DefaultAllocator: Allocator, { #[inline] @@ -405,7 +408,7 @@ where impl AbsDiffEq for Isometry where - R: Rotation> + AbsDiffEq, + R: AbstractRotation + AbsDiffEq, DefaultAllocator: Allocator, N::Epsilon: Copy, { @@ -425,7 +428,7 @@ where impl RelativeEq for Isometry where - R: Rotation> + RelativeEq, + R: AbstractRotation + RelativeEq, DefaultAllocator: Allocator, N::Epsilon: Copy, { @@ -440,8 +443,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.translation .relative_eq(&other.translation, epsilon, max_relative) && self @@ -452,7 +454,7 @@ where impl UlpsEq for Isometry where - R: Rotation> + UlpsEq, + R: AbstractRotation + UlpsEq, DefaultAllocator: Allocator, N::Epsilon: Copy, { diff --git a/src/geometry/isometry_alga.rs b/src/geometry/isometry_alga.rs index 08916775..3cb965a8 100755 --- a/src/geometry/isometry_alga.rs +++ b/src/geometry/isometry_alga.rs @@ -1,6 +1,6 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::Isometry as AlgaIsometry; use alga::linear::{ @@ -12,16 +12,17 @@ use crate::base::allocator::Allocator; use crate::base::dimension::DimName; use crate::base::{DefaultAllocator, VectorN}; -use crate::geometry::{Isometry, Point, Translation}; +use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; /* * * Algebraic structures. * */ -impl Identity for Isometry +impl Identity + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -30,9 +31,10 @@ where } } -impl TwoSidedInverse for Isometry +impl TwoSidedInverse + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -47,9 +49,10 @@ where } } -impl AbstractMagma for Isometry +impl AbstractMagma + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -60,8 +63,8 @@ where macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for Isometry - where R: Rotation>, + impl $marker<$operator> for Isometry + where R: Rotation> + AbstractRotation, DefaultAllocator: Allocator { } )*} ); @@ -79,9 +82,10 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Isometry +impl Transformation> + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -95,9 +99,10 @@ where } } -impl ProjectiveTransformation> for Isometry +impl ProjectiveTransformation> + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -111,9 +116,10 @@ where } } -impl AffineTransformation> for Isometry +impl AffineTransformation> + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { type Rotation = R; @@ -126,7 +132,7 @@ where self.translation.clone(), self.rotation.clone(), Id::new(), - R::identity(), + >::identity(), ) } @@ -142,13 +148,13 @@ where #[inline] fn append_rotation(&self, r: &Self::Rotation) -> Self { - let shift = r.transform_vector(&self.translation.vector); + let shift = Transformation::transform_vector(r, &self.translation.vector); Isometry::from_parts(Translation::from(shift), r.clone() * self.rotation.clone()) } #[inline] fn prepend_rotation(&self, r: &Self::Rotation) -> Self { - self * r + Isometry::from_parts(self.translation.clone(), self.rotation.prepend_rotation(r)) } #[inline] @@ -169,9 +175,10 @@ where } } -impl Similarity> for Isometry +impl Similarity> + for Isometry where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { type Scaling = Id; @@ -194,8 +201,8 @@ where macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for Isometry - where R: Rotation>, + impl $Trait> for Isometry + where R: Rotation> + AbstractRotation, DefaultAllocator: Allocator { } )*} ); diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index 979c3955..a9f9c978 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -7,20 +7,22 @@ use num::One; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use alga::general::RealField; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::RealField; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, U2, U3}; use crate::base::{DefaultAllocator, Vector2, Vector3}; use crate::geometry::{ - Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex, - UnitQuaternion, Translation2, Translation3 + AbstractRotation, Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, + Translation2, Translation3, UnitComplex, UnitQuaternion, }; -impl>> Isometry -where DefaultAllocator: Allocator +impl> Isometry +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { /// Creates a new identity isometry. /// @@ -65,8 +67,10 @@ where DefaultAllocator: Allocator } } -impl>> One for Isometry -where DefaultAllocator: Allocator +impl> One for Isometry +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { /// Creates a new identity isometry. #[inline] @@ -77,7 +81,7 @@ where DefaultAllocator: Allocator impl Distribution> for Standard where - R: AlgaRotation>, + R: AbstractRotation, Standard: Distribution + Distribution, DefaultAllocator: Allocator, { @@ -90,8 +94,9 @@ where #[cfg(feature = "arbitrary")] impl Arbitrary for Isometry where - N: RealField + Arbitrary + Send, - R: AlgaRotation> + Arbitrary + Send, + N: SimdRealField + Arbitrary + Send, + N::Element: SimdRealField, + R: AbstractRotation + Arbitrary + Send, Owned: Send, DefaultAllocator: Allocator, { @@ -108,7 +113,10 @@ where */ // 2D rotation. -impl Isometry> { +impl Isometry> +where + N::Element: SimdRealField, +{ /// Creates a new 2D isometry from a translation and a rotation angle. /// /// Its rotational part is represented as a 2x2 rotation matrix. @@ -143,7 +151,10 @@ impl Isometry> { } } -impl Isometry> { +impl Isometry> +where + N::Element: SimdRealField, +{ /// Creates a new 2D isometry from a translation and a rotation angle. /// /// Its rotational part is represented as an unit complex number. @@ -181,7 +192,8 @@ impl Isometry> { // 3D rotation. macro_rules! isometry_construction_impl( ($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => { - impl Isometry> { + impl Isometry> + where N::Element: SimdRealField { /// Creates a new isometry from a translation and a rotation axis-angle. /// /// # Example diff --git a/src/geometry/isometry_conversion.rs b/src/geometry/isometry_conversion.rs index 4a794f55..7cb6fe85 100644 --- a/src/geometry/isometry_conversion.rs +++ b/src/geometry/isometry_conversion.rs @@ -1,11 +1,13 @@ -use alga::general::{RealField, SubsetOf, SupersetOf}; -use alga::linear::Rotation; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; -use crate::base::{DefaultAllocator, MatrixN}; +use crate::base::{DefaultAllocator, MatrixN, Scalar}; -use crate::geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; +use crate::geometry::{ + AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, +}; /* * This file provides the following conversions: @@ -21,8 +23,8 @@ impl SubsetOf> for Isometry, - R1: Rotation> + SubsetOf, - R2: Rotation>, + R1: AbstractRotation + SubsetOf, + R2: AbstractRotation, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -37,7 +39,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { + fn from_superset_unchecked(iso: &Isometry) -> Self { Isometry::from_parts( iso.translation.to_subset_unchecked(), iso.rotation.to_subset_unchecked(), @@ -49,8 +51,8 @@ impl SubsetOf> for Isometry, - R1: Rotation> + SubsetOf, - R2: Rotation>, + R1: AbstractRotation + SubsetOf, + R2: AbstractRotation, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -64,7 +66,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + fn from_superset_unchecked(sim: &Similarity) -> Self { crate::convert_ref_unchecked(&sim.isometry) } } @@ -74,7 +76,7 @@ where N1: RealField, N2: RealField + SupersetOf, C: SuperTCategoryOf, - R: Rotation> + R: AbstractRotation + SubsetOf>> + SubsetOf>>, D: DimNameAdd + DimMin, // needed by .is_special_orthogonal() @@ -98,7 +100,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -107,7 +109,7 @@ impl SubsetOf>> for Isometry, - R: Rotation> + R: AbstractRotation + SubsetOf>> + SubsetOf>>, D: DimNameAdd + DimMin, // needed by .is_special_orthogonal() @@ -139,7 +141,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { + fn from_superset_unchecked(m: &MatrixN>) -> Self { let t = m.fixed_slice::(0, D::dim()).into_owned(); let t = Translation { vector: crate::convert_unchecked(t), @@ -149,7 +151,7 @@ where } } -impl From> for MatrixN> +impl From> for MatrixN> where D: DimNameAdd, R: SubsetOf>>, @@ -160,3 +162,141 @@ where iso.to_homogeneous() } } + +impl From<[Isometry; 2]> + for Isometry +where + N: From<[::Element; 2]>, + R: SimdValue + AbstractRotation + From<[::Element; 2]>, + R::Element: AbstractRotation, + N::Element: Scalar + Copy, + R::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Isometry; 2]) -> Self { + let tra = Translation::from([arr[0].translation.clone(), arr[1].translation.clone()]); + let rot = R::from([arr[0].rotation.clone(), arr[0].rotation.clone()]); + + Self::from_parts(tra, rot) + } +} + +impl From<[Isometry; 4]> + for Isometry +where + N: From<[::Element; 4]>, + R: SimdValue + AbstractRotation + From<[::Element; 4]>, + R::Element: AbstractRotation, + N::Element: Scalar + Copy, + R::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Isometry; 4]) -> Self { + let tra = Translation::from([ + arr[0].translation.clone(), + arr[1].translation.clone(), + arr[2].translation.clone(), + arr[3].translation.clone(), + ]); + let rot = R::from([ + arr[0].rotation.clone(), + arr[1].rotation.clone(), + arr[2].rotation.clone(), + arr[3].rotation.clone(), + ]); + + Self::from_parts(tra, rot) + } +} + +impl From<[Isometry; 8]> + for Isometry +where + N: From<[::Element; 8]>, + R: SimdValue + AbstractRotation + From<[::Element; 8]>, + R::Element: AbstractRotation, + N::Element: Scalar + Copy, + R::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Isometry; 8]) -> Self { + let tra = Translation::from([ + arr[0].translation.clone(), + arr[1].translation.clone(), + arr[2].translation.clone(), + arr[3].translation.clone(), + arr[4].translation.clone(), + arr[5].translation.clone(), + arr[6].translation.clone(), + arr[7].translation.clone(), + ]); + let rot = R::from([ + arr[0].rotation.clone(), + arr[1].rotation.clone(), + arr[2].rotation.clone(), + arr[3].rotation.clone(), + arr[4].rotation.clone(), + arr[5].rotation.clone(), + arr[6].rotation.clone(), + arr[7].rotation.clone(), + ]); + + Self::from_parts(tra, rot) + } +} + +impl From<[Isometry; 16]> + for Isometry +where + N: From<[::Element; 16]>, + R: SimdValue + AbstractRotation + From<[::Element; 16]>, + R::Element: AbstractRotation, + N::Element: Scalar + Copy, + R::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Isometry; 16]) -> Self { + let tra = Translation::from([ + arr[0].translation.clone(), + arr[1].translation.clone(), + arr[2].translation.clone(), + arr[3].translation.clone(), + arr[4].translation.clone(), + arr[5].translation.clone(), + arr[6].translation.clone(), + arr[7].translation.clone(), + arr[8].translation.clone(), + arr[9].translation.clone(), + arr[10].translation.clone(), + arr[11].translation.clone(), + arr[12].translation.clone(), + arr[13].translation.clone(), + arr[14].translation.clone(), + arr[15].translation.clone(), + ]); + let rot = R::from([ + arr[0].rotation.clone(), + arr[1].rotation.clone(), + arr[2].rotation.clone(), + arr[3].rotation.clone(), + arr[4].rotation.clone(), + arr[5].rotation.clone(), + arr[6].rotation.clone(), + arr[7].rotation.clone(), + arr[8].rotation.clone(), + arr[9].rotation.clone(), + arr[10].rotation.clone(), + arr[11].rotation.clone(), + arr[12].rotation.clone(), + arr[13].rotation.clone(), + arr[14].rotation.clone(), + arr[15].rotation.clone(), + ]); + + Self::from_parts(tra, rot) + } +} diff --git a/src/geometry/isometry_ops.rs b/src/geometry/isometry_ops.rs index 6ba9eb3e..8b00fcda 100644 --- a/src/geometry/isometry_ops.rs +++ b/src/geometry/isometry_ops.rs @@ -1,13 +1,17 @@ +use num::{One, Zero}; use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::RealField; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::{ClosedAdd, ClosedMul}; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; -use crate::base::dimension::{DimName, U1, U3, U4}; +use crate::base::dimension::{DimName, U1, U2, U3, U4}; use crate::base::{DefaultAllocator, Unit, VectorN}; +use crate::Scalar; -use crate::geometry::{Isometry, Point, Rotation, Translation, UnitQuaternion}; +use crate::geometry::{ + AbstractRotation, Isometry, Point, Rotation, Translation, UnitComplex, UnitQuaternion, +}; // FIXME: there are several cloning of rotations that we could probably get rid of (but we didn't // yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` @@ -64,8 +68,9 @@ macro_rules! isometry_binop_impl( ($Op: ident, $op: ident; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField, D: DimName, R> $Op<$Rhs> for $Lhs - where R: AlgaRotation>, + impl<$($lives ,)* N: SimdRealField, D: DimName, R> $Op<$Rhs> for $Lhs + where N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator { type Output = $Output; @@ -111,8 +116,9 @@ macro_rules! isometry_binop_assign_impl_all( $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; [val] => $action_val: expr; [ref] => $action_ref: expr;) => { - impl $OpAssign<$Rhs> for $Lhs - where R: AlgaRotation>, + impl $OpAssign<$Rhs> for $Lhs + where N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: $Rhs) { @@ -120,8 +126,9 @@ macro_rules! isometry_binop_assign_impl_all( } } - impl<'b, N: RealField, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs - where R: AlgaRotation>, + impl<'b, N: SimdRealField, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs + where N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { @@ -189,39 +196,55 @@ isometry_binop_assign_impl_all!( // Isometry ×= R // Isometry ÷= R -isometry_binop_assign_impl_all!( - MulAssign, mul_assign; - self: Isometry, rhs: R; +md_assign_impl_all!( + MulAssign, mul_assign where N: SimdRealField for N::Element: SimdRealField; + (D, U1), (D, D) for D: DimName; + self: Isometry>, rhs: Rotation; [val] => self.rotation *= rhs; [ref] => self.rotation *= rhs.clone(); ); -isometry_binop_assign_impl_all!( - DivAssign, div_assign; - self: Isometry, rhs: R; +md_assign_impl_all!( + DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; + (D, U1), (D, D) for D: DimName; + self: Isometry>, rhs: Rotation; // FIXME: don't invert explicitly? - [val] => *self *= rhs.two_sided_inverse(); - [ref] => *self *= rhs.two_sided_inverse(); + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); ); -// Isometry × R -// Isometry ÷ R -isometry_binop_impl_all!( - Mul, mul; - self: Isometry, rhs: R, Output = Isometry; - [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. - [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); - [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +md_assign_impl_all!( + MulAssign, mul_assign where N: SimdRealField for N::Element: SimdRealField; + (U3, U3), (U3, U3) for; + self: Isometry>, rhs: UnitQuaternion; + [val] => self.rotation *= rhs; + [ref] => self.rotation *= rhs.clone(); ); -isometry_binop_impl_all!( - Div, div; - self: Isometry, rhs: R, Output = Isometry; - [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); - [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); - [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); - [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +md_assign_impl_all!( + DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; + (U3, U3), (U3, U3) for; + self: Isometry>, rhs: UnitQuaternion; + // FIXME: don't invert explicitly? + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); +); + +md_assign_impl_all!( + MulAssign, mul_assign where N: SimdRealField for N::Element: SimdRealField; + (U2, U2), (U2, U2) for; + self: Isometry>, rhs: UnitComplex; + [val] => self.rotation *= rhs; + [ref] => self.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; + (U2, U2), (U2, U2) for; + self: Isometry>, rhs: UnitComplex; + // FIXME: don't invert explicitly? + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); ); // Isometry × Point @@ -286,8 +309,9 @@ macro_rules! isometry_from_composition_impl( ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(for $Dims: ident: $DimsBound: ident),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs - where DefaultAllocator: Allocator + + impl<$($lives ,)* N: SimdRealField $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + where N::Element: SimdRealField, + DefaultAllocator: Allocator + Allocator { type Output = $Output; @@ -357,6 +381,18 @@ isometry_from_composition_impl_all!( [ref ref] => Isometry::from_parts(Translation::from( self * &right.vector), self.clone()); ); +// Isometry × Rotation +isometry_from_composition_impl_all!( + Mul, mul; + (D, D), (D, U1) for D: DimName; + self: Isometry>, rhs: Rotation, + Output = Isometry>; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +); + // Rotation × Isometry isometry_from_composition_impl_all!( Mul, mul; @@ -372,6 +408,18 @@ isometry_from_composition_impl_all!( }; ); +// Isometry ÷ Rotation +isometry_from_composition_impl_all!( + Div, div; + (D, D), (D, U1) for D: DimName; + self: Isometry>, rhs: Rotation, + Output = Isometry>; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +); + // Rotation ÷ Isometry isometry_from_composition_impl_all!( Div, div; @@ -385,6 +433,18 @@ isometry_from_composition_impl_all!( [ref ref] => self * right.inverse(); ); +// Isometry × UnitQuaternion +isometry_from_composition_impl_all!( + Mul, mul; + (U4, U1), (U3, U1); + self: Isometry>, rhs: UnitQuaternion, + Output = Isometry>; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +); + // UnitQuaternion × Isometry isometry_from_composition_impl_all!( Mul, mul; @@ -400,6 +460,18 @@ isometry_from_composition_impl_all!( }; ); +// Isometry ÷ UnitQuaternion +isometry_from_composition_impl_all!( + Div, div; + (U4, U1), (U3, U1); + self: Isometry>, rhs: UnitQuaternion, + Output = Isometry>; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +); + // UnitQuaternion ÷ Isometry isometry_from_composition_impl_all!( Div, div; @@ -434,3 +506,27 @@ isometry_from_composition_impl_all!( [val ref] => Isometry::from_parts(self, right.clone()); [ref ref] => Isometry::from_parts(self.clone(), right.clone()); ); + +// Isometry × UnitComplex +isometry_from_composition_impl_all!( + Mul, mul; + (U2, U1), (U2, U1); + self: Isometry>, rhs: UnitComplex, + Output = Isometry>; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +); + +// Isometry ÷ UnitComplex +isometry_from_composition_impl_all!( + Div, div; + (U2, U1), (U2, U1); + self: Isometry>, rhs: UnitComplex, + Output = Isometry>; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); // FIXME: do not clone. + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +); diff --git a/src/geometry/isometry_simba.rs b/src/geometry/isometry_simba.rs new file mode 100755 index 00000000..e5d2c839 --- /dev/null +++ b/src/geometry/isometry_simba.rs @@ -0,0 +1,62 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::DefaultAllocator; +use crate::SimdRealField; + +use crate::geometry::{AbstractRotation, Isometry, Translation}; + +impl SimdValue for Isometry +where + N::Element: SimdRealField, + R: SimdValue + AbstractRotation, + R::Element: AbstractRotation, + DefaultAllocator: Allocator + Allocator, +{ + type Element = Isometry; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + Isometry::from_parts(Translation::splat(val.translation), R::splat(val.rotation)) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Isometry::from_parts(self.translation.extract(i), self.rotation.extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Isometry::from_parts( + self.translation.extract_unchecked(i), + self.rotation.extract_unchecked(i), + ) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.translation.replace(i, val.translation); + self.rotation.replace(i, val.rotation); + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.translation.replace_unchecked(i, val.translation); + self.rotation.replace_unchecked(i, val.rotation); + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Isometry::from_parts( + self.translation.select(cond, other.translation), + self.rotation.select(cond, other.rotation), + ) + } +} diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 9e25dc29..6f991f72 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -3,71 +3,91 @@ mod op_macros; +mod abstract_rotation; + mod point; +#[cfg(feature = "alga")] mod point_alga; mod point_alias; mod point_construction; mod point_conversion; mod point_coordinates; mod point_ops; +mod point_simba; mod rotation; -mod rotation_alga; // FIXME: implement Rotation methods. +#[cfg(feature = "alga")] +mod rotation_alga; mod rotation_alias; mod rotation_construction; mod rotation_conversion; mod rotation_ops; +mod rotation_simba; // FIXME: implement Rotation methods. mod rotation_specialization; mod quaternion; +#[cfg(feature = "alga")] mod quaternion_alga; mod quaternion_construction; mod quaternion_conversion; mod quaternion_coordinates; mod quaternion_ops; +mod quaternion_simba; mod unit_complex; +#[cfg(feature = "alga")] mod unit_complex_alga; mod unit_complex_construction; mod unit_complex_conversion; mod unit_complex_ops; +mod unit_complex_simba; mod translation; +#[cfg(feature = "alga")] mod translation_alga; mod translation_alias; mod translation_construction; mod translation_conversion; mod translation_coordinates; mod translation_ops; +mod translation_simba; mod isometry; +#[cfg(feature = "alga")] mod isometry_alga; mod isometry_alias; mod isometry_construction; mod isometry_conversion; mod isometry_ops; +mod isometry_simba; mod similarity; +#[cfg(feature = "alga")] mod similarity_alga; mod similarity_alias; mod similarity_construction; mod similarity_conversion; mod similarity_ops; +mod similarity_simba; mod swizzle; mod transform; +#[cfg(feature = "alga")] mod transform_alga; mod transform_alias; mod transform_construction; mod transform_conversion; mod transform_ops; +mod transform_simba; mod reflection; mod orthographic; mod perspective; +pub use self::abstract_rotation::AbstractRotation; + pub use self::point::*; pub use self::point_alias::*; diff --git a/src/geometry/op_macros.rs b/src/geometry/op_macros.rs index 382afe06..19d348f4 100644 --- a/src/geometry/op_macros.rs +++ b/src/geometry/op_macros.rs @@ -1,6 +1,5 @@ #![macro_use] - // FIXME: merge with `md_impl`. /// Macro for the implementation of multiplication and division. macro_rules! md_impl( @@ -86,9 +85,9 @@ macro_rules! md_impl_all( macro_rules! md_assign_impl( ( // Operator, operator method, and scalar bounds. - $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; + $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)* $(for N::Element: $ElementBounds: ident)*; // Storage dimensions, and dimension bounds. - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+ + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),* // [Optional] Extra allocator bounds. $(where $ConstraintType: ty: $ConstraintBound: ident $(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)* )*; // Argument identifiers and types. @@ -97,6 +96,7 @@ macro_rules! md_assign_impl( $action: expr; $($lives: tt),*) => { impl<$($lives ,)* N $(, $Dims: $DimsBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs where N: Scalar + Zero + One + ClosedAdd + ClosedMul $($(+ $ScalarBounds)*)*, + $(N::Element: $ElementBounds,)* DefaultAllocator: Allocator + Allocator, $( $ConstraintType: $ConstraintBound $(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),* @@ -114,9 +114,9 @@ macro_rules! md_assign_impl( macro_rules! md_assign_impl_all( ( // Operator, operator method, and scalar bounds. - $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)*; + $Op: ident, $op: ident $(where N: $($ScalarBounds: ident),*)* $(for N::Element: $($ElementBounds: ident),*)*; // Storage dimensions, and dimension bounds. - ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),+ + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) for $($Dims: ident: $DimsBound: ident $(<$($BoundParam: ty),*>)*),* // [Optional] Extra allocator bounds. $(where $ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)* )*; // Argument identifiers and types. @@ -125,15 +125,15 @@ macro_rules! md_assign_impl_all( [val] => $action_val: expr; [ref] => $action_ref: expr;) => { md_assign_impl!( - $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ + $Op, $op $(where N: $($ScalarBounds),*)* $(for N::Element: $($ElementBounds),*)*; + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),* $(where $ConstraintType: $ConstraintBound $(<$($ConstraintBoundParams $( = $EqBound )*),*>)*)*; $lhs: $Lhs, $rhs: $Rhs; $action_val; ); md_assign_impl!( - $Op, $op $(where N: $($ScalarBounds),*)*; - ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),+ + $Op, $op $(where N: $($ScalarBounds),*)* $(for N::Element: $($ElementBounds),*)*; + ($R1, $C1),($R2, $C2) for $($Dims: $DimsBound $(<$($BoundParam),*>)*),* $(where $ConstraintType: $ConstraintBound $(<$($ConstraintBoundParams $( = $EqBound )*),*>)*)*; $lhs: $Lhs, $rhs: &'b $Rhs; $action_ref; 'b); diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index 1ac0d264..a7d5372f 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::mem; -use alga::general::RealField; +use simba::scalar::RealField; use crate::base::dimension::U3; use crate::base::helper; @@ -46,7 +46,9 @@ impl PartialEq for Orthographic3 { #[cfg(feature = "serde-serialize")] impl Serialize for Orthographic3 { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.matrix.serialize(serializer) } } @@ -54,7 +56,9 @@ impl Serialize for Orthographic3 { #[cfg(feature = "serde-serialize")] impl<'a, N: RealField + Deserialize<'a>> Deserialize<'a> for Orthographic3 { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let matrix = Matrix4::::deserialize(deserializer)?; Ok(Self::from_matrix_unchecked(matrix)) @@ -286,7 +290,7 @@ impl Orthographic3 { /// Retrieves the underlying homogeneous matrix. /// Deprecated: Use [Orthographic3::into_inner] instead. - #[deprecated(note="use `.into_inner()` instead")] + #[deprecated(note = "use `.into_inner()` instead")] #[inline] pub fn unwrap(self) -> Matrix4 { self.matrix @@ -480,7 +484,9 @@ impl Orthographic3 { /// ``` #[inline] pub fn project_vector(&self, p: &Vector) -> Vector3 - where SB: Storage { + where + SB: Storage, + { Vector3::new( self.matrix[(0, 0)] * p[0], self.matrix[(1, 1)] * p[1], @@ -679,7 +685,8 @@ impl Orthographic3 { } impl Distribution> for Standard -where Standard: Distribution +where + Standard: Distribution, { fn sample(&self, r: &mut R) -> Orthographic3 { let left = r.gen(); @@ -695,7 +702,8 @@ where Standard: Distribution #[cfg(feature = "arbitrary")] impl Arbitrary for Orthographic3 -where Matrix4: Send +where + Matrix4: Send, { fn arbitrary(g: &mut G) -> Self { let left = Arbitrary::arbitrary(g); diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index 45bb7aad..325a450c 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::mem; -use alga::general::RealField; +use simba::scalar::RealField; use crate::base::dimension::U3; use crate::base::helper; @@ -47,7 +47,9 @@ impl PartialEq for Perspective3 { #[cfg(feature = "serde-serialize")] impl Serialize for Perspective3 { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.matrix.serialize(serializer) } } @@ -55,7 +57,9 @@ impl Serialize for Perspective3 { #[cfg(feature = "serde-serialize")] impl<'a, N: RealField + Deserialize<'a>> Deserialize<'a> for Perspective3 { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let matrix = Matrix4::::deserialize(deserializer)?; Ok(Self::from_matrix_unchecked(matrix)) @@ -147,7 +151,7 @@ impl Perspective3 { /// Retrieves the underlying homogeneous matrix. /// Deprecated: Use [Perspective3::into_inner] instead. - #[deprecated(note="use `.into_inner()` instead")] + #[deprecated(note = "use `.into_inner()` instead")] #[inline] pub fn unwrap(self) -> Matrix4 { self.matrix @@ -170,7 +174,8 @@ impl Perspective3 { pub fn znear(&self) -> N { let ratio = (-self.matrix[(2, 2)] + N::one()) / (-self.matrix[(2, 2)] - N::one()); - self.matrix[(2, 3)] / (ratio * crate::convert(2.0)) - self.matrix[(2, 3)] / crate::convert(2.0) + self.matrix[(2, 3)] / (ratio * crate::convert(2.0)) + - self.matrix[(2, 3)] / crate::convert(2.0) } /// Gets the far plane offset of the view frustum. @@ -211,7 +216,9 @@ impl Perspective3 { /// Projects a vector. Faster than matrix multiplication. #[inline] pub fn project_vector(&self, p: &Vector) -> Vector3 - where SB: Storage { + where + SB: Storage, + { let inverse_denom = -N::one() / p[2]; Vector3::new( self.matrix[(0, 0)] * p[0] * inverse_denom, @@ -262,7 +269,8 @@ impl Perspective3 { } impl Distribution> for Standard -where Standard: Distribution +where + Standard: Distribution, { fn sample<'a, R: Rng + ?Sized>(&self, r: &'a mut R) -> Perspective3 { let znear = r.gen(); diff --git a/src/geometry/point.rs b/src/geometry/point.rs index bc1b138a..ab26589b 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -12,6 +12,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; +use simba::simd::SimdPartialOrd; + use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::iter::{MatrixIter, MatrixIterMut}; @@ -21,7 +23,8 @@ use crate::base::{DefaultAllocator, Scalar, VectorN}; #[repr(C)] #[derive(Debug, Clone)] pub struct Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// The coordinates of this point, i.e., the shift from the origin. pub coords: VectorN, @@ -51,7 +54,9 @@ where >::Buffer: Serialize, { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.coords.serialize(serializer) } } @@ -63,7 +68,9 @@ where >::Buffer: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let coords = VectorN::::deserialize(deserializer)?; Ok(Self::from(coords)) @@ -92,7 +99,8 @@ where } impl Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the /// end of it. @@ -244,8 +252,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.coords .relative_eq(&other.coords, epsilon, max_relative) } @@ -270,7 +277,8 @@ where impl Eq for Point where DefaultAllocator: Allocator {} impl PartialEq for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn eq(&self, right: &Self) -> bool { @@ -279,7 +287,8 @@ where DefaultAllocator: Allocator } impl PartialOrd for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn partial_cmp(&self, other: &Self) -> Option { @@ -307,13 +316,41 @@ where DefaultAllocator: Allocator } } +/* + * inf/sup + */ +impl Point +where + DefaultAllocator: Allocator, +{ + /// Computes the infimum (aka. componentwise min) of two points. + #[inline] + pub fn inf(&self, other: &Self) -> Point { + self.coords.inf(&other.coords).into() + } + + /// Computes the supremum (aka. componentwise max) of two points. + #[inline] + pub fn sup(&self, other: &Self) -> Point { + self.coords.sup(&other.coords).into() + } + + /// Computes the (infimum, supremum) of two points. + #[inline] + pub fn inf_sup(&self, other: &Self) -> (Point, Point) { + let (inf, sup) = self.coords.inf_sup(&other.coords); + (inf.into(), sup.into()) + } +} + /* * * Display * */ impl fmt::Display for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; diff --git a/src/geometry/point_alga.rs b/src/geometry/point_alga.rs index 162e6c68..5a7cace5 100644 --- a/src/geometry/point_alga.rs +++ b/src/geometry/point_alga.rs @@ -15,8 +15,9 @@ where type Translation = VectorN; } -impl EuclideanSpace for Point -where DefaultAllocator: Allocator +impl EuclideanSpace for Point +where + DefaultAllocator: Allocator, { type Coordinates = VectorN; type RealField = N; diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index e5d2ee44..c54cb779 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -5,15 +5,16 @@ use num::{Bounded, One, Zero}; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use alga::general::ClosedDiv; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3, U4, U5, U6}; use crate::base::{DefaultAllocator, Scalar, VectorN}; +use simba::scalar::ClosedDiv; use crate::geometry::Point; impl Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Creates a new point with uninitialized coordinates. #[inline] @@ -38,7 +39,9 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn origin() -> Self - where N: Zero { + where + N: Zero, + { Self::from(VectorN::from_element(N::zero())) } @@ -113,7 +116,8 @@ where DefaultAllocator: Allocator * */ impl Bounded for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn max_value() -> Self { diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index 4f32d840..83b4521d 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -1,5 +1,6 @@ -use alga::general::{ClosedDiv, SubsetOf, SupersetOf}; use num::{One, Zero}; +use simba::scalar::{ClosedDiv, SubsetOf, SupersetOf}; +use simba::simd::PrimitiveSimdValue; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; @@ -44,7 +45,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &Point) -> Self { + fn from_superset_unchecked(m: &Point) -> Self { Self::from(Matrix::from_superset_unchecked(&m.coords)) } } @@ -71,10 +72,10 @@ where } #[inline] - unsafe fn from_superset_unchecked(v: &VectorN>) -> Self { + fn from_superset_unchecked(v: &VectorN>) -> Self { let coords = v.fixed_slice::(0, 0) / v[D::dim()].inlined_clone(); Self { - coords: crate::convert_unchecked(coords) + coords: crate::convert_unchecked(coords), } } } @@ -142,13 +143,98 @@ where } impl From> for Point - where - DefaultAllocator: Allocator, +where + DefaultAllocator: Allocator, { #[inline] fn from(coords: VectorN) -> Self { - Point { - coords - } + Point { coords } + } +} + +impl From<[Point; 2]> + for Point +where + N: From<[::Element; 2]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, + >::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 2]) -> Self { + Self::from(VectorN::from([arr[0].coords, arr[1].coords])) + } +} + +impl From<[Point; 4]> + for Point +where + N: From<[::Element; 4]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, + >::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 4]) -> Self { + Self::from(VectorN::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + ])) + } +} + +impl From<[Point; 8]> + for Point +where + N: From<[::Element; 8]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, + >::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 8]) -> Self { + Self::from(VectorN::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + ])) + } +} + +impl From<[Point; 16]> + for Point +where + N: From<[::Element; 16]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, + >::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 16]) -> Self { + Self::from(VectorN::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + arr[8].coords, + arr[9].coords, + arr[10].coords, + arr[11].coords, + arr[12].coords, + arr[13].coords, + arr[14].coords, + arr[15].coords, + ])) } } diff --git a/src/geometry/point_ops.rs b/src/geometry/point_ops.rs index 648a71a6..e6547fc4 100644 --- a/src/geometry/point_ops.rs +++ b/src/geometry/point_ops.rs @@ -3,10 +3,12 @@ use std::ops::{ Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, }; -use alga::general::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; +use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; use crate::base::allocator::{Allocator, SameShapeAllocator}; -use crate::base::constraint::{AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::constraint::{ + AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, +}; use crate::base::dimension::{Dim, DimName, U1}; use crate::base::storage::Storage; use crate::base::{DefaultAllocator, Matrix, Scalar, Vector, VectorSum}; @@ -19,7 +21,8 @@ use crate::geometry::Point; * */ impl Index for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type Output = N; @@ -30,7 +33,8 @@ where DefaultAllocator: Allocator } impl IndexMut for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn index_mut(&mut self, i: usize) -> &mut Self::Output { @@ -44,7 +48,8 @@ where DefaultAllocator: Allocator * */ impl Neg for Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type Output = Self; @@ -55,7 +60,8 @@ where DefaultAllocator: Allocator } impl<'a, N: Scalar + ClosedNeg, D: DimName> Neg for &'a Point -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type Output = Point; diff --git a/src/geometry/point_simba.rs b/src/geometry/point_simba.rs new file mode 100644 index 00000000..a6c8465e --- /dev/null +++ b/src/geometry/point_simba.rs @@ -0,0 +1,51 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, Scalar, VectorN}; + +use crate::geometry::Point; + +impl SimdValue for Point +where + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + type Element = Point; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + VectorN::splat(val.coords).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.coords.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.coords.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.coords.replace(i, val.coords) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.coords.replace_unchecked(i, val.coords) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.coords.select(cond, other.coords).into() + } +} diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index c2f48796..45a03c78 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -13,11 +13,14 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::RealField; +use simba::scalar::RealField; +use simba::simd::{SimdBool, SimdOption, SimdRealField, SimdValue}; use crate::base::dimension::{U1, U3, U4}; use crate::base::storage::{CStride, RStride}; -use crate::base::{Matrix3, Matrix4, MatrixSlice, MatrixSliceMut, Unit, Vector3, Vector4}; +use crate::base::{ + Matrix3, Matrix4, MatrixSlice, MatrixSliceMut, Normed, Scalar, Unit, Vector3, Vector4, +}; use crate::geometry::{Point3, Rotation}; @@ -25,14 +28,15 @@ use crate::geometry::{Point3, Rotation}; /// that may be used as a rotation. #[repr(C)] #[derive(Debug)] -pub struct Quaternion { +pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. pub coords: Vector4, } #[cfg(feature = "abomonation-serialize")] -impl Abomonation for Quaternion -where Vector4: Abomonation +impl Abomonation for Quaternion +where + Vector4: Abomonation, { unsafe fn entomb(&self, writer: &mut W) -> IOResult<()> { self.coords.entomb(writer) @@ -47,9 +51,12 @@ where Vector4: Abomonation } } -impl Eq for Quaternion {} +impl Eq for Quaternion where N::Element: SimdRealField {} -impl PartialEq for Quaternion { +impl PartialEq for Quaternion +where + N::Element: SimdRealField, +{ fn eq(&self, rhs: &Self) -> bool { self.coords == rhs.coords || // Account for the double-covering of S², i.e. q = -q @@ -57,15 +64,15 @@ impl PartialEq for Quaternion { } } -impl hash::Hash for Quaternion { +impl hash::Hash for Quaternion { fn hash(&self, state: &mut H) { self.coords.hash(state) } } -impl Copy for Quaternion {} +impl Copy for Quaternion {} -impl Clone for Quaternion { +impl Clone for Quaternion { #[inline] fn clone(&self) -> Self { Self::from(self.coords.clone()) @@ -73,28 +80,37 @@ impl Clone for Quaternion { } #[cfg(feature = "serde-serialize")] -impl Serialize for Quaternion -where Owned: Serialize +impl Serialize for Quaternion +where + Owned: Serialize, { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.coords.serialize(serializer) } } #[cfg(feature = "serde-serialize")] -impl<'a, N: RealField> Deserialize<'a> for Quaternion -where Owned: Deserialize<'a> +impl<'a, N: SimdRealField> Deserialize<'a> for Quaternion +where + Owned: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let coords = Vector4::::deserialize(deserializer)?; Ok(Self::from(coords)) } } -impl Quaternion { +impl Quaternion +where + N::Element: SimdRealField, +{ /// Moves this unit quaternion into one that owns its data. #[inline] #[deprecated(note = "This method is a no-op and will be removed in a future release.")] @@ -146,36 +162,6 @@ impl Quaternion { Self::from_parts(self.w, -self.imag()) } - /// Inverts this quaternion if it is not zero. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::Quaternion; - /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); - /// let inv_q = q.try_inverse(); - /// - /// assert!(inv_q.is_some()); - /// assert_relative_eq!(inv_q.unwrap() * q, Quaternion::identity()); - /// - /// //Non-invertible case - /// let q = Quaternion::new(0.0, 0.0, 0.0, 0.0); - /// let inv_q = q.try_inverse(); - /// - /// assert!(inv_q.is_none()); - /// ``` - #[inline] - #[must_use = "Did you mean to use try_inverse_mut()?"] - pub fn try_inverse(&self) -> Option { - let mut res = Self::from(self.coords.clone_owned()); - - if res.try_inverse_mut() { - Some(res) - } else { - None - } - } - /// Linear interpolation between two quaternion. /// /// Computes `self * (1 - t) + other * t`. @@ -309,6 +295,57 @@ impl Quaternion { pub fn dot(&self, rhs: &Self) -> N { self.coords.dot(&rhs.coords) } +} + +impl Quaternion +where + N::Element: SimdRealField, +{ + /// Inverts this quaternion if it is not zero. + /// + /// This method also does not works with SIMD components (see `simd_try_inverse` instead). + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let inv_q = q.try_inverse(); + /// + /// assert!(inv_q.is_some()); + /// assert_relative_eq!(inv_q.unwrap() * q, Quaternion::identity()); + /// + /// //Non-invertible case + /// let q = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// let inv_q = q.try_inverse(); + /// + /// assert!(inv_q.is_none()); + /// ``` + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn try_inverse(&self) -> Option + where + N: RealField, + { + let mut res = self.clone(); + + if res.try_inverse_mut() { + Some(res) + } else { + None + } + } + + /// Attempt to inverse this quaternion. + /// + /// This method also works with SIMD components. + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn simd_try_inverse(&self) -> SimdOption { + let norm_squared = self.norm_squared(); + let ge = norm_squared.simd_ge(N::simd_default_epsilon()); + SimdOption::new(self.conjugate() / norm_squared, ge) + } /// Calculates the inner product (also known as the dot product). /// See "Foundations of Game Engine Development, Volume 1: Mathematics" by Lengyel @@ -362,7 +399,10 @@ impl Quaternion { /// assert_relative_eq!(expected, result, epsilon = 1.0e-5); /// ``` #[inline] - pub fn project(&self, other: &Self) -> Option { + pub fn project(&self, other: &Self) -> Option + where + N: RealField, + { self.inner(other).right_div(other) } @@ -381,7 +421,10 @@ impl Quaternion { /// assert_relative_eq!(expected, result, epsilon = 1.0e-5); /// ``` #[inline] - pub fn reject(&self, other: &Self) -> Option { + pub fn reject(&self, other: &Self) -> Option + where + N: RealField, + { self.outer(other).right_div(other) } @@ -400,7 +443,10 @@ impl Quaternion { /// assert_eq!(half_ang, f32::consts::FRAC_PI_2); /// assert_eq!(axis, Some(Vector3::x_axis())); /// ``` - pub fn polar_decomposition(&self) -> (N, N, Option>>) { + pub fn polar_decomposition(&self) -> (N, N, Option>>) + where + N: RealField, + { if let Some((q, n)) = Unit::try_new_and_get(*self, N::zero()) { if let Some(axis) = Unit::try_new(self.vector().clone_owned(), N::zero()) { let angle = q.angle() / crate::convert(2.0f64); @@ -429,7 +475,7 @@ impl Quaternion { let v = self.vector(); let s = self.scalar(); - Self::from_parts(n.ln(), v.normalize() * (s / n).acos()) + Self::from_parts(n.simd_ln(), v.normalize() * (s / n).simd_acos()) } /// Compute the exponential of a quaternion. @@ -443,7 +489,7 @@ impl Quaternion { /// ``` #[inline] pub fn exp(&self) -> Self { - self.exp_eps(N::default_epsilon()) + self.exp_eps(N::simd_default_epsilon()) } /// Compute the exponential of a quaternion. Returns the identity if the vector part of this quaternion @@ -464,16 +510,17 @@ impl Quaternion { pub fn exp_eps(&self, eps: N) -> Self { let v = self.vector(); let nn = v.norm_squared(); + let le = nn.simd_le(eps * eps); + le.if_else( + || Self::identity(), + || { + let w_exp = self.scalar().simd_exp(); + let n = nn.simd_sqrt(); + let nv = v * (w_exp * n.simd_sin() / n); - if nn <= eps * eps { - Self::identity() - } else { - let w_exp = self.scalar().exp(); - let n = nn.sqrt(); - let nv = v * (w_exp * n.sin() / n); - - Self::from_parts(w_exp * n.cos(), nv) - } + Self::from_parts(w_exp * n.simd_cos(), nv) + }, + ) } /// Raise the quaternion to a given floating power. @@ -547,27 +594,21 @@ impl Quaternion { /// ``` /// # #[macro_use] extern crate approx; /// # use nalgebra::Quaternion; - /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let mut q = Quaternion::new(1.0f32, 2.0, 3.0, 4.0); /// /// assert!(q.try_inverse_mut()); /// assert_relative_eq!(q * Quaternion::new(1.0, 2.0, 3.0, 4.0), Quaternion::identity()); /// /// //Non-invertible case - /// let mut q = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// let mut q = Quaternion::new(0.0f32, 0.0, 0.0, 0.0); /// assert!(!q.try_inverse_mut()); /// ``` #[inline] - pub fn try_inverse_mut(&mut self) -> bool { + pub fn try_inverse_mut(&mut self) -> N::SimdBool { let norm_squared = self.norm_squared(); - - if relative_eq!(&norm_squared, &N::zero()) { - false - } else { - self.conjugate_mut(); - self.coords /= norm_squared; - - true - } + let ge = norm_squared.simd_ge(N::simd_default_epsilon()); + *self = ge.if_else(|| self.conjugate() / norm_squared, || *self); + ge } /// Normalizes this quaternion. @@ -604,6 +645,8 @@ impl Quaternion { } /// Check if the quaternion is pure. + /// + /// A quaternion is pure if it has no real part (`self.w == 0.0`). #[inline] pub fn is_pure(&self) -> bool { self.w.is_zero() @@ -619,7 +662,10 @@ impl Quaternion { /// /// Calculates B-1 * A where A = self, B = other. #[inline] - pub fn left_div(&self, other: &Self) -> Option { + pub fn left_div(&self, other: &Self) -> Option + where + N: RealField, + { other.try_inverse().map(|inv| inv * self) } @@ -638,7 +684,10 @@ impl Quaternion { /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// ``` #[inline] - pub fn right_div(&self, other: &Self) -> Option { + pub fn right_div(&self, other: &Self) -> Option + where + N: RealField, + { other.try_inverse().map(|inv| self * inv) } @@ -656,8 +705,8 @@ impl Quaternion { #[inline] pub fn cos(&self) -> Self { let z = self.imag().magnitude(); - let w = -self.w.sin() * z.sinhc(); - Self::from_parts(self.w.cos() * z.cosh(), self.imag() * w) + let w = -self.w.simd_sin() * z.simd_sinhc(); + Self::from_parts(self.w.simd_cos() * z.simd_cosh(), self.imag() * w) } /// Calculates the quaternionic arccosinus. @@ -694,8 +743,8 @@ impl Quaternion { #[inline] pub fn sin(&self) -> Self { let z = self.imag().magnitude(); - let w = self.w.cos() * z.sinhc(); - Self::from_parts(self.w.sin() * z.cosh(), self.imag() * w) + let w = self.w.simd_cos() * z.simd_sinhc(); + Self::from_parts(self.w.simd_sin() * z.simd_cosh(), self.imag() * w) } /// Calculates the quaternionic arcsinus. @@ -730,7 +779,10 @@ impl Quaternion { /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// ``` #[inline] - pub fn tan(&self) -> Self { + pub fn tan(&self) -> Self + where + N: RealField, + { self.sin().right_div(&self.cos()).unwrap() } @@ -745,7 +797,10 @@ impl Quaternion { /// assert_relative_eq!(input, result, epsilon = 1.0e-7); /// ``` #[inline] - pub fn atan(&self) -> Self { + pub fn atan(&self) -> Self + where + N: RealField, + { let u = Self::from_imag(self.imag().normalize()); let num = u + self; let den = u - self; @@ -832,7 +887,10 @@ impl Quaternion { /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); /// ``` #[inline] - pub fn tanh(&self) -> Self { + pub fn tanh(&self) -> Self + where + N: RealField, + { self.sinh().right_div(&self.cosh()).unwrap() } @@ -882,8 +940,7 @@ impl> RelativeEq for Quaternion { other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.as_vector().relative_eq(other.as_vector(), epsilon, max_relative) || // Account for the double-covering of S², i.e. q = -q self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.relative_eq(&-*b, epsilon, max_relative)) @@ -917,25 +974,34 @@ impl fmt::Display for Quaternion { /// A unit quaternions. May be used to represent a rotation. pub type UnitQuaternion = Unit>; -impl UnitQuaternion { - /// Moves this unit quaternion into one that owns its data. +impl Normed for Quaternion { + type Norm = N::SimdRealField; + #[inline] - #[deprecated( - note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead." - )] - pub fn into_owned(self) -> Self { - self + fn norm(&self) -> N::SimdRealField { + self.coords.norm() } - /// Clones this unit quaternion into one that owns its data. #[inline] - #[deprecated( - note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead." - )] - pub fn clone_owned(&self) -> Self { - *self + fn norm_squared(&self) -> N::SimdRealField { + self.coords.norm_squared() } + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.coords.scale_mut(n) + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.coords.unscale_mut(n) + } +} + +impl UnitQuaternion +where + N::Element: SimdRealField, +{ /// The rotation angle in [0; pi] of this unit quaternion. /// /// # Example @@ -947,8 +1013,8 @@ impl UnitQuaternion { /// ``` #[inline] pub fn angle(&self) -> N { - let w = self.quaternion().scalar().abs(); - self.quaternion().imag().norm().atan2(w) * crate::convert(2.0f64) + let w = self.quaternion().scalar().simd_abs(); + self.quaternion().imag().norm().simd_atan2(w) * crate::convert(2.0f64) } /// The underlying quaternion. @@ -1029,7 +1095,7 @@ impl UnitQuaternion { /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); /// ``` #[inline] - pub fn rotation_to(&self, other: &Self) -> Self{ + pub fn rotation_to(&self, other: &Self) -> Self { other / self } @@ -1086,8 +1152,12 @@ impl UnitQuaternion { /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); /// ``` #[inline] - pub fn slerp(&self, other: &Self, t: N) -> Self { - self.try_slerp(other, t, N::default_epsilon()).expect("Quaternion slerp: ambiguous configuration.") + pub fn slerp(&self, other: &Self, t: N) -> Self + where + N: RealField, + { + self.try_slerp(other, t, N::default_epsilon()) + .expect("Quaternion slerp: ambiguous configuration.") } /// Computes the spherical linear interpolation between two unit quaternions or returns `None` @@ -1101,22 +1171,24 @@ impl UnitQuaternion { /// * `epsilon`: the value below which the sinus of the angle separating both quaternion /// must be to return `None`. #[inline] - pub fn try_slerp( - &self, - other: &Self, - t: N, - epsilon: N, - ) -> Option + pub fn try_slerp(&self, other: &Self, t: N, epsilon: N) -> Option + where + N: RealField, { let coords = if self.coords.dot(&other.coords) < N::zero() { - Unit::new_unchecked(self.coords) - .try_slerp(&Unit::new_unchecked(-other.coords), t, epsilon) + Unit::new_unchecked(self.coords).try_slerp( + &Unit::new_unchecked(-other.coords), + t, + epsilon, + ) } else { - Unit::new_unchecked(self.coords) - .try_slerp(&Unit::new_unchecked(other.coords), t, epsilon) + Unit::new_unchecked(self.coords).try_slerp( + &Unit::new_unchecked(other.coords), + t, + epsilon, + ) }; - coords.map(|q| Unit::new_unchecked(Quaternion::from(q.into_inner()))) } @@ -1158,7 +1230,10 @@ impl UnitQuaternion { /// assert!(rot.axis().is_none()); /// ``` #[inline] - pub fn axis(&self) -> Option>> { + pub fn axis(&self) -> Option>> + where + N: RealField, + { let v = if self.quaternion().scalar() >= N::zero() { self.as_ref().vector().clone_owned() } else { @@ -1179,7 +1254,10 @@ impl UnitQuaternion { /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6); /// ``` #[inline] - pub fn scaled_axis(&self) -> Vector3 { + pub fn scaled_axis(&self) -> Vector3 + where + N: RealField, + { if let Some(axis) = self.axis() { axis.into_inner() * self.angle() } else { @@ -1204,7 +1282,10 @@ impl UnitQuaternion { /// assert!(rot.axis_angle().is_none()); /// ``` #[inline] - pub fn axis_angle(&self) -> Option<(Unit>, N)> { + pub fn axis_angle(&self) -> Option<(Unit>, N)> + where + N: RealField, + { self.axis().map(|axis| (axis, self.angle())) } @@ -1231,7 +1312,10 @@ impl UnitQuaternion { /// assert_relative_eq!(q.ln().vector().into_owned(), axisangle, epsilon = 1.0e-6); /// ``` #[inline] - pub fn ln(&self) -> Quaternion { + pub fn ln(&self) -> Quaternion + where + N: RealField, + { if let Some(v) = self.axis() { Quaternion::from_imag(v.into_inner() * self.angle()) } else { @@ -1256,7 +1340,10 @@ impl UnitQuaternion { /// assert_eq!(pow.angle(), 2.4); /// ``` #[inline] - pub fn powf(&self, n: N) -> Self { + pub fn powf(&self, n: N) -> Self + where + N: RealField, + { if let Some(v) = self.axis() { Self::from_axis_angle(&v, self.angle() * n) } else { @@ -1316,7 +1403,10 @@ impl UnitQuaternion { /// The angles are produced in the form (roll, pitch, yaw). #[inline] #[deprecated(note = "This is renamed to use `.euler_angles()`.")] - pub fn to_euler_angles(&self) -> (N, N, N) { + pub fn to_euler_angles(&self) -> (N, N, N) + where + N: RealField, + { self.euler_angles() } @@ -1335,7 +1425,10 @@ impl UnitQuaternion { /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); /// ``` #[inline] - pub fn euler_angles(&self) -> (N, N, N) { + pub fn euler_angles(&self) -> (N, N, N) + where + N: RealField, + { self.to_rotation_matrix().euler_angles() } @@ -1491,8 +1584,7 @@ impl> RelativeEq for UnitQuaternion { other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.as_ref() .relative_eq(other.as_ref(), epsilon, max_relative) } diff --git a/src/geometry/quaternion_alga.rs b/src/geometry/quaternion_alga.rs index 86eeedb1..087c8a58 100755 --- a/src/geometry/quaternion_alga.rs +++ b/src/geometry/quaternion_alga.rs @@ -2,8 +2,8 @@ use num::Zero; use alga::general::{ AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, - AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module, - Multiplicative, RealField, + AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Module, + Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::{ AffineTransformation, DirectIsometry, FiniteDimVectorSpace, Isometry, NormedSpace, @@ -14,35 +14,35 @@ use alga::linear::{ use crate::base::{Vector3, Vector4}; use crate::geometry::{Point3, Quaternion, UnitQuaternion}; -impl Identity for Quaternion { +impl Identity for Quaternion { #[inline] fn identity() -> Self { Self::identity() } } -impl Identity for Quaternion { +impl Identity for Quaternion { #[inline] fn identity() -> Self { Self::zero() } } -impl AbstractMagma for Quaternion { +impl AbstractMagma for Quaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } -impl AbstractMagma for Quaternion { +impl AbstractMagma for Quaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self + rhs } } -impl TwoSidedInverse for Quaternion { +impl TwoSidedInverse for Quaternion { #[inline] fn two_sided_inverse(&self) -> Self { -self @@ -51,7 +51,7 @@ impl TwoSidedInverse for Quaternion { macro_rules! impl_structures( ($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for $Quaternion { } + impl $marker<$operator> for $Quaternion { } )*} ); @@ -73,7 +73,7 @@ impl_structures!( * Vector space. * */ -impl AbstractModule for Quaternion { +impl AbstractModule for Quaternion { type AbstractRing = N; #[inline] @@ -82,15 +82,15 @@ impl AbstractModule for Quaternion { } } -impl Module for Quaternion { +impl Module for Quaternion { type Ring = N; } -impl VectorSpace for Quaternion { +impl VectorSpace for Quaternion { type Field = N; } -impl FiniteDimVectorSpace for Quaternion { +impl FiniteDimVectorSpace for Quaternion { #[inline] fn dimension() -> usize { 4 @@ -117,7 +117,7 @@ impl FiniteDimVectorSpace for Quaternion { } } -impl NormedSpace for Quaternion { +impl NormedSpace for Quaternion { type RealField = N; type ComplexField = N; @@ -162,21 +162,23 @@ impl NormedSpace for Quaternion { * Implementations for UnitQuaternion. * */ -impl Identity for UnitQuaternion { +impl Identity for UnitQuaternion { #[inline] fn identity() -> Self { Self::identity() } } -impl AbstractMagma for UnitQuaternion { +impl AbstractMagma for UnitQuaternion { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } -impl TwoSidedInverse for UnitQuaternion { +impl TwoSidedInverse + for UnitQuaternion +{ #[inline] fn two_sided_inverse(&self) -> Self { self.inverse() @@ -197,7 +199,7 @@ impl_structures!( AbstractGroup ); -impl Transformation> for UnitQuaternion { +impl Transformation> for UnitQuaternion { #[inline] fn transform_point(&self, pt: &Point3) -> Point3 { self.transform_point(pt) @@ -209,7 +211,9 @@ impl Transformation> for UnitQuaternion { } } -impl ProjectiveTransformation> for UnitQuaternion { +impl ProjectiveTransformation> + for UnitQuaternion +{ #[inline] fn inverse_transform_point(&self, pt: &Point3) -> Point3 { self.inverse_transform_point(pt) @@ -221,7 +225,9 @@ impl ProjectiveTransformation> for UnitQuaternion { } } -impl AffineTransformation> for UnitQuaternion { +impl AffineTransformation> + for UnitQuaternion +{ type Rotation = Self; type NonUniformScaling = Id; type Translation = Id; @@ -262,7 +268,7 @@ impl AffineTransformation> for UnitQuaternion { } } -impl Similarity> for UnitQuaternion { +impl Similarity> for UnitQuaternion { type Scaling = Id; #[inline] @@ -283,13 +289,13 @@ impl Similarity> for UnitQuaternion { macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for UnitQuaternion { } + impl $Trait> for UnitQuaternion { } )*} ); marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); -impl Rotation> for UnitQuaternion { +impl Rotation> for UnitQuaternion { #[inline] fn powf(&self, n: N) -> Option { Some(self.powf(n)) diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 3de302f5..175275d4 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -9,15 +9,17 @@ use num::{One, Zero}; use rand::distributions::{Distribution, OpenClosed01, Standard}; use rand::Rng; -use alga::general::RealField; +use simba::scalar::RealField; +use simba::simd::{SimdBool, SimdValue}; use crate::base::dimension::U3; use crate::base::storage::Storage; -use crate::base::{Unit, Vector, Vector3, Vector4, Matrix3, Matrix4}; +use crate::base::{Matrix3, Matrix4, Unit, Vector, Vector3, Vector4}; +use crate::{Scalar, SimdRealField}; use crate::geometry::{Quaternion, Rotation3, UnitQuaternion}; -impl Quaternion { +impl Quaternion { /// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w` /// vector component. #[inline] @@ -43,7 +45,9 @@ impl Quaternion { pub fn new(w: N, i: N, j: N, k: N) -> Self { Self::from(Vector4::new(i, j, k, w)) } +} +impl Quaternion { /// Constructs a pure quaternion. #[inline] pub fn from_imag(vector: Vector3) -> Self { @@ -67,7 +71,9 @@ impl Quaternion { #[inline] // FIXME: take a reference to `vector`? pub fn from_parts(scalar: N, vector: Vector) -> Self - where SB: Storage { + where + SB: Storage, + { Self::new(scalar, vector[0], vector[1], vector[2]) } @@ -77,17 +83,6 @@ impl Quaternion { Self::from_parts(r, Vector3::zero()) } - /// Creates a new quaternion from its polar decomposition. - /// - /// Note that `axis` is assumed to be a unit vector. - // FIXME: take a reference to `axis`? - pub fn from_polar_decomposition(scale: N, theta: N, axis: Unit>) -> Self - where SB: Storage { - let rot = UnitQuaternion::::from_axis_angle(&axis, theta * crate::convert(2.0f64)); - - rot.into_inner() * scale - } - /// The quaternion multiplicative identity. /// /// # Example @@ -105,14 +100,39 @@ impl Quaternion { } } -impl One for Quaternion { +// FIXME: merge with the previous block. +impl Quaternion +where + N::Element: SimdRealField, +{ + /// Creates a new quaternion from its polar decomposition. + /// + /// Note that `axis` is assumed to be a unit vector. + // FIXME: take a reference to `axis`? + pub fn from_polar_decomposition(scale: N, theta: N, axis: Unit>) -> Self + where + SB: Storage, + { + let rot = UnitQuaternion::::from_axis_angle(&axis, theta * crate::convert(2.0f64)); + + rot.into_inner() * scale + } +} + +impl One for Quaternion +where + N::Element: SimdRealField, +{ #[inline] fn one() -> Self { Self::identity() } } -impl Zero for Quaternion { +impl Zero for Quaternion +where + N::Element: SimdRealField, +{ #[inline] fn zero() -> Self { Self::from(Vector4::zero()) @@ -124,8 +144,9 @@ impl Zero for Quaternion { } } -impl Distribution> for Standard -where Standard: Distribution +impl Distribution> for Standard +where + Standard: Distribution, { #[inline] fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Quaternion { @@ -134,8 +155,9 @@ where Standard: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Quaternion -where Owned: Send +impl Arbitrary for Quaternion +where + Owned: Send, { #[inline] fn arbitrary(g: &mut G) -> Self { @@ -148,7 +170,10 @@ where Owned: Send } } -impl UnitQuaternion { +impl UnitQuaternion +where + N::Element: SimdRealField, +{ /// The rotation identity. /// /// # Example @@ -194,8 +219,10 @@ impl UnitQuaternion { /// ``` #[inline] pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self - where SB: Storage { - let (sang, cang) = (angle / crate::convert(2.0f64)).sin_cos(); + where + SB: Storage, + { + let (sang, cang) = (angle / crate::convert(2.0f64)).simd_sin_cos(); let q = Quaternion::from_parts(cang, axis.as_ref() * sang); Self::new_unchecked(q) @@ -225,9 +252,9 @@ impl UnitQuaternion { /// ``` #[inline] pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { - let (sr, cr) = (roll * crate::convert(0.5f64)).sin_cos(); - let (sp, cp) = (pitch * crate::convert(0.5f64)).sin_cos(); - let (sy, cy) = (yaw * crate::convert(0.5f64)).sin_cos(); + let (sr, cr) = (roll * crate::convert(0.5f64)).simd_sin_cos(); + let (sp, cp) = (pitch * crate::convert(0.5f64)).simd_sin_cos(); + let (sy, cy) = (yaw * crate::convert(0.5f64)).simd_sin_cos(); let q = Quaternion::new( cr * cp * cy + sr * sp * sy, @@ -258,46 +285,58 @@ impl UnitQuaternion { // Robust matrix to quaternion transformation. // See https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)]; - let res; - let _0_25: N = crate::convert(0.25); - if tr > N::zero() { - let denom = (tr + N::one()).sqrt() * crate::convert(2.0); - res = Quaternion::new( - _0_25 * denom, - (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, - (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, - (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, - ); - } else if rotmat[(0, 0)] > rotmat[(1, 1)] && rotmat[(0, 0)] > rotmat[(2, 2)] { - let denom = (N::one() + rotmat[(0, 0)] - rotmat[(1, 1)] - rotmat[(2, 2)]).sqrt() - * crate::convert(2.0); - res = Quaternion::new( - (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, - _0_25 * denom, - (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, - (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom, - ); - } else if rotmat[(1, 1)] > rotmat[(2, 2)] { - let denom = (N::one() + rotmat[(1, 1)] - rotmat[(0, 0)] - rotmat[(2, 2)]).sqrt() - * crate::convert(2.0); - res = Quaternion::new( - (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, - (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, - _0_25 * denom, - (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom, - ); - } else { - let denom = (N::one() + rotmat[(2, 2)] - rotmat[(0, 0)] - rotmat[(1, 1)]).sqrt() - * crate::convert(2.0); - res = Quaternion::new( - (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, - (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom, - (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom, - _0_25 * denom, - ); - } + let res = tr.simd_gt(N::zero()).if_else3( + || { + let denom = (tr + N::one()).simd_sqrt() * crate::convert(2.0); + Quaternion::new( + _0_25 * denom, + (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, + (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, + (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, + ) + }, + ( + || rotmat[(0, 0)].simd_gt(rotmat[(1, 1)]) & rotmat[(0, 0)].simd_gt(rotmat[(2, 2)]), + || { + let denom = (N::one() + rotmat[(0, 0)] - rotmat[(1, 1)] - rotmat[(2, 2)]) + .simd_sqrt() + * crate::convert(2.0); + Quaternion::new( + (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, + _0_25 * denom, + (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, + (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom, + ) + }, + ), + ( + || rotmat[(1, 1)].simd_gt(rotmat[(2, 2)]), + || { + let denom = (N::one() + rotmat[(1, 1)] - rotmat[(0, 0)] - rotmat[(2, 2)]) + .simd_sqrt() + * crate::convert(2.0); + Quaternion::new( + (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, + (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, + _0_25 * denom, + (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom, + ) + }, + ), + || { + let denom = (N::one() + rotmat[(2, 2)] - rotmat[(0, 0)] - rotmat[(1, 1)]) + .simd_sqrt() + * crate::convert(2.0); + Quaternion::new( + (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, + (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom, + (rotmat[(1, 2)] + rotmat[(2, 1)]) / denom, + _0_25 * denom, + ) + }, + ); Self::new_unchecked(res) } @@ -307,7 +346,10 @@ impl UnitQuaternion { /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - pub fn from_matrix(m: &Matrix3) -> Self { + pub fn from_matrix(m: &Matrix3) -> Self + where + N: RealField, + { Rotation3::from_matrix(m).into() } @@ -323,7 +365,10 @@ impl UnitQuaternion { /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close /// to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other /// guesses come to mind. - pub fn from_matrix_eps(m: &Matrix3, eps: N, max_iter: usize, guess: Self) -> Self { + pub fn from_matrix_eps(m: &Matrix3, eps: N, max_iter: usize, guess: Self) -> Self + where + N: RealField, + { let guess = Rotation3::from(guess); Rotation3::from_matrix_eps(m, eps, max_iter, guess).into() } @@ -344,6 +389,7 @@ impl UnitQuaternion { #[inline] pub fn rotation_between(a: &Vector, b: &Vector) -> Option where + N: RealField, SB: Storage, SC: Storage, { @@ -371,6 +417,7 @@ impl UnitQuaternion { s: N, ) -> Option where + N: RealField, SB: Storage, SC: Storage, { @@ -404,6 +451,7 @@ impl UnitQuaternion { b: &Unit>, ) -> Option where + N: RealField, SB: Storage, SC: Storage, { @@ -431,6 +479,7 @@ impl UnitQuaternion { s: N, ) -> Option where + N: RealField, SB: Storage, SC: Storage, { @@ -492,7 +541,7 @@ impl UnitQuaternion { } /// Deprecated: Use [UnitQuaternion::face_towards] instead. - #[deprecated(note="renamed to `face_towards`")] + #[deprecated(note = "renamed to `face_towards`")] pub fn new_observer_frames(dir: &Vector, up: &Vector) -> Self where SB: Storage, @@ -586,7 +635,9 @@ impl UnitQuaternion { /// ``` #[inline] pub fn new(axisangle: Vector) -> Self - where SB: Storage { + where + SB: Storage, + { let two: N = crate::convert(2.0f64); let q = Quaternion::::from_imag(axisangle / two).exp(); Self::new_unchecked(q) @@ -615,7 +666,9 @@ impl UnitQuaternion { /// ``` #[inline] pub fn new_eps(axisangle: Vector, eps: N) -> Self - where SB: Storage { + where + SB: Storage, + { let two: N = crate::convert(2.0f64); let q = Quaternion::::from_imag(axisangle / two).exp_eps(eps); Self::new_unchecked(q) @@ -645,7 +698,9 @@ impl UnitQuaternion { /// ``` #[inline] pub fn from_scaled_axis(axisangle: Vector) -> Self - where SB: Storage { + where + SB: Storage, + { Self::new(axisangle) } @@ -673,7 +728,9 @@ impl UnitQuaternion { /// ``` #[inline] pub fn from_scaled_axis_eps(axisangle: Vector, eps: N) -> Self - where SB: Storage { + where + SB: Storage, + { Self::new_eps(axisangle, eps) } @@ -685,7 +742,7 @@ impl UnitQuaternion { /// Algorithm from: Oshman, Yaakov, and Avishy Carmi. "Attitude estimation from vector /// observations using a genetic-algorithm-embedded quaternion particle filter." Journal of /// Guidance, Control, and Dynamics 29.4 (2006): 879-891. - /// + /// /// # Example /// ``` /// # #[macro_use] extern crate approx; @@ -702,14 +759,17 @@ impl UnitQuaternion { /// assert_relative_eq!(euler_angles_mean.0, 0.0, epsilon = 1.0e-7) /// ``` #[inline] - pub fn mean_of(unit_quaternions: impl IntoIterator) -> Self { + pub fn mean_of(unit_quaternions: impl IntoIterator) -> Self + where + N: RealField, + { let quaternions_matrix: Matrix4 = unit_quaternions .into_iter() .map(|q| q.as_vector() * q.as_vector().transpose()) .sum(); assert!(!quaternions_matrix.is_zero()); - + let eigen_matrix = quaternions_matrix .try_symmetric_eigen(N::RealField::default_epsilon(), 10) .expect("Quaternions matrix could not be diagonalized. This behavior should not be possible."); @@ -730,15 +790,20 @@ impl UnitQuaternion { } } -impl One for UnitQuaternion { +impl One for UnitQuaternion +where + N::Element: SimdRealField, +{ #[inline] fn one() -> Self { Self::identity() } } -impl Distribution> for Standard -where OpenClosed01: Distribution +impl Distribution> for Standard +where + N::Element: SimdRealField, + OpenClosed01: Distribution, { /// Generate a uniformly distributed random rotation quaternion. #[inline] @@ -749,14 +814,14 @@ where OpenClosed01: Distribution let x0 = rng.sample(OpenClosed01); let x1 = rng.sample(OpenClosed01); let x2 = rng.sample(OpenClosed01); - let theta1 = N::two_pi() * x1; - let theta2 = N::two_pi() * x2; - let s1 = theta1.sin(); - let c1 = theta1.cos(); - let s2 = theta2.sin(); - let c2 = theta2.cos(); - let r1 = (N::one() - x0).sqrt(); - let r2 = x0.sqrt(); + let theta1 = N::simd_two_pi() * x1; + let theta2 = N::simd_two_pi() * x2; + let s1 = theta1.simd_sin(); + let c1 = theta1.simd_cos(); + let s2 = theta2.simd_sin(); + let c2 = theta2.simd_cos(); + let r1 = (N::one() - x0).simd_sqrt(); + let r2 = x0.simd_sqrt(); Unit::new_unchecked(Quaternion::new(s1 * r1, c1 * r1, s2 * r2, c2 * r2)) } } diff --git a/src/geometry/quaternion_conversion.rs b/src/geometry/quaternion_conversion.rs index 4ac8b5a7..37a8bebd 100644 --- a/src/geometry/quaternion_conversion.rs +++ b/src/geometry/quaternion_conversion.rs @@ -1,16 +1,16 @@ use num::Zero; -use alga::general::{RealField, SubsetOf, SupersetOf}; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; #[cfg(feature = "mint")] use mint; use crate::base::dimension::U3; -use crate::base::{Matrix3, Matrix4, Vector4}; +use crate::base::{Matrix3, Matrix4, Scalar, Vector4}; use crate::geometry::{ - Isometry, Point3, Quaternion, Rotation, Rotation3, Similarity, SuperTCategoryOf, TAffine, - Transform, Translation, UnitQuaternion, + AbstractRotation, Isometry, Quaternion, Rotation, Rotation3, Similarity, SuperTCategoryOf, + TAffine, Transform, Translation, UnitQuaternion, }; /* @@ -34,8 +34,8 @@ use crate::geometry::{ impl SubsetOf> for Quaternion where - N1: RealField, - N2: RealField + SupersetOf, + N1: SimdRealField, + N2: SimdRealField + SupersetOf, { #[inline] fn to_superset(&self) -> Quaternion { @@ -48,7 +48,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(q: &Quaternion) -> Self { + fn from_superset_unchecked(q: &Quaternion) -> Self { Self { coords: q.coords.to_subset_unchecked(), } @@ -57,8 +57,8 @@ where impl SubsetOf> for UnitQuaternion where - N1: RealField, - N2: RealField + SupersetOf, + N1: SimdRealField, + N2: SimdRealField + SupersetOf, { #[inline] fn to_superset(&self) -> UnitQuaternion { @@ -71,7 +71,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(uq: &UnitQuaternion) -> Self { + fn from_superset_unchecked(uq: &UnitQuaternion) -> Self { Self::new_unchecked(crate::convert_ref_unchecked(uq.as_ref())) } } @@ -93,7 +93,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(rot: &Rotation3) -> Self { + fn from_superset_unchecked(rot: &Rotation3) -> Self { let q = UnitQuaternion::::from_rotation_matrix(rot); crate::convert_unchecked(q) } @@ -103,7 +103,7 @@ impl SubsetOf> for UnitQuaternion where N1: RealField, N2: RealField + SupersetOf, - R: AlgaRotation> + SupersetOf, + R: AbstractRotation + SupersetOf, { #[inline] fn to_superset(&self) -> Isometry { @@ -116,7 +116,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { + fn from_superset_unchecked(iso: &Isometry) -> Self { crate::convert_ref_unchecked(&iso.rotation) } } @@ -125,7 +125,7 @@ impl SubsetOf> for UnitQuaternion where N1: RealField, N2: RealField + SupersetOf, - R: AlgaRotation> + SupersetOf, + R: AbstractRotation + SupersetOf, { #[inline] fn to_superset(&self) -> Similarity { @@ -138,7 +138,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + fn from_superset_unchecked(sim: &Similarity) -> Self { crate::convert_ref_unchecked(&sim.isometry) } } @@ -160,7 +160,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -177,21 +177,21 @@ impl> SubsetOf> for Un } #[inline] - unsafe fn from_superset_unchecked(m: &Matrix4) -> Self { + fn from_superset_unchecked(m: &Matrix4) -> Self { let rot: Rotation3 = crate::convert_ref_unchecked(m); Self::from_rotation_matrix(&rot) } } #[cfg(feature = "mint")] -impl From> for Quaternion { +impl From> for Quaternion { fn from(q: mint::Quaternion) -> Self { Self::new(q.s, q.v.x, q.v.y, q.v.z) } } #[cfg(feature = "mint")] -impl Into> for Quaternion { +impl Into> for Quaternion { fn into(self) -> mint::Quaternion { mint::Quaternion { v: mint::Vector3 { @@ -205,7 +205,7 @@ impl Into> for Quaternion { } #[cfg(feature = "mint")] -impl Into> for UnitQuaternion { +impl Into> for UnitQuaternion { fn into(self) -> mint::Quaternion { mint::Quaternion { v: mint::Vector3 { @@ -218,37 +218,203 @@ impl Into> for UnitQuaternion { } } -impl From> for Matrix4 { +impl From> for Matrix4 +where + N::Element: SimdRealField, +{ #[inline] fn from(q: UnitQuaternion) -> Self { q.to_homogeneous() } } -impl From> for Rotation3 { +impl From> for Rotation3 +where + N::Element: SimdRealField, +{ #[inline] fn from(q: UnitQuaternion) -> Self { q.to_rotation_matrix() } } -impl From> for UnitQuaternion { +impl From> for UnitQuaternion +where + N::Element: SimdRealField, +{ #[inline] fn from(q: Rotation3) -> Self { Self::from_rotation_matrix(&q) } } -impl From> for Matrix3 { +impl From> for Matrix3 +where + N::Element: SimdRealField, +{ #[inline] fn from(q: UnitQuaternion) -> Self { q.to_rotation_matrix().into_inner() } } -impl From> for Quaternion { +impl From> for Quaternion { #[inline] fn from(coords: Vector4) -> Self { Self { coords } } } + +impl From<[Quaternion; 2]> for Quaternion +where + N: From<[::Element; 2]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 2]) -> Self { + Self::from(Vector4::from([arr[0].coords, arr[1].coords])) + } +} + +impl From<[Quaternion; 4]> for Quaternion +where + N: From<[::Element; 4]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 4]) -> Self { + Self::from(Vector4::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + ])) + } +} + +impl From<[Quaternion; 8]> for Quaternion +where + N: From<[::Element; 8]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 8]) -> Self { + Self::from(Vector4::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + ])) + } +} + +impl From<[Quaternion; 16]> for Quaternion +where + N: From<[::Element; 16]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 16]) -> Self { + Self::from(Vector4::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + arr[8].coords, + arr[9].coords, + arr[10].coords, + arr[11].coords, + arr[12].coords, + arr[13].coords, + arr[14].coords, + arr[15].coords, + ])) + } +} + +impl From<[UnitQuaternion; 2]> + for UnitQuaternion +where + N: From<[::Element; 2]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 2]) -> Self { + Self::new_unchecked(Quaternion::from([arr[0].into_inner(), arr[1].into_inner()])) + } +} + +impl From<[UnitQuaternion; 4]> + for UnitQuaternion +where + N: From<[::Element; 4]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 4]) -> Self { + Self::new_unchecked(Quaternion::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + ])) + } +} + +impl From<[UnitQuaternion; 8]> + for UnitQuaternion +where + N: From<[::Element; 8]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 8]) -> Self { + Self::new_unchecked(Quaternion::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + arr[4].into_inner(), + arr[5].into_inner(), + arr[6].into_inner(), + arr[7].into_inner(), + ])) + } +} + +impl From<[UnitQuaternion; 16]> + for UnitQuaternion +where + N: From<[::Element; 16]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 16]) -> Self { + Self::new_unchecked(Quaternion::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + arr[4].into_inner(), + arr[5].into_inner(), + arr[6].into_inner(), + arr[7].into_inner(), + arr[8].into_inner(), + arr[9].into_inner(), + arr[10].into_inner(), + arr[11].into_inner(), + arr[12].into_inner(), + arr[13].into_inner(), + arr[14].into_inner(), + arr[15].into_inner(), + ])) + } +} diff --git a/src/geometry/quaternion_coordinates.rs b/src/geometry/quaternion_coordinates.rs index a9399f18..0d318087 100644 --- a/src/geometry/quaternion_coordinates.rs +++ b/src/geometry/quaternion_coordinates.rs @@ -1,13 +1,14 @@ use std::mem; use std::ops::{Deref, DerefMut}; -use alga::general::RealField; +use simba::simd::SimdValue; use crate::base::coordinates::IJKW; +use crate::Scalar; use crate::geometry::Quaternion; -impl Deref for Quaternion { +impl Deref for Quaternion { type Target = IJKW; #[inline] @@ -16,7 +17,7 @@ impl Deref for Quaternion { } } -impl DerefMut for Quaternion { +impl DerefMut for Quaternion { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { mem::transmute(self) } diff --git a/src/geometry/quaternion_ops.rs b/src/geometry/quaternion_ops.rs index 7f2b274a..e18c1b16 100644 --- a/src/geometry/quaternion_ops.rs +++ b/src/geometry/quaternion_ops.rs @@ -54,16 +54,15 @@ use std::ops::{ Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, }; -use alga::general::RealField; - use crate::base::allocator::Allocator; use crate::base::dimension::{U1, U3, U4}; use crate::base::storage::Storage; use crate::base::{DefaultAllocator, Unit, Vector, Vector3}; +use crate::SimdRealField; use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion}; -impl Index for Quaternion { +impl Index for Quaternion { type Output = N; #[inline] @@ -72,7 +71,7 @@ impl Index for Quaternion { } } -impl IndexMut for Quaternion { +impl IndexMut for Quaternion { #[inline] fn index_mut(&mut self, i: usize) -> &mut N { &mut self.coords[i] @@ -85,8 +84,9 @@ macro_rules! quaternion_op_impl( $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty $(=> $VDimA: ty, $VDimB: ty)*; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs - where DefaultAllocator: Allocator + + impl<$($lives ,)* N: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where N::Element: SimdRealField, + DefaultAllocator: Allocator + Allocator { type Output = $Result; @@ -121,11 +121,11 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Add, add; - (U4, U1), (U4, U1); - self: Quaternion, rhs: Quaternion, Output = Quaternion; - Quaternion::from(self.coords + rhs.coords); - ); +Add, add; +(U4, U1), (U4, U1); +self: Quaternion, rhs: Quaternion, Output = Quaternion; +Quaternion::from(self.coords + rhs.coords); +); // Quaternion - Quaternion quaternion_op_impl!( @@ -150,11 +150,11 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Sub, sub; - (U4, U1), (U4, U1); - self: Quaternion, rhs: Quaternion, Output = Quaternion; - Quaternion::from(self.coords - rhs.coords); - ); +Sub, sub; +(U4, U1), (U4, U1); +self: Quaternion, rhs: Quaternion, Output = Quaternion; +Quaternion::from(self.coords - rhs.coords); +); // Quaternion × Quaternion quaternion_op_impl!( @@ -183,11 +183,11 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U4, U1), (U4, U1); - self: Quaternion, rhs: Quaternion, Output = Quaternion; - &self * &rhs; - ); +Mul, mul; +(U4, U1), (U4, U1); +self: Quaternion, rhs: Quaternion, Output = Quaternion; +&self * &rhs; +); // UnitQuaternion × UnitQuaternion quaternion_op_impl!( @@ -212,11 +212,11 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U4, U1), (U4, U1); - self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; - &self * &rhs; - ); +Mul, mul; +(U4, U1), (U4, U1); +self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; +&self * &rhs; +); // UnitQuaternion ÷ UnitQuaternion quaternion_op_impl!( @@ -241,11 +241,11 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Div, div; - (U4, U1), (U4, U1); - self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; - &self / &rhs; - ); +Div, div; +(U4, U1), (U4, U1); +self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; +&self / &rhs; +); // UnitQuaternion × Rotation quaternion_op_impl!( @@ -274,12 +274,12 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U4, U1), (U3, U3); - self: UnitQuaternion, rhs: Rotation, - Output = UnitQuaternion => U3, U3; - self * UnitQuaternion::::from_rotation_matrix(&rhs); - ); +Mul, mul; +(U4, U1), (U3, U3); +self: UnitQuaternion, rhs: Rotation, +Output = UnitQuaternion => U3, U3; +self * UnitQuaternion::::from_rotation_matrix(&rhs); +); // UnitQuaternion ÷ Rotation quaternion_op_impl!( @@ -308,12 +308,12 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Div, div; - (U4, U1), (U3, U3); - self: UnitQuaternion, rhs: Rotation, - Output = UnitQuaternion => U3, U3; - self / UnitQuaternion::::from_rotation_matrix(&rhs); - ); +Div, div; +(U4, U1), (U3, U3); +self: UnitQuaternion, rhs: Rotation, +Output = UnitQuaternion => U3, U3; +self / UnitQuaternion::::from_rotation_matrix(&rhs); +); // Rotation × UnitQuaternion quaternion_op_impl!( @@ -342,12 +342,12 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U3, U3), (U4, U1); - self: Rotation, rhs: UnitQuaternion, - Output = UnitQuaternion => U3, U3; - UnitQuaternion::::from_rotation_matrix(&self) * rhs; - ); +Mul, mul; +(U3, U3), (U4, U1); +self: Rotation, rhs: UnitQuaternion, +Output = UnitQuaternion => U3, U3; +UnitQuaternion::::from_rotation_matrix(&self) * rhs; +); // Rotation ÷ UnitQuaternion quaternion_op_impl!( @@ -376,12 +376,12 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Div, div; - (U3, U3), (U4, U1); - self: Rotation, rhs: UnitQuaternion, - Output = UnitQuaternion => U3, U3; - UnitQuaternion::::from_rotation_matrix(&self) / rhs; - ); +Div, div; +(U3, U3), (U4, U1); +self: Rotation, rhs: UnitQuaternion, +Output = UnitQuaternion => U3, U3; +UnitQuaternion::::from_rotation_matrix(&self) / rhs; +); // UnitQuaternion × Vector quaternion_op_impl!( @@ -415,12 +415,12 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U4, U1), (U3, U1) for SB: Storage ; - self: UnitQuaternion, rhs: Vector, - Output = Vector3 => U3, U4; - &self * &rhs; - ); +Mul, mul; +(U4, U1), (U3, U1) for SB: Storage ; +self: UnitQuaternion, rhs: Vector, +Output = Vector3 => U3, U4; +&self * &rhs; +); // UnitQuaternion × Point quaternion_op_impl!( @@ -448,12 +448,12 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U4, U1), (U3, U1); - self: UnitQuaternion, rhs: Point3, - Output = Point3 => U3, U4; - Point3::from(self * rhs.coords); - ); +Mul, mul; +(U4, U1), (U3, U1); +self: UnitQuaternion, rhs: Point3, +Output = Point3 => U3, U4; +Point3::from(self * rhs.coords); +); // UnitQuaternion × Unit quaternion_op_impl!( @@ -481,16 +481,17 @@ quaternion_op_impl!( 'b); quaternion_op_impl!( - Mul, mul; - (U4, U1), (U3, U1) for SB: Storage ; - self: UnitQuaternion, rhs: Unit>, - Output = Unit> => U3, U4; - Unit::new_unchecked(self * rhs.into_inner()); - ); +Mul, mul; +(U4, U1), (U3, U1) for SB: Storage ; +self: UnitQuaternion, rhs: Unit>, +Output = Unit> => U3, U4; +Unit::new_unchecked(self * rhs.into_inner()); +); macro_rules! scalar_op_impl( ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$( - impl $Op for Quaternion { + impl $Op for Quaternion + where N::Element: SimdRealField { type Output = Quaternion; #[inline] @@ -499,7 +500,8 @@ macro_rules! scalar_op_impl( } } - impl<'a, N: RealField> $Op for &'a Quaternion { + impl<'a, N: SimdRealField> $Op for &'a Quaternion + where N::Element: SimdRealField { type Output = Quaternion; #[inline] @@ -508,7 +510,8 @@ macro_rules! scalar_op_impl( } } - impl $OpAssign for Quaternion { + impl $OpAssign for Quaternion + where N::Element: SimdRealField { #[inline] fn $op_assign(&mut self, n: N) { @@ -547,7 +550,10 @@ macro_rules! left_scalar_mul_impl( left_scalar_mul_impl!(f32, f64); -impl Neg for Quaternion { +impl Neg for Quaternion +where + N::Element: SimdRealField, +{ type Output = Quaternion; #[inline] @@ -556,7 +562,10 @@ impl Neg for Quaternion { } } -impl<'a, N: RealField> Neg for &'a Quaternion { +impl<'a, N: SimdRealField> Neg for &'a Quaternion +where + N::Element: SimdRealField, +{ type Output = Quaternion; #[inline] @@ -570,8 +579,9 @@ macro_rules! quaternion_op_impl( ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident); $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField> $OpAssign<$Rhs> for $Lhs - where DefaultAllocator: Allocator + + impl<$($lives ,)* N: SimdRealField> $OpAssign<$Rhs> for $Lhs + where N::Element: SimdRealField, + DefaultAllocator: Allocator + Allocator { #[inline] diff --git a/src/geometry/quaternion_simba.rs b/src/geometry/quaternion_simba.rs new file mode 100755 index 00000000..b43db8d9 --- /dev/null +++ b/src/geometry/quaternion_simba.rs @@ -0,0 +1,92 @@ +use simba::simd::SimdValue; + +use crate::base::Vector4; +use crate::geometry::{Quaternion, UnitQuaternion}; +use crate::Scalar; + +impl SimdValue for Quaternion +where + N::Element: Scalar, +{ + type Element = Quaternion; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + Vector4::splat(val.coords).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.coords.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.coords.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.coords.replace(i, val.coords) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.coords.replace_unchecked(i, val.coords) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.coords.select(cond, other.coords).into() + } +} + +impl SimdValue for UnitQuaternion +where + N::Element: Scalar, +{ + type Element = UnitQuaternion; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + UnitQuaternion::new_unchecked(Quaternion::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + UnitQuaternion::new_unchecked(self.as_ref().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + UnitQuaternion::new_unchecked(self.as_ref().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + UnitQuaternion::new_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/src/geometry/reflection.rs b/src/geometry/reflection.rs index b4658a11..c0500e84 100644 --- a/src/geometry/reflection.rs +++ b/src/geometry/reflection.rs @@ -1,9 +1,9 @@ -use alga::general::ComplexField; use crate::base::allocator::Allocator; use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint}; use crate::base::{DefaultAllocator, Matrix, Scalar, Unit, Vector}; use crate::dimension::{Dim, DimName, U1}; use crate::storage::{Storage, StorageMut}; +use simba::scalar::ComplexField; use crate::geometry::Point; @@ -27,10 +27,7 @@ impl> Reflection { /// Creates a new reflection wrt. the plane orthogonal to the given axis and that contains the /// point `pt`. - pub fn new_containing_point( - axis: Unit>, - pt: &Point, - ) -> Self + pub fn new_containing_point(axis: Unit>, pt: &Point) -> Self where D: DimName, DefaultAllocator: Allocator, @@ -64,9 +61,9 @@ impl> Reflection { // FIXME: naming convention: reflect_to, reflect_assign ? /// Applies the reflection to the columns of `rhs`. pub fn reflect_with_sign(&self, rhs: &mut Matrix, sign: N) - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { for i in 0..rhs.ncols() { // NOTE: we borrow the column twice here. First it is borrowed immutably for the diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 2cf8822c..c6cd3d86 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -14,7 +14,8 @@ use crate::base::storage::Owned; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::RealField; +use simba::scalar::RealField; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; @@ -25,7 +26,8 @@ use crate::geometry::Point; #[repr(C)] #[derive(Debug)] pub struct Rotation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { matrix: MatrixN, } @@ -86,7 +88,9 @@ where Owned: Serialize, { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.matrix.serialize(serializer) } } @@ -98,7 +102,9 @@ where Owned: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let matrix = MatrixN::::deserialize(deserializer)?; Ok(Self::from_matrix_unchecked(matrix)) @@ -106,7 +112,8 @@ where } impl Rotation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// A reference to the underlying matrix representation of this rotation. /// @@ -175,7 +182,7 @@ where DefaultAllocator: Allocator /// Unwraps the underlying matrix. /// Deprecated: Use [Rotation::into_inner] instead. - #[deprecated(note="use `.into_inner()` instead")] + #[deprecated(note = "use `.into_inner()` instead")] #[inline] pub fn unwrap(self) -> MatrixN { self.matrix @@ -354,8 +361,10 @@ where DefaultAllocator: Allocator } } -impl Rotation -where DefaultAllocator: Allocator + Allocator +impl Rotation +where + N::Element: SimdRealField, + DefaultAllocator: Allocator + Allocator, { /// Rotate the given point. /// @@ -437,7 +446,8 @@ where DefaultAllocator: Allocator + Allocator impl Eq for Rotation where DefaultAllocator: Allocator {} impl PartialEq for Rotation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn eq(&self, right: &Self) -> bool { @@ -481,8 +491,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.matrix .relative_eq(&other.matrix, epsilon, max_relative) } diff --git a/src/geometry/rotation_alga.rs b/src/geometry/rotation_alga.rs index c4133e41..f37ebbd1 100755 --- a/src/geometry/rotation_alga.rs +++ b/src/geometry/rotation_alga.rs @@ -1,6 +1,6 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::{ self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, @@ -18,8 +18,10 @@ use crate::geometry::{Point, Rotation}; * Algebraic structures. * */ -impl Identity for Rotation -where DefaultAllocator: Allocator +impl Identity + for Rotation +where + DefaultAllocator: Allocator, { #[inline] fn identity() -> Self { @@ -27,8 +29,10 @@ where DefaultAllocator: Allocator } } -impl TwoSidedInverse for Rotation -where DefaultAllocator: Allocator +impl TwoSidedInverse + for Rotation +where + DefaultAllocator: Allocator, { #[inline] #[must_use = "Did you mean to use two_sided_inverse_mut()?"] @@ -42,8 +46,10 @@ where DefaultAllocator: Allocator } } -impl AbstractMagma for Rotation -where DefaultAllocator: Allocator +impl AbstractMagma + for Rotation +where + DefaultAllocator: Allocator, { #[inline] fn operate(&self, rhs: &Self) -> Self { @@ -53,7 +59,7 @@ where DefaultAllocator: Allocator macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for Rotation + impl $marker<$operator> for Rotation where DefaultAllocator: Allocator { } )*} ); @@ -71,8 +77,10 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Rotation -where DefaultAllocator: Allocator + Allocator +impl Transformation> + for Rotation +where + DefaultAllocator: Allocator + Allocator, { #[inline] fn transform_point(&self, pt: &Point) -> Point { @@ -85,8 +93,10 @@ where DefaultAllocator: Allocator + Allocator } } -impl ProjectiveTransformation> for Rotation -where DefaultAllocator: Allocator + Allocator +impl ProjectiveTransformation> + for Rotation +where + DefaultAllocator: Allocator + Allocator, { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { @@ -99,8 +109,10 @@ where DefaultAllocator: Allocator + Allocator } } -impl AffineTransformation> for Rotation -where DefaultAllocator: Allocator + Allocator +impl AffineTransformation> + for Rotation +where + DefaultAllocator: Allocator + Allocator, { type Rotation = Self; type NonUniformScaling = Id; @@ -142,8 +154,9 @@ where DefaultAllocator: Allocator + Allocator } } -impl Similarity> for Rotation -where DefaultAllocator: Allocator + Allocator +impl Similarity> for Rotation +where + DefaultAllocator: Allocator + Allocator, { type Scaling = Id; @@ -165,7 +178,7 @@ where DefaultAllocator: Allocator + Allocator macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for Rotation + impl $Trait> for Rotation where DefaultAllocator: Allocator + Allocator { } )*} @@ -174,8 +187,10 @@ macro_rules! marker_impl( marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); /// Subgroups of the n-dimensional rotation group `SO(n)`. -impl linear::Rotation> for Rotation -where DefaultAllocator: Allocator + Allocator +impl linear::Rotation> + for Rotation +where + DefaultAllocator: Allocator + Allocator, { #[inline] fn powf(&self, _: N) -> Option { @@ -200,7 +215,7 @@ where DefaultAllocator: Allocator + Allocator } /* -impl Matrix for Rotation { +impl Matrix for Rotation { type Field = N; type Row = Matrix; type Column = Matrix; @@ -242,7 +257,7 @@ impl Matrix for Rotation { } } -impl SquareMatrix for Rotation { +impl SquareMatrix for Rotation { type Vector = Matrix; #[inline] @@ -272,5 +287,5 @@ impl SquareMatrix for Rotation { } } -impl InversibleSquareMatrix for Rotation { } +impl InversibleSquareMatrix for Rotation { } */ diff --git a/src/geometry/rotation_construction.rs b/src/geometry/rotation_construction.rs index a7779cc6..12d93402 100644 --- a/src/geometry/rotation_construction.rs +++ b/src/geometry/rotation_construction.rs @@ -1,6 +1,6 @@ use num::{One, Zero}; -use alga::general::{ClosedAdd, ClosedMul}; +use simba::scalar::{ClosedAdd, ClosedMul}; use crate::base::allocator::Allocator; use crate::base::dimension::DimName; diff --git a/src/geometry/rotation_conversion.rs b/src/geometry/rotation_conversion.rs index ac314221..c49b92c4 100644 --- a/src/geometry/rotation_conversion.rs +++ b/src/geometry/rotation_conversion.rs @@ -1,18 +1,18 @@ use num::Zero; -use alga::general::{RealField, SubsetOf, SupersetOf}; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdValue}; #[cfg(feature = "mint")] use mint; use crate::base::allocator::Allocator; use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; -use crate::base::{DefaultAllocator, Matrix2, Matrix3, Matrix4, MatrixN}; +use crate::base::{DefaultAllocator, Matrix2, Matrix3, Matrix4, MatrixN, Scalar}; use crate::geometry::{ - Isometry, Point, Rotation, Rotation2, Rotation3, Similarity, SuperTCategoryOf, TAffine, - Transform, Translation, UnitComplex, UnitQuaternion, + AbstractRotation, Isometry, Rotation, Rotation2, Rotation3, Similarity, SuperTCategoryOf, + TAffine, Transform, Translation, UnitComplex, UnitQuaternion, }; /* @@ -47,7 +47,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(rot: &Rotation) -> Self { + fn from_superset_unchecked(rot: &Rotation) -> Self { Rotation::from_matrix_unchecked(rot.matrix().to_subset_unchecked()) } } @@ -69,7 +69,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(q: &UnitQuaternion) -> Self { + fn from_superset_unchecked(q: &UnitQuaternion) -> Self { let q: UnitQuaternion = crate::convert_ref_unchecked(q); q.to_rotation_matrix() } @@ -92,7 +92,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(q: &UnitComplex) -> Self { + fn from_superset_unchecked(q: &UnitComplex) -> Self { let q: UnitComplex = crate::convert_ref_unchecked(q); q.to_rotation_matrix() } @@ -102,7 +102,7 @@ impl SubsetOf> for Rotation where N1: RealField, N2: RealField + SupersetOf, - R: AlgaRotation> + SupersetOf, + R: AbstractRotation + SupersetOf, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -116,7 +116,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { + fn from_superset_unchecked(iso: &Isometry) -> Self { crate::convert_ref_unchecked(&iso.rotation) } } @@ -125,7 +125,7 @@ impl SubsetOf> for Rotation where N1: RealField, N2: RealField + SupersetOf, - R: AlgaRotation> + SupersetOf, + R: AbstractRotation + SupersetOf, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -139,7 +139,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + fn from_superset_unchecked(sim: &Similarity) -> Self { crate::convert_ref_unchecked(&sim.isometry.rotation) } } @@ -168,7 +168,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -204,7 +204,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { + fn from_superset_unchecked(m: &MatrixN>) -> Self { let r = m.fixed_slice::(0, 0); Self::from_matrix_unchecked(crate::convert_unchecked(r.into_owned())) } @@ -219,7 +219,7 @@ impl From> for Rotation3 { impl From> for Matrix3 { #[inline] - fn from(q: Rotation2) ->Self { + fn from(q: Rotation2) -> Self { q.to_homogeneous() } } @@ -244,3 +244,89 @@ impl From> for Matrix3 { q.into_inner() } } + +impl From<[Rotation; 2]> + for Rotation +where + N: From<[::Element; 2]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Rotation; 2]) -> Self { + Self::from_matrix_unchecked(MatrixN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + ])) + } +} + +impl From<[Rotation; 4]> + for Rotation +where + N: From<[::Element; 4]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Rotation; 4]) -> Self { + Self::from_matrix_unchecked(MatrixN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + ])) + } +} + +impl From<[Rotation; 8]> + for Rotation +where + N: From<[::Element; 8]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Rotation; 8]) -> Self { + Self::from_matrix_unchecked(MatrixN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + arr[4].clone().into_inner(), + arr[5].clone().into_inner(), + arr[6].clone().into_inner(), + arr[7].clone().into_inner(), + ])) + } +} + +impl From<[Rotation; 16]> + for Rotation +where + N: From<[::Element; 16]>, + N::Element: Scalar + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Rotation; 16]) -> Self { + Self::from_matrix_unchecked(MatrixN::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + arr[4].clone().into_inner(), + arr[5].clone().into_inner(), + arr[6].clone().into_inner(), + arr[7].clone().into_inner(), + arr[8].clone().into_inner(), + arr[9].clone().into_inner(), + arr[10].clone().into_inner(), + arr[11].clone().into_inner(), + arr[12].clone().into_inner(), + arr[13].clone().into_inner(), + arr[14].clone().into_inner(), + arr[15].clone().into_inner(), + ])) + } +} diff --git a/src/geometry/rotation_ops.rs b/src/geometry/rotation_ops.rs index ed555b6b..b3330877 100644 --- a/src/geometry/rotation_ops.rs +++ b/src/geometry/rotation_ops.rs @@ -20,7 +20,7 @@ use num::{One, Zero}; use std::ops::{Div, DivAssign, Index, Mul, MulAssign}; -use alga::general::{ClosedAdd, ClosedMul}; +use simba::scalar::{ClosedAdd, ClosedMul}; use crate::base::allocator::Allocator; use crate::base::constraint::{AreMultipliable, ShapeConstraint}; @@ -31,7 +31,8 @@ use crate::base::{DefaultAllocator, Matrix, MatrixMN, Scalar, Unit, Vector, Vect use crate::geometry::{Point, Rotation}; impl Index<(usize, usize)> for Rotation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type Output = N; diff --git a/src/geometry/rotation_simba.rs b/src/geometry/rotation_simba.rs new file mode 100755 index 00000000..cb064a81 --- /dev/null +++ b/src/geometry/rotation_simba.rs @@ -0,0 +1,54 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, MatrixN, Scalar}; + +use crate::geometry::Rotation; + +impl SimdValue for Rotation +where + N: Scalar + SimdValue, + D: DimName, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + type Element = Rotation; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + Rotation::from_matrix_unchecked(MatrixN::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Rotation::from_matrix_unchecked(self.matrix().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Rotation::from_matrix_unchecked(self.matrix().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Rotation::from_matrix_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 4baec27c..1ee4a9df 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -3,10 +3,11 @@ use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; -use alga::general::RealField; use num::Zero; use rand::distributions::{Distribution, OpenClosed01, Standard}; use rand::Rng; +use simba::scalar::RealField; +use simba::simd::{SimdBool, SimdRealField}; use std::ops::Neg; use crate::base::dimension::{U1, U2, U3}; @@ -20,7 +21,7 @@ use crate::geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; * 2D Rotation matrix. * */ -impl Rotation2 { +impl Rotation2 { /// Builds a 2 dimensional rotation matrix from an angle in radian. /// /// # Example @@ -34,7 +35,7 @@ impl Rotation2 { /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0)); /// ``` pub fn new(angle: N) -> Self { - let (sia, coa) = angle.sin_cos(); + let (sia, coa) = angle.simd_sin_cos(); Self::from_matrix_unchecked(Matrix2::new(coa, -sia, sia, coa)) } @@ -53,7 +54,10 @@ impl Rotation2 { /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - pub fn from_matrix(m: &Matrix2) -> Self { + pub fn from_matrix(m: &Matrix2) -> Self + where + N: RealField, + { Self::from_matrix_eps(m, N::default_epsilon(), 0, Self::identity()) } @@ -69,7 +73,10 @@ impl Rotation2 { /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close /// to the actual solution is provided. Can be set to `Rotation2::identity()` if no other /// guesses come to mind. - pub fn from_matrix_eps(m: &Matrix2, eps: N, mut max_iter: usize, guess: Self) -> Self { + pub fn from_matrix_eps(m: &Matrix2, eps: N, mut max_iter: usize, guess: Self) -> Self + where + N: RealField, + { if max_iter == 0 { max_iter = usize::max_value(); } @@ -77,10 +84,8 @@ impl Rotation2 { let mut rot = guess.into_inner(); for _ in 0..max_iter { - let axis = rot.column(0).perp(&m.column(0)) + - rot.column(1).perp(&m.column(1)); - let denom = rot.column(0).dot(&m.column(0)) + - rot.column(1).dot(&m.column(1)); + let axis = rot.column(0).perp(&m.column(0)) + rot.column(1).perp(&m.column(1)); + let denom = rot.column(0).dot(&m.column(0)) + rot.column(1).dot(&m.column(1)); let angle = axis / (denom.abs() + N::default_epsilon()); if angle.abs() > eps { @@ -110,6 +115,7 @@ impl Rotation2 { #[inline] pub fn rotation_between(a: &Vector, b: &Vector) -> Self where + N: RealField, SB: Storage, SC: Storage, { @@ -137,6 +143,7 @@ impl Rotation2 { s: N, ) -> Self where + N: RealField, SB: Storage, SC: Storage, { @@ -154,7 +161,7 @@ impl Rotation2 { /// ``` #[inline] pub fn angle(&self) -> N { - self.matrix()[(1, 0)].atan2(self.matrix()[(0, 0)]) + self.matrix()[(1, 0)].simd_atan2(self.matrix()[(0, 0)]) } /// The rotation angle needed to make `self` and `other` coincide. @@ -192,18 +199,19 @@ impl Rotation2 { other * self.inverse() } - /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated /// computations might cause the matrix from progressively not being orthonormal anymore. #[inline] - pub fn renormalize(&mut self) { + pub fn renormalize(&mut self) + where + N: RealField, + { let mut c = UnitComplex::from(*self); let _ = c.renormalize(); *self = Self::from_matrix_eps(self.matrix(), N::default_epsilon(), 0, c.into()) } - /// Raise the quaternion to a given floating power, i.e., returns the rotation with the angle /// of `self` multiplied by `n`. /// @@ -230,19 +238,23 @@ impl Rotation2 { } } -impl Distribution> for Standard -where OpenClosed01: Distribution +impl Distribution> for Standard +where + N::Element: SimdRealField, + OpenClosed01: Distribution, { /// Generate a uniformly distributed random rotation. #[inline] fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Rotation2 { - Rotation2::new(rng.sample(OpenClosed01) * N::two_pi()) + Rotation2::new(rng.sample(OpenClosed01) * N::simd_two_pi()) } } #[cfg(feature = "arbitrary")] -impl Arbitrary for Rotation2 -where Owned: Send +impl Arbitrary for Rotation2 +where + N::Element: SimdRealField, + Owned: Send, { #[inline] fn arbitrary(g: &mut G) -> Self { @@ -255,7 +267,10 @@ where Owned: Send * 3D Rotation matrix. * */ -impl Rotation3 { +impl Rotation3 +where + N::Element: SimdRealField, +{ /// Builds a 3 dimensional rotation matrix from an axis and an angle. /// /// # Arguments @@ -290,7 +305,10 @@ impl Rotation3 { /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - pub fn from_matrix(m: &Matrix3) -> Self { + pub fn from_matrix(m: &Matrix3) -> Self + where + N: RealField, + { Self::from_matrix_eps(m, N::default_epsilon(), 0, Self::identity()) } @@ -306,7 +324,10 @@ impl Rotation3 { /// * `guess`: a guess of the solution. Convergence will be significantly faster if an initial solution close /// to the actual solution is provided. Can be set to `Rotation3::identity()` if no other /// guesses come to mind. - pub fn from_matrix_eps(m: &Matrix3, eps: N, mut max_iter: usize, guess: Self) -> Self { + pub fn from_matrix_eps(m: &Matrix3, eps: N, mut max_iter: usize, guess: Self) -> Self + where + N: RealField, + { if max_iter == 0 { max_iter = usize::max_value(); } @@ -314,12 +335,12 @@ impl Rotation3 { let mut rot = guess.into_inner(); for _ in 0..max_iter { - let axis = rot.column(0).cross(&m.column(0)) + - rot.column(1).cross(&m.column(1)) + - rot.column(2).cross(&m.column(2)); - let denom = rot.column(0).dot(&m.column(0)) + - rot.column(1).dot(&m.column(1)) + - rot.column(2).dot(&m.column(2)); + let axis = rot.column(0).cross(&m.column(0)) + + rot.column(1).cross(&m.column(1)) + + rot.column(2).cross(&m.column(2)); + let denom = rot.column(0).dot(&m.column(0)) + + rot.column(1).dot(&m.column(1)) + + rot.column(2).dot(&m.column(2)); let axisangle = axis / (denom.abs() + N::default_epsilon()); @@ -381,31 +402,34 @@ impl Rotation3 { /// assert_eq!(Rotation3::from_scaled_axis(Vector3::::zeros()), Rotation3::identity()); /// ``` pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self - where SB: Storage { - if angle.is_zero() { - Self::identity() - } else { - let ux = axis.as_ref()[0]; - let uy = axis.as_ref()[1]; - let uz = axis.as_ref()[2]; - let sqx = ux * ux; - let sqy = uy * uy; - let sqz = uz * uz; - let (sin, cos) = angle.sin_cos(); - let one_m_cos = N::one() - cos; + where + SB: Storage, + { + angle.simd_ne(N::zero()).if_else( + || { + let ux = axis.as_ref()[0]; + let uy = axis.as_ref()[1]; + let uz = axis.as_ref()[2]; + let sqx = ux * ux; + let sqy = uy * uy; + let sqz = uz * uz; + let (sin, cos) = angle.simd_sin_cos(); + let one_m_cos = N::one() - cos; - Self::from_matrix_unchecked(MatrixN::::new( - sqx + (N::one() - sqx) * cos, - ux * uy * one_m_cos - uz * sin, - ux * uz * one_m_cos + uy * sin, - ux * uy * one_m_cos + uz * sin, - sqy + (N::one() - sqy) * cos, - uy * uz * one_m_cos - ux * sin, - ux * uz * one_m_cos - uy * sin, - uy * uz * one_m_cos + ux * sin, - sqz + (N::one() - sqz) * cos, - )) - } + Self::from_matrix_unchecked(MatrixN::::new( + sqx + (N::one() - sqx) * cos, + ux * uy * one_m_cos - uz * sin, + ux * uz * one_m_cos + uy * sin, + ux * uy * one_m_cos + uz * sin, + sqy + (N::one() - sqy) * cos, + uy * uz * one_m_cos - ux * sin, + ux * uz * one_m_cos - uy * sin, + uy * uz * one_m_cos + ux * sin, + sqz + (N::one() - sqz) * cos, + )) + }, + || Self::identity(), + ) } /// Creates a new rotation from Euler angles. @@ -423,9 +447,9 @@ impl Rotation3 { /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); /// ``` pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { - let (sr, cr) = roll.sin_cos(); - let (sp, cp) = pitch.sin_cos(); - let (sy, cy) = yaw.sin_cos(); + let (sr, cr) = roll.simd_sin_cos(); + let (sp, cp) = pitch.simd_sin_cos(); + let (sy, cy) = yaw.simd_sin_cos(); Self::from_matrix_unchecked(MatrixN::::new( cy * cp, @@ -444,7 +468,10 @@ impl Rotation3 { /// /// The angles are produced in the form (roll, pitch, yaw). #[deprecated(note = "This is renamed to use `.euler_angles()`.")] - pub fn to_euler_angles(&self) -> (N, N, N) { + pub fn to_euler_angles(&self) -> (N, N, N) + where + N: RealField, + { self.euler_angles() } @@ -462,7 +489,10 @@ impl Rotation3 { /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); /// ``` - pub fn euler_angles(&self) -> (N, N, N) { + pub fn euler_angles(&self) -> (N, N, N) + where + N: RealField, + { // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh // https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 if self[(2, 0)].abs() < N::one() { @@ -484,7 +514,10 @@ impl Rotation3 { /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated /// computations might cause the matrix from progressively not being orthonormal anymore. #[inline] - pub fn renormalize(&mut self) { + pub fn renormalize(&mut self) + where + N: RealField, + { let mut c = UnitQuaternion::from(*self); let _ = c.renormalize(); @@ -528,7 +561,7 @@ impl Rotation3 { } /// Deprecated: Use [Rotation3::face_towards] instead. - #[deprecated(note="renamed to `face_towards`")] + #[deprecated(note = "renamed to `face_towards`")] pub fn new_observer_frames(dir: &Vector, up: &Vector) -> Self where SB: Storage, @@ -616,6 +649,7 @@ impl Rotation3 { #[inline] pub fn rotation_between(a: &Vector, b: &Vector) -> Option where + N: RealField, SB: Storage, SC: Storage, { @@ -643,6 +677,7 @@ impl Rotation3 { n: N, ) -> Option where + N: RealField, SB: Storage, SC: Storage, { @@ -681,7 +716,7 @@ impl Rotation3 { pub fn angle(&self) -> N { ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) / crate::convert(2.0)) - .acos() + .simd_acos() } /// The rotation axis. Returns `None` if the rotation angle is zero or PI. @@ -700,7 +735,10 @@ impl Rotation3 { /// assert!(rot.axis().is_none()); /// ``` #[inline] - pub fn axis(&self) -> Option>> { + pub fn axis(&self) -> Option>> + where + N: RealField, + { let axis = VectorN::::new( self.matrix()[(2, 1)] - self.matrix()[(1, 2)], self.matrix()[(0, 2)] - self.matrix()[(2, 0)], @@ -721,7 +759,10 @@ impl Rotation3 { /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6); /// ``` #[inline] - pub fn scaled_axis(&self) -> Vector3 { + pub fn scaled_axis(&self) -> Vector3 + where + N: RealField, + { if let Some(axis) = self.axis() { axis.into_inner() * self.angle() } else { @@ -749,7 +790,10 @@ impl Rotation3 { /// assert!(rot.axis_angle().is_none()); /// ``` #[inline] - pub fn axis_angle(&self) -> Option<(Unit>, N)> { + pub fn axis_angle(&self) -> Option<(Unit>, N)> + where + N: RealField, + { if let Some(axis) = self.axis() { Some((axis, self.angle())) } else { @@ -805,7 +849,10 @@ impl Rotation3 { /// assert_eq!(pow.angle(), 2.4); /// ``` #[inline] - pub fn powf(&self, n: N) -> Self { + pub fn powf(&self, n: N) -> Self + where + N: RealField, + { if let Some(axis) = self.axis() { Self::from_axis_angle(&axis, self.angle() * n) } else if self.matrix()[(0, 0)] < N::zero() { @@ -817,8 +864,10 @@ impl Rotation3 { } } -impl Distribution> for Standard -where OpenClosed01: Distribution +impl Distribution> for Standard +where + N::Element: SimdRealField, + OpenClosed01: Distribution, { /// Generate a uniformly distributed random rotation. #[inline] @@ -828,8 +877,8 @@ where OpenClosed01: Distribution // In D. Kirk, editor, Graphics Gems III, pages 117-120. Academic, New York, 1992. // Compute a random rotation around Z - let theta = N::two_pi() * rng.sample(OpenClosed01); - let (ts, tc) = theta.sin_cos(); + let theta = N::simd_two_pi() * rng.sample(OpenClosed01); + let (ts, tc) = theta.simd_sin_cos(); let a = MatrixN::::new( tc, ts, @@ -843,11 +892,11 @@ where OpenClosed01: Distribution ); // Compute a random rotation *of* Z - let phi = N::two_pi() * rng.sample(OpenClosed01); + let phi = N::simd_two_pi() * rng.sample(OpenClosed01); let z = rng.sample(OpenClosed01); - let (ps, pc) = phi.sin_cos(); - let sqrt_z = z.sqrt(); - let v = Vector3::new(pc * sqrt_z, ps * sqrt_z, (N::one() - z).sqrt()); + let (ps, pc) = phi.simd_sin_cos(); + let sqrt_z = z.simd_sqrt(); + let v = Vector3::new(pc * sqrt_z, ps * sqrt_z, (N::one() - z).simd_sqrt()); let mut b = v * v.transpose(); b += b; b -= MatrixN::::identity(); @@ -857,8 +906,9 @@ where OpenClosed01: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Rotation3 +impl Arbitrary for Rotation3 where + N::Element: SimdRealField, Owned: Send, Owned: Send, { diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 9f5fee41..fab54759 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -1,6 +1,8 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::Zero; use std::fmt; use std::hash; + #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; @@ -10,14 +12,14 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{RealField, SubsetOf}; -use alga::linear::Rotation; +use simba::scalar::{RealField, SubsetOf}; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::storage::Owned; -use crate::base::{DefaultAllocator, MatrixN, VectorN}; -use crate::geometry::{Isometry, Point, Translation}; +use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. #[repr(C)] @@ -25,24 +27,21 @@ use crate::geometry::{Isometry, Point, Translation}; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "N: Serialize, + serde(bound(serialize = "N: Serialize, R: Serialize, DefaultAllocator: Allocator, - Owned: Serialize" - )) + Owned: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "N: Deserialize<'de>, + serde(bound(deserialize = "N: Deserialize<'de>, R: Deserialize<'de>, DefaultAllocator: Allocator, - Owned: Deserialize<'de>" - )) + Owned: Deserialize<'de>")) )] -pub struct Similarity -where DefaultAllocator: Allocator +pub struct Similarity +where + DefaultAllocator: Allocator, { /// The part of this similarity that does not include the scaling factor. pub isometry: Isometry, @@ -50,7 +49,7 @@ where DefaultAllocator: Allocator } #[cfg(feature = "abomonation-serialize")] -impl Abomonation for Similarity +impl Abomonation for Similarity where Isometry: Abomonation, DefaultAllocator: Allocator, @@ -68,7 +67,7 @@ where } } -impl hash::Hash +impl hash::Hash for Similarity where DefaultAllocator: Allocator, @@ -80,51 +79,72 @@ where } } -impl> + Copy> Copy for Similarity +impl + Copy> Copy + for Similarity where DefaultAllocator: Allocator, Owned: Copy, -{} +{ +} -impl> + Clone> Clone for Similarity -where DefaultAllocator: Allocator +impl + Clone> Clone for Similarity +where + DefaultAllocator: Allocator, { #[inline] fn clone(&self) -> Self { - Similarity::from_isometry(self.isometry.clone(), self.scaling) + Similarity::from_isometry(self.isometry.clone(), self.scaling.clone()) } } -impl Similarity +impl Similarity where - R: Rotation>, + R: AbstractRotation, DefaultAllocator: Allocator, { /// Creates a new similarity from its rotational and translational parts. #[inline] - pub fn from_parts( - translation: Translation, - rotation: R, - scaling: N, - ) -> Self - { + pub fn from_parts(translation: Translation, rotation: R, scaling: N) -> Self { Self::from_isometry(Isometry::from_parts(translation, rotation), scaling) } /// Creates a new similarity from its rotational and translational parts. #[inline] pub fn from_isometry(isometry: Isometry, scaling: N) -> Self { - assert!( - !relative_eq!(scaling, N::zero()), - "The scaling factor must not be zero." - ); + assert!(!scaling.is_zero(), "The scaling factor must not be zero."); - Self { - isometry: isometry, - scaling: scaling, - } + Self { isometry, scaling } } + /// The scaling factor of this similarity transformation. + #[inline] + pub fn set_scaling(&mut self, scaling: N) { + assert!( + !scaling.is_zero(), + "The similarity scaling factor must not be zero." + ); + + self.scaling = scaling; + } +} + +impl Similarity +where + DefaultAllocator: Allocator, +{ + /// The scaling factor of this similarity transformation. + #[inline] + pub fn scaling(&self) -> N { + self.scaling.inlined_clone() + } +} + +impl Similarity +where + N::Element: SimdRealField, + R: AbstractRotation, + DefaultAllocator: Allocator, +{ /// Creates a new similarity that applies only a scaling factor. #[inline] pub fn from_scaling(scaling: N) -> Self { @@ -148,29 +168,12 @@ where self.isometry.translation.vector *= self.scaling; } - /// The scaling factor of this similarity transformation. - #[inline] - pub fn set_scaling(&mut self, scaling: N) { - assert!( - !relative_eq!(scaling, N::zero()), - "The similarity scaling factor must not be zero." - ); - - self.scaling = scaling; - } - - /// The scaling factor of this similarity transformation. - #[inline] - pub fn scaling(&self) -> N { - self.scaling - } - /// The similarity transformation that applies a scaling factor `scaling` before `self`. #[inline] #[must_use = "Did you mean to use prepend_scaling_mut()?"] pub fn prepend_scaling(&self, scaling: N) -> Self { assert!( - !relative_eq!(scaling, N::zero()), + !scaling.is_zero(), "The similarity scaling factor must not be zero." ); @@ -182,7 +185,7 @@ where #[must_use = "Did you mean to use append_scaling_mut()?"] pub fn append_scaling(&self, scaling: N) -> Self { assert!( - !relative_eq!(scaling, N::zero()), + !scaling.is_zero(), "The similarity scaling factor must not be zero." ); @@ -197,7 +200,7 @@ where #[inline] pub fn prepend_scaling_mut(&mut self, scaling: N) { assert!( - !relative_eq!(scaling, N::zero()), + !scaling.is_zero(), "The similarity scaling factor must not be zero." ); @@ -208,7 +211,7 @@ where #[inline] pub fn append_scaling_mut(&mut self, scaling: N) { assert!( - !relative_eq!(scaling, N::zero()), + !scaling.is_zero(), "The similarity scaling factor must not be zero." ); @@ -328,8 +331,9 @@ where // and makes it harder to use it, e.g., for Transform × Isometry implementation. // This is OK since all constructors of the isometry enforce the Rotation bound already (and // explicit struct construction is prevented by the private scaling factor). -impl Similarity -where DefaultAllocator: Allocator +impl Similarity +where + DefaultAllocator: Allocator, { /// Converts this similarity into its equivalent homogeneous transformation matrix. #[inline] @@ -349,15 +353,16 @@ where DefaultAllocator: Allocator } } -impl Eq for Similarity +impl Eq for Similarity where - R: Rotation> + Eq, + R: AbstractRotation + Eq, DefaultAllocator: Allocator, -{} +{ +} -impl PartialEq for Similarity +impl PartialEq for Similarity where - R: Rotation> + PartialEq, + R: AbstractRotation + PartialEq, DefaultAllocator: Allocator, { #[inline] @@ -368,7 +373,7 @@ where impl AbsDiffEq for Similarity where - R: Rotation> + AbsDiffEq, + R: AbstractRotation + AbsDiffEq, DefaultAllocator: Allocator, N::Epsilon: Copy, { @@ -388,7 +393,7 @@ where impl RelativeEq for Similarity where - R: Rotation> + RelativeEq, + R: AbstractRotation + RelativeEq, DefaultAllocator: Allocator, N::Epsilon: Copy, { @@ -403,8 +408,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.isometry .relative_eq(&other.isometry, epsilon, max_relative) && self @@ -415,7 +419,7 @@ where impl UlpsEq for Similarity where - R: Rotation> + UlpsEq, + R: AbstractRotation + UlpsEq, DefaultAllocator: Allocator, N::Epsilon: Copy, { @@ -439,7 +443,7 @@ where impl fmt::Display for Similarity where N: RealField + fmt::Display, - R: Rotation> + fmt::Display, + R: AbstractRotation + fmt::Display, DefaultAllocator: Allocator + Allocator, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/geometry/similarity_alga.rs b/src/geometry/similarity_alga.rs index c3df94c1..58dd4563 100755 --- a/src/geometry/similarity_alga.rs +++ b/src/geometry/similarity_alga.rs @@ -1,6 +1,6 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, RealField, + AbstractSemigroup, Identity, Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::Similarity as AlgaSimilarity; use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation}; @@ -9,16 +9,17 @@ use crate::base::allocator::Allocator; use crate::base::dimension::DimName; use crate::base::{DefaultAllocator, VectorN}; -use crate::geometry::{Point, Similarity, Translation}; +use crate::geometry::{AbstractRotation, Point, Similarity, Translation}; /* * * Algebraic structures. * */ -impl Identity for Similarity +impl Identity + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -27,9 +28,10 @@ where } } -impl TwoSidedInverse for Similarity +impl TwoSidedInverse + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -44,9 +46,10 @@ where } } -impl AbstractMagma for Similarity +impl AbstractMagma + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -57,8 +60,8 @@ where macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for Similarity - where R: Rotation>, + impl $marker<$operator> for Similarity + where R: Rotation> + AbstractRotation, DefaultAllocator: Allocator { } )*} ); @@ -76,9 +79,10 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Similarity +impl Transformation> + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -92,9 +96,10 @@ where } } -impl ProjectiveTransformation> for Similarity +impl ProjectiveTransformation> + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { #[inline] @@ -108,9 +113,10 @@ where } } -impl AffineTransformation> for Similarity +impl AffineTransformation> + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { type NonUniformScaling = N; @@ -123,7 +129,7 @@ where self.isometry.translation.clone(), self.isometry.rotation.clone(), self.scaling(), - R::identity(), + >::identity(), ) } @@ -144,7 +150,7 @@ where #[inline] fn prepend_rotation(&self, r: &Self::Rotation) -> Self { - self * r + Similarity::from_isometry(self.isometry.prepend_rotation(r), self.scaling()) } #[inline] @@ -165,9 +171,10 @@ where } } -impl AlgaSimilarity> for Similarity +impl AlgaSimilarity> + for Similarity where - R: Rotation>, + R: Rotation> + AbstractRotation, DefaultAllocator: Allocator, { type Scaling = N; diff --git a/src/geometry/similarity_construction.rs b/src/geometry/similarity_construction.rs index a3722ba9..510758cf 100644 --- a/src/geometry/similarity_construction.rs +++ b/src/geometry/similarity_construction.rs @@ -7,21 +7,22 @@ use num::One; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use alga::general::RealField; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::RealField; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, U2, U3}; use crate::base::{DefaultAllocator, Vector2, Vector3}; use crate::geometry::{ - Isometry, Point, Point3, Rotation2, Rotation3, Similarity, Translation, UnitComplex, - UnitQuaternion, + AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Similarity, Translation, + UnitComplex, UnitQuaternion, }; -impl Similarity +impl Similarity where - R: AlgaRotation>, + N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator, { /// Creates a new identity similarity. @@ -45,9 +46,10 @@ where } } -impl One for Similarity +impl One for Similarity where - R: AlgaRotation>, + N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator, { /// Creates a new identity similarity. @@ -59,7 +61,7 @@ where impl Distribution> for Standard where - R: AlgaRotation>, + R: AbstractRotation, DefaultAllocator: Allocator, Standard: Distribution + Distribution, { @@ -74,9 +76,10 @@ where } } -impl Similarity +impl Similarity where - R: AlgaRotation>, + N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator, { /// The similarity that applies the scaling factor `scaling`, followed by the rotation `r` with @@ -105,14 +108,15 @@ where impl Arbitrary for Similarity where N: RealField + Arbitrary + Send, - R: AlgaRotation> + Arbitrary + Send, + N::Element: RealField, + R: AbstractRotation + Arbitrary + Send, DefaultAllocator: Allocator, Owned: Send, { #[inline] fn arbitrary(rng: &mut G) -> Self { - let mut s = Arbitrary::arbitrary(rng); - while relative_eq!(s, N::zero()) { + let mut s: N = Arbitrary::arbitrary(rng); + while s.is_zero() { s = Arbitrary::arbitrary(rng) } @@ -126,8 +130,11 @@ where * */ -// 2D rotation. -impl Similarity> { +// 2D similarity. +impl Similarity> +where + N::Element: SimdRealField, +{ /// Creates a new similarity from a translation, a rotation, and an uniform scaling factor. /// /// # Example @@ -150,7 +157,10 @@ impl Similarity> { } } -impl Similarity> { +impl Similarity> +where + N::Element: SimdRealField, +{ /// Creates a new similarity from a translation and a rotation angle. /// /// # Example @@ -176,7 +186,8 @@ impl Similarity> { // 3D rotation. macro_rules! similarity_construction_impl( ($Rot: ty) => { - impl Similarity { + impl Similarity + where N::Element: SimdRealField { /// Creates a new similarity from a translation, rotation axis-angle, and scaling /// factor. /// @@ -203,7 +214,8 @@ macro_rules! similarity_construction_impl( /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5); /// ``` #[inline] - pub fn new(translation: Vector3, axisangle: Vector3, scaling: N) -> Self { + pub fn new(translation: Vector3, axisangle: Vector3, scaling: N) -> Self + { Self::from_isometry(Isometry::<_, U3, $Rot>::new(translation, axisangle), scaling) } diff --git a/src/geometry/similarity_conversion.rs b/src/geometry/similarity_conversion.rs index a0d207e4..7953bc47 100644 --- a/src/geometry/similarity_conversion.rs +++ b/src/geometry/similarity_conversion.rs @@ -1,11 +1,15 @@ -use alga::general::{RealField, SubsetOf, SupersetOf}; -use alga::linear::Rotation; +use num::Zero; + +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; -use crate::base::{DefaultAllocator, MatrixN}; +use crate::base::{DefaultAllocator, MatrixN, Scalar}; -use crate::geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; +use crate::geometry::{ + AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, +}; /* * This file provides the following conversions: @@ -20,8 +24,8 @@ impl SubsetOf> for Similarity< where N1: RealField + SubsetOf, N2: RealField + SupersetOf, - R1: Rotation> + SubsetOf, - R2: Rotation>, + R1: AbstractRotation + SubsetOf, + R2: AbstractRotation, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -36,7 +40,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + fn from_superset_unchecked(sim: &Similarity) -> Self { Similarity::from_isometry( sim.isometry.to_subset_unchecked(), sim.scaling().to_subset_unchecked(), @@ -49,7 +53,7 @@ where N1: RealField, N2: RealField + SupersetOf, C: SuperTCategoryOf, - R: Rotation> + R: AbstractRotation + SubsetOf>> + SubsetOf>>, D: DimNameAdd + DimMin, // needed by .determinant() @@ -73,7 +77,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -82,7 +86,7 @@ impl SubsetOf>> for Similarity, - R: Rotation> + R: AbstractRotation + SubsetOf>> + SubsetOf>>, D: DimNameAdd + DimMin, // needed by .determinant() @@ -137,7 +141,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { + fn from_superset_unchecked(m: &MatrixN>) -> Self { let mut mm = m.clone_owned(); let na = mm.fixed_slice_mut::(0, 0).normalize_mut(); let nb = mm.fixed_slice_mut::(0, 1).normalize_mut(); @@ -159,11 +163,15 @@ where vector: crate::convert_unchecked(t), }; - Self::from_parts(t, crate::convert_unchecked(mm), crate::convert_unchecked(scale)) + Self::from_parts( + t, + crate::convert_unchecked(mm), + crate::convert_unchecked(scale), + ) } } -impl From> for MatrixN> +impl From> for MatrixN> where D: DimNameAdd, R: SubsetOf>>, @@ -174,3 +182,141 @@ where sim.to_homogeneous() } } + +impl + From<[Similarity; 2]> for Similarity +where + N: From<[::Element; 2]>, + R: SimdValue + AbstractRotation + From<[::Element; 2]>, + R::Element: AbstractRotation, + N::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Similarity; 2]) -> Self { + let iso = Isometry::from([arr[0].isometry.clone(), arr[1].isometry.clone()]); + let scale = N::from([arr[0].scaling(), arr[1].scaling()]); + + Self::from_isometry(iso, scale) + } +} + +impl + From<[Similarity; 4]> for Similarity +where + N: From<[::Element; 4]>, + R: SimdValue + AbstractRotation + From<[::Element; 4]>, + R::Element: AbstractRotation, + N::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Similarity; 4]) -> Self { + let iso = Isometry::from([ + arr[0].isometry.clone(), + arr[1].isometry.clone(), + arr[2].isometry.clone(), + arr[3].isometry.clone(), + ]); + let scale = N::from([ + arr[0].scaling(), + arr[1].scaling(), + arr[2].scaling(), + arr[3].scaling(), + ]); + + Self::from_isometry(iso, scale) + } +} + +impl + From<[Similarity; 8]> for Similarity +where + N: From<[::Element; 8]>, + R: SimdValue + AbstractRotation + From<[::Element; 8]>, + R::Element: AbstractRotation, + N::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Similarity; 8]) -> Self { + let iso = Isometry::from([ + arr[0].isometry.clone(), + arr[1].isometry.clone(), + arr[2].isometry.clone(), + arr[3].isometry.clone(), + arr[4].isometry.clone(), + arr[5].isometry.clone(), + arr[6].isometry.clone(), + arr[7].isometry.clone(), + ]); + let scale = N::from([ + arr[0].scaling(), + arr[1].scaling(), + arr[2].scaling(), + arr[3].scaling(), + arr[4].scaling(), + arr[5].scaling(), + arr[6].scaling(), + arr[7].scaling(), + ]); + + Self::from_isometry(iso, scale) + } +} + +impl + From<[Similarity; 16]> for Similarity +where + N: From<[::Element; 16]>, + R: SimdValue + AbstractRotation + From<[::Element; 16]>, + R::Element: AbstractRotation, + N::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Similarity; 16]) -> Self { + let iso = Isometry::from([ + arr[0].isometry.clone(), + arr[1].isometry.clone(), + arr[2].isometry.clone(), + arr[3].isometry.clone(), + arr[4].isometry.clone(), + arr[5].isometry.clone(), + arr[6].isometry.clone(), + arr[7].isometry.clone(), + arr[8].isometry.clone(), + arr[9].isometry.clone(), + arr[10].isometry.clone(), + arr[11].isometry.clone(), + arr[12].isometry.clone(), + arr[13].isometry.clone(), + arr[14].isometry.clone(), + arr[15].isometry.clone(), + ]); + let scale = N::from([ + arr[0].scaling(), + arr[1].scaling(), + arr[2].scaling(), + arr[3].scaling(), + arr[4].scaling(), + arr[5].scaling(), + arr[6].scaling(), + arr[7].scaling(), + arr[8].scaling(), + arr[9].scaling(), + arr[10].scaling(), + arr[11].scaling(), + arr[12].scaling(), + arr[13].scaling(), + arr[14].scaling(), + arr[15].scaling(), + ]); + + Self::from_isometry(iso, scale) + } +} diff --git a/src/geometry/similarity_ops.rs b/src/geometry/similarity_ops.rs index 80d84b86..9043a667 100644 --- a/src/geometry/similarity_ops.rs +++ b/src/geometry/similarity_ops.rs @@ -1,13 +1,17 @@ +use num::{One, Zero}; use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::RealField; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::{ClosedAdd, ClosedMul}; +use simba::simd::SimdRealField; use crate::base::allocator::Allocator; -use crate::base::dimension::{DimName, U1, U3, U4}; -use crate::base::{DefaultAllocator, VectorN}; +use crate::base::dimension::{DimName, U1, U2, U3, U4}; +use crate::base::{DefaultAllocator, Scalar, VectorN}; -use crate::geometry::{Isometry, Point, Rotation, Similarity, Translation, UnitQuaternion}; +use crate::geometry::{ + AbstractRotation, Isometry, Point, Rotation, Similarity, Translation, UnitComplex, + UnitQuaternion, +}; // FIXME: there are several cloning of rotations that we could probably get rid of (but we didn't // yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` @@ -66,8 +70,9 @@ macro_rules! similarity_binop_impl( ($Op: ident, $op: ident; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField, D: DimName, R> $Op<$Rhs> for $Lhs - where R: AlgaRotation>, + impl<$($lives ,)* N: SimdRealField, D: DimName, R> $Op<$Rhs> for $Lhs + where N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator { type Output = $Output; @@ -113,8 +118,9 @@ macro_rules! similarity_binop_assign_impl_all( $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; [val] => $action_val: expr; [ref] => $action_ref: expr;) => { - impl $OpAssign<$Rhs> for $Lhs - where R: AlgaRotation>, + impl $OpAssign<$Rhs> for $Lhs + where N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: $Rhs) { @@ -122,8 +128,9 @@ macro_rules! similarity_binop_assign_impl_all( } } - impl<'b, N: RealField, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs - where R: AlgaRotation>, + impl<'b, N: SimdRealField, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs + where N::Element: SimdRealField, + R: AbstractRotation, DefaultAllocator: Allocator { #[inline] fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { @@ -159,6 +166,7 @@ similarity_binop_impl_all!( // Similarity ×= Translation similarity_binop_assign_impl_all!( + MulAssign, mul_assign; self: Similarity, rhs: Translation; [val] => *self *= &rhs; @@ -211,51 +219,55 @@ similarity_binop_assign_impl_all!( // Similarity ×= R // Similarity ÷= R -similarity_binop_assign_impl_all!( - MulAssign, mul_assign; - self: Similarity, rhs: R; +md_assign_impl_all!( + MulAssign, mul_assign where N: SimdRealField for N::Element: SimdRealField; + (D, U1), (D, D) for D: DimName; + self: Similarity>, rhs: Rotation; [val] => self.isometry.rotation *= rhs; [ref] => self.isometry.rotation *= rhs.clone(); ); -similarity_binop_assign_impl_all!( - DivAssign, div_assign; - self: Similarity, rhs: R; +md_assign_impl_all!( + DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; + (D, U1), (D, D) for D: DimName; + self: Similarity>, rhs: Rotation; // FIXME: don't invert explicitly? - [val] => *self *= rhs.two_sided_inverse(); - [ref] => *self *= rhs.two_sided_inverse(); + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); ); -// Similarity × R -// Similarity ÷ R -similarity_binop_impl_all!( - Mul, mul; - self: Similarity, rhs: R, Output = Similarity; - [val val] => { - let scaling = self.scaling(); - Similarity::from_isometry(self.isometry * rhs, scaling) - }; - [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); - [val ref] => { - let scaling = self.scaling(); - Similarity::from_isometry(self.isometry * rhs, scaling) - }; - [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +md_assign_impl_all!( + MulAssign, mul_assign where N: SimdRealField for N::Element: SimdRealField; + (U3, U3), (U3, U3) for; + self: Similarity>, rhs: UnitQuaternion; + [val] => self.isometry.rotation *= rhs; + [ref] => self.isometry.rotation *= rhs.clone(); ); -similarity_binop_impl_all!( - Div, div; - self: Similarity, rhs: R, Output = Similarity; - [val val] => { - let scaling = self.scaling(); - Similarity::from_isometry(self.isometry / rhs, scaling) - }; - [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); - [val ref] => { - let scaling = self.scaling(); - Similarity::from_isometry(self.isometry / rhs, scaling) - }; - [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +md_assign_impl_all!( + DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; + (U3, U3), (U3, U3) for; + self: Similarity>, rhs: UnitQuaternion; + // FIXME: don't invert explicitly? + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); +); + +md_assign_impl_all!( + MulAssign, mul_assign where N: SimdRealField for N::Element: SimdRealField; + (U2, U2), (U2, U2) for; + self: Similarity>, rhs: UnitComplex; + [val] => self.isometry.rotation *= rhs; + [ref] => self.isometry.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where N: SimdRealField for N::Element: SimdRealField; + (U2, U2), (U2, U2) for; + self: Similarity>, rhs: UnitComplex; + // FIXME: don't invert explicitly? + [val] => *self *= rhs.inverse(); + [ref] => *self *= rhs.inverse(); ); // Similarity × Isometry @@ -379,8 +391,9 @@ macro_rules! similarity_from_composition_impl( ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(for $Dims: ident: $DimsBound: ident),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs - where DefaultAllocator: Allocator + + impl<$($lives ,)* N: SimdRealField $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + where N::Element: SimdRealField, + DefaultAllocator: Allocator + Allocator { type Output = $Output; @@ -427,6 +440,24 @@ macro_rules! similarity_from_composition_impl_all( } ); +// Similarity × Rotation +similarity_from_composition_impl_all!( + Mul, mul; + (D, D), (D, U1) for D: DimName; + self: Similarity>, rhs: Rotation, + Output = Similarity>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +); + // Rotation × Similarity similarity_from_composition_impl_all!( Mul, mul; @@ -439,6 +470,24 @@ similarity_from_composition_impl_all!( [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); ); +// Similarity ÷ Rotation +similarity_from_composition_impl_all!( + Div, div; + (D, D), (D, U1) for D: DimName; + self: Similarity>, rhs: Rotation, + Output = Similarity>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +); + // Rotation ÷ Similarity similarity_from_composition_impl_all!( Div, div; @@ -452,6 +501,24 @@ similarity_from_composition_impl_all!( [ref ref] => self * right.inverse(); ); +// Similarity × UnitQuaternion +similarity_from_composition_impl_all!( + Mul, mul; + (U4, U1), (U3, U1); + self: Similarity>, rhs: UnitQuaternion, + Output = Similarity>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +); + // UnitQuaternion × Similarity similarity_from_composition_impl_all!( Mul, mul; @@ -464,6 +531,24 @@ similarity_from_composition_impl_all!( [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); ); +// Similarity ÷ UnitQuaternion +similarity_from_composition_impl_all!( + Div, div; + (U4, U1), (U3, U1); + self: Similarity>, rhs: UnitQuaternion, + Output = Similarity>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +); + // UnitQuaternion ÷ Similarity similarity_from_composition_impl_all!( Div, div; @@ -476,3 +561,39 @@ similarity_from_composition_impl_all!( [val ref] => self * right.inverse(); [ref ref] => self * right.inverse(); ); + +// Similarity × UnitComplex +similarity_from_composition_impl_all!( + Mul, mul; + (U2, U1), (U2, U1); + self: Similarity>, rhs: UnitComplex, + Output = Similarity>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +); + +// Similarity ÷ UnitComplex +similarity_from_composition_impl_all!( + Div, div; + (U2, U1), (U2, U1); + self: Similarity>, rhs: UnitComplex, + Output = Similarity>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +); diff --git a/src/geometry/similarity_simba.rs b/src/geometry/similarity_simba.rs new file mode 100755 index 00000000..bf3858f7 --- /dev/null +++ b/src/geometry/similarity_simba.rs @@ -0,0 +1,64 @@ +use simba::simd::{SimdRealField, SimdValue}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::DefaultAllocator; + +use crate::geometry::{AbstractRotation, Isometry, Similarity}; + +impl SimdValue for Similarity +where + N::Element: SimdRealField, + R: SimdValue + AbstractRotation, + R::Element: AbstractRotation, + DefaultAllocator: Allocator + Allocator, +{ + type Element = Similarity; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + let scaling = N::splat(val.scaling()); + Similarity::from_isometry(Isometry::splat(val.isometry), scaling) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Similarity::from_isometry(self.isometry.extract(i), self.scaling().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Similarity::from_isometry( + self.isometry.extract_unchecked(i), + self.scaling().extract_unchecked(i), + ) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + let mut s = self.scaling(); + s.replace(i, val.scaling()); + self.set_scaling(s); + self.isometry.replace(i, val.isometry); + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + let mut s = self.scaling(); + s.replace_unchecked(i, val.scaling()); + self.set_scaling(s); + self.isometry.replace_unchecked(i, val.isometry); + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + let scaling = self.scaling().select(cond, other.scaling()); + Similarity::from_isometry(self.isometry.select(cond, other.isometry), scaling) + } +} diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index a8570c9d..42586509 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use alga::general::{RealField, TwoSidedInverse}; +use simba::scalar::RealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; @@ -158,7 +158,8 @@ super_tcategory_impl!( #[repr(C)] #[derive(Debug)] pub struct Transform, C: TCategory> -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { matrix: MatrixN>, _phantom: PhantomData, @@ -181,7 +182,8 @@ where } impl, C: TCategory> Clone for Transform -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { #[inline] fn clone(&self) -> Self { @@ -196,7 +198,9 @@ where Owned, DimNameSum>: Serialize, { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.matrix.serialize(serializer) } } @@ -208,18 +212,23 @@ where Owned, DimNameSum>: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let matrix = MatrixN::>::deserialize(deserializer)?; Ok(Transform::from_matrix_unchecked(matrix)) } } -impl, C: TCategory> Eq for Transform where DefaultAllocator: Allocator, DimNameSum> -{} +impl, C: TCategory> Eq for Transform where + DefaultAllocator: Allocator, DimNameSum> +{ +} impl, C: TCategory> PartialEq for Transform -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { #[inline] fn eq(&self, right: &Self) -> bool { @@ -228,7 +237,8 @@ where DefaultAllocator: Allocator, DimNameSum> } impl, C: TCategory> Transform -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { /// Creates a new transformation from the given homogeneous matrix. The transformation category /// of `Self` is not checked to be verified by the given matrix. @@ -259,7 +269,7 @@ where DefaultAllocator: Allocator, DimNameSum> /// Retrieves the underlying matrix. /// Deprecated: Use [Transform::into_inner] instead. - #[deprecated(note="use `.into_inner()` instead")] + #[deprecated(note = "use `.into_inner()` instead")] #[inline] pub fn unwrap(self) -> MatrixN> { self.matrix @@ -398,7 +408,9 @@ where DefaultAllocator: Allocator, DimNameSum> #[inline] #[must_use = "Did you mean to use inverse_mut()?"] pub fn inverse(self) -> Transform - where C: SubTCategoryOf { + where + C: SubTCategoryOf, + { // FIXME: specialize for TAffine? Transform::from_matrix_unchecked(self.matrix.try_inverse().unwrap()) } @@ -451,7 +463,9 @@ where DefaultAllocator: Allocator, DimNameSum> /// ``` #[inline] pub fn inverse_mut(&mut self) - where C: SubTCategoryOf { + where + C: SubTCategoryOf, + { let _ = self.matrix.try_inverse_mut(); } } @@ -484,8 +498,9 @@ where } impl, C: TCategory> Transform -where C: SubTCategoryOf, - DefaultAllocator: Allocator, DimNameSum> +where + C: SubTCategoryOf, + DefaultAllocator: Allocator, DimNameSum> + Allocator> + Allocator + Allocator, @@ -495,7 +510,7 @@ where C: SubTCategoryOf, /// the point. #[inline] pub fn inverse_transform_point(&self, pt: &Point) -> Point { - self.two_sided_inverse() * pt + self.clone().inverse() * pt } /// Transform the given vector by the inverse of this transformation. @@ -503,12 +518,13 @@ where C: SubTCategoryOf, /// the vector. #[inline] pub fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { - self.two_sided_inverse() * v + self.clone().inverse() * v } } impl> Transform -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this /// transformation category is not `TGeneral`. @@ -552,8 +568,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.matrix .relative_eq(&other.matrix, epsilon, max_relative) } diff --git a/src/geometry/transform_alga.rs b/src/geometry/transform_alga.rs index 65fbb32f..3ba6eb7d 100755 --- a/src/geometry/transform_alga.rs +++ b/src/geometry/transform_alga.rs @@ -1,6 +1,6 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, RealField, + AbstractSemigroup, Identity, Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::{ProjectiveTransformation, Transformation}; @@ -15,7 +15,8 @@ use crate::geometry::{Point, SubTCategoryOf, TCategory, TProjective, Transform}; * Algebraic structures. * */ -impl, C> Identity for Transform +impl, C> Identity + for Transform where C: TCategory, DefaultAllocator: Allocator, DimNameSum>, @@ -26,7 +27,8 @@ where } } -impl, C> TwoSidedInverse for Transform +impl, C> TwoSidedInverse + for Transform where C: SubTCategoryOf, DefaultAllocator: Allocator, DimNameSum>, @@ -43,7 +45,8 @@ where } } -impl, C> AbstractMagma for Transform +impl, C> AbstractMagma + for Transform where C: TCategory, DefaultAllocator: Allocator, DimNameSum>, @@ -56,7 +59,7 @@ where macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl, C> $marker<$operator> for Transform + impl, C> $marker<$operator> for Transform where C: TCategory, DefaultAllocator: Allocator, DimNameSum> { } )*} @@ -64,7 +67,7 @@ macro_rules! impl_multiplicative_structures( macro_rules! impl_inversible_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl, C> $marker<$operator> for Transform + impl, C> $marker<$operator> for Transform where C: SubTCategoryOf, DefaultAllocator: Allocator, DimNameSum> { } )*} @@ -88,7 +91,7 @@ impl_inversible_multiplicative_structures!( */ impl, C> Transformation> for Transform where - N: RealField, + N: RealField + simba::scalar::RealField, C: TCategory, DefaultAllocator: Allocator, DimNameSum> + Allocator> @@ -108,7 +111,7 @@ where impl, C> ProjectiveTransformation> for Transform where - N: RealField, + N: RealField + simba::scalar::RealField, C: SubTCategoryOf, DefaultAllocator: Allocator, DimNameSum> + Allocator> diff --git a/src/geometry/transform_construction.rs b/src/geometry/transform_construction.rs index 1b23daba..e0826eeb 100644 --- a/src/geometry/transform_construction.rs +++ b/src/geometry/transform_construction.rs @@ -1,6 +1,6 @@ use num::One; -use alga::general::RealField; +use simba::scalar::RealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; @@ -9,7 +9,8 @@ use crate::base::{DefaultAllocator, MatrixN}; use crate::geometry::{TCategory, Transform}; impl, C: TCategory> Transform -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { /// Creates a new identity transform. /// @@ -46,7 +47,8 @@ where DefaultAllocator: Allocator, DimNameSum> } impl, C: TCategory> One for Transform -where DefaultAllocator: Allocator, DimNameSum> +where + DefaultAllocator: Allocator, DimNameSum>, { /// Creates a new identity transform. #[inline] diff --git a/src/geometry/transform_conversion.rs b/src/geometry/transform_conversion.rs index a0e00291..6c531f84 100644 --- a/src/geometry/transform_conversion.rs +++ b/src/geometry/transform_conversion.rs @@ -1,4 +1,4 @@ -use alga::general::{RealField, SubsetOf}; +use simba::scalar::{RealField, SubsetOf}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; @@ -29,7 +29,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -56,7 +56,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { + fn from_superset_unchecked(m: &MatrixN>) -> Self { Self::from_matrix_unchecked(crate::convert_ref_unchecked(m)) } } diff --git a/src/geometry/transform_ops.rs b/src/geometry/transform_ops.rs index 4aa943e8..5773782c 100644 --- a/src/geometry/transform_ops.rs +++ b/src/geometry/transform_ops.rs @@ -1,7 +1,7 @@ use num::{One, Zero}; use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign}; -use alga::general::{ClosedAdd, ClosedMul, RealField, SubsetOf}; +use simba::scalar::{ClosedAdd, ClosedMul, RealField, SubsetOf}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U3, U4}; diff --git a/src/geometry/transform_simba.rs b/src/geometry/transform_simba.rs new file mode 100755 index 00000000..d50843f4 --- /dev/null +++ b/src/geometry/transform_simba.rs @@ -0,0 +1,55 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN, Scalar}; +use crate::RealField; + +use crate::geometry::{TCategory, Transform}; + +impl, C> SimdValue for Transform +where + N::Element: Scalar, + C: TCategory, + DefaultAllocator: Allocator, DimNameSum> + + Allocator, DimNameSum>, +{ + type Element = Transform; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + Transform::from_matrix_unchecked(MatrixN::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Transform::from_matrix_unchecked(self.matrix().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Transform::from_matrix_unchecked(self.matrix().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Transform::from_matrix_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 5b907f3a..88d52ce4 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{ClosedAdd, ClosedNeg, ClosedSub, RealField}; +use simba::scalar::{ClosedAdd, ClosedNeg, ClosedSub}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; @@ -24,7 +24,8 @@ use crate::geometry::Point; #[repr(C)] #[derive(Debug)] pub struct Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. @@ -45,7 +46,8 @@ impl Copy for Translation where DefaultAllocator: Allocator, Owned: Copy, -{} +{ +} impl Clone for Translation where @@ -86,7 +88,9 @@ where Owned: Serialize, { fn serialize(&self, serializer: S) -> Result - where S: Serializer { + where + S: Serializer, + { self.vector.serialize(serializer) } } @@ -98,7 +102,9 @@ where Owned: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result - where Des: Deserializer<'a> { + where + Des: Deserializer<'a>, + { let matrix = VectorN::::deserialize(deserializer)?; Ok(Translation::from(matrix)) @@ -106,7 +112,8 @@ where } impl Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Creates a new translation from the given vector. #[inline] @@ -132,7 +139,9 @@ where DefaultAllocator: Allocator #[inline] #[must_use = "Did you mean to use inverse_mut()?"] pub fn inverse(&self) -> Translation - where N: ClosedNeg { + where + N: ClosedNeg, + { Translation::from(-&self.vector) } @@ -188,13 +197,16 @@ where DefaultAllocator: Allocator /// ``` #[inline] pub fn inverse_mut(&mut self) - where N: ClosedNeg { + where + N: ClosedNeg, + { self.vector.neg_mut() } } impl Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Translate the given point. /// @@ -213,7 +225,8 @@ where DefaultAllocator: Allocator } impl Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Translate the given point by the inverse of this translation. /// @@ -232,7 +245,8 @@ where DefaultAllocator: Allocator impl Eq for Translation where DefaultAllocator: Allocator {} impl PartialEq for Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn eq(&self, right: &Translation) -> bool { @@ -274,8 +288,7 @@ where other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.vector .relative_eq(&other.vector, epsilon, max_relative) } @@ -302,8 +315,9 @@ where * Display * */ -impl fmt::Display for Translation -where DefaultAllocator: Allocator + Allocator +impl fmt::Display for Translation +where + DefaultAllocator: Allocator + Allocator, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); diff --git a/src/geometry/translation_alga.rs b/src/geometry/translation_alga.rs index 7add6438..aba6f1f4 100755 --- a/src/geometry/translation_alga.rs +++ b/src/geometry/translation_alga.rs @@ -1,6 +1,6 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::Translation as AlgaTranslation; use alga::linear::{ @@ -19,8 +19,10 @@ use crate::geometry::{Point, Translation}; * Algebraic structures. * */ -impl Identity for Translation -where DefaultAllocator: Allocator +impl Identity + for Translation +where + DefaultAllocator: Allocator, { #[inline] fn identity() -> Self { @@ -28,8 +30,10 @@ where DefaultAllocator: Allocator } } -impl TwoSidedInverse for Translation -where DefaultAllocator: Allocator +impl TwoSidedInverse + for Translation +where + DefaultAllocator: Allocator, { #[inline] #[must_use = "Did you mean to use two_sided_inverse_mut()?"] @@ -43,8 +47,10 @@ where DefaultAllocator: Allocator } } -impl AbstractMagma for Translation -where DefaultAllocator: Allocator +impl AbstractMagma + for Translation +where + DefaultAllocator: Allocator, { #[inline] fn operate(&self, rhs: &Self) -> Self { @@ -54,7 +60,7 @@ where DefaultAllocator: Allocator macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for Translation + impl $marker<$operator> for Translation where DefaultAllocator: Allocator { } )*} ); @@ -72,8 +78,10 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Translation -where DefaultAllocator: Allocator +impl Transformation> + for Translation +where + DefaultAllocator: Allocator, { #[inline] fn transform_point(&self, pt: &Point) -> Point { @@ -86,8 +94,10 @@ where DefaultAllocator: Allocator } } -impl ProjectiveTransformation> for Translation -where DefaultAllocator: Allocator +impl ProjectiveTransformation> + for Translation +where + DefaultAllocator: Allocator, { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { @@ -100,8 +110,10 @@ where DefaultAllocator: Allocator } } -impl AffineTransformation> for Translation -where DefaultAllocator: Allocator +impl AffineTransformation> + for Translation +where + DefaultAllocator: Allocator, { type Rotation = Id; type NonUniformScaling = Id; @@ -143,8 +155,10 @@ where DefaultAllocator: Allocator } } -impl Similarity> for Translation -where DefaultAllocator: Allocator +impl Similarity> + for Translation +where + DefaultAllocator: Allocator, { type Scaling = Id; @@ -166,7 +180,7 @@ where DefaultAllocator: Allocator macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for Translation + impl $Trait> for Translation where DefaultAllocator: Allocator { } )*} ); @@ -174,8 +188,10 @@ macro_rules! marker_impl( marker_impl!(Isometry, DirectIsometry); /// Subgroups of the n-dimensional translation group `T(n)`. -impl AlgaTranslation> for Translation -where DefaultAllocator: Allocator +impl AlgaTranslation> + for Translation +where + DefaultAllocator: Allocator, { #[inline] fn to_vector(&self) -> VectorN { diff --git a/src/geometry/translation_construction.rs b/src/geometry/translation_construction.rs index 339bdd2a..9466816d 100644 --- a/src/geometry/translation_construction.rs +++ b/src/geometry/translation_construction.rs @@ -7,7 +7,7 @@ use num::{One, Zero}; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use alga::general::ClosedAdd; +use simba::scalar::ClosedAdd; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, U1, U2, U3, U4, U5, U6}; @@ -16,7 +16,8 @@ use crate::base::{DefaultAllocator, Scalar, VectorN}; use crate::geometry::Translation; impl Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Creates a new identity translation. /// @@ -39,7 +40,8 @@ where DefaultAllocator: Allocator } impl One for Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn one() -> Self { diff --git a/src/geometry/translation_conversion.rs b/src/geometry/translation_conversion.rs index b44412e6..0754a678 100644 --- a/src/geometry/translation_conversion.rs +++ b/src/geometry/translation_conversion.rs @@ -1,13 +1,15 @@ use num::{One, Zero}; -use alga::general::{RealField, SubsetOf, SupersetOf}; -use alga::linear::Rotation; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::PrimitiveSimdValue; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; -use crate::geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; +use crate::geometry::{ + AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, +}; /* * This file provides the following conversions: @@ -37,7 +39,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(rot: &Translation) -> Self { + fn from_superset_unchecked(rot: &Translation) -> Self { Translation { vector: rot.vector.to_subset_unchecked(), } @@ -48,7 +50,7 @@ impl SubsetOf> for Translation where N1: RealField, N2: RealField + SupersetOf, - R: Rotation>, + R: AbstractRotation, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -62,7 +64,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { + fn from_superset_unchecked(iso: &Isometry) -> Self { Self::from_superset_unchecked(&iso.translation) } } @@ -71,7 +73,7 @@ impl SubsetOf> for Translation, - R: Rotation>, + R: AbstractRotation, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -85,7 +87,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + fn from_superset_unchecked(sim: &Similarity) -> Self { Self::from_superset_unchecked(&sim.isometry.translation) } } @@ -112,7 +114,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -145,7 +147,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { + fn from_superset_unchecked(m: &MatrixN>) -> Self { let t = m.fixed_slice::(0, D::dim()); Self { vector: crate::convert_unchecked(t.into_owned()), @@ -165,10 +167,97 @@ where } impl From> for Translation -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn from(vector: VectorN) -> Self { Translation { vector } } } + +impl From<[Translation; 2]> + for Translation +where + N: From<[::Element; 2]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Translation; 2]) -> Self { + Self::from(VectorN::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + ])) + } +} + +impl From<[Translation; 4]> + for Translation +where + N: From<[::Element; 4]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Translation; 4]) -> Self { + Self::from(VectorN::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + ])) + } +} + +impl From<[Translation; 8]> + for Translation +where + N: From<[::Element; 8]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Translation; 8]) -> Self { + Self::from(VectorN::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + ])) + } +} + +impl From<[Translation; 16]> + for Translation +where + N: From<[::Element; 16]>, + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + #[inline] + fn from(arr: [Translation; 16]) -> Self { + Self::from(VectorN::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + arr[8].vector.clone(), + arr[9].vector.clone(), + arr[10].vector.clone(), + arr[11].vector.clone(), + arr[12].vector.clone(), + arr[13].vector.clone(), + arr[14].vector.clone(), + arr[15].vector.clone(), + ])) + } +} diff --git a/src/geometry/translation_ops.rs b/src/geometry/translation_ops.rs index 55366a05..c00b25bc 100644 --- a/src/geometry/translation_ops.rs +++ b/src/geometry/translation_ops.rs @@ -1,6 +1,6 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::{ClosedAdd, ClosedSub}; +use simba::scalar::{ClosedAdd, ClosedSub}; use crate::base::allocator::{Allocator, SameShapeAllocator}; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; diff --git a/src/geometry/translation_simba.rs b/src/geometry/translation_simba.rs new file mode 100755 index 00000000..c439a5d2 --- /dev/null +++ b/src/geometry/translation_simba.rs @@ -0,0 +1,52 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, VectorN}; +use crate::Scalar; + +use crate::geometry::Translation; + +impl SimdValue for Translation +where + N::Element: Scalar, + DefaultAllocator: Allocator + Allocator, +{ + type Element = Translation; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + VectorN::splat(val.vector).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.vector.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.vector.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.vector.replace(i, val.vector) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.vector.replace_unchecked(i, val.vector) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.vector.select(cond, other.vector).into() + } +} diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index d411d82a..a8ac5bcd 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -2,14 +2,48 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_complex::Complex; use std::fmt; -use alga::general::RealField; -use crate::base::{Matrix2, Matrix3, Unit, Vector1, Vector2}; -use crate::geometry::{Rotation2, Point2}; +use crate::base::{Matrix2, Matrix3, Normed, Unit, Vector1, Vector2}; +use crate::geometry::{Point2, Rotation2}; +use simba::scalar::RealField; +use simba::simd::SimdRealField; /// A complex number with a norm equal to 1. pub type UnitComplex = Unit>; -impl UnitComplex { +impl Normed for Complex { + type Norm = N::SimdRealField; + + #[inline] + fn norm(&self) -> N::SimdRealField { + // We don't use `.norm_sqr()` because it requires + // some very strong Num trait requirements. + (self.re * self.re + self.im * self.im).simd_sqrt() + } + + #[inline] + fn norm_squared(&self) -> N::SimdRealField { + // We don't use `.norm_sqr()` because it requires + // some very strong Num trait requirements. + self.re * self.re + self.im * self.im + } + + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.re *= n; + self.im *= n; + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.re /= n; + self.im /= n; + } +} + +impl UnitComplex +where + N::Element: SimdRealField, +{ /// The rotation angle in `]-pi; pi]` of this unit complex number. /// /// # Example @@ -20,7 +54,7 @@ impl UnitComplex { /// ``` #[inline] pub fn angle(&self) -> N { - self.im.atan2(self.re) + self.im.simd_atan2(self.re) } /// The sine of the rotation angle. @@ -66,7 +100,10 @@ impl UnitComplex { /// the `.angle()` method instead is more common. /// Returns `None` if the angle is zero. #[inline] - pub fn axis_angle(&self) -> Option<(Unit>, N)> { + pub fn axis_angle(&self) -> Option<(Unit>, N)> + where + N: RealField, + { let ang = self.angle(); if ang.is_zero() { @@ -357,8 +394,7 @@ impl RelativeEq for UnitComplex { other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, - ) -> bool - { + ) -> bool { self.re.relative_eq(&other.re, epsilon, max_relative) && self.im.relative_eq(&other.im, epsilon, max_relative) } @@ -375,4 +411,4 @@ impl UlpsEq for UnitComplex { self.re.ulps_eq(&other.re, epsilon, max_ulps) && self.im.ulps_eq(&other.im, epsilon, max_ulps) } -} \ No newline at end of file +} diff --git a/src/geometry/unit_complex_alga.rs b/src/geometry/unit_complex_alga.rs index 94cfa6e1..46e30535 100755 --- a/src/geometry/unit_complex_alga.rs +++ b/src/geometry/unit_complex_alga.rs @@ -1,6 +1,6 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, }; use alga::linear::{ AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, @@ -17,21 +17,21 @@ use crate::geometry::{Point2, UnitComplex}; * Implementations for UnitComplex. * */ -impl Identity for UnitComplex { +impl Identity for UnitComplex { #[inline] fn identity() -> Self { Self::identity() } } -impl AbstractMagma for UnitComplex { +impl AbstractMagma for UnitComplex { #[inline] fn operate(&self, rhs: &Self) -> Self { self * rhs } } -impl TwoSidedInverse for UnitComplex { +impl TwoSidedInverse for UnitComplex { #[inline] #[must_use = "Did you mean to use two_sided_inverse_mut()?"] fn two_sided_inverse(&self) -> Self { @@ -46,7 +46,7 @@ impl TwoSidedInverse for UnitComplex { macro_rules! impl_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for UnitComplex { + impl $marker<$operator> for UnitComplex { } )*} ); @@ -59,8 +59,9 @@ impl_structures!( AbstractGroup ); -impl Transformation> for UnitComplex -where DefaultAllocator: Allocator +impl Transformation> for UnitComplex +where + DefaultAllocator: Allocator, { #[inline] fn transform_point(&self, pt: &Point2) -> Point2 { @@ -73,8 +74,9 @@ where DefaultAllocator: Allocator } } -impl ProjectiveTransformation> for UnitComplex -where DefaultAllocator: Allocator +impl ProjectiveTransformation> for UnitComplex +where + DefaultAllocator: Allocator, { #[inline] fn inverse_transform_point(&self, pt: &Point2) -> Point2 { @@ -87,8 +89,9 @@ where DefaultAllocator: Allocator } } -impl AffineTransformation> for UnitComplex -where DefaultAllocator: Allocator +impl AffineTransformation> for UnitComplex +where + DefaultAllocator: Allocator, { type Rotation = Self; type NonUniformScaling = Id; @@ -130,8 +133,9 @@ where DefaultAllocator: Allocator } } -impl Similarity> for UnitComplex -where DefaultAllocator: Allocator +impl Similarity> for UnitComplex +where + DefaultAllocator: Allocator, { type Scaling = Id; @@ -153,15 +157,16 @@ where DefaultAllocator: Allocator macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for UnitComplex + impl $Trait> for UnitComplex where DefaultAllocator: Allocator { } )*} ); marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); -impl Rotation> for UnitComplex -where DefaultAllocator: Allocator +impl Rotation> for UnitComplex +where + DefaultAllocator: Allocator, { #[inline] fn powf(&self, n: N) -> Option { diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index 046142c8..cfe8d918 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -6,13 +6,17 @@ use num_complex::Complex; use rand::distributions::{Distribution, OpenClosed01, Standard}; use rand::Rng; -use alga::general::RealField; use crate::base::dimension::{U1, U2}; use crate::base::storage::Storage; -use crate::base::{Unit, Vector, Matrix2}; +use crate::base::{Matrix2, Unit, Vector}; use crate::geometry::{Rotation2, UnitComplex}; +use simba::scalar::RealField; +use simba::simd::SimdRealField; -impl UnitComplex { +impl UnitComplex +where + N::Element: SimdRealField, +{ /// The unit complex number multiplicative identity. /// /// # Example @@ -43,7 +47,7 @@ impl UnitComplex { /// ``` #[inline] pub fn new(angle: N) -> Self { - let (sin, cos) = angle.sin_cos(); + let (sin, cos) = angle.simd_sin_cos(); Self::from_cos_sin_unchecked(cos, sin) } @@ -110,7 +114,7 @@ impl UnitComplex { /// The input complex number will be normalized. Returns the norm of the complex number as well. #[inline] pub fn from_complex_and_get(q: Complex) -> (Self, N) { - let norm = (q.im * q.im + q.re * q.re).sqrt(); + let norm = (q.im * q.im + q.re * q.re).simd_sqrt(); (Self::new_unchecked(q / norm), norm) } @@ -134,7 +138,10 @@ impl UnitComplex { /// This is an iterative method. See `.from_matrix_eps` to provide mover /// convergence parameters and starting solution. /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - pub fn from_matrix(m: &Matrix2) -> Self { + pub fn from_matrix(m: &Matrix2) -> Self + where + N: RealField, + { Rotation2::from_matrix(m).into() } @@ -150,7 +157,10 @@ impl UnitComplex { /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close /// to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other /// guesses come to mind. - pub fn from_matrix_eps(m: &Matrix2, eps: N, max_iter: usize, guess: Self) -> Self { + pub fn from_matrix_eps(m: &Matrix2, eps: N, max_iter: usize, guess: Self) -> Self + where + N: RealField, + { let guess = Rotation2::from(guess); Rotation2::from_matrix_eps(m, eps, max_iter, guess).into() } @@ -171,6 +181,7 @@ impl UnitComplex { #[inline] pub fn rotation_between(a: &Vector, b: &Vector) -> Self where + N: RealField, SB: Storage, SC: Storage, { @@ -198,6 +209,7 @@ impl UnitComplex { s: N, ) -> Self where + N: RealField, SB: Storage, SC: Storage, { @@ -264,29 +276,37 @@ impl UnitComplex { let sang = na.perp(&nb); let cang = na.dot(&nb); - Self::from_angle(sang.atan2(cang) * s) + Self::from_angle(sang.simd_atan2(cang) * s) } } -impl One for UnitComplex { +impl One for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn one() -> Self { Self::identity() } } -impl Distribution> for Standard -where OpenClosed01: Distribution +impl Distribution> for Standard +where + N::Element: SimdRealField, + OpenClosed01: Distribution, { /// Generate a uniformly distributed random `UnitComplex`. #[inline] fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex { - UnitComplex::from_angle(rng.sample(OpenClosed01) * N::two_pi()) + UnitComplex::from_angle(rng.sample(OpenClosed01) * N::simd_two_pi()) } } #[cfg(feature = "arbitrary")] -impl Arbitrary for UnitComplex { +impl Arbitrary for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn arbitrary(g: &mut G) -> Self { UnitComplex::from_angle(N::arbitrary(g)) diff --git a/src/geometry/unit_complex_conversion.rs b/src/geometry/unit_complex_conversion.rs index f7fe4532..91736764 100644 --- a/src/geometry/unit_complex_conversion.rs +++ b/src/geometry/unit_complex_conversion.rs @@ -1,14 +1,14 @@ use num::Zero; use num_complex::Complex; -use alga::general::{RealField, SubsetOf, SupersetOf}; -use alga::linear::Rotation as AlgaRotation; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField}; use crate::base::dimension::U2; -use crate::base::{Matrix2, Matrix3}; +use crate::base::{Matrix2, Matrix3, Scalar}; use crate::geometry::{ - Isometry, Point2, Rotation2, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, - UnitComplex + AbstractRotation, Isometry, Rotation2, Similarity, SuperTCategoryOf, TAffine, Transform, + Translation, UnitComplex, }; /* @@ -42,7 +42,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(uq: &UnitComplex) -> Self { + fn from_superset_unchecked(uq: &UnitComplex) -> Self { Self::new_unchecked(crate::convert_ref_unchecked(uq.as_ref())) } } @@ -64,7 +64,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(rot: &Rotation2) -> Self { + fn from_superset_unchecked(rot: &Rotation2) -> Self { let q = UnitComplex::::from_rotation_matrix(rot); crate::convert_unchecked(q) } @@ -74,7 +74,7 @@ impl SubsetOf> for UnitComplex where N1: RealField, N2: RealField + SupersetOf, - R: AlgaRotation> + SupersetOf, + R: AbstractRotation + SupersetOf, { #[inline] fn to_superset(&self) -> Isometry { @@ -87,7 +87,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { + fn from_superset_unchecked(iso: &Isometry) -> Self { crate::convert_ref_unchecked(&iso.rotation) } } @@ -96,7 +96,7 @@ impl SubsetOf> for UnitComplex where N1: RealField, N2: RealField + SupersetOf, - R: AlgaRotation> + SupersetOf, + R: AbstractRotation + SupersetOf, { #[inline] fn to_superset(&self) -> Similarity { @@ -109,7 +109,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { + fn from_superset_unchecked(sim: &Similarity) -> Self { crate::convert_ref_unchecked(&sim.isometry) } } @@ -131,7 +131,7 @@ where } #[inline] - unsafe fn from_superset_unchecked(t: &Transform) -> Self { + fn from_superset_unchecked(t: &Transform) -> Self { Self::from_superset_unchecked(t.matrix()) } } @@ -148,37 +148,118 @@ impl> SubsetOf> for Un } #[inline] - unsafe fn from_superset_unchecked(m: &Matrix3) -> Self { + fn from_superset_unchecked(m: &Matrix3) -> Self { let rot: Rotation2 = crate::convert_ref_unchecked(m); Self::from_rotation_matrix(&rot) } } - -impl From> for Rotation2 { +impl From> for Rotation2 +where + N::Element: SimdRealField, +{ #[inline] fn from(q: UnitComplex) -> Self { q.to_rotation_matrix() } } -impl From> for UnitComplex { +impl From> for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn from(q: Rotation2) -> Self { Self::from_rotation_matrix(&q) } } -impl From> for Matrix3 { +impl From> for Matrix3 +where + N::Element: SimdRealField, +{ #[inline] fn from(q: UnitComplex) -> Matrix3 { q.to_homogeneous() } } -impl From> for Matrix2 { +impl From> for Matrix2 +where + N::Element: SimdRealField, +{ #[inline] fn from(q: UnitComplex) -> Self { q.to_rotation_matrix().into_inner() } } + +impl From<[UnitComplex; 2]> for UnitComplex +where + N: From<[::Element; 2]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 2]) -> Self { + Self::new_unchecked(Complex { + re: N::from([arr[0].re, arr[1].re]), + im: N::from([arr[0].im, arr[1].im]), + }) + } +} + +impl From<[UnitComplex; 4]> for UnitComplex +where + N: From<[::Element; 4]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 4]) -> Self { + Self::new_unchecked(Complex { + re: N::from([arr[0].re, arr[1].re, arr[2].re, arr[3].re]), + im: N::from([arr[0].im, arr[1].im, arr[2].im, arr[3].im]), + }) + } +} + +impl From<[UnitComplex; 8]> for UnitComplex +where + N: From<[::Element; 8]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 8]) -> Self { + Self::new_unchecked(Complex { + re: N::from([ + arr[0].re, arr[1].re, arr[2].re, arr[3].re, arr[4].re, arr[5].re, arr[6].re, + arr[7].re, + ]), + im: N::from([ + arr[0].im, arr[1].im, arr[2].im, arr[3].im, arr[4].im, arr[5].im, arr[6].im, + arr[7].im, + ]), + }) + } +} + +impl From<[UnitComplex; 16]> for UnitComplex +where + N: From<[::Element; 16]>, + N::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 16]) -> Self { + Self::new_unchecked(Complex { + re: N::from([ + arr[0].re, arr[1].re, arr[2].re, arr[3].re, arr[4].re, arr[5].re, arr[6].re, + arr[7].re, arr[8].re, arr[9].re, arr[10].re, arr[11].re, arr[12].re, arr[13].re, + arr[14].re, arr[15].re, + ]), + im: N::from([ + arr[0].im, arr[1].im, arr[2].im, arr[3].im, arr[4].im, arr[5].im, arr[6].im, + arr[7].im, arr[8].im, arr[9].im, arr[10].im, arr[11].im, arr[12].im, arr[13].im, + arr[14].im, arr[15].im, + ]), + }) + } +} diff --git a/src/geometry/unit_complex_ops.rs b/src/geometry/unit_complex_ops.rs index 11ffdc4a..f7af7088 100644 --- a/src/geometry/unit_complex_ops.rs +++ b/src/geometry/unit_complex_ops.rs @@ -1,11 +1,11 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::RealField; use crate::base::allocator::Allocator; use crate::base::dimension::{U1, U2}; use crate::base::storage::Storage; use crate::base::{DefaultAllocator, Unit, Vector, Vector2}; use crate::geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex}; +use simba::simd::SimdRealField; /* * This file provides: @@ -28,8 +28,6 @@ use crate::geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitC * UnitComplex × Similarity * UnitComplex × Translation -> Isometry * - * NOTE: -UnitComplex is already provided by `Unit`. - * * (Assignment Operators) * * UnitComplex ×= UnitComplex @@ -44,7 +42,7 @@ use crate::geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitC */ // UnitComplex × UnitComplex -impl Mul for UnitComplex { +impl Mul for UnitComplex { type Output = Self; #[inline] @@ -53,7 +51,10 @@ impl Mul for UnitComplex { } } -impl<'a, N: RealField> Mul> for &'a UnitComplex { +impl<'a, N: SimdRealField> Mul> for &'a UnitComplex +where + N::Element: SimdRealField, +{ type Output = UnitComplex; #[inline] @@ -62,26 +63,35 @@ impl<'a, N: RealField> Mul> for &'a UnitComplex { } } -impl<'b, N: RealField> Mul<&'b UnitComplex> for UnitComplex { +impl<'b, N: SimdRealField> Mul<&'b UnitComplex> for UnitComplex +where + N::Element: SimdRealField, +{ type Output = Self; #[inline] fn mul(self, rhs: &'b UnitComplex) -> Self::Output { - Unit::new_unchecked(self.into_inner() * rhs.complex()) + Unit::new_unchecked(self.into_inner() * rhs.as_ref()) } } -impl<'a, 'b, N: RealField> Mul<&'b UnitComplex> for &'a UnitComplex { +impl<'a, 'b, N: SimdRealField> Mul<&'b UnitComplex> for &'a UnitComplex +where + N::Element: SimdRealField, +{ type Output = UnitComplex; #[inline] fn mul(self, rhs: &'b UnitComplex) -> Self::Output { - Unit::new_unchecked(self.complex() * rhs.complex()) + Unit::new_unchecked(self.complex() * rhs.as_ref()) } } // UnitComplex ÷ UnitComplex -impl Div for UnitComplex { +impl Div for UnitComplex +where + N::Element: SimdRealField, +{ type Output = Self; #[inline] @@ -90,7 +100,10 @@ impl Div for UnitComplex { } } -impl<'a, N: RealField> Div> for &'a UnitComplex { +impl<'a, N: SimdRealField> Div> for &'a UnitComplex +where + N::Element: SimdRealField, +{ type Output = UnitComplex; #[inline] @@ -99,7 +112,10 @@ impl<'a, N: RealField> Div> for &'a UnitComplex { } } -impl<'b, N: RealField> Div<&'b UnitComplex> for UnitComplex { +impl<'b, N: SimdRealField> Div<&'b UnitComplex> for UnitComplex +where + N::Element: SimdRealField, +{ type Output = Self; #[inline] @@ -108,7 +124,10 @@ impl<'b, N: RealField> Div<&'b UnitComplex> for UnitComplex { } } -impl<'a, 'b, N: RealField> Div<&'b UnitComplex> for &'a UnitComplex { +impl<'a, 'b, N: SimdRealField> Div<&'b UnitComplex> for &'a UnitComplex +where + N::Element: SimdRealField, +{ type Output = UnitComplex; #[inline] @@ -122,8 +141,9 @@ macro_rules! complex_op_impl( ($RDim: ident, $CDim: ident) $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; $action: expr; $($lives: tt),*) => { - impl<$($lives ,)* N: RealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs - where DefaultAllocator: Allocator { + impl<$($lives ,)* N: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where N::Element: SimdRealField, + DefaultAllocator: Allocator { type Output = $Result; #[inline] @@ -300,14 +320,20 @@ complex_op_impl_all!( ); // UnitComplex ×= UnitComplex -impl MulAssign> for UnitComplex { +impl MulAssign> for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn mul_assign(&mut self, rhs: UnitComplex) { *self = &*self * rhs } } -impl<'b, N: RealField> MulAssign<&'b UnitComplex> for UnitComplex { +impl<'b, N: SimdRealField> MulAssign<&'b UnitComplex> for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn mul_assign(&mut self, rhs: &'b UnitComplex) { *self = &*self * rhs @@ -315,14 +341,20 @@ impl<'b, N: RealField> MulAssign<&'b UnitComplex> for UnitComplex { } // UnitComplex /= UnitComplex -impl DivAssign> for UnitComplex { +impl DivAssign> for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn div_assign(&mut self, rhs: UnitComplex) { *self = &*self / rhs } } -impl<'b, N: RealField> DivAssign<&'b UnitComplex> for UnitComplex { +impl<'b, N: SimdRealField> DivAssign<&'b UnitComplex> for UnitComplex +where + N::Element: SimdRealField, +{ #[inline] fn div_assign(&mut self, rhs: &'b UnitComplex) { *self = &*self / rhs @@ -330,8 +362,10 @@ impl<'b, N: RealField> DivAssign<&'b UnitComplex> for UnitComplex { } // UnitComplex ×= Rotation -impl MulAssign> for UnitComplex -where DefaultAllocator: Allocator +impl MulAssign> for UnitComplex +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn mul_assign(&mut self, rhs: Rotation) { @@ -339,8 +373,10 @@ where DefaultAllocator: Allocator } } -impl<'b, N: RealField> MulAssign<&'b Rotation> for UnitComplex -where DefaultAllocator: Allocator +impl<'b, N: SimdRealField> MulAssign<&'b Rotation> for UnitComplex +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn mul_assign(&mut self, rhs: &'b Rotation) { @@ -349,8 +385,10 @@ where DefaultAllocator: Allocator } // UnitComplex ÷= Rotation -impl DivAssign> for UnitComplex -where DefaultAllocator: Allocator +impl DivAssign> for UnitComplex +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn div_assign(&mut self, rhs: Rotation) { @@ -358,8 +396,10 @@ where DefaultAllocator: Allocator } } -impl<'b, N: RealField> DivAssign<&'b Rotation> for UnitComplex -where DefaultAllocator: Allocator +impl<'b, N: SimdRealField> DivAssign<&'b Rotation> for UnitComplex +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn div_assign(&mut self, rhs: &'b Rotation) { @@ -368,8 +408,10 @@ where DefaultAllocator: Allocator } // Rotation ×= UnitComplex -impl MulAssign> for Rotation -where DefaultAllocator: Allocator +impl MulAssign> for Rotation +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn mul_assign(&mut self, rhs: UnitComplex) { @@ -377,8 +419,10 @@ where DefaultAllocator: Allocator } } -impl<'b, N: RealField> MulAssign<&'b UnitComplex> for Rotation -where DefaultAllocator: Allocator +impl<'b, N: SimdRealField> MulAssign<&'b UnitComplex> for Rotation +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn mul_assign(&mut self, rhs: &'b UnitComplex) { @@ -387,8 +431,10 @@ where DefaultAllocator: Allocator } // Rotation ÷= UnitComplex -impl DivAssign> for Rotation -where DefaultAllocator: Allocator +impl DivAssign> for Rotation +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn div_assign(&mut self, rhs: UnitComplex) { @@ -396,11 +442,13 @@ where DefaultAllocator: Allocator } } -impl<'b, N: RealField> DivAssign<&'b UnitComplex> for Rotation -where DefaultAllocator: Allocator +impl<'b, N: SimdRealField> DivAssign<&'b UnitComplex> for Rotation +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, { #[inline] fn div_assign(&mut self, rhs: &'b UnitComplex) { self.div_assign(rhs.to_rotation_matrix()) } -} \ No newline at end of file +} diff --git a/src/geometry/unit_complex_simba.rs b/src/geometry/unit_complex_simba.rs new file mode 100755 index 00000000..5e8bfa78 --- /dev/null +++ b/src/geometry/unit_complex_simba.rs @@ -0,0 +1,51 @@ +use num_complex::Complex; +use simba::simd::SimdValue; +use std::ops::Deref; + +use crate::base::Unit; +use crate::geometry::UnitComplex; +use crate::SimdRealField; + +impl SimdValue for UnitComplex +where + N::Element: SimdRealField, +{ + type Element = UnitComplex; + type SimdBool = N::SimdBool; + + #[inline] + fn lanes() -> usize { + N::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + Unit::new_unchecked(Complex::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Unit::new_unchecked(self.deref().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Unit::new_unchecked(self.deref().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Unit::new_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/src/io/matrix_market.rs b/src/io/matrix_market.rs index f0e817a1..3f7834ac 100644 --- a/src/io/matrix_market.rs +++ b/src/io/matrix_market.rs @@ -1,9 +1,9 @@ use std::fs; use std::path::Path; -use pest::Parser; use crate::sparse::CsMatrix; use crate::RealField; +use pest::Parser; #[derive(Parser)] #[grammar = "io/matrix_market.pest"] diff --git a/src/lib.rs b/src/lib.rs index 055b10ff..9db176bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,8 +68,6 @@ an optimized set of tools for computer graphics and physics. Those features incl * 3D projections for computer graphics: `Perspective3`, `Orthographic3`. * Matrix factorizations: `Cholesky`, `QR`, `LU`, `FullPivLU`, `SVD`, `Schur`, `Hessenberg`, `SymmetricEigen`. * Insertion and removal of rows of columns of a matrix. -* Implements traits from the [alga](https://crates.io/crates/alga) crate for - generic programming. */ // #![feature(plugin)] @@ -106,18 +104,11 @@ extern crate mint; #[macro_use] extern crate approx; -extern crate generic_array; #[cfg(feature = "std")] extern crate matrixmultiply; -extern crate num_complex; extern crate num_traits as num; -extern crate num_rational; -extern crate rand; #[cfg(feature = "std")] extern crate rand_distr; -extern crate typenum; - -extern crate alga; #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc; @@ -141,45 +132,28 @@ pub mod linalg; #[cfg(feature = "sparse")] pub mod sparse; -#[cfg(feature = "std")] -#[deprecated( - note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate." -)] -pub use base as core; pub use crate::base::*; pub use crate::geometry::*; pub use crate::linalg::*; #[cfg(feature = "sparse")] pub use crate::sparse::*; +#[cfg(feature = "std")] +#[deprecated( + note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate." +)] +pub use base as core; +use simba::scalar::SupersetOf; use std::cmp::{self, Ordering, PartialOrd}; -use alga::general::{ - Additive, AdditiveGroup, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice, - Multiplicative, SupersetOf, -}; -use alga::linear::SquareMatrix as AlgaSquareMatrix; -use alga::linear::{EuclideanSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace}; -use num::Signed; +use num::{One, Signed, Zero}; -pub use alga::general::{Id, RealField, ComplexField}; -#[allow(deprecated)] -pub use alga::general::Real; +use base::allocator::Allocator; pub use num_complex::Complex; - -/* - * - * Multiplicative identity. - * - */ -/// Gets the ubiquitous multiplicative identity element. -/// -/// Same as `Id::new()`. -#[deprecated(note = "use `Id::new()` instead.")] -#[inline] -pub fn id() -> Id { - Id::new() -} +pub use simba::scalar::{ + ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, ComplexField, Field, RealField, +}; +pub use simba::simd::{SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField}; /// Gets the multiplicative identity element. /// @@ -188,8 +162,8 @@ pub fn id() -> Id { /// * [`origin`](../nalgebra/fn.origin.html) /// * [`zero`](fn.zero.html) #[inline] -pub fn one>() -> T { - T::identity() +pub fn one() -> T { + T::one() } /// Gets the additive identity element. @@ -199,36 +173,8 @@ pub fn one>() -> T { /// * [`one`](fn.one.html) /// * [`origin`](../nalgebra/fn.origin.html) #[inline] -pub fn zero>() -> T { - T::identity() -} - -/// Gets the origin of the given point. -/// -/// # See also: -/// -/// * [`one`](fn.one.html) -/// * [`zero`](fn.zero.html) -/// -/// # Deprecated -/// Use [Point::origin] instead. -/// -/// Or, use [EuclideanSpace::origin](https://docs.rs/alga/0.7.2/alga/linear/trait.EuclideanSpace.html#tymethod.origin). -#[deprecated(note = "use `Point::origin` instead")] -#[inline] -pub fn origin() -> P { - P::origin() -} - -/* - * - * Dimension - * - */ -/// The dimension of the given algebraic entity seen as a vector space. -#[inline] -pub fn dimension() -> usize { - V::dimension() +pub fn zero() -> T { + T::zero() } /* @@ -244,7 +190,9 @@ pub fn dimension() -> usize { /// The range must not be empty. #[inline] pub fn wrap(mut val: T, min: T, max: T) -> T -where T: Copy + PartialOrd + AdditiveGroup { +where + T: Copy + PartialOrd + ClosedAdd + ClosedSub, +{ assert!(min < max, "Invalid wrapping bounds."); let width = max - min; @@ -303,28 +251,46 @@ pub fn min(a: T, b: T) -> T { /// The absolute value of `a`. /// /// Deprecated: Use [Matrix::abs] or [RealField::abs] instead. -#[deprecated(note = "use `Matrix::abs` or `RealField::abs` instead")] +#[deprecated(note = "use the inherent method `Matrix::abs` or `RealField::abs` instead")] #[inline] pub fn abs(a: &T) -> T { a.abs() } /// Returns the infimum of `a` and `b`. +#[deprecated(note = "use the inherent method `Matrix::inf` instead")] #[inline] -pub fn inf(a: &T, b: &T) -> T { - a.meet(b) +pub fn inf(a: &MatrixMN, b: &MatrixMN) -> MatrixMN +where + N: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + a.inf(b) } /// Returns the supremum of `a` and `b`. +#[deprecated(note = "use the inherent method `Matrix::sup` instead")] #[inline] -pub fn sup(a: &T, b: &T) -> T { - a.join(b) +pub fn sup(a: &MatrixMN, b: &MatrixMN) -> MatrixMN +where + N: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + a.sup(b) } /// Returns simultaneously the infimum and supremum of `a` and `b`. +#[deprecated(note = "use the inherent method `Matrix::inf_sup` instead")] #[inline] -pub fn inf_sup(a: &T, b: &T) -> (T, T) { - a.meet_join(b) +pub fn inf_sup( + a: &MatrixMN, + b: &MatrixMN, +) -> (MatrixMN, MatrixMN) +where + N: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + a.inf_sup(b) } /// Compare `a` and `b` using a partial ordering relation. @@ -413,175 +379,6 @@ pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &' } } -/* - * Inverse - */ - -/// Tries to gets an inverted copy of a square matrix. -/// -/// # See also: -/// -/// * [`inverse`](fn.inverse.html) -#[deprecated(note = "use the `.try_inverse()` method instead")] -#[inline] -pub fn try_inverse(m: &M) -> Option { - m.try_inverse() -} - -/// Computes the multiplicative inverse of an (always invertible) algebraic entity. -/// -/// # See also: -/// -/// * [`try_inverse`](fn.try_inverse.html) -#[deprecated(note = "use the `.inverse()` method instead")] -#[inline] -pub fn inverse>(m: &M) -> M { - m.two_sided_inverse() -} - -/* - * Inner vector space - */ - -/// Computes the dot product of two vectors. -/// -/// ## Deprecated -/// Use these methods instead: -/// - [Matrix::dot] -/// - [Quaternion::dot] -/// -/// Or, use [FiniteDimVectorSpace::dot](https://docs.rs/alga/0.7.2/alga/linear/trait.FiniteDimVectorSpace.html#tymethod.dot). -#[deprecated(note = "use `Matrix::dot` or `Quaternion::dot` instead")] -#[inline] -pub fn dot(a: &V, b: &V) -> V::Field { - a.dot(b) -} - -/// Computes the smallest angle between two vectors. -/// -/// ## Deprecated -/// Use [Matrix::angle] instead. -/// -/// Or, use [InnerSpace::angle](https://docs.rs/alga/0.7.2/alga/linear/trait.InnerSpace.html#method.angle). -#[deprecated(note = "use `Matrix::angle` instead")] -#[inline] -pub fn angle(a: &V, b: &V) -> V::RealField { - a.angle(b) -} - -/* - * Normed space - */ - -/// Computes the L2 (Euclidean) norm of a vector. -/// -/// # See also: -/// -/// * [`magnitude`](fn.magnitude.html) -/// * [`magnitude_squared`](fn.magnitude_squared.html) -/// * [`norm_squared`](fn.norm_squared.html) -/// -/// # Deprecated -/// Use these methods instead: -/// * [Matrix::norm] -/// * [Quaternion::norm] -/// -/// Or, use [NormedSpace::norm](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm). -#[deprecated(note = "use `Matrix::norm` or `Quaternion::norm` instead")] -#[inline] -pub fn norm(v: &V) -> V::RealField { - v.norm() -} - -/// Computes the squared L2 (Euclidean) norm of the vector `v`. -/// -/// # See also: -/// -/// * [`magnitude`](fn.magnitude.html) -/// * [`magnitude_squared`](fn.magnitude_squared.html) -/// * [`norm`](fn.norm.html) -/// -/// # Deprecated -/// Use these methods instead: -/// * [Matrix::norm_squared] -/// * [Quaternion::norm_squared] -/// -/// Or, use [NormedSpace::norm_squared](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm_squared). -#[deprecated(note = "use `Matrix::norm_squared` or `Quaternion::norm_squared` instead")] -#[inline] -pub fn norm_squared(v: &V) -> V::RealField { - v.norm_squared() -} - -/// A synonym for [`norm`](fn.norm.html), aka length. -/// -/// # See also: -/// -/// * [`magnitude_squared`](fn.magnitude_squared.html) -/// * [`norm`](fn.norm.html) -/// * [`norm_squared`](fn.norm_squared.html) -/// -/// # Deprecated -/// Use these methods instead: -/// * [Matrix::magnitude] -/// * [Quaternion::magnitude] -/// -/// Or, use [NormedSpace::norm](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm). -#[deprecated(note = "use `Matrix::magnitude` or `Quaternion::magnitude` instead")] -#[inline] -pub fn magnitude(v: &V) -> V::RealField { - v.norm() -} - -/// A synonym for [`norm_squared`](fn.norm_squared.html), -/// aka length squared. -/// -/// # See also: -/// -/// * [`magnitude`](fn.magnitude.html) -/// * [`norm`](fn.norm.html) -/// * [`norm_squared`](fn.norm_squared.html) -/// -/// # Deprecated -/// Use these methods instead: -/// * [Matrix::magnitude_squared] -/// * [Quaternion::magnitude_squared] -/// -/// Or, use [NormedSpace::norm_squared](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.norm_squared). -#[deprecated(note = "use `Matrix::magnitude_squared` or `Quaternion::magnitude_squared` instead")] -#[inline] -pub fn magnitude_squared(v: &V) -> V::RealField { - v.norm_squared() -} - -/// Computes the normalized version of the vector `v`. -/// -/// # Deprecated -/// Use these methods instead: -/// * [Matrix::normalize] -/// * [Quaternion::normalize] -/// -/// Or, use [NormedSpace::normalize](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.normalize). -#[deprecated(note = "use `Matrix::normalize` or `Quaternion::normalize` instead")] -#[inline] -pub fn normalize(v: &V) -> V { - v.normalize() -} - -/// Computes the normalized version of the vector `v` or returns `None` if its norm is smaller than `min_norm`. -/// -/// # Deprecated -/// Use these methods instead: -/// * [Matrix::try_normalize] -/// * [Quaternion::try_normalize] -/// -/// Or, use [NormedSpace::try_normalize](https://docs.rs/alga/0.7.2/alga/linear/trait.NormedSpace.html#tymethod.try_normalize). -#[deprecated(note = "use `Matrix::try_normalize` or `Quaternion::try_normalize` instead")] -#[inline] -pub fn try_normalize(v: &V, min_norm: V::RealField) -> Option { - v.try_normalize(min_norm) -} - /* * * Point operations. @@ -594,8 +391,11 @@ pub fn try_normalize(v: &V, min_norm: V::RealField) -> Option /// * [distance](fn.distance.html) /// * [distance_squared](fn.distance_squared.html) #[inline] -pub fn center(p1: &P, p2: &P) -> P { - P::from_coordinates((p1.coordinates() + p2.coordinates()) * convert(0.5)) +pub fn center(p1: &Point, p2: &Point) -> Point +where + DefaultAllocator: Allocator, +{ + ((&p1.coords + &p2.coords) * convert::<_, N>(0.5)).into() } /// The distance between two points. @@ -605,8 +405,14 @@ pub fn center(p1: &P, p2: &P) -> P { /// * [center](fn.center.html) /// * [distance_squared](fn.distance_squared.html) #[inline] -pub fn distance(p1: &P, p2: &P) -> P::RealField { - (p2.coordinates() - p1.coordinates()).norm() +pub fn distance( + p1: &Point, + p2: &Point, +) -> N::SimdRealField +where + DefaultAllocator: Allocator, +{ + (&p2.coords - &p1.coords).norm() } /// The squared distance between two points. @@ -616,8 +422,14 @@ pub fn distance(p1: &P, p2: &P) -> P::RealField { /// * [center](fn.center.html) /// * [distance](fn.distance.html) #[inline] -pub fn distance_squared(p1: &P, p2: &P) -> P::RealField { - (p2.coordinates() - p1.coordinates()).norm_squared() +pub fn distance_squared( + p1: &Point, + p2: &Point, +) -> N::SimdRealField +where + DefaultAllocator: Allocator, +{ + (&p2.coords - &p1.coords).norm_squared() } /* @@ -682,7 +494,7 @@ pub fn is_convertible, To>(t: &From) -> bool { /// * [try_convert](fn.try_convert.html) /// * [try_convert_ref](fn.try_convert_ref.html) #[inline] -pub unsafe fn convert_unchecked, To>(t: From) -> To { +pub fn convert_unchecked, To>(t: From) -> To { t.to_subset_unchecked() } @@ -725,6 +537,6 @@ pub fn try_convert_ref, To>(t: &From) -> Option { /// * [try_convert](fn.try_convert.html) /// * [try_convert_ref](fn.try_convert_ref.html) #[inline] -pub unsafe fn convert_ref_unchecked, To>(t: &From) -> To { +pub fn convert_ref_unchecked, To>(t: &From) -> To { t.to_subset_unchecked() } diff --git a/src/linalg/balancing.rs b/src/linalg/balancing.rs index e8abbefb..e7dbc6fb 100644 --- a/src/linalg/balancing.rs +++ b/src/linalg/balancing.rs @@ -1,6 +1,6 @@ //! Functions for balancing a matrix. -use alga::general::RealField; +use simba::scalar::RealField; use std::ops::{DivAssign, MulAssign}; use crate::allocator::Allocator; @@ -13,7 +13,9 @@ use crate::base::{DefaultAllocator, MatrixN, VectorN}; /// /// See https://arxiv.org/pdf/1401.5766.pdf pub fn balance_parlett_reinsch(m: &mut MatrixN) -> VectorN -where DefaultAllocator: Allocator + Allocator { +where + DefaultAllocator: Allocator + Allocator, +{ assert!(m.is_square(), "Unable to balance a non-square matrix."); let dim = m.data.shape().0; @@ -65,7 +67,9 @@ where DefaultAllocator: Allocator + Allocator { /// Computes in-place `D * m * D.inverse()`, where `D` is the matrix with diagonal `d`. pub fn unbalance(m: &mut MatrixN, d: &VectorN) -where DefaultAllocator: Allocator + Allocator { +where + DefaultAllocator: Allocator + Allocator, +{ assert!(m.is_square(), "Unable to unbalance a non-square matrix."); assert_eq!(m.nrows(), d.len(), "Unbalancing: mismatched dimensions."); diff --git a/src/linalg/bidiagonal.rs b/src/linalg/bidiagonal.rs index f766c91e..c19a0662 100644 --- a/src/linalg/bidiagonal.rs +++ b/src/linalg/bidiagonal.rs @@ -1,11 +1,11 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Unit, VectorN}; use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1}; use crate::storage::Storage; +use simba::scalar::ComplexField; use crate::geometry::Reflection; use crate::linalg::householder; @@ -14,27 +14,23 @@ use crate::linalg::householder; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DimMinimum: DimSub, + serde(bound(serialize = "DimMinimum: DimSub, DefaultAllocator: Allocator + Allocator> + Allocator, U1>>, MatrixMN: Serialize, VectorN>: Serialize, - VectorN, U1>>: Serialize" - )) + VectorN, U1>>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DimMinimum: DimSub, + serde(bound(deserialize = "DimMinimum: DimSub, DefaultAllocator: Allocator + Allocator> + Allocator, U1>>, MatrixMN: Deserialize<'de>, VectorN>: Deserialize<'de>, - VectorN, U1>>: Deserialize<'de>" - )) + VectorN, U1>>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Bidiagonal, C: Dim> @@ -63,7 +59,8 @@ where MatrixMN: Copy, VectorN>: Copy, VectorN, U1>>: Copy, -{} +{ +} impl, C: Dim> Bidiagonal where @@ -205,7 +202,9 @@ where // FIXME: code duplication with householder::assemble_q. // Except that we are returning a rectangular matrix here. pub fn u(&self) -> MatrixMN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { let (nrows, ncols) = self.uv.data.shape(); let mut res = Matrix::identity_generic(nrows, nrows.min(ncols)); @@ -233,7 +232,9 @@ where /// Computes the orthogonal matrix `V_t` of this `U * D * V_t` decomposition. pub fn v_t(&self) -> MatrixMN, C> - where DefaultAllocator: Allocator, C> { + where + DefaultAllocator: Allocator, C>, + { let (nrows, ncols) = self.uv.data.shape(); let min_nrows_ncols = nrows.min(ncols); @@ -266,13 +267,17 @@ where /// The diagonal part of this decomposed matrix. pub fn diagonal(&self) -> VectorN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { self.diagonal.map(|e| e.modulus()) } /// The off-diagonal part of this decomposed matrix. pub fn off_diagonal(&self) -> VectorN, U1>> - where DefaultAllocator: Allocator, U1>> { + where + DefaultAllocator: Allocator, U1>>, + { self.off_diagonal.map(|e| e.modulus()) } diff --git a/src/linalg/cholesky.rs b/src/linalg/cholesky.rs index 23ebdea5..e02209b6 100644 --- a/src/linalg/cholesky.rs +++ b/src/linalg/cholesky.rs @@ -2,12 +2,12 @@ use serde::{Deserialize, Serialize}; use num::One; -use alga::general::ComplexField; +use simba::scalar::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix, Vector}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; -use crate::dimension::{Dim, DimAdd, DimSum, DimDiff, DimSub, Dynamic, U1}; +use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, Dynamic, U1}; use crate::storage::{Storage, StorageMut}; /// The Cholesky decomposition of a symmetric-definite-positive matrix. @@ -176,22 +176,38 @@ where let mut col = col.into_owned(); // for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition let n = col.nrows(); - assert_eq!(n, self.chol.nrows() + 1, "The new column must have the size of the factored matrix plus one."); + assert_eq!( + n, + self.chol.nrows() + 1, + "The new column must have the size of the factored matrix plus one." + ); assert!(j < n, "j needs to be within the bound of the new matrix."); // loads the data into a new matrix with an additional jth row/column - let mut chol = unsafe { Matrix::new_uninitialized_generic(self.chol.data.shape().0.add(U1), self.chol.data.shape().1.add(U1)) }; - chol.slice_range_mut(..j, ..j).copy_from(&self.chol.slice_range(..j, ..j)); - chol.slice_range_mut(..j, j + 1..).copy_from(&self.chol.slice_range(..j, j..)); - chol.slice_range_mut(j + 1.., ..j).copy_from(&self.chol.slice_range(j.., ..j)); - chol.slice_range_mut(j + 1.., j + 1..).copy_from(&self.chol.slice_range(j.., j..)); + let mut chol = unsafe { + Matrix::new_uninitialized_generic( + self.chol.data.shape().0.add(U1), + self.chol.data.shape().1.add(U1), + ) + }; + chol.slice_range_mut(..j, ..j) + .copy_from(&self.chol.slice_range(..j, ..j)); + chol.slice_range_mut(..j, j + 1..) + .copy_from(&self.chol.slice_range(..j, j..)); + chol.slice_range_mut(j + 1.., ..j) + .copy_from(&self.chol.slice_range(j.., ..j)); + chol.slice_range_mut(j + 1.., j + 1..) + .copy_from(&self.chol.slice_range(j.., j..)); // update the jth row let top_left_corner = self.chol.slice_range(..j, ..j); let col_j = col[j]; let (mut new_rowj_adjoint, mut new_colj) = col.rows_range_pair_mut(..j, j + 1..); - assert!(top_left_corner.solve_lower_triangular_mut(&mut new_rowj_adjoint), "Cholesky::insert_column : Unable to solve lower triangular system!"); + assert!( + top_left_corner.solve_lower_triangular_mut(&mut new_rowj_adjoint), + "Cholesky::insert_column : Unable to solve lower triangular system!" + ); new_rowj_adjoint.adjoint_to(&mut chol.slice_range_mut(j, ..j)); @@ -202,36 +218,51 @@ where // update the jth column let bottom_left_corner = self.chol.slice_range(j.., ..j); // new_colj = (col_jplus - bottom_left_corner * new_rowj.adjoint()) / center_element; - new_colj.gemm(-N::one() / center_element, &bottom_left_corner, &new_rowj_adjoint, N::one() / center_element); + new_colj.gemm( + -N::one() / center_element, + &bottom_left_corner, + &new_rowj_adjoint, + N::one() / center_element, + ); chol.slice_range_mut(j + 1.., j).copy_from(&new_colj); // update the bottom right corner let mut bottom_right_corner = chol.slice_range_mut(j + 1.., j + 1..); - Self::xx_rank_one_update(&mut bottom_right_corner, &mut new_colj, -N::RealField::one()); + Self::xx_rank_one_update( + &mut bottom_right_corner, + &mut new_colj, + -N::RealField::one(), + ); Cholesky { chol } } /// Updates the decomposition such that we get the decomposition of the factored matrix with its `j`th column removed. /// Since the matrix is square, the `j`th row will also be removed. - pub fn remove_column( - &self, - j: usize, - ) -> Cholesky> - where - D: DimSub, - DefaultAllocator: Allocator, DimDiff> + Allocator + pub fn remove_column(&self, j: usize) -> Cholesky> + where + D: DimSub, + DefaultAllocator: Allocator, DimDiff> + Allocator, { let n = self.chol.nrows(); assert!(n > 0, "The matrix needs at least one column."); assert!(j < n, "j needs to be within the bound of the matrix."); // loads the data into a new matrix except for the jth row/column - let mut chol = unsafe { Matrix::new_uninitialized_generic(self.chol.data.shape().0.sub(U1), self.chol.data.shape().1.sub(U1)) }; - chol.slice_range_mut(..j, ..j).copy_from(&self.chol.slice_range(..j, ..j)); - chol.slice_range_mut(..j, j..).copy_from(&self.chol.slice_range(..j, j + 1..)); - chol.slice_range_mut(j.., ..j).copy_from(&self.chol.slice_range(j + 1.., ..j)); - chol.slice_range_mut(j.., j..).copy_from(&self.chol.slice_range(j + 1.., j + 1..)); + let mut chol = unsafe { + Matrix::new_uninitialized_generic( + self.chol.data.shape().0.sub(U1), + self.chol.data.shape().1.sub(U1), + ) + }; + chol.slice_range_mut(..j, ..j) + .copy_from(&self.chol.slice_range(..j, ..j)); + chol.slice_range_mut(..j, j..) + .copy_from(&self.chol.slice_range(..j, j + 1..)); + chol.slice_range_mut(j.., ..j) + .copy_from(&self.chol.slice_range(j + 1.., ..j)); + chol.slice_range_mut(j.., j..) + .copy_from(&self.chol.slice_range(j + 1.., j + 1..)); // updates the bottom right corner let mut bottom_right_corner = chol.slice_range_mut(j.., j..); @@ -247,13 +278,16 @@ where /// /// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column` /// where it is used on a square slice of the decomposition - fn xx_rank_one_update(chol : &mut Matrix, x: &mut Vector, sigma: N::RealField) - where - //N: ComplexField, - Dm: Dim, - Rx: Dim, - Sm: StorageMut, - Sx: StorageMut, + fn xx_rank_one_update( + chol: &mut Matrix, + x: &mut Vector, + sigma: N::RealField, + ) where + //N: ComplexField, + Dm: Dim, + Rx: Dim, + Sm: StorageMut, + Sx: StorageMut, { // heavily inspired by Eigen's `llt_rank_update_lower` implementation https://eigen.tuxfamily.org/dox/LLT_8h_source.html let n = x.nrows(); diff --git a/src/linalg/convolution.rs b/src/linalg/convolution.rs index 29c5f61c..df84c301 100644 --- a/src/linalg/convolution.rs +++ b/src/linalg/convolution.rs @@ -64,7 +64,10 @@ impl> Vector { /// # Errors /// Inputs must satisfy `self.len() >= kernel.len() > 0`. /// - pub fn convolve_valid(&self, kernel: Vector) -> VectorN, D2>> + pub fn convolve_valid( + &self, + kernel: Vector, + ) -> VectorN, D2>> where D1: DimAdd, D2: Dim, diff --git a/src/linalg/determinant.rs b/src/linalg/determinant.rs index 54ec9e5a..73365d78 100644 --- a/src/linalg/determinant.rs +++ b/src/linalg/determinant.rs @@ -1,4 +1,4 @@ -use alga::general::ComplexField; +use simba::scalar::ComplexField; use crate::base::allocator::Allocator; use crate::base::dimension::DimMin; @@ -13,7 +13,9 @@ impl, S: Storage> SquareMatri /// If the matrix has a dimension larger than 3, an LU decomposition is used. #[inline] pub fn determinant(&self) -> N - where DefaultAllocator: Allocator + Allocator<(usize, usize), D> { + where + DefaultAllocator: Allocator + Allocator<(usize, usize), D>, + { assert!( self.is_square(), "Unable to compute the determinant of a non-square matrix." diff --git a/src/linalg/eigen.rs b/src/linalg/eigen.rs index 8d1d26ca..2177903e 100644 --- a/src/linalg/eigen.rs +++ b/src/linalg/eigen.rs @@ -1,8 +1,8 @@ #[cfg(feature = "serde-serialize")] -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; -use alga::general::ComplexField; use num_complex::Complex; +use simba::scalar::ComplexField; use std::cmp; use std::fmt::Display; use std::ops::MulAssign; @@ -10,7 +10,9 @@ use std::ops::MulAssign; use crate::allocator::Allocator; use crate::base::dimension::{Dim, DimDiff, DimSub, Dynamic, U1, U2, U3}; use crate::base::storage::Storage; -use crate::base::{DefaultAllocator, Hessenberg, MatrixN, SquareMatrix, Unit, Vector2, Vector3, VectorN}; +use crate::base::{ + DefaultAllocator, Hessenberg, MatrixN, SquareMatrix, Unit, Vector2, Vector3, VectorN, +}; use crate::constraint::{DimEq, ShapeConstraint}; use crate::geometry::{Reflection, UnitComplex}; @@ -21,28 +23,19 @@ use crate::linalg::Schur; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde( - bound( - serialize = "DefaultAllocator: Allocator, + serde(bound(serialize = "DefaultAllocator: Allocator, VectorN: Serialize, - MatrixN: Serialize" - ) - ) + MatrixN: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde( - bound( - deserialize = "DefaultAllocator: Allocator, + serde(bound(deserialize = "DefaultAllocator: Allocator, VectorN: Serialize, - MatrixN: Deserialize<'de>" - ) - ) + MatrixN: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Eigen -where - DefaultAllocator: Allocator + Allocator, +where DefaultAllocator: Allocator + Allocator { pub eigenvectors: MatrixN, pub eigenvalues: VectorN, diff --git a/src/linalg/full_piv_lu.rs b/src/linalg/full_piv_lu.rs index f2bfc874..bfa6854f 100644 --- a/src/linalg/full_piv_lu.rs +++ b/src/linalg/full_piv_lu.rs @@ -1,12 +1,12 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::dimension::{Dim, DimMin, DimMinimum}; use crate::storage::{Storage, StorageMut}; +use simba::scalar::ComplexField; use crate::linalg::lu; use crate::linalg::PermutationSequence; @@ -15,25 +15,22 @@ use crate::linalg::PermutationSequence; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Serialize, - PermutationSequence>: Serialize" - )) + PermutationSequence>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Deserialize<'de>, - PermutationSequence>: Deserialize<'de>" - )) + PermutationSequence>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct FullPivLU, C: Dim> -where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, { lu: MatrixMN, p: PermutationSequence>, @@ -45,10 +42,12 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Copy, PermutationSequence>: Copy, -{} +{ +} impl, C: Dim> FullPivLU -where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, { /// Computes the LU decomposition with full pivoting of `matrix`. /// @@ -106,7 +105,9 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu /// The lower triangular matrix of this decomposition. #[inline] pub fn l(&self) -> MatrixMN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { let (nrows, ncols) = self.lu.data.shape(); let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); m.fill_upper_triangle(N::zero(), 1); @@ -117,7 +118,9 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu /// The upper triangular matrix of this decomposition. #[inline] pub fn u(&self) -> MatrixMN, C> - where DefaultAllocator: Allocator, C> { + where + DefaultAllocator: Allocator, C>, + { let (nrows, ncols) = self.lu.data.shape(); self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle() } @@ -144,7 +147,8 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu MatrixMN, C>, PermutationSequence>, ) - where DefaultAllocator: Allocator> + Allocator, C> + where + DefaultAllocator: Allocator> + Allocator, C>, { // Use reallocation for either l or u. let l = self.l(); @@ -157,7 +161,8 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu } impl> FullPivLU -where DefaultAllocator: Allocator + Allocator<(usize, usize), D> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), D>, { /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. /// @@ -262,7 +267,8 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), D> } impl, C: Dim, S: Storage> Matrix -where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, { /// Computes the LU decomposition with full pivoting of `matrix`. /// diff --git a/src/linalg/givens.rs b/src/linalg/givens.rs index 20e2c309..164a0971 100644 --- a/src/linalg/givens.rs +++ b/src/linalg/givens.rs @@ -1,19 +1,18 @@ //! Construction of givens rotations. -use alga::general::ComplexField; -use num::{Zero, One}; +use num::{One, Zero}; +use simba::scalar::ComplexField; +use crate::base::constraint::{DimEq, ShapeConstraint}; use crate::base::dimension::{Dim, U2}; -use crate::base::constraint::{ShapeConstraint, DimEq}; use crate::base::storage::{Storage, StorageMut}; -use crate::base::{Vector, Matrix}; - +use crate::base::{Matrix, Vector}; /// A Givens rotation. #[derive(Debug, Clone, Copy)] pub struct GivensRotation { c: N::RealField, - s: N + s: N, } // Matrix = UnitComplex * Matrix @@ -22,7 +21,7 @@ impl GivensRotation { pub fn identity() -> Self { Self { c: N::RealField::one(), - s: N::zero() + s: N::zero(), } } @@ -31,9 +30,7 @@ impl GivensRotation { /// The components are copies as-is. It is not checked whether they describe /// an actually valid Givens rotation. pub fn new_unchecked(c: N::RealField, s: N) -> Self { - Self { - c, s - } + Self { c, s } } /// Initializes a Givens rotation from its non-normalized cosine an sine components. @@ -103,7 +100,10 @@ impl GivensRotation { /// The inverse of this givens rotation. pub fn inverse(&self) -> Self { - Self { c: self.c, s: -self.s } + Self { + c: self.c, + s: -self.s, + } } /// Performs the multiplication `rhs = self * rhs` in-place. @@ -159,4 +159,3 @@ impl GivensRotation { } } } - diff --git a/src/linalg/hessenberg.rs b/src/linalg/hessenberg.rs index c87c06a2..57a24097 100644 --- a/src/linalg/hessenberg.rs +++ b/src/linalg/hessenberg.rs @@ -1,11 +1,11 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, MatrixMN, MatrixN, SquareMatrix, VectorN}; use crate::dimension::{DimDiff, DimSub, U1}; use crate::storage::Storage; +use simba::scalar::ComplexField; use crate::linalg::householder; @@ -13,25 +13,22 @@ use crate::linalg::householder; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator>, MatrixN: Serialize, - VectorN>: Serialize" - )) + VectorN>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator>, MatrixN: Deserialize<'de>, - VectorN>: Deserialize<'de>" - )) + VectorN>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Hessenberg> -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { hess: MatrixN, subdiag: VectorN>, @@ -42,10 +39,12 @@ where DefaultAllocator: Allocator + Allocator>, MatrixN: Copy, VectorN>: Copy, -{} +{ +} impl> Hessenberg -where DefaultAllocator: Allocator + Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator + Allocator>, { /// Computes the Hessenberg decomposition using householder reflections. pub fn new(hess: MatrixN) -> Self { @@ -134,7 +133,8 @@ where DefaultAllocator: Allocator + Allocator + Allocator, S: Storage> SquareMatrix -where DefaultAllocator: Allocator + Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator + Allocator>, { /// Computes the Hessenberg decomposition of this matrix using householder reflections. pub fn hessenberg(self) -> Hessenberg { diff --git a/src/linalg/householder.rs b/src/linalg/householder.rs index 11fa32eb..9f4c9e69 100644 --- a/src/linalg/householder.rs +++ b/src/linalg/householder.rs @@ -1,11 +1,11 @@ //! Construction of householder elementary reflections. -use num::Zero; -use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Unit, Vector, VectorN}; use crate::dimension::Dim; use crate::storage::{Storage, StorageMut}; +use num::Zero; +use simba::scalar::ComplexField; use crate::geometry::Reflection; @@ -109,7 +109,9 @@ pub fn clear_row_unchecked( /// matrices. #[doc(hidden)] pub fn assemble_q(m: &MatrixN, signs: &[N]) -> MatrixN -where DefaultAllocator: Allocator { +where + DefaultAllocator: Allocator, +{ assert!(m.is_square()); let dim = m.data.shape().0; diff --git a/src/linalg/inverse.rs b/src/linalg/inverse.rs index f0920cca..79d64121 100644 --- a/src/linalg/inverse.rs +++ b/src/linalg/inverse.rs @@ -1,4 +1,4 @@ -use alga::general::ComplexField; +use simba::scalar::ComplexField; use crate::base::allocator::Allocator; use crate::base::dimension::Dim; @@ -12,7 +12,9 @@ impl> SquareMatrix { #[inline] #[must_use = "Did you mean to use try_inverse_mut()?"] pub fn try_inverse(self) -> Option> - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let mut me = self.into_owned(); if me.try_inverse_mut() { Some(me) @@ -27,7 +29,9 @@ impl> SquareMatrix { /// inversion fails. #[inline] pub fn try_inverse_mut(&mut self) -> bool - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { assert!(self.is_square(), "Unable to invert a non-square matrix."); let dim = self.shape().0; diff --git a/src/linalg/lu.rs b/src/linalg/lu.rs index 521df894..b3acaaa0 100644 --- a/src/linalg/lu.rs +++ b/src/linalg/lu.rs @@ -1,13 +1,13 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::{Field, ComplexField}; use crate::allocator::{Allocator, Reallocator}; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::dimension::{Dim, DimMin, DimMinimum}; -use std::mem; use crate::storage::{Storage, StorageMut}; +use simba::scalar::{ComplexField, Field}; +use std::mem; use crate::linalg::PermutationSequence; @@ -15,25 +15,22 @@ use crate::linalg::PermutationSequence; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Serialize, - PermutationSequence>: Serialize" - )) + PermutationSequence>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Deserialize<'de>, - PermutationSequence>: Deserialize<'de>" - )) + PermutationSequence>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct LU, C: Dim> -where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, { lu: MatrixMN, p: PermutationSequence>, @@ -44,7 +41,8 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Copy, PermutationSequence>: Copy, -{} +{ +} /// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`. /// @@ -87,7 +85,8 @@ where } impl, C: Dim> LU -where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, { /// Computes the LU decomposition with partial (row) pivoting of `matrix`. pub fn new(mut matrix: MatrixMN) -> Self { @@ -129,7 +128,9 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu /// The lower triangular matrix of this decomposition. #[inline] pub fn l(&self) -> MatrixMN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { let (nrows, ncols) = self.lu.data.shape(); let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); m.fill_upper_triangle(N::zero(), 1); @@ -144,7 +145,9 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu MatrixMN>, PermutationSequence>, ) - where DefaultAllocator: Reallocator> { + where + DefaultAllocator: Reallocator>, + { let (nrows, ncols) = self.lu.data.shape(); let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), N::zero()); m.fill_upper_triangle(N::zero(), 1); @@ -155,7 +158,9 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu /// The lower triangular matrix of this decomposition. #[inline] pub fn l_unpack(self) -> MatrixMN> - where DefaultAllocator: Reallocator> { + where + DefaultAllocator: Reallocator>, + { let (nrows, ncols) = self.lu.data.shape(); let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), N::zero()); m.fill_upper_triangle(N::zero(), 1); @@ -166,7 +171,9 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu /// The upper triangular matrix of this decomposition. #[inline] pub fn u(&self) -> MatrixMN, C> - where DefaultAllocator: Allocator, C> { + where + DefaultAllocator: Allocator, C>, + { let (nrows, ncols) = self.lu.data.shape(); self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle() } @@ -186,9 +193,11 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu MatrixMN>, MatrixMN, C>, ) - where DefaultAllocator: Allocator> + where + DefaultAllocator: Allocator> + Allocator, C> - + Reallocator> { + + Reallocator>, + { // Use reallocation for either l or u. let u = self.u(); let (l, p) = self.l_unpack_with_p(); @@ -198,7 +207,8 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu } impl> LU -where DefaultAllocator: Allocator + Allocator<(usize, usize), D> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), D>, { /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. /// @@ -333,7 +343,8 @@ where let (pivot_row, mut down) = submat.rows_range_pair_mut(0, 1..); for k in 0..pivot_row.ncols() { - down.column_mut(k).axpy(-pivot_row[k].inlined_clone(), &coeffs, N::one()); + down.column_mut(k) + .axpy(-pivot_row[k].inlined_clone(), &coeffs, N::one()); } } @@ -364,12 +375,14 @@ pub fn gauss_step_swap( for k in 0..pivot_row.ncols() { mem::swap(&mut pivot_row[k], &mut down[(piv - 1, k)]); - down.column_mut(k).axpy(-pivot_row[k].inlined_clone(), &coeffs, N::one()); + down.column_mut(k) + .axpy(-pivot_row[k].inlined_clone(), &coeffs, N::one()); } } impl, C: Dim, S: Storage> Matrix -where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> +where + DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, { /// Computes the LU decomposition with partial (row) pivoting of `matrix`. pub fn lu(self) -> LU { diff --git a/src/linalg/mod.rs b/src/linalg/mod.rs index b6a9e8d8..de1108f7 100644 --- a/src/linalg/mod.rs +++ b/src/linalg/mod.rs @@ -3,6 +3,7 @@ pub mod balancing; mod bidiagonal; mod cholesky; +mod convolution; mod determinant; mod full_piv_lu; pub mod givens; @@ -17,7 +18,6 @@ mod solve; mod svd; mod symmetric_eigen; mod symmetric_tridiagonal; -mod convolution; //// FIXME: Not complete enough for publishing. //// This handles only cases where each eigenvalue has multiplicity one. @@ -25,6 +25,7 @@ mod convolution; pub use self::bidiagonal::*; pub use self::cholesky::*; +pub use self::convolution::*; pub use self::full_piv_lu::*; pub use self::hessenberg::*; pub use self::lu::*; @@ -34,4 +35,3 @@ pub use self::schur::*; pub use self::svd::*; pub use self::symmetric_eigen::*; pub use self::symmetric_tridiagonal::*; -pub use self::convolution::*; diff --git a/src/linalg/permutation_sequence.rs b/src/linalg/permutation_sequence.rs index ce493905..0b45510c 100644 --- a/src/linalg/permutation_sequence.rs +++ b/src/linalg/permutation_sequence.rs @@ -1,8 +1,8 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::ClosedNeg; use num::One; +use simba::scalar::ClosedNeg; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, Scalar, VectorN}; @@ -15,21 +15,18 @@ use crate::storage::StorageMut; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator<(usize, usize), D>, - VectorN<(usize, usize), D>: Serialize" - )) + serde(bound(serialize = "DefaultAllocator: Allocator<(usize, usize), D>, + VectorN<(usize, usize), D>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator<(usize, usize), D>, - VectorN<(usize, usize), D>: Deserialize<'de>" - )) + serde(bound(deserialize = "DefaultAllocator: Allocator<(usize, usize), D>, + VectorN<(usize, usize), D>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct PermutationSequence -where DefaultAllocator: Allocator<(usize, usize), D> +where + DefaultAllocator: Allocator<(usize, usize), D>, { len: usize, ipiv: VectorN<(usize, usize), D>, @@ -39,10 +36,12 @@ impl Copy for PermutationSequence where DefaultAllocator: Allocator<(usize, usize), D>, VectorN<(usize, usize), D>: Copy, -{} +{ +} impl PermutationSequence -where DefaultAllocator: Allocator<(usize, usize), D> +where + DefaultAllocator: Allocator<(usize, usize), D>, { /// Creates a new statically-allocated sequence of `D` identity permutations. #[inline] @@ -53,7 +52,8 @@ where DefaultAllocator: Allocator<(usize, usize), D> #[cfg(any(feature = "std", feature = "alloc"))] impl PermutationSequence -where DefaultAllocator: Allocator<(usize, usize), Dynamic> +where + DefaultAllocator: Allocator<(usize, usize), Dynamic>, { /// Creates a new dynamically-allocated sequence of `n` identity permutations. #[inline] @@ -63,7 +63,8 @@ where DefaultAllocator: Allocator<(usize, usize), Dynamic> } impl PermutationSequence -where DefaultAllocator: Allocator<(usize, usize), D> +where + DefaultAllocator: Allocator<(usize, usize), D>, { /// Creates a new sequence of D identity permutations. #[inline] @@ -93,7 +94,9 @@ where DefaultAllocator: Allocator<(usize, usize), D> /// Applies this sequence of permutations to the rows of `rhs`. #[inline] pub fn permute_rows(&self, rhs: &mut Matrix) - where S2: StorageMut { + where + S2: StorageMut, + { for i in self.ipiv.rows_range(..self.len).iter() { rhs.swap_rows(i.0, i.1) } @@ -101,10 +104,8 @@ where DefaultAllocator: Allocator<(usize, usize), D> /// Applies this sequence of permutations in reverse to the rows of `rhs`. #[inline] - pub fn inv_permute_rows( - &self, - rhs: &mut Matrix, - ) where + pub fn inv_permute_rows(&self, rhs: &mut Matrix) + where S2: StorageMut, { for i in 0..self.len { @@ -115,10 +116,8 @@ where DefaultAllocator: Allocator<(usize, usize), D> /// Applies this sequence of permutations to the columns of `rhs`. #[inline] - pub fn permute_columns( - &self, - rhs: &mut Matrix, - ) where + pub fn permute_columns(&self, rhs: &mut Matrix) + where S2: StorageMut, { for i in self.ipiv.rows_range(..self.len).iter() { diff --git a/src/linalg/qr.rs b/src/linalg/qr.rs index 74b4de85..f218d47b 100644 --- a/src/linalg/qr.rs +++ b/src/linalg/qr.rs @@ -1,13 +1,13 @@ +use num::Zero; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use num::Zero; -use alga::general::ComplexField; use crate::allocator::{Allocator, Reallocator}; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Unit, VectorN}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::dimension::{Dim, DimMin, DimMinimum, U1}; use crate::storage::{Storage, StorageMut}; +use simba::scalar::ComplexField; use crate::geometry::Reflection; use crate::linalg::householder; @@ -16,25 +16,22 @@ use crate::linalg::householder; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator>, MatrixMN: Serialize, - VectorN>: Serialize" - )) + VectorN>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator>, MatrixMN: Deserialize<'de>, - VectorN>: Deserialize<'de>" - )) + VectorN>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct QR, C: Dim> -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { qr: MatrixMN, diag: VectorN>, @@ -45,10 +42,12 @@ where DefaultAllocator: Allocator + Allocator>, MatrixMN: Copy, VectorN>: Copy, -{} +{ +} impl, C: Dim> QR -where DefaultAllocator: Allocator + Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator + Allocator>, { /// Computes the QR decomposition using householder reflections. pub fn new(mut matrix: MatrixMN) -> Self { @@ -103,7 +102,9 @@ where DefaultAllocator: Allocator + Allocator + Allocator MatrixMN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { let (nrows, ncols) = self.qr.data.shape(); // NOTE: we could build the identity matrix and call q_mul on it. @@ -146,7 +147,9 @@ where DefaultAllocator: Allocator + Allocator + Allocator(&self, rhs: &mut Matrix) // FIXME: do we need a static constraint on the number of rows of rhs? - where S2: StorageMut { + where + S2: StorageMut, + { let dim = self.diag.len(); for i in 0..dim { @@ -160,7 +163,8 @@ where DefaultAllocator: Allocator + Allocator + Allocator> QR -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. /// @@ -292,7 +296,8 @@ where DefaultAllocator: Allocator + Allocator } impl, C: Dim, S: Storage> Matrix -where DefaultAllocator: Allocator + Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator + Allocator>, { /// Computes the QR decomposition of this matrix. pub fn qr(self) -> QR { diff --git a/src/linalg/schur.rs b/src/linalg/schur.rs index 57ebd8f7..99e73ea1 100644 --- a/src/linalg/schur.rs +++ b/src/linalg/schur.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; use approx::AbsDiffEq; -use alga::general::{ComplexField, RealField}; use num_complex::Complex as NumComplex; +use simba::scalar::{ComplexField, RealField}; use std::cmp; use crate::allocator::Allocator; @@ -12,9 +12,9 @@ use crate::base::storage::Storage; use crate::base::{DefaultAllocator, MatrixN, SquareMatrix, Unit, Vector2, Vector3, VectorN}; use crate::geometry::Reflection; +use crate::linalg::givens::GivensRotation; use crate::linalg::householder; use crate::linalg::Hessenberg; -use crate::linalg::givens::GivensRotation; /// Schur decomposition of a square matrix. /// @@ -22,21 +22,18 @@ use crate::linalg::givens::GivensRotation; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator, - MatrixN: Serialize" - )) + serde(bound(serialize = "DefaultAllocator: Allocator, + MatrixN: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator, - MatrixN: Deserialize<'de>" - )) + serde(bound(deserialize = "DefaultAllocator: Allocator, + MatrixN: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Schur -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { q: MatrixN, t: MatrixN, @@ -46,11 +43,12 @@ impl Copy for Schur where DefaultAllocator: Allocator, MatrixN: Copy, -{} +{ +} impl Schur where - D: DimSub, // For Hessenberg. + D: DimSub, // For Hessenberg. DefaultAllocator: Allocator> + Allocator> + Allocator @@ -87,8 +85,7 @@ where eps: N::RealField, max_niter: usize, compute_q: bool, - ) -> Option<(Option>, MatrixN)> - { + ) -> Option<(Option>, MatrixN)> { assert!( m.is_square(), "Unable to compute the eigenvectors and eigenvalues of a non-square matrix." @@ -291,8 +288,10 @@ where /// Computes the complex eigenvalues of the decomposed matrix. fn do_complex_eigenvalues(t: &MatrixN, out: &mut VectorN, D>) - where N: RealField, - DefaultAllocator: Allocator, D> { + where + N: RealField, + DefaultAllocator: Allocator, D>, + { let dim = t.nrows(); let mut m = 0; @@ -391,8 +390,10 @@ where /// Computes the complex eigenvalues of the decomposed matrix. pub fn complex_eigenvalues(&self) -> VectorN, D> - where N: RealField, - DefaultAllocator: Allocator, D> { + where + N: RealField, + DefaultAllocator: Allocator, D>, + { let mut out = unsafe { VectorN::new_uninitialized_generic(self.t.data.shape().0, U1) }; Self::do_complex_eigenvalues(&self.t, &mut out); out @@ -491,7 +492,7 @@ fn compute_2x2_basis>( impl> SquareMatrix where - D: DimSub, // For Hessenberg. + D: DimSub, // For Hessenberg. DefaultAllocator: Allocator> + Allocator> + Allocator @@ -560,8 +561,10 @@ where /// Computes the eigenvalues of this matrix. pub fn complex_eigenvalues(&self) -> VectorN, D> // FIXME: add balancing? - where N: RealField, - DefaultAllocator: Allocator, D> { + where + N: RealField, + DefaultAllocator: Allocator, D>, + { let dim = self.data.shape().0; let mut work = unsafe { VectorN::new_uninitialized_generic(dim, U1) }; diff --git a/src/linalg/solve.rs b/src/linalg/solve.rs index a6b9196f..56db4ade 100644 --- a/src/linalg/solve.rs +++ b/src/linalg/solve.rs @@ -1,10 +1,10 @@ -use alga::general::ComplexField; +use simba::scalar::ComplexField; use crate::base::allocator::Allocator; use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::base::dimension::{Dim, U1}; use crate::base::storage::{Storage, StorageMut}; -use crate::base::{DefaultAllocator, Matrix, MatrixMN, SquareMatrix, Vector, DVectorSlice}; +use crate::base::{DVectorSlice, DefaultAllocator, Matrix, MatrixMN, SquareMatrix, Vector}; impl> SquareMatrix { /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only @@ -190,10 +190,10 @@ impl> SquareMatrix { &self, b: &Matrix, ) -> Option> - where - S2: Storage, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = b.clone_owned(); if self.tr_solve_lower_triangular_mut(&mut res) { @@ -210,10 +210,10 @@ impl> SquareMatrix { &self, b: &Matrix, ) -> Option> - where - S2: Storage, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = b.clone_owned(); if self.tr_solve_upper_triangular_mut(&mut res) { @@ -229,14 +229,18 @@ impl> SquareMatrix { &self, b: &mut Matrix, ) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let cols = b.ncols(); for i in 0..cols { - if !self.xx_solve_lower_triangular_vector_mut(&mut b.column_mut(i), |e| e, |a, b| a.dot(b)) { + if !self.xx_solve_lower_triangular_vector_mut( + &mut b.column_mut(i), + |e| e, + |a, b| a.dot(b), + ) { return false; } } @@ -250,14 +254,18 @@ impl> SquareMatrix { &self, b: &mut Matrix, ) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let cols = b.ncols(); for i in 0..cols { - if !self.xx_solve_upper_triangular_vector_mut(&mut b.column_mut(i), |e| e, |a, b| a.dot(b)) { + if !self.xx_solve_upper_triangular_vector_mut( + &mut b.column_mut(i), + |e| e, + |a, b| a.dot(b), + ) { return false; } } @@ -272,10 +280,10 @@ impl> SquareMatrix { &self, b: &Matrix, ) -> Option> - where - S2: Storage, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = b.clone_owned(); if self.ad_solve_lower_triangular_mut(&mut res) { @@ -292,10 +300,10 @@ impl> SquareMatrix { &self, b: &Matrix, ) -> Option> - where - S2: Storage, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = b.clone_owned(); if self.ad_solve_upper_triangular_mut(&mut res) { @@ -311,14 +319,18 @@ impl> SquareMatrix { &self, b: &mut Matrix, ) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let cols = b.ncols(); for i in 0..cols { - if !self.xx_solve_lower_triangular_vector_mut(&mut b.column_mut(i), |e| e.conjugate(), |a, b| a.dotc(b)) { + if !self.xx_solve_lower_triangular_vector_mut( + &mut b.column_mut(i), + |e| e.conjugate(), + |a, b| a.dotc(b), + ) { return false; } } @@ -332,14 +344,18 @@ impl> SquareMatrix { &self, b: &mut Matrix, ) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let cols = b.ncols(); for i in 0..cols { - if !self.xx_solve_upper_triangular_vector_mut(&mut b.column_mut(i), |e| e.conjugate(), |a, b| a.dotc(b)) { + if !self.xx_solve_upper_triangular_vector_mut( + &mut b.column_mut(i), + |e| e.conjugate(), + |a, b| a.dotc(b), + ) { return false; } } @@ -347,17 +363,19 @@ impl> SquareMatrix { true } - #[inline(always)] fn xx_solve_lower_triangular_vector_mut( &self, b: &mut Vector, conjugate: impl Fn(N) -> N, - dot: impl Fn(&DVectorSlice, &DVectorSlice) -> N, + dot: impl Fn( + &DVectorSlice, + &DVectorSlice, + ) -> N, ) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let dim = self.nrows(); @@ -385,11 +403,14 @@ impl> SquareMatrix { &self, b: &mut Vector, conjugate: impl Fn(N) -> N, - dot: impl Fn(&DVectorSlice, &DVectorSlice) -> N, + dot: impl Fn( + &DVectorSlice, + &DVectorSlice, + ) -> N, ) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let dim = self.nrows(); diff --git a/src/linalg/svd.rs b/src/linalg/svd.rs index b608ec0c..6d74a438 100644 --- a/src/linalg/svd.rs +++ b/src/linalg/svd.rs @@ -1,19 +1,19 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use num::{Zero, One}; use approx::AbsDiffEq; +use num::{One, Zero}; -use alga::general::{RealField, ComplexField}; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, Matrix2x3, MatrixMN, Vector2, VectorN}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1, U2}; use crate::storage::Storage; +use simba::scalar::{ComplexField, RealField}; +use crate::linalg::givens::GivensRotation; use crate::linalg::symmetric_eigen; use crate::linalg::Bidiagonal; -use crate::linalg::givens::GivensRotation; /// Singular Value Decomposition of a general matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -41,9 +41,10 @@ use crate::linalg::givens::GivensRotation; )] #[derive(Clone, Debug)] pub struct SVD, C: Dim> -where DefaultAllocator: Allocator, C> +where + DefaultAllocator: Allocator, C> + Allocator> - + Allocator> + + Allocator>, { /// The left-singular vectors `U` of this SVD. pub u: Option>>, @@ -61,7 +62,8 @@ where MatrixMN>: Copy, MatrixMN, C>: Copy, VectorN>: Copy, -{} +{ +} impl, C: Dim> SVD where @@ -78,7 +80,14 @@ where { /// Computes the Singular Value Decomposition of `matrix` using implicit shift. pub fn new(matrix: MatrixMN, compute_u: bool, compute_v: bool) -> Self { - Self::try_new(matrix, compute_u, compute_v, N::RealField::default_epsilon(), 0).unwrap() + Self::try_new( + matrix, + compute_u, + compute_v, + N::RealField::default_epsilon(), + 0, + ) + .unwrap() } /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. @@ -97,8 +106,7 @@ where compute_v: bool, eps: N::RealField, max_niter: usize, - ) -> Option - { + ) -> Option { assert!( matrix.len() != 0, "Cannot compute the SVD of an empty matrix." @@ -120,7 +128,15 @@ where let mut off_diagonal = b.off_diagonal(); let mut niter = 0; - let (mut start, mut end) = Self::delimit_subproblem(&mut diagonal, &mut off_diagonal, &mut u, &mut v_t, b.is_upper_diagonal(), dim - 1, eps); + let (mut start, mut end) = Self::delimit_subproblem( + &mut diagonal, + &mut off_diagonal, + &mut u, + &mut v_t, + b.is_upper_diagonal(), + dim - 1, + eps, + ); while end != start { let subdim = end - start + 1; @@ -165,7 +181,8 @@ where ); if let Some((rot1, norm1)) = GivensRotation::cancel_y(&vec) { - rot1.inverse().rotate_rows(&mut subm.fixed_columns_mut::(0)); + rot1.inverse() + .rotate_rows(&mut subm.fixed_columns_mut::(0)); let rot1 = GivensRotation::new_unchecked(rot1.c(), N::from_real(rot1.s())); if k > start { @@ -175,8 +192,8 @@ where let v = Vector2::new(subm[(0, 0)], subm[(1, 0)]); // FIXME: does the case `v.y == 0` ever happen? - let (rot2, norm2) = - GivensRotation::cancel_y(&v).unwrap_or((GivensRotation::identity(), subm[(0, 0)])); + let (rot2, norm2) = GivensRotation::cancel_y(&v) + .unwrap_or((GivensRotation::identity(), subm[(0, 0)])); rot2.rotate(&mut subm.fixed_columns_mut::(1)); let rot2 = GivensRotation::new_unchecked(rot2.c(), N::from_real(rot2.s())); @@ -253,7 +270,15 @@ where } // Re-delimit the subproblem in case some decoupling occurred. - let sub = Self::delimit_subproblem(&mut diagonal, &mut off_diagonal, &mut u, &mut v_t, b.is_upper_diagonal(), end, eps); + let sub = Self::delimit_subproblem( + &mut diagonal, + &mut off_diagonal, + &mut u, + &mut v_t, + b.is_upper_diagonal(), + end, + eps, + ); start = sub.0; end = sub.1; @@ -308,8 +333,7 @@ where is_upper_diagonal: bool, end: usize, eps: N::RealField, - ) -> (usize, usize) - { + ) -> (usize, usize) { let mut n = end; while n > 0 { @@ -321,14 +345,36 @@ where off_diagonal[m] = N::RealField::zero(); } else if diagonal[m].norm1() <= eps { diagonal[m] = N::RealField::zero(); - Self::cancel_horizontal_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m, m + 1); + Self::cancel_horizontal_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m, + m + 1, + ); if m != 0 { - Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m - 1); + Self::cancel_vertical_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m - 1, + ); } } else if diagonal[n].norm1() <= eps { diagonal[n] = N::RealField::zero(); - Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m); + Self::cancel_vertical_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m, + ); } else { break; } @@ -352,10 +398,25 @@ where // FIXME: write a test that enters this case. else if diagonal[m].norm1() <= eps { diagonal[m] = N::RealField::zero(); - Self::cancel_horizontal_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m, n); + Self::cancel_horizontal_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m, + n, + ); if m != 0 { - Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m - 1); + Self::cancel_vertical_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m - 1, + ); } break; } @@ -375,8 +436,7 @@ where is_upper_diagonal: bool, i: usize, end: usize, - ) - { + ) { let mut v = Vector2::new(off_diagonal[i], diagonal[i + 1]); off_diagonal[i] = N::RealField::zero(); @@ -413,8 +473,7 @@ where v_t: &mut Option, C>>, is_upper_diagonal: bool, i: usize, - ) - { + ) { let mut v = Vector2::new(diagonal[i], off_diagonal[i]); off_diagonal[i] = N::RealField::zero(); @@ -469,7 +528,7 @@ where } (None, None) => Err("SVD recomposition: U and V^t have not been computed."), (None, _) => Err("SVD recomposition: U has not been computed."), - (_, None) => Err("SVD recomposition: V^t has not been computed.") + (_, None) => Err("SVD recomposition: V^t has not been computed."), } } @@ -484,8 +543,7 @@ where { if eps < N::RealField::zero() { Err("SVD pseudo inverse: the epsilon must be non-negative.") - } - else { + } else { for i in 0..self.singular_values.len() { let val = self.singular_values[i]; @@ -517,8 +575,7 @@ where { if eps < N::RealField::zero() { Err("SVD solve: the epsilon must be non-negative.") - } - else { + } else { match (&self.u, &self.v_t) { (Some(u), Some(v_t)) => { let mut ut_b = u.ad_mul(b); @@ -540,7 +597,7 @@ where } (None, None) => Err("SVD solve: U and V^t have not been computed."), (None, _) => Err("SVD solve: U has not been computed."), - (_, None) => Err("SVD solve: V^t has not been computed.") + (_, None) => Err("SVD solve: V^t has not been computed."), } } } @@ -580,8 +637,7 @@ where compute_v: bool, eps: N::RealField, max_niter: usize, - ) -> Option> - { + ) -> Option> { SVD::try_new(self.into_owned(), compute_u, compute_v, eps, max_niter) } @@ -609,7 +665,6 @@ where } } - // Explicit formulae inspired from the paper "Computing the Singular Values of 2-by-2 Complex // Matrices", Sanzheng Qiao and Xiaohong Wang. // http://www.cas.mcmaster.ca/sqrl/papers/sqrl5.pdf @@ -619,8 +674,11 @@ fn compute_2x2_uptrig_svd( m22: N, compute_u: bool, compute_v: bool, -) -> (Option>, Vector2, Option>) -{ +) -> ( + Option>, + Vector2, + Option>, +) { let two: N::RealField = crate::convert(2.0f64); let half: N::RealField = crate::convert(0.5f64); @@ -657,4 +715,4 @@ fn compute_2x2_uptrig_svd( } (u, Vector2::new(v1, v2), v_t) -} \ No newline at end of file +} diff --git a/src/linalg/symmetric_eigen.rs b/src/linalg/symmetric_eigen.rs index fc493dca..70f57cdf 100644 --- a/src/linalg/symmetric_eigen.rs +++ b/src/linalg/symmetric_eigen.rs @@ -1,14 +1,14 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use num::Zero; use approx::AbsDiffEq; +use num::Zero; -use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix2, MatrixN, SquareMatrix, Vector2, VectorN}; use crate::dimension::{Dim, DimDiff, DimSub, U1, U2}; use crate::storage::Storage; +use simba::scalar::ComplexField; use crate::linalg::givens::GivensRotation; use crate::linalg::SymmetricTridiagonal; @@ -17,25 +17,22 @@ use crate::linalg::SymmetricTridiagonal; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator, VectorN: Serialize, - MatrixN: Serialize" - )) + MatrixN: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator, VectorN: Deserialize<'de>, - MatrixN: Deserialize<'de>" - )) + MatrixN: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct SymmetricEigen -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// The eigenvectors of the decomposed matrix. pub eigenvectors: MatrixN, @@ -49,10 +46,12 @@ where DefaultAllocator: Allocator + Allocator, MatrixN: Copy, VectorN: Copy, -{} +{ +} impl SymmetricEigen -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Computes the eigendecomposition of the given symmetric matrix. /// @@ -60,8 +59,7 @@ where DefaultAllocator: Allocator + Allocator pub fn new(m: MatrixN) -> Self where D: DimSub, - DefaultAllocator: Allocator> + // For tridiagonalization - Allocator>, + DefaultAllocator: Allocator> + Allocator>, { Self::try_new(m, N::RealField::default_epsilon(), 0).unwrap() } @@ -80,8 +78,7 @@ where DefaultAllocator: Allocator + Allocator pub fn try_new(m: MatrixN, eps: N::RealField, max_niter: usize) -> Option where D: DimSub, - DefaultAllocator: Allocator> + // For tridiagonalization - Allocator>, + DefaultAllocator: Allocator> + Allocator>, { Self::do_decompose(m, true, eps, max_niter).map(|(vals, vecs)| SymmetricEigen { eigenvectors: vecs.unwrap(), @@ -97,8 +94,7 @@ where DefaultAllocator: Allocator + Allocator ) -> Option<(VectorN, Option>)> where D: DimSub, - DefaultAllocator: Allocator> + // For tridiagonalization - Allocator>, + DefaultAllocator: Allocator> + Allocator>, { assert!( m.is_square(), @@ -154,7 +150,6 @@ where DefaultAllocator: Allocator + Allocator off_diag[i - 1] = norm; } - let mii = diag[i]; let mjj = diag[j]; let mij = off_diag[i]; @@ -189,8 +184,10 @@ where DefaultAllocator: Allocator + Allocator } } else if subdim == 2 { let m = Matrix2::new( - diag[start], off_diag[start].conjugate(), - off_diag[start], diag[start + 1], + diag[start], + off_diag[start].conjugate(), + off_diag[start], + diag[start + 1], ); let eigvals = m.eigenvalues().unwrap(); let basis = Vector2::new(eigvals.x - diag[start + 1], off_diag[start]); @@ -305,8 +302,11 @@ pub fn wilkinson_shift(tmm: N, tnn: N, tmn: N) -> N { * */ impl, S: Storage> SquareMatrix -where DefaultAllocator: Allocator + Allocator> + - Allocator + Allocator> +where + DefaultAllocator: Allocator + + Allocator> + + Allocator + + Allocator>, { /// Computes the eigendecomposition of this symmetric matrix. /// @@ -326,7 +326,11 @@ where DefaultAllocator: Allocator + Allocator> + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm /// continues indefinitely until convergence. - pub fn try_symmetric_eigen(self, eps: N::RealField, max_niter: usize) -> Option> { + pub fn try_symmetric_eigen( + self, + eps: N::RealField, + max_niter: usize, + ) -> Option> { SymmetricEigen::try_new(self.into_owned(), eps, max_niter) } @@ -334,9 +338,14 @@ where DefaultAllocator: Allocator + Allocator> + /// /// Only the lower-triangular part of the matrix is read. pub fn symmetric_eigenvalues(&self) -> VectorN { - SymmetricEigen::do_decompose(self.clone_owned(), false, N::RealField::default_epsilon(), 0) - .unwrap() - .0 + SymmetricEigen::do_decompose( + self.clone_owned(), + false, + N::RealField::default_epsilon(), + 0, + ) + .unwrap() + .0 } } diff --git a/src/linalg/symmetric_tridiagonal.rs b/src/linalg/symmetric_tridiagonal.rs index 40da8677..f4dc13ba 100644 --- a/src/linalg/symmetric_tridiagonal.rs +++ b/src/linalg/symmetric_tridiagonal.rs @@ -1,11 +1,11 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, MatrixMN, MatrixN, SquareMatrix, VectorN}; use crate::dimension::{DimDiff, DimSub, U1}; use crate::storage::Storage; +use simba::scalar::ComplexField; use crate::linalg::householder; @@ -13,25 +13,22 @@ use crate::linalg::householder; #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator + + serde(bound(serialize = "DefaultAllocator: Allocator + Allocator>, MatrixN: Serialize, - VectorN>: Serialize" - )) + VectorN>: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator + + serde(bound(deserialize = "DefaultAllocator: Allocator + Allocator>, MatrixN: Deserialize<'de>, - VectorN>: Deserialize<'de>" - )) + VectorN>: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct SymmetricTridiagonal> -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { tri: MatrixN, off_diagonal: VectorN>, @@ -42,10 +39,12 @@ where DefaultAllocator: Allocator + Allocator>, MatrixN: Copy, VectorN>: Copy, -{} +{ +} impl> SymmetricTridiagonal -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { /// Computes the tridiagonalization of the symmetric matrix `m`. /// @@ -98,9 +97,16 @@ where DefaultAllocator: Allocator + Allocator> /// Retrieve the orthogonal transformation, diagonal, and off diagonal elements of this /// decomposition. - pub fn unpack(self) -> (MatrixN, VectorN, VectorN>) - where DefaultAllocator: Allocator - + Allocator> { + pub fn unpack( + self, + ) -> ( + MatrixN, + VectorN, + VectorN>, + ) + where + DefaultAllocator: Allocator + Allocator>, + { let diag = self.diagonal(); let q = self.q(); @@ -108,19 +114,31 @@ where DefaultAllocator: Allocator + Allocator> } /// Retrieve the diagonal, and off diagonal elements of this decomposition. - pub fn unpack_tridiagonal(self) -> (VectorN, VectorN>) - where DefaultAllocator: Allocator - + Allocator> { + pub fn unpack_tridiagonal( + self, + ) -> ( + VectorN, + VectorN>, + ) + where + DefaultAllocator: Allocator + Allocator>, + { (self.diagonal(), self.off_diagonal.map(N::modulus)) } /// The diagonal components of this decomposition. pub fn diagonal(&self) -> VectorN - where DefaultAllocator: Allocator { self.tri.map_diagonal(|e| e.real()) } + where + DefaultAllocator: Allocator, + { + self.tri.map_diagonal(|e| e.real()) + } /// The off-diagonal components of this decomposition. pub fn off_diagonal(&self) -> VectorN> - where DefaultAllocator: Allocator> { + where + DefaultAllocator: Allocator>, + { self.off_diagonal.map(N::modulus) } @@ -146,7 +164,8 @@ where DefaultAllocator: Allocator + Allocator> } impl, S: Storage> SquareMatrix -where DefaultAllocator: Allocator + Allocator> +where + DefaultAllocator: Allocator + Allocator>, { /// Computes the tridiagonalization of this symmetric matrix. /// diff --git a/src/sparse/cs_matrix.rs b/src/sparse/cs_matrix.rs index 9fc91af0..9ff656d4 100644 --- a/src/sparse/cs_matrix.rs +++ b/src/sparse/cs_matrix.rs @@ -1,5 +1,5 @@ -use alga::general::ClosedAdd; use num::Zero; +use simba::scalar::ClosedAdd; use std::iter; use std::marker::PhantomData; use std::ops::Range; @@ -7,9 +7,7 @@ use std::slice; use crate::allocator::Allocator; use crate::sparse::cs_utils; -use crate::{ - DefaultAllocator, Dim, Dynamic, Scalar, Vector, VectorN, U1 -}; +use crate::{DefaultAllocator, Dim, Dynamic, Scalar, Vector, VectorN, U1}; pub struct ColumnEntries<'a, N> { curr: usize, @@ -33,9 +31,11 @@ impl<'a, N: Clone> Iterator for ColumnEntries<'a, N> { if self.curr >= self.i.len() { None } else { - let res = Some((unsafe { self.i.get_unchecked(self.curr).clone() }, unsafe { - self.v.get_unchecked(self.curr).clone() - })); + let res = Some( + (unsafe { self.i.get_unchecked(self.curr).clone() }, unsafe { + self.v.get_unchecked(self.curr).clone() + }), + ); self.curr += 1; res } @@ -55,7 +55,6 @@ pub trait CsStorageIter<'a, N, R, C = U1> { /// Iterates through all the row indices of the j-th column. fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices; - #[inline(always)] /// Iterates through all the entries of the j-th column. fn column_entries(&'a self, j: usize) -> Self::ColumnEntries; } @@ -106,7 +105,8 @@ pub trait CsStorageMut: /// A storage of column-compressed sparse matrix based on a Vec. #[derive(Clone, Debug, PartialEq)] pub struct CsVecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { pub(crate) shape: (R, C), pub(crate) p: VectorN, @@ -115,7 +115,8 @@ where DefaultAllocator: Allocator } impl CsVecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// The value buffer of this storage. pub fn values(&self) -> &[N] { @@ -136,7 +137,8 @@ where DefaultAllocator: Allocator impl CsVecStorage where DefaultAllocator: Allocator {} impl<'a, N: Scalar, R: Dim, C: Dim> CsStorageIter<'a, N, R, C> for CsVecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type ColumnEntries = ColumnEntries<'a, N>; type ColumnRowIndices = iter::Cloned>; @@ -155,7 +157,8 @@ where DefaultAllocator: Allocator } impl CsStorage for CsVecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { #[inline] fn shape(&self) -> (R, C) { @@ -200,7 +203,8 @@ where DefaultAllocator: Allocator } impl<'a, N: Scalar, R: Dim, C: Dim> CsStorageIterMut<'a, N, R, C> for CsVecStorage -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { type ValuesMut = slice::IterMut<'a, N>; type ColumnEntriesMut = iter::Zip>, slice::IterMut<'a, N>>; @@ -220,8 +224,10 @@ where DefaultAllocator: Allocator } } -impl CsStorageMut for CsVecStorage where DefaultAllocator: Allocator -{} +impl CsStorageMut for CsVecStorage where + DefaultAllocator: Allocator +{ +} /* pub struct CsSliceStorage<'a, N: Scalar, R: Dim, C: DimAdd> { @@ -247,7 +253,8 @@ pub struct CsMatrix< pub type CsVector> = CsMatrix; impl CsMatrix -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Creates a new compressed sparse column matrix with the specified dimension and /// `nvals` possible non-zero values. @@ -403,7 +410,9 @@ impl> CsMatrix { /// Computes the transpose of this sparse matrix. pub fn transpose(&self) -> CsMatrix - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { let (nrows, ncols) = self.data.shape(); let nvals = self.len(); @@ -442,10 +451,13 @@ impl> CsMatrix { } impl CsMatrix -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { pub(crate) fn sort(&mut self) - where DefaultAllocator: Allocator { + where + DefaultAllocator: Allocator, + { // Size = R let nrows = self.data.shape().0; let mut workspace = unsafe { VectorN::new_uninitialized_generic(nrows, U1) }; @@ -477,7 +489,9 @@ where DefaultAllocator: Allocator // Remove dupliate entries on a sorted CsMatrix. pub(crate) fn dedup(&mut self) - where N: Zero + ClosedAdd { + where + N: Zero + ClosedAdd, + { let mut curr_i = 0; for j in 0..self.ncols() { diff --git a/src/sparse/cs_matrix_cholesky.rs b/src/sparse/cs_matrix_cholesky.rs index 4c3fffd8..db3c221a 100644 --- a/src/sparse/cs_matrix_cholesky.rs +++ b/src/sparse/cs_matrix_cholesky.rs @@ -7,7 +7,8 @@ use crate::{DefaultAllocator, Dim, RealField, VectorN, U1}; /// The cholesky decomposition of a column compressed sparse matrix. pub struct CsCholesky -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { // Non-zero pattern of the original matrix upper-triangular part. // Unlike the original matrix, the `original_p` array does contain the last sentinel value @@ -26,7 +27,8 @@ where DefaultAllocator: Allocator + Allocator } impl CsCholesky -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Computes the cholesky decomposition of the sparse matrix `m`. pub fn new(m: &CsMatrix) -> Self { @@ -260,8 +262,7 @@ where DefaultAllocator: Allocator + Allocator tree: &[usize], marks: &mut Vec, out: &mut Vec, - ) - { + ) { marks.clear(); marks.resize(tree.len(), false); @@ -333,24 +334,24 @@ where DefaultAllocator: Allocator + Allocator let mut counts: Vec<_> = iter::repeat(0).take(len).collect(); let mut reach = Vec::new(); let mut marks = Vec::new(); - + for i in 0..len { Self::reach(m, i, i, tree, &mut marks, &mut reach); - + for j in reach.drain(..) { counts[j] += 1; } } - + counts } - + fn tree_postorder(tree: &[usize]) -> Vec { // FIXME: avoid all those allocations? let mut first_child: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect(); let mut other_children: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect(); - + // Build the children list from the parent list. // The set of children of the node `i` is given by the linked list // starting at `first_child[i]`. The nodes of this list are then: @@ -362,10 +363,10 @@ where DefaultAllocator: Allocator + Allocator other_children[i] = brother; } } - + let mut stack = Vec::with_capacity(tree.len()); let mut postorder = Vec::with_capacity(tree.len()); - + for (i, node) in tree.iter().enumerate() { if *node == usize::max_value() { Self::dfs( @@ -377,10 +378,10 @@ where DefaultAllocator: Allocator + Allocator ) } } - + postorder } - + fn dfs( i: usize, first_child: &mut [usize], @@ -390,10 +391,10 @@ where DefaultAllocator: Allocator + Allocator ) { stack.clear(); stack.push(i); - + while let Some(n) = stack.pop() { let child = first_child[n]; - + if child == usize::max_value() { // No children left. result.push(n); diff --git a/src/sparse/cs_matrix_conversion.rs b/src/sparse/cs_matrix_conversion.rs index abf195e2..8025f94e 100644 --- a/src/sparse/cs_matrix_conversion.rs +++ b/src/sparse/cs_matrix_conversion.rs @@ -1,5 +1,5 @@ -use alga::general::ClosedAdd; use num::Zero; +use simba::scalar::ClosedAdd; use crate::allocator::Allocator; use crate::sparse::cs_utils; @@ -15,14 +15,14 @@ impl<'a, N: Scalar + Zero + ClosedAdd> CsMatrix { irows: &[usize], icols: &[usize], vals: &[N], - ) -> Self - { + ) -> Self { Self::from_triplet_generic(Dynamic::new(nrows), Dynamic::new(ncols), irows, icols, vals) } } impl<'a, N: Scalar + Zero + ClosedAdd, R: Dim, C: Dim> CsMatrix -where DefaultAllocator: Allocator + Allocator +where + DefaultAllocator: Allocator + Allocator, { /// Creates a column-compressed sparse matrix from a sparse matrix in triplet form. pub fn from_triplet_generic( @@ -31,8 +31,7 @@ where DefaultAllocator: Allocator + Allocator irows: &[usize], icols: &[usize], vals: &[N], - ) -> Self - { + ) -> Self { assert!(vals.len() == irows.len()); assert!(vals.len() == icols.len()); diff --git a/src/sparse/cs_matrix_ops.rs b/src/sparse/cs_matrix_ops.rs index 8a4c063a..803bc61f 100644 --- a/src/sparse/cs_matrix_ops.rs +++ b/src/sparse/cs_matrix_ops.rs @@ -1,5 +1,5 @@ -use alga::general::{ClosedAdd, ClosedMul}; use num::{One, Zero}; +use simba::scalar::{ClosedAdd, ClosedMul}; use std::ops::{Add, Mul}; use crate::allocator::Allocator; @@ -112,11 +112,11 @@ impl> Vect let col2 = a.column(0); let val = unsafe { *x.vget_unchecked(0) }; self.axpy_sparse(alpha * val, &col2, beta); - + for j in 1..ncols2 { let col2 = a.column(j); let val = unsafe { *x.vget_unchecked(j) }; - + self.axpy_sparse(alpha * val, &col2, N::one()); } } diff --git a/src/sparse/cs_matrix_solve.rs b/src/sparse/cs_matrix_solve.rs index 14ca9f78..73b50db3 100644 --- a/src/sparse/cs_matrix_solve.rs +++ b/src/sparse/cs_matrix_solve.rs @@ -264,8 +264,7 @@ impl> CsMatrix { visited: &mut [bool], stack: &mut Vec, xi: &mut Vec, - ) - { + ) { if !visited[start] { stack.clear(); stack.push(start); diff --git a/src/sparse/cs_utils.rs b/src/sparse/cs_utils.rs index a8a454eb..c73b9639 100644 --- a/src/sparse/cs_utils.rs +++ b/src/sparse/cs_utils.rs @@ -2,7 +2,9 @@ use crate::allocator::Allocator; use crate::{DefaultAllocator, Dim, VectorN}; pub fn cumsum(a: &mut VectorN, b: &mut VectorN) -> usize -where DefaultAllocator: Allocator { +where + DefaultAllocator: Allocator, +{ assert!(a.len() == b.len()); let mut sum = 0; diff --git a/tests/core/abomonation.rs b/tests/core/abomonation.rs index 01760e14..5148db81 100644 --- a/tests/core/abomonation.rs +++ b/tests/core/abomonation.rs @@ -32,8 +32,6 @@ test_abomonation! { } fn assert_encode_and_decode(original_data: T) { - use std::mem::drop; - // Hold on to a clone for later comparison let data = original_data.clone(); diff --git a/tests/core/conversion.rs b/tests/core/conversion.rs index 783654ca..74aa41e9 100644 --- a/tests/core/conversion.rs +++ b/tests/core/conversion.rs @@ -8,10 +8,10 @@ use na::{ RowVector4, RowVector5, RowVector6, Similarity3, Transform3, Translation3, UnitQuaternion, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, }; +use na::{DMatrix, DMatrixSlice, DMatrixSliceMut, MatrixSlice, MatrixSliceMut}; use na::{U1, U3, U4}; -use na::{DMatrix, MatrixSlice, MatrixSliceMut, DMatrixSlice, DMatrixSliceMut}; -quickcheck!{ +quickcheck! { fn translation_conversion(t: Translation3, v: Vector3, p: Point3) -> bool { let iso: Isometry3 = na::convert(t); let sim: Similarity3 = na::convert(t); @@ -255,9 +255,9 @@ array_matrix_conversion!( #[test] fn matrix_slice_from_matrix_ref() { - let a = Matrix3x4::new(11.0, 12.0, 13.0, 14.0, - 21.0, 22.0, 23.0, 24.0, - 31.0, 32.0, 33.0, 34.0); + let a = Matrix3x4::new( + 11.0, 12.0, 13.0, 14.0, 21.0, 22.0, 23.0, 24.0, 31.0, 32.0, 33.0, 34.0, + ); // TODO: What's a more idiomatic/better way to convert a static matrix to a dynamic one? let d = DMatrix::from(a.get((0..a.nrows(), 0..a.ncols())).unwrap()); @@ -265,11 +265,25 @@ fn matrix_slice_from_matrix_ref() { // Note: these have to be macros, and not functions, because the input type is different // across the different tests. Moreover, the output type depends on the stride of the input, // which is different for static and dynamic matrices. - macro_rules! dynamic_slice { ($mref:expr) => { DMatrixSlice::<_>::from($mref) } } - macro_rules! dynamic_slice_mut { ($mref:expr) => { DMatrixSliceMut::<_>::from($mref) } } - macro_rules! fixed_slice { ($mref:expr) => { MatrixSlice::<_, U3, U4, U1, U3>::from($mref)} }; + macro_rules! dynamic_slice { + ($mref:expr) => { + DMatrixSlice::<_>::from($mref) + }; + } + macro_rules! dynamic_slice_mut { + ($mref:expr) => { + DMatrixSliceMut::<_>::from($mref) + }; + } + macro_rules! fixed_slice { + ($mref:expr) => { + MatrixSlice::<_, U3, U4, U1, U3>::from($mref) + }; + }; macro_rules! fixed_slice_mut { - ($mref:expr) => { MatrixSliceMut::<_, U3, U4, U1, U3>::from($mref) } + ($mref:expr) => { + MatrixSliceMut::<_, U3, U4, U1, U3>::from($mref) + }; }; // TODO: The `into_owned()` is a result of `PartialEq` not being implemented for different diff --git a/tests/core/empty.rs b/tests/core/empty.rs index 3e17ee1b..f2a52e6d 100644 --- a/tests/core/empty.rs +++ b/tests/core/empty.rs @@ -57,4 +57,4 @@ fn empty_matrix_gemm_tr() { let m2 = DMatrix::::zeros(0, 4); res.gemm_tr(1.0, &m1, &m2, 0.5); assert_eq!(res, DMatrix::repeat(3, 4, 0.5)); -} \ No newline at end of file +} diff --git a/tests/core/helper.rs b/tests/core/helper.rs index 625a4a46..42938580 100644 --- a/tests/core/helper.rs +++ b/tests/core/helper.rs @@ -1,11 +1,11 @@ // This module implement several methods to fill some // missing features of num-complex when it comes to randomness. -use quickcheck::{Arbitrary, Gen}; -use rand::distributions::{Standard, Distribution}; -use rand::Rng; -use num_complex::Complex; use na::RealField; +use num_complex::Complex; +use quickcheck::{Arbitrary, Gen}; +use rand::distributions::{Distribution, Standard}; +use rand::Rng; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct RandComplex(pub Complex); @@ -20,8 +20,8 @@ impl Arbitrary for RandComplex { } impl Distribution> for Standard - where - Standard: Distribution, +where + Standard: Distribution, { #[inline] fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> RandComplex { @@ -44,11 +44,11 @@ impl Arbitrary for RandScalar { } impl Distribution> for Standard - where - Standard: Distribution, +where + Standard: Distribution, { #[inline] fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> RandScalar { RandScalar(self.sample(rng)) } -} \ No newline at end of file +} diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 6fad5e8c..9e25db58 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1,15 +1,12 @@ use num::{One, Zero}; use std::cmp::Ordering; -use na::dimension::{U15, U8, U2, U4}; +use na::dimension::{U15, U2, U4, U8}; use na::{ self, DMatrix, DVector, Matrix2, Matrix2x3, Matrix2x4, Matrix3, Matrix3x2, Matrix3x4, Matrix4, - Matrix4x3, Matrix4x5, Matrix5, Matrix6, MatrixMN, RowVector3, RowVector4, RowVector5, - Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, + Matrix4x3, Matrix4x5, Matrix5, Matrix6, MatrixMN, RowVector3, RowVector4, RowVector5, Vector1, + Vector2, Vector3, Vector4, Vector5, Vector6, }; -use typenum::{UInt, UTerm}; -use serde_json::error::Category::Data; -use typenum::bit::{B0, B1}; #[test] fn iter() { @@ -1025,7 +1022,9 @@ mod finite_dim_inner_space_tests { * */ #[cfg(feature = "arbitrary")] - fn is_subspace_basis + Display>(vs: &[T]) -> bool { + fn is_subspace_basis + Display>( + vs: &[T], + ) -> bool { for i in 0..vs.len() { // Basis elements must be normalized. if !relative_eq!(vs[i].norm(), 1.0, epsilon = 1.0e-7) { @@ -1066,7 +1065,7 @@ fn partial_eq_different_types() { let static_mat = Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8); let mut typenum_static_mat = MatrixMN::::zeros(); - let mut slice = typenum_static_mat.slice_mut((0,0), (2, 4)); + let mut slice = typenum_static_mat.slice_mut((0, 0), (2, 4)); slice += static_mat; let fslice_of_dmat = dynamic_mat.fixed_slice::(0, 0); @@ -1107,5 +1106,4 @@ fn partial_eq_different_types() { // TODO - implement those comparisons // assert_ne!(static_mat, typenum_static_mat); //assert_ne!(typenum_static_mat, static_mat); - } diff --git a/tests/core/mod.rs b/tests/core/mod.rs index f8c7e477..6e897c85 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -5,11 +5,10 @@ mod conversion; mod edition; mod matrix; mod matrix_slice; +mod empty; #[cfg(feature = "mint")] mod mint; mod serde; -mod empty; - #[cfg(feature = "arbitrary")] -pub mod helper; \ No newline at end of file +pub mod helper; diff --git a/tests/core/serde.rs b/tests/core/serde.rs index 781ace77..aced2a9f 100644 --- a/tests/core/serde.rs +++ b/tests/core/serde.rs @@ -1,9 +1,9 @@ #![cfg(feature = "serde-serialize")] use na::{ - DMatrix, Isometry3, IsometryMatrix3, Matrix3x4, Point3, Quaternion, Rotation3, Similarity3, - SimilarityMatrix3, Translation3, Unit, Point2, Translation2, Rotation2, Isometry2, IsometryMatrix2, - Similarity2, SimilarityMatrix2, + DMatrix, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix3x4, Point2, Point3, + Quaternion, Rotation2, Rotation3, Similarity2, Similarity3, SimilarityMatrix2, + SimilarityMatrix3, Translation2, Translation3, Unit, }; use rand; use serde_json; diff --git a/tests/geometry/isometry.rs b/tests/geometry/isometry.rs index ecf29e94..6d48c6bf 100644 --- a/tests/geometry/isometry.rs +++ b/tests/geometry/isometry.rs @@ -75,6 +75,7 @@ quickcheck!( ) } + #[cfg_attr(rustfmt, rustfmt_skip)] fn composition2( i: Isometry2, uc: UnitComplex, @@ -82,8 +83,7 @@ quickcheck!( t: Translation2, v: Vector2, p: Point2 - ) -> bool - { + ) -> bool { // (rotation × translation) * point = rotation × (translation * point) relative_eq!((uc * t) * v, uc * v, epsilon = 1.0e-7) && relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) && @@ -113,6 +113,7 @@ quickcheck!( relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7) } + #[cfg_attr(rustfmt, rustfmt_skip)] fn composition3( i: Isometry3, uq: UnitQuaternion, @@ -120,8 +121,7 @@ quickcheck!( t: Translation3, v: Vector3, p: Point3 - ) -> bool - { + ) -> bool { // (rotation × translation) * point = rotation × (translation * point) relative_eq!((uq * t) * v, uq * v, epsilon = 1.0e-7) && relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) && @@ -151,6 +151,7 @@ quickcheck!( relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7) } + #[cfg_attr(rustfmt, rustfmt_skip)] fn all_op_exist( i: Isometry3, uq: UnitQuaternion, @@ -158,8 +159,7 @@ quickcheck!( v: Vector3, p: Point3, r: Rotation3 - ) -> bool - { + ) -> bool { let iMi = i * i; let iMuq = i * uq; let iDi = i / i; diff --git a/tests/geometry/projection.rs b/tests/geometry/projection.rs index 03c6d4df..626c4ffb 100644 --- a/tests/geometry/projection.rs +++ b/tests/geometry/projection.rs @@ -37,7 +37,7 @@ fn perspective_matrix_point_transformation() { mod quickcheck_tests { use na::{Orthographic3, Perspective3, Point3}; - quickcheck!{ + quickcheck! { fn perspective_project_unproject(pt: Point3) -> bool { let proj = Perspective3::new(800.0 / 600.0, 3.14 / 2.0, 1.0, 1000.0); diff --git a/tests/geometry/quaternion.rs b/tests/geometry/quaternion.rs index 4dd3da62..77456ca0 100644 --- a/tests/geometry/quaternion.rs +++ b/tests/geometry/quaternion.rs @@ -10,15 +10,15 @@ quickcheck!( * */ fn from_euler_angles(r: f64, p: f64, y: f64) -> bool { - let roll = UnitQuaternion::from_euler_angles(r, 0.0, 0.0); + let roll = UnitQuaternion::from_euler_angles(r, 0.0, 0.0); let pitch = UnitQuaternion::from_euler_angles(0.0, p, 0.0); - let yaw = UnitQuaternion::from_euler_angles(0.0, 0.0, y); + let yaw = UnitQuaternion::from_euler_angles(0.0, 0.0, y); let rpy = UnitQuaternion::from_euler_angles(r, p, y); - let rroll = roll.to_rotation_matrix(); + let rroll = roll.to_rotation_matrix(); let rpitch = pitch.to_rotation_matrix(); - let ryaw = yaw.to_rotation_matrix(); + let ryaw = yaw.to_rotation_matrix(); relative_eq!(rroll[(0, 0)], 1.0, epsilon = 1.0e-7) && // rotation wrt. x axis. relative_eq!(rpitch[(1, 1)], 1.0, epsilon = 1.0e-7) && // rotation wrt. y axis. @@ -29,22 +29,24 @@ quickcheck!( fn euler_angles(r: f64, p: f64, y: f64) -> bool { let rpy = UnitQuaternion::from_euler_angles(r, p, y); let (roll, pitch, yaw) = rpy.euler_angles(); - relative_eq!(UnitQuaternion::from_euler_angles(roll, pitch, yaw), rpy, epsilon = 1.0e-7) + relative_eq!( + UnitQuaternion::from_euler_angles(roll, pitch, yaw), + rpy, + epsilon = 1.0e-7 + ) } - /* * * From/to rotation matrix. * */ fn unit_quaternion_rotation_conversion(q: UnitQuaternion) -> bool { - let r = q.to_rotation_matrix(); + let r = q.to_rotation_matrix(); let qq = UnitQuaternion::from_rotation_matrix(&r); let rr = qq.to_rotation_matrix(); - relative_eq!(q, qq, epsilon = 1.0e-7) && - relative_eq!(r, rr, epsilon = 1.0e-7) + relative_eq!(q, qq, epsilon = 1.0e-7) && relative_eq!(r, rr, epsilon = 1.0e-7) } /* @@ -52,23 +54,27 @@ quickcheck!( * Point/Vector transformation. * */ - fn unit_quaternion_transformation(q: UnitQuaternion, v: Vector3, p: Point3) -> bool { + + #[cfg_attr(rustfmt, rustfmt_skip)] + fn unit_quaternion_transformation( + q: UnitQuaternion, + v: Vector3, + p: Point3 + ) -> bool { let r = q.to_rotation_matrix(); let rv = r * v; let rp = r * p; - relative_eq!( q * v, rv, epsilon = 1.0e-7) && - relative_eq!( q * &v, rv, epsilon = 1.0e-7) && - relative_eq!(&q * v, rv, epsilon = 1.0e-7) && - relative_eq!(&q * &v, rv, epsilon = 1.0e-7) && - - relative_eq!( q * p, rp, epsilon = 1.0e-7) && - relative_eq!( q * &p, rp, epsilon = 1.0e-7) && - relative_eq!(&q * p, rp, epsilon = 1.0e-7) && - relative_eq!(&q * &p, rp, epsilon = 1.0e-7) + relative_eq!(q * v, rv, epsilon = 1.0e-7) + && relative_eq!(q * &v, rv, epsilon = 1.0e-7) + && relative_eq!(&q * v, rv, epsilon = 1.0e-7) + && relative_eq!(&q * &v, rv, epsilon = 1.0e-7) + && relative_eq!(q * p, rp, epsilon = 1.0e-7) + && relative_eq!(q * &p, rp, epsilon = 1.0e-7) + && relative_eq!(&q * p, rp, epsilon = 1.0e-7) + && relative_eq!(&q * &p, rp, epsilon = 1.0e-7) } - /* * * Inversion. @@ -76,15 +82,14 @@ quickcheck!( */ fn unit_quaternion_inv(q: UnitQuaternion) -> bool { let iq = q.inverse(); - relative_eq!(&iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7) && - relative_eq!( iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7) && - relative_eq!(&iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7) && - relative_eq!( iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7) && - - relative_eq!(&q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7) && - relative_eq!( q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7) && - relative_eq!(&q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7) && - relative_eq!( q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7) + relative_eq!(&iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(&iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(&q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(&q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7) + && relative_eq!(q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7) } /* @@ -98,8 +103,8 @@ quickcheck!( relative_eq!(q * v, r * v, epsilon = 1.0e-7) && relative_eq!(q * p, r * p, epsilon = 1.0e-7) && // Equivalence q = -q - relative_eq!((-q) * v, r * v, epsilon = 1.0e-7) && - relative_eq!((-q) * p, r * p, epsilon = 1.0e-7) + relative_eq!(UnitQuaternion::new_unchecked(-q.into_inner()) * v, r * v, epsilon = 1.0e-7) && + relative_eq!(UnitQuaternion::new_unchecked(-q.into_inner()) * p, r * p, epsilon = 1.0e-7) } /* @@ -108,7 +113,7 @@ quickcheck!( * */ fn unit_quaternion_double_covering(q: UnitQuaternion) -> bool { - let mq = -q; + let mq = UnitQuaternion::new_unchecked(-q.into_inner()); mq == q && mq.angle() == q.angle() && mq.axis() == q.axis() } @@ -116,28 +121,34 @@ quickcheck!( // Test that all operators (incl. all combinations of references) work. // See the top comment on `geometry/quaternion_ops.rs` for details on which operations are // supported. - fn all_op_exist(q: Quaternion, uq: UnitQuaternion, - v: Vector3, p: Point3, r: Rotation3, - s: f64) -> bool { + #[cfg_attr(rustfmt, rustfmt_skip)] + fn all_op_exist( + q: Quaternion, + uq: UnitQuaternion, + v: Vector3, + p: Point3, + r: Rotation3, + s: f64 + ) -> bool { let uv = Unit::new_normalize(v); let qpq = q + q; let qmq = q - q; let qMq = q * q; - let mq = -q; + let mq = -q; let qMs = q * s; let qDs = q / s; let sMq = s * q; let uqMuq = uq * uq; - let uqMr = uq * r; - let rMuq = r * uq; + let uqMr = uq * r; + let rMuq = r * uq; let uqDuq = uq / uq; - let uqDr = uq / r; - let rDuq = r / uq; + let uqDr = uq / r; + let rDuq = r / uq; - let uqMp = uq * p; - let uqMv = uq * v; + let uqMp = uq * p; + let uqMv = uq * v; let uqMuv = uq * uv; let mut qMs1 = q; @@ -186,81 +197,60 @@ quickcheck!( uqDr1 /= r; uqDr2 /= &r; - qMs1 == qMs && - - qMq1 == qMq && - qMq1 == qMq2 && - - qpq1 == qpq && - qpq1 == qpq2 && - - qmq1 == qmq && - qmq1 == qmq2 && - - uqMuq1 == uqMuq && - uqMuq1 == uqMuq2 && - - uqMr1 == uqMr && - uqMr1 == uqMr2 && - - uqDuq1 == uqDuq && - uqDuq1 == uqDuq2 && - - uqDr1 == uqDr && - uqDr1 == uqDr2 && - - qpq == &q + &q && - qpq == q + &q && - qpq == &q + q && - - qmq == &q - &q && - qmq == q - &q && - qmq == &q - q && - - qMq == &q * &q && - qMq == q * &q && - qMq == &q * q && - - mq == -&q && - - qMs == &q * s && - qDs == &q / s && - sMq == s * &q && - - uqMuq == &uq * &uq && - uqMuq == uq * &uq && - uqMuq == &uq * uq && - - uqMr == &uq * &r && - uqMr == uq * &r && - uqMr == &uq * r && - - rMuq == &r * &uq && - rMuq == r * &uq && - rMuq == &r * uq && - - uqDuq == &uq / &uq && - uqDuq == uq / &uq && - uqDuq == &uq / uq && - - uqDr == &uq / &r && - uqDr == uq / &r && - uqDr == &uq / r && - - rDuq == &r / &uq && - rDuq == r / &uq && - rDuq == &r / uq && - - uqMp == &uq * &p && - uqMp == uq * &p && - uqMp == &uq * p && - - uqMv == &uq * &v && - uqMv == uq * &v && - uqMv == &uq * v && - - uqMuv == &uq * &uv && - uqMuv == uq * &uv && - uqMuv == &uq * uv + qMs1 == qMs + && qMq1 == qMq + && qMq1 == qMq2 + && qpq1 == qpq + && qpq1 == qpq2 + && qmq1 == qmq + && qmq1 == qmq2 + && uqMuq1 == uqMuq + && uqMuq1 == uqMuq2 + && uqMr1 == uqMr + && uqMr1 == uqMr2 + && uqDuq1 == uqDuq + && uqDuq1 == uqDuq2 + && uqDr1 == uqDr + && uqDr1 == uqDr2 + && qpq == &q + &q + && qpq == q + &q + && qpq == &q + q + && qmq == &q - &q + && qmq == q - &q + && qmq == &q - q + && qMq == &q * &q + && qMq == q * &q + && qMq == &q * q + && mq == -&q + && qMs == &q * s + && qDs == &q / s + && sMq == s * &q + && uqMuq == &uq * &uq + && uqMuq == uq * &uq + && uqMuq == &uq * uq + && uqMr == &uq * &r + && uqMr == uq * &r + && uqMr == &uq * r + && rMuq == &r * &uq + && rMuq == r * &uq + && rMuq == &r * uq + && uqDuq == &uq / &uq + && uqDuq == uq / &uq + && uqDuq == &uq / uq + && uqDr == &uq / &r + && uqDr == uq / &r + && uqDr == &uq / r + && rDuq == &r / &uq + && rDuq == r / &uq + && rDuq == &r / uq + && uqMp == &uq * &p + && uqMp == uq * &p + && uqMp == &uq * p + && uqMv == &uq * &v + && uqMv == uq * &v + && uqMv == &uq * v + && uqMuv == &uq * &uv + && uqMuv == uq * &uv + && uqMuv == &uq * uv } ); diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index c0886754..2ada2939 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -32,8 +32,8 @@ fn quaternion_euler_angles_issue_494() { #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use alga::general::RealField; use na::{self, Rotation2, Rotation3, Unit, Vector2, Vector3}; + use simba::scalar::RealField; use std::f64; quickcheck! { diff --git a/tests/geometry/similarity.rs b/tests/geometry/similarity.rs index a5736864..b93d2e51 100644 --- a/tests/geometry/similarity.rs +++ b/tests/geometry/similarity.rs @@ -15,12 +15,12 @@ quickcheck!( && relative_eq!((ii * i) * v, v, epsilon = 1.0e-7) } + #[cfg_attr(rustfmt, rustfmt_skip)] fn inverse_is_parts_inversion( t: Translation3, r: UnitQuaternion, scaling: f64 - ) -> bool - { + ) -> bool { if relative_eq!(scaling, 0.0) { true } else { @@ -29,12 +29,12 @@ quickcheck!( } } + #[cfg_attr(rustfmt, rustfmt_skip)] fn multiply_equals_alga_transform( s: Similarity3, v: Vector3, p: Point3 - ) -> bool - { + ) -> bool { s * v == s.transform_vector(&v) && s * p == s.transform_point(&p) && relative_eq!( @@ -49,6 +49,7 @@ quickcheck!( ) } + #[cfg_attr(rustfmt, rustfmt_skip)] fn composition( i: Isometry3, uq: UnitQuaternion, @@ -56,8 +57,7 @@ quickcheck!( v: Vector3, p: Point3, scaling: f64 - ) -> bool - { + ) -> bool { if relative_eq!(scaling, 0.0) { return true; } @@ -145,6 +145,7 @@ quickcheck!( relative_eq!((s * i * t) * p, scaling * (i * (t * p)), epsilon = 1.0e-7) } + #[cfg_attr(rustfmt, rustfmt_skip)] fn all_op_exist( s: Similarity3, i: Isometry3, @@ -152,8 +153,7 @@ quickcheck!( t: Translation3, v: Vector3, p: Point3 - ) -> bool - { + ) -> bool { let sMs = s * s; let sMuq = s * uq; let sDs = s / s; diff --git a/tests/geometry/unit_complex.rs b/tests/geometry/unit_complex.rs index 46998036..263ecd33 100644 --- a/tests/geometry/unit_complex.rs +++ b/tests/geometry/unit_complex.rs @@ -68,13 +68,13 @@ quickcheck!( // Test that all operators (incl. all combinations of references) work. // See the top comment on `geometry/quaternion_ops.rs` for details on which operations are // supported. + #[cfg_attr(rustfmt, rustfmt_skip)] fn all_op_exist( uc: UnitComplex, v: Vector2, p: Point2, r: Rotation2 - ) -> bool - { + ) -> bool { let uv = Unit::new_normalize(v); let ucMuc = uc * uc; diff --git a/tests/lib.rs b/tests/lib.rs index f6634d0f..ee180666 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,6 +1,5 @@ #[cfg(feature = "abomonation-serialize")] extern crate abomonation; -extern crate alga; #[macro_use] extern crate approx; #[cfg(feature = "mint")] @@ -10,9 +9,6 @@ extern crate num_traits as num; #[cfg(feature = "arbitrary")] #[macro_use] extern crate quickcheck; -extern crate rand; -extern crate serde_json; -extern crate num_complex; mod core; mod geometry; diff --git a/tests/linalg/bidiagonal.rs b/tests/linalg/bidiagonal.rs index 9778eea3..8fefb4a2 100644 --- a/tests/linalg/bidiagonal.rs +++ b/tests/linalg/bidiagonal.rs @@ -75,4 +75,4 @@ fn bidiagonal_identity() { let bidiagonal = m.clone().bidiagonalize(); let (u, d, v_t) = bidiagonal.unpack(); assert_eq!(m, &u * d * &v_t); -} \ No newline at end of file +} diff --git a/tests/linalg/convolution.rs b/tests/linalg/convolution.rs index 65380162..84f42a6e 100644 --- a/tests/linalg/convolution.rs +++ b/tests/linalg/convolution.rs @@ -1,4 +1,4 @@ -use na::{Vector2,Vector3,Vector4,Vector5,DVector}; +use na::{DVector, Vector2, Vector3, Vector4, Vector5}; use std::panic; // @@ -9,111 +9,109 @@ use std::panic; // >>> convolve([1,2,3,4],[1,2],"same") // array([ 1, 4, 7, 10]) #[test] -fn convolve_same_check(){ +fn convolve_same_check() { // Static Tests - let actual_s = Vector4::new(1.0, 4.0, 7.0, 10.0); + let actual_s = Vector4::new(1.0, 4.0, 7.0, 10.0); let expected_s = Vector4::new(1.0, 2.0, 3.0, 4.0).convolve_same(Vector2::new(1.0, 2.0)); assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); // Dynamic Tests - let actual_d = DVector::from_vec(vec![1.0, 4.0, 7.0, 10.0]); - let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_same(DVector::from_vec(vec![1.0, 2.0])); + let actual_d = DVector::from_vec(vec![1.0, 4.0, 7.0, 10.0]); + let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) + .convolve_same(DVector::from_vec(vec![1.0, 2.0])); assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7)); // Panic Tests // These really only apply to dynamic sized vectors - assert!( - panic::catch_unwind(|| { - DVector::from_vec(vec![1.0, 2.0]).convolve_same(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::from_vec(vec![1.0, 2.0]) + .convolve_same(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); + }) + .is_err()); - assert!( - panic::catch_unwind(|| { - DVector::::from_vec(vec![]).convolve_same(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::::from_vec(vec![]).convolve_same(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); + }) + .is_err()); - assert!( - panic::catch_unwind(|| { - DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_same(DVector::::from_vec(vec![])); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_same(DVector::::from_vec(vec![])); + }) + .is_err()); } // >>> convolve([1,2,3,4],[1,2],"full") // array([ 1, 4, 7, 10, 8]) #[test] -fn convolve_full_check(){ +fn convolve_full_check() { // Static Tests - let actual_s = Vector5::new(1.0, 4.0, 7.0, 10.0, 8.0); + let actual_s = Vector5::new(1.0, 4.0, 7.0, 10.0, 8.0); let expected_s = Vector4::new(1.0, 2.0, 3.0, 4.0).convolve_full(Vector2::new(1.0, 2.0)); assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); // Dynamic Tests - let actual_d = DVector::from_vec(vec![1.0, 4.0, 7.0, 10.0, 8.0]); - let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_full(DVector::from_vec(vec![1.0, 2.0])); + let actual_d = DVector::from_vec(vec![1.0, 4.0, 7.0, 10.0, 8.0]); + let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) + .convolve_full(DVector::from_vec(vec![1.0, 2.0])); assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7)); // Panic Tests // These really only apply to dynamic sized vectors - assert!( - panic::catch_unwind(|| { - DVector::from_vec(vec![1.0, 2.0] ).convolve_full(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0] )); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::from_vec(vec![1.0, 2.0]) + .convolve_full(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); + }) + .is_err()); - assert!( - panic::catch_unwind(|| { - DVector::::from_vec(vec![]).convolve_full(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0] )); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::::from_vec(vec![]).convolve_full(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); + }) + .is_err()); - assert!( - panic::catch_unwind(|| { - DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0] ).convolve_full(DVector::::from_vec(vec![])); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_full(DVector::::from_vec(vec![])); + }) + .is_err()); } // >>> convolve([1, 2, 3, 4],[1, 2],"valid") // array([4, 7, 10]) #[test] -fn convolve_valid_check(){ +fn convolve_valid_check() { // Static Tests - let actual_s = Vector3::from_vec(vec![4.0, 7.0, 10.0]); - let expected_s = Vector4::new(1.0, 2.0, 3.0, 4.0).convolve_valid( Vector2::new(1.0, 2.0)); + let actual_s = Vector3::from_vec(vec![4.0, 7.0, 10.0]); + let expected_s = Vector4::new(1.0, 2.0, 3.0, 4.0).convolve_valid(Vector2::new(1.0, 2.0)); assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); // Dynamic Tests - let actual_d = DVector::from_vec(vec![4.0, 7.0, 10.0]); - let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_valid(DVector::from_vec(vec![1.0, 2.0])); + let actual_d = DVector::from_vec(vec![4.0, 7.0, 10.0]); + let expected_d = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) + .convolve_valid(DVector::from_vec(vec![1.0, 2.0])); assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7)); // Panic Tests // These really only apply to dynamic sized vectors - assert!( - panic::catch_unwind(|| { - DVector::from_vec(vec![1.0, 2.0]).convolve_valid(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::from_vec(vec![1.0, 2.0]) + .convolve_valid(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); + }) + .is_err()); - assert!( - panic::catch_unwind(|| { - DVector::::from_vec(vec![]).convolve_valid(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); - }).is_err() - ); + assert!(panic::catch_unwind(|| { + DVector::::from_vec(vec![]) + .convolve_valid(DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0])); + }) + .is_err()); - assert!( - panic::catch_unwind(|| { - DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]).convolve_valid(DVector::::from_vec(vec![])); - }).is_err() - ); - -} \ No newline at end of file + assert!(panic::catch_unwind(|| { + DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]) + .convolve_valid(DVector::::from_vec(vec![])); + }) + .is_err()); +} diff --git a/tests/linalg/hessenberg.rs b/tests/linalg/hessenberg.rs index 378fbd87..ec499f82 100644 --- a/tests/linalg/hessenberg.rs +++ b/tests/linalg/hessenberg.rs @@ -2,7 +2,6 @@ use na::Matrix2; - #[test] fn hessenberg_simple() { let m = Matrix2::new(1.0, 0.0, 1.0, 3.0); @@ -11,7 +10,6 @@ fn hessenberg_simple() { assert!(relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7)) } - macro_rules! gen_tests( ($module: ident, $scalar: ty) => { mod $module { @@ -49,4 +47,4 @@ macro_rules! gen_tests( ); gen_tests!(complex, RandComplex); -gen_tests!(f64, RandScalar); \ No newline at end of file +gen_tests!(f64, RandScalar); diff --git a/tests/linalg/inverse.rs b/tests/linalg/inverse.rs index 61f43324..f0be4dd7 100644 --- a/tests/linalg/inverse.rs +++ b/tests/linalg/inverse.rs @@ -130,7 +130,7 @@ fn matrix5_try_inverse_scaled_identity() { 0.0, 1.0e+20, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0e+20, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0e+20, 0.0, - 0.0, 0.0, 0.0, 0.0, 1.0e+20);; + 0.0, 0.0, 0.0, 0.0, 1.0e+20); let a_inv = a.try_inverse().expect("Matrix should be invertible"); assert_relative_eq!(a_inv, expected_inverse); diff --git a/tests/linalg/mod.rs b/tests/linalg/mod.rs index e881d999..234cac39 100644 --- a/tests/linalg/mod.rs +++ b/tests/linalg/mod.rs @@ -10,5 +10,5 @@ mod qr; mod schur; mod solve; mod svd; +mod convolution; mod tridiagonal; -mod convolution; \ No newline at end of file diff --git a/tests/linalg/tridiagonal.rs b/tests/linalg/tridiagonal.rs index 5d04587e..7f7300a1 100644 --- a/tests/linalg/tridiagonal.rs +++ b/tests/linalg/tridiagonal.rs @@ -51,6 +51,5 @@ macro_rules! gen_tests( } ); - gen_tests!(complex, RandComplex); gen_tests!(f64, RandScalar);