diff --git a/Cargo.toml b/Cargo.toml index 0c53df562..79d761f3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.17.2" +version = "0.17.3" authors = [ "Sébastien Crozet " ] description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices." @@ -11,6 +11,7 @@ readme = "README.md" categories = [ "science" ] keywords = [ "linear", "algebra", "matrix", "vector", "math" ] license = "BSD-3-Clause" +edition = "2018" exclude = ["/ci/*", "/.travis.yml", "/Makefile"] @@ -26,7 +27,7 @@ arbitrary = [ "quickcheck" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] abomonation-serialize = [ "abomonation" ] sparse = [ ] -debug = [ ] +debug = [ "approx/num-complex", "rand/std" ] alloc = [ ] io = [ "pest", "pest_derive" ] @@ -53,6 +54,19 @@ alga = { git = "https://github.com/rustsim/alga", branch = "dev" } [dev-dependencies] serde_json = "1.0" rand_xorshift = "0.1" +### Uncomment this line before running benchmarks. +### We can't just let this uncommented because that would breack +### compilation for #[no-std] because of the terrible Cargo bug +### https://github.com/rust-lang/cargo/issues/4866 +#criterion = "0.2.10" [workspace] members = [ "nalgebra-lapack", "nalgebra-glm" ] + +[[bench]] +name = "nalgebra_bench" +harness = false +path = "benches/lib.rs" + +[profile.bench] +lto = true diff --git a/benches/common/macros.rs b/benches/common/macros.rs index 758336a82..43bcf59d7 100644 --- a/benches/common/macros.rs +++ b/benches/common/macros.rs @@ -2,56 +2,52 @@ macro_rules! bench_binop( ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { - #[bench] - fn $name(bh: &mut Bencher) { + fn $name(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let a = rng.gen::<$t1>(); let b = rng.gen::<$t2>(); - bh.iter(|| { + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { a.$binop(b) - }) + })); } } ); macro_rules! bench_binop_ref( ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { - #[bench] - fn $name(bh: &mut Bencher) { + fn $name(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let a = rng.gen::<$t1>(); let b = rng.gen::<$t2>(); - bh.iter(|| { + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { a.$binop(&b) - }) + })); } } ); macro_rules! bench_binop_fn( ($name: ident, $t1: ty, $t2: ty, $binop: path) => { - #[bench] - fn $name(bh: &mut Bencher) { + fn $name(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let a = rng.gen::<$t1>(); let b = rng.gen::<$t2>(); - bh.iter(|| { + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { $binop(&a, &b) - }) + })); } } ); macro_rules! bench_unop_na( ($name: ident, $t: ty, $unop: ident) => { - #[bench] - fn $name(bh: &mut Bencher) { + fn $name(bh: &mut criterion::Criterion) { const LEN: usize = 1 << 13; use rand::SeedableRng; @@ -60,21 +56,20 @@ macro_rules! bench_unop_na( let elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect(); let mut i = 0; - bh.iter(|| { + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { i = (i + 1) & (LEN - 1); unsafe { test::black_box(na::$unop(elems.get_unchecked(i))) } - }) + })); } } ); macro_rules! bench_unop( ($name: ident, $t: ty, $unop: ident) => { - #[bench] - fn $name(bh: &mut Bencher) { + fn $name(bh: &mut criterion::Criterion) { const LEN: usize = 1 << 13; use rand::SeedableRng; @@ -83,21 +78,20 @@ macro_rules! bench_unop( let mut elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect(); let mut i = 0; - bh.iter(|| { + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { i = (i + 1) & (LEN - 1); unsafe { test::black_box(elems.get_unchecked_mut(i).$unop()) } - }) + })); } } ); macro_rules! bench_construction( ($name: ident, $constructor: path, $( $args: ident: $types: ty),*) => { - #[bench] - fn $name(bh: &mut Bencher) { + fn $name(bh: &mut criterion::Criterion) { const LEN: usize = 1 << 13; use rand::SeedableRng; @@ -106,14 +100,14 @@ macro_rules! bench_construction( $(let $args: Vec<$types> = (0usize .. LEN).map(|_| rng.gen::<$types>()).collect();)* let mut i = 0; - bh.iter(|| { + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { i = (i + 1) & (LEN - 1); unsafe { let res = $constructor($(*$args.get_unchecked(i),)*); test::black_box(res) } - }) + })); } } ); diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs index c323cd6ec..12fb836d3 100644 --- a/benches/core/matrix.rs +++ b/benches/core/matrix.rs @@ -1,7 +1,6 @@ use na::{DMatrix, DVector, Matrix2, Matrix3, Matrix4, MatrixN, Vector2, Vector3, Vector4, U10}; use rand::{IsaacRng, Rng}; use std::ops::{Add, Div, Mul, Sub}; -use test::{self, Bencher}; #[path = "../common/macros.rs"] mod macros; @@ -46,153 +45,196 @@ bench_unop!(mat2_transpose, Matrix2, transpose); bench_unop!(mat3_transpose, Matrix3, transpose); bench_unop!(mat4_transpose, Matrix4, transpose); -#[bench] -fn mat_div_scalar(b: &mut Bencher) { +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.iter(|| { + 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 - }) + })); } -#[bench] -fn mat100_add_mat100(bench: &mut Bencher) { +fn mat100_add_mat100(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(100, 100); let b = DMatrix::::new_random(100, 100); - bench.iter(|| &a + &b) + bench.bench_function("mat100_add_mat100", move |bh| bh.iter(|| &a + &b)); } -#[bench] -fn mat4_mul_mat4(bench: &mut Bencher) { +fn mat4_mul_mat4(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(4, 4); let b = DMatrix::::new_random(4, 4); - bench.iter(|| &a * &b) + bench.bench_function("mat4_mul_mat4", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat5_mul_mat5(bench: &mut Bencher) { +fn mat5_mul_mat5(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(5, 5); let b = DMatrix::::new_random(5, 5); - bench.iter(|| &a * &b) + bench.bench_function("mat5_mul_mat5", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat6_mul_mat6(bench: &mut Bencher) { +fn mat6_mul_mat6(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(6, 6); let b = DMatrix::::new_random(6, 6); - bench.iter(|| &a * &b) + bench.bench_function("mat6_mul_mat6", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat7_mul_mat7(bench: &mut Bencher) { +fn mat7_mul_mat7(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(7, 7); let b = DMatrix::::new_random(7, 7); - bench.iter(|| &a * &b) + bench.bench_function("mat7_mul_mat7", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat8_mul_mat8(bench: &mut Bencher) { +fn mat8_mul_mat8(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(8, 8); let b = DMatrix::::new_random(8, 8); - bench.iter(|| &a * &b) + bench.bench_function("mat8_mul_mat8", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat9_mul_mat9(bench: &mut Bencher) { +fn mat9_mul_mat9(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(9, 9); let b = DMatrix::::new_random(9, 9); - bench.iter(|| &a * &b) + bench.bench_function("mat9_mul_mat9", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat10_mul_mat10(bench: &mut Bencher) { +fn mat10_mul_mat10(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(10, 10); let b = DMatrix::::new_random(10, 10); - bench.iter(|| &a * &b) + bench.bench_function("mat10_mul_mat10", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat10_mul_mat10_static(bench: &mut Bencher) { +fn mat10_mul_mat10_static(bench: &mut criterion::Criterion) { let a = MatrixN::::new_random(); let b = MatrixN::::new_random(); - bench.iter(|| &a * &b) + bench.bench_function("mat10_mul_mat10_static", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat100_mul_mat100(bench: &mut Bencher) { +fn mat100_mul_mat100(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(100, 100); let b = DMatrix::::new_random(100, 100); - bench.iter(|| &a * &b) + bench.bench_function("mat100_mul_mat100", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn mat500_mul_mat500(bench: &mut Bencher) { +fn mat500_mul_mat500(bench: &mut criterion::Criterion) { let a = DMatrix::::from_element(500, 500, 5f64); let b = DMatrix::::from_element(500, 500, 6f64); - bench.iter(|| &a * &b) + bench.bench_function("mat500_mul_mat500", move |bh| bh.iter(|| &a * &b)); } -#[bench] -fn copy_from(bench: &mut Bencher) { +fn copy_from(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(1000, 1000); let mut b = DMatrix::::new_random(1000, 1000); - bench.iter(|| { - b.copy_from(&a); - }) + bench.bench_function("copy_from", move |bh| bh.iter(|| { + b.copy_from(&a); + })); } -#[bench] -fn axpy(bench: &mut Bencher) { +fn axpy(bench: &mut criterion::Criterion) { let x = DVector::::from_element(100000, 2.0); let mut y = DVector::::from_element(100000, 3.0); let a = 42.0; - bench.iter(|| { - y.axpy(a, &x, 1.0); - }) + bench.bench_function("axpy", move |bh| bh.iter(|| { + y.axpy(a, &x, 1.0); + })); } -#[bench] -fn tr_mul_to(bench: &mut Bencher) { +fn tr_mul_to(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(1000, 1000); let b = DVector::::new_random(1000); let mut c = DVector::from_element(1000, 0.0); - bench.iter(|| a.tr_mul_to(&b, &mut c)) + bench.bench_function("", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c))); } -#[bench] -fn mat_mul_mat(bench: &mut Bencher) { +fn mat_mul_mat(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(100, 100); let b = DMatrix::::new_random(100, 100); let mut ab = DMatrix::::from_element(100, 100, 0.0); - bench.iter(|| { - test::black_box(a.mul_to(&b, &mut ab)); - }) -} - -#[bench] -fn mat100_from_fn(bench: &mut Bencher) { - bench.iter(|| DMatrix::from_fn(100, 100, |a, b| a + b)) -} - -#[bench] -fn mat500_from_fn(bench: &mut Bencher) { - bench.iter(|| DMatrix::from_fn(500, 500, |a, b| a + b)) -} + 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))); +} + +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))); +} + +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, + mat5_mul_mat5, + mat6_mul_mat6, + mat7_mul_mat7, + mat8_mul_mat8, + mat9_mul_mat9, + mat10_mul_mat10, + mat10_mul_mat10_static, + mat100_mul_mat100, + mat500_mul_mat500, + copy_from, + axpy, + tr_mul_to, + mat_mul_mat, + mat100_from_fn, + mat500_from_fn, +); \ No newline at end of file diff --git a/benches/core/mod.rs b/benches/core/mod.rs index 9699a728b..eda9ddaac 100644 --- a/benches/core/mod.rs +++ b/benches/core/mod.rs @@ -1,2 +1,5 @@ +pub use self::matrix::matrix; +pub use self::vector::vector; + mod matrix; mod vector; diff --git a/benches/core/vector.rs b/benches/core/vector.rs index 837eb7ca4..7d3237e8a 100644 --- a/benches/core/vector.rs +++ b/benches/core/vector.rs @@ -1,7 +1,6 @@ use na::{DVector, Vector2, Vector3, Vector4, VectorN}; use rand::{IsaacRng, Rng}; use std::ops::{Add, Div, Mul, Sub}; -use test::{self, Bencher}; use typenum::U10000; #[path = "../common/macros.rs"] @@ -48,19 +47,17 @@ bench_unop!(vec4_normalize, Vector4, normalize); bench_binop_ref!(vec10000_dot_f64, VectorN, VectorN, dot); bench_binop_ref!(vec10000_dot_f32, VectorN, VectorN, dot); -#[bench] -fn vec10000_axpy_f64(bh: &mut Bencher) { +fn vec10000_axpy_f64(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); let n = rng.gen::(); - bh.iter(|| a.axpy(n, &b, 1.0)) + bh.bench_function("vec10000_axpy_f64", move |bh| bh.iter(|| a.axpy(n, &b, 1.0))); } -#[bench] -fn vec10000_axpy_beta_f64(bh: &mut Bencher) { +fn vec10000_axpy_beta_f64(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); @@ -68,27 +65,25 @@ fn vec10000_axpy_beta_f64(bh: &mut Bencher) { let n = rng.gen::(); let beta = rng.gen::(); - bh.iter(|| a.axpy(n, &b, beta)) + bh.bench_function("vec10000_axpy_beta_f64", move |bh| bh.iter(|| a.axpy(n, &b, beta))); } -#[bench] -fn vec10000_axpy_f64_slice(bh: &mut Bencher) { +fn vec10000_axpy_f64_slice(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); let n = rng.gen::(); - bh.iter(|| { + 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) - }) + })); } -#[bench] -fn vec10000_axpy_f64_static(bh: &mut Bencher) { +fn vec10000_axpy_f64_static(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = VectorN::::new_random(); @@ -96,22 +91,20 @@ fn vec10000_axpy_f64_static(bh: &mut Bencher) { let n = rng.gen::(); // NOTE: for some reasons, it is much faster if the arument are boxed (Box::new(VectorN...)). - 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))); } -#[bench] -fn vec10000_axpy_f32(bh: &mut Bencher) { +fn vec10000_axpy_f32(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); let n = rng.gen::(); - bh.iter(|| a.axpy(n, &b, 1.0)) + bh.bench_function("vec10000_axpy_f32", move |bh| bh.iter(|| a.axpy(n, &b, 1.0))); } -#[bench] -fn vec10000_axpy_beta_f32(bh: &mut Bencher) { +fn vec10000_axpy_beta_f32(bh: &mut criterion::Criterion) { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); @@ -119,5 +112,55 @@ fn vec10000_axpy_beta_f32(bh: &mut Bencher) { let n = rng.gen::(); let beta = rng.gen::(); - 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, + 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, + vec10000_axpy_f64_static, + vec10000_axpy_f32, + vec10000_axpy_beta_f32 +); diff --git a/benches/geometry/mod.rs b/benches/geometry/mod.rs index 0f9eb3711..cb23cbf9d 100644 --- a/benches/geometry/mod.rs +++ b/benches/geometry/mod.rs @@ -1 +1,3 @@ +pub use self::quaternion::quaternion; + mod quaternion; diff --git a/benches/geometry/quaternion.rs b/benches/geometry/quaternion.rs index bc94c054e..dd079aacd 100644 --- a/benches/geometry/quaternion.rs +++ b/benches/geometry/quaternion.rs @@ -1,7 +1,6 @@ use na::{Quaternion, UnitQuaternion, Vector3}; use rand::{IsaacRng, Rng}; use std::ops::{Add, Div, Mul, Sub}; -use test::{self, Bencher}; #[path = "../common/macros.rs"] mod macros; @@ -25,3 +24,14 @@ bench_unop!(unit_quaternion_inv, UnitQuaternion, inverse); // bench_unop_self!(quaternion_conjugate, Quaternion, conjugate); // bench_unop!(quaternion_normalize, Quaternion, normalize); + +criterion_group!(quaternion, + quaternion_add_q, + quaternion_sub_q, + quaternion_mul_q, + unit_quaternion_mul_v, + quaternion_mul_s, + quaternion_div_s, + quaternion_inv, + unit_quaternion_inv +); \ No newline at end of file diff --git a/benches/lib.rs b/benches/lib.rs index f788c9988..d5333542d 100644 --- a/benches/lib.rs +++ b/benches/lib.rs @@ -6,15 +6,34 @@ extern crate rand; extern crate test; extern crate typenum; +#[macro_use] +extern crate criterion; + use na::DMatrix; use rand::{IsaacRng, Rng}; -mod core; -mod geometry; -mod linalg; +pub mod core; +pub mod geometry; +pub mod linalg; fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix { use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); DMatrix::::from_fn(nrows, ncols, |_, _| rng.gen()) } + +criterion_main!( + core::matrix, + core::vector, + geometry::quaternion, + linalg::bidiagonal, + linalg::cholesky, + linalg::full_piv_lu, + linalg::hessenberg, + linalg::lu, + linalg::qr, + linalg::schur, + linalg::solve, + linalg::svd, + linalg::symmetric_eigen, +); \ No newline at end of file diff --git a/benches/linalg/bidiagonal.rs b/benches/linalg/bidiagonal.rs index 9e5a723ef..ed126205c 100644 --- a/benches/linalg/bidiagonal.rs +++ b/benches/linalg/bidiagonal.rs @@ -1,73 +1,75 @@ use na::{Bidiagonal, DMatrix, Matrix4}; -use test::{self, Bencher}; #[path = "../common/macros.rs"] mod macros; // Without unpack. -#[bench] -fn bidiagonalize_100x100(bh: &mut Bencher) { +fn bidiagonalize_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - 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())))); } -#[bench] -fn bidiagonalize_100x500(bh: &mut Bencher) { +fn bidiagonalize_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - 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())))); } -#[bench] -fn bidiagonalize_4x4(bh: &mut Bencher) { +fn bidiagonalize_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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())))); } -#[bench] -fn bidiagonalize_500x100(bh: &mut Bencher) { +fn bidiagonalize_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - 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())))); } -#[bench] -fn bidiagonalize_500x500(bh: &mut Bencher) { +fn bidiagonalize_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - 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. -#[bench] -fn bidiagonalize_unpack_100x100(bh: &mut Bencher) { +fn bidiagonalize_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.iter(|| { + bh.bench_function("bidiagonalize_unpack_100x100", move |bh| bh.iter(|| { let bidiag = Bidiagonal::new(m.clone()); let _ = bidiag.unpack(); - }) + })); } -#[bench] -fn bidiagonalize_unpack_100x500(bh: &mut Bencher) { +fn bidiagonalize_unpack_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - bh.iter(|| { + bh.bench_function("bidiagonalize_unpack_100x500", move |bh| bh.iter(|| { let bidiag = Bidiagonal::new(m.clone()); let _ = bidiag.unpack(); - }) + })); } -#[bench] -fn bidiagonalize_unpack_500x100(bh: &mut Bencher) { +fn bidiagonalize_unpack_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - bh.iter(|| { + bh.bench_function("bidiagonalize_unpack_500x100", move |bh| bh.iter(|| { let bidiag = Bidiagonal::new(m.clone()); let _ = bidiag.unpack(); - }) + })); } -#[bench] -fn bidiagonalize_unpack_500x500(bh: &mut Bencher) { +fn bidiagonalize_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.iter(|| { + bh.bench_function("bidiagonalize_unpack_500x500", move |bh| bh.iter(|| { let bidiag = Bidiagonal::new(m.clone()); let _ = bidiag.unpack(); - }) + })); } + +criterion_group!(bidiagonal, + bidiagonalize_100x100, + bidiagonalize_100x500, + bidiagonalize_4x4, + bidiagonalize_500x100, +// bidiagonalize_500x500, // too long + bidiagonalize_unpack_100x100, + bidiagonalize_unpack_100x500, + bidiagonalize_unpack_500x100, +// bidiagonalize_unpack_500x500 // too long +); \ No newline at end of file diff --git a/benches/linalg/cholesky.rs b/benches/linalg/cholesky.rs index 73c028cb5..40ca98211 100644 --- a/benches/linalg/cholesky.rs +++ b/benches/linalg/cholesky.rs @@ -1,109 +1,112 @@ use na::{Cholesky, DMatrix, DVector}; -use test::{self, Bencher}; -#[bench] -fn cholesky_100x100(bh: &mut Bencher) { +fn cholesky_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let m = &m * m.transpose(); - 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())))); } -#[bench] -fn cholesky_500x500(bh: &mut Bencher) { +fn cholesky_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let m = &m * m.transpose(); - 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. -#[bench] -fn cholesky_decompose_unpack_100x100(bh: &mut Bencher) { +fn cholesky_decompose_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let m = &m * m.transpose(); - bh.iter(|| { + bh.bench_function("cholesky_decompose_unpack_100x100", move |bh| bh.iter(|| { let chol = Cholesky::new(m.clone()).unwrap(); let _ = chol.unpack(); - }) + })); } -#[bench] -fn cholesky_decompose_unpack_500x500(bh: &mut Bencher) { +fn cholesky_decompose_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let m = &m * m.transpose(); - bh.iter(|| { + bh.bench_function("cholesky_decompose_unpack_500x500", move |bh| bh.iter(|| { let chol = Cholesky::new(m.clone()).unwrap(); let _ = chol.unpack(); - }) + })); } -#[bench] -fn cholesky_solve_10x10(bh: &mut Bencher) { +fn cholesky_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let m = &m * m.transpose(); let v = DVector::::new_random(10); let chol = Cholesky::new(m.clone()).unwrap(); - bh.iter(|| { + bh.bench_function("cholesky_solve_10x10", move |bh| bh.iter(|| { let _ = chol.solve(&v); - }) + })); } -#[bench] -fn cholesky_solve_100x100(bh: &mut Bencher) { +fn cholesky_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let m = &m * m.transpose(); let v = DVector::::new_random(100); let chol = Cholesky::new(m.clone()).unwrap(); - bh.iter(|| { + bh.bench_function("cholesky_solve_100x100", move |bh| bh.iter(|| { let _ = chol.solve(&v); - }) + })); } -#[bench] -fn cholesky_solve_500x500(bh: &mut Bencher) { +fn cholesky_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let m = &m * m.transpose(); let v = DVector::::new_random(500); let chol = Cholesky::new(m.clone()).unwrap(); - bh.iter(|| { + bh.bench_function("cholesky_solve_500x500", move |bh| bh.iter(|| { let _ = chol.solve(&v); - }) + })); } -#[bench] -fn cholesky_inverse_10x10(bh: &mut Bencher) { + +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.iter(|| { + bh.bench_function("cholesky_inverse_10x10", move |bh| bh.iter(|| { let _ = chol.inverse(); - }) + })); } -#[bench] -fn cholesky_inverse_100x100(bh: &mut Bencher) { +fn cholesky_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let m = &m * m.transpose(); let chol = Cholesky::new(m.clone()).unwrap(); - bh.iter(|| { + bh.bench_function("cholesky_inverse_100x100", move |bh| bh.iter(|| { let _ = chol.inverse(); - }) + })); } -#[bench] -fn cholesky_inverse_500x500(bh: &mut Bencher) { +fn cholesky_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let m = &m * m.transpose(); let chol = Cholesky::new(m.clone()).unwrap(); - bh.iter(|| { + bh.bench_function("cholesky_inverse_500x500", move |bh| bh.iter(|| { let _ = chol.inverse(); - }) + })); } + +criterion_group!(cholesky, + cholesky_100x100, + cholesky_500x500, + cholesky_decompose_unpack_100x100, + cholesky_decompose_unpack_500x500, + cholesky_solve_10x10, + cholesky_solve_100x100, + cholesky_solve_500x500, + cholesky_inverse_10x10, + cholesky_inverse_100x100, + cholesky_inverse_500x500 +); \ No newline at end of file diff --git a/benches/linalg/eigen.rs b/benches/linalg/eigen.rs index 54aa77a50..0b1e6b266 100644 --- a/benches/linalg/eigen.rs +++ b/benches/linalg/eigen.rs @@ -1,30 +1,33 @@ use test::Bencher; use na::{DMatrix, Eigen}; -#[bench] -fn eigen_100x100(bh: &mut Bencher) { +fn eigen_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0)) + bh.bench_function("eigen_100x100", move |bh| bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))); } -#[bench] -fn eigen_500x500(bh: &mut Bencher) { +fn eigen_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0)) + bh.bench_function("eigen_500x500", move |bh| bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))); } -#[bench] -fn eigenvalues_100x100(bh: &mut Bencher) { +fn eigenvalues_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.iter(|| m.clone().eigenvalues(1.0e-7, 0)) + bh.bench_function("eigenvalues_100x100", move |bh| bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))); } -#[bench] -fn eigenvalues_500x500(bh: &mut Bencher) { +fn eigenvalues_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.iter(|| m.clone().eigenvalues(1.0e-7, 0)) + bh.bench_function("eigenvalues_500x500", move |bh| bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))); } + +criterion_group!(eigen, + eigen_100x100, +// eigen_500x500, + eigenvalues_100x100, +// eigenvalues_500x500 +); diff --git a/benches/linalg/full_piv_lu.rs b/benches/linalg/full_piv_lu.rs index ad82b069e..6c7b1fa6f 100644 --- a/benches/linalg/full_piv_lu.rs +++ b/benches/linalg/full_piv_lu.rs @@ -1,102 +1,105 @@ use na::{DMatrix, DVector, FullPivLU}; -use test::{self, Bencher}; // Without unpack. -#[bench] -fn full_piv_lu_decompose_10x10(bh: &mut Bencher) { +fn full_piv_lu_decompose_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); - 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())))); } -#[bench] -fn full_piv_lu_decompose_100x100(bh: &mut Bencher) { +fn full_piv_lu_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - 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())))); } -#[bench] -fn full_piv_lu_decompose_500x500(bh: &mut Bencher) { +fn full_piv_lu_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - 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())))); } -#[bench] -fn full_piv_lu_solve_10x10(bh: &mut Bencher) { +fn full_piv_lu_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = FullPivLU::new(m.clone()); - bh.iter(|| { + 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); - }) + })); } -#[bench] -fn full_piv_lu_solve_100x100(bh: &mut Bencher) { +fn full_piv_lu_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = FullPivLU::new(m.clone()); - bh.iter(|| { + 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); - }) + })); } -#[bench] -fn full_piv_lu_solve_500x500(bh: &mut Bencher) { +fn full_piv_lu_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = FullPivLU::new(m.clone()); - bh.iter(|| { + 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); - }) + })); } -#[bench] -fn full_piv_lu_inverse_10x10(bh: &mut Bencher) { +fn full_piv_lu_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = FullPivLU::new(m.clone()); - 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()))); } -#[bench] -fn full_piv_lu_inverse_100x100(bh: &mut Bencher) { +fn full_piv_lu_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = FullPivLU::new(m.clone()); - 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()))); } -#[bench] -fn full_piv_lu_inverse_500x500(bh: &mut Bencher) { +fn full_piv_lu_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = FullPivLU::new(m.clone()); - 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()))); } -#[bench] -fn full_piv_lu_determinant_10x10(bh: &mut Bencher) { +fn full_piv_lu_determinant_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = FullPivLU::new(m.clone()); - bh.iter(|| test::black_box(lu.determinant())) + bh.bench_function("full_piv_lu_determinant_10x10", move |bh| bh.iter(|| test::black_box(lu.determinant()))); } -#[bench] -fn full_piv_lu_determinant_100x100(bh: &mut Bencher) { + +fn full_piv_lu_determinant_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = FullPivLU::new(m.clone()); - bh.iter(|| test::black_box(lu.determinant())) + bh.bench_function("full_piv_lu_determinant_100x100", move |bh| bh.iter(|| test::black_box(lu.determinant()))); } -#[bench] -fn full_piv_lu_determinant_500x500(bh: &mut Bencher) { +fn full_piv_lu_determinant_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = FullPivLU::new(m.clone()); - 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, + full_piv_lu_decompose_10x10, + full_piv_lu_decompose_100x100, +// full_piv_lu_decompose_500x500, + full_piv_lu_solve_10x10, + full_piv_lu_solve_100x100, +// full_piv_lu_solve_500x500, + full_piv_lu_inverse_10x10, + full_piv_lu_inverse_100x100, +// 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 diff --git a/benches/linalg/hessenberg.rs b/benches/linalg/hessenberg.rs index 427aa1fe2..3340c3efc 100644 --- a/benches/linalg/hessenberg.rs +++ b/benches/linalg/hessenberg.rs @@ -1,58 +1,60 @@ use na::{DMatrix, Hessenberg, Matrix4}; -use test::{self, Bencher}; #[path = "../common/macros.rs"] mod macros; // Without unpack. -#[bench] -fn hessenberg_decompose_4x4(bh: &mut Bencher) { +fn hessenberg_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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())))); } -#[bench] -fn hessenberg_decompose_100x100(bh: &mut Bencher) { +fn hessenberg_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - 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())))); } -#[bench] -fn hessenberg_decompose_200x200(bh: &mut Bencher) { +fn hessenberg_decompose_200x200(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(200, 200); - 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())))); } -#[bench] -fn hessenberg_decompose_500x500(bh: &mut Bencher) { +fn hessenberg_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - 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. -#[bench] -fn hessenberg_decompose_unpack_100x100(bh: &mut Bencher) { +fn hessenberg_decompose_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.iter(|| { + bh.bench_function("hessenberg_decompose_unpack_100x100", move |bh| bh.iter(|| { let hess = Hessenberg::new(m.clone()); let _ = hess.unpack(); - }) + })); } -#[bench] -fn hessenberg_decompose_unpack_200x200(bh: &mut Bencher) { +fn hessenberg_decompose_unpack_200x200(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(200, 200); - bh.iter(|| { + bh.bench_function("hessenberg_decompose_unpack_200x200", move |bh| bh.iter(|| { let hess = Hessenberg::new(m.clone()); let _ = hess.unpack(); - }) + })); } -#[bench] -fn hessenberg_decompose_unpack_500x500(bh: &mut Bencher) { +fn hessenberg_decompose_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.iter(|| { + bh.bench_function("hessenberg_decompose_unpack_500x500", move |bh| bh.iter(|| { let hess = Hessenberg::new(m.clone()); let _ = hess.unpack(); - }) + })); } + +criterion_group!(hessenberg, + hessenberg_decompose_4x4, + hessenberg_decompose_100x100, + hessenberg_decompose_200x200, +// hessenberg_decompose_500x500, + hessenberg_decompose_unpack_100x100, + hessenberg_decompose_unpack_200x200, +// hessenberg_decompose_unpack_500x500 +); \ No newline at end of file diff --git a/benches/linalg/lu.rs b/benches/linalg/lu.rs index 2428cf9c4..e37cfe751 100644 --- a/benches/linalg/lu.rs +++ b/benches/linalg/lu.rs @@ -1,102 +1,102 @@ use na::{DMatrix, DVector, LU}; -use test::{self, Bencher}; // Without unpack. -#[bench] -fn lu_decompose_10x10(bh: &mut Bencher) { +fn lu_decompose_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); - 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())))); } -#[bench] -fn lu_decompose_100x100(bh: &mut Bencher) { +fn lu_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - 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())))); } -#[bench] -fn lu_decompose_500x500(bh: &mut Bencher) { +fn lu_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - 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())))); } -#[bench] -fn lu_solve_10x10(bh: &mut Bencher) { +fn lu_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = LU::new(m.clone()); - bh.iter(|| { + bh.bench_function("lu_solve_10x10", move |bh| bh.iter(|| { let mut b = DVector::::from_element(10, 1.0); lu.solve(&mut b); - }) + })); } -#[bench] -fn lu_solve_100x100(bh: &mut Bencher) { +fn lu_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = LU::new(m.clone()); - bh.iter(|| { + bh.bench_function("lu_solve_100x100", move |bh| bh.iter(|| { let mut b = DVector::::from_element(100, 1.0); lu.solve(&mut b); - }) + })); } -#[bench] -fn lu_solve_500x500(bh: &mut Bencher) { +fn lu_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = LU::new(m.clone()); - bh.iter(|| { + bh.bench_function("", move |bh| bh.iter(|| { let mut b = DVector::::from_element(500, 1.0); lu.solve(&mut b); - }) + })); } -#[bench] -fn lu_inverse_10x10(bh: &mut Bencher) { +fn lu_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = LU::new(m.clone()); - bh.iter(|| test::black_box(lu.try_inverse())) + bh.bench_function("lu_inverse_10x10", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); } -#[bench] -fn lu_inverse_100x100(bh: &mut Bencher) { +fn lu_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = LU::new(m.clone()); - bh.iter(|| test::black_box(lu.try_inverse())) + bh.bench_function("lu_inverse_100x100", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); } -#[bench] -fn lu_inverse_500x500(bh: &mut Bencher) { +fn lu_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = LU::new(m.clone()); - bh.iter(|| test::black_box(lu.try_inverse())) + bh.bench_function("lu_inverse_500x500", move |bh| bh.iter(|| test::black_box(lu.try_inverse()))); } -#[bench] -fn lu_determinant_10x10(bh: &mut Bencher) { +fn lu_determinant_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let lu = LU::new(m.clone()); - bh.iter(|| test::black_box(lu.determinant())) + bh.bench_function("lu_determinant_10x10", move |bh| bh.iter(|| test::black_box(lu.determinant()))); } -#[bench] -fn lu_determinant_100x100(bh: &mut Bencher) { +fn lu_determinant_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let lu = LU::new(m.clone()); - bh.iter(|| test::black_box(lu.determinant())) + bh.bench_function("lu_determinant_100x100", move |bh| bh.iter(|| test::black_box(lu.determinant()))); } -#[bench] -fn lu_determinant_500x500(bh: &mut Bencher) { +fn lu_determinant_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let lu = LU::new(m.clone()); - bh.iter(|| test::black_box(lu.determinant())) + bh.bench_function("", move |bh| bh.iter(|| test::black_box(lu.determinant()))); } + +criterion_group!(lu, + lu_decompose_10x10, + lu_decompose_100x100, +// lu_decompose_500x500, + lu_solve_10x10, + lu_solve_100x100, + lu_inverse_10x10, + lu_inverse_100x100, +// 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 526b32ea5..a6e7a8ef7 100644 --- a/benches/linalg/mod.rs +++ b/benches/linalg/mod.rs @@ -1,3 +1,14 @@ +pub use self::bidiagonal::bidiagonal; +pub use self::cholesky::cholesky; +pub use self::full_piv_lu::full_piv_lu; +pub use self::hessenberg::hessenberg; +pub use self::lu::lu; +pub use self::qr::qr; +pub use self::schur::schur; +pub use self::solve::solve; +pub use self::svd::svd; +pub use self::symmetric_eigen::symmetric_eigen; + mod bidiagonal; mod cholesky; mod full_piv_lu; @@ -8,4 +19,4 @@ mod schur; mod solve; mod svd; mod symmetric_eigen; -// mod eigen; +// mod eigen; \ No newline at end of file diff --git a/benches/linalg/qr.rs b/benches/linalg/qr.rs index 41a814ff2..8283c5e9c 100644 --- a/benches/linalg/qr.rs +++ b/benches/linalg/qr.rs @@ -1,130 +1,133 @@ use na::{DMatrix, DVector, Matrix4, QR}; -use test::{self, Bencher}; #[path = "../common/macros.rs"] mod macros; // Without unpack. -#[bench] -fn qr_decompose_100x100(bh: &mut Bencher) { +fn qr_decompose_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - 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())))); } -#[bench] -fn qr_decompose_100x500(bh: &mut Bencher) { +fn qr_decompose_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - 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())))); } -#[bench] -fn qr_decompose_4x4(bh: &mut Bencher) { +fn qr_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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())))); } -#[bench] -fn qr_decompose_500x100(bh: &mut Bencher) { +fn qr_decompose_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - 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())))); } -#[bench] -fn qr_decompose_500x500(bh: &mut Bencher) { +fn qr_decompose_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - 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. -#[bench] -fn qr_decompose_unpack_100x100(bh: &mut Bencher) { +fn qr_decompose_unpack_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); - bh.iter(|| { + bh.bench_function("qr_decompose_unpack_100x100", move |bh| bh.iter(|| { let qr = QR::new(m.clone()); let _ = qr.unpack(); - }) + })); } -#[bench] -fn qr_decompose_unpack_100x500(bh: &mut Bencher) { +fn qr_decompose_unpack_100x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 500); - bh.iter(|| { + bh.bench_function("qr_decompose_unpack_100x500", move |bh| bh.iter(|| { let qr = QR::new(m.clone()); let _ = qr.unpack(); - }) + })); } -#[bench] -fn qr_decompose_unpack_500x100(bh: &mut Bencher) { +fn qr_decompose_unpack_500x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 100); - bh.iter(|| { + bh.bench_function("qr_decompose_unpack_500x100", move |bh| bh.iter(|| { let qr = QR::new(m.clone()); let _ = qr.unpack(); - }) + })); } -#[bench] -fn qr_decompose_unpack_500x500(bh: &mut Bencher) { +fn qr_decompose_unpack_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); - bh.iter(|| { + bh.bench_function("qr_decompose_unpack_500x500", move |bh| bh.iter(|| { let qr = QR::new(m.clone()); let _ = qr.unpack(); - }) + })); } -#[bench] -fn qr_solve_10x10(bh: &mut Bencher) { +fn qr_solve_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let qr = QR::new(m.clone()); - bh.iter(|| { + bh.bench_function("qr_solve_10x10", move |bh| bh.iter(|| { let mut b = DVector::::from_element(10, 1.0); qr.solve(&mut b); - }) + })); } -#[bench] -fn qr_solve_100x100(bh: &mut Bencher) { +fn qr_solve_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let qr = QR::new(m.clone()); - bh.iter(|| { + bh.bench_function("qr_solve_100x100", move |bh| bh.iter(|| { let mut b = DVector::::from_element(100, 1.0); qr.solve(&mut b); - }) + })); } -#[bench] -fn qr_solve_500x500(bh: &mut Bencher) { +fn qr_solve_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let qr = QR::new(m.clone()); - bh.iter(|| { + bh.bench_function("qr_solve_500x500", move |bh| bh.iter(|| { let mut b = DVector::::from_element(500, 1.0); qr.solve(&mut b); - }) + })); } -#[bench] -fn qr_inverse_10x10(bh: &mut Bencher) { +fn qr_inverse_10x10(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(10, 10); let qr = QR::new(m.clone()); - bh.iter(|| test::black_box(qr.try_inverse())) + bh.bench_function("qr_inverse_10x10", move |bh| bh.iter(|| test::black_box(qr.try_inverse()))); } -#[bench] -fn qr_inverse_100x100(bh: &mut Bencher) { +fn qr_inverse_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let qr = QR::new(m.clone()); - bh.iter(|| test::black_box(qr.try_inverse())) + bh.bench_function("qr_inverse_100x100", move |bh| bh.iter(|| test::black_box(qr.try_inverse()))); } -#[bench] -fn qr_inverse_500x500(bh: &mut Bencher) { +fn qr_inverse_500x500(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(500, 500); let qr = QR::new(m.clone()); - 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, + qr_decompose_100x100, + qr_decompose_100x500, + qr_decompose_4x4, + qr_decompose_500x100, +// qr_decompose_500x500, + qr_decompose_unpack_100x100, + qr_decompose_unpack_100x500, + qr_decompose_unpack_500x100, +// qr_decompose_unpack_500x500, + qr_solve_10x10, + qr_solve_100x100, +// qr_solve_500x500, + qr_inverse_10x10, + qr_inverse_100x100, +// qr_inverse_500x500 +); \ No newline at end of file diff --git a/benches/linalg/schur.rs b/benches/linalg/schur.rs index e0e588ac9..ffabc5393 100644 --- a/benches/linalg/schur.rs +++ b/benches/linalg/schur.rs @@ -1,50 +1,52 @@ -use na::{Matrix4, RealSchur}; -use test::{self, Bencher}; +use na::{Matrix4, Schur}; -#[bench] -fn schur_decompose_4x4(bh: &mut Bencher) { +fn schur_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.iter(|| test::black_box(RealSchur::new(m.clone()))) + bh.bench_function("schur_decompose_4x4", move |bh| bh.iter(|| test::black_box(Schur::new(m.clone())))); } -#[bench] -fn schur_decompose_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - bh.iter(|| test::black_box(RealSchur::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())))); } -#[bench] -fn schur_decompose_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - bh.iter(|| test::black_box(RealSchur::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())))); } -#[bench] -fn schur_decompose_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - bh.iter(|| test::black_box(RealSchur::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())))); } -#[bench] -fn eigenvalues_4x4(bh: &mut Bencher) { +fn eigenvalues_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.iter(|| test::black_box(m.complex_eigenvalues())) + bh.bench_function("eigenvalues_4x4", move |bh| bh.iter(|| test::black_box(m.complex_eigenvalues()))); } -#[bench] -fn eigenvalues_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - 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()))); } -#[bench] -fn eigenvalues_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - 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()))); } -#[bench] -fn eigenvalues_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - 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()))); } + +criterion_group!(schur, + schur_decompose_4x4, + schur_decompose_10x10, + schur_decompose_100x100, + schur_decompose_200x200, + eigenvalues_4x4, + 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 03ec71e56..51c6db596 100644 --- a/benches/linalg/solve.rs +++ b/benches/linalg/solve.rs @@ -1,82 +1,85 @@ use na::{DMatrix, DVector}; -use test::Bencher; -#[bench] -fn solve_l_triangular_100x100(bh: &mut Bencher) { +fn solve_l_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.iter(|| { + bh.bench_function("solve_l_triangular_100x100", move |bh| bh.iter(|| { let _ = m.solve_lower_triangular(&v); - }) + })); } -#[bench] -fn solve_l_triangular_1000x1000(bh: &mut Bencher) { +fn solve_l_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.iter(|| { + bh.bench_function("solve_l_triangular_1000x1000", move |bh| bh.iter(|| { let _ = m.solve_lower_triangular(&v); - }) + })); } -#[bench] -fn tr_solve_l_triangular_100x100(bh: &mut Bencher) { +fn tr_solve_l_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.iter(|| { + bh.bench_function("tr_solve_l_triangular_100x100", move |bh| bh.iter(|| { let _ = m.tr_solve_lower_triangular(&v); - }) + })); } -#[bench] -fn tr_solve_l_triangular_1000x1000(bh: &mut Bencher) { +fn tr_solve_l_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.iter(|| { + bh.bench_function("tr_solve_l_triangular_1000x1000", move |bh| bh.iter(|| { let _ = m.tr_solve_lower_triangular(&v); - }) + })); } -#[bench] -fn solve_u_triangular_100x100(bh: &mut Bencher) { +fn solve_u_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.iter(|| { + bh.bench_function("solve_u_triangular_100x100", move |bh| bh.iter(|| { let _ = m.solve_upper_triangular(&v); - }) + })); } -#[bench] -fn solve_u_triangular_1000x1000(bh: &mut Bencher) { +fn solve_u_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.iter(|| { + bh.bench_function("solve_u_triangular_1000x1000", move |bh| bh.iter(|| { let _ = m.solve_upper_triangular(&v); - }) + })); } -#[bench] -fn tr_solve_u_triangular_100x100(bh: &mut Bencher) { +fn tr_solve_u_triangular_100x100(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(100, 100); let v = DVector::::new_random(100); - bh.iter(|| { + bh.bench_function("tr_solve_u_triangular_100x100", move |bh| bh.iter(|| { let _ = m.tr_solve_upper_triangular(&v); - }) + })); } -#[bench] -fn tr_solve_u_triangular_1000x1000(bh: &mut Bencher) { +fn tr_solve_u_triangular_1000x1000(bh: &mut criterion::Criterion) { let m = DMatrix::::new_random(1000, 1000); let v = DVector::::new_random(1000); - bh.iter(|| { + bh.bench_function("tr_solve_u_triangular_1000x1000", move |bh| bh.iter(|| { let _ = m.tr_solve_upper_triangular(&v); - }) + })); } + + +criterion_group!(solve, + solve_l_triangular_100x100, + solve_l_triangular_1000x1000, + tr_solve_l_triangular_100x100, + tr_solve_l_triangular_1000x1000, + solve_u_triangular_100x100, + 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 47023804a..6804147c1 100644 --- a/benches/linalg/svd.rs +++ b/benches/linalg/svd.rs @@ -1,98 +1,101 @@ use na::{Matrix4, SVD}; -use test::{self, Bencher}; -#[bench] -fn svd_decompose_4x4(bh: &mut Bencher) { +fn svd_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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)))); } -#[bench] -fn svd_decompose_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - 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)))); } -#[bench] -fn svd_decompose_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - 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)))); } -#[bench] -fn svd_decompose_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - 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)))); } -#[bench] -fn rank_4x4(bh: &mut Bencher) { +fn rank_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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)))); } -#[bench] -fn rank_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - 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)))); } -#[bench] -fn rank_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - 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)))); } -#[bench] -fn rank_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - 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)))); } -#[bench] -fn singular_values_4x4(bh: &mut Bencher) { +fn singular_values_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - bh.iter(|| test::black_box(m.singular_values())) + bh.bench_function("singular_values_4x4", move |bh| bh.iter(|| test::black_box(m.singular_values()))); } -#[bench] -fn singular_values_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - 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()))); } -#[bench] -fn singular_values_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - 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()))); } -#[bench] -fn singular_values_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - 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()))); } -#[bench] -fn pseudo_inverse_4x4(bh: &mut Bencher) { +fn pseudo_inverse_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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)))); } -#[bench] -fn pseudo_inverse_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - 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)))); } -#[bench] -fn pseudo_inverse_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - 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)))); } -#[bench] -fn pseudo_inverse_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - 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)))); } + + +criterion_group!(svd, + svd_decompose_4x4, + svd_decompose_10x10, + svd_decompose_100x100, + svd_decompose_200x200, + rank_4x4, + rank_10x10, + rank_100x100, + rank_200x200, + singular_values_4x4, + singular_values_10x10, + singular_values_100x100, + singular_values_200x200, + pseudo_inverse_4x4, + 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 2a9058dae..822ea30ed 100644 --- a/benches/linalg/symmetric_eigen.rs +++ b/benches/linalg/symmetric_eigen.rs @@ -1,26 +1,28 @@ use na::{Matrix4, SymmetricEigen}; -use test::{self, Bencher}; -#[bench] -fn symmetric_eigen_decompose_4x4(bh: &mut Bencher) { +fn symmetric_eigen_decompose_4x4(bh: &mut criterion::Criterion) { let m = Matrix4::::new_random(); - 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())))); } -#[bench] -fn symmetric_eigen_decompose_10x10(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(10, 10); - 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())))); } -#[bench] -fn symmetric_eigen_decompose_100x100(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(100, 100); - 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())))); } -#[bench] -fn symmetric_eigen_decompose_200x200(bh: &mut Bencher) { - let m = ::reproductible_dmatrix(200, 200); - 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())))); } + +criterion_group!(symmetric_eigen, + symmetric_eigen_decompose_4x4, + symmetric_eigen_decompose_10x10, + symmetric_eigen_decompose_100x100, + symmetric_eigen_decompose_200x200 +); diff --git a/ci/test.sh b/ci/test.sh index 88071149d..a3a27fb27 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -6,7 +6,7 @@ if [ -z "$NO_STD" ]; then if [ -z "$LAPACK" ]; then cargo test --verbose; cargo test --verbose "arbitrary"; - cargo test --verbose "debug arbitrary mint serde-serialize abomonation-serialize"; + cargo test --verbose --all-features; cd nalgebra-glm; cargo test --verbose; else cd nalgebra-lapack; cargo test --verbose; diff --git a/examples/dimensional_genericity.rs b/examples/dimensional_genericity.rs index ca653d57d..411a06664 100644 --- a/examples/dimensional_genericity.rs +++ b/examples/dimensional_genericity.rs @@ -4,7 +4,7 @@ extern crate nalgebra as na; use alga::linear::FiniteDimInnerSpace; use na::allocator::Allocator; use na::dimension::Dim; -use na::{DefaultAllocator, Real, Unit, Vector2, Vector3, VectorN}; +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 @@ -14,12 +14,12 @@ where V: FiniteDimInnerSpace + Copy { } /// Reflects a vector wrt. the hyperplane with normal `plane_normal`. -fn reflect_wrt_hyperplane_with_dimensional_genericity( +fn reflect_wrt_hyperplane_with_dimensional_genericity( plane_normal: &Unit>, vector: &VectorN, ) -> VectorN where - N: Real, + N: RealField, D: Dim, DefaultAllocator: Allocator, { @@ -29,7 +29,7 @@ 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: Real { +where N: RealField { let n = plane_normal.as_ref(); // Get the underlying Vector2 vector - n * (n.dot(vector) * na::convert(2.0)) } @@ -37,7 +37,7 @@ where N: Real { /// 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: Real { +where N: RealField { let n = plane_normal.as_ref(); // Get the underlying Vector3 vector - n * (n.dot(vector) * na::convert(2.0)) } diff --git a/examples/identity.rs b/examples/identity.rs index 06d69f708..c20c5616c 100644 --- a/examples/identity.rs +++ b/examples/identity.rs @@ -36,4 +36,4 @@ fn main() { // 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 246d1efd4..75f6f9d40 100644 --- a/examples/scalar_genericity.rs +++ b/examples/scalar_genericity.rs @@ -1,7 +1,7 @@ extern crate alga; extern crate nalgebra as na; -use alga::general::{Real, RingCommutative}; +use alga::general::{RealField, RingCommutative}; use na::{Scalar, Vector3}; fn print_vector(m: &Vector3) { @@ -14,11 +14,11 @@ fn print_squared_norm(v: &Vector3) { println!("{:?}", sqnorm); } -fn print_norm(v: &Vector3) { +fn print_norm(v: &Vector3) { // NOTE: alternatively, nalgebra already defines `v.norm()`. let norm = v.dot(v).sqrt(); - // The Real bound implies that N is Display so we can + // The RealField bound implies that N is Display so we can // use "{}" instead of "{:?}" for the format string. println!("{}", norm) } diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index 1da1333d8..042c75fb6 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -11,6 +11,7 @@ readme = "../README.md" categories = [ "science" ] keywords = [ "linear", "algebra", "matrix", "vector", "math" ] license = "BSD-3-Clause" +edition = "2018" [features] default = [ "std" ] diff --git a/nalgebra-glm/src/common.rs b/nalgebra-glm/src/common.rs index 021ac3efe..c9f9c2655 100644 --- a/nalgebra-glm/src/common.rs +++ b/nalgebra-glm/src/common.rs @@ -1,9 +1,9 @@ -use na::{self, DefaultAllocator, Real}; +use na::{self, DefaultAllocator, RealField}; use num::FromPrimitive; use std::mem; -use aliases::{TMat, TVec}; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::{TMat, TVec}; +use crate::traits::{Alloc, Dimension, Number}; /// For each matrix or vector component `x` if `x >= 0`; otherwise, it returns `-x`. /// @@ -43,7 +43,7 @@ where DefaultAllocator: Alloc { /// * [`fract`](fn.fract.html) /// * [`round`](fn.round.html) /// * [`trunc`](fn.trunc.html) -pub fn ceil(x: &TVec) -> TVec +pub fn ceil(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|x| x.ceil()) } @@ -222,7 +222,7 @@ where DefaultAllocator: Alloc { /// * [`fract`](fn.fract.html) /// * [`round`](fn.round.html) /// * [`trunc`](fn.trunc.html) -pub fn floor(x: &TVec) -> TVec +pub fn floor(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|x| x.floor()) } @@ -249,14 +249,14 @@ where DefaultAllocator: Alloc { /// * [`floor`](fn.floor.html) /// * [`round`](fn.round.html) /// * [`trunc`](fn.trunc.html) -pub fn fract(x: &TVec) -> TVec +pub fn fract(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|x| x.fract()) } //// FIXME: should be implemented for TVec/TMat? ///// Returns the (significant, exponent) of this float number. -//pub fn frexp(x: N, exp: N) -> (N, N) { +//pub fn frexp(x: N, exp: N) -> (N, N) { // // FIXME: is there a better approach? // let e = x.log2().ceil(); // (x * (-e).exp2(), e) @@ -310,7 +310,7 @@ where DefaultAllocator: Alloc { //} ///// Returns the (significant, exponent) of this float number. -//pub fn ldexp(x: N, exp: N) -> N { +//pub fn ldexp(x: N, exp: N) -> N { // // FIXME: is there a better approach? // x * (exp).exp2() //} @@ -499,7 +499,7 @@ pub fn modf(x: N, i: N) -> N { /// * [`floor`](fn.floor.html) /// * [`fract`](fn.fract.html) /// * [`trunc`](fn.trunc.html) -pub fn round(x: &TVec) -> TVec +pub fn round(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|x| x.round()) } @@ -576,7 +576,7 @@ where DefaultAllocator: Alloc { /// * [`floor`](fn.floor.html) /// * [`fract`](fn.fract.html) /// * [`round`](fn.round.html) -pub fn trunc(x: &TVec) -> TVec +pub fn trunc(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|x| x.trunc()) } diff --git a/nalgebra-glm/src/constructors.rs b/nalgebra-glm/src/constructors.rs index 1651dd20b..949ea9e4a 100644 --- a/nalgebra-glm/src/constructors.rs +++ b/nalgebra-glm/src/constructors.rs @@ -1,7 +1,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] -use na::{Scalar, Real, U2, U3, U4}; -use aliases::{TMat, Qua, TVec1, TVec2, TVec3, TVec4, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, +use na::{Scalar, RealField, U2, U3, U4}; +use crate::aliases::{TMat, Qua, TVec1, TVec2, TVec3, TVec4, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3}; @@ -168,6 +168,6 @@ pub fn mat4(m11: N, m12: N, m13: N, m14: N, } /// Creates a new quaternion. -pub fn quat(x: N, y: N, z: N, w: N) -> Qua { +pub fn quat(x: N, y: N, z: N, w: N) -> Qua { Qua::new(w, x, y, z) } diff --git a/nalgebra-glm/src/exponential.rs b/nalgebra-glm/src/exponential.rs index 21b716f2a..fd54fb343 100644 --- a/nalgebra-glm/src/exponential.rs +++ b/nalgebra-glm/src/exponential.rs @@ -1,13 +1,13 @@ -use aliases::TVec; -use na::{DefaultAllocator, Real}; -use traits::{Alloc, Dimension}; +use crate::aliases::TVec; +use na::{DefaultAllocator, RealField}; +use crate::traits::{Alloc, Dimension}; /// Component-wise exponential. /// /// # See also: /// /// * [`exp2`](fn.exp2.html) -pub fn exp(v: &TVec) -> TVec +pub fn exp(v: &TVec) -> TVec where DefaultAllocator: Alloc { v.map(|x| x.exp()) } @@ -17,7 +17,7 @@ where DefaultAllocator: Alloc { /// # See also: /// /// * [`exp`](fn.exp.html) -pub fn exp2(v: &TVec) -> TVec +pub fn exp2(v: &TVec) -> TVec where DefaultAllocator: Alloc { v.map(|x| x.exp2()) } @@ -27,7 +27,7 @@ where DefaultAllocator: Alloc { /// # See also: /// /// * [`sqrt`](fn.sqrt.html) -pub fn inversesqrt(v: &TVec) -> TVec +pub fn inversesqrt(v: &TVec) -> TVec where DefaultAllocator: Alloc { v.map(|x| N::one() / x.sqrt()) } @@ -37,7 +37,7 @@ where DefaultAllocator: Alloc { /// # See also: /// /// * [`log2`](fn.log2.html) -pub fn log(v: &TVec) -> TVec +pub fn log(v: &TVec) -> TVec where DefaultAllocator: Alloc { v.map(|x| x.ln()) } @@ -47,13 +47,13 @@ where DefaultAllocator: Alloc { /// # See also: /// /// * [`log`](fn.log.html) -pub fn log2(v: &TVec) -> TVec +pub fn log2(v: &TVec) -> TVec where DefaultAllocator: Alloc { v.map(|x| x.log2()) } /// Component-wise power. -pub fn pow(base: &TVec, exponent: &TVec) -> TVec +pub fn pow(base: &TVec, exponent: &TVec) -> TVec where DefaultAllocator: Alloc { base.zip_map(exponent, |b, e| b.powf(e)) } @@ -66,7 +66,7 @@ where DefaultAllocator: Alloc { /// * [`exp2`](fn.exp2.html) /// * [`inversesqrt`](fn.inversesqrt.html) /// * [`pow`](fn.pow.html) -pub fn sqrt(v: &TVec) -> TVec +pub fn sqrt(v: &TVec) -> TVec 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 02179759c..6ef1404bf 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -1,55 +1,55 @@ -use aliases::TMat4; -use na::{Real}; +use crate::aliases::TMat4; +use na::{RealField}; -//pub fn frustum(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} -//pub fn frustum_lh(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_lh(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_lr_no(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_lr_no(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_lh_zo(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_lh_zo(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_no(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_no(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_rh(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_rh(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_rh_no(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_rh_no(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_rh_zo(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_rh_zo(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} // -//pub fn frustum_zo(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { +//pub fn frustum_zo(left: N, right: N, bottom: N, top: N, near: N, far: N) -> TMat4 { // unimplemented!() //} -//pub fn infinite_perspective(fovy: N, aspect: N, near: N) -> TMat4 { +//pub fn infinite_perspective(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() //} // -//pub fn infinite_perspective_lh(fovy: N, aspect: N, near: N) -> TMat4 { +//pub fn infinite_perspective_lh(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() //} // -//pub fn infinite_perspective_rh(fovy: N, aspect: N, near: N) -> TMat4 { +//pub fn infinite_perspective_rh(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() //} // -//pub fn infinite_ortho(left: N, right: N, bottom: N, top: N) -> TMat4 { +//pub fn infinite_ortho(left: N, right: N, bottom: N, top: N) -> TMat4 { // unimplemented!() //} @@ -64,7 +64,7 @@ use na::{Real}; /// * `znear` - Distance from the viewer to the near clipping plane /// * `zfar` - Distance from the viewer to the far clipping plane /// -pub fn ortho(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { +pub fn ortho(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { ortho_rh_no(left, right, bottom, top, znear, zfar) } @@ -79,7 +79,7 @@ pub fn ortho(left: N, right: N, bottom: N, top: N, znear: N, zfar: 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(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { +pub fn ortho_lh(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { ortho_lh_no(left, right, bottom, top, znear, zfar) } @@ -94,8 +94,8 @@ pub fn ortho_lh(left: N, right: N, bottom: N, top: N, znear: N, zfar: 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_no(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { - let two : N = ::convert(2.0); +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); @@ -119,9 +119,9 @@ pub fn ortho_lh_no(left: N, right: N, bottom: N, top: N, znear: N, zfar /// * `znear` - Distance from the viewer to the near clipping plane /// * `zfar` - Distance from the viewer to the far clipping plane /// -pub fn ortho_lh_zo(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { +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 = ::convert(2.0); + let two : N = crate::convert(2.0); let mut mat : TMat4 = TMat4::::identity(); mat[(0, 0)] = two / (right - left); @@ -145,7 +145,7 @@ pub fn ortho_lh_zo(left: N, right: N, bottom: N, top: N, znear: N, zfar /// * `znear` - Distance from the viewer to the near clipping plane /// * `zfar` - Distance from the viewer to the far clipping plane /// -pub fn ortho_no(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { +pub fn ortho_no(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { ortho_rh_no(left, right, bottom, top, znear, zfar) } @@ -160,7 +160,7 @@ pub fn ortho_no(left: N, right: N, bottom: N, top: N, znear: N, zfar: 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(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { +pub fn ortho_rh(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { ortho_rh_no(left, right, bottom, top, znear, zfar) } @@ -175,8 +175,8 @@ pub fn ortho_rh(left: N, right: N, bottom: N, top: N, znear: N, zfar: 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_no(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { - let two : N = ::convert(2.0); +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); @@ -200,9 +200,9 @@ pub fn ortho_rh_no(left: N, right: N, bottom: N, top: N, znear: N, zfar /// * `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 { +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 = ::convert(2.0); + let two : N = crate::convert(2.0); let mut mat : TMat4 = TMat4::::identity(); mat[(0, 0)] = two / (right - left); @@ -226,7 +226,7 @@ pub fn ortho_rh_zo(left: N, right: N, bottom: N, top: N, znear: N, zfar /// * `znear` - Distance from the viewer to the near clipping plane /// * `zfar` - Distance from the viewer to the far clipping plane /// -pub fn ortho_zo(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { +pub fn ortho_zo(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> TMat4 { ortho_rh_zo(left, right, bottom, top, znear, zfar) } @@ -240,7 +240,7 @@ pub fn ortho_zo(left: N, right: N, bottom: N, top: N, znear: N, zfar: 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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +pub fn perspective_fov(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { perspective_fov_rh_no(fov, width, height, near, far) } @@ -254,7 +254,7 @@ pub fn perspective_fov(fov: N, width: N, height: N, near: N, far: 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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +pub fn perspective_fov_lh(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { perspective_fov_lh_no(fov, width, height, near, far) } @@ -268,7 +268,7 @@ pub fn perspective_fov_lh(fov: N, width: N, height: N, near: N, far: 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_no(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +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" @@ -285,13 +285,13 @@ pub fn perspective_fov_lh_no(fov: N, width: N, height: N, near: N, far: let mut mat = TMat4::zeros(); let rad = fov; - let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin(); + let h = (rad * crate::convert(0.5)).cos() / (rad * crate::convert(0.5)).sin(); let w = h * height / width; mat[(0, 0)] = w; mat[(1, 1)] = h; mat[(2, 2)] = (far + near) / (far - near); - mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near); + mat[(2, 3)] = - (far * near * crate::convert(2.0)) / (far - near); mat[(3, 2)] = N::one(); mat @@ -307,7 +307,7 @@ pub fn perspective_fov_lh_no(fov: N, width: N, height: N, near: N, far: /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// -pub fn perspective_fov_lh_zo(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +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" @@ -324,7 +324,7 @@ pub fn perspective_fov_lh_zo(fov: N, width: N, height: N, near: N, far: let mut mat = TMat4::zeros(); let rad = fov; - let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin(); + let h = (rad * crate::convert(0.5)).cos() / (rad * crate::convert(0.5)).sin(); let w = h * height / width; mat[(0, 0)] = w; @@ -346,7 +346,7 @@ pub fn perspective_fov_lh_zo(fov: N, width: N, height: N, near: N, far: /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// -pub fn perspective_fov_no(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +pub fn perspective_fov_no(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { perspective_fov_rh_no(fov, width, height, near, far) } @@ -360,7 +360,7 @@ pub fn perspective_fov_no(fov: N, width: N, height: N, near: N, far: 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(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +pub fn perspective_fov_rh(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { perspective_fov_rh_no(fov, width, height, near, far) } @@ -374,7 +374,7 @@ pub fn perspective_fov_rh(fov: N, width: N, height: N, near: N, far: 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_no(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +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" @@ -391,13 +391,13 @@ pub fn perspective_fov_rh_no(fov: N, width: N, height: N, near: N, far: let mut mat = TMat4::zeros(); let rad = fov; - let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin(); + let h = (rad * crate::convert(0.5)).cos() / (rad * crate::convert(0.5)).sin(); let w = h * height / width; mat[(0, 0)] = w; mat[(1, 1)] = h; mat[(2, 2)] = - (far + near) / (far - near); - mat[(2, 3)] = - (far * near * ::convert(2.0)) / (far - near); + mat[(2, 3)] = - (far * near * crate::convert(2.0)) / (far - near); mat[(3, 2)] = -N::one(); mat @@ -413,7 +413,7 @@ pub fn perspective_fov_rh_no(fov: N, width: N, height: N, near: N, far: /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// -pub fn perspective_fov_rh_zo(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +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" @@ -430,7 +430,7 @@ pub fn perspective_fov_rh_zo(fov: N, width: N, height: N, near: N, far: let mut mat = TMat4::zeros(); let rad = fov; - let h = (rad * ::convert(0.5)).cos() / (rad * ::convert(0.5)).sin(); + let h = (rad * crate::convert(0.5)).cos() / (rad * crate::convert(0.5)).sin(); let w = h * height / width; mat[(0, 0)] = w; @@ -452,7 +452,7 @@ pub fn perspective_fov_rh_zo(fov: N, width: N, height: N, near: N, far: /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// -pub fn perspective_fov_zo(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { +pub fn perspective_fov_zo(fov: N, width: N, height: N, near: N, far: N) -> TMat4 { perspective_fov_rh_zo(fov, width, height, near, far) } @@ -467,7 +467,7 @@ pub fn perspective_fov_zo(fov: N, width: N, height: N, near: N, far: N) /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective(aspect: N, fovy: N, near: N, far: N) -> TMat4 { // TODO: Breaking change - revert back to proper glm conventions? // // Prior to changes to support configuring the behaviour of this function it was simply @@ -496,7 +496,7 @@ pub fn perspective(aspect: N, fovy: N, near: N, far: N) -> TMat4 { /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_lh(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_lh(aspect: N, fovy: N, near: N, far: N) -> TMat4 { perspective_lh_no(aspect, fovy, near, far) } @@ -511,7 +511,7 @@ pub fn perspective_lh(aspect: N, fovy: N, near: N, far: N) -> TMat4 /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_lh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_lh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { assert!( !relative_eq!(far - near, N::zero()), "The near-plane and far-plane must not be superimposed." @@ -522,7 +522,7 @@ pub fn perspective_lh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4< ); let one = N::one(); - let two: N = ::convert( 2.0); + let two: N = crate::convert( 2.0); let mut mat : TMat4 = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -547,7 +547,7 @@ pub fn perspective_lh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4< /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_lh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_lh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { assert!( !relative_eq!(far - near, N::zero()), "The near-plane and far-plane must not be superimposed." @@ -558,7 +558,7 @@ pub fn perspective_lh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4< ); let one = N::one(); - let two: N = ::convert( 2.0); + let two: N = crate::convert( 2.0); let mut mat: TMat4 = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -583,7 +583,7 @@ pub fn perspective_lh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4< /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { perspective_rh_no(aspect, fovy, near, far) } @@ -598,7 +598,7 @@ pub fn perspective_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_rh(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_rh(aspect: N, fovy: N, near: N, far: N) -> TMat4 { perspective_rh_no(aspect, fovy, near, far) } @@ -613,7 +613,7 @@ pub fn perspective_rh(aspect: N, fovy: N, near: N, far: N) -> TMat4 /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { assert!( !relative_eq!(far - near, N::zero()), "The near-plane and far-plane must not be superimposed." @@ -625,7 +625,7 @@ pub fn perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4< let negone = -N::one(); let one = N::one(); - let two: N = ::convert( 2.0); + let two: N = crate::convert( 2.0); let mut mat = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -650,7 +650,7 @@ pub fn perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4< /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { assert!( !relative_eq!(far - near, N::zero()), "The near-plane and far-plane must not be superimposed." @@ -662,7 +662,7 @@ pub fn perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4< let negone = -N::one(); let one = N::one(); - let two = ::convert( 2.0); + let two = crate::convert( 2.0); let mut mat = TMat4::zeros(); let tan_half_fovy = (fovy / two).tan(); @@ -687,14 +687,14 @@ pub fn perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4< /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn perspective_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { +pub fn perspective_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { perspective_rh_zo(aspect, fovy, near, far) } -//pub fn tweaked_infinite_perspective(fovy: N, aspect: N, near: N) -> TMat4 { +//pub fn tweaked_infinite_perspective(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() //} // -//pub fn tweaked_infinite_perspective_ep(fovy: N, aspect: N, near: N, ep: N) -> TMat4 { +//pub fn tweaked_infinite_perspective_ep(fovy: N, aspect: N, near: N, ep: N) -> TMat4 { // unimplemented!() //} diff --git a/nalgebra-glm/src/ext/matrix_projection.rs b/nalgebra-glm/src/ext/matrix_projection.rs index 4ed23fb32..3048b77cd 100644 --- a/nalgebra-glm/src/ext/matrix_projection.rs +++ b/nalgebra-glm/src/ext/matrix_projection.rs @@ -1,6 +1,6 @@ -use na::{self, Real, U3}; +use na::{self, RealField, U3}; -use aliases::{TMat4, TVec2, TVec3, TVec4}; +use crate::aliases::{TMat4, TVec2, TVec3, TVec4}; /// Define a picking region. /// @@ -9,7 +9,7 @@ use 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, @@ -41,7 +41,7 @@ pub fn pick_matrix(center: &TVec2, delta: &TVec2, viewport: &TVec /// * [`unproject`](fn.unproject.html) /// * [`unproject_no`](fn.unproject_no.html) /// * [`unproject_zo`](fn.unproject_zo.html) -pub fn project( +pub fn project( obj: &TVec3, model: &TMat4, proj: &TMat4, @@ -69,7 +69,7 @@ pub fn project( /// * [`unproject`](fn.unproject.html) /// * [`unproject_no`](fn.unproject_no.html) /// * [`unproject_zo`](fn.unproject_zo.html) -pub fn project_no( +pub fn project_no( obj: &TVec3, model: &TMat4, proj: &TMat4, @@ -98,7 +98,7 @@ pub fn project_no( /// * [`unproject`](fn.unproject.html) /// * [`unproject_no`](fn.unproject_no.html) /// * [`unproject_zo`](fn.unproject_zo.html) -pub fn project_zo( +pub fn project_zo( obj: &TVec3, model: &TMat4, proj: &TMat4, @@ -132,7 +132,7 @@ pub fn project_zo( /// * [`project_zo`](fn.project_zo.html) /// * [`unproject_no`](fn.unproject_no.html) /// * [`unproject_zo`](fn.unproject_zo.html) -pub fn unproject( +pub fn unproject( win: &TVec3, model: &TMat4, proj: &TMat4, @@ -160,7 +160,7 @@ pub fn unproject( /// * [`project_zo`](fn.project_zo.html) /// * [`unproject`](fn.unproject.html) /// * [`unproject_zo`](fn.unproject_zo.html) -pub fn unproject_no( +pub fn unproject_no( win: &TVec3, model: &TMat4, proj: &TMat4, @@ -198,7 +198,7 @@ pub fn unproject_no( /// * [`project_zo`](fn.project_zo.html) /// * [`unproject`](fn.unproject.html) /// * [`unproject_no`](fn.unproject_no.html) -pub fn unproject_zo( +pub fn unproject_zo( win: &TVec3, model: &TMat4, proj: &TMat4, diff --git a/nalgebra-glm/src/ext/matrix_relationnal.rs b/nalgebra-glm/src/ext/matrix_relationnal.rs index 80fb8b6fd..7866e72a1 100644 --- a/nalgebra-glm/src/ext/matrix_relationnal.rs +++ b/nalgebra-glm/src/ext/matrix_relationnal.rs @@ -1,7 +1,7 @@ use na::DefaultAllocator; -use aliases::{TMat, TVec}; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::{TMat, TVec}; +use crate::traits::{Alloc, Dimension, Number}; /// Perform a component-wise equal-to comparison of two matrices. /// diff --git a/nalgebra-glm/src/ext/matrix_transform.rs b/nalgebra-glm/src/ext/matrix_transform.rs index 829262494..c7f6b72df 100644 --- a/nalgebra-glm/src/ext/matrix_transform.rs +++ b/nalgebra-glm/src/ext/matrix_transform.rs @@ -1,7 +1,7 @@ -use na::{DefaultAllocator, Point3, Real, Rotation3, Unit}; +use na::{DefaultAllocator, Point3, RealField, Rotation3, Unit}; -use aliases::{TMat, TMat4, TVec, TVec3}; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::{TMat, TMat4, TVec, TVec3}; +use crate::traits::{Alloc, Dimension, Number}; /// The identity matrix. pub fn identity() -> TMat @@ -21,7 +21,7 @@ where DefaultAllocator: Alloc { /// /// * [`look_at_lh`](fn.look_at_lh.html) /// * [`look_at_rh`](fn.look_at_rh.html) -pub fn look_at(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { +pub fn look_at(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { look_at_rh(eye, center, up) } @@ -37,7 +37,7 @@ pub fn look_at(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMa /// /// * [`look_at`](fn.look_at.html) /// * [`look_at_rh`](fn.look_at_rh.html) -pub fn look_at_lh(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { +pub fn look_at_lh(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { TMat::look_at_lh(&Point3::from(*eye), &Point3::from(*center), up) } @@ -53,7 +53,7 @@ pub fn look_at_lh(eye: &TVec3, center: &TVec3, up: &TVec3) -> /// /// * [`look_at`](fn.look_at.html) /// * [`look_at_lh`](fn.look_at_lh.html) -pub fn look_at_rh(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { +pub fn look_at_rh(eye: &TVec3, center: &TVec3, up: &TVec3) -> TMat4 { TMat::look_at_rh(&Point3::from(*eye), &Point3::from(*center), up) } @@ -72,7 +72,7 @@ pub fn look_at_rh(eye: &TVec3, center: &TVec3, up: &TVec3) -> /// * [`rotate_z`](fn.rotate_z.html) /// * [`scale`](fn.scale.html) /// * [`translate`](fn.translate.html) -pub fn rotate(m: &TMat4, angle: N, axis: &TVec3) -> TMat4 { +pub fn rotate(m: &TMat4, angle: N, axis: &TVec3) -> TMat4 { m * Rotation3::from_axis_angle(&Unit::new_normalize(*axis), angle).to_homogeneous() } @@ -90,7 +90,7 @@ pub fn rotate(m: &TMat4, angle: N, axis: &TVec3) -> TMat4 { /// * [`rotate_z`](fn.rotate_z.html) /// * [`scale`](fn.scale.html) /// * [`translate`](fn.translate.html) -pub fn rotate_x(m: &TMat4, angle: N) -> TMat4 { +pub fn rotate_x(m: &TMat4, angle: N) -> TMat4 { rotate(m, angle, &TVec::x()) } @@ -108,7 +108,7 @@ pub fn rotate_x(m: &TMat4, angle: N) -> TMat4 { /// * [`rotate_z`](fn.rotate_z.html) /// * [`scale`](fn.scale.html) /// * [`translate`](fn.translate.html) -pub fn rotate_y(m: &TMat4, angle: N) -> TMat4 { +pub fn rotate_y(m: &TMat4, angle: N) -> TMat4 { rotate(m, angle, &TVec::y()) } @@ -126,7 +126,7 @@ pub fn rotate_y(m: &TMat4, angle: N) -> TMat4 { /// * [`rotate_y`](fn.rotate_y.html) /// * [`scale`](fn.scale.html) /// * [`translate`](fn.translate.html) -pub fn rotate_z(m: &TMat4, angle: N) -> TMat4 { +pub fn rotate_z(m: &TMat4, angle: N) -> TMat4 { rotate(m, angle, &TVec::z()) } diff --git a/nalgebra-glm/src/ext/quaternion_common.rs b/nalgebra-glm/src/ext/quaternion_common.rs index 3a91d0c7c..072b57e21 100644 --- a/nalgebra-glm/src/ext/quaternion_common.rs +++ b/nalgebra-glm/src/ext/quaternion_common.rs @@ -1,36 +1,36 @@ -use na::{self, Real, Unit}; +use na::{self, RealField, Unit}; -use aliases::Qua; +use crate::aliases::Qua; /// The conjugate of `q`. -pub fn quat_conjugate(q: &Qua) -> Qua { +pub fn quat_conjugate(q: &Qua) -> Qua { q.conjugate() } /// The inverse of `q`. -pub fn quat_inverse(q: &Qua) -> Qua { +pub fn quat_inverse(q: &Qua) -> Qua { q.try_inverse().unwrap_or_else(na::zero) } -//pub fn quat_isinf(x: &Qua) -> TVec { +//pub fn quat_isinf(x: &Qua) -> TVec { // x.coords.map(|e| e.is_inf()) //} -//pub fn quat_isnan(x: &Qua) -> TVec { +//pub fn quat_isnan(x: &Qua) -> TVec { // x.coords.map(|e| e.is_nan()) //} /// Interpolate linearly between `x` and `y`. -pub fn quat_lerp(x: &Qua, y: &Qua, a: N) -> Qua { +pub fn quat_lerp(x: &Qua, y: &Qua, a: N) -> Qua { x.lerp(y, a) } -//pub fn quat_mix(x: &Qua, y: &Qua, a: N) -> Qua { +//pub fn quat_mix(x: &Qua, y: &Qua, a: N) -> Qua { // x * (N::one() - a) + y * a //} /// Interpolate spherically between `x` and `y`. -pub fn quat_slerp(x: &Qua, y: &Qua, a: N) -> Qua { +pub fn quat_slerp(x: &Qua, y: &Qua, a: N) -> Qua { Unit::new_normalize(*x) .slerp(&Unit::new_normalize(*y), a) .into_inner() diff --git a/nalgebra-glm/src/ext/quaternion_geometric.rs b/nalgebra-glm/src/ext/quaternion_geometric.rs index a67de587f..24d9310de 100644 --- a/nalgebra-glm/src/ext/quaternion_geometric.rs +++ b/nalgebra-glm/src/ext/quaternion_geometric.rs @@ -1,28 +1,28 @@ -use na::Real; +use na::RealField; -use aliases::Qua; +use crate::aliases::Qua; /// Multiplies two quaternions. -pub fn quat_cross(q1: &Qua, q2: &Qua) -> Qua { +pub fn quat_cross(q1: &Qua, q2: &Qua) -> Qua { q1 * q2 } /// The scalar product of two quaternions. -pub fn quat_dot(x: &Qua, y: &Qua) -> N { +pub fn quat_dot(x: &Qua, y: &Qua) -> N { x.dot(y) } /// The magnitude of the quaternion `q`. -pub fn quat_length(q: &Qua) -> N { +pub fn quat_length(q: &Qua) -> N { q.norm() } /// The magnitude of the quaternion `q`. -pub fn quat_magnitude(q: &Qua) -> N { +pub fn quat_magnitude(q: &Qua) -> N { q.norm() } /// Normalizes the quaternion `q`. -pub fn quat_normalize(q: &Qua) -> Qua { +pub fn quat_normalize(q: &Qua) -> Qua { q.normalize() } diff --git a/nalgebra-glm/src/ext/quaternion_relational.rs b/nalgebra-glm/src/ext/quaternion_relational.rs index e459054fb..bd24edbe7 100644 --- a/nalgebra-glm/src/ext/quaternion_relational.rs +++ b/nalgebra-glm/src/ext/quaternion_relational.rs @@ -1,23 +1,23 @@ -use na::{Real, U4}; +use na::{RealField, U4}; -use aliases::{Qua, TVec}; +use crate::aliases::{Qua, TVec}; /// Component-wise equality comparison between two quaternions. -pub fn quat_equal(x: &Qua, y: &Qua) -> TVec { - ::equal(&x.coords, &y.coords) +pub fn quat_equal(x: &Qua, y: &Qua) -> TVec { + crate::equal(&x.coords, &y.coords) } /// Component-wise approximate equality comparison between two quaternions. -pub fn quat_equal_eps(x: &Qua, y: &Qua, epsilon: N) -> TVec { - ::equal_eps(&x.coords, &y.coords, epsilon) +pub fn quat_equal_eps(x: &Qua, y: &Qua, epsilon: N) -> TVec { + crate::equal_eps(&x.coords, &y.coords, epsilon) } /// Component-wise non-equality comparison between two quaternions. -pub fn quat_not_equal(x: &Qua, y: &Qua) -> TVec { - ::not_equal(&x.coords, &y.coords) +pub fn quat_not_equal(x: &Qua, y: &Qua) -> TVec { + crate::not_equal(&x.coords, &y.coords) } /// Component-wise approximate non-equality comparison between two quaternions. -pub fn quat_not_equal_eps(x: &Qua, y: &Qua, epsilon: N) -> TVec { - ::not_equal_eps(&x.coords, &y.coords, epsilon) +pub fn quat_not_equal_eps(x: &Qua, y: &Qua, epsilon: N) -> TVec { + crate::not_equal_eps(&x.coords, &y.coords, epsilon) } diff --git a/nalgebra-glm/src/ext/quaternion_transform.rs b/nalgebra-glm/src/ext/quaternion_transform.rs index a4a60210f..1e4e97713 100644 --- a/nalgebra-glm/src/ext/quaternion_transform.rs +++ b/nalgebra-glm/src/ext/quaternion_transform.rs @@ -1,27 +1,27 @@ -use na::{Real, Unit, UnitQuaternion}; +use na::{RealField, Unit, UnitQuaternion}; -use aliases::{Qua, TVec3}; +use crate::aliases::{Qua, TVec3}; /// Computes the quaternion exponential. -pub fn quat_exp(q: &Qua) -> Qua { +pub fn quat_exp(q: &Qua) -> Qua { q.exp() } /// Computes the quaternion logarithm. -pub fn quat_log(q: &Qua) -> Qua { +pub fn quat_log(q: &Qua) -> Qua { q.ln() } /// Raises the quaternion `q` to the power `y`. -pub fn quat_pow(q: &Qua, y: N) -> Qua { +pub fn quat_pow(q: &Qua, y: N) -> Qua { q.powf(y) } /// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`. -pub fn quat_rotate(q: &Qua, angle: N, axis: &TVec3) -> Qua { +pub fn quat_rotate(q: &Qua, angle: N, axis: &TVec3) -> Qua { q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner() } -//pub fn quat_sqrt(q: &Qua) -> Qua { +//pub fn quat_sqrt(q: &Qua) -> Qua { // unimplemented!() //} diff --git a/nalgebra-glm/src/ext/quaternion_trigonometric.rs b/nalgebra-glm/src/ext/quaternion_trigonometric.rs index 762bd9e97..a711e69ac 100644 --- a/nalgebra-glm/src/ext/quaternion_trigonometric.rs +++ b/nalgebra-glm/src/ext/quaternion_trigonometric.rs @@ -1,19 +1,19 @@ -use na::{Real, Unit, UnitQuaternion}; +use na::{RealField, Unit, UnitQuaternion}; -use aliases::{Qua, TVec3}; +use crate::aliases::{Qua, TVec3}; /// The rotation angle of this quaternion assumed to be normalized. -pub fn quat_angle(x: &Qua) -> N { +pub fn quat_angle(x: &Qua) -> N { UnitQuaternion::from_quaternion(*x).angle() } /// Creates a quaternion from an axis and an angle. -pub fn quat_angle_axis(angle: N, axis: &TVec3) -> Qua { +pub fn quat_angle_axis(angle: N, axis: &TVec3) -> Qua { UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner() } /// The rotation axis of a quaternion assumed to be normalized. -pub fn quat_axis(x: &Qua) -> TVec3 { +pub fn quat_axis(x: &Qua) -> TVec3 { if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() { a.into_inner() } else { diff --git a/nalgebra-glm/src/ext/scalar_common.rs b/nalgebra-glm/src/ext/scalar_common.rs index 48d3255de..11104ce2d 100644 --- a/nalgebra-glm/src/ext/scalar_common.rs +++ b/nalgebra-glm/src/ext/scalar_common.rs @@ -1,6 +1,6 @@ use na; -use traits::Number; +use crate::traits::Number; /// Returns the maximum among three values. /// diff --git a/nalgebra-glm/src/ext/scalar_constants.rs b/nalgebra-glm/src/ext/scalar_constants.rs index 2b9ed14dd..e0741465f 100644 --- a/nalgebra-glm/src/ext/scalar_constants.rs +++ b/nalgebra-glm/src/ext/scalar_constants.rs @@ -1,5 +1,5 @@ use approx::AbsDiffEq; -use na::Real; +use na::RealField; /// Default epsilon value used for approximate comparison. pub fn epsilon>() -> N { @@ -22,6 +22,6 @@ pub fn epsilon>() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn pi() -> N { +pub fn pi() -> N { N::pi() } diff --git a/nalgebra-glm/src/ext/vector_common.rs b/nalgebra-glm/src/ext/vector_common.rs index c0318067e..a6418ef86 100644 --- a/nalgebra-glm/src/ext/vector_common.rs +++ b/nalgebra-glm/src/ext/vector_common.rs @@ -1,7 +1,7 @@ use na::{self, DefaultAllocator}; -use aliases::TVec; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension, Number}; /// Component-wise maximum between a vector and a scalar. /// diff --git a/nalgebra-glm/src/ext/vector_relational.rs b/nalgebra-glm/src/ext/vector_relational.rs index ee418588f..a50713361 100644 --- a/nalgebra-glm/src/ext/vector_relational.rs +++ b/nalgebra-glm/src/ext/vector_relational.rs @@ -1,7 +1,7 @@ use na::DefaultAllocator; -use aliases::TVec; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension, Number}; /// Component-wise approximate equality of two vectors, using a scalar epsilon. /// diff --git a/nalgebra-glm/src/geometric.rs b/nalgebra-glm/src/geometric.rs index 998709d66..ffdc825ae 100644 --- a/nalgebra-glm/src/geometric.rs +++ b/nalgebra-glm/src/geometric.rs @@ -1,7 +1,7 @@ -use na::{DefaultAllocator, Real}; +use na::{DefaultAllocator, RealField}; -use aliases::{TVec, TVec3}; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::{TVec, TVec3}; +use crate::traits::{Alloc, Dimension, Number}; /// The cross product of two vectors. pub fn cross(x: &TVec3, y: &TVec3) -> TVec3 { @@ -13,7 +13,7 @@ pub fn cross(x: &TVec3, y: &TVec3) -> TVec3 { /// # See also: /// /// * [`distance2`](fn.distance2.html) -pub fn distance(p0: &TVec, p1: &TVec) -> N +pub fn distance(p0: &TVec, p1: &TVec) -> N where DefaultAllocator: Alloc { (p1 - p0).norm() } @@ -49,7 +49,7 @@ where /// * [`length2`](fn.length2.html) /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) -pub fn length(x: &TVec) -> N +pub fn length(x: &TVec) -> N where DefaultAllocator: Alloc { x.norm() } @@ -63,13 +63,13 @@ where DefaultAllocator: Alloc { /// * [`length`](fn.length.html) /// * [`magnitude2`](fn.magnitude2.html) /// * [`nalgebra::norm`](../nalgebra/fn.norm.html) -pub fn magnitude(x: &TVec) -> N +pub fn magnitude(x: &TVec) -> N where DefaultAllocator: Alloc { x.norm() } /// Normalizes a vector. -pub fn normalize(x: &TVec) -> TVec +pub fn normalize(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.normalize() } @@ -82,7 +82,7 @@ where DefaultAllocator: Alloc { } /// 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 +pub fn refract_vec(i: &TVec, n: &TVec, eta: N) -> TVec 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/bitfield.rs b/nalgebra-glm/src/gtc/bitfield.rs index 65fbcce05..bdf18552d 100644 --- a/nalgebra-glm/src/gtc/bitfield.rs +++ b/nalgebra-glm/src/gtc/bitfield.rs @@ -1,7 +1,7 @@ use na::{Scalar, DefaultAllocator}; -use traits::{Alloc, Dimension}; -use aliases::*; +use crate::traits::{Alloc, Dimension}; +use crate::aliases::*; pub fn bitfieldDeinterleave(x: u16) -> U8Vec2 { unimplemented!() diff --git a/nalgebra-glm/src/gtc/constants.rs b/nalgebra-glm/src/gtc/constants.rs index 5e2e1b0d2..4112d65e7 100644 --- a/nalgebra-glm/src/gtc/constants.rs +++ b/nalgebra-glm/src/gtc/constants.rs @@ -1,14 +1,14 @@ -use na::{self, Real}; +use na::{self, RealField}; /// The Euler constant. /// /// This is a shorthand alias for [`euler`](fn.euler.html). -pub fn e() -> N { +pub fn e() -> N { N::e() } /// The Euler constant. -pub fn euler() -> N { +pub fn euler() -> N { N::e() } @@ -28,12 +28,12 @@ pub fn euler() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn four_over_pi() -> N { +pub fn four_over_pi() -> N { na::convert::<_, N>(4.0) / N::pi() } /// Returns the golden ratio. -pub fn golden_ratio() -> N { +pub fn golden_ratio() -> N { (N::one() + root_five()) / na::convert(2.0) } @@ -53,7 +53,7 @@ pub fn golden_ratio() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn half_pi() -> N { +pub fn half_pi() -> N { N::frac_pi_2() } @@ -63,7 +63,7 @@ pub fn half_pi() -> N { /// /// * [`ln_ten`](fn.ln_ten.html) /// * [`ln_two`](fn.ln_two.html) -pub fn ln_ln_two() -> N { +pub fn ln_ln_two() -> N { N::ln_2().ln() } @@ -73,7 +73,7 @@ pub fn ln_ln_two() -> N { /// /// * [`ln_ln_two`](fn.ln_ln_two.html) /// * [`ln_two`](fn.ln_two.html) -pub fn ln_ten() -> N { +pub fn ln_ten() -> N { N::ln_10() } @@ -83,7 +83,7 @@ pub fn ln_ten() -> N { /// /// * [`ln_ln_two`](fn.ln_ln_two.html) /// * [`ln_ten`](fn.ln_ten.html) -pub fn ln_two() -> N { +pub fn ln_two() -> N { N::ln_2() } @@ -106,12 +106,12 @@ pub use na::one; /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn one_over_pi() -> N { +pub fn one_over_pi() -> N { N::frac_1_pi() } /// Returns `1 / sqrt(2)`. -pub fn one_over_root_two() -> N { +pub fn one_over_root_two() -> N { N::one() / root_two() } @@ -131,7 +131,7 @@ pub fn one_over_root_two() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn one_over_two_pi() -> N { +pub fn one_over_two_pi() -> N { N::frac_1_pi() * na::convert(0.5) } @@ -151,7 +151,7 @@ pub fn one_over_two_pi() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn quarter_pi() -> N { +pub fn quarter_pi() -> N { N::frac_pi_4() } @@ -161,7 +161,7 @@ pub fn quarter_pi() -> N { /// /// * [`root_three`](fn.root_three.html) /// * [`root_two`](fn.root_two.html) -pub fn root_five() -> N { +pub fn root_five() -> N { na::convert::<_, N>(5.0).sqrt() } @@ -181,12 +181,12 @@ pub fn root_five() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn root_half_pi() -> N { +pub fn root_half_pi() -> N { (N::pi() / na::convert(2.0)).sqrt() } /// Returns `sqrt(ln(4))`. -pub fn root_ln_four() -> N { +pub fn root_ln_four() -> N { na::convert::<_, N>(4.0).ln().sqrt() } @@ -206,7 +206,7 @@ pub fn root_ln_four() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn root_pi() -> N { +pub fn root_pi() -> N { N::pi().sqrt() } @@ -216,7 +216,7 @@ pub fn root_pi() -> N { /// /// * [`root_five`](fn.root_five.html) /// * [`root_two`](fn.root_two.html) -pub fn root_three() -> N { +pub fn root_three() -> N { na::convert::<_, N>(3.0).sqrt() } @@ -226,8 +226,8 @@ pub fn root_three() -> N { /// /// * [`root_five`](fn.root_five.html) /// * [`root_three`](fn.root_three.html) -pub fn root_two() -> N { - // FIXME: there should be a ::sqrt_2() on the Real trait. +pub fn root_two() -> N { + // FIXME: there should be a crate::sqrt_2() on the RealField trait. na::convert::<_, N>(2.0).sqrt() } @@ -247,7 +247,7 @@ pub fn root_two() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn root_two_pi() -> N { +pub fn root_two_pi() -> N { N::two_pi().sqrt() } @@ -256,7 +256,7 @@ pub fn root_two_pi() -> N { /// # See also: /// /// * [`two_thirds`](fn.two_thirds.html) -pub fn third() -> N { +pub fn third() -> N { na::convert(1.0 / 3.0) } @@ -276,7 +276,7 @@ pub fn third() -> N { /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn three_over_two_pi() -> N { +pub fn three_over_two_pi() -> N { na::convert::<_, N>(3.0) / N::two_pi() } @@ -295,7 +295,7 @@ pub fn three_over_two_pi() -> N { /// * [`three_over_two_pi`](fn.three_over_two_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn two_over_pi() -> N { +pub fn two_over_pi() -> N { N::frac_2_pi() } @@ -315,7 +315,7 @@ pub fn two_over_pi() -> N { /// * [`three_over_two_pi`](fn.three_over_two_pi.html) /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_pi`](fn.two_pi.html) -pub fn two_over_root_pi() -> N { +pub fn two_over_root_pi() -> N { N::frac_2_sqrt_pi() } @@ -335,7 +335,7 @@ pub fn two_over_root_pi() -> N { /// * [`three_over_two_pi`](fn.three_over_two_pi.html) /// * [`two_over_pi`](fn.two_over_pi.html) /// * [`two_over_root_pi`](fn.two_over_root_pi.html) -pub fn two_pi() -> N { +pub fn two_pi() -> N { N::two_pi() } @@ -344,7 +344,7 @@ pub fn two_pi() -> N { /// # See also: /// /// * [`third`](fn.third.html) -pub fn two_thirds() -> N { +pub fn two_thirds() -> N { na::convert(2.0 / 3.0) } diff --git a/nalgebra-glm/src/gtc/epsilon.rs b/nalgebra-glm/src/gtc/epsilon.rs index 4fd7138a7..81ac2e6c9 100644 --- a/nalgebra-glm/src/gtc/epsilon.rs +++ b/nalgebra-glm/src/gtc/epsilon.rs @@ -4,8 +4,8 @@ use approx::AbsDiffEq; use na::DefaultAllocator; -use traits::{Alloc, Number, Dimension}; -use aliases::TVec; +use crate::traits::{Alloc, Number, Dimension}; +use crate::aliases::TVec; /// Component-wise approximate equality beween two vectors. pub fn epsilon_equal(x: &TVec, y: &TVec, epsilon: N) -> TVec diff --git a/nalgebra-glm/src/gtc/integer.rs b/nalgebra-glm/src/gtc/integer.rs index df65843fd..a972a4ab8 100644 --- a/nalgebra-glm/src/gtc/integer.rs +++ b/nalgebra-glm/src/gtc/integer.rs @@ -1,7 +1,7 @@ //use na::{Scalar, DefaultAllocator}; // -//use traits::{Alloc, Dimension}; -//use aliases::TVec; +//use crate::traits::{Alloc, Dimension}; +//use crate::aliases::TVec; //pub fn iround(x: &TVec) -> TVec // where DefaultAllocator: Alloc { diff --git a/nalgebra-glm/src/gtc/matrix_access.rs b/nalgebra-glm/src/gtc/matrix_access.rs index 3eabf5e26..f61d97821 100644 --- a/nalgebra-glm/src/gtc/matrix_access.rs +++ b/nalgebra-glm/src/gtc/matrix_access.rs @@ -1,7 +1,7 @@ use na::{DefaultAllocator, Scalar}; -use aliases::{TMat, TVec}; -use traits::{Alloc, Dimension}; +use crate::aliases::{TMat, TVec}; +use crate::traits::{Alloc, Dimension}; /// The `index`-th column of the matrix `m`. /// diff --git a/nalgebra-glm/src/gtc/matrix_inverse.rs b/nalgebra-glm/src/gtc/matrix_inverse.rs index 4fc305e07..eab0b995b 100644 --- a/nalgebra-glm/src/gtc/matrix_inverse.rs +++ b/nalgebra-glm/src/gtc/matrix_inverse.rs @@ -1,17 +1,17 @@ -use na::{DefaultAllocator, Real}; +use na::{DefaultAllocator, RealField}; -use aliases::TMat; -use traits::{Alloc, Dimension}; +use crate::aliases::TMat; +use crate::traits::{Alloc, Dimension}; /// Fast matrix inverse for affine matrix. -pub fn affine_inverse(m: TMat) -> TMat +pub fn affine_inverse(m: TMat) -> TMat 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 +pub fn inverse_transpose(m: TMat) -> TMat where DefaultAllocator: Alloc { m.try_inverse() .unwrap_or_else(TMat::<_, D, D>::zeros) diff --git a/nalgebra-glm/src/gtc/packing.rs b/nalgebra-glm/src/gtc/packing.rs index b02612398..ea5acac45 100644 --- a/nalgebra-glm/src/gtc/packing.rs +++ b/nalgebra-glm/src/gtc/packing.rs @@ -1,7 +1,7 @@ -use na::{Scalar, Real, DefaultAllocator, U3, U4}; +use na::{Scalar, RealField, DefaultAllocator, U3, U4}; -use traits::{Alloc, Dimension}; -use aliases::*; +use crate::traits::{Alloc, Dimension}; +use crate::aliases::*; pub fn packF2x11_1x10(v: &Vec3) -> i32 { @@ -53,7 +53,7 @@ pub fn packRGBM(rgb: &TVec3) -> TVec4 { unimplemented!() } -pub fn packSnorm(v: TVec) -> TVec +pub fn packSnorm(v: TVec) -> TVec where DefaultAllocator: Alloc + Alloc { unimplemented!() } @@ -102,7 +102,7 @@ pub fn packUint4x8(v: &U8Vec4) -> i32 { unimplemented!() } -pub fn packUnorm(v: &TVec) -> TVec +pub fn packUnorm(v: &TVec) -> TVec where DefaultAllocator: Alloc + Alloc { unimplemented!() } @@ -196,7 +196,7 @@ pub fn unpackRGBM(rgbm: &TVec4) -> TVec3 { unimplemented!() } -pub fn unpackSnorm(v: &TVec) -> TVec +pub fn unpackSnorm(v: &TVec) -> TVec where DefaultAllocator: Alloc + Alloc { unimplemented!() } @@ -245,7 +245,7 @@ pub fn unpackUint4x8(p: i32) -> U8Vec4 { unimplemented!() } -pub fn unpackUnorm(v: &TVec) -> TVec +pub fn unpackUnorm(v: &TVec) -> TVec where DefaultAllocator: Alloc + Alloc { unimplemented!() } diff --git a/nalgebra-glm/src/gtc/quaternion.rs b/nalgebra-glm/src/gtc/quaternion.rs index d31a0bcbb..36977e96c 100644 --- a/nalgebra-glm/src/gtc/quaternion.rs +++ b/nalgebra-glm/src/gtc/quaternion.rs @@ -1,37 +1,37 @@ -use na::{Real, UnitQuaternion, U4}; +use na::{RealField, UnitQuaternion, U4}; -use aliases::{Qua, TMat4, TVec, TVec3}; +use crate::aliases::{Qua, TMat4, TVec, TVec3}; /// Euler angles of the quaternion `q` as (pitch, yaw, roll). -pub fn quat_euler_angles(x: &Qua) -> TVec3 { +pub fn quat_euler_angles(x: &Qua) -> TVec3 { let q = UnitQuaternion::new_unchecked(*x); let a = q.euler_angles(); TVec3::new(a.2, a.1, a.0) } /// Component-wise `>` comparison between two quaternions. -pub fn quat_greater_than(x: &Qua, y: &Qua) -> TVec { - ::greater_than(&x.coords, &y.coords) +pub fn quat_greater_than(x: &Qua, y: &Qua) -> TVec { + crate::greater_than(&x.coords, &y.coords) } /// Component-wise `>=` comparison between two quaternions. -pub fn quat_greater_than_equal(x: &Qua, y: &Qua) -> TVec { - ::greater_than_equal(&x.coords, &y.coords) +pub fn quat_greater_than_equal(x: &Qua, y: &Qua) -> TVec { + crate::greater_than_equal(&x.coords, &y.coords) } /// Component-wise `<` comparison between two quaternions. -pub fn quat_less_than(x: &Qua, y: &Qua) -> TVec { - ::less_than(&x.coords, &y.coords) +pub fn quat_less_than(x: &Qua, y: &Qua) -> TVec { + crate::less_than(&x.coords, &y.coords) } /// Component-wise `<=` comparison between two quaternions. -pub fn quat_less_than_equal(x: &Qua, y: &Qua) -> TVec { - ::less_than_equal(&x.coords, &y.coords) +pub fn quat_less_than_equal(x: &Qua, y: &Qua) -> TVec { + crate::less_than_equal(&x.coords, &y.coords) } /// Convert a quaternion to a rotation matrix in homogeneous coordinates. -pub fn quat_cast(x: &Qua) -> TMat4 { - ::quat_to_mat4(x) +pub fn quat_cast(x: &Qua) -> TMat4 { + crate::quat_to_mat4(x) } /// Computes a right hand look-at quaternion @@ -41,34 +41,34 @@ pub fn quat_cast(x: &Qua) -> TMat4 { /// * `direction` - Direction vector point at where to look /// * `up` - Object up vector /// -pub fn quat_look_at(direction: &TVec3, up: &TVec3) -> Qua { +pub fn quat_look_at(direction: &TVec3, up: &TVec3) -> Qua { quat_look_at_rh(direction, up) } /// Computes a left-handed look-at quaternion (equivalent to a left-handed look-at matrix). -pub fn quat_look_at_lh(direction: &TVec3, up: &TVec3) -> Qua { +pub fn quat_look_at_lh(direction: &TVec3, up: &TVec3) -> Qua { UnitQuaternion::look_at_lh(direction, up).into_inner() } /// Computes a right-handed look-at quaternion (equivalent to a right-handed look-at matrix). -pub fn quat_look_at_rh(direction: &TVec3, up: &TVec3) -> Qua { +pub fn quat_look_at_rh(direction: &TVec3, up: &TVec3) -> Qua { UnitQuaternion::look_at_rh(direction, up).into_inner() } /// The "roll" Euler angle of the quaternion `x` assumed to be normalized. -pub fn quat_roll(x: &Qua) -> N { +pub fn quat_roll(x: &Qua) -> N { // FIXME: optimize this. quat_euler_angles(x).z } /// The "yaw" Euler angle of the quaternion `x` assumed to be normalized. -pub fn quat_yaw(x: &Qua) -> N { +pub fn quat_yaw(x: &Qua) -> N { // FIXME: optimize this. quat_euler_angles(x).y } /// The "pitch" Euler angle of the quaternion `x` assumed to be normalized. -pub fn quat_pitch(x: &Qua) -> N { +pub fn quat_pitch(x: &Qua) -> N { // FIXME: optimize this. quat_euler_angles(x).x } diff --git a/nalgebra-glm/src/gtc/round.rs b/nalgebra-glm/src/gtc/round.rs index 75bd44623..5ad95780b 100644 --- a/nalgebra-glm/src/gtc/round.rs +++ b/nalgebra-glm/src/gtc/round.rs @@ -1,7 +1,7 @@ -use na::{Scalar, Real, U3, DefaultAllocator}; +use na::{Scalar, RealField, U3, DefaultAllocator}; -use traits::{Number, Alloc, Dimension}; -use aliases::TVec; +use crate::traits::{Number, Alloc, Dimension}; +use crate::aliases::TVec; pub fn ceilMultiple(v: T, Multiple: T) -> T { diff --git a/nalgebra-glm/src/gtc/type_ptr.rs b/nalgebra-glm/src/gtc/type_ptr.rs index ed901f20b..4029bf01a 100644 --- a/nalgebra-glm/src/gtc/type_ptr.rs +++ b/nalgebra-glm/src/gtc/type_ptr.rs @@ -1,10 +1,10 @@ -use na::{DefaultAllocator, Quaternion, Real, Scalar}; +use na::{DefaultAllocator, Quaternion, RealField, Scalar}; -use aliases::{ +use crate::aliases::{ Qua, TMat, TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3, TVec1, TVec2, TVec3, TVec4, }; -use traits::{Alloc, Dimension, Number}; +use crate::traits::{Alloc, Dimension, Number}; /// Creates a 2x2 matrix from a slice arranged in column-major order. pub fn make_mat2(ptr: &[N]) -> TMat2 { @@ -112,7 +112,7 @@ pub fn mat4_to_mat2(m: &TMat4) -> TMat2 { } /// Creates a quaternion from a slice arranged as `[x, y, z, w]`. -pub fn make_quat(ptr: &[N]) -> Qua { +pub fn make_quat(ptr: &[N]) -> Qua { Quaternion::from(TVec4::from_column_slice(ptr)) } diff --git a/nalgebra-glm/src/gtc/ulp.rs b/nalgebra-glm/src/gtc/ulp.rs index 860d73be1..8258d0df4 100644 --- a/nalgebra-glm/src/gtc/ulp.rs +++ b/nalgebra-glm/src/gtc/ulp.rs @@ -1,6 +1,6 @@ use na::{Scalar, U2}; -use aliases::TVec; +use crate::aliases::TVec; pub fn float_distance(x: T, y: T) -> u64 { diff --git a/nalgebra-glm/src/gtx/component_wise.rs b/nalgebra-glm/src/gtx/component_wise.rs index 338f43800..7c4af7a0a 100644 --- a/nalgebra-glm/src/gtx/component_wise.rs +++ b/nalgebra-glm/src/gtx/component_wise.rs @@ -1,7 +1,7 @@ use na::{self, DefaultAllocator}; -use aliases::TMat; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::TMat; +use crate::traits::{Alloc, Dimension, Number}; /// The sum of every component of the given matrix or vector. /// diff --git a/nalgebra-glm/src/gtx/euler_angles.rs b/nalgebra-glm/src/gtx/euler_angles.rs index 2c4940a69..c9d16738f 100644 --- a/nalgebra-glm/src/gtx/euler_angles.rs +++ b/nalgebra-glm/src/gtx/euler_angles.rs @@ -1,163 +1,163 @@ -use na::{Real, U3, U4}; +use na::{RealField, U3, U4}; -use aliases::{TVec, TMat}; +use crate::aliases::{TVec, TMat}; -pub fn derivedEulerAngleX(angleX: N, angularVelocityX: N) -> TMat4 { +pub fn derivedEulerAngleX(angleX: N, angularVelocityX: N) -> TMat4 { unimplemented!() } -pub fn derivedEulerAngleY(angleY: N, angularVelocityY: N) -> TMat4 { +pub fn derivedEulerAngleY(angleY: N, angularVelocityY: N) -> TMat4 { unimplemented!() } -pub fn derivedEulerAngleZ(angleZ: N, angularVelocityZ: N) -> TMat4 { +pub fn derivedEulerAngleZ(angleZ: N, angularVelocityZ: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleX(angleX: N) -> TMat4 { +pub fn eulerAngleX(angleX: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleXY(angleX: N, angleY: N) -> TMat4 { +pub fn eulerAngleXY(angleX: N, angleY: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleXYX(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleXYX(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleXYZ(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleXYZ(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleXZ(angleX: N, angleZ: N) -> TMat4 { +pub fn eulerAngleXZ(angleX: N, angleZ: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleXZX(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleXZX(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleXZY(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleXZY(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleY(angleY: N) -> TMat4 { +pub fn eulerAngleY(angleY: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleYX(angleY: N, angleX: N) -> TMat4 { +pub fn eulerAngleYX(angleY: N, angleX: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleYXY(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleYXY(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleYXZ(yaw: N, pitch: N, roll: N) -> TMat4 { +pub fn eulerAngleYXZ(yaw: N, pitch: N, roll: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleYZ(angleY: N, angleZ: N) -> TMat4 { +pub fn eulerAngleYZ(angleY: N, angleZ: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleYZX(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleYZX(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleYZY(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleYZY(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZ(angleZ: N) -> TMat4 { +pub fn eulerAngleZ(angleZ: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZX(angle: N, angleX: N) -> TMat4 { +pub fn eulerAngleZX(angle: N, angleX: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZXY(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleZXY(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZXZ(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleZXZ(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZY(angleZ: N, angleY: N) -> TMat4 { +pub fn eulerAngleZY(angleZ: N, angleY: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZYX(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleZYX(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn eulerAngleZYZ(t1: N, t2: N, t3: N) -> TMat4 { +pub fn eulerAngleZYZ(t1: N, t2: N, t3: N) -> TMat4 { unimplemented!() } -pub fn extractEulerAngleXYX(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleXYX(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleXYZ(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleXYZ(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleXZX(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleXZX(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleXZY(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleXZY(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleYXY(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleYXY(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleYXZ(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleYXZ(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleYZX(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleYZX(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleYZY(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleYZY(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleZXY(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleZXY(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleZXZ(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleZXZ(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleZYX(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleZYX(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn extractEulerAngleZYZ(M: &TMat4) -> (N, N, N) { +pub fn extractEulerAngleZYZ(M: &TMat4) -> (N, N, N) { unimplemented!() } -pub fn orientate2(angle: N) -> TMat3x3 { +pub fn orientate2(angle: N) -> TMat3x3 { unimplemented!() } -pub fn orientate3(angles: TVec3) -> TMat3x3 { +pub fn orientate3(angles: TVec3) -> TMat3x3 { unimplemented!() } -pub fn orientate4(angles: TVec3) -> TMat4 { +pub fn orientate4(angles: TVec3) -> TMat4 { unimplemented!() } -pub fn yawPitchRoll(yaw: N, pitch: N, roll: N) -> TMat4 { +pub fn yawPitchRoll(yaw: N, pitch: N, roll: N) -> TMat4 { unimplemented!() } diff --git a/nalgebra-glm/src/gtx/exterior_product.rs b/nalgebra-glm/src/gtx/exterior_product.rs index cc58597bf..a95c557b8 100644 --- a/nalgebra-glm/src/gtx/exterior_product.rs +++ b/nalgebra-glm/src/gtx/exterior_product.rs @@ -1,5 +1,5 @@ -use aliases::TVec2; -use traits::Number; +use crate::aliases::TVec2; +use crate::traits::Number; /// The 2D perpendicular product between two vectors. pub fn cross2d(v: &TVec2, u: &TVec2) -> N { diff --git a/nalgebra-glm/src/gtx/handed_coordinate_space.rs b/nalgebra-glm/src/gtx/handed_coordinate_space.rs index ee1979adc..22d250564 100644 --- a/nalgebra-glm/src/gtx/handed_coordinate_space.rs +++ b/nalgebra-glm/src/gtx/handed_coordinate_space.rs @@ -1,5 +1,5 @@ -use aliases::TVec3; -use traits::Number; +use crate::aliases::TVec3; +use crate::traits::Number; /// Returns `true` if `{a, b, c}` forms a left-handed trihedron. /// diff --git a/nalgebra-glm/src/gtx/matrix_cross_product.rs b/nalgebra-glm/src/gtx/matrix_cross_product.rs index 7d70d438a..40aa03e82 100644 --- a/nalgebra-glm/src/gtx/matrix_cross_product.rs +++ b/nalgebra-glm/src/gtx/matrix_cross_product.rs @@ -1,13 +1,13 @@ -use na::Real; +use na::RealField; -use aliases::{TMat3, TMat4, TVec3}; +use crate::aliases::{TMat3, TMat4, TVec3}; /// Builds a 3x3 matrix `m` such that for any `v`: `m * v == cross(x, v)`. /// /// # See also: /// /// * [`matrix_cross`](fn.matrix_cross.html) -pub fn matrix_cross3(x: &TVec3) -> TMat3 { +pub fn matrix_cross3(x: &TVec3) -> TMat3 { x.cross_matrix() } @@ -16,6 +16,6 @@ pub fn matrix_cross3(x: &TVec3) -> TMat3 { /// # See also: /// /// * [`matrix_cross3`](fn.matrix_cross3.html) -pub fn matrix_cross(x: &TVec3) -> TMat4 { - ::mat3_to_mat4(&x.cross_matrix()) +pub fn matrix_cross(x: &TVec3) -> TMat4 { + crate::mat3_to_mat4(&x.cross_matrix()) } diff --git a/nalgebra-glm/src/gtx/matrix_operation.rs b/nalgebra-glm/src/gtx/matrix_operation.rs index 954607ef7..cc0512732 100644 --- a/nalgebra-glm/src/gtx/matrix_operation.rs +++ b/nalgebra-glm/src/gtx/matrix_operation.rs @@ -1,7 +1,7 @@ -use aliases::{ +use crate::aliases::{ TMat2, TMat2x3, TMat2x4, TMat3, TMat3x2, TMat3x4, TMat4, TMat4x2, TMat4x3, TVec2, TVec3, TVec4, }; -use traits::Number; +use crate::traits::Number; /// Builds a 2x2 diagonal matrix. /// diff --git a/nalgebra-glm/src/gtx/norm.rs b/nalgebra-glm/src/gtx/norm.rs index 0a2875300..9332c0107 100644 --- a/nalgebra-glm/src/gtx/norm.rs +++ b/nalgebra-glm/src/gtx/norm.rs @@ -1,14 +1,14 @@ -use na::{DefaultAllocator, Real}; +use na::{DefaultAllocator, RealField}; -use aliases::TVec; -use traits::{Alloc, Dimension}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension}; /// The squared distance between two points. /// /// # See also: /// /// * [`distance`](fn.distance.html) -pub fn distance2(p0: &TVec, p1: &TVec) -> N +pub fn distance2(p0: &TVec, p1: &TVec) -> N where DefaultAllocator: Alloc { (p1 - p0).norm_squared() } @@ -20,7 +20,7 @@ where DefaultAllocator: Alloc { /// * [`l1_norm`](fn.l1_norm.html) /// * [`l2_distance`](fn.l2_distance.html) /// * [`l2_norm`](fn.l2_norm.html) -pub fn l1_distance(x: &TVec, y: &TVec) -> N +pub fn l1_distance(x: &TVec, y: &TVec) -> N where DefaultAllocator: Alloc { l1_norm(&(y - x)) } @@ -35,9 +35,9 @@ where DefaultAllocator: Alloc { /// * [`l1_distance`](fn.l1_distance.html) /// * [`l2_distance`](fn.l2_distance.html) /// * [`l2_norm`](fn.l2_norm.html) -pub fn l1_norm(v: &TVec) -> N +pub fn l1_norm(v: &TVec) -> N where DefaultAllocator: Alloc { - ::comp_add(&v.abs()) + crate::comp_add(&v.abs()) } /// The l2-norm of `x - y`. @@ -54,7 +54,7 @@ where DefaultAllocator: Alloc { /// * [`length2`](fn.length2.html) /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) -pub fn l2_distance(x: &TVec, y: &TVec) -> N +pub fn l2_distance(x: &TVec, y: &TVec) -> N where DefaultAllocator: Alloc { l2_norm(&(y - x)) } @@ -75,7 +75,7 @@ where DefaultAllocator: Alloc { /// * [`length2`](fn.length2.html) /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) -pub fn l2_norm(x: &TVec) -> N +pub fn l2_norm(x: &TVec) -> N where DefaultAllocator: Alloc { x.norm() } @@ -91,7 +91,7 @@ where DefaultAllocator: Alloc { /// * [`length`](fn.length.html) /// * [`magnitude`](fn.magnitude.html) /// * [`magnitude2`](fn.magnitude2.html) -pub fn length2(x: &TVec) -> N +pub fn length2(x: &TVec) -> N where DefaultAllocator: Alloc { x.norm_squared() } @@ -107,17 +107,17 @@ where DefaultAllocator: Alloc { /// * [`length2`](fn.length2.html) /// * [`magnitude`](fn.magnitude.html) /// * [`nalgebra::norm_squared`](../nalgebra/fn.norm_squared.html) -pub fn magnitude2(x: &TVec) -> N +pub fn magnitude2(x: &TVec) -> N where DefaultAllocator: Alloc { x.norm_squared() } -//pub fn lxNorm(x: &TVec, y: &TVec, unsigned int Depth) -> N +//pub fn lxNorm(x: &TVec, y: &TVec, unsigned int Depth) -> N // where DefaultAllocator: Alloc { // unimplemented!() //} // -//pub fn lxNorm(x: &TVec, unsigned int Depth) -> N +//pub fn lxNorm(x: &TVec, unsigned int Depth) -> N // where DefaultAllocator: Alloc { // unimplemented!() //} diff --git a/nalgebra-glm/src/gtx/normal.rs b/nalgebra-glm/src/gtx/normal.rs index 63fc9246e..d9f480342 100644 --- a/nalgebra-glm/src/gtx/normal.rs +++ b/nalgebra-glm/src/gtx/normal.rs @@ -1,10 +1,10 @@ -use na::Real; +use na::RealField; -use aliases::TVec3; +use crate::aliases::TVec3; /// The normal vector of the given triangle. /// /// The normal is computed as the normalized vector `cross(p2 - p1, p3 - p1)`. -pub fn triangle_normal(p1: &TVec3, p2: &TVec3, p3: &TVec3) -> TVec3 { +pub fn triangle_normal(p1: &TVec3, p2: &TVec3, p3: &TVec3) -> TVec3 { (p2 - p1).cross(&(p3 - p1)).normalize() } diff --git a/nalgebra-glm/src/gtx/normalize_dot.rs b/nalgebra-glm/src/gtx/normalize_dot.rs index df52d2c02..06ce6978e 100644 --- a/nalgebra-glm/src/gtx/normalize_dot.rs +++ b/nalgebra-glm/src/gtx/normalize_dot.rs @@ -1,7 +1,7 @@ -use na::{DefaultAllocator, Real}; +use na::{DefaultAllocator, RealField}; -use aliases::TVec; -use traits::{Alloc, Dimension}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension}; /// The dot product of the normalized version of `x` and `y`. /// @@ -10,7 +10,7 @@ use traits::{Alloc, Dimension}; /// # See also: /// /// * [`normalize_dot`](fn.normalize_dot.html`) -pub fn fast_normalize_dot(x: &TVec, y: &TVec) -> N +pub fn fast_normalize_dot(x: &TVec, y: &TVec) -> N where DefaultAllocator: Alloc { // XXX: improve those. x.normalize().dot(&y.normalize()) @@ -21,7 +21,7 @@ where DefaultAllocator: Alloc { /// # See also: /// /// * [`fast_normalize_dot`](fn.fast_normalize_dot.html`) -pub fn normalize_dot(x: &TVec, y: &TVec) -> N +pub fn normalize_dot(x: &TVec, y: &TVec) -> N where DefaultAllocator: Alloc { // XXX: improve those. x.normalize().dot(&y.normalize()) diff --git a/nalgebra-glm/src/gtx/quaternion.rs b/nalgebra-glm/src/gtx/quaternion.rs index 70005ca86..a90760d4b 100644 --- a/nalgebra-glm/src/gtx/quaternion.rs +++ b/nalgebra-glm/src/gtx/quaternion.rs @@ -1,97 +1,97 @@ -use na::{Real, Rotation3, Unit, UnitQuaternion, U3}; +use na::{RealField, Rotation3, Unit, UnitQuaternion, U3}; -use aliases::{Qua, TMat3, TMat4, TVec3, TVec4}; +use crate::aliases::{Qua, TMat3, TMat4, TVec3, TVec4}; /// Rotate the vector `v` by the quaternion `q` assumed to be normalized. -pub fn quat_cross_vec(q: &Qua, v: &TVec3) -> TVec3 { +pub fn quat_cross_vec(q: &Qua, v: &TVec3) -> TVec3 { UnitQuaternion::new_unchecked(*q) * v } /// Rotate the vector `v` by the inverse of the quaternion `q` assumed to be normalized. -pub fn quat_inv_cross_vec(v: &TVec3, q: &Qua) -> TVec3 { +pub fn quat_inv_cross_vec(v: &TVec3, q: &Qua) -> TVec3 { UnitQuaternion::new_unchecked(*q).inverse() * v } /// The quaternion `w` component. -pub fn quat_extract_real_component(q: &Qua) -> N { +pub fn quat_extract_real_component(q: &Qua) -> N { q.w } /// Normalized linear interpolation between two quaternions. -pub fn quat_fast_mix(x: &Qua, y: &Qua, a: N) -> Qua { +pub fn quat_fast_mix(x: &Qua, y: &Qua, a: N) -> Qua { Unit::new_unchecked(*x) .nlerp(&Unit::new_unchecked(*y), a) .into_inner() } -//pub fn quat_intermediate(prev: &Qua, curr: &Qua, next: &Qua) -> Qua { +//pub fn quat_intermediate(prev: &Qua, curr: &Qua, next: &Qua) -> Qua { // unimplemented!() //} /// The squared magnitude of a quaternion `q`. -pub fn quat_length2(q: &Qua) -> N { +pub fn quat_length2(q: &Qua) -> N { q.norm_squared() } /// The squared magnitude of a quaternion `q`. -pub fn quat_magnitude2(q: &Qua) -> N { +pub fn quat_magnitude2(q: &Qua) -> N { q.norm_squared() } /// The quaternion representing the identity rotation. -pub fn quat_identity() -> Qua { +pub fn quat_identity() -> Qua { UnitQuaternion::identity().into_inner() } /// Rotates a vector by a quaternion assumed to be normalized. -pub fn quat_rotate_vec3(q: &Qua, v: &TVec3) -> TVec3 { +pub fn quat_rotate_vec3(q: &Qua, v: &TVec3) -> TVec3 { UnitQuaternion::new_unchecked(*q) * v } /// Rotates a vector in homogeneous coordinates by a quaternion assumed to be normalized. -pub fn quat_rotate_vec(q: &Qua, v: &TVec4) -> TVec4 { +pub fn quat_rotate_vec(q: &Qua, v: &TVec4) -> TVec4 { let rotated = Unit::new_unchecked(*q) * v.fixed_rows::(0); TVec4::new(rotated.x, rotated.y, rotated.z, v.w) } /// The rotation required to align `orig` to `dest`. -pub fn quat_rotation(orig: &TVec3, dest: &TVec3) -> Qua { +pub fn quat_rotation(orig: &TVec3, dest: &TVec3) -> Qua { UnitQuaternion::rotation_between(orig, dest) .unwrap_or_else(UnitQuaternion::identity) .into_inner() } /// The spherical linear interpolation between two quaternions. -pub fn quat_short_mix(x: &Qua, y: &Qua, a: N) -> Qua { +pub fn quat_short_mix(x: &Qua, y: &Qua, a: N) -> Qua { Unit::new_normalize(*x) .slerp(&Unit::new_normalize(*y), a) .into_inner() } -//pub fn quat_squad(q1: &Qua, q2: &Qua, s1: &Qua, s2: &Qua, h: N) -> Qua { +//pub fn quat_squad(q1: &Qua, q2: &Qua, s1: &Qua, s2: &Qua, h: N) -> Qua { // unimplemented!() //} /// Converts a quaternion to a rotation matrix. -pub fn quat_to_mat3(x: &Qua) -> TMat3 { +pub fn quat_to_mat3(x: &Qua) -> TMat3 { UnitQuaternion::new_unchecked(*x) .to_rotation_matrix() .into_inner() } /// Converts a quaternion to a rotation matrix in homogenous coordinates. -pub fn quat_to_mat4(x: &Qua) -> TMat4 { +pub fn quat_to_mat4(x: &Qua) -> TMat4 { UnitQuaternion::new_unchecked(*x).to_homogeneous() } /// Converts a rotation matrix to a quaternion. -pub fn mat3_to_quat(x: &TMat3) -> Qua { +pub fn mat3_to_quat(x: &TMat3) -> Qua { let r = Rotation3::from_matrix_unchecked(*x); UnitQuaternion::from_rotation_matrix(&r).into_inner() } /// Converts a rotation matrix in homogeneous coordinates to a quaternion. -pub fn to_quat(x: &TMat4) -> Qua { +pub fn to_quat(x: &TMat4) -> Qua { let rot = x.fixed_slice::(0, 0).into_owned(); mat3_to_quat(&rot) } diff --git a/nalgebra-glm/src/gtx/rotate_normalized_axis.rs b/nalgebra-glm/src/gtx/rotate_normalized_axis.rs index 224d7bfec..1672b9784 100644 --- a/nalgebra-glm/src/gtx/rotate_normalized_axis.rs +++ b/nalgebra-glm/src/gtx/rotate_normalized_axis.rs @@ -1,6 +1,6 @@ -use na::{Real, Rotation3, Unit, UnitQuaternion}; +use na::{RealField, Rotation3, Unit, UnitQuaternion}; -use aliases::{Qua, TMat4, TVec3}; +use crate::aliases::{Qua, TMat4, TVec3}; /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. /// @@ -9,7 +9,7 @@ use aliases::{Qua, TMat4, TVec3}; /// * `m` - Input matrix multiplied by this rotation matrix. /// * `angle` - Rotation angle expressed in radians. /// * `axis` - Rotation axis, must be normalized. -pub fn rotate_normalized_axis(m: &TMat4, angle: N, axis: &TVec3) -> TMat4 { +pub fn rotate_normalized_axis(m: &TMat4, angle: N, axis: &TVec3) -> TMat4 { m * Rotation3::from_axis_angle(&Unit::new_unchecked(*axis), angle).to_homogeneous() } @@ -20,6 +20,6 @@ pub fn rotate_normalized_axis(m: &TMat4, angle: N, axis: &TVec3) /// * `q` - Source orientation. /// * `angle` - Angle expressed in radians. /// * `axis` - Normalized axis of the rotation, must be normalized. -pub fn quat_rotate_normalized_axis(q: &Qua, angle: N, axis: &TVec3) -> Qua { +pub fn quat_rotate_normalized_axis(q: &Qua, angle: N, axis: &TVec3) -> Qua { q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).into_inner() } diff --git a/nalgebra-glm/src/gtx/rotate_vector.rs b/nalgebra-glm/src/gtx/rotate_vector.rs index 64ce72448..30abc7670 100644 --- a/nalgebra-glm/src/gtx/rotate_vector.rs +++ b/nalgebra-glm/src/gtx/rotate_vector.rs @@ -1,9 +1,9 @@ -use na::{Real, Rotation3, Unit, UnitComplex}; +use na::{RealField, Rotation3, Unit, UnitComplex}; -use aliases::{TMat4, TVec2, TVec3, TVec4}; +use crate::aliases::{TMat4, TVec2, TVec3, TVec4}; /// Build the rotation matrix needed to align `normal` and `up`. -pub fn orientation(normal: &TVec3, up: &TVec3) -> TMat4 { +pub fn orientation(normal: &TVec3, up: &TVec3) -> TMat4 { if let Some(r) = Rotation3::rotation_between(normal, up) { r.to_homogeneous() } else { @@ -12,52 +12,52 @@ pub fn orientation(normal: &TVec3, up: &TVec3) -> TMat4 { } /// Rotate a two dimensional vector. -pub fn rotate_vec2(v: &TVec2, angle: N) -> TVec2 { +pub fn rotate_vec2(v: &TVec2, angle: N) -> TVec2 { UnitComplex::new(angle) * v } /// Rotate a three dimensional vector around an axis. -pub fn rotate_vec3(v: &TVec3, angle: N, normal: &TVec3) -> TVec3 { +pub fn rotate_vec3(v: &TVec3, angle: N, normal: &TVec3) -> TVec3 { Rotation3::from_axis_angle(&Unit::new_normalize(*normal), angle) * v } /// Rotate a thee dimensional vector in homogeneous coordinates around an axis. -pub fn rotate_vec4(v: &TVec4, angle: N, normal: &TVec3) -> TVec4 { +pub fn rotate_vec4(v: &TVec4, angle: N, normal: &TVec3) -> TVec4 { Rotation3::from_axis_angle(&Unit::new_normalize(*normal), angle).to_homogeneous() * v } /// Rotate a three dimensional vector around the `X` axis. -pub fn rotate_x_vec3(v: &TVec3, angle: N) -> TVec3 { +pub fn rotate_x_vec3(v: &TVec3, angle: N) -> TVec3 { Rotation3::from_axis_angle(&TVec3::x_axis(), angle) * v } /// Rotate a three dimensional vector in homogeneous coordinates around the `X` axis. -pub fn rotate_x_vec4(v: &TVec4, angle: N) -> TVec4 { +pub fn rotate_x_vec4(v: &TVec4, angle: N) -> TVec4 { Rotation3::from_axis_angle(&TVec3::x_axis(), angle).to_homogeneous() * v } /// Rotate a three dimensional vector around the `Y` axis. -pub fn rotate_y_vec3(v: &TVec3, angle: N) -> TVec3 { +pub fn rotate_y_vec3(v: &TVec3, angle: N) -> TVec3 { Rotation3::from_axis_angle(&TVec3::y_axis(), angle) * v } /// Rotate a three dimensional vector in homogeneous coordinates around the `Y` axis. -pub fn rotate_y_vec4(v: &TVec4, angle: N) -> TVec4 { +pub fn rotate_y_vec4(v: &TVec4, angle: N) -> TVec4 { Rotation3::from_axis_angle(&TVec3::y_axis(), angle).to_homogeneous() * v } /// Rotate a three dimensional vector around the `Z` axis. -pub fn rotate_z_vec3(v: &TVec3, angle: N) -> TVec3 { +pub fn rotate_z_vec3(v: &TVec3, angle: N) -> TVec3 { Rotation3::from_axis_angle(&TVec3::z_axis(), angle) * v } /// Rotate a three dimensional vector in homogeneous coordinates around the `Z` axis. -pub fn rotate_z_vec4(v: &TVec4, angle: N) -> TVec4 { +pub fn rotate_z_vec4(v: &TVec4, angle: N) -> TVec4 { Rotation3::from_axis_angle(&TVec3::z_axis(), angle).to_homogeneous() * v } /// Computes a spherical linear interpolation between the vectors `x` and `y` assumed to be normalized. -pub fn slerp(x: &TVec3, y: &TVec3, a: N) -> TVec3 { +pub fn slerp(x: &TVec3, y: &TVec3, a: N) -> TVec3 { Unit::new_unchecked(*x) .slerp(&Unit::new_unchecked(*y), a) .into_inner() diff --git a/nalgebra-glm/src/gtx/transform.rs b/nalgebra-glm/src/gtx/transform.rs index 85554fe5a..17a853c14 100644 --- a/nalgebra-glm/src/gtx/transform.rs +++ b/nalgebra-glm/src/gtx/transform.rs @@ -1,7 +1,7 @@ -use na::{Real, Rotation2, Rotation3, Unit}; +use na::{RealField, Rotation2, Rotation3, Unit}; -use aliases::{TMat3, TMat4, TVec2, TVec3}; -use traits::Number; +use crate::aliases::{TMat3, TMat4, TVec2, TVec3}; +use crate::traits::Number; /// A rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. /// @@ -12,7 +12,7 @@ use traits::Number; /// * [`rotation2d`](fn.rotation2d.html) /// * [`scaling2d`](fn.scaling2d.html) /// * [`translation2d`](fn.translation2d.html) -pub fn rotation(angle: N, v: &TVec3) -> TMat4 { +pub fn rotation(angle: N, v: &TVec3) -> TMat4 { Rotation3::from_axis_angle(&Unit::new_normalize(*v), angle).to_homogeneous() } @@ -51,7 +51,7 @@ pub fn translation(v: &TVec3) -> TMat4 { /// * [`translation`](fn.translation.html) /// * [`scaling2d`](fn.scaling2d.html) /// * [`translation2d`](fn.translation2d.html) -pub fn rotation2d(angle: N) -> TMat3 { +pub fn rotation2d(angle: N) -> TMat3 { Rotation2::new(angle).to_homogeneous() } diff --git a/nalgebra-glm/src/gtx/transform2.rs b/nalgebra-glm/src/gtx/transform2.rs index fa5533f70..eaa74acb6 100644 --- a/nalgebra-glm/src/gtx/transform2.rs +++ b/nalgebra-glm/src/gtx/transform2.rs @@ -1,7 +1,7 @@ use na::{U2, U3}; -use aliases::{TMat3, TMat4, TVec2, TVec3}; -use traits::Number; +use crate::aliases::{TMat3, TMat4, TVec2, TVec3}; +use crate::traits::Number; /// Build planar projection matrix along normal axis and right-multiply it to `m`. pub fn proj2d(m: &TMat3, normal: &TVec2) -> TMat3 { diff --git a/nalgebra-glm/src/gtx/transform2d.rs b/nalgebra-glm/src/gtx/transform2d.rs index 3d401f566..0c7deb18b 100644 --- a/nalgebra-glm/src/gtx/transform2d.rs +++ b/nalgebra-glm/src/gtx/transform2d.rs @@ -1,7 +1,7 @@ -use na::{Real, UnitComplex}; +use na::{RealField, UnitComplex}; -use aliases::{TMat3, TVec2}; -use traits::Number; +use crate::aliases::{TMat3, TVec2}; +use crate::traits::Number; /// Builds a 2D rotation matrix from an angle and right-multiply it to `m`. /// @@ -12,7 +12,7 @@ use traits::Number; /// * [`scaling2d`](fn.scaling2d.html) /// * [`translate2d`](fn.translate2d.html) /// * [`translation2d`](fn.translation2d.html) -pub fn rotate2d(m: &TMat3, angle: N) -> TMat3 { +pub fn rotate2d(m: &TMat3, angle: N) -> TMat3 { m * UnitComplex::new(angle).to_homogeneous() } diff --git a/nalgebra-glm/src/gtx/vector_angle.rs b/nalgebra-glm/src/gtx/vector_angle.rs index 1ebb39a44..8753ccd0a 100644 --- a/nalgebra-glm/src/gtx/vector_angle.rs +++ b/nalgebra-glm/src/gtx/vector_angle.rs @@ -1,18 +1,18 @@ -use na::{DefaultAllocator, Real}; +use na::{DefaultAllocator, RealField}; -use aliases::TVec; -use traits::{Alloc, Dimension}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension}; /// The angle between two vectors. -pub fn angle(x: &TVec, y: &TVec) -> N +pub fn angle(x: &TVec, y: &TVec) -> N where DefaultAllocator: Alloc { x.angle(y) } -//pub fn oriented_angle(x: &TVec2, y: &TVec2) -> N { +//pub fn oriented_angle(x: &TVec2, y: &TVec2) -> N { // unimplemented!() //} // -//pub fn oriented_angle_ref(x: &TVec3, y: &TVec3, refv: &TVec3) -> N { +//pub fn oriented_angle_ref(x: &TVec3, y: &TVec3, refv: &TVec3) -> N { // unimplemented!() //} diff --git a/nalgebra-glm/src/gtx/vector_query.rs b/nalgebra-glm/src/gtx/vector_query.rs index f408a4b39..2a127f007 100644 --- a/nalgebra-glm/src/gtx/vector_query.rs +++ b/nalgebra-glm/src/gtx/vector_query.rs @@ -1,7 +1,7 @@ -use na::{DefaultAllocator, Real}; +use na::{DefaultAllocator, RealField}; -use aliases::{TVec, TVec2, TVec3}; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::{TVec, TVec2, TVec3}; +use crate::traits::{Alloc, Dimension, Number}; /// Returns `true` if two vectors are collinear (up to an epsilon). /// @@ -45,7 +45,7 @@ where DefaultAllocator: Alloc { } /// Returns `true` if `v` has a magnitude of 1 (up to an epsilon). -pub fn is_normalized(v: &TVec, epsilon: N) -> bool +pub fn is_normalized(v: &TVec, epsilon: N) -> bool where DefaultAllocator: Alloc { abs_diff_eq!(v.norm_squared(), N::one(), epsilon = epsilon * epsilon) } diff --git a/nalgebra-glm/src/integer.rs b/nalgebra-glm/src/integer.rs index 67a0116ca..198d737a8 100644 --- a/nalgebra-glm/src/integer.rs +++ b/nalgebra-glm/src/integer.rs @@ -1,7 +1,7 @@ -use na::{Scalar, Real, U3, DefaultAllocator}; +use na::{Scalar, RealField, U3, DefaultAllocator}; -use traits::{Number, Alloc, Dimension}; -use aliases::TVec; +use crate::traits::{Number, Alloc, Dimension}; +use crate::aliases::TVec; pub fn bitCount(v: T) -> i32 { unimplemented!() diff --git a/nalgebra-glm/src/lib.rs b/nalgebra-glm/src/lib.rs index 53830f2bb..66502e73b 100644 --- a/nalgebra-glm/src/lib.rs +++ b/nalgebra-glm/src/lib.rs @@ -119,7 +119,7 @@ extern crate approx; extern crate alga; extern crate nalgebra as na; -pub use aliases::*; +pub use crate::aliases::*; 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,7 @@ 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 traits::{Alloc, Dimension, Number}; +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, }; @@ -191,7 +191,7 @@ pub use gtx::{ pub use na::{ convert, convert_ref, convert_ref_unchecked, convert_unchecked, try_convert, try_convert_ref, }; -pub use na::{DefaultAllocator, Real, Scalar, U1, U2, U3, U4}; +pub use na::{DefaultAllocator, RealField, Scalar, U1, U2, U3, U4}; mod aliases; mod common; diff --git a/nalgebra-glm/src/matrix.rs b/nalgebra-glm/src/matrix.rs index 812122484..a4c4efe9f 100644 --- a/nalgebra-glm/src/matrix.rs +++ b/nalgebra-glm/src/matrix.rs @@ -1,16 +1,16 @@ -use na::{DefaultAllocator, Real, Scalar}; +use na::{DefaultAllocator, RealField, Scalar}; -use aliases::{TMat, TVec}; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::{TMat, TVec}; +use crate::traits::{Alloc, Dimension, Number}; /// The determinant of the matrix `m`. -pub fn determinant(m: &TMat) -> N +pub fn determinant(m: &TMat) -> N where DefaultAllocator: Alloc { m.determinant() } /// The inverse of the matrix `m`. -pub fn inverse(m: &TMat) -> TMat +pub fn inverse(m: &TMat) -> TMat where DefaultAllocator: Alloc { m.clone() .try_inverse() diff --git a/nalgebra-glm/src/packing.rs b/nalgebra-glm/src/packing.rs index 71df195ca..3273fb266 100644 --- a/nalgebra-glm/src/packing.rs +++ b/nalgebra-glm/src/packing.rs @@ -1,6 +1,6 @@ use na::Scalar; -use aliases::{Vec2, Vec4, UVec2}; +use crate::aliases::{Vec2, Vec4, UVec2}; pub fn packDouble2x32(v: &UVec2) -> f64 { diff --git a/nalgebra-glm/src/trigonometric.rs b/nalgebra-glm/src/trigonometric.rs index cf0b26529..139a48dab 100644 --- a/nalgebra-glm/src/trigonometric.rs +++ b/nalgebra-glm/src/trigonometric.rs @@ -1,94 +1,94 @@ -use na::{self, DefaultAllocator, Real}; +use na::{self, DefaultAllocator, RealField}; -use aliases::TVec; -use traits::{Alloc, Dimension}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension}; /// Component-wise arc-cosinus. -pub fn acos(x: &TVec) -> TVec +pub fn acos(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|e| e.acos()) } /// Component-wise hyperbolic arc-cosinus. -pub fn acosh(x: &TVec) -> TVec +pub fn acosh(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|e| e.acosh()) } /// Component-wise arc-sinus. -pub fn asin(x: &TVec) -> TVec +pub fn asin(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|e| e.asin()) } /// Component-wise hyperbolic arc-sinus. -pub fn asinh(x: &TVec) -> TVec +pub fn asinh(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|e| e.asinh()) } /// Component-wise arc-tangent of `y / x`. -pub fn atan2(y: &TVec, x: &TVec) -> TVec +pub fn atan2(y: &TVec, x: &TVec) -> TVec where DefaultAllocator: Alloc { y.zip_map(x, |y, x| y.atan2(x)) } /// Component-wise arc-tangent. -pub fn atan(y_over_x: &TVec) -> TVec +pub fn atan(y_over_x: &TVec) -> TVec where DefaultAllocator: Alloc { y_over_x.map(|e| e.atan()) } /// Component-wise hyperbolic arc-tangent. -pub fn atanh(x: &TVec) -> TVec +pub fn atanh(x: &TVec) -> TVec where DefaultAllocator: Alloc { x.map(|e| e.atanh()) } /// Component-wise cosinus. -pub fn cos(angle: &TVec) -> TVec +pub fn cos(angle: &TVec) -> TVec where DefaultAllocator: Alloc { angle.map(|e| e.cos()) } /// Component-wise hyperbolic cosinus. -pub fn cosh(angle: &TVec) -> TVec +pub fn cosh(angle: &TVec) -> TVec where DefaultAllocator: Alloc { angle.map(|e| e.cosh()) } /// Component-wise conversion from radians to degrees. -pub fn degrees(radians: &TVec) -> TVec +pub fn degrees(radians: &TVec) -> TVec 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 +pub fn radians(degrees: &TVec) -> TVec where DefaultAllocator: Alloc { degrees.map(|e| e * N::pi() / na::convert(180.0)) } /// Component-wise sinus. -pub fn sin(angle: &TVec) -> TVec +pub fn sin(angle: &TVec) -> TVec where DefaultAllocator: Alloc { angle.map(|e| e.sin()) } /// Component-wise hyperbolic sinus. -pub fn sinh(angle: &TVec) -> TVec +pub fn sinh(angle: &TVec) -> TVec where DefaultAllocator: Alloc { angle.map(|e| e.sinh()) } /// Component-wise tangent. -pub fn tan(angle: &TVec) -> TVec +pub fn tan(angle: &TVec) -> TVec where DefaultAllocator: Alloc { angle.map(|e| e.tan()) } /// Component-wise hyperbolic tangent. -pub fn tanh(angle: &TVec) -> TVec +pub fn tanh(angle: &TVec) -> TVec 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 c92f69fe8..844936fef 100644 --- a/nalgebra-glm/src/vector_relational.rs +++ b/nalgebra-glm/src/vector_relational.rs @@ -1,7 +1,7 @@ use na::DefaultAllocator; -use aliases::TVec; -use traits::{Alloc, Dimension, Number}; +use crate::aliases::TVec; +use crate::traits::{Alloc, Dimension, Number}; /// Checks that all the vector components are `true`. /// diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index ac54589c8..3d8a24d8f 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/rustsim/nalgebra" readme = "README.md" keywords = [ "linear", "algebra", "matrix", "vector" ] license = "BSD-3-Clause" +edition = "2018" [features] serde-serialize = [ "serde", "serde_derive" ] diff --git a/nalgebra-lapack/src/eigen.rs b/nalgebra-lapack/src/eigen.rs index fbc49319a..d5397841b 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::Real; +use alga::general::RealField; use na::allocator::Allocator; use na::dimension::{Dim, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use ComplexHelper; +use crate::ComplexHelper; use lapack; @@ -51,7 +51,7 @@ where MatrixN: Copy, {} -impl Eigen +impl Eigen where DefaultAllocator: Allocator + Allocator { /// Computes the eigenvalues and eigenvectors of the square matrix `m`. @@ -101,7 +101,7 @@ where DefaultAllocator: Allocator + Allocator lapack_check!(info); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; match (left_eigenvectors, eigenvectors) { (true, true) => { @@ -263,7 +263,7 @@ where DefaultAllocator: Allocator + Allocator lapack_panic!(info); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; N::xgeev( b'N', diff --git a/nalgebra-lapack/src/hessenberg.rs b/nalgebra-lapack/src/hessenberg.rs index 65a27d1ea..c9f8d2821 100644 --- a/nalgebra-lapack/src/hessenberg.rs +++ b/nalgebra-lapack/src/hessenberg.rs @@ -5,7 +5,7 @@ use na::allocator::Allocator; use na::dimension::{DimDiff, DimSub, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use ComplexHelper; +use crate::ComplexHelper; use lapack; @@ -66,7 +66,7 @@ where DefaultAllocator: Allocator + Allocator> let mut info = 0; let lwork = N::xgehrd_work_size(n, 1, n, m.as_mut_slice(), n, tau.as_mut_slice(), &mut info); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; lapack_panic!(info); diff --git a/nalgebra-lapack/src/lib.rs b/nalgebra-lapack/src/lib.rs index c343ba836..a1a7b7b79 100644 --- a/nalgebra-lapack/src/lib.rs +++ b/nalgebra-lapack/src/lib.rs @@ -98,7 +98,7 @@ pub use self::eigen::Eigen; pub use self::hessenberg::Hessenberg; pub use self::lu::{LUScalar, LU}; pub use self::qr::QR; -pub use self::schur::RealSchur; +pub use self::schur::Schur; pub use self::svd::SVD; pub use self::symmetric_eigen::SymmetricEigen; diff --git a/nalgebra-lapack/src/lu.rs b/nalgebra-lapack/src/lu.rs index ad76e2451..ada9bb34e 100644 --- a/nalgebra-lapack/src/lu.rs +++ b/nalgebra-lapack/src/lu.rs @@ -5,7 +5,7 @@ use na::allocator::Allocator; use na::dimension::{Dim, DimMin, DimMinimum, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar, VectorN}; -use ComplexHelper; +use crate::ComplexHelper; use lapack; @@ -214,7 +214,7 @@ where } } - /// Solves the linear system `self.conjugate_transpose() * x = b`, where `x` is the unknown to + /// Solves the linear system `self.adjoint() * x = b`, where `x` is the unknown to /// be determined. pub fn solve_conjugate_transpose( &self, @@ -249,11 +249,11 @@ where self.generic_solve_mut(b'T', b) } - /// Solves in-place the linear system `self.conjugate_transpose() * x = b`, where `x` is the unknown to + /// Solves in-place the linear system `self.adjoint() * x = b`, where `x` is the unknown to /// be determined. /// /// Returns `false` if no solution was found (the decomposed matrix is singular). - pub fn solve_conjugate_transpose_mut( + pub fn solve_adjoint_mut( &self, b: &mut MatrixMN, ) -> bool @@ -283,7 +283,7 @@ where ); lapack_check!(info); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; N::xgetri( dim, diff --git a/nalgebra-lapack/src/qr.rs b/nalgebra-lapack/src/qr.rs index 1fa9b0664..5d4b3108a 100644 --- a/nalgebra-lapack/src/qr.rs +++ b/nalgebra-lapack/src/qr.rs @@ -8,7 +8,7 @@ use na::allocator::Allocator; use na::dimension::{Dim, DimMin, DimMinimum, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixMN, Scalar, VectorN}; -use ComplexHelper; +use crate::ComplexHelper; use lapack; @@ -73,7 +73,7 @@ where DefaultAllocator: Allocator &mut info, ); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; N::xgeqrf( nrows.value() as i32, diff --git a/nalgebra-lapack/src/schur.rs b/nalgebra-lapack/src/schur.rs index a09b31ff3..eb618fe9c 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::Real; +use alga::general::RealField; use na::allocator::Allocator; use na::dimension::{Dim, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use ComplexHelper; +use crate::ComplexHelper; use lapack; @@ -33,7 +33,7 @@ use lapack; )) )] #[derive(Clone, Debug)] -pub struct RealSchur +pub struct Schur where DefaultAllocator: Allocator + Allocator { re: VectorN, @@ -42,21 +42,21 @@ where DefaultAllocator: Allocator + Allocator q: MatrixN, } -impl Copy for RealSchur +impl Copy for Schur where DefaultAllocator: Allocator + Allocator, MatrixN: Copy, VectorN: Copy, {} -impl RealSchur +impl Schur where DefaultAllocator: Allocator + Allocator { /// Computes the eigenvalues and real Schur form of the matrix `m`. /// /// Panics if the method did not converge. pub fn new(m: MatrixN) -> Self { - Self::try_new(m).expect("RealSchur decomposition: convergence failed.") + Self::try_new(m).expect("Schur decomposition: convergence failed.") } /// Computes the eigenvalues and real Schur form of the matrix `m`. @@ -98,7 +98,7 @@ where DefaultAllocator: Allocator + Allocator ); lapack_check!(info); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; N::xgees( b'V', @@ -118,7 +118,7 @@ where DefaultAllocator: Allocator + Allocator ); lapack_check!(info); - Some(RealSchur { + Some(Schur { re: wr, im: wi, t: m, @@ -161,8 +161,8 @@ where DefaultAllocator: Allocator + Allocator * Lapack functions dispatch. * */ -/// Trait implemented by scalars for which Lapack implements the Real Schur decomposition. -pub trait RealSchurScalar: Scalar { +/// Trait implemented by scalars for which Lapack implements the RealField Schur decomposition. +pub trait SchurScalar: Scalar { #[allow(missing_docs)] fn xgees( jobvs: u8, @@ -202,7 +202,7 @@ pub trait RealSchurScalar: Scalar { macro_rules! real_eigensystem_scalar_impl ( ($N: ty, $xgees: path) => ( - impl RealSchurScalar for $N { + impl SchurScalar for $N { #[inline] fn xgees(jobvs: u8, sort: u8, diff --git a/nalgebra-lapack/src/svd.rs b/nalgebra-lapack/src/svd.rs index 2d048bf3b..9363fcedb 100644 --- a/nalgebra-lapack/src/svd.rs +++ b/nalgebra-lapack/src/svd.rs @@ -109,7 +109,7 @@ macro_rules! svd_impl( let mut work = [ 0.0 ]; let mut lwork = -1 as i32; let mut info = 0; - let mut iwork = unsafe { ::uninitialized_vec(8 * cmp::min(nrows.value(), ncols.value())) }; + let mut iwork = unsafe { crate::uninitialized_vec(8 * cmp::min(nrows.value(), ncols.value())) }; unsafe { $lapack_func(job, nrows.value() as i32, ncols.value() as i32, m.as_mut_slice(), @@ -119,7 +119,7 @@ macro_rules! svd_impl( lapack_check!(info); lwork = work[0] as i32; - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; unsafe { $lapack_func(job, nrows.value() as i32, ncols.value() as i32, m.as_mut_slice(), diff --git a/nalgebra-lapack/src/symmetric_eigen.rs b/nalgebra-lapack/src/symmetric_eigen.rs index 48e444ba7..d34b3fcec 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::Real; +use alga::general::RealField; use na::allocator::Allocator; use na::dimension::{Dim, U1}; use na::storage::Storage; use na::{DefaultAllocator, Matrix, MatrixN, Scalar, VectorN}; -use ComplexHelper; +use crate::ComplexHelper; use lapack; @@ -52,7 +52,7 @@ where VectorN: Copy, {} -impl SymmetricEigen +impl SymmetricEigen where DefaultAllocator: Allocator + Allocator { /// Computes the eigenvalues and eigenvectors of the symmetric matrix `m`. @@ -102,7 +102,7 @@ where DefaultAllocator: Allocator + Allocator let lwork = N::xsyev_work_size(jobz, b'L', n as i32, m.as_mut_slice(), lda, &mut info); lapack_check!(info); - let mut work = unsafe { ::uninitialized_vec(lwork as usize) }; + let mut work = unsafe { crate::uninitialized_vec(lwork as usize) }; N::xsyev( jobz, diff --git a/nalgebra-lapack/tests/linalg/mod.rs b/nalgebra-lapack/tests/linalg/mod.rs index ba2283085..a67422172 100644 --- a/nalgebra-lapack/tests/linalg/mod.rs +++ b/nalgebra-lapack/tests/linalg/mod.rs @@ -2,6 +2,6 @@ mod cholesky; mod lu; mod qr; mod real_eigensystem; -mod real_schur; +mod schur; mod svd; mod symmetric_eigen; diff --git a/nalgebra-lapack/tests/linalg/real_schur.rs b/nalgebra-lapack/tests/linalg/schur.rs similarity index 73% rename from nalgebra-lapack/tests/linalg/real_schur.rs rename to nalgebra-lapack/tests/linalg/schur.rs index 127107dd3..ccdb0f0b9 100644 --- a/nalgebra-lapack/tests/linalg/real_schur.rs +++ b/nalgebra-lapack/tests/linalg/schur.rs @@ -1,5 +1,5 @@ use na::{DMatrix, Matrix4}; -use nl::RealSchur; +use nl::Schur; use std::cmp; quickcheck! { @@ -7,13 +7,13 @@ quickcheck! { let n = cmp::max(1, cmp::min(n, 10)); let m = DMatrix::::new_random(n, n); - let (vecs, vals) = RealSchur::new(m.clone()).unpack(); + let (vecs, vals) = Schur::new(m.clone()).unpack(); relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7) } fn schur_static(m: Matrix4) -> bool { - let (vecs, vals) = RealSchur::new(m.clone()).unpack(); + let (vecs, vals) = Schur::new(m.clone()).unpack(); relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7) } diff --git a/src/base/alias.rs b/src/base/alias.rs index f7ca2b340..a8925cf32 100644 --- a/src/base/alias.rs +++ b/src/base/alias.rs @@ -1,10 +1,10 @@ #[cfg(any(feature = "alloc", feature = "std"))] -use base::dimension::Dynamic; -use base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::dimension::Dynamic; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; #[cfg(any(feature = "std", feature = "alloc"))] -use base::vec_storage::VecStorage; -use base::storage::Owned; -use base::Matrix; +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 790e4e599..3a332defb 100644 --- a/src/base/alias_slice.rs +++ b/src/base/alias_slice.rs @@ -1,6 +1,6 @@ -use base::dimension::{Dynamic, U1, U2, U3, U4, U5, U6}; -use base::matrix_slice::{SliceStorage, SliceStorageMut}; -use base::Matrix; +use crate::base::dimension::{Dynamic, U1, U2, U3, U4, U5, U6}; +use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; +use crate::base::Matrix; /* * diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 5b17c1831..0ad309816 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -2,10 +2,10 @@ use std::any::Any; -use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::{Dim, U1}; -use base::storage::ContiguousStorageMut; -use base::{DefaultAllocator, Scalar}; +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::ContiguousStorageMut; +use crate::base::{DefaultAllocator, Scalar}; /// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()` /// elements of type `N`. diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 3beab9e16..bebb8740b 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -21,11 +21,11 @@ use abomonation::Abomonation; use generic_array::{ArrayLength, GenericArray}; use typenum::Prod; -use base::allocator::Allocator; -use base::default_allocator::DefaultAllocator; -use base::dimension::{DimName, U1}; -use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut}; -use base::Scalar; +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{DimName, U1}; +use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut}; +use crate::base::Scalar; /* * @@ -330,7 +330,7 @@ where let mut out: Self::Value = unsafe { mem::uninitialized() }; let mut curr = 0; - while let Some(value) = try!(visitor.next_element()) { + while let Some(value) = visitor.next_element()? { *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 be71a1070..6e1b6c818 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -1,17 +1,52 @@ -use alga::general::{ClosedAdd, ClosedMul}; +use alga::general::{ClosedAdd, ClosedMul, ComplexField}; #[cfg(feature = "std")] use matrixmultiply; use num::{One, Signed, Zero}; #[cfg(feature = "std")] use std::mem; -use base::allocator::Allocator; -use base::constraint::{ +use crate::base::allocator::Allocator; +use crate::base::constraint::{ AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, }; -use base::dimension::{Dim, Dynamic, U1, U2, U3, U4}; -use base::storage::{Storage, StorageMut}; -use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector}; +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}; + + +// FIXME: find a way to avoid code duplication just for complex number support. +impl> Vector { + /// Computes the index of the vector component with the largest complex or real absolute value. + /// + /// # Examples: + /// + /// ``` + /// # extern crate num_complex; + /// # extern crate nalgebra; + /// # use num_complex::Complex; + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(Complex::new(11.0, 3.0), Complex::new(-15.0, 0.0), Complex::new(13.0, 5.0)); + /// assert_eq!(vec.icamax(), 2); + /// ``` + #[inline] + pub fn icamax(&self) -> usize { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0).norm1() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).norm1() }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + the_i + } +} impl> Vector { /// Computes the index and value of the vector component with the largest value. @@ -157,6 +192,44 @@ impl> Vector { } } +// FIXME: find a way to avoid code duplication just for complex number support. +impl> Matrix { + /// Computes the index of the matrix component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # extern crate num_complex; + /// # extern crate nalgebra; + /// # use num_complex::Complex; + /// # use nalgebra::Matrix2x3; + /// let mat = Matrix2x3::new(Complex::new(11.0, 1.0), Complex::new(-12.0, 2.0), Complex::new(13.0, 3.0), + /// Complex::new(21.0, 43.0), Complex::new(22.0, 5.0), Complex::new(-23.0, 0.0)); + /// assert_eq!(mat.icamax_full(), (1, 0)); + /// ``` + #[inline] + pub fn icamax_full(&self) -> (usize, usize) { + assert!(!self.is_empty(), "The input matrix must not be empty."); + + let mut the_max = unsafe { self.get_unchecked((0, 0)).norm1() }; + let mut the_ij = (0, 0); + + for j in 0..self.ncols() { + for i in 0..self.nrows() { + let val = unsafe { self.get_unchecked((i, j)).norm1() }; + + if val > the_max { + the_max = val; + the_ij = (i, j); + } + } + } + + the_ij + } +} + + impl> Matrix { /// Computes the index of the matrix component with the largest absolute value. /// @@ -193,30 +266,11 @@ impl> Matri impl> Matrix where N: Scalar + Zero + ClosedAdd + ClosedMul { - /// The dot product between two vectors or matrices (seen as vectors). - /// - /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix - /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::{Vector3, Matrix2x3}; - /// let vec1 = Vector3::new(1.0, 2.0, 3.0); - /// let vec2 = Vector3::new(0.1, 0.2, 0.3); - /// assert_eq!(vec1.dot(&vec2), 1.4); - /// - /// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0, - /// 4.0, 5.0, 6.0); - /// let mat2 = Matrix2x3::new(0.1, 0.2, 0.3, - /// 0.4, 0.5, 0.6); - /// assert_eq!(mat1.dot(&mat2), 9.1); - /// ``` - #[inline] - pub fn dot(&self, rhs: &Matrix) -> N - where - SB: Storage, - ShapeConstraint: DimEq + DimEq, + #[inline(always)] + fn dotx(&self, rhs: &Matrix, conjugate: impl Fn(N) -> N) -> N + where + SB: Storage, + ShapeConstraint: DimEq + DimEq, { assert!( self.nrows() == rhs.nrows(), @@ -227,27 +281,27 @@ 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 = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0)); - let b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0)); + let a = conjugate(*self.get_unchecked((0, 0))) * *rhs.get_unchecked((0, 0)); + let b = conjugate(*self.get_unchecked((1, 0))) * *rhs.get_unchecked((1, 0)); return a + b; } } if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { unsafe { - let a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0)); - let b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0)); - let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0)); + let a = conjugate(*self.get_unchecked((0, 0))) * *rhs.get_unchecked((0, 0)); + let b = conjugate(*self.get_unchecked((1, 0))) * *rhs.get_unchecked((1, 0)); + let c = conjugate(*self.get_unchecked((2, 0))) * *rhs.get_unchecked((2, 0)); return a + b + c; } } if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { unsafe { - let mut a = *self.get_unchecked((0, 0)) * *rhs.get_unchecked((0, 0)); - let mut b = *self.get_unchecked((1, 0)) * *rhs.get_unchecked((1, 0)); - let c = *self.get_unchecked((2, 0)) * *rhs.get_unchecked((2, 0)); - let d = *self.get_unchecked((3, 0)) * *rhs.get_unchecked((3, 0)); + let mut a = conjugate(*self.get_unchecked((0, 0))) * *rhs.get_unchecked((0, 0)); + let mut b = conjugate(*self.get_unchecked((1, 0))) * *rhs.get_unchecked((1, 0)); + let c = conjugate(*self.get_unchecked((2, 0))) * *rhs.get_unchecked((2, 0)); + let d = conjugate(*self.get_unchecked((3, 0))) * *rhs.get_unchecked((3, 0)); a += c; b += d; @@ -287,14 +341,14 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul acc7 = N::zero(); while self.nrows() - i >= 8 { - acc0 += unsafe { *self.get_unchecked((i + 0, j)) * *rhs.get_unchecked((i + 0, j)) }; - acc1 += unsafe { *self.get_unchecked((i + 1, j)) * *rhs.get_unchecked((i + 1, j)) }; - acc2 += unsafe { *self.get_unchecked((i + 2, j)) * *rhs.get_unchecked((i + 2, j)) }; - acc3 += unsafe { *self.get_unchecked((i + 3, j)) * *rhs.get_unchecked((i + 3, j)) }; - acc4 += unsafe { *self.get_unchecked((i + 4, j)) * *rhs.get_unchecked((i + 4, j)) }; - acc5 += unsafe { *self.get_unchecked((i + 5, j)) * *rhs.get_unchecked((i + 5, j)) }; - acc6 += unsafe { *self.get_unchecked((i + 6, j)) * *rhs.get_unchecked((i + 6, j)) }; - acc7 += unsafe { *self.get_unchecked((i + 7, j)) * *rhs.get_unchecked((i + 7, j)) }; + acc0 += unsafe { conjugate(*self.get_unchecked((i + 0, j))) * *rhs.get_unchecked((i + 0, j)) }; + acc1 += unsafe { conjugate(*self.get_unchecked((i + 1, j))) * *rhs.get_unchecked((i + 1, j)) }; + acc2 += unsafe { conjugate(*self.get_unchecked((i + 2, j))) * *rhs.get_unchecked((i + 2, j)) }; + acc3 += unsafe { conjugate(*self.get_unchecked((i + 3, j))) * *rhs.get_unchecked((i + 3, j)) }; + acc4 += unsafe { conjugate(*self.get_unchecked((i + 4, j))) * *rhs.get_unchecked((i + 4, j)) }; + acc5 += unsafe { conjugate(*self.get_unchecked((i + 5, j))) * *rhs.get_unchecked((i + 5, j)) }; + acc6 += unsafe { conjugate(*self.get_unchecked((i + 6, j))) * *rhs.get_unchecked((i + 6, j)) }; + acc7 += unsafe { conjugate(*self.get_unchecked((i + 7, j))) * *rhs.get_unchecked((i + 7, j)) }; i += 8; } @@ -304,13 +358,75 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul res += acc3 + acc7; for k in i..self.nrows() { - res += unsafe { *self.get_unchecked((k, j)) * *rhs.get_unchecked((k, j)) } + res += unsafe { conjugate(*self.get_unchecked((k, j))) * *rhs.get_unchecked((k, j)) } } } 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 + /// `self.dotc(rhs)`. + /// + /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix + /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Vector3, Matrix2x3}; + /// let vec1 = Vector3::new(1.0, 2.0, 3.0); + /// let vec2 = Vector3::new(0.1, 0.2, 0.3); + /// assert_eq!(vec1.dot(&vec2), 1.4); + /// + /// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// let mat2 = Matrix2x3::new(0.1, 0.2, 0.3, + /// 0.4, 0.5, 0.6); + /// assert_eq!(mat1.dot(&mat2), 9.1); + /// ``` + /// + #[inline] + pub fn dot(&self, rhs: &Matrix) -> N + where + SB: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.dotx(rhs, |e| e) + } + + /// The conjugate-linear dot product between two vectors or matrices (seen as vectors). + /// + /// This is equal to `self.adjoint() * rhs`. + /// For real vectors, this is identical to `self.dot(&rhs)`. + /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix + /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Vector2, Complex}; + /// let vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.4, 0.3), Complex::new(0.2, 0.1)); + /// assert_eq!(vec1.dotc(&vec2), Complex::new(2.0, -1.0)); + /// + /// // Note that for complex vectors, we generally have: + /// // vec1.dotc(&vec2) != vec2.dot(&vec2) + /// assert_ne!(vec1.dotc(&vec2), vec1.dot(&vec2)); + /// ``` + #[inline] + pub fn dotc(&self, rhs: &Matrix) -> N + where + N: ComplexField, + SB: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.dotx(rhs, ComplexField::conjugate) + } + /// The dot product between the transpose of `self` and `rhs`. /// /// # Examples: @@ -465,40 +581,15 @@ where } } - /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a - /// vector, and `alpha, beta` two scalars. - /// - /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part - /// (including the diagonal) is actually read. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::{Matrix2, Vector2}; - /// let mat = Matrix2::new(1.0, 2.0, - /// 2.0, 4.0); - /// let mut vec1 = Vector2::new(1.0, 2.0); - /// let vec2 = Vector2::new(0.1, 0.2); - /// vec1.gemv_symm(10.0, &mat, &vec2, 5.0); - /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); - /// - /// - /// // The matrix upper-triangular elements can be garbage because it is never - /// // read by this method. Therefore, it is not necessary for the caller to - /// // fill the matrix struct upper-triangle. - /// let mat = Matrix2::new(1.0, 9999999.9999999, - /// 2.0, 4.0); - /// let mut vec1 = Vector2::new(1.0, 2.0); - /// vec1.gemv_symm(10.0, &mat, &vec2, 5.0); - /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); - /// ``` - #[inline] - pub fn gemv_symm( + + #[inline(always)] + fn xxgemv( &mut self, alpha: N, a: &SquareMatrix, x: &Vector, beta: N, + dot: impl Fn(&DVectorSlice, &DVectorSlice) -> N, ) where N: One, SB: Storage, @@ -511,11 +602,11 @@ where assert!( a.is_square(), - "Syetric gemv: the input matrix must be square." + "Symmetric cgemv: the input matrix must be square." ); assert!( dim2 == dim3 && dim1 == dim2, - "Symmetric gemv: dimensions mismatch." + "Symmetric cgemv: dimensions mismatch." ); if dim2 == 0 { @@ -526,11 +617,11 @@ where let col2 = a.column(0); let val = unsafe { *x.vget_unchecked(0) }; self.axpy(alpha * val, &col2, beta); - self[0] += alpha * x.rows_range(1..).dot(&a.slice_range(1.., 0)); + self[0] += alpha * dot(&a.slice_range(1.., 0), &x.rows_range(1..)); for j in 1..dim2 { let col2 = a.column(j); - let dot = x.rows_range(j..).dot(&col2.rows_range(j..)); + let dot = dot(&col2.rows_range(j..), &x.rows_range(j..)); let val; unsafe { @@ -542,31 +633,123 @@ where } } - /// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and - /// `alpha, beta` two scalars. + /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a + /// vector, and `alpha, beta` two scalars. DEPRECATED: use `sygemv` instead. + #[inline] + #[deprecated(note = "This is renamed `sygemv` to match the original BLAS terminology.")] + pub fn gemv_symm( + &mut self, + alpha: N, + a: &SquareMatrix, + x: &Vector, + beta: N, + ) where + N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.sygemv(alpha, a, x, beta) + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a + /// vector, and `alpha, beta` two scalars. /// - /// If `beta` is zero, `self` is never read. + /// For hermitian matrices, use `.hegemv` instead. + /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part + /// (including the diagonal) is actually read. /// /// # Examples: /// /// ``` /// # use nalgebra::{Matrix2, Vector2}; - /// let mat = Matrix2::new(1.0, 3.0, + /// let mat = Matrix2::new(1.0, 2.0, /// 2.0, 4.0); /// let mut vec1 = Vector2::new(1.0, 2.0); /// let vec2 = Vector2::new(0.1, 0.2); - /// let expected = mat.transpose() * vec2 * 10.0 + vec1 * 5.0; + /// vec1.sygemv(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); /// - /// vec1.gemv_tr(10.0, &mat, &vec2, 5.0); - /// assert_eq!(vec1, expected); + /// + /// // The matrix upper-triangular elements can be garbage because it is never + /// // read by this method. Therefore, it is not necessary for the caller to + /// // fill the matrix struct upper-triangle. + /// let mat = Matrix2::new(1.0, 9999999.9999999, + /// 2.0, 4.0); + /// let mut vec1 = Vector2::new(1.0, 2.0); + /// vec1.sygemv(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); /// ``` #[inline] - pub fn gemv_tr( + pub fn sygemv( + &mut self, + alpha: N, + a: &SquareMatrix, + x: &Vector, + beta: N, + ) where + N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.xxgemv(alpha, a, x, beta, |a, b| a.dot(b)) + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is an **hermitian** matrix, `x` a + /// vector, and `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part + /// (including the diagonal) is actually read. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Matrix2, Vector2, Complex}; + /// let mat = Matrix2::new(Complex::new(1.0, 0.0), Complex::new(2.0, -0.1), + /// Complex::new(2.0, 1.0), Complex::new(4.0, 0.0)); + /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); + /// vec1.sygemv(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(vec1, Vector2::new(Complex::new(-48.0, 44.0), Complex::new(-75.0, 110.0))); + /// + /// + /// // The matrix upper-triangular elements can be garbage because it is never + /// // read by this method. Therefore, it is not necessary for the caller to + /// // fill the matrix struct upper-triangle. + /// + /// let mat = Matrix2::new(Complex::new(1.0, 0.0), Complex::new(99999999.9, 999999999.9), + /// Complex::new(2.0, 1.0), Complex::new(4.0, 0.0)); + /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); + /// vec1.sygemv(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(vec1, Vector2::new(Complex::new(-48.0, 44.0), Complex::new(-75.0, 110.0))); + /// ``` + #[inline] + pub fn hegemv( + &mut self, + alpha: N, + a: &SquareMatrix, + x: &Vector, + beta: N, + ) where + N: ComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.xxgemv(alpha, a, x, beta, |a, b| a.dotc(b)) + } + + + #[inline(always)] + fn gemv_xx( &mut self, alpha: N, a: &Matrix, x: &Vector, beta: N, + dot: impl Fn(&VectorSliceN, &Vector) -> N, ) where N: One, SB: Storage, @@ -589,20 +772,120 @@ where if beta.is_zero() { for j in 0..ncols2 { let val = unsafe { self.vget_unchecked_mut(j) }; - *val = alpha * a.column(j).dot(x) + *val = alpha * dot(&a.column(j), x) } } else { for j in 0..ncols2 { let val = unsafe { self.vget_unchecked_mut(j) }; - *val = alpha * a.column(j).dot(x) + beta * *val; + *val = alpha * dot(&a.column(j), x) + beta * *val; } } } + + + /// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and + /// `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mat = Matrix2::new(1.0, 3.0, + /// 2.0, 4.0); + /// let mut vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// let expected = mat.transpose() * vec2 * 10.0 + vec1 * 5.0; + /// + /// vec1.gemv_tr(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, expected); + /// ``` + #[inline] + pub fn gemv_tr( + &mut self, + alpha: N, + a: &Matrix, + x: &Vector, + beta: N, + ) where + N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.gemv_xx(alpha, a, x, beta, |a, b| a.dot(b)) + } + + /// Computes `self = alpha * a.adjoint() * x + beta * self`, where `a` is a matrix, `x` a vector, and + /// `alpha, beta` two scalars. + /// + /// For real matrices, this is the same as `.gemv_tr`. + /// If `beta` is zero, `self` is never read. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Matrix2, Vector2, Complex}; + /// let mat = Matrix2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0), + /// Complex::new(5.0, 6.0), Complex::new(7.0, 8.0)); + /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); + /// let expected = mat.adjoint() * vec2 * Complex::new(10.0, 20.0) + vec1 * Complex::new(5.0, 15.0); + /// + /// vec1.gemv_ad(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(vec1, expected); + /// ``` + #[inline] + pub fn gemv_ad( + &mut self, + alpha: N, + a: &Matrix, + x: &Vector, + beta: N, + ) where + N: ComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.gemv_xx(alpha, a, x, beta, |a, b| a.dotc(b)) + } } impl> Matrix where N: Scalar + Zero + ClosedAdd + ClosedMul { + #[inline(always)] + fn gerx( + &mut self, + alpha: N, + x: &Vector, + y: &Vector, + beta: N, + conjugate: impl Fn(N) -> N, + ) where + N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + let (nrows1, ncols1) = self.shape(); + let dim2 = x.nrows(); + let dim3 = y.nrows(); + + assert!( + nrows1 == dim2 && ncols1 == dim3, + "ger: dimensions mismatch." + ); + + for j in 0..ncols1 { + // FIXME: avoid bound checks. + let val = unsafe { conjugate(*y.vget_unchecked(j)) }; + self.column_mut(j).axpy(alpha * val, x, beta); + } + } + /// Computes `self = alpha * x * y.transpose() + beta * self`. /// /// If `beta` is zero, `self` is never read. @@ -632,20 +915,40 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul SC: Storage, ShapeConstraint: DimEq + DimEq, { - let (nrows1, ncols1) = self.shape(); - let dim2 = x.nrows(); - let dim3 = y.nrows(); - - assert!( - nrows1 == dim2 && ncols1 == dim3, - "ger: dimensions mismatch." - ); + self.gerx(alpha, x, y, beta, |e| e) + } - for j in 0..ncols1 { - // FIXME: avoid bound checks. - let val = unsafe { *y.vget_unchecked(j) }; - self.column_mut(j).axpy(alpha * val, x, beta); - } + /// Computes `self = alpha * x * y.adjoint() + beta * self`. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix2x3, Vector2, Vector3, Complex}; + /// let mut mat = Matrix2x3::repeat(Complex::new(4.0, 5.0)); + /// let vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector3::new(Complex::new(0.6, 0.5), Complex::new(0.4, 0.5), Complex::new(0.2, 0.1)); + /// let expected = vec1 * vec2.adjoint() * Complex::new(10.0, 20.0) + mat * Complex::new(5.0, 15.0); + /// + /// mat.gerc(Complex::new(10.0, 20.0), &vec1, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(mat, expected); + /// ``` + #[inline] + pub fn gerc( + &mut self, + alpha: N, + x: &Vector, + y: &Vector, + beta: N, + ) where + N: ComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.gerx(alpha, x, y, beta, ComplexField::conjugate) } /// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices. @@ -800,7 +1103,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul /// let expected = mat2.transpose() * mat3 * 10.0 + mat1 * 5.0; /// /// mat1.gemm_tr(10.0, &mat2, &mat3, 5.0); - /// assert_relative_eq!(mat1, expected); + /// assert_eq!(mat1, expected); /// ``` #[inline] pub fn gemm_tr( @@ -836,11 +1139,105 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul self.column_mut(j1).gemv_tr(alpha, a, &b.column(j1), beta); } } + + + /// Computes `self = alpha * a.adjoint() * b + beta * self`, where `a, b, self` are matrices. + /// `alpha` and `beta` are scalar. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4, Complex}; + /// let mut mat1 = Matrix2x4::identity(); + /// let mat2 = Matrix3x2::new(Complex::new(1.0, 4.0), Complex::new(7.0, 8.0), + /// Complex::new(2.0, 5.0), Complex::new(9.0, 10.0), + /// Complex::new(3.0, 6.0), Complex::new(11.0, 12.0)); + /// let mat3 = Matrix3x4::new(Complex::new(0.1, 1.3), Complex::new(0.2, 1.4), Complex::new(0.3, 1.5), Complex::new(0.4, 1.6), + /// Complex::new(0.5, 1.7), Complex::new(0.6, 1.8), Complex::new(0.7, 1.9), Complex::new(0.8, 2.0), + /// Complex::new(0.9, 2.1), Complex::new(1.0, 2.2), Complex::new(1.1, 2.3), Complex::new(1.2, 2.4)); + /// let expected = mat2.adjoint() * mat3 * Complex::new(10.0, 20.0) + mat1 * Complex::new(5.0, 15.0); + /// + /// mat1.gemm_ad(Complex::new(10.0, 20.0), &mat2, &mat3, Complex::new(5.0, 15.0)); + /// assert_eq!(mat1, expected); + /// ``` + #[inline] + pub fn gemm_ad( + &mut self, + alpha: N, + a: &Matrix, + b: &Matrix, + beta: N, + ) where + N: ComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable, + { + let (nrows1, ncols1) = self.shape(); + let (nrows2, ncols2) = a.shape(); + let (nrows3, ncols3) = b.shape(); + + assert_eq!( + nrows2, nrows3, + "gemm: dimensions mismatch for multiplication." + ); + assert_eq!( + (nrows1, ncols1), + (ncols2, ncols3), + "gemm: dimensions mismatch for addition." + ); + + for j1 in 0..ncols1 { + // FIXME: avoid bound checks. + self.column_mut(j1).gemv_ad(alpha, a, &b.column(j1), beta); + } + } } impl> Matrix where N: Scalar + Zero + ClosedAdd + ClosedMul { + #[inline(always)] + fn xxgerx( + &mut self, + alpha: N, + x: &Vector, + y: &Vector, + beta: N, + conjugate: impl Fn(N) -> N, + ) where + N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + let dim1 = self.nrows(); + let dim2 = x.nrows(); + let dim3 = y.nrows(); + + assert!( + self.is_square(), + "Symmetric ger: the input matrix must be square." + ); + assert!(dim1 == dim2 && dim1 == dim3, "ger: dimensions mismatch."); + + for j in 0..dim1 { + let val = unsafe { conjugate(*y.vget_unchecked(j)) }; + let subdim = Dynamic::new(dim1 - j); + // FIXME: avoid bound checks. + self.generic_slice_mut((j, j), (subdim, U1)).axpy( + alpha * val, + &x.rows_range(j..), + beta, + ); + } + } + /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** /// matrix. /// @@ -861,6 +1258,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); /// assert_eq!(mat.m12, 99999.99999); // This was untouched. #[inline] + #[deprecated(note = "This is renamed `syger` to match the original BLAS terminology.")] pub fn ger_symm( &mut self, alpha: N, @@ -873,26 +1271,78 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul SC: Storage, ShapeConstraint: DimEq + DimEq, { - let dim1 = self.nrows(); - let dim2 = x.nrows(); - let dim3 = y.nrows(); + self.syger(alpha, x, y, beta) + } - assert!( - self.is_square(), - "Symmetric ger: the input matrix must be square." - ); - assert!(dim1 == dim2 && dim1 == dim3, "ger: dimensions mismatch."); + /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** + /// matrix. + /// + /// For hermitian complex matrices, use `.hegerc` instead. + /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular + /// (including the diagonal) part of `self` is read/written. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mut mat = Matrix2::identity(); + /// let vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; + /// mat.m12 = 99999.99999; // This component is on the upper-triangular part and will not be read/written. + /// + /// mat.syger(10.0, &vec1, &vec2, 5.0); + /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); + /// assert_eq!(mat.m12, 99999.99999); // This was untouched. + #[inline] + pub fn syger( + &mut self, + alpha: N, + x: &Vector, + y: &Vector, + beta: N, + ) where + N: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.xxgerx(alpha, x, y, beta, |e| e) + } - for j in 0..dim1 { - let val = unsafe { *y.vget_unchecked(j) }; - let subdim = Dynamic::new(dim1 - j); - // FIXME: avoid bound checks. - self.generic_slice_mut((j, j), (subdim, U1)).axpy( - alpha * val, - &x.rows_range(j..), - beta, - ); - } + /// Computes `self = alpha * x * y.adjoint() + beta * self`, where `self` is an **hermitian** + /// matrix. + /// + /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular + /// (including the diagonal) part of `self` is read/written. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Matrix2, Vector2, Complex}; + /// let mut mat = Matrix2::identity(); + /// let vec1 = Vector2::new(Complex::new(1.0, 3.0), Complex::new(2.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.2, 0.4), Complex::new(0.1, 0.3)); + /// let expected = vec1 * vec2.adjoint() * Complex::new(10.0, 20.0) + mat * Complex::new(5.0, 15.0); + /// mat.m12 = Complex::new(99999.99999, 88888.88888); // This component is on the upper-triangular part and will not be read/written. + /// + /// mat.hegerc(Complex::new(10.0, 20.0), &vec1, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); + /// assert_eq!(mat.m12, Complex::new(99999.99999, 88888.88888)); // This was untouched. + #[inline] + pub fn hegerc( + &mut self, + alpha: N, + x: &Vector, + y: &Vector, + beta: N, + ) where + N: ComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.xxgerx(alpha, x, y, beta, ComplexField::conjugate) } } diff --git a/src/base/cg.rs b/src/base/cg.rs index 5883e710b..4029dbc31 100644 --- a/src/base/cg.rs +++ b/src/base/cg.rs @@ -7,18 +7,18 @@ use num::One; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameDiff, DimNameSub, U1}; -use base::storage::{Storage, StorageMut}; -use base::{ +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameDiff, DimNameSub, U1}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{ DefaultAllocator, Matrix3, Matrix4, MatrixN, Scalar, SquareMatrix, Unit, Vector, Vector3, VectorN, }; -use geometry::{ +use crate::geometry::{ Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point3, Rotation2, Rotation3, }; -use alga::general::{Real, Ring}; +use alga::general::{RealField, Ring}; use alga::linear::Transformation; impl MatrixN @@ -65,7 +65,7 @@ where } } -impl Matrix3 { +impl Matrix3 { /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian. #[inline] pub fn new_rotation(angle: N) -> Self { @@ -73,7 +73,7 @@ impl Matrix3 { } } -impl Matrix4 { +impl Matrix4 { /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). /// /// Returns the identity matrix if the given argument is zero. @@ -320,7 +320,7 @@ impl> SquareMatrix } } -impl, S: Storage> SquareMatrix +impl, S: Storage> SquareMatrix where DefaultAllocator: Allocator + Allocator> + Allocator, DimNameDiff> @@ -364,7 +364,7 @@ where DefaultAllocator: Allocator } } -impl> Transformation>> for MatrixN +impl> Transformation>> for MatrixN where DefaultAllocator: Allocator + Allocator> + Allocator, DimNameDiff> diff --git a/src/base/componentwise.rs b/src/base/componentwise.rs index 9081cf369..e5f4d7ecb 100644 --- a/src/base/componentwise.rs +++ b/src/base/componentwise.rs @@ -5,11 +5,11 @@ use std::ops::{Add, Mul}; use alga::general::{ClosedDiv, ClosedMul}; -use base::allocator::{Allocator, SameShapeAllocator}; -use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::Dim; -use base::storage::{Storage, StorageMut}; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar}; +use crate::base::allocator::{Allocator, SameShapeAllocator}; +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::Dim; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixSum, Scalar}; /// The type of the result of a matrix component-wise operation. pub type MatrixComponentOp = MatrixSum; diff --git a/src/base/constraint.rs b/src/base/constraint.rs index 3bd0540b6..89226fe3b 100644 --- a/src/base/constraint.rs +++ b/src/base/constraint.rs @@ -1,6 +1,6 @@ //! Compatibility constraints between matrix shapes, e.g., for addition or multiplication. -use base::dimension::{Dim, DimName, Dynamic}; +use crate::base::dimension::{Dim, DimName, Dynamic}; /// A type used in `where` clauses for enforcing constraints. pub struct ShapeConstraint; diff --git a/src/base/construction.rs b/src/base/construction.rs index aeee61213..5eace4bb0 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -1,5 +1,5 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -12,13 +12,13 @@ use std::iter; use typenum::{self, Cmp, Greater}; #[cfg(feature = "std")] -use alga::general::Real; +use alga::general::RealField; use alga::general::{ClosedAdd, ClosedMul}; -use base::allocator::Allocator; -use base::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6}; -use base::storage::Storage; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar, Unit, Vector, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar, Unit, Vector, VectorN}; /* * @@ -131,7 +131,7 @@ where DefaultAllocator: Allocator where N: Zero + One { let mut res = Self::zeros_generic(nrows, ncols); - for i in 0..::min(nrows.value(), ncols.value()) { + for i in 0..crate::min(nrows.value(), ncols.value()) { unsafe { *res.get_unchecked_mut((i, i)) = elt } } @@ -147,7 +147,7 @@ where DefaultAllocator: Allocator where N: Zero { let mut res = Self::zeros_generic(nrows, ncols); assert!( - elts.len() <= ::min(nrows.value(), ncols.value()), + elts.len() <= crate::min(nrows.value(), ncols.value()), "Too many diagonal elements provided." ); @@ -795,7 +795,7 @@ where } #[cfg(feature = "std")] -impl Distribution>> for Standard +impl Distribution>> for Standard where DefaultAllocator: Allocator, StandardNormal: Distribution, diff --git a/src/base/construction_slice.rs b/src/base/construction_slice.rs index 419720bf3..0946653a5 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_slice.rs @@ -1,6 +1,6 @@ -use base::dimension::{Dim, DimName, Dynamic, U1}; -use base::matrix_slice::{SliceStorage, SliceStorageMut}; -use base::{MatrixSliceMN, MatrixSliceMutMN, Scalar}; +use crate::base::dimension::{Dim, DimName, Dynamic, U1}; +use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; +use crate::base::{MatrixSliceMN, MatrixSliceMutMN, Scalar}; /* * diff --git a/src/base/conversion.rs b/src/base/conversion.rs index fcb6907da..4c5bb0170 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -9,18 +9,18 @@ use generic_array::ArrayLength; use std::ops::Mul; use typenum::Prod; -use base::allocator::{Allocator, SameShapeAllocator}; -use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::{ +use crate::base::allocator::{Allocator, SameShapeAllocator}; +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +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 base::dimension::Dynamic; -use base::iter::{MatrixIter, MatrixIterMut}; -use base::storage::{ContiguousStorage, ContiguousStorageMut, Storage, StorageMut}; +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 base::VecStorage; -use base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar}; +use crate::base::VecStorage; +use crate::base::{DefaultAllocator, Matrix, ArrayStorage, MatrixMN, MatrixSlice, MatrixSliceMut, Scalar}; // FIXME: too bad this won't work allo slice conversions. impl SubsetOf> for MatrixMN @@ -331,9 +331,9 @@ macro_rules! impl_from_into_mint_2D( #[cfg(feature = "mint")] impl_from_into_mint_2D!( (U2, U2) => ColumnMatrix2{x, y}[2]; - (U2, U3) => ColumnMatrix2x3{x, y}[2]; + (U2, U3) => ColumnMatrix2x3{x, y, z}[2]; (U3, U3) => ColumnMatrix3{x, y, z}[3]; - (U3, U4) => ColumnMatrix3x4{x, y, z}[3]; + (U3, U4) => ColumnMatrix3x4{x, y, z, w}[3]; (U4, U4) => ColumnMatrix4{x, y, z, w}[4]; ); diff --git a/src/base/coordinates.rs b/src/base/coordinates.rs index 986b8e9d4..832723e39 100644 --- a/src/base/coordinates.rs +++ b/src/base/coordinates.rs @@ -7,9 +7,9 @@ use std::mem; use std::ops::{Deref, DerefMut}; -use base::dimension::{U1, U2, U3, U4, U5, U6}; -use base::storage::{ContiguousStorage, ContiguousStorageMut}; -use base::{Matrix, Scalar}; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::storage::{ContiguousStorage, ContiguousStorageMut}; +use crate::base::{Matrix, Scalar}; /* * diff --git a/src/base/default_allocator.rs b/src/base/default_allocator.rs index 5926f39d8..c07c87085 100644 --- a/src/base/default_allocator.rs +++ b/src/base/default_allocator.rs @@ -14,15 +14,15 @@ use alloc::vec::Vec; use generic_array::ArrayLength; use typenum::Prod; -use base::allocator::{Allocator, Reallocator}; +use crate::base::allocator::{Allocator, Reallocator}; #[cfg(any(feature = "alloc", feature = "std"))] -use base::dimension::Dynamic; -use base::dimension::{Dim, DimName}; -use base::array_storage::ArrayStorage; +use crate::base::dimension::Dynamic; +use crate::base::dimension::{Dim, DimName}; +use crate::base::array_storage::ArrayStorage; #[cfg(any(feature = "std", feature = "alloc"))] -use base::vec_storage::VecStorage; -use base::storage::{Storage, StorageMut}; -use base::Scalar; +use crate::base::vec_storage::VecStorage; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::Scalar; /* * diff --git a/src/base/edition.rs b/src/base/edition.rs index 32e2c1aa7..5b1c16c49 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -6,17 +6,17 @@ use std::iter::ExactSizeIterator; #[cfg(any(feature = "std", feature = "alloc"))] use std::mem; -use base::allocator::{Allocator, Reallocator}; -use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::{ +use crate::base::allocator::{Allocator, Reallocator}; +use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{ Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1, }; #[cfg(any(feature = "std", feature = "alloc"))] -use base::dimension::Dynamic; -use base::storage::{Storage, StorageMut}; +use crate::base::dimension::Dynamic; +use crate::base::storage::{Storage, StorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] -use base::DMatrix; -use base::{DefaultAllocator, Matrix, MatrixMN, RowVector, Scalar, Vector}; +use crate::base::DMatrix; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, RowVector, Scalar, Vector}; impl> Matrix { /// Extracts the upper triangular part of this matrix (including the diagonal). @@ -58,7 +58,7 @@ impl> Matrix { for j in 0..ncols.value() { // FIXME: use unchecked column indexing let mut res = res.column_mut(j); - let mut src = self.column(j); + let src = self.column(j); for (destination, source) in irows.clone().enumerate() { unsafe { @@ -137,10 +137,10 @@ impl> Matrix { /// Fills the diagonal of this matrix with the content of the given vector. #[inline] pub fn set_diagonal(&mut self, diag: &Vector) - where - R: DimMin, - S2: Storage, - ShapeConstraint: DimEq, R2>, + where + R: DimMin, + S2: Storage, + ShapeConstraint: DimEq, R2>, { let (nrows, ncols) = self.shape(); let min_nrows_ncols = cmp::min(nrows, ncols); @@ -151,6 +151,21 @@ impl> Matrix { } } + /// Fills the diagonal of this matrix with the content of the given iterator. + /// + /// This will fill as many diagonal elements as the iterator yields, up to the + /// minimum of the number of rows and columns of `self`, and starting with the + /// diagonal element at index (0, 0). + #[inline] + pub fn set_partial_diagonal(&mut self, diag: impl Iterator) { + let (nrows, ncols) = self.shape(); + let min_nrows_ncols = cmp::min(nrows, ncols); + + for (i, val) in diag.enumerate().take(min_nrows_ncols) { + unsafe { *self.get_unchecked_mut((i, i)) = val } + } + } + /// Fills the selected row of this matrix with the content of the given vector. #[inline] pub fn set_row(&mut self, i: usize, row: &RowVector) diff --git a/src/base/indexing.rs b/src/base/indexing.rs index 976eef874..ca786530a 100644 --- a/src/base/indexing.rs +++ b/src/base/indexing.rs @@ -1,7 +1,7 @@ //! Indexing -use base::{Dim, DimName, DimDiff, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1}; -use base::storage::{Storage, StorageMut}; +use crate::base::{Dim, DimName, DimDiff, DimSub, Dynamic, Matrix, MatrixSlice, MatrixSliceMut, Scalar, U1}; +use crate::base::storage::{Storage, StorageMut}; use std::ops; @@ -42,7 +42,7 @@ impl DimRange for usize { #[test] fn dimrange_usize() { - use base::dimension::U0; + use crate::base::dimension::U0; assert_eq!(DimRange::contained_by(&0, U0), false); assert_eq!(DimRange::contained_by(&0, U1), true); } @@ -69,7 +69,7 @@ impl DimRange for ops::Range { #[test] fn dimrange_range_usize() { use std::usize::MAX; - use base::dimension::U0; + use crate::base::dimension::U0; 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); @@ -101,7 +101,7 @@ impl DimRange for ops::RangeFrom { #[test] fn dimrange_rangefrom_usize() { use std::usize::MAX; - use base::dimension::U0; + use crate::base::dimension::U0; assert_eq!(DimRange::contained_by(&(0..), U0), false); assert_eq!(DimRange::contained_by(&(0..), U0), false); assert_eq!(DimRange::contained_by(&(0..), U1), true); @@ -133,7 +133,7 @@ where D: DimSub #[test] fn dimrange_rangefrom_dimname() { - use base::dimension::{U5, U4}; + use crate::base::dimension::{U5, U4}; assert_eq!(DimRange::length(&(U1..), U5), U4); } @@ -158,7 +158,7 @@ impl DimRange for ops::RangeFull { #[test] fn dimrange_rangefull() { - use base::dimension::U0; + use crate::base::dimension::U0; assert_eq!(DimRange::contained_by(&(..), U0), true); assert_eq!(DimRange::length(&(..), U1), U1); } @@ -190,7 +190,7 @@ impl DimRange for ops::RangeInclusive { #[test] fn dimrange_rangeinclusive_usize() { use std::usize::MAX; - use base::dimension::U0; + use crate::base::dimension::U0; 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); @@ -225,7 +225,7 @@ impl DimRange for ops::RangeTo #[test] fn dimrange_rangeto_usize() { use std::usize::MAX; - use base::dimension::U0; + use crate::base::dimension::U0; assert_eq!(DimRange::contained_by(&(..0), U0), true); assert_eq!(DimRange::contained_by(&(..1), U0), false); assert_eq!(DimRange::contained_by(&(..0), U1), true); @@ -257,7 +257,7 @@ impl DimRange for ops::RangeToInclusive #[test] fn dimrange_rangetoinclusive_usize() { use std::usize::MAX; - use base::dimension::U0; + use crate::base::dimension::U0; assert_eq!(DimRange::contained_by(&(..=0), U0), false); assert_eq!(DimRange::contained_by(&(..=1), U0), false); assert_eq!(DimRange::contained_by(&(..=0), U1), true); @@ -627,7 +627,7 @@ macro_rules! impl_index_pair { #[doc(hidden)] #[inline(always)] unsafe fn get_unchecked(self, matrix: &'a Matrix) -> Self::Output { - use base::SliceStorage; + use crate::base::SliceStorage; let (rows, cols) = self; let (nrows, ncols) = matrix.data.shape(); @@ -655,7 +655,7 @@ macro_rules! impl_index_pair { #[doc(hidden)] #[inline(always)] unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut { - use base::SliceStorageMut; + use crate::base::SliceStorageMut; let (rows, cols) = self; let (nrows, ncols) = matrix.data.shape(); diff --git a/src/base/iter.rs b/src/base/iter.rs index 8a5f10abf..74e4f0185 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -3,9 +3,9 @@ use std::marker::PhantomData; use std::mem; -use base::dimension::{Dim, U1}; -use base::storage::{Storage, StorageMut}; -use base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut}; +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{Scalar, Matrix, MatrixSlice, MatrixSliceMut}; macro_rules! iterator { (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty) => { diff --git a/src/base/matrix.rs b/src/base/matrix.rs index fcd537031..6c1db1d6b 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -1,5 +1,4 @@ use num::{One, Zero}; -use num_complex::Complex; #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; @@ -17,16 +16,16 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{ClosedAdd, ClosedMul, ClosedSub, Real, Ring}; +use alga::general::{ClosedAdd, ClosedMul, ClosedSub, RealField, Ring, ComplexField, Field}; -use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; -use base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3}; -use base::iter::{MatrixIter, MatrixIterMut, RowIter, RowIterMut, ColumnIter, ColumnIterMut}; -use base::storage::{ +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::storage::{ ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut, }; -use base::{DefaultAllocator, MatrixMN, MatrixN, Scalar, Unit, VectorN}; +use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Scalar, Unit, VectorN}; /// A square matrix. pub type SquareMatrix = Matrix; @@ -771,6 +770,14 @@ 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{ + self.apply(f); + self + } + /// Replaces each component of `self` by the result of a closure `f` applied on it. #[inline] pub fn apply N>(&mut self, mut f: F) { @@ -906,14 +913,14 @@ impl> Matrix { } } -impl, R, C>> Matrix, R, C, S> { - /// Takes the conjugate and transposes `self` and store the result into `out`. +impl> Matrix { + /// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`. #[inline] - pub fn conjugate_transpose_to(&self, out: &mut Matrix, R2, C2, SB>) + pub fn adjoint_to(&self, out: &mut Matrix) where R2: Dim, C2: Dim, - SB: StorageMut, R2, C2>, + SB: StorageMut, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, { let (nrows, ncols) = self.shape(); @@ -926,30 +933,98 @@ impl, R, C>> Matrix, R for i in 0..nrows { for j in 0..ncols { unsafe { - *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conj(); + *out.get_unchecked_mut((j, i)) = self.get_unchecked((i, j)).conjugate(); } } } } - /// The conjugate transposition of `self`. + /// The adjoint (aka. conjugate-transpose) of `self`. #[inline] - pub fn conjugate_transpose(&self) -> MatrixMN, C, R> - where DefaultAllocator: Allocator, C, R> { + pub fn adjoint(&self) -> MatrixMN + where DefaultAllocator: Allocator { let (nrows, ncols) = self.data.shape(); unsafe { let mut res: MatrixMN<_, C, R> = Matrix::new_uninitialized_generic(ncols, nrows); - self.conjugate_transpose_to(&mut res); + self.adjoint_to(&mut res); res } } + + /// Takes the conjugate and transposes `self` and store the result into `out`. + #[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, + { + self.adjoint_to(out) + } + + /// The conjugate transposition of `self`. + #[deprecated(note = "Renamed `self.adjoint()`.")] + #[inline] + pub fn conjugate_transpose(&self) -> MatrixMN + where DefaultAllocator: Allocator { + self.adjoint() + } + + /// The conjugate of `self`. + #[inline] + pub fn conjugate(&self) -> MatrixMN + where DefaultAllocator: Allocator { + self.map(|e| e.conjugate()) + } + + /// Divides each component of the complex matrix `self` by the given real. + #[inline] + pub fn unscale(&self, real: N::RealField) -> MatrixMN + where DefaultAllocator: Allocator { + self.map(|e| e.unscale(real)) + } + + /// Multiplies each component of the complex matrix `self` by the given real. + #[inline] + pub fn scale(&self, real: N::RealField) -> MatrixMN + where DefaultAllocator: Allocator { + self.map(|e| e.scale(real)) + } } -impl, D, D>> Matrix, D, D, S> { - /// Sets `self` to its conjugate transpose. - pub fn conjugate_transpose_mut(&mut self) { +impl> Matrix { + /// The conjugate of the complex matrix `self` computed in-place. + #[inline] + pub fn conjugate_mut(&mut self) { + self.apply(|e| e.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)) + } + + /// 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)) + } +} + +impl> Matrix { + /// Sets `self` to its adjoint. + #[deprecated(note = "Renamed to `self.adjoint_mut()`.")] + pub fn conjugate_transform_mut(&mut self) { + self.adjoint_mut() + } + + /// Sets `self` to its adjoint (aka. conjugate-transpose). + pub fn adjoint_mut(&mut self) { assert!( self.is_square(), "Unable to transpose a non-square matrix in-place." @@ -957,26 +1032,40 @@ impl, D, D>> Matrix, D, D, let dim = self.shape().0; - for i in 1..dim { + for i in 0..dim { for j in 0..i { unsafe { - let ref_ij = self.get_unchecked_mut((i, j)) as *mut Complex; - let ref_ji = self.get_unchecked_mut((j, i)) as *mut Complex; - let conj_ij = (*ref_ij).conj(); - let conj_ji = (*ref_ji).conj(); + 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(); *ref_ij = conj_ji; *ref_ji = conj_ij; } } + + { + let diag = unsafe { self.get_unchecked_mut((i, i)) }; + *diag = diag.conjugate(); + } } } } impl> SquareMatrix { - /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. + /// The diagonal of this matrix. #[inline] pub fn diagonal(&self) -> VectorN - where DefaultAllocator: Allocator { + where DefaultAllocator: Allocator { + self.map_diagonal(|e| e) + } + + /// Apply the given function to this matrix's diagonal and returns it. + /// + /// 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 { assert!( self.is_square(), "Unable to get the diagonal of a non-square matrix." @@ -987,7 +1076,7 @@ impl> SquareMatrix { for i in 0..dim.value() { unsafe { - *res.vget_unchecked_mut(i) = *self.get_unchecked((i, i)); + *res.vget_unchecked_mut(i) = f(*self.get_unchecked((i, i))); } } @@ -997,7 +1086,7 @@ 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: Ring { assert!( self.is_square(), "Cannot compute the trace of non-square matrix." @@ -1014,6 +1103,31 @@ 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."); + let mut tr = self.transpose(); + tr += self; + tr *= crate::convert::<_, N>(0.5); + tr + } + + /// 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."); + + let mut tr = self.adjoint(); + tr += self; + tr *= crate::convert::<_, N>(0.5); + tr + } +} + impl + IsNotStaticOne, S: Storage> Matrix { /// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and @@ -1278,40 +1392,40 @@ where for i in 0..nrows { for j in 0..ncols { lengths[(i, j)] = val_width(self[(i, j)], f); - max_length = ::max(max_length, lengths[(i, j)]); + max_length = crate::max(max_length, lengths[(i, j)]); } } let max_length_with_space = max_length + 1; - try!(writeln!(f)); - try!(writeln!( + writeln!(f)?; + writeln!( f, " ┌ {:>width$} ┐", "", width = max_length_with_space * ncols - 1 - )); + )?; for i in 0..nrows { - try!(write!(f, " │")); + write!(f, " │")?; for j in 0..ncols { let number_length = lengths[(i, j)] + 1; let pad = max_length_with_space - number_length; - try!(write!(f, " {:>thepad$}", "", thepad = pad)); + write!(f, " {:>thepad$}", "", thepad = pad)?; match f.precision() { - Some(precision) => try!(write!(f, "{:.1$}", (*self)[(i, j)], precision)), - None => try!(write!(f, "{}", (*self)[(i, j)])), + Some(precision) => write!(f, "{:.1$}", (*self)[(i, j)], precision)?, + None => write!(f, "{}", (*self)[(i, j)])?, } } - try!(writeln!(f, " │")); + writeln!(f, " │")?; } - try!(writeln!( + writeln!( f, " └ {:>width$} ┘", "", width = max_length_with_space * ncols - 1 - )); + )?; writeln!(f) } } @@ -1407,7 +1521,7 @@ impl> Matrix { } } -impl> Vector +impl> Vector where DefaultAllocator: Allocator { /// Computes the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`. @@ -1427,27 +1541,27 @@ where DefaultAllocator: Allocator } } -impl> Matrix { +impl> Matrix { /// The smallest angle between two vectors. #[inline] - pub fn angle(&self, other: &Matrix) -> N + pub fn angle(&self, other: &Matrix) -> N::RealField where SB: Storage, ShapeConstraint: DimEq + DimEq, { - let prod = self.dot(other); + let prod = self.dotc(other); let n1 = self.norm(); let n2 = other.norm(); if n1.is_zero() || n2.is_zero() { - N::zero() + N::RealField::zero() } else { - let cang = prod / (n1 * n2); + let cang = prod.real() / (n1 * n2); - if cang > N::one() { - N::zero() - } else if cang < -N::one() { - N::pi() + if cang > N::RealField::one() { + N::RealField::zero() + } else if cang < -N::RealField::one() { + N::RealField::pi() } else { cang.acos() } @@ -1478,18 +1592,18 @@ impl> Unit> { +impl> Unit> { /// Computes the spherical linear interpolation between two unit vectors. pub fn slerp>( &self, rhs: &Unit>, - t: N, + t: N::RealField, ) -> Unit> where DefaultAllocator: Allocator, { // FIXME: the result is wrong when self and rhs are collinear with opposite direction. - self.try_slerp(rhs, t, N::default_epsilon()) + self.try_slerp(rhs, t, N::RealField::default_epsilon()) .unwrap_or(Unit::new_unchecked(self.clone_owned())) } @@ -1500,29 +1614,30 @@ impl> Unit> { pub fn try_slerp>( &self, rhs: &Unit>, - t: N, - epsilon: N, + t: N::RealField, + epsilon: N::RealField, ) -> Option>> where DefaultAllocator: Allocator, { - let c_hang = self.dot(rhs); + let (c_hang, c_hang_sign) = self.dotc(rhs).to_exp(); // self == other - if c_hang.abs() >= N::one() { + if c_hang >= N::RealField::one() { return Some(Unit::new_unchecked(self.clone_owned())); } let hang = c_hang.acos(); - let s_hang = (N::one() - c_hang * c_hang).sqrt(); + let s_hang = (N::RealField::one() - c_hang * c_hang).sqrt(); // FIXME: what if s_hang is 0.0 ? The result is not well-defined. - if relative_eq!(s_hang, N::zero(), epsilon = epsilon) { + if relative_eq!(s_hang, N::RealField::zero(), epsilon = epsilon) { None } else { - let ta = ((N::one() - t) * hang).sin() / s_hang; + let ta = ((N::RealField::one() - t) * hang).sin() / s_hang; let tb = (t * hang).sin() / s_hang; - let res = &**self * ta + &**rhs * tb; + let mut res = self.scale(ta); + res.axpy(c_hang_sign.scale(tb), &**rhs, N::one()); Some(Unit::new_unchecked(res)) } diff --git a/src/base/matrix_alga.rs b/src/base/matrix_alga.rs index 6ce608097..ac6aced78 100644 --- a/src/base/matrix_alga.rs +++ b/src/base/matrix_alga.rs @@ -7,16 +7,16 @@ use alga::general::{ AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul, ClosedNeg, Field, Identity, TwoSidedInverse, JoinSemilattice, Lattice, MeetSemilattice, Module, - Multiplicative, Real, RingCommutative, + Multiplicative, RingCommutative, ComplexField }; use alga::linear::{ FiniteDimInnerSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace, VectorSpace, }; -use base::allocator::Allocator; -use base::dimension::{Dim, DimName}; -use base::storage::{Storage, StorageMut}; -use base::{DefaultAllocator, MatrixMN, MatrixN, Scalar}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, DimName}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{DefaultAllocator, MatrixMN, MatrixN, Scalar}; /* * @@ -145,16 +145,19 @@ where } } -impl NormedSpace for MatrixMN +impl NormedSpace for MatrixMN where DefaultAllocator: Allocator { + type RealField = N::RealField; + type ComplexField = N; + #[inline] - fn norm_squared(&self) -> N { + fn norm_squared(&self) -> N::RealField { self.norm_squared() } #[inline] - fn norm(&self) -> N { + fn norm(&self) -> N::RealField { self.norm() } @@ -164,34 +167,32 @@ where DefaultAllocator: Allocator } #[inline] - fn normalize_mut(&mut self) -> N { + fn normalize_mut(&mut self) -> N::RealField { self.normalize_mut() } #[inline] - fn try_normalize(&self, min_norm: N) -> Option { + fn try_normalize(&self, min_norm: N::RealField) -> Option { self.try_normalize(min_norm) } #[inline] - fn try_normalize_mut(&mut self, min_norm: N) -> Option { + fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option { self.try_normalize_mut(min_norm) } } -impl InnerSpace for MatrixMN +impl InnerSpace for MatrixMN where DefaultAllocator: Allocator { - type Real = N; - #[inline] - fn angle(&self, other: &Self) -> N { + fn angle(&self, other: &Self) -> N::RealField { self.angle(other) } #[inline] fn inner_product(&self, other: &Self) -> N { - self.dot(other) + self.dotc(other) } } @@ -199,7 +200,7 @@ 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 +impl FiniteDimInnerSpace for MatrixMN where DefaultAllocator: Allocator { #[inline] @@ -215,7 +216,7 @@ where DefaultAllocator: Allocator } } - if vs[i].try_normalize_mut(N::zero()).is_some() { + 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); @@ -268,7 +269,7 @@ where DefaultAllocator: Allocator let v = &vs[0]; let mut a; - if v[0].abs() > v[1].abs() { + 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]]); @@ -300,7 +301,7 @@ where DefaultAllocator: Allocator elt -= v * elt.dot(v) } - if let Some(subsp_elt) = elt.try_normalize(N::zero()) { + if let Some(subsp_elt) = elt.try_normalize(N::RealField::zero()) { if !f(&subsp_elt) { return; }; diff --git a/src/base/matrix_slice.rs b/src/base/matrix_slice.rs index a4ce15330..be53034a5 100644 --- a/src/base/matrix_slice.rs +++ b/src/base/matrix_slice.rs @@ -2,12 +2,12 @@ use std::marker::PhantomData; use std::ops::{Range, RangeFrom, RangeFull, RangeTo}; use std::slice; -use base::allocator::Allocator; -use base::default_allocator::DefaultAllocator; -use base::dimension::{Dim, DimName, Dynamic, U1, IsNotStaticOne}; -use base::iter::MatrixIter; -use base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut}; -use base::{Matrix, Scalar}; +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Dim, DimName, Dynamic, U1, IsNotStaticOne}; +use crate::base::iter::MatrixIter; +use crate::base::storage::{Owned, Storage, StorageMut, ContiguousStorage, ContiguousStorageMut}; +use crate::base::{Matrix, Scalar}; macro_rules! slice_storage_impl( ($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { diff --git a/src/base/norm.rs b/src/base/norm.rs index 68fb88a1c..93319ddc8 100644 --- a/src/base/norm.rs +++ b/src/base/norm.rs @@ -1,23 +1,22 @@ -use num::Signed; -use std::cmp::PartialOrd; +use num::Zero; -use allocator::Allocator; -use ::{Real, Scalar}; -use storage::{Storage, StorageMut}; -use base::{DefaultAllocator, Matrix, Dim, MatrixMN}; -use constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint}; +use crate::allocator::Allocator; +use crate::{RealField, ComplexField}; +use crate::storage::{Storage, StorageMut}; +use crate::base::{DefaultAllocator, Matrix, Dim, MatrixMN}; +use crate::constraint::{SameNumberOfRows, SameNumberOfColumns, ShapeConstraint}; // 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 + fn norm(&self, m: &Matrix) -> N::RealField 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 + 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; @@ -30,60 +29,62 @@ 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 + fn norm(&self, m: &Matrix) -> N::RealField where R: Dim, C: Dim, S: Storage { m.norm_squared().sqrt() } #[inline] - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N + 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::zero(), |acc, a, b| { + m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| { let diff = a - b; - acc + diff * diff + acc + diff.modulus_squared() }).sqrt() } } -impl Norm for LpNorm { +impl Norm for LpNorm { #[inline] - fn norm(&self, m: &Matrix) -> N + fn norm(&self, m: &Matrix) -> N::RealField where R: Dim, C: Dim, S: Storage { - m.fold(N::zero(), |a, b| { - a + b.abs().powi(self.0) - }).powf(::convert(1.0 / (self.0 as f64))) + m.fold(N::RealField::zero(), |a, b| { + a + b.modulus().powi(self.0) + }).powf(crate::convert(1.0 / (self.0 as f64))) } #[inline] - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N + 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::zero(), |acc, a, b| { + m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| { let diff = a - b; - acc + diff.abs().powi(self.0) - }).powf(::convert(1.0 / (self.0 as f64))) + acc + diff.modulus().powi(self.0) + }).powf(crate::convert(1.0 / (self.0 as f64))) } } -impl Norm for UniformNorm { +impl Norm for UniformNorm { #[inline] - fn norm(&self, m: &Matrix) -> N + fn norm(&self, m: &Matrix) -> N::RealField where R: Dim, C: Dim, S: Storage { - m.amax() + // 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())) } #[inline] - fn metric_distance(&self, m1: &Matrix, m2: &Matrix) -> N + 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::zero(), |acc, a, b| { - let val = (a - b).abs(); + m1.zip_fold(m2, N::RealField::zero(), |acc, a, b| { + let val = (a - b).modulus(); if val > acc { val } else { @@ -94,15 +95,15 @@ impl Norm for UniformNorm { } -impl> Matrix { +impl> Matrix { /// The squared L2 norm of this vector. #[inline] - pub fn norm_squared(&self) -> N { - let mut res = N::zero(); + pub fn norm_squared(&self) -> N::RealField { + let mut res = N::RealField::zero(); for i in 0..self.ncols() { let col = self.column(i); - res += col.dot(&col) + res += col.dotc(&col).real() } res @@ -112,7 +113,7 @@ impl> Matrix { /// /// Use `.apply_norm` to apply a custom norm. #[inline] - pub fn norm(&self) -> N { + pub fn norm(&self) -> N::RealField { self.norm_squared().sqrt() } @@ -120,7 +121,7 @@ impl> Matrix { /// /// Use `.apply_metric_distance` to apply a custom norm. #[inline] - pub fn metric_distance(&self, rhs: &Matrix) -> N + pub fn metric_distance(&self, rhs: &Matrix) -> N::RealField where R2: Dim, C2: Dim, S2: Storage, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { self.apply_metric_distance(rhs, &EuclideanNorm) @@ -139,7 +140,7 @@ impl> Matrix { /// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm()); /// ``` #[inline] - pub fn apply_norm(&self, norm: &impl Norm) -> N { + pub fn apply_norm(&self, norm: &impl Norm) -> N::RealField { norm.norm(self) } @@ -158,16 +159,10 @@ 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 + pub fn apply_metric_distance(&self, rhs: &Matrix, norm: &impl Norm) -> N::RealField where R2: Dim, C2: Dim, S2: Storage, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { - norm.metric_distance(self,rhs) - } - - /// The Lp norm of this matrix. - #[inline] - pub fn lp_norm(&self, p: i32) -> N { - self.apply_norm(&LpNorm(p)) + norm.metric_distance(self, rhs) } /// A synonym for the norm of this matrix. @@ -176,7 +171,7 @@ impl> Matrix { /// /// This function is simply implemented as a call to `norm()` #[inline] - pub fn magnitude(&self) -> N { + pub fn magnitude(&self) -> N::RealField { self.norm() } @@ -186,7 +181,7 @@ impl> Matrix { /// /// This function is simply implemented as a call to `norm_squared()` #[inline] - pub fn magnitude_squared(&self) -> N { + pub fn magnitude_squared(&self) -> N::RealField { self.norm_squared() } @@ -194,29 +189,36 @@ impl> Matrix { #[inline] pub fn normalize(&self) -> MatrixMN where DefaultAllocator: Allocator { - self / self.norm() + self.unscale(self.norm()) } /// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`. #[inline] - pub fn try_normalize(&self, min_norm: N) -> Option> + pub fn try_normalize(&self, min_norm: N::RealField) -> Option> where DefaultAllocator: Allocator { let n = self.norm(); if n <= min_norm { None } else { - Some(self / n) + 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. #[inline] - pub fn normalize_mut(&mut self) -> N { + pub fn normalize_mut(&mut self) -> N::RealField { let n = self.norm(); - *self /= n; + self.unscale_mut(n); n } @@ -225,13 +227,13 @@ impl> Matrix { /// /// If the normalization succeeded, returns the old normal of this matrix. #[inline] - pub fn try_normalize_mut(&mut self, min_norm: N) -> Option { + pub fn try_normalize_mut(&mut self, min_norm: N::RealField) -> Option { let n = self.norm(); if n <= min_norm { None } else { - *self /= n; + self.unscale_mut(n); Some(n) } } diff --git a/src/base/ops.rs b/src/base/ops.rs index 301232f2e..cf921c331 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -5,15 +5,15 @@ use std::ops::{ Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, }; -use alga::general::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; +use alga::general::{ComplexField, ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; -use base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; -use base::constraint::{ +use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; +use crate::base::constraint::{ AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, }; -use base::dimension::{Dim, DimMul, DimName, DimProd, Dynamic}; -use base::storage::{ContiguousStorageMut, Storage, StorageMut}; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, MatrixSum, Scalar}; +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}; /* * @@ -689,13 +689,28 @@ where res } - /// Equivalent to `self.transpose() * rhs` but stores the result into `out` to avoid - /// allocations. + /// Equivalent to `self.adjoint() * rhs`. #[inline] - pub fn tr_mul_to( + pub fn ad_mul(&self, rhs: &Matrix) -> MatrixMN + where + N: ComplexField, + SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = + unsafe { Matrix::new_uninitialized_generic(self.data.shape().1, rhs.data.shape().1) }; + + self.ad_mul_to(rhs, &mut res); + res + } + + #[inline(always)] + fn xx_mul_to( &self, rhs: &Matrix, out: &mut Matrix, + dot: impl Fn(&VectorSliceN, &VectorSliceN) -> N, ) where SB: Storage, SC: StorageMut, @@ -716,12 +731,43 @@ where for i in 0..ncols1 { for j in 0..ncols2 { - let dot = self.column(i).dot(&rhs.column(j)); + let dot = dot(&self.column(i), &rhs.column(j)); unsafe { *out.get_unchecked_mut((i, j)) = dot }; } } } + /// Equivalent to `self.transpose() * rhs` but stores the result into `out` to avoid + /// allocations. + #[inline] + pub fn tr_mul_to( + &self, + rhs: &Matrix, + out: &mut Matrix, + ) where + SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + DimEq + DimEq, + { + self.xx_mul_to(rhs, out, |a, b| a.dot(b)) + } + + /// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid + /// allocations. + #[inline] + pub fn ad_mul_to( + &self, + rhs: &Matrix, + out: &mut Matrix, + ) where + N: ComplexField, + SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + DimEq + DimEq, + { + self.xx_mul_to(rhs, out, |a, b| a.dotc(b)) + } + /// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations. #[inline] pub fn mul_to( @@ -820,16 +866,16 @@ where } } -impl> Matrix { - /// Returns the absolute value of the component with the largest absolute value. - #[inline] - pub fn amax(&self) -> N { - let mut max = N::zero(); +impl> Matrix { + #[inline(always)] + fn xcmp(&self, abs: impl Fn(N) -> N2, cmp: impl Fn(N2, N2) -> bool) -> N2 + where N2: Scalar + PartialOrd + Zero { + let mut max = N2::zero(); for e in self.iter() { - let ae = e.abs(); + let ae = abs(*e); - if ae > max { + if cmp(ae, max) { max = ae; } } @@ -837,61 +883,45 @@ impl> Matri max } - /// Returns the absolute value of the component with the smallest absolute value. + /// Returns the absolute value of the component with the largest absolute value. #[inline] - pub fn amin(&self) -> N { - let mut it = self.iter(); - let mut min = it - .next() - .expect("amin: empty matrices not supported.") - .abs(); - - for e in it { - let ae = e.abs(); - - if ae < min { - min = ae; - } - } + pub fn amax(&self) -> N + where N: PartialOrd + Signed { + self.xcmp(|e| e.abs(), |a, b| a > b) + } - min + /// Returns the the 1-norm of the complex component with the largest 1-norm. + #[inline] + pub fn camax(&self) -> N::RealField + where N: ComplexField { + self.xcmp(|e| e.norm1(), |a, b| a > b) } /// Returns the component with the largest value. #[inline] - pub fn max(&self) -> N { - let mut it = self.iter(); - let mut max = it - .next() - .expect("max: empty matrices not supported."); - - for e in it { - let ae = e; + pub fn max(&self) -> N + where N: PartialOrd + Signed { + self.xcmp(|e| e, |a, b| a > b) + } - if ae > max { - max = ae; - } - } + /// Returns the absolute value of the component with the smallest absolute value. + #[inline] + pub fn amin(&self) -> N + where N: PartialOrd + Signed { + self.xcmp(|e| e.abs(), |a, b| a < b) + } - *max + /// Returns the the 1-norm of the complex component with the smallest 1-norm. + #[inline] + pub fn camin(&self) -> N::RealField + where N: ComplexField { + self.xcmp(|e| e.norm1(), |a, b| a < b) } /// Returns the component with the smallest value. #[inline] - pub fn min(&self) -> N { - let mut it = self.iter(); - let mut min = it - .next() - .expect("min: empty matrices not supported."); - - for e in it { - let ae = e; - - if ae < min { - min = ae; - } - } - - *min + pub fn min(&self) -> N + where N: PartialOrd + Signed { + self.xcmp(|e| e, |a, b| a < b) } -} +} \ No newline at end of file diff --git a/src/base/properties.rs b/src/base/properties.rs index 7e5015758..8ca495688 100644 --- a/src/base/properties.rs +++ b/src/base/properties.rs @@ -2,12 +2,12 @@ use approx::RelativeEq; use num::{One, Zero}; -use alga::general::{ClosedAdd, ClosedMul, Real}; +use alga::general::{ClosedAdd, ClosedMul, RealField, ComplexField}; -use base::allocator::Allocator; -use base::dimension::{Dim, DimMin}; -use base::storage::Storage; -use base::{DefaultAllocator, Matrix, Scalar, SquareMatrix}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, DimMin}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, Matrix, Scalar, SquareMatrix}; impl> Matrix { /// Indicates if this is an empty matrix. @@ -82,24 +82,26 @@ impl> Matrix { true } +} +impl> Matrix { /// Checks that `Mᵀ × M = Id`. /// /// In this definition `Id` is approximately equal to the identity matrix with a relative error /// 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, + where + N: Zero + One + ClosedAdd + ClosedMul + RelativeEq, + S: Storage, + N::Epsilon: Copy, + DefaultAllocator: Allocator + Allocator, { - (self.tr_mul(self)).is_identity(eps) + (self.ad_mul(self)).is_identity(eps) } } -impl> SquareMatrix +impl> SquareMatrix where DefaultAllocator: Allocator { /// Checks that this matrix is orthogonal and has a determinant equal to 1. diff --git a/src/base/statistics.rs b/src/base/statistics.rs index 11cc9e1c4..0fe181308 100644 --- a/src/base/statistics.rs +++ b/src/base/statistics.rs @@ -1,8 +1,9 @@ -use ::{Real, Dim, Matrix, VectorN, RowVectorN, DefaultAllocator, U1, VectorSliceN}; -use storage::Storage; -use allocator::Allocator; +use crate::{Scalar, Dim, Matrix, VectorN, RowVectorN, DefaultAllocator, U1, VectorSliceN}; +use alga::general::{Field, SupersetOf}; +use crate::storage::Storage; +use crate::allocator::Allocator; -impl> Matrix { +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] @@ -53,7 +54,7 @@ impl> Matrix { } } -impl> Matrix { +impl, R: Dim, C: Dim, S: Storage> Matrix { /* * * Sum computation. @@ -154,7 +155,7 @@ impl> Matrix { N::zero() } else { let val = self.iter().cloned().fold((N::zero(), N::zero()), |a, b| (a.0 + b * b, a.1 + b)); - let denom = N::one() / ::convert::<_, N>(self.len() as f64); + let denom = N::one() / crate::convert::<_, N>(self.len() as f64); val.0 * denom - (val.1 * denom) * (val.1 * denom) } } @@ -214,7 +215,7 @@ impl> Matrix { let mut mean = self.column_mean(); mean.apply(|e| -(e * e)); - let denom = N::one() / ::convert::<_, N>(ncols.value() as f64); + let denom = N::one() / crate::convert::<_, N>(ncols.value() as f64); self.compress_columns(mean, |out, col| { for i in 0..nrows.value() { unsafe { @@ -246,7 +247,7 @@ impl> Matrix { if self.len() == 0 { N::zero() } else { - self.sum() / ::convert(self.len() as f64) + self.sum() / crate::convert(self.len() as f64) } } @@ -301,7 +302,7 @@ impl> Matrix { pub fn column_mean(&self) -> VectorN where DefaultAllocator: Allocator { let (nrows, ncols) = self.data.shape(); - let denom = N::one() / ::convert::<_, N>(ncols.value() as f64); + let denom = N::one() / crate::convert::<_, N>(ncols.value() as f64); self.compress_columns(VectorN::zeros_generic(nrows, U1), |out, col| { out.axpy(denom, &col, N::one()) }) diff --git a/src/base/storage.rs b/src/base/storage.rs index 0a07713b2..02941e478 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -3,10 +3,10 @@ use std::fmt::Debug; use std::mem; -use base::allocator::{Allocator, SameShapeC, SameShapeR}; -use base::default_allocator::DefaultAllocator; -use base::dimension::{Dim, U1}; -use base::Scalar; +use crate::base::allocator::{Allocator, SameShapeC, SameShapeR}; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Dim, U1}; +use crate::base::Scalar; /* * Aliases for allocation results. diff --git a/src/base/swizzle.rs b/src/base/swizzle.rs index b09316d49..4c9b0b63b 100644 --- a/src/base/swizzle.rs +++ b/src/base/swizzle.rs @@ -1,5 +1,5 @@ -use base::{DimName, Scalar, Vector, Vector2, Vector3}; -use storage::Storage; +use crate::base::{DimName, Scalar, Vector, Vector2, Vector3}; +use crate::storage::Storage; use typenum::{self, Cmp, Greater}; macro_rules! impl_swizzle { diff --git a/src/base/unit.rs b/src/base/unit.rs index 20f159560..6fe831da1 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -10,11 +10,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::SubsetOf; +use alga::general::{SubsetOf, ComplexField}; use alga::linear::NormedSpace; -use ::Real; - /// A wrapper that ensures the underlying algebraic entity has a unit norm. /// /// Use `.as_ref()` or `.into_inner()` to obtain the underlying value by-reference or by-move. @@ -66,13 +64,13 @@ impl Unit { /// /// Returns `None` if the norm was smaller or equal to `min_norm`. #[inline] - pub fn try_new(value: T, min_norm: T::Field) -> Option { + pub fn try_new(value: T, min_norm: T::RealField) -> Option { 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. #[inline] - pub fn new_and_get(mut value: T) -> (Self, T::Field) { + pub fn new_and_get(mut value: T) -> (Self, T::RealField) { let n = value.normalize_mut(); (Unit { value: value }, n) @@ -82,7 +80,7 @@ impl Unit { /// /// 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::Field) -> Option<(Self, T::Field)> { + 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)) } else { @@ -96,7 +94,7 @@ impl Unit { /// 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::Field { + pub fn renormalize(&mut self) -> T::RealField { self.value.normalize_mut() } @@ -104,12 +102,11 @@ impl Unit { /// This is useful when repeated computations might cause a drift in the norm /// because of float inaccuracies. #[inline] - pub fn renormalize_fast(&mut self) - where T::Field: Real { + pub fn renormalize_fast(&mut self) { let sq_norm = self.value.norm_squared(); - let _3: T::Field = ::convert(3.0); - let _0_5: T::Field = ::convert(0.5); - self.value *= _0_5 * (_3 - sq_norm); + 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)); } } @@ -171,7 +168,7 @@ where T::Field: RelativeEq #[inline] fn is_in_subset(value: &T) -> bool { - relative_eq!(value.norm_squared(), ::one()) + relative_eq!(value.norm_squared(), crate::one()) } #[inline] diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index afde36775..2b4bf7432 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -4,12 +4,12 @@ use std::io::{Result as IOResult, Write}; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; -use base::allocator::Allocator; -use base::default_allocator::DefaultAllocator; -use base::dimension::{Dim, DimName, Dynamic, U1}; -use base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut}; -use base::{Scalar, Vector}; -use base::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::base::allocator::Allocator; +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; diff --git a/src/debug/random_orthogonal.rs b/src/debug/random_orthogonal.rs index 6d393a24d..421b041a6 100644 --- a/src/debug/random_orthogonal.rs +++ b/src/debug/random_orthogonal.rs @@ -1,24 +1,24 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; -use alga::general::Real; -use base::allocator::Allocator; -use base::dimension::{Dim, Dynamic, U2}; -use base::{DefaultAllocator, MatrixN}; -use geometry::UnitComplex; -use num_complex::Complex; +use alga::general::ComplexField; +use crate::base::Scalar; +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, Dynamic, U2}; +use crate::base::{DefaultAllocator, MatrixN}; +use crate::linalg::givens::GivensRotation; /// A random orthogonal matrix. #[derive(Clone, Debug)] -pub struct RandomOrthogonal +pub struct RandomOrthogonal where DefaultAllocator: Allocator { m: MatrixN, } -impl RandomOrthogonal +impl RandomOrthogonal where DefaultAllocator: Allocator { /// Retrieve the generated matrix. @@ -30,10 +30,9 @@ where DefaultAllocator: Allocator pub fn new N>(dim: D, mut rand: Rand) -> Self { let mut res = MatrixN::identity_generic(dim, dim); - // Create an orthogonal matrix by compositing planar 2D rotations. + // Create an orthogonal matrix by composing random Givens rotations rotations. for i in 0..dim.value() - 1 { - let c = Complex::new(rand(), rand()); - let rot: UnitComplex = UnitComplex::from_complex(c); + let rot = GivensRotation::new(rand(), rand()).0; rot.rotate(&mut res.fixed_rows_mut::(i)); } @@ -42,7 +41,7 @@ where DefaultAllocator: Allocator } #[cfg(feature = "arbitrary")] -impl Arbitrary for RandomOrthogonal +impl Arbitrary for RandomOrthogonal where DefaultAllocator: Allocator, Owned: Clone + Send, diff --git a/src/debug/random_sdp.rs b/src/debug/random_sdp.rs index 7835c775b..47e3ca601 100644 --- a/src/debug/random_sdp.rs +++ b/src/debug/random_sdp.rs @@ -1,24 +1,25 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; -use alga::general::Real; -use base::allocator::Allocator; -use base::dimension::{Dim, Dynamic}; -use base::{DefaultAllocator, MatrixN}; +use alga::general::ComplexField; +use crate::base::Scalar; +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, Dynamic}; +use crate::base::{DefaultAllocator, MatrixN}; -use debug::RandomOrthogonal; +use crate::debug::RandomOrthogonal; /// A random, well-conditioned, symmetric definite-positive matrix. #[derive(Clone, Debug)] -pub struct RandomSDP +pub struct RandomSDP where DefaultAllocator: Allocator { m: MatrixN, } -impl RandomSDP +impl RandomSDP where DefaultAllocator: Allocator { /// Retrieve the generated matrix. @@ -30,11 +31,11 @@ where DefaultAllocator: Allocator /// random reals generators. pub fn new N>(dim: D, mut rand: Rand) -> Self { let mut m = RandomOrthogonal::new(dim, || rand()).unwrap(); - let mt = m.transpose(); + let mt = m.adjoint(); for i in 0..dim.value() { let mut col = m.column_mut(i); - let eigenval = N::one() + rand().abs(); + let eigenval = N::one() + N::from_real(rand().modulus()); col *= eigenval; } @@ -43,7 +44,7 @@ where DefaultAllocator: Allocator } #[cfg(feature = "arbitrary")] -impl Arbitrary for RandomSDP +impl Arbitrary for RandomSDP where DefaultAllocator: Allocator, Owned: Clone + Send, diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 1ffbbe3ad..888a8307c 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -11,14 +11,14 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{Real, SubsetOf}; +use alga::general::{RealField, SubsetOf}; use alga::linear::Rotation; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::storage::Owned; -use base::{DefaultAllocator, MatrixN, VectorN}; -use geometry::{Point, Translation}; +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}; /// 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,7 +36,7 @@ use geometry::{Point, Translation}; DefaultAllocator: Allocator, Owned: Deserialize<'de>")) )] -pub struct Isometry +pub struct Isometry where DefaultAllocator: Allocator { /// The pure rotational part of this isometry. @@ -55,7 +55,7 @@ where DefaultAllocator: Allocator #[cfg(feature = "abomonation-serialize")] impl Abomonation for Isometry where - N: Real, + N: RealField, D: DimName, R: Abomonation, Translation: Abomonation, @@ -77,7 +77,7 @@ where } } -impl hash::Hash for Isometry +impl hash::Hash for Isometry where DefaultAllocator: Allocator, Owned: hash::Hash, @@ -88,14 +88,14 @@ where } } -impl> + Copy> Copy for Isometry +impl> + Copy> Copy for Isometry where DefaultAllocator: Allocator, Owned: Copy, { } -impl> + Clone> Clone for Isometry +impl> + Clone> Clone for Isometry where DefaultAllocator: Allocator { #[inline] @@ -104,7 +104,7 @@ where DefaultAllocator: Allocator } } -impl>> Isometry +impl>> Isometry where DefaultAllocator: Allocator { /// Creates a new isometry from its rotational and translational parts. @@ -351,7 +351,7 @@ 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 +impl Isometry where DefaultAllocator: Allocator { /// Converts this isometry into its equivalent homogeneous transformation matrix. @@ -376,7 +376,7 @@ where DefaultAllocator: Allocator R: SubsetOf>>, DefaultAllocator: Allocator, DimNameSum>, { - let mut res: MatrixN = ::convert_ref(&self.rotation); + let mut res: MatrixN = crate::convert_ref(&self.rotation); res.fixed_slice_mut::(0, D::dim()) .copy_from(&self.translation.vector); @@ -384,14 +384,14 @@ where DefaultAllocator: Allocator } } -impl Eq for Isometry +impl Eq for Isometry where R: Rotation> + Eq, DefaultAllocator: Allocator, { } -impl PartialEq for Isometry +impl PartialEq for Isometry where R: Rotation> + PartialEq, DefaultAllocator: Allocator, @@ -402,7 +402,7 @@ where } } -impl AbsDiffEq for Isometry +impl AbsDiffEq for Isometry where R: Rotation> + AbsDiffEq, DefaultAllocator: Allocator, @@ -422,7 +422,7 @@ where } } -impl RelativeEq for Isometry +impl RelativeEq for Isometry where R: Rotation> + RelativeEq, DefaultAllocator: Allocator, @@ -449,7 +449,7 @@ where } } -impl UlpsEq for Isometry +impl UlpsEq for Isometry where R: Rotation> + UlpsEq, DefaultAllocator: Allocator, @@ -473,7 +473,7 @@ where * Display * */ -impl fmt::Display for Isometry +impl fmt::Display for Isometry where R: fmt::Display, DefaultAllocator: Allocator + Allocator, @@ -481,9 +481,9 @@ where fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "Isometry {{")); - try!(write!(f, "{:.*}", precision, self.translation)); - try!(write!(f, "{:.*}", precision, self.rotation)); + writeln!(f, "Isometry {{")?; + write!(f, "{:.*}", precision, self.translation)?; + write!(f, "{:.*}", precision, self.rotation)?; writeln!(f, "}}") } } diff --git a/src/geometry/isometry_alga.rs b/src/geometry/isometry_alga.rs index 5a4f749cc..e68b269c2 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, Real, + AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, }; use alga::linear::Isometry as AlgaIsometry; use alga::linear::{ @@ -8,18 +8,18 @@ use alga::linear::{ Transformation, }; -use base::allocator::Allocator; -use base::dimension::DimName; -use base::{DefaultAllocator, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, VectorN}; -use geometry::{Isometry, Point, Translation}; +use crate::geometry::{Isometry, Point, Translation}; /* * * Algebraic structures. * */ -impl Identity for Isometry +impl Identity for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -30,7 +30,7 @@ where } } -impl TwoSidedInverse for Isometry +impl TwoSidedInverse for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -46,7 +46,7 @@ where } } -impl AbstractMagma for Isometry +impl AbstractMagma for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -59,7 +59,7 @@ where macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for Isometry + impl $marker<$operator> for Isometry where R: Rotation>, DefaultAllocator: Allocator { } )*} @@ -78,7 +78,7 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Isometry +impl Transformation> for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -94,7 +94,7 @@ where } } -impl ProjectiveTransformation> for Isometry +impl ProjectiveTransformation> for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -110,7 +110,7 @@ where } } -impl AffineTransformation> for Isometry +impl AffineTransformation> for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -168,7 +168,7 @@ where } } -impl Similarity> for Isometry +impl Similarity> for Isometry where R: Rotation>, DefaultAllocator: Allocator, @@ -193,7 +193,7 @@ where macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for Isometry + impl $Trait> for Isometry where R: Rotation>, DefaultAllocator: Allocator { } )*} diff --git a/src/geometry/isometry_alias.rs b/src/geometry/isometry_alias.rs index a0804b5c5..ba9a69e7d 100644 --- a/src/geometry/isometry_alias.rs +++ b/src/geometry/isometry_alias.rs @@ -1,6 +1,6 @@ -use base::dimension::{U2, U3}; +use crate::base::dimension::{U2, U3}; -use geometry::{Isometry, Rotation2, Rotation3, UnitComplex, UnitQuaternion}; +use crate::geometry::{Isometry, Rotation2, Rotation3, UnitComplex, UnitQuaternion}; /// A 2-dimensional direct isometry using a unit complex number for its rotational part. Also known as a rigid-body motion, or as an element of SE(2). pub type Isometry2 = Isometry>; diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index 5a402c0a2..979c39556 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -1,5 +1,5 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -7,19 +7,19 @@ use num::One; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use alga::general::Real; +use alga::general::RealField; use alga::linear::Rotation as AlgaRotation; -use base::allocator::Allocator; -use base::dimension::{DimName, U2, U3}; -use base::{DefaultAllocator, Vector2, Vector3}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, U2, U3}; +use crate::base::{DefaultAllocator, Vector2, Vector3}; -use geometry::{ +use crate::geometry::{ Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation, UnitComplex, UnitQuaternion, Translation2, Translation3 }; -impl>> Isometry +impl>> Isometry where DefaultAllocator: Allocator { /// Creates a new identity isometry. @@ -65,7 +65,7 @@ where DefaultAllocator: Allocator } } -impl>> One for Isometry +impl>> One for Isometry where DefaultAllocator: Allocator { /// Creates a new identity isometry. @@ -75,7 +75,7 @@ where DefaultAllocator: Allocator } } -impl Distribution> for Standard +impl Distribution> for Standard where R: AlgaRotation>, Standard: Distribution + Distribution, @@ -90,7 +90,7 @@ where #[cfg(feature = "arbitrary")] impl Arbitrary for Isometry where - N: Real + Arbitrary + Send, + N: RealField + Arbitrary + Send, R: AlgaRotation> + Arbitrary + Send, Owned: Send, DefaultAllocator: Allocator, @@ -108,7 +108,7 @@ where */ // 2D rotation. -impl Isometry> { +impl Isometry> { /// Creates a new 2D isometry from a translation and a rotation angle. /// /// Its rotational part is represented as a 2x2 rotation matrix. @@ -143,7 +143,7 @@ impl Isometry> { } } -impl Isometry> { +impl Isometry> { /// Creates a new 2D isometry from a translation and a rotation angle. /// /// Its rotational part is represented as an unit complex number. @@ -181,7 +181,7 @@ impl Isometry> { // 3D rotation. macro_rules! isometry_construction_impl( ($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => { - impl Isometry> { + impl Isometry> { /// 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 5dc460094..4a794f55e 100644 --- a/src/geometry/isometry_conversion.rs +++ b/src/geometry/isometry_conversion.rs @@ -1,11 +1,11 @@ -use alga::general::{Real, SubsetOf, SupersetOf}; +use alga::general::{RealField, SubsetOf, SupersetOf}; use alga::linear::Rotation; -use base::allocator::Allocator; -use base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN}; -use geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; +use crate::geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; /* * This file provides the following conversions: @@ -19,8 +19,8 @@ use geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform impl SubsetOf> for Isometry where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R1: Rotation> + SubsetOf, R2: Rotation>, DefaultAllocator: Allocator + Allocator, @@ -32,8 +32,8 @@ where #[inline] fn is_in_subset(iso: &Isometry) -> bool { - ::is_convertible::<_, Translation>(&iso.translation) - && ::is_convertible::<_, R1>(&iso.rotation) + crate::is_convertible::<_, Translation>(&iso.translation) + && crate::is_convertible::<_, R1>(&iso.rotation) } #[inline] @@ -47,8 +47,8 @@ where impl SubsetOf> for Isometry where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R1: Rotation> + SubsetOf, R2: Rotation>, DefaultAllocator: Allocator + Allocator, @@ -60,19 +60,19 @@ where #[inline] fn is_in_subset(sim: &Similarity) -> bool { - ::is_convertible::<_, Isometry>(&sim.isometry) && sim.scaling() == N2::one() + crate::is_convertible::<_, Isometry>(&sim.isometry) && sim.scaling() == N2::one() } #[inline] unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { - ::convert_ref_unchecked(&sim.isometry) + crate::convert_ref_unchecked(&sim.isometry) } } impl SubsetOf> for Isometry where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, C: SuperTCategoryOf, R: Rotation> + SubsetOf>> @@ -105,8 +105,8 @@ where impl SubsetOf>> for Isometry where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: Rotation> + SubsetOf>> + SubsetOf>>, @@ -133,7 +133,7 @@ where // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && // The block part is a rotation. - rot.is_special_orthogonal(N2::default_epsilon() * ::convert(100.0)) && + rot.is_special_orthogonal(N2::default_epsilon() * crate::convert(100.0)) && // The bottom row is (0, 0, ..., 1) bottom.iter().all(|e| e.is_zero()) && m[(D::dim(), D::dim())] == N2::one() } @@ -142,14 +142,14 @@ where unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let t = m.fixed_slice::(0, D::dim()).into_owned(); let t = Translation { - vector: ::convert_unchecked(t), + vector: crate::convert_unchecked(t), }; - Self::from_parts(t, ::convert_unchecked(m.clone_owned())) + Self::from_parts(t, crate::convert_unchecked(m.clone_owned())) } } -impl From> for MatrixN> +impl From> for MatrixN> where D: DimNameAdd, R: SubsetOf>>, diff --git a/src/geometry/isometry_ops.rs b/src/geometry/isometry_ops.rs index 6a4b921ea..6ba9eb3ef 100644 --- a/src/geometry/isometry_ops.rs +++ b/src/geometry/isometry_ops.rs @@ -1,13 +1,13 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::Real; +use alga::general::RealField; use alga::linear::Rotation as AlgaRotation; -use base::allocator::Allocator; -use base::dimension::{DimName, U1, U3, U4}; -use base::{DefaultAllocator, Unit, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, U1, U3, U4}; +use crate::base::{DefaultAllocator, Unit, VectorN}; -use geometry::{Isometry, Point, Rotation, Translation, UnitQuaternion}; +use crate::geometry::{Isometry, Point, Rotation, Translation, 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,7 +64,7 @@ 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: Real, D: DimName, R> $Op<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField, D: DimName, R> $Op<$Rhs> for $Lhs where R: AlgaRotation>, DefaultAllocator: Allocator { type Output = $Output; @@ -111,7 +111,7 @@ 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 + impl $OpAssign<$Rhs> for $Lhs where R: AlgaRotation>, DefaultAllocator: Allocator { #[inline] @@ -120,7 +120,7 @@ macro_rules! isometry_binop_assign_impl_all( } } - impl<'b, N: Real, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs + impl<'b, N: RealField, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs where R: AlgaRotation>, DefaultAllocator: Allocator { #[inline] @@ -286,7 +286,7 @@ 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: Real $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs where DefaultAllocator: Allocator + Allocator { type Output = $Output; diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index 3117c1b62..2c7131182 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -7,36 +7,36 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::mem; -use alga::general::Real; +use alga::general::RealField; -use base::dimension::U3; -use base::helper; -use base::storage::Storage; -use base::{Matrix4, Vector, Vector3}; +use crate::base::dimension::U3; +use crate::base::helper; +use crate::base::storage::Storage; +use crate::base::{Matrix4, Vector, Vector3}; -use geometry::{Point3, Projective3}; +use crate::geometry::{Point3, Projective3}; /// A 3D orthographic projection stored as an homogeneous 4x4 matrix. -pub struct Orthographic3 { +pub struct Orthographic3 { matrix: Matrix4, } -impl Copy for Orthographic3 {} +impl Copy for Orthographic3 {} -impl Clone for Orthographic3 { +impl Clone for Orthographic3 { #[inline] fn clone(&self) -> Self { Self::from_matrix_unchecked(self.matrix.clone()) } } -impl fmt::Debug for Orthographic3 { +impl fmt::Debug for Orthographic3 { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.matrix.fmt(f) } } -impl PartialEq for Orthographic3 { +impl PartialEq for Orthographic3 { #[inline] fn eq(&self, right: &Self) -> bool { self.matrix == right.matrix @@ -44,7 +44,7 @@ impl PartialEq for Orthographic3 { } #[cfg(feature = "serde-serialize")] -impl Serialize for Orthographic3 { +impl Serialize for Orthographic3 { fn serialize(&self, serializer: S) -> Result where S: Serializer { self.matrix.serialize(serializer) @@ -52,7 +52,7 @@ impl Serialize for Orthographic3 { } #[cfg(feature = "serde-serialize")] -impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Orthographic3 { +impl<'a, N: RealField + Deserialize<'a>> Deserialize<'a> for Orthographic3 { fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a> { let matrix = Matrix4::::deserialize(deserializer)?; @@ -61,7 +61,7 @@ impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Orthographic3 { } } -impl Orthographic3 { +impl Orthographic3 { /// Creates a new orthographic projection matrix. /// /// This follows the OpenGL convention, so this will flip the `z` axis. @@ -150,7 +150,7 @@ impl Orthographic3 { "The apsect ratio must not be zero." ); - let half: N = ::convert(0.5); + let half: N = crate::convert(0.5); let width = zfar * (vfov * half).tan(); let height = width / aspect; @@ -623,7 +623,7 @@ impl Orthographic3 { left != right, "The left corner must not be equal to the right corner." ); - self.matrix[(0, 0)] = ::convert::<_, N>(2.0) / (right - left); + self.matrix[(0, 0)] = crate::convert::<_, N>(2.0) / (right - left); self.matrix[(0, 3)] = -(right + left) / (right - left); } @@ -648,7 +648,7 @@ impl Orthographic3 { bottom != top, "The top corner must not be equal to the bottom corner." ); - self.matrix[(1, 1)] = ::convert::<_, N>(2.0) / (top - bottom); + self.matrix[(1, 1)] = crate::convert::<_, N>(2.0) / (top - bottom); self.matrix[(1, 3)] = -(top + bottom) / (top - bottom); } @@ -673,12 +673,12 @@ impl Orthographic3 { zfar != znear, "The near-plane and far-plane must not be superimposed." ); - self.matrix[(2, 2)] = -::convert::<_, N>(2.0) / (zfar - znear); + self.matrix[(2, 2)] = -crate::convert::<_, N>(2.0) / (zfar - znear); self.matrix[(2, 3)] = -(zfar + znear) / (zfar - znear); } } -impl Distribution> for Standard +impl Distribution> for Standard where Standard: Distribution { fn sample(&self, r: &mut R) -> Orthographic3 { @@ -694,7 +694,7 @@ where Standard: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Orthographic3 +impl Arbitrary for Orthographic3 where Matrix4: Send { fn arbitrary(g: &mut G) -> Self { @@ -709,7 +709,7 @@ where Matrix4: Send } } -impl From> for Matrix4 { +impl From> for Matrix4 { #[inline] fn from(orth: Orthographic3) -> Self { orth.into_inner() diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index 550469be1..8020c0cf5 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -8,36 +8,36 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::fmt; use std::mem; -use alga::general::Real; +use alga::general::RealField; -use base::dimension::U3; -use base::helper; -use base::storage::Storage; -use base::{Matrix4, Scalar, Vector, Vector3}; +use crate::base::dimension::U3; +use crate::base::helper; +use crate::base::storage::Storage; +use crate::base::{Matrix4, Scalar, Vector, Vector3}; -use geometry::{Point3, Projective3}; +use crate::geometry::{Point3, Projective3}; /// A 3D perspective projection stored as an homogeneous 4x4 matrix. pub struct Perspective3 { matrix: Matrix4, } -impl Copy for Perspective3 {} +impl Copy for Perspective3 {} -impl Clone for Perspective3 { +impl Clone for Perspective3 { #[inline] fn clone(&self) -> Self { Self::from_matrix_unchecked(self.matrix.clone()) } } -impl fmt::Debug for Perspective3 { +impl fmt::Debug for Perspective3 { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.matrix.fmt(f) } } -impl PartialEq for Perspective3 { +impl PartialEq for Perspective3 { #[inline] fn eq(&self, right: &Self) -> bool { self.matrix == right.matrix @@ -45,7 +45,7 @@ impl PartialEq for Perspective3 { } #[cfg(feature = "serde-serialize")] -impl Serialize for Perspective3 { +impl Serialize for Perspective3 { fn serialize(&self, serializer: S) -> Result where S: Serializer { self.matrix.serialize(serializer) @@ -53,7 +53,7 @@ impl Serialize for Perspective3 { } #[cfg(feature = "serde-serialize")] -impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Perspective3 { +impl<'a, N: RealField + Deserialize<'a>> Deserialize<'a> for Perspective3 { fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a> { let matrix = Matrix4::::deserialize(deserializer)?; @@ -62,7 +62,7 @@ impl<'a, N: Real + Deserialize<'a>> Deserialize<'a> for Perspective3 { } } -impl Perspective3 { +impl Perspective3 { /// Creates a new perspective matrix from the aspect ratio, y field of view, and near/far planes. pub fn new(aspect: N, fovy: N, znear: N, zfar: N) -> Self { assert!( @@ -162,7 +162,7 @@ impl Perspective3 { /// Gets the y field of view of the view frustum. #[inline] pub fn fovy(&self) -> N { - (N::one() / self.matrix[(1, 1)]).atan() * ::convert(2.0) + (N::one() / self.matrix[(1, 1)]).atan() * crate::convert(2.0) } /// Gets the near plane offset of the view frustum. @@ -170,7 +170,7 @@ 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 * ::convert(2.0)) - self.matrix[(2, 3)] / ::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. @@ -178,7 +178,7 @@ impl Perspective3 { pub fn zfar(&self) -> N { let ratio = (-self.matrix[(2, 2)] + N::one()) / (-self.matrix[(2, 2)] - N::one()); - (self.matrix[(2, 3)] - ratio * self.matrix[(2, 3)]) / ::convert(2.0) + (self.matrix[(2, 3)] - ratio * self.matrix[(2, 3)]) / crate::convert(2.0) } // FIXME: add a method to retrieve znear and zfar simultaneously? @@ -235,7 +235,7 @@ impl Perspective3 { #[inline] pub fn set_fovy(&mut self, fovy: N) { let old_m22 = self.matrix[(1, 1)]; - self.matrix[(1, 1)] = N::one() / (fovy / ::convert(2.0)).tan(); + self.matrix[(1, 1)] = N::one() / (fovy / crate::convert(2.0)).tan(); self.matrix[(0, 0)] = self.matrix[(0, 0)] * (self.matrix[(1, 1)] / old_m22); } @@ -257,11 +257,11 @@ impl Perspective3 { #[inline] pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) { self.matrix[(2, 2)] = (zfar + znear) / (znear - zfar); - self.matrix[(2, 3)] = zfar * znear * ::convert(2.0) / (znear - zfar); + self.matrix[(2, 3)] = zfar * znear * crate::convert(2.0) / (znear - zfar); } } -impl Distribution> for Standard +impl Distribution> for Standard where Standard: Distribution { fn sample<'a, R: Rng + ?Sized>(&self, r: &'a mut R) -> Perspective3 { @@ -274,7 +274,7 @@ where Standard: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Perspective3 { +impl Arbitrary for Perspective3 { fn arbitrary(g: &mut G) -> Self { let znear = Arbitrary::arbitrary(g); let zfar = helper::reject(g, |&x: &N| !(x - znear).is_zero()); @@ -284,7 +284,7 @@ impl Arbitrary for Perspective3 { } } -impl From> for Matrix4 { +impl From> for Matrix4 { #[inline] fn from(orth: Perspective3) -> Self { orth.into_inner() diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 14ce7dc28..04338d2aa 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -12,10 +12,10 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::iter::{MatrixIter, MatrixIterMut}; -use base::{DefaultAllocator, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::iter::{MatrixIter, MatrixIterMut}; +use crate::base::{DefaultAllocator, Scalar, VectorN}; /// A point in a n-dimensional euclidean space. #[repr(C)] @@ -316,14 +316,14 @@ impl fmt::Display for Point where DefaultAllocator: Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{{")); + write!(f, "{{")?; let mut it = self.coords.iter(); - try!(write!(f, "{}", *it.next().unwrap())); + write!(f, "{}", *it.next().unwrap())?; for comp in it { - try!(write!(f, ", {}", *comp)); + write!(f, ", {}", *comp)?; } write!(f, "}}") diff --git a/src/geometry/point_alga.rs b/src/geometry/point_alga.rs index 2f81ceff8..162e6c68b 100644 --- a/src/geometry/point_alga.rs +++ b/src/geometry/point_alga.rs @@ -1,11 +1,11 @@ -use alga::general::{Field, JoinSemilattice, Lattice, MeetSemilattice, Real}; +use alga::general::{Field, JoinSemilattice, Lattice, MeetSemilattice, RealField}; use alga::linear::{AffineSpace, EuclideanSpace}; -use base::allocator::Allocator; -use base::dimension::DimName; -use base::{DefaultAllocator, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, Scalar, VectorN}; -use geometry::Point; +use crate::geometry::Point; impl AffineSpace for Point where @@ -15,11 +15,11 @@ where type Translation = VectorN; } -impl EuclideanSpace for Point +impl EuclideanSpace for Point where DefaultAllocator: Allocator { type Coordinates = VectorN; - type Real = N; + type RealField = N; #[inline] fn origin() -> Self { diff --git a/src/geometry/point_alias.rs b/src/geometry/point_alias.rs index 42086d043..83f57301b 100644 --- a/src/geometry/point_alias.rs +++ b/src/geometry/point_alias.rs @@ -1,6 +1,6 @@ -use base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; -use geometry::Point; +use crate::geometry::Point; /// A statically sized 1-dimensional column point. pub type Point1 = Point; diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index b6c46779f..2fac11d42 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -6,11 +6,11 @@ use rand::distributions::{Distribution, Standard}; use rand::Rng; use alga::general::ClosedDiv; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3, U4, U5, U6}; -use base::{DefaultAllocator, Scalar, VectorN}; +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 geometry::Point; +use crate::geometry::Point; impl Point where DefaultAllocator: Allocator @@ -28,7 +28,7 @@ where DefaultAllocator: Allocator /// ``` /// # use nalgebra::{Point2, Point3}; /// // This works in any dimension. - /// // The explicit :: type annotation may not always be needed, + /// // The explicit crate:: type annotation may not always be needed, /// // depending on the context of type inference. /// let pt = Point2::::origin(); /// assert!(pt.x == 0.0 && pt.y == 0.0); diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index 50a3a4d2e..104381650 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -1,15 +1,15 @@ use alga::general::{ClosedDiv, SubsetOf, SupersetOf}; use num::{One, Zero}; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, Matrix, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, Matrix, Scalar, VectorN}; #[cfg(feature = "mint")] -use base::dimension::{U2, U3}; +use crate::base::dimension::{U2, U3}; #[cfg(feature = "mint")] -use base::storage::{Storage, StorageMut}; -use geometry::Point; +use crate::base::storage::{Storage, StorageMut}; +use crate::geometry::Point; #[cfg(feature = "mint")] use mint; #[cfg(feature = "mint")] @@ -67,14 +67,14 @@ where #[inline] fn is_in_subset(v: &VectorN>) -> bool { - ::is_convertible::<_, VectorN>>(v) && !v[D::dim()].is_zero() + crate::is_convertible::<_, VectorN>>(v) && !v[D::dim()].is_zero() } #[inline] unsafe fn from_superset_unchecked(v: &VectorN>) -> Self { let coords = v.fixed_slice::(0, 0) / v[D::dim()]; Self { - coords: ::convert_unchecked(coords) + coords: crate::convert_unchecked(coords) } } } diff --git a/src/geometry/point_coordinates.rs b/src/geometry/point_coordinates.rs index b24ec052f..b56e120ed 100644 --- a/src/geometry/point_coordinates.rs +++ b/src/geometry/point_coordinates.rs @@ -1,12 +1,12 @@ use std::mem; use std::ops::{Deref, DerefMut}; -use base::allocator::Allocator; -use base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; -use base::dimension::{U1, U2, U3, U4, U5, U6}; -use base::{DefaultAllocator, Scalar}; +use crate::base::allocator::Allocator; +use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::{DefaultAllocator, Scalar}; -use geometry::Point; +use crate::geometry::Point; /* * diff --git a/src/geometry/point_ops.rs b/src/geometry/point_ops.rs index 0a20bc90c..b49495f8b 100644 --- a/src/geometry/point_ops.rs +++ b/src/geometry/point_ops.rs @@ -5,13 +5,13 @@ use std::ops::{ use alga::general::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; -use base::allocator::{Allocator, SameShapeAllocator}; -use base::constraint::{AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::{Dim, DimName, U1}; -use base::storage::Storage; -use base::{DefaultAllocator, Matrix, Scalar, Vector, VectorSum}; +use crate::base::allocator::{Allocator, SameShapeAllocator}; +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}; -use geometry::Point; +use crate::geometry::Point; /* * diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index d691f48c4..2986dc12c 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -6,32 +6,32 @@ use std::hash; use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::Real; +use alga::general::RealField; -use base::dimension::{U1, U3, U4}; -use base::storage::{CStride, RStride}; -use base::{Matrix3, Matrix4, MatrixSlice, MatrixSliceMut, Unit, Vector3, Vector4}; +use crate::base::dimension::{U1, U3, U4}; +use crate::base::storage::{CStride, RStride}; +use crate::base::{Matrix3, Matrix4, MatrixSlice, MatrixSliceMut, Unit, Vector3, Vector4}; -use geometry::{Point3, Rotation}; +use crate::geometry::{Point3, Rotation}; /// A quaternion. See the type alias `UnitQuaternion = Unit` for a quaternion /// 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 +impl Abomonation for Quaternion where Vector4: Abomonation { unsafe fn entomb(&self, writer: &mut W) -> IOResult<()> { @@ -47,9 +47,9 @@ where Vector4: Abomonation } } -impl Eq for Quaternion {} +impl Eq for Quaternion {} -impl PartialEq for Quaternion { +impl PartialEq for Quaternion { fn eq(&self, rhs: &Self) -> bool { self.coords == rhs.coords || // Account for the double-covering of S², i.e. q = -q @@ -57,15 +57,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,7 +73,7 @@ impl Clone for Quaternion { } #[cfg(feature = "serde-serialize")] -impl Serialize for Quaternion +impl Serialize for Quaternion where Owned: Serialize { fn serialize(&self, serializer: S) -> Result @@ -83,7 +83,7 @@ where Owned: Serialize } #[cfg(feature = "serde-serialize")] -impl<'a, N: Real> Deserialize<'a> for Quaternion +impl<'a, N: RealField> Deserialize<'a> for Quaternion where Owned: Deserialize<'a> { fn deserialize(deserializer: Des) -> Result @@ -94,7 +94,7 @@ where Owned: Deserialize<'a> } } -impl Quaternion { +impl Quaternion { /// 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.")] @@ -225,7 +225,7 @@ impl Quaternion { /// # use nalgebra::{Vector4, Quaternion}; /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); /// // Recall that the quaternion is stored internally as (i, j, k, w) - /// // while the ::new constructor takes the arguments as (w, i, j, k). + /// // while the crate::new constructor takes the arguments as (w, i, j, k). /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); /// ``` #[inline] @@ -400,7 +400,7 @@ impl Quaternion { pub fn polar_decomposition(&self) -> (N, N, Option>>) { 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() / ::convert(2.0f64); + let angle = q.angle() / crate::convert(2.0f64); (n, angle, Some(axis)) } else { @@ -591,13 +591,13 @@ impl Quaternion { /// Divides quaternion into two. #[inline] pub fn half(&self) -> Self { - self / ::convert(2.0f64) + self / crate::convert(2.0f64) } /// Calculates square root. #[inline] pub fn sqrt(&self) -> Self { - self.powf(::convert(0.5)) + self.powf(crate::convert(0.5)) } /// Check if the quaternion is pure. @@ -851,7 +851,7 @@ impl Quaternion { } } -impl> AbsDiffEq for Quaternion { +impl> AbsDiffEq for Quaternion { type Epsilon = N; #[inline] @@ -867,7 +867,7 @@ impl> AbsDiffEq for Quaternion { } } -impl> RelativeEq for Quaternion { +impl> RelativeEq for Quaternion { #[inline] fn default_max_relative() -> Self::Epsilon { N::default_max_relative() @@ -887,7 +887,7 @@ impl> RelativeEq for Quaternion { } } -impl> UlpsEq for Quaternion { +impl> UlpsEq for Quaternion { #[inline] fn default_max_ulps() -> u32 { N::default_max_ulps() @@ -901,7 +901,7 @@ impl> UlpsEq for Quaternion { } } -impl fmt::Display for Quaternion { +impl fmt::Display for Quaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, @@ -914,7 +914,7 @@ impl fmt::Display for Quaternion { /// A unit quaternions. May be used to represent a rotation. pub type UnitQuaternion = Unit>; -impl UnitQuaternion { +impl UnitQuaternion { /// Moves this unit quaternion into one that owns its data. #[inline] #[deprecated( @@ -950,7 +950,7 @@ impl UnitQuaternion { if w >= N::one() { N::zero() } else { - w.acos() * ::convert(2.0f64) + w.acos() * crate::convert(2.0f64) } } @@ -1276,12 +1276,12 @@ impl UnitQuaternion { let ii = i * i; let jj = j * j; let kk = k * k; - let ij = i * j * ::convert(2.0f64); - let wk = w * k * ::convert(2.0f64); - let wj = w * j * ::convert(2.0f64); - let ik = i * k * ::convert(2.0f64); - let jk = j * k * ::convert(2.0f64); - let wi = w * i * ::convert(2.0f64); + let ij = i * j * crate::convert(2.0f64); + let wk = w * k * crate::convert(2.0f64); + let wj = w * j * crate::convert(2.0f64); + let ik = i * k * crate::convert(2.0f64); + let jk = j * k * crate::convert(2.0f64); + let wi = w * i * crate::convert(2.0f64); Rotation::from_matrix_unchecked(Matrix3::new( ww + ii - jj - kk, @@ -1428,7 +1428,7 @@ impl UnitQuaternion { } } -impl fmt::Display for UnitQuaternion { +impl fmt::Display for UnitQuaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(axis) = self.axis() { let axis = axis.into_inner(); @@ -1450,7 +1450,7 @@ impl fmt::Display for UnitQuaternion { } } -impl> AbsDiffEq for UnitQuaternion { +impl> AbsDiffEq for UnitQuaternion { type Epsilon = N; #[inline] @@ -1464,7 +1464,7 @@ impl> AbsDiffEq for UnitQuaternion { } } -impl> RelativeEq for UnitQuaternion { +impl> RelativeEq for UnitQuaternion { #[inline] fn default_max_relative() -> Self::Epsilon { N::default_max_relative() @@ -1483,7 +1483,7 @@ impl> RelativeEq for UnitQuaternion { } } -impl> UlpsEq for UnitQuaternion { +impl> UlpsEq for UnitQuaternion { #[inline] fn default_max_ulps() -> u32 { N::default_max_ulps() @@ -1494,4 +1494,3 @@ impl> UlpsEq for UnitQuaternion { self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) } } - diff --git a/src/geometry/quaternion_alga.rs b/src/geometry/quaternion_alga.rs index d931b2068..86eeedb11 100755 --- a/src/geometry/quaternion_alga.rs +++ b/src/geometry/quaternion_alga.rs @@ -3,7 +3,7 @@ use num::Zero; use alga::general::{ AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, TwoSidedInverse, Module, - Multiplicative, Real, + Multiplicative, RealField, }; use alga::linear::{ AffineTransformation, DirectIsometry, FiniteDimVectorSpace, Isometry, NormedSpace, @@ -11,38 +11,38 @@ use alga::linear::{ VectorSpace, }; -use base::{Vector3, Vector4}; -use geometry::{Point3, Quaternion, UnitQuaternion}; +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,10 @@ impl FiniteDimVectorSpace for Quaternion { } } -impl NormedSpace for Quaternion { +impl NormedSpace for Quaternion { + type RealField = N; + type ComplexField = N; + #[inline] fn norm_squared(&self) -> N { self.coords.norm_squared() @@ -159,21 +162,21 @@ 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() @@ -194,7 +197,7 @@ impl_structures!( AbstractGroup ); -impl Transformation> for UnitQuaternion { +impl Transformation> for UnitQuaternion { #[inline] fn transform_point(&self, pt: &Point3) -> Point3 { self.transform_point(pt) @@ -206,7 +209,7 @@ 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) @@ -218,7 +221,7 @@ impl ProjectiveTransformation> for UnitQuaternion { } } -impl AffineTransformation> for UnitQuaternion { +impl AffineTransformation> for UnitQuaternion { type Rotation = Self; type NonUniformScaling = Id; type Translation = Id; @@ -259,7 +262,7 @@ impl AffineTransformation> for UnitQuaternion { } } -impl Similarity> for UnitQuaternion { +impl Similarity> for UnitQuaternion { type Scaling = Id; #[inline] @@ -280,13 +283,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 4b7976bdf..7758b4c96 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -1,7 +1,7 @@ #[cfg(feature = "arbitrary")] -use base::dimension::U4; +use crate::base::dimension::U4; #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -9,15 +9,15 @@ use num::{One, Zero}; use rand::distributions::{Distribution, OpenClosed01, Standard}; use rand::Rng; -use alga::general::Real; +use alga::general::RealField; -use base::dimension::U3; -use base::storage::Storage; -use base::{Unit, Vector, Vector3, Vector4, Matrix3}; +use crate::base::dimension::U3; +use crate::base::storage::Storage; +use crate::base::{Unit, Vector, Vector3, Vector4, Matrix3}; -use geometry::{Quaternion, Rotation3, UnitQuaternion}; +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] @@ -83,7 +83,7 @@ impl Quaternion { // 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 * ::convert(2.0f64)); + let rot = UnitQuaternion::::from_axis_angle(&axis, theta * crate::convert(2.0f64)); rot.into_inner() * scale } @@ -105,14 +105,14 @@ impl Quaternion { } } -impl One for Quaternion { +impl One for Quaternion { #[inline] fn one() -> Self { Self::identity() } } -impl Zero for Quaternion { +impl Zero for Quaternion { #[inline] fn zero() -> Self { Self::from(Vector4::zero()) @@ -124,7 +124,7 @@ impl Zero for Quaternion { } } -impl Distribution> for Standard +impl Distribution> for Standard where Standard: Distribution { #[inline] @@ -134,7 +134,7 @@ where Standard: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Quaternion +impl Arbitrary for Quaternion where Owned: Send { #[inline] @@ -148,7 +148,7 @@ where Owned: Send } } -impl UnitQuaternion { +impl UnitQuaternion { /// The rotation identity. /// /// # Example @@ -195,7 +195,7 @@ impl UnitQuaternion { #[inline] pub fn from_axis_angle(axis: &Unit>, angle: N) -> Self where SB: Storage { - let (sang, cang) = (angle / ::convert(2.0f64)).sin_cos(); + let (sang, cang) = (angle / crate::convert(2.0f64)).sin_cos(); let q = Quaternion::from_parts(cang, axis.as_ref() * sang); Self::new_unchecked(q) @@ -225,9 +225,9 @@ impl UnitQuaternion { /// ``` #[inline] pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self { - let (sr, cr) = (roll * ::convert(0.5f64)).sin_cos(); - let (sp, cp) = (pitch * ::convert(0.5f64)).sin_cos(); - let (sy, cy) = (yaw * ::convert(0.5f64)).sin_cos(); + 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 q = Quaternion::new( cr * cp * cy + sr * sp * sy, @@ -260,10 +260,10 @@ impl UnitQuaternion { let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)]; let res; - let _0_25: N = ::convert(0.25); + let _0_25: N = crate::convert(0.25); if tr > N::zero() { - let denom = (tr + N::one()).sqrt() * ::convert(2.0); + let denom = (tr + N::one()).sqrt() * crate::convert(2.0); res = Quaternion::new( _0_25 * denom, (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, @@ -272,7 +272,7 @@ impl UnitQuaternion { ); } 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() - * ::convert(2.0); + * crate::convert(2.0); res = Quaternion::new( (rotmat[(2, 1)] - rotmat[(1, 2)]) / denom, _0_25 * denom, @@ -281,7 +281,7 @@ impl UnitQuaternion { ); } else if rotmat[(1, 1)] > rotmat[(2, 2)] { let denom = (N::one() + rotmat[(1, 1)] - rotmat[(0, 0)] - rotmat[(2, 2)]).sqrt() - * ::convert(2.0); + * crate::convert(2.0); res = Quaternion::new( (rotmat[(0, 2)] - rotmat[(2, 0)]) / denom, (rotmat[(0, 1)] + rotmat[(1, 0)]) / denom, @@ -290,7 +290,7 @@ impl UnitQuaternion { ); } else { let denom = (N::one() + rotmat[(2, 2)] - rotmat[(0, 0)] - rotmat[(1, 1)]).sqrt() - * ::convert(2.0); + * crate::convert(2.0); res = Quaternion::new( (rotmat[(1, 0)] - rotmat[(0, 1)]) / denom, (rotmat[(0, 2)] + rotmat[(2, 0)]) / denom, @@ -587,7 +587,7 @@ impl UnitQuaternion { #[inline] pub fn new(axisangle: Vector) -> Self where SB: Storage { - let two: N = ::convert(2.0f64); + let two: N = crate::convert(2.0f64); let q = Quaternion::::from_imag(axisangle / two).exp(); Self::new_unchecked(q) } @@ -616,7 +616,7 @@ impl UnitQuaternion { #[inline] pub fn new_eps(axisangle: Vector, eps: N) -> Self where SB: Storage { - let two: N = ::convert(2.0f64); + let two: N = crate::convert(2.0f64); let q = Quaternion::::from_imag(axisangle / two).exp_eps(eps); Self::new_unchecked(q) } @@ -678,14 +678,14 @@ impl UnitQuaternion { } } -impl One for UnitQuaternion { +impl One for UnitQuaternion { #[inline] fn one() -> Self { Self::identity() } } -impl Distribution> for Standard +impl Distribution> for Standard where OpenClosed01: Distribution { /// Generate a uniformly distributed random rotation quaternion. @@ -710,7 +710,7 @@ where OpenClosed01: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for UnitQuaternion +impl Arbitrary for UnitQuaternion where Owned: Send, Owned: Send, diff --git a/src/geometry/quaternion_conversion.rs b/src/geometry/quaternion_conversion.rs index a0b44390b..4ac8b5a75 100644 --- a/src/geometry/quaternion_conversion.rs +++ b/src/geometry/quaternion_conversion.rs @@ -1,14 +1,14 @@ use num::Zero; -use alga::general::{Real, SubsetOf, SupersetOf}; +use alga::general::{RealField, SubsetOf, SupersetOf}; use alga::linear::Rotation as AlgaRotation; #[cfg(feature = "mint")] use mint; -use base::dimension::U3; -use base::{Matrix3, Matrix4, Vector4}; -use geometry::{ +use crate::base::dimension::U3; +use crate::base::{Matrix3, Matrix4, Vector4}; +use crate::geometry::{ Isometry, Point3, Quaternion, Rotation, Rotation3, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, UnitQuaternion, }; @@ -34,8 +34,8 @@ use geometry::{ impl SubsetOf> for Quaternion where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> Quaternion { @@ -44,7 +44,7 @@ where #[inline] fn is_in_subset(q: &Quaternion) -> bool { - ::is_convertible::<_, Vector4>(&q.coords) + crate::is_convertible::<_, Vector4>(&q.coords) } #[inline] @@ -57,8 +57,8 @@ where impl SubsetOf> for UnitQuaternion where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> UnitQuaternion { @@ -67,19 +67,19 @@ where #[inline] fn is_in_subset(uq: &UnitQuaternion) -> bool { - ::is_convertible::<_, Quaternion>(uq.as_ref()) + crate::is_convertible::<_, Quaternion>(uq.as_ref()) } #[inline] unsafe fn from_superset_unchecked(uq: &UnitQuaternion) -> Self { - Self::new_unchecked(::convert_ref_unchecked(uq.as_ref())) + Self::new_unchecked(crate::convert_ref_unchecked(uq.as_ref())) } } impl SubsetOf> for UnitQuaternion where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> Rotation3 { @@ -89,25 +89,25 @@ where #[inline] fn is_in_subset(rot: &Rotation3) -> bool { - ::is_convertible::<_, Rotation3>(rot) + crate::is_convertible::<_, Rotation3>(rot) } #[inline] unsafe fn from_superset_unchecked(rot: &Rotation3) -> Self { let q = UnitQuaternion::::from_rotation_matrix(rot); - ::convert_unchecked(q) + crate::convert_unchecked(q) } } impl SubsetOf> for UnitQuaternion where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: AlgaRotation> + SupersetOf, { #[inline] fn to_superset(&self) -> Isometry { - Isometry::from_parts(Translation::identity(), ::convert_ref(self)) + Isometry::from_parts(Translation::identity(), crate::convert_ref(self)) } #[inline] @@ -117,19 +117,19 @@ where #[inline] unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { - ::convert_ref_unchecked(&iso.rotation) + crate::convert_ref_unchecked(&iso.rotation) } } impl SubsetOf> for UnitQuaternion where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: AlgaRotation> + SupersetOf, { #[inline] fn to_superset(&self) -> Similarity { - Similarity::from_isometry(::convert_ref(self), N2::one()) + Similarity::from_isometry(crate::convert_ref(self), N2::one()) } #[inline] @@ -139,14 +139,14 @@ where #[inline] unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { - ::convert_ref_unchecked(&sim.isometry) + crate::convert_ref_unchecked(&sim.isometry) } } impl SubsetOf> for UnitQuaternion where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, C: SuperTCategoryOf, { #[inline] @@ -165,7 +165,7 @@ where } } -impl> SubsetOf> for UnitQuaternion { +impl> SubsetOf> for UnitQuaternion { #[inline] fn to_superset(&self) -> Matrix4 { self.to_homogeneous().to_superset() @@ -173,25 +173,25 @@ impl> SubsetOf> for UnitQuaterni #[inline] fn is_in_subset(m: &Matrix4) -> bool { - ::is_convertible::<_, Rotation3>(m) + crate::is_convertible::<_, Rotation3>(m) } #[inline] unsafe fn from_superset_unchecked(m: &Matrix4) -> Self { - let rot: Rotation3 = ::convert_ref_unchecked(m); + 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,35 +218,35 @@ impl Into> for UnitQuaternion { } } -impl From> for Matrix4 { +impl From> for Matrix4 { #[inline] fn from(q: UnitQuaternion) -> Self { q.to_homogeneous() } } -impl From> for Rotation3 { +impl From> for Rotation3 { #[inline] fn from(q: UnitQuaternion) -> Self { q.to_rotation_matrix() } } -impl From> for UnitQuaternion { +impl From> for UnitQuaternion { #[inline] fn from(q: Rotation3) -> Self { Self::from_rotation_matrix(&q) } } -impl From> for Matrix3 { +impl From> for Matrix3 { #[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 } diff --git a/src/geometry/quaternion_coordinates.rs b/src/geometry/quaternion_coordinates.rs index 228f74bfb..a9399f18b 100644 --- a/src/geometry/quaternion_coordinates.rs +++ b/src/geometry/quaternion_coordinates.rs @@ -1,13 +1,13 @@ use std::mem; use std::ops::{Deref, DerefMut}; -use alga::general::Real; +use alga::general::RealField; -use base::coordinates::IJKW; +use crate::base::coordinates::IJKW; -use geometry::Quaternion; +use crate::geometry::Quaternion; -impl Deref for Quaternion { +impl Deref for Quaternion { type Target = IJKW; #[inline] @@ -16,7 +16,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 d43f104fe..7f2b274aa 100644 --- a/src/geometry/quaternion_ops.rs +++ b/src/geometry/quaternion_ops.rs @@ -54,16 +54,16 @@ use std::ops::{ Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, }; -use alga::general::Real; +use alga::general::RealField; -use base::allocator::Allocator; -use base::dimension::{U1, U3, U4}; -use base::storage::Storage; -use base::{DefaultAllocator, Unit, Vector, Vector3}; +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 geometry::{Point3, Quaternion, Rotation, UnitQuaternion}; +use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion}; -impl Index for Quaternion { +impl Index for Quaternion { type Output = N; #[inline] @@ -72,7 +72,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,7 +85,7 @@ 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: Real $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs where DefaultAllocator: Allocator + Allocator { type Output = $Result; @@ -390,7 +390,7 @@ quaternion_op_impl!( self: &'a UnitQuaternion, rhs: &'b Vector, Output = Vector3 => U3, U4; { - let two: N = ::convert(2.0f64); + let two: N = crate::convert(2.0f64); let t = self.as_ref().vector().cross(rhs) * two; let cross = self.as_ref().vector().cross(&t); @@ -490,7 +490,7 @@ quaternion_op_impl!( macro_rules! scalar_op_impl( ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$( - impl $Op for Quaternion { + impl $Op for Quaternion { type Output = Quaternion; #[inline] @@ -499,7 +499,7 @@ macro_rules! scalar_op_impl( } } - impl<'a, N: Real> $Op for &'a Quaternion { + impl<'a, N: RealField> $Op for &'a Quaternion { type Output = Quaternion; #[inline] @@ -508,7 +508,7 @@ macro_rules! scalar_op_impl( } } - impl $OpAssign for Quaternion { + impl $OpAssign for Quaternion { #[inline] fn $op_assign(&mut self, n: N) { @@ -547,7 +547,7 @@ macro_rules! left_scalar_mul_impl( left_scalar_mul_impl!(f32, f64); -impl Neg for Quaternion { +impl Neg for Quaternion { type Output = Quaternion; #[inline] @@ -556,7 +556,7 @@ impl Neg for Quaternion { } } -impl<'a, N: Real> Neg for &'a Quaternion { +impl<'a, N: RealField> Neg for &'a Quaternion { type Output = Quaternion; #[inline] @@ -570,7 +570,7 @@ 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: Real> $OpAssign<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField> $OpAssign<$Rhs> for $Lhs where DefaultAllocator: Allocator + Allocator { diff --git a/src/geometry/reflection.rs b/src/geometry/reflection.rs index 6b668c6f9..b4658a11f 100644 --- a/src/geometry/reflection.rs +++ b/src/geometry/reflection.rs @@ -1,11 +1,11 @@ -use alga::general::Real; -use base::allocator::Allocator; -use base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint}; -use base::{DefaultAllocator, Matrix, Scalar, Unit, Vector}; -use dimension::{Dim, DimName, U1}; -use storage::{Storage, StorageMut}; +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 geometry::Point; +use crate::geometry::Point; /// A reflection wrt. a plane. pub struct Reflection> { @@ -13,7 +13,7 @@ pub struct Reflection> { bias: N, } -impl> Reflection { +impl> Reflection { /// Creates a new reflection wrt the plane orthogonal to the given axis and bias. /// /// The bias is the position of the plane on the axis. In particular, a bias equal to zero @@ -21,7 +21,7 @@ impl> Reflection { pub fn new(axis: Unit>, bias: N) -> Self { Self { axis: axis.into_inner(), - bias: bias, + bias, } } @@ -35,7 +35,7 @@ impl> Reflection { D: DimName, DefaultAllocator: Allocator, { - let bias = pt.coords.dot(axis.as_ref()); + let bias = axis.dotc(&pt.coords); Self::new(axis, bias) } @@ -55,29 +55,67 @@ impl> Reflection { // NOTE: we borrow the column twice here. First it is borrowed immutably for the // dot product, and then mutably. Somehow, this allows significantly // better optimizations of the dot product from the compiler. - let m_two: N = ::convert(-2.0f64); - let factor = (rhs.column(i).dot(&self.axis) - self.bias) * m_two; + let m_two: N = crate::convert(-2.0f64); + let factor = (self.axis.dotc(&rhs.column(i)) - self.bias) * m_two; rhs.column_mut(i).axpy(factor, &self.axis, N::one()); } } - /// Applies the reflection to the rows of `rhs`. + // 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, + { + for i in 0..rhs.ncols() { + // NOTE: we borrow the column twice here. First it is borrowed immutably for the + // dot product, and then mutably. Somehow, this allows significantly + // better optimizations of the dot product from the compiler. + let m_two = sign.scale(crate::convert(-2.0f64)); + let factor = (self.axis.dotc(&rhs.column(i)) - self.bias) * m_two; + rhs.column_mut(i).axpy(factor, &self.axis, sign); + } + } + + /// Applies the reflection to the rows of `lhs`. pub fn reflect_rows( &self, - rhs: &mut Matrix, + lhs: &mut Matrix, + work: &mut Vector, + ) where + S2: StorageMut, + S3: StorageMut, + ShapeConstraint: DimEq + AreMultipliable, + { + lhs.mul_to(&self.axis, work); + + if !self.bias.is_zero() { + work.add_scalar_mut(-self.bias); + } + + let m_two: N = crate::convert(-2.0f64); + lhs.gerc(m_two, &work, &self.axis, N::one()); + } + + /// Applies the reflection to the rows of `lhs`. + pub fn reflect_rows_with_sign( + &self, + lhs: &mut Matrix, work: &mut Vector, + sign: N, ) where S2: StorageMut, S3: StorageMut, ShapeConstraint: DimEq + AreMultipliable, { - rhs.mul_to(&self.axis, work); + lhs.mul_to(&self.axis, work); if !self.bias.is_zero() { work.add_scalar_mut(-self.bias); } - let m_two: N = ::convert(-2.0f64); - rhs.ger(m_two, &work, &self.axis, N::one()); + let m_two = sign.scale(crate::convert(-2.0f64)); + lhs.gerc(m_two, &work, &self.axis, sign); } } diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 426e9d251..ec9c8150b 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -9,18 +9,17 @@ use std::io::{Result as IOResult, Write}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde-serialize")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::Real; +use alga::general::RealField; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN, Scalar, VectorN}; - -use geometry::Point; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use crate::geometry::Point; /// A rotation matrix. #[repr(C)] @@ -353,7 +352,7 @@ where DefaultAllocator: Allocator } } -impl Rotation +impl Rotation where DefaultAllocator: Allocator + Allocator { /// Rotate the given point. @@ -511,14 +510,14 @@ where */ impl fmt::Display for Rotation where - N: Real + fmt::Display, + N: RealField + fmt::Display, DefaultAllocator: Allocator + Allocator, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "Rotation matrix {{")); - try!(write!(f, "{:.*}", precision, self.matrix)); + writeln!(f, "Rotation matrix {{")?; + write!(f, "{:.*}", precision, self.matrix)?; writeln!(f, "}}") } } diff --git a/src/geometry/rotation_alga.rs b/src/geometry/rotation_alga.rs index cd411c8ca..e8cf74e74 100755 --- a/src/geometry/rotation_alga.rs +++ b/src/geometry/rotation_alga.rs @@ -1,24 +1,24 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real, + AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, }; use alga::linear::{ self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, ProjectiveTransformation, Similarity, Transformation, }; -use base::allocator::Allocator; -use base::dimension::DimName; -use base::{DefaultAllocator, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, VectorN}; -use geometry::{Point, Rotation}; +use crate::geometry::{Point, Rotation}; /* * * Algebraic structures. * */ -impl Identity for Rotation +impl Identity for Rotation where DefaultAllocator: Allocator { #[inline] @@ -27,7 +27,7 @@ where DefaultAllocator: Allocator } } -impl TwoSidedInverse for Rotation +impl TwoSidedInverse for Rotation where DefaultAllocator: Allocator { #[inline] @@ -41,7 +41,7 @@ where DefaultAllocator: Allocator } } -impl AbstractMagma for Rotation +impl AbstractMagma for Rotation where DefaultAllocator: Allocator { #[inline] @@ -52,7 +52,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 { } )*} ); @@ -70,7 +70,7 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Rotation +impl Transformation> for Rotation where DefaultAllocator: Allocator + Allocator { #[inline] @@ -84,7 +84,7 @@ where DefaultAllocator: Allocator + Allocator } } -impl ProjectiveTransformation> for Rotation +impl ProjectiveTransformation> for Rotation where DefaultAllocator: Allocator + Allocator { #[inline] @@ -98,7 +98,7 @@ where DefaultAllocator: Allocator + Allocator } } -impl AffineTransformation> for Rotation +impl AffineTransformation> for Rotation where DefaultAllocator: Allocator + Allocator { type Rotation = Self; @@ -141,7 +141,7 @@ where DefaultAllocator: Allocator + Allocator } } -impl Similarity> for Rotation +impl Similarity> for Rotation where DefaultAllocator: Allocator + Allocator { type Scaling = Id; @@ -164,7 +164,7 @@ where DefaultAllocator: Allocator + Allocator macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for Rotation + impl $Trait> for Rotation where DefaultAllocator: Allocator + Allocator { } )*} @@ -173,7 +173,7 @@ macro_rules! marker_impl( marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); /// Subgroups of the n-dimensional rotation group `SO(n)`. -impl linear::Rotation> for Rotation +impl linear::Rotation> for Rotation where DefaultAllocator: Allocator + Allocator { #[inline] @@ -199,7 +199,7 @@ where DefaultAllocator: Allocator + Allocator } /* -impl Matrix for Rotation { +impl Matrix for Rotation { type Field = N; type Row = Matrix; type Column = Matrix; @@ -241,7 +241,7 @@ impl Matrix for Rotation { } } -impl SquareMatrix for Rotation { +impl SquareMatrix for Rotation { type Vector = Matrix; #[inline] @@ -251,7 +251,7 @@ impl SquareMatrix for Rotation { #[inline] fn determinant(&self) -> Self::Field { - ::one() + crate::one() } #[inline] @@ -271,5 +271,5 @@ impl SquareMatrix for Rotation { } } -impl InversibleSquareMatrix for Rotation { } +impl InversibleSquareMatrix for Rotation { } */ diff --git a/src/geometry/rotation_alias.rs b/src/geometry/rotation_alias.rs index a11bba99e..9fa5c2d05 100644 --- a/src/geometry/rotation_alias.rs +++ b/src/geometry/rotation_alias.rs @@ -1,6 +1,6 @@ -use base::dimension::{U2, U3}; +use crate::base::dimension::{U2, U3}; -use geometry::Rotation; +use crate::geometry::Rotation; /// A 2-dimensional rotation matrix. pub type Rotation2 = Rotation; diff --git a/src/geometry/rotation_construction.rs b/src/geometry/rotation_construction.rs index 0da2cb29c..a7779cc6d 100644 --- a/src/geometry/rotation_construction.rs +++ b/src/geometry/rotation_construction.rs @@ -2,11 +2,11 @@ use num::{One, Zero}; use alga::general::{ClosedAdd, ClosedMul}; -use base::allocator::Allocator; -use base::dimension::DimName; -use base::{DefaultAllocator, MatrixN, Scalar}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, MatrixN, Scalar}; -use geometry::Rotation; +use crate::geometry::Rotation; impl Rotation where diff --git a/src/geometry/rotation_conversion.rs b/src/geometry/rotation_conversion.rs index 044d85af7..ac3142211 100644 --- a/src/geometry/rotation_conversion.rs +++ b/src/geometry/rotation_conversion.rs @@ -1,16 +1,16 @@ use num::Zero; -use alga::general::{Real, SubsetOf, SupersetOf}; +use alga::general::{RealField, SubsetOf, SupersetOf}; use alga::linear::Rotation as AlgaRotation; #[cfg(feature = "mint")] use mint; -use base::allocator::Allocator; -use base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, Matrix2, Matrix3, Matrix4, MatrixN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, Matrix2, Matrix3, Matrix4, MatrixN}; -use geometry::{ +use crate::geometry::{ Isometry, Point, Rotation, Rotation2, Rotation3, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, UnitComplex, UnitQuaternion, }; @@ -32,8 +32,8 @@ use geometry::{ impl SubsetOf> for Rotation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, DefaultAllocator: Allocator + Allocator, { #[inline] @@ -43,7 +43,7 @@ where #[inline] fn is_in_subset(rot: &Rotation) -> bool { - ::is_convertible::<_, MatrixN>(rot.matrix()) + crate::is_convertible::<_, MatrixN>(rot.matrix()) } #[inline] @@ -54,8 +54,8 @@ where impl SubsetOf> for Rotation3 where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> UnitQuaternion { @@ -65,20 +65,20 @@ where #[inline] fn is_in_subset(q: &UnitQuaternion) -> bool { - ::is_convertible::<_, UnitQuaternion>(q) + crate::is_convertible::<_, UnitQuaternion>(q) } #[inline] unsafe fn from_superset_unchecked(q: &UnitQuaternion) -> Self { - let q: UnitQuaternion = ::convert_ref_unchecked(q); + let q: UnitQuaternion = crate::convert_ref_unchecked(q); q.to_rotation_matrix() } } impl SubsetOf> for Rotation2 where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> UnitComplex { @@ -88,26 +88,26 @@ where #[inline] fn is_in_subset(q: &UnitComplex) -> bool { - ::is_convertible::<_, UnitComplex>(q) + crate::is_convertible::<_, UnitComplex>(q) } #[inline] unsafe fn from_superset_unchecked(q: &UnitComplex) -> Self { - let q: UnitComplex = ::convert_ref_unchecked(q); + let q: UnitComplex = crate::convert_ref_unchecked(q); q.to_rotation_matrix() } } impl SubsetOf> for Rotation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: AlgaRotation> + SupersetOf, DefaultAllocator: Allocator + Allocator, { #[inline] fn to_superset(&self) -> Isometry { - Isometry::from_parts(Translation::identity(), ::convert_ref(self)) + Isometry::from_parts(Translation::identity(), crate::convert_ref(self)) } #[inline] @@ -117,20 +117,20 @@ where #[inline] unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { - ::convert_ref_unchecked(&iso.rotation) + crate::convert_ref_unchecked(&iso.rotation) } } impl SubsetOf> for Rotation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: AlgaRotation> + SupersetOf, DefaultAllocator: Allocator + Allocator, { #[inline] fn to_superset(&self) -> Similarity { - Similarity::from_parts(Translation::identity(), ::convert_ref(self), N2::one()) + Similarity::from_parts(Translation::identity(), crate::convert_ref(self), N2::one()) } #[inline] @@ -140,14 +140,14 @@ where #[inline] unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { - ::convert_ref_unchecked(&sim.isometry.rotation) + crate::convert_ref_unchecked(&sim.isometry.rotation) } } impl SubsetOf> for Rotation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, C: SuperTCategoryOf, D: DimNameAdd + DimMin, // needed by .is_special_orthogonal() DefaultAllocator: Allocator @@ -175,8 +175,8 @@ where impl SubsetOf>> for Rotation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, D: DimNameAdd + DimMin, // needed by .is_special_orthogonal() DefaultAllocator: Allocator + Allocator @@ -198,7 +198,7 @@ where // Scalar types agree. m.iter().all(|e| SupersetOf::::is_in_subset(e)) && // The block part is a rotation. - rot.is_special_orthogonal(N2::default_epsilon() * ::convert(100.0)) && + rot.is_special_orthogonal(N2::default_epsilon() * crate::convert(100.0)) && // The bottom row is (0, 0, ..., 1) bottom.iter().all(|e| e.is_zero()) && m[(D::dim(), D::dim())] == N2::one() } @@ -206,39 +206,39 @@ where #[inline] unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let r = m.fixed_slice::(0, 0); - Self::from_matrix_unchecked(::convert_unchecked(r.into_owned())) + Self::from_matrix_unchecked(crate::convert_unchecked(r.into_owned())) } } #[cfg(feature = "mint")] -impl From> for Rotation3 { +impl From> for Rotation3 { fn from(euler: mint::EulerAngles) -> Self { Self::from_euler_angles(euler.a, euler.b, euler.c) } } -impl From> for Matrix3 { +impl From> for Matrix3 { #[inline] fn from(q: Rotation2) ->Self { q.to_homogeneous() } } -impl From> for Matrix2 { +impl From> for Matrix2 { #[inline] fn from(q: Rotation2) -> Self { q.into_inner() } } -impl From> for Matrix4 { +impl From> for Matrix4 { #[inline] fn from(q: Rotation3) -> Self { q.to_homogeneous() } } -impl From> for Matrix3 { +impl From> for Matrix3 { #[inline] fn from(q: Rotation3) -> Self { q.into_inner() diff --git a/src/geometry/rotation_ops.rs b/src/geometry/rotation_ops.rs index fae709210..ed555b6b4 100644 --- a/src/geometry/rotation_ops.rs +++ b/src/geometry/rotation_ops.rs @@ -22,13 +22,13 @@ use std::ops::{Div, DivAssign, Index, Mul, MulAssign}; use alga::general::{ClosedAdd, ClosedMul}; -use base::allocator::Allocator; -use base::constraint::{AreMultipliable, ShapeConstraint}; -use base::dimension::{Dim, DimName, U1}; -use base::storage::Storage; -use base::{DefaultAllocator, Matrix, MatrixMN, Scalar, Unit, Vector, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::constraint::{AreMultipliable, ShapeConstraint}; +use crate::base::dimension::{Dim, DimName, U1}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, Scalar, Unit, Vector, VectorN}; -use geometry::{Point, Rotation}; +use crate::geometry::{Point, Rotation}; impl Index<(usize, usize)> for Rotation where DefaultAllocator: Allocator diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 0aeb3041e..973190a6d 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -1,26 +1,26 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; -use alga::general::Real; +use alga::general::RealField; use num::Zero; use rand::distributions::{Distribution, OpenClosed01, Standard}; use rand::Rng; use std::ops::Neg; -use base::dimension::{U1, U2, U3}; -use base::storage::Storage; -use base::{Matrix2, Matrix3, MatrixN, Unit, Vector, Vector1, Vector3, VectorN}; +use crate::base::dimension::{U1, U2, U3}; +use crate::base::storage::Storage; +use crate::base::{Matrix2, Matrix3, MatrixN, Unit, Vector, Vector1, Vector3, VectorN}; -use geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; +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 @@ -113,7 +113,7 @@ impl Rotation2 { SB: Storage, SC: Storage, { - ::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix()) + crate::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix()) } /// The smallest rotation needed to make `a` and `b` collinear and point toward the same @@ -140,7 +140,7 @@ impl Rotation2 { SB: Storage, SC: Storage, { - ::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) + crate::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) } /// The rotation angle. @@ -193,7 +193,6 @@ impl Rotation2 { } - /* FIXME: requires alga v0.9 to be released so that Complex implements VectorSpace. /// 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] @@ -203,7 +202,6 @@ impl Rotation2 { *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 @@ -232,7 +230,7 @@ impl Rotation2 { } } -impl Distribution> for Standard +impl Distribution> for Standard where OpenClosed01: Distribution { /// Generate a uniformly distributed random rotation. @@ -243,7 +241,7 @@ where OpenClosed01: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Rotation2 +impl Arbitrary for Rotation2 where Owned: Send { #[inline] @@ -257,7 +255,7 @@ where Owned: Send * 3D Rotation matrix. * */ -impl Rotation3 { +impl Rotation3 { /// Builds a 3 dimensional rotation matrix from an axis and an angle. /// /// # Arguments @@ -682,7 +680,7 @@ impl Rotation3 { #[inline] pub fn angle(&self) -> N { ((self.matrix()[(0, 0)] + self.matrix()[(1, 1)] + self.matrix()[(2, 2)] - N::one()) - / ::convert(2.0)) + / crate::convert(2.0)) .acos() } @@ -819,7 +817,7 @@ impl Rotation3 { } } -impl Distribution> for Standard +impl Distribution> for Standard where OpenClosed01: Distribution { /// Generate a uniformly distributed random rotation. @@ -859,7 +857,7 @@ where OpenClosed01: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for Rotation3 +impl Arbitrary for Rotation3 where Owned: Send, Owned: Send, diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 4cce91a6d..fed047258 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -10,14 +10,14 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{Real, SubsetOf}; +use alga::general::{RealField, SubsetOf}; use alga::linear::Rotation; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::storage::Owned; -use base::{DefaultAllocator, MatrixN, VectorN}; -use geometry::{Isometry, Point, Translation}; +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}; /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. #[repr(C)] @@ -41,7 +41,7 @@ use geometry::{Isometry, Point, Translation}; Owned: Deserialize<'de>" )) )] -pub struct Similarity +pub struct Similarity where DefaultAllocator: Allocator { /// The part of this similarity that does not include the scaling factor. @@ -50,7 +50,7 @@ where DefaultAllocator: Allocator } #[cfg(feature = "abomonation-serialize")] -impl Abomonation for Similarity +impl Abomonation for Similarity where Isometry: Abomonation, DefaultAllocator: Allocator, @@ -68,7 +68,7 @@ where } } -impl hash::Hash +impl hash::Hash for Similarity where DefaultAllocator: Allocator, @@ -80,13 +80,13 @@ where } } -impl> + Copy> Copy for Similarity +impl> + Copy> Copy for Similarity where DefaultAllocator: Allocator, Owned: Copy, {} -impl> + Clone> Clone for Similarity +impl> + Clone> Clone for Similarity where DefaultAllocator: Allocator { #[inline] @@ -95,7 +95,7 @@ where DefaultAllocator: Allocator } } -impl Similarity +impl Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -325,7 +325,7 @@ 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 +impl Similarity where DefaultAllocator: Allocator { /// Converts this similarity into its equivalent homogeneous transformation matrix. @@ -346,13 +346,13 @@ where DefaultAllocator: Allocator } } -impl Eq for Similarity +impl Eq for Similarity where R: Rotation> + Eq, DefaultAllocator: Allocator, {} -impl PartialEq for Similarity +impl PartialEq for Similarity where R: Rotation> + PartialEq, DefaultAllocator: Allocator, @@ -363,7 +363,7 @@ where } } -impl AbsDiffEq for Similarity +impl AbsDiffEq for Similarity where R: Rotation> + AbsDiffEq, DefaultAllocator: Allocator, @@ -383,7 +383,7 @@ where } } -impl RelativeEq for Similarity +impl RelativeEq for Similarity where R: Rotation> + RelativeEq, DefaultAllocator: Allocator, @@ -410,7 +410,7 @@ where } } -impl UlpsEq for Similarity +impl UlpsEq for Similarity where R: Rotation> + UlpsEq, DefaultAllocator: Allocator, @@ -435,16 +435,16 @@ where */ impl fmt::Display for Similarity where - N: Real + fmt::Display, + N: RealField + fmt::Display, R: Rotation> + fmt::Display, DefaultAllocator: Allocator + Allocator, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); - try!(writeln!(f, "Similarity {{")); - try!(write!(f, "{:.*}", precision, self.isometry)); - try!(write!(f, "Scaling: {:.*}", precision, self.scaling)); + writeln!(f, "Similarity {{")?; + write!(f, "{:.*}", precision, self.isometry)?; + write!(f, "Scaling: {:.*}", precision, self.scaling)?; writeln!(f, "}}") } } diff --git a/src/geometry/similarity_alga.rs b/src/geometry/similarity_alga.rs index 9b7230294..448fb1335 100755 --- a/src/geometry/similarity_alga.rs +++ b/src/geometry/similarity_alga.rs @@ -1,22 +1,22 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real, + AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, RealField, }; use alga::linear::Similarity as AlgaSimilarity; use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation}; -use base::allocator::Allocator; -use base::dimension::DimName; -use base::{DefaultAllocator, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, VectorN}; -use geometry::{Point, Similarity, Translation}; +use crate::geometry::{Point, Similarity, Translation}; /* * * Algebraic structures. * */ -impl Identity for Similarity +impl Identity for Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -27,7 +27,7 @@ where } } -impl TwoSidedInverse for Similarity +impl TwoSidedInverse for Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -43,7 +43,7 @@ where } } -impl AbstractMagma for Similarity +impl AbstractMagma for Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -56,7 +56,7 @@ where macro_rules! impl_multiplicative_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for Similarity + impl $marker<$operator> for Similarity where R: Rotation>, DefaultAllocator: Allocator { } )*} @@ -75,7 +75,7 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Similarity +impl Transformation> for Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -91,7 +91,7 @@ where } } -impl ProjectiveTransformation> for Similarity +impl ProjectiveTransformation> for Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -107,7 +107,7 @@ where } } -impl AffineTransformation> for Similarity +impl AffineTransformation> for Similarity where R: Rotation>, DefaultAllocator: Allocator, @@ -164,7 +164,7 @@ where } } -impl AlgaSimilarity> for Similarity +impl AlgaSimilarity> for Similarity where R: Rotation>, DefaultAllocator: Allocator, diff --git a/src/geometry/similarity_alias.rs b/src/geometry/similarity_alias.rs index 9d3a2f45b..c2c887ac0 100644 --- a/src/geometry/similarity_alias.rs +++ b/src/geometry/similarity_alias.rs @@ -1,6 +1,6 @@ -use base::dimension::{U2, U3}; +use crate::base::dimension::{U2, U3}; -use geometry::{Rotation2, Rotation3, Similarity, UnitComplex, UnitQuaternion}; +use crate::geometry::{Rotation2, Rotation3, Similarity, UnitComplex, UnitQuaternion}; /// A 2-dimensional similarity. pub type Similarity2 = Similarity>; diff --git a/src/geometry/similarity_construction.rs b/src/geometry/similarity_construction.rs index 47bb46c75..a3722ba95 100644 --- a/src/geometry/similarity_construction.rs +++ b/src/geometry/similarity_construction.rs @@ -1,5 +1,5 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -7,19 +7,19 @@ use num::One; use rand::distributions::{Distribution, Standard}; use rand::Rng; -use alga::general::Real; +use alga::general::RealField; use alga::linear::Rotation as AlgaRotation; -use base::allocator::Allocator; -use base::dimension::{DimName, U2, U3}; -use base::{DefaultAllocator, Vector2, Vector3}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, U2, U3}; +use crate::base::{DefaultAllocator, Vector2, Vector3}; -use geometry::{ +use crate::geometry::{ Isometry, Point, Point3, Rotation2, Rotation3, Similarity, Translation, UnitComplex, UnitQuaternion, }; -impl Similarity +impl Similarity where R: AlgaRotation>, DefaultAllocator: Allocator, @@ -45,7 +45,7 @@ where } } -impl One for Similarity +impl One for Similarity where R: AlgaRotation>, DefaultAllocator: Allocator, @@ -57,7 +57,7 @@ where } } -impl Distribution> for Standard +impl Distribution> for Standard where R: AlgaRotation>, DefaultAllocator: Allocator, @@ -74,7 +74,7 @@ where } } -impl Similarity +impl Similarity where R: AlgaRotation>, DefaultAllocator: Allocator, @@ -104,7 +104,7 @@ where #[cfg(feature = "arbitrary")] impl Arbitrary for Similarity where - N: Real + Arbitrary + Send, + N: RealField + Arbitrary + Send, R: AlgaRotation> + Arbitrary + Send, DefaultAllocator: Allocator, Owned: Send, @@ -127,7 +127,7 @@ where */ // 2D rotation. -impl Similarity> { +impl Similarity> { /// Creates a new similarity from a translation, a rotation, and an uniform scaling factor. /// /// # Example @@ -150,7 +150,7 @@ impl Similarity> { } } -impl Similarity> { +impl Similarity> { /// Creates a new similarity from a translation and a rotation angle. /// /// # Example @@ -176,7 +176,7 @@ impl Similarity> { // 3D rotation. macro_rules! similarity_construction_impl( ($Rot: ty) => { - impl Similarity { + impl Similarity { /// Creates a new similarity from a translation, rotation axis-angle, and scaling /// factor. /// diff --git a/src/geometry/similarity_conversion.rs b/src/geometry/similarity_conversion.rs index 34943fee8..a0d207e4e 100644 --- a/src/geometry/similarity_conversion.rs +++ b/src/geometry/similarity_conversion.rs @@ -1,11 +1,11 @@ -use alga::general::{Real, SubsetOf, SupersetOf}; +use alga::general::{RealField, SubsetOf, SupersetOf}; use alga::linear::Rotation; -use base::allocator::Allocator; -use base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimMin, DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN}; -use geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; +use crate::geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; /* * This file provides the following conversions: @@ -18,8 +18,8 @@ use geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform impl SubsetOf> for Similarity where - N1: Real + SubsetOf, - N2: Real + SupersetOf, + N1: RealField + SubsetOf, + N2: RealField + SupersetOf, R1: Rotation> + SubsetOf, R2: Rotation>, DefaultAllocator: Allocator + Allocator, @@ -31,8 +31,8 @@ where #[inline] fn is_in_subset(sim: &Similarity) -> bool { - ::is_convertible::<_, Isometry>(&sim.isometry) - && ::is_convertible::<_, N1>(&sim.scaling()) + crate::is_convertible::<_, Isometry>(&sim.isometry) + && crate::is_convertible::<_, N1>(&sim.scaling()) } #[inline] @@ -46,8 +46,8 @@ where impl SubsetOf> for Similarity where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, C: SuperTCategoryOf, R: Rotation> + SubsetOf>> @@ -80,8 +80,8 @@ where impl SubsetOf>> for Similarity where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: Rotation> + SubsetOf>> + SubsetOf>>, @@ -143,7 +143,7 @@ where let nb = mm.fixed_slice_mut::(0, 1).normalize_mut(); let nc = mm.fixed_slice_mut::(0, 2).normalize_mut(); - let mut scale = (na + nb + nc) / ::convert(3.0); // We take the mean, for robustness. + let mut scale = (na + nb + nc) / crate::convert(3.0); // We take the mean, for robustness. // FIXME: could we avoid the explicit computation of the determinant? // (its sign is needed to see if the scaling factor is negative). @@ -156,14 +156,14 @@ where let t = m.fixed_slice::(0, D::dim()).into_owned(); let t = Translation { - vector: ::convert_unchecked(t), + vector: crate::convert_unchecked(t), }; - Self::from_parts(t, ::convert_unchecked(mm), ::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>>, diff --git a/src/geometry/similarity_ops.rs b/src/geometry/similarity_ops.rs index 081e51330..80d84b86e 100644 --- a/src/geometry/similarity_ops.rs +++ b/src/geometry/similarity_ops.rs @@ -1,13 +1,13 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::Real; +use alga::general::RealField; use alga::linear::Rotation as AlgaRotation; -use base::allocator::Allocator; -use base::dimension::{DimName, U1, U3, U4}; -use base::{DefaultAllocator, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, U1, U3, U4}; +use crate::base::{DefaultAllocator, VectorN}; -use geometry::{Isometry, Point, Rotation, Similarity, Translation, UnitQuaternion}; +use crate::geometry::{Isometry, Point, Rotation, Similarity, Translation, 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,7 +66,7 @@ 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: Real, D: DimName, R> $Op<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField, D: DimName, R> $Op<$Rhs> for $Lhs where R: AlgaRotation>, DefaultAllocator: Allocator { type Output = $Output; @@ -113,7 +113,7 @@ 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 + impl $OpAssign<$Rhs> for $Lhs where R: AlgaRotation>, DefaultAllocator: Allocator { #[inline] @@ -122,7 +122,7 @@ macro_rules! similarity_binop_assign_impl_all( } } - impl<'b, N: Real, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs + impl<'b, N: RealField, D: DimName, R> $OpAssign<&'b $Rhs> for $Lhs where R: AlgaRotation>, DefaultAllocator: Allocator { #[inline] @@ -379,7 +379,7 @@ 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: Real $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField $(, $Dims: $DimsBound)*> $Op<$Rhs> for $Lhs where DefaultAllocator: Allocator + Allocator { type Output = $Output; diff --git a/src/geometry/swizzle.rs b/src/geometry/swizzle.rs index 20c8dffd1..d57400160 100644 --- a/src/geometry/swizzle.rs +++ b/src/geometry/swizzle.rs @@ -1,6 +1,6 @@ -use base::allocator::Allocator; -use base::{DefaultAllocator, DimName, Scalar}; -use geometry::{Point, Point2, Point3}; +use crate::base::allocator::Allocator; +use crate::base::{DefaultAllocator, DimName, Scalar}; +use crate::geometry::{Point, Point2, Point3}; use typenum::{self, Cmp, Greater}; macro_rules! impl_swizzle { diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index e0eb1bb92..baf3308bc 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -6,14 +6,14 @@ use std::marker::PhantomData; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use alga::general::{Real, TwoSidedInverse}; +use alga::general::{RealField, TwoSidedInverse}; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::storage::Owned; -use base::{DefaultAllocator, MatrixN, VectorN}; +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 geometry::Point; +use crate::geometry::Point; /// Trait implemented by phantom types identifying the projective transformation type. /// @@ -28,7 +28,7 @@ pub trait TCategory: Any + Debug + Copy + PartialEq + Send { /// Checks that the given matrix is a valid homogeneous representation of an element of the /// category `Self`. - fn check_homogeneous_invariants(mat: &MatrixN) -> bool + fn check_homogeneous_invariants(mat: &MatrixN) -> bool where N::Epsilon: Copy, DefaultAllocator: Allocator; @@ -71,7 +71,7 @@ pub enum TAffine {} impl TCategory for TGeneral { #[inline] - fn check_homogeneous_invariants(_: &MatrixN) -> bool + fn check_homogeneous_invariants(_: &MatrixN) -> bool where N::Epsilon: Copy, DefaultAllocator: Allocator, @@ -82,7 +82,7 @@ impl TCategory for TGeneral { impl TCategory for TProjective { #[inline] - fn check_homogeneous_invariants(mat: &MatrixN) -> bool + fn check_homogeneous_invariants(mat: &MatrixN) -> bool where N::Epsilon: Copy, DefaultAllocator: Allocator, @@ -98,7 +98,7 @@ impl TCategory for TAffine { } #[inline] - fn check_homogeneous_invariants(mat: &MatrixN) -> bool + fn check_homogeneous_invariants(mat: &MatrixN) -> bool where N::Epsilon: Copy, DefaultAllocator: Allocator, @@ -157,7 +157,7 @@ super_tcategory_impl!( /// 3D transformation. #[repr(C)] #[derive(Debug)] -pub struct Transform, C: TCategory> +pub struct Transform, C: TCategory> where DefaultAllocator: Allocator, DimNameSum> { matrix: MatrixN>, @@ -165,7 +165,7 @@ where DefaultAllocator: Allocator, DimNameSum> } // FIXME -// impl + hash::Hash, C: TCategory> hash::Hash for Transform +// impl + hash::Hash, C: TCategory> hash::Hash for Transform // where DefaultAllocator: Allocator, DimNameSum>, // Owned, DimNameSum>: hash::Hash { // fn hash(&self, state: &mut H) { @@ -173,14 +173,14 @@ where DefaultAllocator: Allocator, DimNameSum> // } // } -impl + Copy, C: TCategory> Copy for Transform +impl + Copy, C: TCategory> Copy for Transform where DefaultAllocator: Allocator, DimNameSum>, Owned, DimNameSum>: Copy, { } -impl, C: TCategory> Clone for Transform +impl, C: TCategory> Clone for Transform where DefaultAllocator: Allocator, DimNameSum> { #[inline] @@ -190,7 +190,7 @@ where DefaultAllocator: Allocator, DimNameSum> } #[cfg(feature = "serde-serialize")] -impl, C: TCategory> Serialize for Transform +impl, C: TCategory> Serialize for Transform where DefaultAllocator: Allocator, DimNameSum>, Owned, DimNameSum>: Serialize, @@ -202,7 +202,7 @@ where } #[cfg(feature = "serde-serialize")] -impl<'a, N: Real, D: DimNameAdd, C: TCategory> Deserialize<'a> for Transform +impl<'a, N: RealField, D: DimNameAdd, C: TCategory> Deserialize<'a> for Transform where DefaultAllocator: Allocator, DimNameSum>, Owned, DimNameSum>: Deserialize<'a>, @@ -215,10 +215,10 @@ where } } -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 +impl, C: TCategory> PartialEq for Transform where DefaultAllocator: Allocator, DimNameSum> { #[inline] @@ -227,7 +227,7 @@ where DefaultAllocator: Allocator, DimNameSum> } } -impl, C: TCategory> Transform +impl, C: TCategory> Transform where DefaultAllocator: Allocator, DimNameSum> { /// Creates a new transformation from the given homogeneous matrix. The transformation category @@ -456,7 +456,7 @@ where DefaultAllocator: Allocator, DimNameSum> impl, C> Transform where - N: Real, + N: RealField, C: TCategory, DefaultAllocator: Allocator, DimNameSum> + Allocator> @@ -481,7 +481,7 @@ where } } -impl, C: TCategory> Transform +impl, C: TCategory> Transform where C: SubTCategoryOf, DefaultAllocator: Allocator, DimNameSum> + Allocator> @@ -505,7 +505,7 @@ where C: SubTCategoryOf, } } -impl> Transform +impl> Transform where DefaultAllocator: Allocator, DimNameSum> { /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this @@ -516,7 +516,7 @@ where DefaultAllocator: Allocator, DimNameSum> } } -impl, C: TCategory> AbsDiffEq for Transform +impl, C: TCategory> AbsDiffEq for Transform where N::Epsilon: Copy, DefaultAllocator: Allocator, DimNameSum>, @@ -534,7 +534,7 @@ where } } -impl, C: TCategory> RelativeEq for Transform +impl, C: TCategory> RelativeEq for Transform where N::Epsilon: Copy, DefaultAllocator: Allocator, DimNameSum>, @@ -557,7 +557,7 @@ where } } -impl, C: TCategory> UlpsEq for Transform +impl, C: TCategory> UlpsEq for Transform where N::Epsilon: Copy, DefaultAllocator: Allocator, DimNameSum>, @@ -576,7 +576,7 @@ where #[cfg(test)] mod tests { use super::*; - use base::Matrix4; + use crate::base::Matrix4; #[test] fn checks_homogeneous_invariants_of_square_identity_matrix() { diff --git a/src/geometry/transform_alga.rs b/src/geometry/transform_alga.rs index d58b1d53b..ec3fd7c69 100755 --- a/src/geometry/transform_alga.rs +++ b/src/geometry/transform_alga.rs @@ -1,21 +1,21 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, Real, + AbstractSemigroup, Identity, TwoSidedInverse, Multiplicative, RealField, }; use alga::linear::{ProjectiveTransformation, Transformation}; -use base::allocator::Allocator; -use base::dimension::{DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, VectorN}; -use geometry::{Point, SubTCategoryOf, TCategory, TProjective, Transform}; +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 +26,7 @@ where } } -impl, C> TwoSidedInverse for Transform +impl, C> TwoSidedInverse for Transform where C: SubTCategoryOf, DefaultAllocator: Allocator, DimNameSum>, @@ -42,7 +42,7 @@ where } } -impl, C> AbstractMagma for Transform +impl, C> AbstractMagma for Transform where C: TCategory, DefaultAllocator: Allocator, DimNameSum>, @@ -55,7 +55,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> { } )*} @@ -63,7 +63,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> { } )*} @@ -87,7 +87,7 @@ impl_inversible_multiplicative_structures!( */ impl, C> Transformation> for Transform where - N: Real, + N: RealField, C: TCategory, DefaultAllocator: Allocator, DimNameSum> + Allocator> @@ -107,7 +107,7 @@ where impl, C> ProjectiveTransformation> for Transform where - N: Real, + N: RealField, C: SubTCategoryOf, DefaultAllocator: Allocator, DimNameSum> + Allocator> @@ -128,7 +128,7 @@ where // FIXME: we need to implement an SVD for this. // // impl, C> AffineTransformation> for Transform -// where N: Real, +// where N: RealField, // C: SubTCategoryOf, // DefaultAllocator: Allocator, DimNameSum> + // Allocator + diff --git a/src/geometry/transform_alias.rs b/src/geometry/transform_alias.rs index 6f529966f..1ccc5f95e 100644 --- a/src/geometry/transform_alias.rs +++ b/src/geometry/transform_alias.rs @@ -1,6 +1,6 @@ -use base::dimension::{U2, U3}; +use crate::base::dimension::{U2, U3}; -use geometry::{TAffine, TGeneral, TProjective, Transform}; +use crate::geometry::{TAffine, TGeneral, TProjective, Transform}; /// A 2D general transformation that may not be invertible. Stored as an homogeneous 3x3 matrix. pub type Transform2 = Transform; diff --git a/src/geometry/transform_construction.rs b/src/geometry/transform_construction.rs index 3244ad8a6..1b23dabaa 100644 --- a/src/geometry/transform_construction.rs +++ b/src/geometry/transform_construction.rs @@ -1,14 +1,14 @@ use num::One; -use alga::general::Real; +use alga::general::RealField; -use base::allocator::Allocator; -use base::dimension::{DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN}; -use geometry::{TCategory, Transform}; +use crate::geometry::{TCategory, Transform}; -impl, C: TCategory> Transform +impl, C: TCategory> Transform where DefaultAllocator: Allocator, DimNameSum> { /// Creates a new identity transform. @@ -45,7 +45,7 @@ where DefaultAllocator: Allocator, DimNameSum> } } -impl, C: TCategory> One for Transform +impl, C: TCategory> One for Transform where DefaultAllocator: Allocator, DimNameSum> { /// Creates a new identity transform. diff --git a/src/geometry/transform_conversion.rs b/src/geometry/transform_conversion.rs index ab5ad5df7..a0e002916 100644 --- a/src/geometry/transform_conversion.rs +++ b/src/geometry/transform_conversion.rs @@ -1,15 +1,15 @@ -use alga::general::{Real, SubsetOf}; +use alga::general::{RealField, SubsetOf}; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN}; -use geometry::{SuperTCategoryOf, TCategory, Transform}; +use crate::geometry::{SuperTCategoryOf, TCategory, Transform}; impl SubsetOf> for Transform where - N1: Real + SubsetOf, - N2: Real, + N1: RealField + SubsetOf, + N2: RealField, C1: TCategory, C2: SuperTCategoryOf, D: DimNameAdd, @@ -36,8 +36,8 @@ where impl SubsetOf>> for Transform where - N1: Real + SubsetOf, - N2: Real, + N1: RealField + SubsetOf, + N2: RealField, C: TCategory, D: DimNameAdd, DefaultAllocator: Allocator, DimNameSum> @@ -57,11 +57,11 @@ where #[inline] unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { - Self::from_matrix_unchecked(::convert_ref_unchecked(m)) + Self::from_matrix_unchecked(crate::convert_ref_unchecked(m)) } } -impl From> for MatrixN> +impl From> for MatrixN> where D: DimNameAdd, C: TCategory, diff --git a/src/geometry/transform_ops.rs b/src/geometry/transform_ops.rs index 2ede5c602..4aa943e8f 100644 --- a/src/geometry/transform_ops.rs +++ b/src/geometry/transform_ops.rs @@ -1,13 +1,13 @@ use num::{One, Zero}; use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign}; -use alga::general::{ClosedAdd, ClosedMul, Real, SubsetOf}; +use alga::general::{ClosedAdd, ClosedMul, RealField, SubsetOf}; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U3, U4}; -use base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U3, U4}; +use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; -use geometry::{ +use crate::geometry::{ Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory, TCategoryMul, TGeneral, TProjective, Transform, Translation, UnitQuaternion, }; @@ -79,7 +79,7 @@ use geometry::{ * Indexing. * */ -impl Index<(usize, usize)> for Transform +impl Index<(usize, usize)> for Transform where D: DimName + DimNameAdd, DefaultAllocator: Allocator, DimNameSum>, @@ -93,7 +93,7 @@ where } // Only general transformations are mutably indexable. -impl IndexMut<(usize, usize)> for Transform +impl IndexMut<(usize, usize)> for Transform where D: DimName + DimNameAdd, DefaultAllocator: Allocator, DimNameSum>, @@ -106,7 +106,7 @@ where // Transform × Vector md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory; self: Transform, rhs: VectorN, Output = VectorN; [val val] => &self * &rhs; @@ -130,7 +130,7 @@ md_impl_all!( // Transform × Point md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory where DefaultAllocator: Allocator; self: Transform, rhs: Point, Output = Point; @@ -156,7 +156,7 @@ md_impl_all!( // Transform × Transform md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: TCategoryMul, CB: TCategory; self: Transform, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.into_inner()); @@ -167,7 +167,7 @@ md_impl_all!( // Transform × Rotation md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategoryMul; self: Transform, rhs: Rotation, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); @@ -178,7 +178,7 @@ md_impl_all!( // Rotation × Transform md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (D, D), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul; self: Rotation, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); @@ -189,7 +189,7 @@ md_impl_all!( // Transform × UnitQuaternion md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (U4, U4), (U4, U1) for C: TCategoryMul; self: Transform, rhs: UnitQuaternion, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); @@ -200,7 +200,7 @@ md_impl_all!( // UnitQuaternion × Transform md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (U4, U1), (U4, U4) for C: TCategoryMul; self: UnitQuaternion, rhs: Transform, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); @@ -211,7 +211,7 @@ md_impl_all!( // Transform × Isometry md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; self: Transform, rhs: Isometry, Output = Transform; @@ -223,7 +223,7 @@ md_impl_all!( // Isometry × Transform md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (D, U1), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; self: Isometry, rhs: Transform, Output = Transform; @@ -235,7 +235,7 @@ md_impl_all!( // Transform × Similarity md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; self: Transform, rhs: Similarity, Output = Transform; @@ -247,7 +247,7 @@ md_impl_all!( // Similarity × Transform md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (D, U1), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> >; self: Similarity, rhs: Transform, Output = Transform; @@ -267,7 +267,7 @@ md_impl_all!( */ // Transform × Translation md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul; self: Transform, rhs: Translation, Output = Transform; [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); @@ -278,7 +278,7 @@ md_impl_all!( // Translation × Transform md_impl_all!( - Mul, mul where N: Real; + Mul, mul where N: RealField; (D, U1), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul; self: Translation, rhs: Transform, Output = Transform; @@ -290,7 +290,7 @@ md_impl_all!( // Transform ÷ Transform md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: TCategoryMul, CB: SubTCategoryOf; self: Transform, rhs: Transform, Output = Transform; [val val] => self * rhs.inverse(); @@ -301,7 +301,7 @@ md_impl_all!( // Transform ÷ Rotation md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategoryMul; self: Transform, rhs: Rotation, Output = Transform; [val val] => self * rhs.inverse(); @@ -312,7 +312,7 @@ md_impl_all!( // Rotation ÷ Transform md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (D, D), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul; self: Rotation, rhs: Transform, Output = Transform; [val val] => self.inverse() * rhs; @@ -323,7 +323,7 @@ md_impl_all!( // Transform ÷ UnitQuaternion md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (U4, U4), (U4, U1) for C: TCategoryMul; self: Transform, rhs: UnitQuaternion, Output = Transform; [val val] => self * rhs.inverse(); @@ -334,7 +334,7 @@ md_impl_all!( // UnitQuaternion ÷ Transform md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (U4, U1), (U4, U4) for C: TCategoryMul; self: UnitQuaternion, rhs: Transform, Output = Transform; [val val] => self.inverse() * rhs; @@ -345,7 +345,7 @@ md_impl_all!( // // Transform ÷ Isometry // md_impl_all!( -// Div, div where N: Real; +// Div, div where N: RealField; // (DimNameSum, DimNameSum), (D, U1) // for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SB::Alloc: Allocator, DimNameSum >; @@ -358,7 +358,7 @@ md_impl_all!( // // Isometry ÷ Transform // md_impl_all!( -// Div, div where N: Real; +// Div, div where N: RealField; // (D, U1), (DimNameSum, DimNameSum) // for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SA::Alloc: Allocator, DimNameSum >; @@ -371,7 +371,7 @@ md_impl_all!( // // Transform ÷ Similarity // md_impl_all!( -// Div, div where N: Real; +// Div, div where N: RealField; // (DimNameSum, DimNameSum), (D, U1) // for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SB::Alloc: Allocator @@ -385,7 +385,7 @@ md_impl_all!( // // Similarity ÷ Transform // md_impl_all!( -// Div, div where N: Real; +// Div, div where N: RealField; // (D, U1), (DimNameSum, DimNameSum) // for D: DimNameAdd, C: TCategoryMul, R: SubsetOf> > // where SA::Alloc: Allocator @@ -399,7 +399,7 @@ md_impl_all!( // Transform ÷ Translation md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategoryMul; self: Transform, rhs: Translation, Output = Transform; [val val] => self * rhs.inverse(); @@ -410,7 +410,7 @@ md_impl_all!( // Translation ÷ Transform md_impl_all!( - Div, div where N: Real; + Div, div where N: RealField; (D, U1), (DimNameSum, DimNameSum) for D: DimNameAdd, C: TCategoryMul; self: Translation, rhs: Transform, Output = Transform; @@ -422,7 +422,7 @@ md_impl_all!( // Transform ×= Transform md_assign_impl_all!( - MulAssign, mul_assign where N: Real; + MulAssign, mul_assign where N: RealField; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: TCategory, CB: SubTCategoryOf; self: Transform, rhs: Transform; [val] => *self.matrix_mut_unchecked() *= rhs.into_inner(); @@ -431,7 +431,7 @@ md_assign_impl_all!( // Transform ×= Similarity md_assign_impl_all!( - MulAssign, mul_assign where N: Real; + MulAssign, mul_assign where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory, R: SubsetOf> >; self: Transform, rhs: Similarity; @@ -441,7 +441,7 @@ md_assign_impl_all!( // Transform ×= Isometry md_assign_impl_all!( - MulAssign, mul_assign where N: Real; + MulAssign, mul_assign where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory, R: SubsetOf> >; self: Transform, rhs: Isometry; @@ -459,7 +459,7 @@ md_assign_impl_all!( */ // Transform ×= Translation md_assign_impl_all!( - MulAssign, mul_assign where N: Real; + MulAssign, mul_assign where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory; self: Transform, rhs: Translation; [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); @@ -468,7 +468,7 @@ md_assign_impl_all!( // Transform ×= Rotation md_assign_impl_all!( - MulAssign, mul_assign where N: Real; + MulAssign, mul_assign where N: RealField; (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategory; self: Transform, rhs: Rotation; [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); @@ -477,7 +477,7 @@ md_assign_impl_all!( // Transform ×= UnitQuaternion md_assign_impl_all!( - MulAssign, mul_assign where N: Real; + MulAssign, mul_assign where N: RealField; (U4, U4), (U4, U1) for C: TCategory; self: Transform, rhs: UnitQuaternion; [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); @@ -486,7 +486,7 @@ md_assign_impl_all!( // Transform ÷= Transform md_assign_impl_all!( - DivAssign, div_assign where N: Real; + DivAssign, div_assign where N: RealField; (DimNameSum, DimNameSum), (DimNameSum, DimNameSum) for D: DimNameAdd, CA: SuperTCategoryOf, CB: SubTCategoryOf; self: Transform, rhs: Transform; @@ -517,7 +517,7 @@ md_assign_impl_all!( // Transform ÷= Translation md_assign_impl_all!( - DivAssign, div_assign where N: Real; + DivAssign, div_assign where N: RealField; (DimNameSum, DimNameSum), (D, U1) for D: DimNameAdd, C: TCategory; self: Transform, rhs: Translation; [val] => *self *= rhs.inverse(); @@ -526,7 +526,7 @@ md_assign_impl_all!( // Transform ÷= Rotation md_assign_impl_all!( - DivAssign, div_assign where N: Real; + DivAssign, div_assign where N: RealField; (DimNameSum, DimNameSum), (D, D) for D: DimNameAdd, C: TCategory; self: Transform, rhs: Rotation; [val] => *self *= rhs.inverse(); @@ -535,7 +535,7 @@ md_assign_impl_all!( // Transform ÷= UnitQuaternion md_assign_impl_all!( - DivAssign, div_assign where N: Real; + DivAssign, div_assign where N: RealField; (U4, U4), (U4, U1) for C: TCategory; self: Transform, rhs: UnitQuaternion; [val] => *self *= rhs.inverse(); diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index a49b2706f..e64b3d2ea 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -11,14 +11,14 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{ClosedAdd, ClosedNeg, ClosedSub, Real}; +use alga::general::{ClosedAdd, ClosedNeg, ClosedSub, RealField}; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::storage::Owned; -use base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; -use geometry::Point; +use crate::geometry::Point; /// A translation. #[repr(C)] @@ -301,14 +301,14 @@ where * Display * */ -impl fmt::Display for Translation +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); - try!(writeln!(f, "Translation {{")); - try!(write!(f, "{:.*}", precision, self.vector)); + writeln!(f, "Translation {{")?; + write!(f, "{:.*}", precision, self.vector)?; writeln!(f, "}}") } } diff --git a/src/geometry/translation_alga.rs b/src/geometry/translation_alga.rs index c6157a170..134790f68 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, Real, + AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, }; use alga::linear::Translation as AlgaTranslation; use alga::linear::{ @@ -8,18 +8,18 @@ use alga::linear::{ Transformation, }; -use base::allocator::Allocator; -use base::dimension::DimName; -use base::{DefaultAllocator, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimName; +use crate::base::{DefaultAllocator, VectorN}; -use geometry::{Point, Translation}; +use crate::geometry::{Point, Translation}; /* * * Algebraic structures. * */ -impl Identity for Translation +impl Identity for Translation where DefaultAllocator: Allocator { #[inline] @@ -28,7 +28,7 @@ where DefaultAllocator: Allocator } } -impl TwoSidedInverse for Translation +impl TwoSidedInverse for Translation where DefaultAllocator: Allocator { #[inline] @@ -42,7 +42,7 @@ where DefaultAllocator: Allocator } } -impl AbstractMagma for Translation +impl AbstractMagma for Translation where DefaultAllocator: Allocator { #[inline] @@ -53,7 +53,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 { } )*} ); @@ -71,7 +71,7 @@ impl_multiplicative_structures!( * Transformation groups. * */ -impl Transformation> for Translation +impl Transformation> for Translation where DefaultAllocator: Allocator { #[inline] @@ -85,7 +85,7 @@ where DefaultAllocator: Allocator } } -impl ProjectiveTransformation> for Translation +impl ProjectiveTransformation> for Translation where DefaultAllocator: Allocator { #[inline] @@ -99,7 +99,7 @@ where DefaultAllocator: Allocator } } -impl AffineTransformation> for Translation +impl AffineTransformation> for Translation where DefaultAllocator: Allocator { type Rotation = Id; @@ -142,7 +142,7 @@ where DefaultAllocator: Allocator } } -impl Similarity> for Translation +impl Similarity> for Translation where DefaultAllocator: Allocator { type Scaling = Id; @@ -165,7 +165,7 @@ where DefaultAllocator: Allocator macro_rules! marker_impl( ($($Trait: ident),*) => {$( - impl $Trait> for Translation + impl $Trait> for Translation where DefaultAllocator: Allocator { } )*} ); @@ -173,7 +173,7 @@ macro_rules! marker_impl( marker_impl!(Isometry, DirectIsometry); /// Subgroups of the n-dimensional translation group `T(n)`. -impl AlgaTranslation> for Translation +impl AlgaTranslation> for Translation where DefaultAllocator: Allocator { #[inline] diff --git a/src/geometry/translation_alias.rs b/src/geometry/translation_alias.rs index 41885db7e..13db0495a 100644 --- a/src/geometry/translation_alias.rs +++ b/src/geometry/translation_alias.rs @@ -1,6 +1,6 @@ -use base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; -use geometry::Translation; +use crate::geometry::Translation; /// A 1-dimensional translation. pub type Translation1 = Translation; diff --git a/src/geometry/translation_construction.rs b/src/geometry/translation_construction.rs index a973603d9..339bdd2a6 100644 --- a/src/geometry/translation_construction.rs +++ b/src/geometry/translation_construction.rs @@ -1,5 +1,5 @@ #[cfg(feature = "arbitrary")] -use base::storage::Owned; +use crate::base::storage::Owned; #[cfg(feature = "arbitrary")] use quickcheck::{Arbitrary, Gen}; @@ -9,11 +9,11 @@ use rand::Rng; use alga::general::ClosedAdd; -use base::allocator::Allocator; -use base::dimension::{DimName, U1, U2, U3, U4, U5, U6}; -use base::{DefaultAllocator, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, U1, U2, U3, U4, U5, U6}; +use crate::base::{DefaultAllocator, Scalar, VectorN}; -use geometry::Translation; +use crate::geometry::Translation; impl Translation where DefaultAllocator: Allocator diff --git a/src/geometry/translation_conversion.rs b/src/geometry/translation_conversion.rs index d4fd9df2c..b44412e69 100644 --- a/src/geometry/translation_conversion.rs +++ b/src/geometry/translation_conversion.rs @@ -1,13 +1,13 @@ use num::{One, Zero}; -use alga::general::{Real, SubsetOf, SupersetOf}; +use alga::general::{RealField, SubsetOf, SupersetOf}; use alga::linear::Rotation; -use base::allocator::Allocator; -use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; -use geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; +use crate::geometry::{Isometry, Point, Similarity, SuperTCategoryOf, TAffine, Transform, Translation}; /* * This file provides the following conversions: @@ -33,7 +33,7 @@ where #[inline] fn is_in_subset(rot: &Translation) -> bool { - ::is_convertible::<_, VectorN>(&rot.vector) + crate::is_convertible::<_, VectorN>(&rot.vector) } #[inline] @@ -46,8 +46,8 @@ where impl SubsetOf> for Translation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: Rotation>, DefaultAllocator: Allocator + Allocator, { @@ -69,8 +69,8 @@ where impl SubsetOf> for Translation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: Rotation>, DefaultAllocator: Allocator + Allocator, { @@ -92,8 +92,8 @@ where impl SubsetOf> for Translation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, C: SuperTCategoryOf, D: DimNameAdd, DefaultAllocator: Allocator @@ -119,8 +119,8 @@ where impl SubsetOf>> for Translation where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, D: DimNameAdd, DefaultAllocator: Allocator + Allocator @@ -148,7 +148,7 @@ where unsafe fn from_superset_unchecked(m: &MatrixN>) -> Self { let t = m.fixed_slice::(0, D::dim()); Self { - vector: ::convert_unchecked(t.into_owned()), + vector: crate::convert_unchecked(t.into_owned()), } } } diff --git a/src/geometry/translation_coordinates.rs b/src/geometry/translation_coordinates.rs index 01207a32e..c422415c5 100644 --- a/src/geometry/translation_coordinates.rs +++ b/src/geometry/translation_coordinates.rs @@ -1,12 +1,12 @@ use std::mem; use std::ops::{Deref, DerefMut}; -use base::allocator::Allocator; -use base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; -use base::dimension::{U1, U2, U3, U4, U5, U6}; -use base::{DefaultAllocator, Scalar}; +use crate::base::allocator::Allocator; +use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::{DefaultAllocator, Scalar}; -use geometry::Translation; +use crate::geometry::Translation; /* * diff --git a/src/geometry/translation_ops.rs b/src/geometry/translation_ops.rs index 57b8d6d16..55366a057 100644 --- a/src/geometry/translation_ops.rs +++ b/src/geometry/translation_ops.rs @@ -2,12 +2,12 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; use alga::general::{ClosedAdd, ClosedSub}; -use base::allocator::{Allocator, SameShapeAllocator}; -use base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; -use base::dimension::{DimName, U1}; -use base::{DefaultAllocator, Scalar}; +use crate::base::allocator::{Allocator, SameShapeAllocator}; +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{DimName, U1}; +use crate::base::{DefaultAllocator, Scalar}; -use geometry::{Point, Translation}; +use crate::geometry::{Point, Translation}; // Translation × Translation add_sub_impl!(Mul, mul, ClosedAdd; diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index a54626e0d..7ba7f3740 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -2,14 +2,14 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_complex::Complex; use std::fmt; -use alga::general::Real; -use base::{Matrix2, Matrix3, Unit, Vector1, Vector2}; -use geometry::{Rotation2, Point2}; +use alga::general::RealField; +use crate::base::{Matrix2, Matrix3, Unit, Vector1, Vector2}; +use crate::geometry::{Rotation2, Point2}; /// A complex number with a norm equal to 1. pub type UnitComplex = Unit>; -impl UnitComplex { +impl UnitComplex { /// The rotation angle in `]-pi; pi]` of this unit complex number. /// /// # Example @@ -323,13 +323,13 @@ impl UnitComplex { } } -impl fmt::Display for UnitComplex { +impl fmt::Display for UnitComplex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UnitComplex angle: {}", self.angle()) } } -impl AbsDiffEq for UnitComplex { +impl AbsDiffEq for UnitComplex { type Epsilon = N; #[inline] @@ -343,7 +343,7 @@ impl AbsDiffEq for UnitComplex { } } -impl RelativeEq for UnitComplex { +impl RelativeEq for UnitComplex { #[inline] fn default_max_relative() -> Self::Epsilon { N::default_max_relative() @@ -362,7 +362,7 @@ impl RelativeEq for UnitComplex { } } -impl UlpsEq for UnitComplex { +impl UlpsEq for UnitComplex { #[inline] fn default_max_ulps() -> u32 { N::default_max_ulps() diff --git a/src/geometry/unit_complex_alga.rs b/src/geometry/unit_complex_alga.rs index a52ea4e86..24b552339 100755 --- a/src/geometry/unit_complex_alga.rs +++ b/src/geometry/unit_complex_alga.rs @@ -1,37 +1,37 @@ use alga::general::{ AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, - AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, Real, + AbstractSemigroup, Id, Identity, TwoSidedInverse, Multiplicative, RealField, }; use alga::linear::{ AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, ProjectiveTransformation, Rotation, Similarity, Transformation, }; -use base::allocator::Allocator; -use base::dimension::U2; -use base::{DefaultAllocator, Vector2}; -use geometry::{Point2, UnitComplex}; +use crate::base::allocator::Allocator; +use crate::base::dimension::U2; +use crate::base::{DefaultAllocator, Vector2}; +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] fn two_sided_inverse(&self) -> Self { self.inverse() @@ -45,7 +45,7 @@ impl TwoSidedInverse for UnitComplex { macro_rules! impl_structures( ($($marker: ident<$operator: ident>),* $(,)*) => {$( - impl $marker<$operator> for UnitComplex { + impl $marker<$operator> for UnitComplex { } )*} ); @@ -58,7 +58,7 @@ impl_structures!( AbstractGroup ); -impl Transformation> for UnitComplex +impl Transformation> for UnitComplex where DefaultAllocator: Allocator { #[inline] @@ -72,7 +72,7 @@ where DefaultAllocator: Allocator } } -impl ProjectiveTransformation> for UnitComplex +impl ProjectiveTransformation> for UnitComplex where DefaultAllocator: Allocator { #[inline] @@ -86,7 +86,7 @@ where DefaultAllocator: Allocator } } -impl AffineTransformation> for UnitComplex +impl AffineTransformation> for UnitComplex where DefaultAllocator: Allocator { type Rotation = Self; @@ -129,7 +129,7 @@ where DefaultAllocator: Allocator } } -impl Similarity> for UnitComplex +impl Similarity> for UnitComplex where DefaultAllocator: Allocator { type Scaling = Id; @@ -152,14 +152,14 @@ 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 +impl Rotation> for UnitComplex where DefaultAllocator: Allocator { #[inline] diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index ba1d6694b..046142c8a 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -6,13 +6,13 @@ use num_complex::Complex; use rand::distributions::{Distribution, OpenClosed01, Standard}; use rand::Rng; -use alga::general::Real; -use base::dimension::{U1, U2}; -use base::storage::Storage; -use base::{Unit, Vector, Matrix2}; -use geometry::{Rotation2, UnitComplex}; +use alga::general::RealField; +use crate::base::dimension::{U1, U2}; +use crate::base::storage::Storage; +use crate::base::{Unit, Vector, Matrix2}; +use crate::geometry::{Rotation2, UnitComplex}; -impl UnitComplex { +impl UnitComplex { /// The unit complex number multiplicative identity. /// /// # Example @@ -268,14 +268,14 @@ impl UnitComplex { } } -impl One for UnitComplex { +impl One for UnitComplex { #[inline] fn one() -> Self { Self::identity() } } -impl Distribution> for Standard +impl Distribution> for Standard where OpenClosed01: Distribution { /// Generate a uniformly distributed random `UnitComplex`. @@ -286,7 +286,7 @@ where OpenClosed01: Distribution } #[cfg(feature = "arbitrary")] -impl Arbitrary for UnitComplex { +impl Arbitrary for UnitComplex { #[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 1751a67cb..f7fe45321 100644 --- a/src/geometry/unit_complex_conversion.rs +++ b/src/geometry/unit_complex_conversion.rs @@ -1,12 +1,12 @@ use num::Zero; use num_complex::Complex; -use alga::general::{Real, SubsetOf, SupersetOf}; +use alga::general::{RealField, SubsetOf, SupersetOf}; use alga::linear::Rotation as AlgaRotation; -use base::dimension::U2; -use base::{Matrix2, Matrix3}; -use geometry::{ +use crate::base::dimension::U2; +use crate::base::{Matrix2, Matrix3}; +use crate::geometry::{ Isometry, Point2, Rotation2, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, UnitComplex }; @@ -28,8 +28,8 @@ use geometry::{ impl SubsetOf> for UnitComplex where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> UnitComplex { @@ -38,19 +38,19 @@ where #[inline] fn is_in_subset(uq: &UnitComplex) -> bool { - ::is_convertible::<_, Complex>(uq.as_ref()) + crate::is_convertible::<_, Complex>(uq.as_ref()) } #[inline] unsafe fn from_superset_unchecked(uq: &UnitComplex) -> Self { - Self::new_unchecked(::convert_ref_unchecked(uq.as_ref())) + Self::new_unchecked(crate::convert_ref_unchecked(uq.as_ref())) } } impl SubsetOf> for UnitComplex where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, { #[inline] fn to_superset(&self) -> Rotation2 { @@ -60,25 +60,25 @@ where #[inline] fn is_in_subset(rot: &Rotation2) -> bool { - ::is_convertible::<_, Rotation2>(rot) + crate::is_convertible::<_, Rotation2>(rot) } #[inline] unsafe fn from_superset_unchecked(rot: &Rotation2) -> Self { let q = UnitComplex::::from_rotation_matrix(rot); - ::convert_unchecked(q) + crate::convert_unchecked(q) } } impl SubsetOf> for UnitComplex where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: AlgaRotation> + SupersetOf, { #[inline] fn to_superset(&self) -> Isometry { - Isometry::from_parts(Translation::identity(), ::convert_ref(self)) + Isometry::from_parts(Translation::identity(), crate::convert_ref(self)) } #[inline] @@ -88,19 +88,19 @@ where #[inline] unsafe fn from_superset_unchecked(iso: &Isometry) -> Self { - ::convert_ref_unchecked(&iso.rotation) + crate::convert_ref_unchecked(&iso.rotation) } } impl SubsetOf> for UnitComplex where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, R: AlgaRotation> + SupersetOf, { #[inline] fn to_superset(&self) -> Similarity { - Similarity::from_isometry(::convert_ref(self), N2::one()) + Similarity::from_isometry(crate::convert_ref(self), N2::one()) } #[inline] @@ -110,14 +110,14 @@ where #[inline] unsafe fn from_superset_unchecked(sim: &Similarity) -> Self { - ::convert_ref_unchecked(&sim.isometry) + crate::convert_ref_unchecked(&sim.isometry) } } impl SubsetOf> for UnitComplex where - N1: Real, - N2: Real + SupersetOf, + N1: RealField, + N2: RealField + SupersetOf, C: SuperTCategoryOf, { #[inline] @@ -136,7 +136,7 @@ where } } -impl> SubsetOf> for UnitComplex { +impl> SubsetOf> for UnitComplex { #[inline] fn to_superset(&self) -> Matrix3 { self.to_homogeneous().to_superset() @@ -144,39 +144,39 @@ impl> SubsetOf> for UnitComplex< #[inline] fn is_in_subset(m: &Matrix3) -> bool { - ::is_convertible::<_, Rotation2>(m) + crate::is_convertible::<_, Rotation2>(m) } #[inline] unsafe fn from_superset_unchecked(m: &Matrix3) -> Self { - let rot: Rotation2 = ::convert_ref_unchecked(m); + let rot: Rotation2 = crate::convert_ref_unchecked(m); Self::from_rotation_matrix(&rot) } } -impl From> for Rotation2 { +impl From> for Rotation2 { #[inline] fn from(q: UnitComplex) -> Self { q.to_rotation_matrix() } } -impl From> for UnitComplex { +impl From> for UnitComplex { #[inline] fn from(q: Rotation2) -> Self { Self::from_rotation_matrix(&q) } } -impl From> for Matrix3 { +impl From> for Matrix3 { #[inline] fn from(q: UnitComplex) -> Matrix3 { q.to_homogeneous() } } -impl From> for Matrix2 { +impl From> for Matrix2 { #[inline] fn from(q: UnitComplex) -> Self { q.to_rotation_matrix().into_inner() diff --git a/src/geometry/unit_complex_ops.rs b/src/geometry/unit_complex_ops.rs index 75b45eda0..11ffdc4af 100644 --- a/src/geometry/unit_complex_ops.rs +++ b/src/geometry/unit_complex_ops.rs @@ -1,12 +1,11 @@ use std::ops::{Div, DivAssign, Mul, MulAssign}; -use alga::general::Real; -use base::allocator::Allocator; -use base::constraint::{DimEq, ShapeConstraint}; -use base::dimension::{Dim, U1, U2}; -use base::storage::{Storage, StorageMut}; -use base::{DefaultAllocator, Matrix, Unit, Vector, Vector2}; -use geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex}; +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}; /* * This file provides: @@ -45,7 +44,7 @@ use geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex} */ // UnitComplex × UnitComplex -impl Mul for UnitComplex { +impl Mul for UnitComplex { type Output = Self; #[inline] @@ -54,7 +53,7 @@ impl Mul for UnitComplex { } } -impl<'a, N: Real> Mul> for &'a UnitComplex { +impl<'a, N: RealField> Mul> for &'a UnitComplex { type Output = UnitComplex; #[inline] @@ -63,7 +62,7 @@ impl<'a, N: Real> Mul> for &'a UnitComplex { } } -impl<'b, N: Real> Mul<&'b UnitComplex> for UnitComplex { +impl<'b, N: RealField> Mul<&'b UnitComplex> for UnitComplex { type Output = Self; #[inline] @@ -72,7 +71,7 @@ impl<'b, N: Real> Mul<&'b UnitComplex> for UnitComplex { } } -impl<'a, 'b, N: Real> Mul<&'b UnitComplex> for &'a UnitComplex { +impl<'a, 'b, N: RealField> Mul<&'b UnitComplex> for &'a UnitComplex { type Output = UnitComplex; #[inline] @@ -82,7 +81,7 @@ impl<'a, 'b, N: Real> Mul<&'b UnitComplex> for &'a UnitComplex { } // UnitComplex ÷ UnitComplex -impl Div for UnitComplex { +impl Div for UnitComplex { type Output = Self; #[inline] @@ -91,7 +90,7 @@ impl Div for UnitComplex { } } -impl<'a, N: Real> Div> for &'a UnitComplex { +impl<'a, N: RealField> Div> for &'a UnitComplex { type Output = UnitComplex; #[inline] @@ -100,7 +99,7 @@ impl<'a, N: Real> Div> for &'a UnitComplex { } } -impl<'b, N: Real> Div<&'b UnitComplex> for UnitComplex { +impl<'b, N: RealField> Div<&'b UnitComplex> for UnitComplex { type Output = Self; #[inline] @@ -109,7 +108,7 @@ impl<'b, N: Real> Div<&'b UnitComplex> for UnitComplex { } } -impl<'a, 'b, N: Real> Div<&'b UnitComplex> for &'a UnitComplex { +impl<'a, 'b, N: RealField> Div<&'b UnitComplex> for &'a UnitComplex { type Output = UnitComplex; #[inline] @@ -123,7 +122,7 @@ 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: Real $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + impl<$($lives ,)* N: RealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs where DefaultAllocator: Allocator { type Output = $Result; @@ -301,14 +300,14 @@ complex_op_impl_all!( ); // UnitComplex ×= UnitComplex -impl MulAssign> for UnitComplex { +impl MulAssign> for UnitComplex { #[inline] fn mul_assign(&mut self, rhs: UnitComplex) { *self = &*self * rhs } } -impl<'b, N: Real> MulAssign<&'b UnitComplex> for UnitComplex { +impl<'b, N: RealField> MulAssign<&'b UnitComplex> for UnitComplex { #[inline] fn mul_assign(&mut self, rhs: &'b UnitComplex) { *self = &*self * rhs @@ -316,14 +315,14 @@ impl<'b, N: Real> MulAssign<&'b UnitComplex> for UnitComplex { } // UnitComplex /= UnitComplex -impl DivAssign> for UnitComplex { +impl DivAssign> for UnitComplex { #[inline] fn div_assign(&mut self, rhs: UnitComplex) { *self = &*self / rhs } } -impl<'b, N: Real> DivAssign<&'b UnitComplex> for UnitComplex { +impl<'b, N: RealField> DivAssign<&'b UnitComplex> for UnitComplex { #[inline] fn div_assign(&mut self, rhs: &'b UnitComplex) { *self = &*self / rhs @@ -331,7 +330,7 @@ impl<'b, N: Real> DivAssign<&'b UnitComplex> for UnitComplex { } // UnitComplex ×= Rotation -impl MulAssign> for UnitComplex +impl MulAssign> for UnitComplex where DefaultAllocator: Allocator { #[inline] @@ -340,7 +339,7 @@ where DefaultAllocator: Allocator } } -impl<'b, N: Real> MulAssign<&'b Rotation> for UnitComplex +impl<'b, N: RealField> MulAssign<&'b Rotation> for UnitComplex where DefaultAllocator: Allocator { #[inline] @@ -350,7 +349,7 @@ where DefaultAllocator: Allocator } // UnitComplex ÷= Rotation -impl DivAssign> for UnitComplex +impl DivAssign> for UnitComplex where DefaultAllocator: Allocator { #[inline] @@ -359,7 +358,7 @@ where DefaultAllocator: Allocator } } -impl<'b, N: Real> DivAssign<&'b Rotation> for UnitComplex +impl<'b, N: RealField> DivAssign<&'b Rotation> for UnitComplex where DefaultAllocator: Allocator { #[inline] @@ -369,7 +368,7 @@ where DefaultAllocator: Allocator } // Rotation ×= UnitComplex -impl MulAssign> for Rotation +impl MulAssign> for Rotation where DefaultAllocator: Allocator { #[inline] @@ -378,7 +377,7 @@ where DefaultAllocator: Allocator } } -impl<'b, N: Real> MulAssign<&'b UnitComplex> for Rotation +impl<'b, N: RealField> MulAssign<&'b UnitComplex> for Rotation where DefaultAllocator: Allocator { #[inline] @@ -388,7 +387,7 @@ where DefaultAllocator: Allocator } // Rotation ÷= UnitComplex -impl DivAssign> for Rotation +impl DivAssign> for Rotation where DefaultAllocator: Allocator { #[inline] @@ -397,67 +396,11 @@ where DefaultAllocator: Allocator } } -impl<'b, N: Real> DivAssign<&'b UnitComplex> for Rotation +impl<'b, N: RealField> DivAssign<&'b UnitComplex> for Rotation where DefaultAllocator: Allocator { #[inline] fn div_assign(&mut self, rhs: &'b UnitComplex) { self.div_assign(rhs.to_rotation_matrix()) } -} - -// Matrix = UnitComplex * Matrix -impl UnitComplex { - /// Performs the multiplication `rhs = self * rhs` in-place. - pub fn rotate>( - &self, - rhs: &mut Matrix, - ) where - ShapeConstraint: DimEq, - { - assert_eq!( - rhs.nrows(), - 2, - "Unit complex rotation: the input matrix must have exactly two rows." - ); - let i = self.as_ref().im; - let r = self.as_ref().re; - - for j in 0..rhs.ncols() { - unsafe { - let a = *rhs.get_unchecked((0, j)); - let b = *rhs.get_unchecked((1, j)); - - *rhs.get_unchecked_mut((0, j)) = r * a - i * b; - *rhs.get_unchecked_mut((1, j)) = i * a + r * b; - } - } - } - - /// Performs the multiplication `lhs = lhs * self` in-place. - pub fn rotate_rows>( - &self, - lhs: &mut Matrix, - ) where - ShapeConstraint: DimEq, - { - assert_eq!( - lhs.ncols(), - 2, - "Unit complex rotation: the input matrix must have exactly two columns." - ); - let i = self.as_ref().im; - let r = self.as_ref().re; - - // FIXME: can we optimize that to iterate on one column at a time ? - for j in 0..lhs.nrows() { - unsafe { - let a = *lhs.get_unchecked((j, 0)); - let b = *lhs.get_unchecked((j, 1)); - - *lhs.get_unchecked_mut((j, 0)) = r * a + i * b; - *lhs.get_unchecked_mut((j, 1)) = -i * a + r * b; - } - } - } -} +} \ No newline at end of file diff --git a/src/io/matrix_market.rs b/src/io/matrix_market.rs index f4919cd44..f0e817a11 100644 --- a/src/io/matrix_market.rs +++ b/src/io/matrix_market.rs @@ -2,8 +2,8 @@ use std::fs; use std::path::Path; use pest::Parser; -use sparse::CsMatrix; -use Real; +use crate::sparse::CsMatrix; +use crate::RealField; #[derive(Parser)] #[grammar = "io/matrix_market.pest"] @@ -11,14 +11,14 @@ struct MatrixMarketParser; // FIXME: return an Error instead of an Option. /// Parses a Matrix Market file at the given path, and returns the corresponding sparse matrix. -pub fn cs_matrix_from_matrix_market>(path: P) -> Option> { +pub fn cs_matrix_from_matrix_market>(path: P) -> Option> { let file = fs::read_to_string(path).ok()?; cs_matrix_from_matrix_market_str(&file) } // FIXME: return an Error instead of an Option. /// Parses a Matrix Market file described by the given string, and returns the corresponding sparse matrix. -pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option> { +pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option> { let file = MatrixMarketParser::parse(Rule::Document, data) .unwrap() .next()?; @@ -41,7 +41,7 @@ pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option().ok()? - 1); cols.push(inner.next()?.as_str().parse::().ok()? - 1); - data.push(::convert(inner.next()?.as_str().parse::().ok()?)); + data.push(crate::convert(inner.next()?.as_str().parse::().ok()?)); } _ => return None, // FIXME: return an Err instead. } diff --git a/src/lib.rs b/src/lib.rs index 80149c7c2..6667ee5a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,8 +4,8 @@ **nalgebra** is a linear algebra library written for Rust targeting: * General-purpose linear algebra (still lacks a lot of features…) -* Real time computer graphics. -* Real time computer physics. +* RealField time computer graphics. +* RealField time computer physics. ## Using **nalgebra** You will need the last stable build of the [rust compiler](http://www.rust-lang.org) @@ -51,7 +51,7 @@ an optimized set of tools for computer graphics and physics. Those features incl allocated on the heap. * Convenient aliases for low-dimensional matrices and vectors: `Vector1` to `Vector6` and `Matrix1x1` to `Matrix6x6`, including rectangular matrices like `Matrix2x5`. -* Points sizes known at compile time, and convenience aliases: `Point1` to `Point6`. +* Points sizes known at compile time, and convenience aliases:: `Point1` to `Point6`. * Translation (seen as a transformation that composes by multiplication): `Translation2`, `Translation3`. * Rotation matrices: `Rotation2`, `Rotation3`. @@ -66,7 +66,7 @@ an optimized set of tools for computer graphics and physics. Those features incl * General transformations that does not have to be invertible, stored as an homogeneous matrix: `Transform2`, `Transform3`. * 3D projections for computer graphics: `Perspective3`, `Orthographic3`. -* Matrix factorizations: `Cholesky`, `QR`, `LU`, `FullPivLU`, `SVD`, `RealSchur`, `Hessenberg`, `SymmetricEigen`. +* 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. @@ -144,11 +144,11 @@ pub mod sparse; note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate." )] pub use base as core; -pub use base::*; -pub use geometry::*; -pub use linalg::*; +pub use crate::base::*; +pub use crate::geometry::*; +pub use crate::linalg::*; #[cfg(feature = "sparse")] -pub use sparse::*; +pub use crate::sparse::*; use std::cmp::{self, Ordering, PartialOrd}; @@ -160,7 +160,10 @@ use alga::linear::SquareMatrix as AlgaSquareMatrix; use alga::linear::{EuclideanSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace}; use num::Signed; -pub use alga::general::{Id, Real}; +pub use alga::general::{Id, RealField, ComplexField}; +#[allow(deprecated)] +pub use alga::general::Real; +pub use num_complex::Complex; /* * @@ -170,6 +173,7 @@ pub use alga::general::{Id, Real}; /// Gets the ubiquitous multiplicative identity element. /// /// Same as `Id::new()`. +#[deprecated(note = "use `Id::new()` instead.")] #[inline] pub fn id() -> Id { Id::new() @@ -296,8 +300,8 @@ pub fn min(a: T, b: T) -> T { /// The absolute value of `a`. /// -/// Deprecated: Use [Matrix::abs] or [Real::abs] instead. -#[deprecated(note = "use `Matrix::abs` or `Real::abs` instead")] +/// Deprecated: Use [Matrix::abs] or [RealField::abs] instead. +#[deprecated(note = "use `Matrix::abs` or `RealField::abs` instead")] #[inline] pub fn abs(a: &T) -> T { a.abs() @@ -416,6 +420,7 @@ pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &' /// # 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() @@ -426,6 +431,7 @@ pub fn try_inverse(m: &M) -> Option { /// # 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() @@ -457,7 +463,7 @@ pub fn dot(a: &V, b: &V) -> V::Field { /// 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::Real { +pub fn angle(a: &V, b: &V) -> V::RealField { a.angle(b) } @@ -481,7 +487,7 @@ pub fn angle(a: &V, b: &V) -> V::Real { /// 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::Field { +pub fn norm(v: &V) -> V::RealField { v.norm() } @@ -501,7 +507,7 @@ pub fn norm(v: &V) -> V::Field { /// 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::Field { +pub fn norm_squared(v: &V) -> V::RealField { v.norm_squared() } @@ -521,7 +527,7 @@ pub fn norm_squared(v: &V) -> V::Field { /// 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::Field { +pub fn magnitude(v: &V) -> V::RealField { v.norm() } @@ -542,7 +548,7 @@ pub fn magnitude(v: &V) -> V::Field { /// 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::Field { +pub fn magnitude_squared(v: &V) -> V::RealField { v.norm_squared() } @@ -570,7 +576,7 @@ pub fn normalize(v: &V) -> V { /// 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::Field) -> Option { +pub fn try_normalize(v: &V, min_norm: V::RealField) -> Option { v.try_normalize(min_norm) } @@ -597,7 +603,7 @@ 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::Real { +pub fn distance(p1: &P, p2: &P) -> P::RealField { (p2.coordinates() - p1.coordinates()).norm() } @@ -608,7 +614,7 @@ pub fn distance(p1: &P, p2: &P) -> P::Real { /// * [center](fn.center.html) /// * [distance](fn.distance.html) #[inline] -pub fn distance_squared(p1: &P, p2: &P) -> P::Real { +pub fn distance_squared(p1: &P, p2: &P) -> P::RealField { (p2.coordinates() - p1.coordinates()).norm_squared() } diff --git a/src/linalg/balancing.rs b/src/linalg/balancing.rs index 5db113bae..e8abbefb2 100644 --- a/src/linalg/balancing.rs +++ b/src/linalg/balancing.rs @@ -1,23 +1,23 @@ //! Functions for balancing a matrix. -use alga::general::Real; +use alga::general::RealField; use std::ops::{DivAssign, MulAssign}; -use allocator::Allocator; -use base::dimension::{Dim, U1}; -use base::storage::Storage; -use base::{DefaultAllocator, MatrixN, VectorN}; +use crate::allocator::Allocator; +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, MatrixN, VectorN}; /// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix `m` and returns /// the corresponding diagonal transformation. /// /// See https://arxiv.org/pdf/1401.5766.pdf -pub fn balance_parlett_reinsch(m: &mut MatrixN) -> VectorN +pub fn balance_parlett_reinsch(m: &mut MatrixN) -> VectorN where DefaultAllocator: Allocator + Allocator { assert!(m.is_square(), "Unable to balance a non-square matrix."); let dim = m.data.shape().0; - let radix: N = ::convert(2.0f64); + let radix: N = crate::convert(2.0f64); let mut d = VectorN::from_element_generic(dim, U1, N::one()); let mut converged = false; @@ -50,7 +50,7 @@ where DefaultAllocator: Allocator + Allocator { f /= radix; } - let eps: N = ::convert(0.95); + let eps: N = crate::convert(0.95); if c * c + r * r < eps * s { converged = false; d[i] *= f; @@ -64,7 +64,7 @@ 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) +pub fn unbalance(m: &mut MatrixN, d: &VectorN) 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 3e73c40f4..f766c91eb 100644 --- a/src/linalg/bidiagonal.rs +++ b/src/linalg/bidiagonal.rs @@ -1,15 +1,14 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Unit, VectorN}; -use constraint::{DimEq, ShapeConstraint}; -use dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, Dynamic, U1}; -use storage::Storage; +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 geometry::Reflection; -use linalg::householder; +use crate::geometry::Reflection; +use crate::linalg::householder; /// The bidiagonalization of a general matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -38,7 +37,7 @@ use linalg::householder; )) )] #[derive(Clone, Debug)] -pub struct Bidiagonal, C: Dim> +pub struct Bidiagonal, C: Dim> where DimMinimum: DimSub, DefaultAllocator: Allocator @@ -49,13 +48,13 @@ where // contiguous. This prevents some useless copies. uv: MatrixMN, /// The diagonal elements of the decomposed matrix. - pub diagonal: VectorN>, + diagonal: VectorN>, /// The off-diagonal elements of the decomposed matrix. - pub off_diagonal: VectorN, U1>>, + off_diagonal: VectorN, U1>>, upper_diagonal: bool, } -impl, C: Dim> Copy for Bidiagonal +impl, C: Dim> Copy for Bidiagonal where DimMinimum: DimSub, DefaultAllocator: Allocator @@ -66,7 +65,7 @@ where VectorN, U1>>: Copy, {} -impl, C: Dim> Bidiagonal +impl, C: Dim> Bidiagonal where DimMinimum: DimSub, DefaultAllocator: Allocator @@ -143,9 +142,9 @@ where Bidiagonal { uv: matrix, - diagonal: diagonal, - off_diagonal: off_diagonal, - upper_diagonal: upper_diagonal, + diagonal, + off_diagonal, + upper_diagonal, } } @@ -179,9 +178,6 @@ where DefaultAllocator: Allocator, DimMinimum> + Allocator> + Allocator, C>, - // FIXME: the following bounds are ugly. - DimMinimum: DimMin, Output = DimMinimum>, - ShapeConstraint: DimEq, U1>>, { // FIXME: optimize by calling a reallocator. (self.u(), self.d(), self.v_t()) @@ -192,19 +188,16 @@ where pub fn d(&self) -> MatrixN> where DefaultAllocator: Allocator, DimMinimum>, - // FIXME: the following bounds are ugly. - DimMinimum: DimMin, Output = DimMinimum>, - ShapeConstraint: DimEq, U1>>, { let (nrows, ncols) = self.uv.data.shape(); let d = nrows.min(ncols); let mut res = MatrixN::identity_generic(d, d); - res.set_diagonal(&self.diagonal); + res.set_partial_diagonal(self.diagonal.iter().map(|e| N::from_real(e.modulus()))); let start = self.axis_shift(); res.slice_mut(start, (d.value() - 1, d.value() - 1)) - .set_diagonal(&self.off_diagonal); + .set_partial_diagonal(self.off_diagonal.iter().map(|e| N::from_real(e.modulus()))); res } @@ -225,13 +218,20 @@ where let refl = Reflection::new(Unit::new_unchecked(axis), N::zero()); let mut res_rows = res.slice_range_mut(i + shift.., i..); - refl.reflect(&mut res_rows); + + let sign = if self.upper_diagonal { + self.diagonal[i].signum() + } else { + self.off_diagonal[i].signum() + }; + + refl.reflect_with_sign(&mut res_rows, sign); } res } - /// Computes the orthogonal matrix `V` of this `U * D * V` decomposition. + /// Computes the orthogonal matrix `V_t` of this `U * D * V_t` decomposition. pub fn v_t(&self) -> MatrixMN, C> where DefaultAllocator: Allocator, C> { let (nrows, ncols) = self.uv.data.shape(); @@ -251,20 +251,29 @@ where let refl = Reflection::new(Unit::new_unchecked(axis_packed), N::zero()); let mut res_rows = res.slice_range_mut(i.., i + shift..); - refl.reflect_rows(&mut res_rows, &mut work.rows_range_mut(i..)); + + let sign = if self.upper_diagonal { + self.off_diagonal[i].signum() + } else { + self.diagonal[i].signum() + }; + + refl.reflect_rows_with_sign(&mut res_rows, &mut work.rows_range_mut(i..), sign); } res } /// The diagonal part of this decomposed matrix. - pub fn diagonal(&self) -> &VectorN> { - &self.diagonal + pub fn diagonal(&self) -> VectorN> + where DefaultAllocator: Allocator> { + self.diagonal.map(|e| e.modulus()) } /// The off-diagonal part of this decomposed matrix. - pub fn off_diagonal(&self) -> &VectorN, U1>> { - &self.off_diagonal + pub fn off_diagonal(&self) -> VectorN, U1>> + where DefaultAllocator: Allocator, U1>> { + self.off_diagonal.map(|e| e.modulus()) } #[doc(hidden)] @@ -273,7 +282,7 @@ where } } -// impl + DimSub> Bidiagonal +// impl + DimSub> Bidiagonal // where DefaultAllocator: Allocator + // Allocator { // /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. @@ -346,7 +355,7 @@ where // // } // } -impl, C: Dim, S: Storage> Matrix +impl, C: Dim, S: Storage> Matrix where DimMinimum: DimSub, DefaultAllocator: Allocator diff --git a/src/linalg/cholesky.rs b/src/linalg/cholesky.rs index c1fd7b853..0b6e6db59 100644 --- a/src/linalg/cholesky.rs +++ b/src/linalg/cholesky.rs @@ -1,13 +1,13 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::Real; +use alga::general::ComplexField; -use allocator::Allocator; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix}; -use constraint::{SameNumberOfRows, ShapeConstraint}; -use dimension::{Dim, DimSub, Dynamic}; -use storage::{Storage, StorageMut}; +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Dim, DimSub, Dynamic}; +use crate::storage::{Storage, StorageMut}; /// The Cholesky decomposition of a symmetric-definite-positive matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -26,19 +26,19 @@ use storage::{Storage, StorageMut}; )) )] #[derive(Clone, Debug)] -pub struct Cholesky +pub struct Cholesky where DefaultAllocator: Allocator { chol: MatrixN, } -impl Copy for Cholesky +impl Copy for Cholesky where DefaultAllocator: Allocator, MatrixN: Copy, {} -impl> Cholesky +impl> Cholesky where DefaultAllocator: Allocator { /// Attempts to compute the Cholesky decomposition of `matrix`. @@ -58,21 +58,25 @@ where DefaultAllocator: Allocator let mut col_j = col_j.rows_range_mut(j..); let col_k = col_k.rows_range(j..); - col_j.axpy(factor, &col_k, N::one()); + col_j.axpy(factor.conjugate(), &col_k, N::one()); } let diag = unsafe { *matrix.get_unchecked((j, j)) }; - if diag > N::zero() { - let denom = diag.sqrt(); - unsafe { - *matrix.get_unchecked_mut((j, j)) = denom; + if !diag.is_zero() { + if let Some(denom) = diag.try_sqrt() { + unsafe { + *matrix.get_unchecked_mut((j, j)) = denom; + } + + let mut col = matrix.slice_range_mut(j + 1.., j); + col /= denom; + continue; } - - let mut col = matrix.slice_range_mut(j + 1.., j); - col /= denom; - } else { - return None; } + + // The diagonal element is either zero or its square root could not + // be taken (e.g. for negative real numbers). + return None; } Some(Cholesky { chol: matrix }) @@ -118,7 +122,7 @@ where DefaultAllocator: Allocator ShapeConstraint: SameNumberOfRows, { let _ = self.chol.solve_lower_triangular_mut(b); - let _ = self.chol.tr_solve_lower_triangular_mut(b); + let _ = self.chol.ad_solve_lower_triangular_mut(b); } /// Returns the solution of the system `self * x = b` where `self` is the decomposed matrix and @@ -144,7 +148,7 @@ where DefaultAllocator: Allocator } } -impl, S: Storage> SquareMatrix +impl, S: Storage> SquareMatrix where DefaultAllocator: Allocator { /// Attempts to compute the Cholesky decomposition of this matrix. diff --git a/src/linalg/convolution.rs b/src/linalg/convolution.rs index b121b34ab..3f934eda1 100644 --- a/src/linalg/convolution.rs +++ b/src/linalg/convolution.rs @@ -1,11 +1,12 @@ -use base::allocator::Allocator; -use base::default_allocator::DefaultAllocator; -use base::dimension::{Dim, DimAdd, DimDiff, DimMax, DimMaximum, DimSub, DimSum}; use std::cmp; -use storage::Storage; -use {zero, Real, Vector, VectorN, U1}; -impl> Vector { +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Dim, DimAdd, DimDiff, DimMax, DimMaximum, DimSub, DimSum}; +use crate::storage::Storage; +use crate::{zero, RealField, Vector, VectorN, U1}; + +impl> Vector { /// Returns the convolution of the target vector and a kernel /// /// # Arguments diff --git a/src/linalg/determinant.rs b/src/linalg/determinant.rs index 6229da0e9..54ec9e5a8 100644 --- a/src/linalg/determinant.rs +++ b/src/linalg/determinant.rs @@ -1,13 +1,13 @@ -use alga::general::Real; +use alga::general::ComplexField; -use base::allocator::Allocator; -use base::dimension::DimMin; -use base::storage::Storage; -use base::{DefaultAllocator, SquareMatrix}; +use crate::base::allocator::Allocator; +use crate::base::dimension::DimMin; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, SquareMatrix}; -use linalg::LU; +use crate::linalg::LU; -impl, S: Storage> SquareMatrix { +impl, S: Storage> SquareMatrix { /// Computes the matrix determinant. /// /// If the matrix has a dimension larger than 3, an LU decomposition is used. diff --git a/src/linalg/eigen.rs b/src/linalg/eigen.rs index c9fe16e67..8d1d26ca8 100644 --- a/src/linalg/eigen.rs +++ b/src/linalg/eigen.rs @@ -1,23 +1,23 @@ #[cfg(feature = "serde-serialize")] use serde::{Serialize, Deserialize}; -use alga::general::Real; +use alga::general::ComplexField; use num_complex::Complex; use std::cmp; use std::fmt::Display; use std::ops::MulAssign; -use allocator::Allocator; -use base::dimension::{Dim, DimDiff, DimSub, Dynamic, U1, U2, U3}; -use base::storage::Storage; -use base::{DefaultAllocator, Hessenberg, MatrixN, SquareMatrix, Unit, Vector2, Vector3, VectorN}; -use constraint::{DimEq, ShapeConstraint}; +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::constraint::{DimEq, ShapeConstraint}; -use geometry::{Reflection, UnitComplex}; -use linalg::householder; -use linalg::RealSchur; +use crate::geometry::{Reflection, UnitComplex}; +use crate::linalg::householder; +use crate::linalg::Schur; -/// Eigendecomposition of a matrix with real eigenvalues. +/// Eigendecomposition of a real matrix with real eigenvalues (or complex eigen values for complex matrices). #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", @@ -40,7 +40,7 @@ use linalg::RealSchur; ) )] #[derive(Clone, Debug)] -pub struct RealEigen +pub struct Eigen where DefaultAllocator: Allocator + Allocator, { @@ -48,7 +48,7 @@ where pub eigenvalues: VectorN, } -impl Copy for RealEigen +impl Copy for Eigen where DefaultAllocator: Allocator + Allocator, MatrixN: Copy, @@ -56,7 +56,7 @@ where { } -impl RealEigen +impl Eigen where D: DimSub, // For Hessenberg. ShapeConstraint: DimEq>, // For Hessenberg. @@ -68,19 +68,19 @@ where DefaultAllocator: Allocator, MatrixN: Display, { - /// Computes the eigendecomposition of a diagonalizable matrix with real eigenvalues. - pub fn new(m: MatrixN) -> Option> { + /// Computes the eigendecomposition of a diagonalizable matrix with Complex eigenvalues. + pub fn new(m: MatrixN) -> Option> { assert!( m.is_square(), "Unable to compute the eigendecomposition of a non-square matrix." ); let dim = m.nrows(); - let (mut eigenvectors, mut eigenvalues) = RealSchur::new(m, 0).unwrap().unpack(); + let (mut eigenvectors, mut eigenvalues) = Schur::new(m, 0).unwrap().unpack(); println!("Schur eigenvalues: {}", eigenvalues); - // Check that the eigenvalues are all real. + // Check that the eigenvalues are all Complex. for i in 0..dim - 1 { if !eigenvalues[(i + 1, i)].is_zero() { return None; @@ -112,8 +112,8 @@ where let _ = eigenvectors.column_mut(i).normalize_mut(); } - Some(RealEigen { - eigenvectors: eigenvectors, + Some(Eigen { + eigenvectors, eigenvalues: eigenvalues.diagonal(), }) } diff --git a/src/linalg/full_piv_lu.rs b/src/linalg/full_piv_lu.rs index 962d4d8b4..04f61faff 100644 --- a/src/linalg/full_piv_lu.rs +++ b/src/linalg/full_piv_lu.rs @@ -1,15 +1,15 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN}; -use constraint::{SameNumberOfRows, ShapeConstraint}; -use dimension::{Dim, DimMin, DimMinimum}; -use storage::{Storage, StorageMut}; +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 linalg::lu; -use linalg::PermutationSequence; +use crate::linalg::lu; +use crate::linalg::PermutationSequence; /// LU decomposition with full row and column pivoting. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -32,7 +32,7 @@ use linalg::PermutationSequence; )) )] #[derive(Clone, Debug)] -pub struct FullPivLU, C: Dim> +pub struct FullPivLU, C: Dim> where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> { lu: MatrixMN, @@ -40,14 +40,14 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu q: PermutationSequence>, } -impl, C: Dim> Copy for FullPivLU +impl, C: Dim> Copy for FullPivLU where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Copy, PermutationSequence>: Copy, {} -impl, C: Dim> FullPivLU +impl, C: Dim> FullPivLU where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> { /// Computes the LU decomposition with full pivoting of `matrix`. @@ -69,7 +69,7 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu } for i in 0..min_nrows_ncols.value() { - let piv = matrix.slice_range(i.., i..).iamax_full(); + let piv = matrix.slice_range(i.., i..).icamax_full(); let row_piv = piv.0 + i; let col_piv = piv.1 + i; let diag = matrix[(row_piv, col_piv)]; @@ -156,7 +156,7 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu } } -impl> FullPivLU +impl> FullPivLU where DefaultAllocator: Allocator + Allocator<(usize, usize), D> { /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. @@ -261,7 +261,7 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), D> } } -impl, C: Dim, S: Storage> Matrix +impl, C: Dim, S: Storage> Matrix 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 9175bff9b..ed93a83c4 100644 --- a/src/linalg/givens.rs +++ b/src/linalg/givens.rs @@ -1,36 +1,161 @@ //! Construction of givens rotations. -use alga::general::Real; -use num_complex::Complex; - -use base::dimension::U2; -use base::storage::Storage; -use base::Vector; - -use geometry::UnitComplex; - -/// Computes the rotation `R` required such that the `y` component of `R * v` is zero. -/// -/// Returns `None` if no rotation is needed (i.e. if `v.y == 0`). Otherwise, this returns the norm -/// of `v` and the rotation `r` such that `R * v = [ |v|, 0.0 ]^t` where `|v|` is the norm of `v`. -pub fn cancel_y>(v: &Vector) -> Option<(UnitComplex, N)> { - if !v[1].is_zero() { - let c = Complex::new(v[0], -v[1]); - Some(UnitComplex::from_complex_and_get(c)) - } else { - None - } +use alga::general::ComplexField; +use num::{Zero, One}; + +use crate::base::dimension::{Dim, U2}; +use crate::base::constraint::{ShapeConstraint, DimEq}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{Vector, Matrix}; + + +/// A Givens rotation. +#[derive(Debug, Clone, Copy)] +pub struct GivensRotation { + c: N::RealField, + s: N } -/// Computes the rotation `R` required such that the `x` component of `R * v` is zero. -/// -/// Returns `None` if no rotation is needed (i.e. if `v.x == 0`). Otherwise, this returns the norm -/// of `v` and the rotation `r` such that `R * v = [ 0.0, |v| ]^t` where `|v|` is the norm of `v`. -pub fn cancel_x>(v: &Vector) -> Option<(UnitComplex, N)> { - if !v[0].is_zero() { - let c = Complex::new(v[1], v[0]); - Some(UnitComplex::from_complex_and_get(c)) - } else { - None +// Matrix = UnitComplex * Matrix +impl GivensRotation { + /// The Givents rotation that does nothing. + pub fn identity() -> Self { + Self { + c: N::RealField::one(), + s: N::zero() + } + } + + /// Initializes a Givens rotation from its components. + /// + /// 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 + } + } + + /// Initializes a Givens rotation from its non-normalized cosine an sine components. + pub fn new(c: N, s: N) -> (Self, N) { + Self::try_new(c, s, N::RealField::zero()).unwrap() + } + + /// Initializes a Givens rotation form its non-normalized cosine an sine components. + pub fn try_new(c: N, s: N, eps: N::RealField) -> Option<(Self, N)> { + let (mod0, sign0) = c.to_exp(); + let denom = (mod0 * mod0 + s.modulus_squared()).sqrt(); + + if denom > eps { + let norm = sign0.scale(denom); + let c = mod0 / denom; + let s = s / norm; + Some((Self { c, s }, norm)) + } else { + None + } + } + + /// Computes the rotation `R` required such that the `y` component of `R * v` is zero. + /// + /// Returns `None` if no rotation is needed (i.e. if `v.y == 0`). Otherwise, this returns the norm + /// of `v` and the rotation `r` such that `R * v = [ |v|, 0.0 ]^t` where `|v|` is the norm of `v`. + pub fn cancel_y>(v: &Vector) -> Option<(Self, N)> { + if !v[1].is_zero() { + let (mod0, sign0) = v[0].to_exp(); + let denom = (mod0 * mod0 + v[1].modulus_squared()).sqrt(); + let c = mod0 / denom; + let s = -v[1] / sign0.scale(denom); + let r = sign0.scale(denom); + Some((Self { c, s }, r)) + } else { + None + } + } + + /// Computes the rotation `R` required such that the `x` component of `R * v` is zero. + /// + /// Returns `None` if no rotation is needed (i.e. if `v.x == 0`). Otherwise, this returns the norm + /// of `v` and the rotation `r` such that `R * v = [ 0.0, |v| ]^t` where `|v|` is the norm of `v`. + pub fn cancel_x>(v: &Vector) -> Option<(Self, N)> { + if !v[0].is_zero() { + let (mod1, sign1) = v[1].to_exp(); + let denom = (mod1 * mod1 + v[0].modulus_squared()).sqrt(); + let c = mod1 / denom; + let s = (v[0].conjugate() * sign1).unscale(denom); + let r = sign1.scale(denom); + Some((Self { c, s }, r)) + } else { + None + } + } + + /// The cos part of this roration. + pub fn c(&self) -> N::RealField { + self.c + } + + /// The sin part of this roration. + pub fn s(&self) -> N { + self.s + } + + /// The inverse of this givens rotation. + pub fn inverse(&self) -> Self { + Self { c: self.c, s: -self.s } + } + + /// Performs the multiplication `rhs = self * rhs` in-place. + pub fn rotate>( + &self, + rhs: &mut Matrix, + ) where + ShapeConstraint: DimEq, + { + assert_eq!( + rhs.nrows(), + 2, + "Unit complex rotation: the input matrix must have exactly two rows." + ); + let s = self.s; + let c = self.c; + + for j in 0..rhs.ncols() { + unsafe { + let a = *rhs.get_unchecked((0, j)); + let b = *rhs.get_unchecked((1, j)); + + *rhs.get_unchecked_mut((0, j)) = a.scale(c) - s.conjugate() * b; + *rhs.get_unchecked_mut((1, j)) = s * a + b.scale(c); + } + } + } + + /// Performs the multiplication `lhs = lhs * self` in-place. + pub fn rotate_rows>( + &self, + lhs: &mut Matrix, + ) where + ShapeConstraint: DimEq, + { + assert_eq!( + lhs.ncols(), + 2, + "Unit complex rotation: the input matrix must have exactly two columns." + ); + let s = self.s; + let c = self.c; + + // FIXME: can we optimize that to iterate on one column at a time ? + for j in 0..lhs.nrows() { + unsafe { + let a = *lhs.get_unchecked((j, 0)); + let b = *lhs.get_unchecked((j, 1)); + + *lhs.get_unchecked_mut((j, 0)) = a.scale(c) + s * b; + *lhs.get_unchecked_mut((j, 1)) = -s.conjugate() * a + b.scale(c); + } + } } } + diff --git a/src/linalg/hessenberg.rs b/src/linalg/hessenberg.rs index 783055a32..c87c06a21 100644 --- a/src/linalg/hessenberg.rs +++ b/src/linalg/hessenberg.rs @@ -1,14 +1,13 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, MatrixMN, MatrixN, SquareMatrix, VectorN}; -use constraint::{DimEq, ShapeConstraint}; -use dimension::{DimDiff, DimSub, Dynamic, U1}; -use storage::Storage; +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 linalg::householder; +use crate::linalg::householder; /// Hessenberg decomposition of a general matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -31,21 +30,21 @@ use linalg::householder; )) )] #[derive(Clone, Debug)] -pub struct Hessenberg> +pub struct Hessenberg> where DefaultAllocator: Allocator + Allocator> { hess: MatrixN, subdiag: VectorN>, } -impl> Copy for Hessenberg +impl> Copy for Hessenberg where DefaultAllocator: Allocator + Allocator>, MatrixN: Copy, VectorN>: Copy, {} -impl> Hessenberg +impl> Hessenberg where DefaultAllocator: Allocator + Allocator + Allocator> { /// Computes the Hessenberg decomposition using householder reflections. @@ -92,8 +91,7 @@ where DefaultAllocator: Allocator + Allocator + Allocator (MatrixN, MatrixN) - where ShapeConstraint: DimEq> { + pub fn unpack(self) -> (MatrixN, MatrixN) { let q = self.q(); (q, self.unpack_h()) @@ -101,13 +99,12 @@ where DefaultAllocator: Allocator + Allocator + Allocator MatrixN - where ShapeConstraint: DimEq> { + pub fn unpack_h(mut self) -> MatrixN { let dim = self.hess.nrows(); self.hess.fill_lower_triangle(N::zero(), 2); self.hess .slice_mut((1, 0), (dim - 1, dim - 1)) - .set_diagonal(&self.subdiag); + .set_partial_diagonal(self.subdiag.iter().map(|e| N::from_real(e.modulus()))); self.hess } @@ -116,19 +113,18 @@ where DefaultAllocator: Allocator + Allocator + Allocator MatrixN - where ShapeConstraint: DimEq> { + pub fn h(&self) -> MatrixN { let dim = self.hess.nrows(); let mut res = self.hess.clone(); res.fill_lower_triangle(N::zero(), 2); res.slice_mut((1, 0), (dim - 1, dim - 1)) - .set_diagonal(&self.subdiag); + .set_partial_diagonal(self.subdiag.iter().map(|e| N::from_real(e.modulus()))); res } /// Computes the orthogonal matrix `Q` of this decomposition. pub fn q(&self) -> MatrixN { - householder::assemble_q(&self.hess) + householder::assemble_q(&self.hess, self.subdiag.as_slice()) } #[doc(hidden)] @@ -137,7 +133,7 @@ where DefaultAllocator: Allocator + Allocator + Allocator, S: Storage> SquareMatrix +impl, S: Storage> SquareMatrix where DefaultAllocator: Allocator + Allocator + Allocator> { /// Computes the Hessenberg decomposition of this matrix using householder reflections. diff --git a/src/linalg/householder.rs b/src/linalg/householder.rs index 09c230916..11fa32eb7 100644 --- a/src/linalg/householder.rs +++ b/src/linalg/householder.rs @@ -1,12 +1,13 @@ //! Construction of householder elementary reflections. -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, MatrixMN, MatrixN, Unit, Vector, VectorN}; -use dimension::Dim; -use storage::{Storage, StorageMut}; +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 geometry::Reflection; +use crate::geometry::Reflection; /// Replaces `column` by the axis of the householder reflection that transforms `column` into /// `(+/-|column|, 0, ..., 0)`. @@ -15,35 +16,35 @@ use geometry::Reflection; /// `column` after reflection and `false` if no reflection was necessary. #[doc(hidden)] #[inline(always)] -pub fn reflection_axis_mut>( +pub fn reflection_axis_mut>( column: &mut Vector, ) -> (N, bool) { let reflection_sq_norm = column.norm_squared(); - let mut reflection_norm = reflection_sq_norm.sqrt(); + let reflection_norm = reflection_sq_norm.sqrt(); let factor; - unsafe { - if *column.vget_unchecked(0) > N::zero() { - reflection_norm = -reflection_norm; - } + let signed_norm; - factor = - (reflection_sq_norm - *column.vget_unchecked(0) * reflection_norm) * ::convert(2.0); - *column.vget_unchecked_mut(0) -= reflection_norm; - } + unsafe { + let (modulus, sign) = column.vget_unchecked(0).to_exp(); + signed_norm = sign.scale(reflection_norm); + factor = (reflection_sq_norm + modulus * reflection_norm) * crate::convert(2.0); + *column.vget_unchecked_mut(0) += signed_norm; + }; if !factor.is_zero() { - *column /= factor.sqrt(); - (reflection_norm, true) + column.unscale_mut(factor.sqrt()); + (-signed_norm, true) } else { - (reflection_norm, false) + // FIXME: not sure why we don't have a - sign here. + (signed_norm, false) } } /// Uses an householder reflection to zero out the `icol`-th column, starting with the `shift + 1`-th /// subdiagonal element. #[doc(hidden)] -pub fn clear_column_unchecked( +pub fn clear_column_unchecked( matrix: &mut MatrixMN, diag_elt: &mut N, icol: usize, @@ -60,17 +61,18 @@ pub fn clear_column_unchecked( if not_zero { let refl = Reflection::new(Unit::new_unchecked(axis), N::zero()); + let sign = reflection_norm.signum(); if let Some(mut work) = bilateral { - refl.reflect_rows(&mut right, &mut work); + refl.reflect_rows_with_sign(&mut right, &mut work, sign); } - refl.reflect(&mut right.rows_range_mut(icol + shift..)); + refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate()); } } -/// Uses an hoseholder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th +/// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th /// superdiagonal element. #[doc(hidden)] -pub fn clear_row_unchecked( +pub fn clear_row_unchecked( matrix: &mut MatrixMN, diag_elt: &mut N, axis_packed: &mut VectorN, @@ -85,26 +87,28 @@ pub fn clear_row_unchecked( axis.tr_copy_from(&top.columns_range(irow + shift..)); let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis); + axis.conjugate_mut(); // So that reflect_rows actually cancels the first row. *diag_elt = reflection_norm; if not_zero { let refl = Reflection::new(Unit::new_unchecked(axis), N::zero()); - refl.reflect_rows( + refl.reflect_rows_with_sign( &mut bottom.columns_range_mut(irow + shift..), &mut work.rows_range_mut(irow + 1..), + reflection_norm.signum().conjugate(), ); top.columns_range_mut(irow + shift..) - .tr_copy_from(refl.axis()); + .tr_copy_from(&refl.axis()); } else { top.columns_range_mut(irow + shift..).tr_copy_from(&axis); } } -/// Computes the orthogonal transformation described by the elementary reflector axices stored on +/// Computes the orthogonal transformation described by the elementary reflector axii stored on /// the lower-diagonal element of the given matrix. /// matrices. #[doc(hidden)] -pub fn assemble_q(m: &MatrixN) -> MatrixN +pub fn assemble_q(m: &MatrixN, signs: &[N]) -> MatrixN where DefaultAllocator: Allocator { assert!(m.is_square()); let dim = m.data.shape().0; @@ -118,7 +122,7 @@ where DefaultAllocator: Allocator { let refl = Reflection::new(Unit::new_unchecked(axis), N::zero()); let mut res_rows = res.slice_range_mut(i + 1.., i..); - refl.reflect(&mut res_rows); + refl.reflect_with_sign(&mut res_rows, signs[i].signum()); } res diff --git a/src/linalg/inverse.rs b/src/linalg/inverse.rs index 69f1463d1..944624429 100644 --- a/src/linalg/inverse.rs +++ b/src/linalg/inverse.rs @@ -1,13 +1,13 @@ -use alga::general::Real; +use alga::general::ComplexField; -use base::allocator::Allocator; -use base::dimension::Dim; -use base::storage::{Storage, StorageMut}; -use base::{DefaultAllocator, MatrixN, SquareMatrix}; +use crate::base::allocator::Allocator; +use crate::base::dimension::Dim; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{DefaultAllocator, MatrixN, SquareMatrix}; -use linalg::lu; +use crate::linalg::lu; -impl> SquareMatrix { +impl> SquareMatrix { /// Attempts to invert this matrix. #[inline] pub fn try_inverse(self) -> Option> @@ -21,7 +21,7 @@ impl> SquareMatrix { } } -impl> SquareMatrix { +impl> SquareMatrix { /// Attempts to invert this matrix in-place. Returns `false` and leaves `self` untouched if /// inversion fails. #[inline] @@ -115,7 +115,7 @@ impl> SquareMatrix { } // NOTE: this is an extremely efficient, loop-unrolled matrix inverse from MESA (MIT licensed). -fn do_inverse4>( +fn do_inverse4>( m: &MatrixN, out: &mut SquareMatrix, ) -> bool diff --git a/src/linalg/lu.rs b/src/linalg/lu.rs index 67fae23fa..2c3beee3c 100644 --- a/src/linalg/lu.rs +++ b/src/linalg/lu.rs @@ -1,15 +1,15 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::{Field, Real}; -use allocator::{Allocator, Reallocator}; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Scalar}; -use constraint::{SameNumberOfRows, ShapeConstraint}; -use dimension::{Dim, DimMin, DimMinimum}; +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 storage::{Storage, StorageMut}; +use crate::storage::{Storage, StorageMut}; -use linalg::PermutationSequence; +use crate::linalg::PermutationSequence; /// LU decomposition with partial (row) pivoting. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -32,14 +32,14 @@ use linalg::PermutationSequence; )) )] #[derive(Clone, Debug)] -pub struct LU, C: Dim> +pub struct LU, C: Dim> where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> { lu: MatrixMN, p: PermutationSequence>, } -impl, C: Dim> Copy for LU +impl, C: Dim> Copy for LU where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum>, MatrixMN: Copy, @@ -49,7 +49,7 @@ where /// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`. /// /// If `matrix` is not invertible, `false` is returned and `out` may contain invalid data. -pub fn try_invert_to( +pub fn try_invert_to( mut matrix: MatrixN, out: &mut Matrix, ) -> bool @@ -66,7 +66,7 @@ where out.fill_with_identity(); for i in 0..dim { - let piv = matrix.slice_range(i.., i).iamax() + i; + let piv = matrix.slice_range(i.., i).icamax() + i; let diag = matrix[(piv, i)]; if diag.is_zero() { @@ -86,7 +86,7 @@ where matrix.solve_upper_triangular_mut(out) } -impl, C: Dim> LU +impl, C: Dim> LU where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> { /// Computes the LU decomposition with partial (row) pivoting of `matrix`. @@ -101,7 +101,7 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu } for i in 0..min_nrows_ncols.value() { - let piv = matrix.slice_range(i.., i).iamax() + i; + let piv = matrix.slice_range(i.., i).icamax() + i; let diag = matrix[(piv, i)]; if diag.is_zero() { @@ -197,7 +197,7 @@ where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimu } } -impl> LU +impl> LU where DefaultAllocator: Allocator + Allocator<(usize, usize), D> { /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. @@ -368,7 +368,7 @@ pub fn gauss_step_swap( } } -impl, C: Dim, S: Storage> Matrix +impl, C: Dim, S: Storage> Matrix where DefaultAllocator: Allocator + Allocator<(usize, usize), DimMinimum> { /// Computes the LU decomposition with partial (row) pivoting of `matrix`. diff --git a/src/linalg/permutation_sequence.rs b/src/linalg/permutation_sequence.rs index 3aef1be62..ce493905e 100644 --- a/src/linalg/permutation_sequence.rs +++ b/src/linalg/permutation_sequence.rs @@ -4,12 +4,12 @@ use serde::{Deserialize, Serialize}; use alga::general::ClosedNeg; use num::One; -use allocator::Allocator; -use base::{DefaultAllocator, Matrix, Scalar, VectorN}; +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix, Scalar, VectorN}; #[cfg(any(feature = "std", feature = "alloc"))] -use dimension::Dynamic; -use dimension::{Dim, DimName, U1}; -use storage::StorageMut; +use crate::dimension::Dynamic; +use crate::dimension::{Dim, DimName, U1}; +use crate::storage::StorageMut; /// A sequence of row or column permutations. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] diff --git a/src/linalg/qr.rs b/src/linalg/qr.rs index 81f722697..683c11b8c 100644 --- a/src/linalg/qr.rs +++ b/src/linalg/qr.rs @@ -1,15 +1,16 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; +use num::Zero; -use alga::general::Real; -use allocator::{Allocator, Reallocator}; -use base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, Unit, VectorN}; -use constraint::{SameNumberOfRows, ShapeConstraint}; -use dimension::{Dim, DimMin, DimMinimum, U1}; -use storage::{Storage, StorageMut}; +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 geometry::Reflection; -use linalg::householder; +use crate::geometry::Reflection; +use crate::linalg::householder; /// The QR decomposition of a general matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -32,21 +33,21 @@ use linalg::householder; )) )] #[derive(Clone, Debug)] -pub struct QR, C: Dim> +pub struct QR, C: Dim> where DefaultAllocator: Allocator + Allocator> { qr: MatrixMN, diag: VectorN>, } -impl, C: Dim> Copy for QR +impl, C: Dim> Copy for QR where DefaultAllocator: Allocator + Allocator>, MatrixMN: Copy, VectorN>: Copy, {} -impl, C: Dim> QR +impl, C: Dim> QR where DefaultAllocator: Allocator + Allocator + Allocator> { /// Computes the QR decomposition using householder reflections. @@ -78,12 +79,10 @@ where DefaultAllocator: Allocator + Allocator + Allocator MatrixMN, C> where DefaultAllocator: Allocator, C>, - // FIXME: the following bound is ugly. - DimMinimum: DimMin>, { let (nrows, ncols) = self.qr.data.shape(); let mut res = self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle(); - res.set_diagonal(&self.diag); + res.set_partial_diagonal(self.diag.iter().map(|e| N::from_real(e.modulus()))); res } @@ -94,13 +93,11 @@ where DefaultAllocator: Allocator + Allocator + Allocator MatrixMN, C> where DefaultAllocator: Reallocator, C>, - // FIXME: the following bound is ugly (needed by `set_diagonal`). - DimMinimum: DimMin>, { let (nrows, ncols) = self.qr.data.shape(); let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, N::zero()); res.fill_lower_triangle(N::zero(), 1); - res.set_diagonal(&self.diag); + res.set_partial_diagonal(self.diag.iter().map(|e| N::from_real(e.modulus()))); res } @@ -120,7 +117,7 @@ where DefaultAllocator: Allocator + Allocator + Allocator + Allocator + Allocator> QR +impl> QR where DefaultAllocator: Allocator + Allocator { /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. @@ -226,13 +223,13 @@ where DefaultAllocator: Allocator + Allocator let coeff; unsafe { - let diag = *self.diag.vget_unchecked(i); + let diag = self.diag.vget_unchecked(i).modulus(); if diag.is_zero() { return false; } - coeff = *b.vget_unchecked(i) / diag; + coeff = b.vget_unchecked(i).unscale(diag); *b.vget_unchecked_mut(i) = coeff; } @@ -294,7 +291,7 @@ where DefaultAllocator: Allocator + Allocator // } } -impl, C: Dim, S: Storage> Matrix +impl, C: Dim, S: Storage> Matrix where DefaultAllocator: Allocator + Allocator + Allocator> { /// Computes the QR decomposition of this matrix. diff --git a/src/linalg/schur.rs b/src/linalg/schur.rs index 0d4250878..b31be9f67 100644 --- a/src/linalg/schur.rs +++ b/src/linalg/schur.rs @@ -1,21 +1,24 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::Real; -use num_complex::Complex; +use approx::AbsDiffEq; +use alga::general::{ComplexField, RealField}; +use num_complex::Complex as NumComplex; use std::cmp; -use allocator::Allocator; -use base::dimension::{Dim, DimDiff, DimSub, Dynamic, U1, U2, U3}; -use base::storage::Storage; -use base::{DefaultAllocator, MatrixN, SquareMatrix, Unit, Vector2, Vector3, VectorN}; -use constraint::{DimEq, ShapeConstraint}; +use crate::allocator::Allocator; +use crate::base::dimension::{Dim, DimDiff, DimSub, Dynamic, U1, U2, U3}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, MatrixN, SquareMatrix, Unit, Vector2, Vector3, VectorN}; -use geometry::{Reflection, UnitComplex}; -use linalg::householder; -use linalg::Hessenberg; +use crate::geometry::Reflection; +use crate::linalg::householder; +use crate::linalg::Hessenberg; +use crate::linalg::givens::GivensRotation; -/// Real Schur decomposition of a square matrix. +/// Schur decomposition of a square matrix. +/// +/// If this is a real matrix, this will be a RealField Schur decomposition. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", @@ -32,23 +35,22 @@ use linalg::Hessenberg; )) )] #[derive(Clone, Debug)] -pub struct RealSchur +pub struct Schur where DefaultAllocator: Allocator { q: MatrixN, t: MatrixN, } -impl Copy for RealSchur +impl Copy for Schur where DefaultAllocator: Allocator, MatrixN: Copy, {} -impl RealSchur +impl Schur where D: DimSub, // For Hessenberg. - ShapeConstraint: DimEq>, // For Hessenberg. DefaultAllocator: Allocator> + Allocator> + Allocator @@ -56,7 +58,7 @@ where { /// Computes the Schur decomposition of a square matrix. pub fn new(m: MatrixN) -> Self { - Self::try_new(m, N::default_epsilon(), 0).unwrap() + Self::try_new(m, N::RealField::default_epsilon(), 0).unwrap() } /// Attempts to compute the Schur decomposition of a square matrix. @@ -70,10 +72,10 @@ where /// * `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_new(m: MatrixN, eps: N, max_niter: usize) -> Option { + pub fn try_new(m: MatrixN, eps: N::RealField, max_niter: usize) -> Option { let mut work = unsafe { VectorN::new_uninitialized_generic(m.data.shape().0, U1) }; - Self::do_decompose(m, &mut work, eps, max_niter, true).map(|(q, t)| RealSchur { + Self::do_decompose(m, &mut work, eps, max_niter, true).map(|(q, t)| Schur { q: q.unwrap(), t: t, }) @@ -82,7 +84,7 @@ where fn do_decompose( mut m: MatrixN, work: &mut VectorN, - eps: N, + eps: N::RealField, max_niter: usize, compute_q: bool, ) -> Option<(Option>, MatrixN)> @@ -94,6 +96,7 @@ where let dim = m.data.shape().0; + // Specialization would make this easier. if dim.value() == 0 { let vecs = Some(MatrixN::from_element_generic(dim, dim, N::zero())); let vals = MatrixN::from_element_generic(dim, dim, N::zero()); @@ -105,14 +108,12 @@ where } else { return Some((None, m)); } - } - // Specialization would make this easier. - else if dim.value() == 2 { + } else if dim.value() == 2 { return decompose_2x2(m, compute_q); } - let amax_m = m.amax(); - m /= amax_m; + let amax_m = m.camax(); + m.unscale_mut(amax_m); let hess = Hessenberg::new_with_workspace(m, work); let mut q; @@ -259,7 +260,7 @@ where } } - t *= amax_m; + t.scale_mut(amax_m); Some((q, t)) } @@ -289,8 +290,9 @@ where } /// Computes the complex eigenvalues of the decomposed matrix. - fn do_complex_eigenvalues(t: &MatrixN, out: &mut VectorN, D>) - where DefaultAllocator: Allocator, D> { + fn do_complex_eigenvalues(t: &MatrixN, out: &mut VectorN, D>) + where N: RealField, + DefaultAllocator: Allocator, D> { let dim = t.nrows(); let mut m = 0; @@ -298,7 +300,7 @@ where let n = m + 1; if t[(n, m)].is_zero() { - out[m] = Complex::new(t[(m, m)], N::zero()); + out[m] = NumComplex::new(t[(m, m)], N::zero()); m += 1; } else { // Solve the 2x2 eigenvalue subproblem. @@ -309,25 +311,25 @@ where let tra = hnn + hmm; let det = hnn * hmm - hnm * hmn; - let discr = tra * tra * ::convert(0.25) - det; + let discr = tra * tra * crate::convert(0.25) - det; // All 2x2 blocks have negative discriminant because we already decoupled those // with positive eigenvalues.. - let sqrt_discr = Complex::new(N::zero(), (-discr).sqrt()); + let sqrt_discr = NumComplex::new(N::zero(), (-discr).sqrt()); - out[m] = Complex::new(tra * ::convert(0.5), N::zero()) + sqrt_discr; - out[m + 1] = Complex::new(tra * ::convert(0.5), N::zero()) - sqrt_discr; + out[m] = NumComplex::new(tra * crate::convert(0.5), N::zero()) + sqrt_discr; + out[m + 1] = NumComplex::new(tra * crate::convert(0.5), N::zero()) - sqrt_discr; m += 2; } } if m == dim - 1 { - out[m] = Complex::new(t[(m, m)], N::zero()); + out[m] = NumComplex::new(t[(m, m)], N::zero()); } } - fn delimit_subproblem(t: &mut MatrixN, eps: N, end: usize) -> (usize, usize) + fn delimit_subproblem(t: &mut MatrixN, eps: N::RealField, end: usize) -> (usize, usize) where D: DimSub, DefaultAllocator: Allocator>, @@ -337,7 +339,7 @@ where while n > 0 { let m = n - 1; - if t[(n, m)].abs() <= eps * (t[(n, n)].abs() + t[(m, m)].abs()) { + if t[(n, m)].norm1() <= eps * (t[(n, n)].norm1() + t[(m, m)].norm1()) { t[(n, m)] = N::zero(); } else { break; @@ -356,7 +358,7 @@ where let off_diag = t[(new_start, m)]; if off_diag.is_zero() - || off_diag.abs() <= eps * (t[(new_start, new_start)].abs() + t[(m, m)].abs()) + || off_diag.norm1() <= eps * (t[(new_start, new_start)].norm1() + t[(m, m)].norm1()) { t[(new_start, m)] = N::zero(); break; @@ -387,15 +389,16 @@ where } /// Computes the complex eigenvalues of the decomposed matrix. - pub fn complex_eigenvalues(&self) -> VectorN, D> - where DefaultAllocator: Allocator, D> { + pub fn complex_eigenvalues(&self) -> VectorN, 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 } } -fn decompose_2x2( +fn decompose_2x2( mut m: MatrixN, compute_q: bool, ) -> Option<(Option>, MatrixN)> @@ -412,13 +415,13 @@ where rot.rotate_rows(&mut m); if compute_q { - let c = rot.into_inner(); // XXX: we have to build the matrix manually because // rot.to_rotation_matrix().unwrap() causes an ICE. + let c = N::from_real(rot.c()); q = Some(MatrixN::from_column_slice_generic( dim, dim, - &[c.re, c.im, -c.im, c.re], + &[c, rot.s(), -rot.s().conjugate(), c], )); } } @@ -432,7 +435,7 @@ where Some((q, m)) } -fn compute_2x2_eigvals>( +fn compute_2x2_eigvals>( m: &SquareMatrix, ) -> Option<(N, N)> { // Solve the 2x2 eigenvalue subproblem. @@ -441,19 +444,16 @@ fn compute_2x2_eigvals>( let h01 = m[(0, 1)]; let h11 = m[(1, 1)]; - // NOTE: this discriminant computation is mor stable than the + // NOTE: this discriminant computation is more stable than the // one based on the trace and determinant: 0.25 * tra * tra - det - // because et ensures positiveness for symmetric matrices. - let val = (h00 - h11) * ::convert(0.5); + // because it ensures positiveness for symmetric matrices. + let val = (h00 - h11) * crate::convert(0.5); let discr = h10 * h01 + val * val; - if discr >= N::zero() { - let sqrt_discr = discr.sqrt(); - let half_tra = (h00 + h11) * ::convert(0.5); - Some((half_tra + sqrt_discr, half_tra - sqrt_discr)) - } else { - None - } + discr.try_sqrt().map(|sqrt_discr| { + let half_tra = (h00 + h11) * crate::convert(0.5); + (half_tra + sqrt_discr, half_tra - sqrt_discr) + }) } // Computes the 2x2 transformation that upper-triangulates a 2x2 matrix with real eigenvalues. @@ -461,9 +461,9 @@ fn compute_2x2_eigvals>( /// /// Returns `None` if the matrix has complex eigenvalues, or is upper-triangular. In both case, /// the basis is the identity. -fn compute_2x2_basis>( +fn compute_2x2_basis>( m: &SquareMatrix, -) -> Option> { +) -> Option> { let h10 = m[(1, 0)]; if h10.is_zero() { @@ -471,36 +471,33 @@ fn compute_2x2_basis>( } if let Some((eigval1, eigval2)) = compute_2x2_eigvals(m) { - let x1 = m[(1, 1)] - eigval1; - let x2 = m[(1, 1)] - eigval2; + let x1 = eigval1 - m[(1, 1)]; + let x2 = eigval2 - m[(1, 1)]; // NOTE: Choose the one that yields a larger x component. // This is necessary for numerical stability of the normalization of the complex // number. - let basis = if x1.abs() > x2.abs() { - Complex::new(x1, -h10) + if x1.norm1() > x2.norm1() { + Some(GivensRotation::new(x1, h10).0) } else { - Complex::new(x2, -h10) - }; - - Some(UnitComplex::from_complex(basis)) + Some(GivensRotation::new(x2, h10).0) + } } else { None } } -impl> SquareMatrix +impl> SquareMatrix where D: DimSub, // For Hessenberg. - ShapeConstraint: DimEq>, // For Hessenberg. DefaultAllocator: Allocator> + Allocator> + Allocator + Allocator, { /// Computes the Schur decomposition of a square matrix. - pub fn real_schur(self) -> RealSchur { - RealSchur::new(self.into_owned()) + pub fn schur(self) -> Schur { + Schur::new(self.into_owned()) } /// Attempts to compute the Schur decomposition of a square matrix. @@ -514,8 +511,8 @@ where /// * `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_real_schur(self, eps: N, max_niter: usize) -> Option> { - RealSchur::try_new(self.into_owned(), eps, max_niter) + pub fn try_schur(self, eps: N::RealField, max_niter: usize) -> Option> { + Schur::try_new(self.into_owned(), eps, max_niter) } /// Computes the eigenvalues of this matrix. @@ -543,15 +540,15 @@ where } // FIXME: add balancing? - let schur = RealSchur::do_decompose( + let schur = Schur::do_decompose( self.clone_owned(), &mut work, - N::default_epsilon(), + N::RealField::default_epsilon(), 0, false, ) .unwrap(); - if RealSchur::do_eigenvalues(&schur.1, &mut work) { + if Schur::do_eigenvalues(&schur.1, &mut work) { Some(work) } else { None @@ -559,13 +556,14 @@ where } /// Computes the eigenvalues of this matrix. - pub fn complex_eigenvalues(&self) -> VectorN, D> + pub fn complex_eigenvalues(&self) -> VectorN, D> // FIXME: add balancing? - where 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) }; - let schur = RealSchur::do_decompose( + let schur = Schur::do_decompose( self.clone_owned(), &mut work, N::default_epsilon(), @@ -574,7 +572,7 @@ where ) .unwrap(); let mut eig = unsafe { VectorN::new_uninitialized_generic(dim, U1) }; - RealSchur::do_complex_eigenvalues(&schur.1, &mut eig); + Schur::do_complex_eigenvalues(&schur.1, &mut eig); eig } } diff --git a/src/linalg/solve.rs b/src/linalg/solve.rs index 4d2d103f5..f10b1d004 100644 --- a/src/linalg/solve.rs +++ b/src/linalg/solve.rs @@ -1,12 +1,12 @@ -use alga::general::Real; +use alga::general::ComplexField; -use base::allocator::Allocator; -use base::constraint::{SameNumberOfRows, ShapeConstraint}; -use base::dimension::{Dim, U1}; -use base::storage::{Storage, StorageMut}; -use base::{DefaultAllocator, Matrix, MatrixMN, SquareMatrix, Vector}; +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}; -impl> SquareMatrix { +impl> SquareMatrix { /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. #[inline] @@ -180,10 +180,9 @@ impl> SquareMatrix { /* * - * Transpose versions + * Transpose and adjoint versions * */ - /// Computes the solution of the linear system `self.transpose() . x = b` where `x` is the unknown and only /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. #[inline] @@ -191,10 +190,10 @@ impl> SquareMatrix { &self, b: &Matrix, ) -> Option> - where - S2: StorageMut, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = b.clone_owned(); if self.tr_solve_lower_triangular_mut(&mut res) { @@ -211,10 +210,10 @@ impl> SquareMatrix { &self, b: &Matrix, ) -> Option> - where - S2: StorageMut, - DefaultAllocator: Allocator, - ShapeConstraint: SameNumberOfRows, + where + S2: StorageMut, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, { let mut res = b.clone_owned(); if self.tr_solve_upper_triangular_mut(&mut res) { @@ -230,14 +229,14 @@ 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.tr_solve_lower_triangular_vector_mut(&mut b.column_mut(i)) { + if !self.xx_solve_lower_triangular_vector_mut(&mut b.column_mut(i), |e| e, |a, b| a.dot(b)) { return false; } } @@ -245,46 +244,102 @@ impl> SquareMatrix { true } - fn tr_solve_lower_triangular_vector_mut(&self, b: &mut Vector) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + /// Solves the linear system `self.transpose() . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn tr_solve_upper_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { - let dim = self.nrows(); + let cols = b.ncols(); - for i in (0..dim).rev() { - let dot = self.slice_range(i + 1.., i).dot(&b.slice_range(i + 1.., 0)); + 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)) { + return false; + } + } - unsafe { - let b_i = b.vget_unchecked_mut(i); + true + } - let diag = *self.get_unchecked((i, i)); + /// Computes the solution of the linear system `self.adjoint() . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[inline] + pub fn ad_solve_lower_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: StorageMut, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.ad_solve_lower_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } - if diag.is_zero() { - return false; - } + /// Computes the solution of the linear system `self.adjoint() . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[inline] + pub fn ad_solve_upper_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: StorageMut, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.ad_solve_upper_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } - *b_i = (*b_i - dot) / diag; + /// Solves the linear system `self.adjoint() . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn ad_solve_lower_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + 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)) { + return false; } } true } - /// Solves the linear system `self.transpose() . x = b` where `x` is the unknown and only the + /// Solves the linear system `self.adjoint() . x = b` where `x` is the unknown and only the /// upper-triangular part of `self` (including the diagonal) is considered not-zero. - pub fn tr_solve_upper_triangular_mut( + pub fn ad_solve_upper_triangular_mut( &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.tr_solve_upper_triangular_vector_mut(&mut b.column_mut(i)) { + if !self.xx_solve_upper_triangular_vector_mut(&mut b.column_mut(i), |e| e.conjugate(), |a, b| a.dotc(b)) { return false; } } @@ -292,19 +347,58 @@ impl> SquareMatrix { true } - fn tr_solve_upper_triangular_vector_mut(&self, b: &mut Vector) -> bool - where - S2: StorageMut, - ShapeConstraint: SameNumberOfRows, + + #[inline(always)] + fn xx_solve_lower_triangular_vector_mut( + &self, + b: &mut Vector, + conjugate: impl Fn(N) -> N, + dot: impl Fn(&DVectorSlice, &DVectorSlice) -> N, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in (0..dim).rev() { + let dot = dot(&self.slice_range(i + 1.., i), &b.slice_range(i + 1.., 0)); + + unsafe { + let b_i = b.vget_unchecked_mut(i); + + let diag = conjugate(*self.get_unchecked((i, i))); + + if diag.is_zero() { + return false; + } + + *b_i = (*b_i - dot) / diag; + } + } + + true + } + + #[inline(always)] + fn xx_solve_upper_triangular_vector_mut( + &self, + b: &mut Vector, + conjugate: impl Fn(N) -> N, + dot: impl Fn(&DVectorSlice, &DVectorSlice) -> N, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, { let dim = self.nrows(); for i in 0..dim { - let dot = self.slice_range(..i, i).dot(&b.slice_range(..i, 0)); + let dot = dot(&self.slice_range(..i, i), &b.slice_range(..i, 0)); unsafe { let b_i = b.vget_unchecked_mut(i); - let diag = *self.get_unchecked((i, i)); + let diag = conjugate(*self.get_unchecked((i, i))); if diag.is_zero() { return false; diff --git a/src/linalg/svd.rs b/src/linalg/svd.rs index 67b49604e..b608ec0cd 100644 --- a/src/linalg/svd.rs +++ b/src/linalg/svd.rs @@ -1,72 +1,69 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use num_complex::Complex; -use std::ops::MulAssign; +use num::{Zero, One}; +use approx::AbsDiffEq; -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, Matrix, Matrix2x3, MatrixMN, Vector2, VectorN}; -use constraint::{SameNumberOfRows, ShapeConstraint}; -use dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1, U2}; -use storage::Storage; +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 geometry::UnitComplex; -use linalg::givens; -use linalg::symmetric_eigen; -use linalg::Bidiagonal; +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))] #[cfg_attr( feature = "serde-serialize", serde(bound( - serialize = "DefaultAllocator: Allocator + - Allocator> + + serialize = "DefaultAllocator: Allocator> + Allocator, C> + Allocator>, MatrixMN>: Serialize, MatrixMN, C>: Serialize, - VectorN>: Serialize" + VectorN>: Serialize" )) )] #[cfg_attr( feature = "serde-serialize", serde(bound( - deserialize = "DefaultAllocator: Allocator + - Allocator> + + deserialize = "DefaultAllocator: Allocator> + Allocator, C> + Allocator>, MatrixMN>: Deserialize<'de>, MatrixMN, C>: Deserialize<'de>, - VectorN>: Deserialize<'de>" + VectorN>: Deserialize<'de>" )) )] #[derive(Clone, Debug)] -pub struct SVD, C: Dim> +pub struct SVD, C: Dim> where DefaultAllocator: Allocator, C> + Allocator> - + Allocator> + + Allocator> { /// The left-singular vectors `U` of this SVD. pub u: Option>>, /// The right-singular vectors `V^t` of this SVD. pub v_t: Option, C>>, /// The singular values of this SVD. - pub singular_values: VectorN>, + pub singular_values: VectorN>, } -impl, C: Dim> Copy for SVD +impl, C: Dim> Copy for SVD where DefaultAllocator: Allocator, C> + Allocator> - + Allocator>, + + Allocator>, MatrixMN>: Copy, MatrixMN, C>: Copy, - VectorN>: Copy, + VectorN>: Copy, {} -impl, C: Dim> SVD +impl, C: Dim> SVD where DimMinimum: DimSub, // for Bidiagonal. DefaultAllocator: Allocator @@ -75,11 +72,13 @@ where + Allocator, U1>> + Allocator, C> + Allocator> - + Allocator>, + + Allocator> + + Allocator> + + Allocator, U1>>, { /// 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::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. @@ -96,7 +95,7 @@ where mut matrix: MatrixMN, compute_u: bool, compute_v: bool, - eps: N, + eps: N::RealField, max_niter: usize, ) -> Option { @@ -108,18 +107,20 @@ where let min_nrows_ncols = nrows.min(ncols); let dim = min_nrows_ncols.value(); - let m_amax = matrix.amax(); + let m_amax = matrix.camax(); if !m_amax.is_zero() { - matrix /= m_amax; + matrix.unscale_mut(m_amax); } - let mut b = Bidiagonal::new(matrix); + let b = Bidiagonal::new(matrix); let mut u = if compute_u { Some(b.u()) } else { None }; let mut v_t = if compute_v { Some(b.v_t()) } else { None }; + let mut diagonal = b.diagonal(); + let mut off_diagonal = b.off_diagonal(); let mut niter = 0; - let (mut start, mut end) = Self::delimit_subproblem(&mut b, &mut u, &mut v_t, 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; @@ -131,52 +132,55 @@ where let mut vec; { - let dm = b.diagonal[m]; - let dn = b.diagonal[n]; - let fm = b.off_diagonal[m]; + let dm = diagonal[m]; + let dn = diagonal[n]; + let fm = off_diagonal[m]; - let tmm = dm * dm + b.off_diagonal[m - 1] * b.off_diagonal[m - 1]; + let tmm = dm * dm + off_diagonal[m - 1] * off_diagonal[m - 1]; let tmn = dm * fm; let tnn = dn * dn + fm * fm; let shift = symmetric_eigen::wilkinson_shift(tmm, tnn, tmn); vec = Vector2::new( - b.diagonal[start] * b.diagonal[start] - shift, - b.diagonal[start] * b.off_diagonal[start], + diagonal[start] * diagonal[start] - shift, + diagonal[start] * off_diagonal[start], ); } for k in start..n { let m12 = if k == n - 1 { - N::zero() + N::RealField::zero() } else { - b.off_diagonal[k + 1] + off_diagonal[k + 1] }; let mut subm = Matrix2x3::new( - b.diagonal[k], - b.off_diagonal[k], - N::zero(), - N::zero(), - b.diagonal[k + 1], + diagonal[k], + off_diagonal[k], + N::RealField::zero(), + N::RealField::zero(), + diagonal[k + 1], m12, ); - if let Some((rot1, norm1)) = givens::cancel_y(&vec) { - rot1.conjugate() - .rotate_rows(&mut subm.fixed_columns_mut::(0)); + if let Some((rot1, norm1)) = GivensRotation::cancel_y(&vec) { + 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 { // This is not the first iteration. - b.off_diagonal[k - 1] = norm1; + off_diagonal[k - 1] = norm1; } let v = Vector2::new(subm[(0, 0)], subm[(1, 0)]); // FIXME: does the case `v.y == 0` ever happen? let (rot2, norm2) = - givens::cancel_y(&v).unwrap_or((UnitComplex::identity(), subm[(0, 0)])); + 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())); + subm[(0, 0)] = norm2; if let Some(ref mut v_t) = v_t { @@ -197,12 +201,12 @@ where } } - b.diagonal[k + 0] = subm[(0, 0)]; - b.diagonal[k + 1] = subm[(1, 1)]; - b.off_diagonal[k + 0] = subm[(0, 1)]; + diagonal[k + 0] = subm[(0, 0)]; + diagonal[k + 1] = subm[(1, 1)]; + off_diagonal[k + 0] = subm[(0, 1)]; if k != n - 1 { - b.off_diagonal[k + 1] = subm[(1, 2)]; + off_diagonal[k + 1] = subm[(1, 2)]; } vec.x = subm[(0, 1)]; @@ -213,17 +217,19 @@ where } } else if subdim == 2 { // Solve the remaining 2x2 subproblem. - let (u2, s, v2) = Self::compute_2x2_uptrig_svd( - b.diagonal[start], - b.off_diagonal[start], - b.diagonal[start + 1], + let (u2, s, v2) = compute_2x2_uptrig_svd( + diagonal[start], + off_diagonal[start], + diagonal[start + 1], compute_u && b.is_upper_diagonal() || compute_v && !b.is_upper_diagonal(), compute_v && b.is_upper_diagonal() || compute_u && !b.is_upper_diagonal(), ); + let u2 = u2.map(|u2| GivensRotation::new_unchecked(u2.c(), N::from_real(u2.s()))); + let v2 = v2.map(|v2| GivensRotation::new_unchecked(v2.c(), N::from_real(v2.s()))); - b.diagonal[start + 0] = s[0]; - b.diagonal[start + 1] = s[1]; - b.off_diagonal[start] = N::zero(); + diagonal[start + 0] = s[0]; + diagonal[start + 1] = s[1]; + off_diagonal[start] = N::RealField::zero(); if let Some(ref mut u) = u { let rot = if b.is_upper_diagonal() { @@ -247,7 +253,7 @@ where } // Re-delimit the subproblem in case some decoupling occurred. - let sub = Self::delimit_subproblem(&mut b, &mut u, &mut v_t, 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; @@ -257,13 +263,14 @@ where } } - b.diagonal *= m_amax; + diagonal *= m_amax; // Ensure all singular value are non-negative. for i in 0..dim { - let sval = b.diagonal[i]; - if sval < N::zero() { - b.diagonal[i] = -sval; + let sval = diagonal[i]; + + if sval < N::RealField::zero() { + diagonal[i] = -sval; if let Some(ref mut u) = u { u.column_mut(i).neg_mut(); @@ -272,56 +279,12 @@ where } Some(Self { - u: u, - v_t: v_t, - singular_values: b.diagonal, + u, + v_t, + singular_values: diagonal, }) } - // Explicit formulaes 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 - fn compute_2x2_uptrig_svd( - m11: N, - m12: N, - m22: N, - compute_u: bool, - compute_v: bool, - ) -> (Option>, Vector2, Option>) - { - let two: N = ::convert(2.0f64); - let half: N = ::convert(0.5f64); - - let denom = (m11 + m22).hypot(m12) + (m11 - m22).hypot(m12); - - // NOTE: v1 is the singular value that is the closest to m22. - // This prevents cancellation issues when constructing the vector `csv` below. If we chose - // otherwise, we would have v1 ~= m11 when m12 is small. This would cause catastrophic - // cancellation on `v1 * v1 - m11 * m11` below. - let v1 = two * m11 * m22 / denom; - let v2 = half * denom; - - let mut u = None; - let mut v_t = None; - - if compute_u || compute_v { - let csv = Vector2::new(m11 * m12, v1 * v1 - m11 * m11).normalize(); - - if compute_v { - v_t = Some(UnitComplex::new_unchecked(Complex::new(csv.x, csv.y))); - } - - if compute_u { - let cu = (m11 * csv.x + m12 * csv.y) / v1; - let su = (m22 * csv.y) / v1; - - u = Some(UnitComplex::new_unchecked(Complex::new(cu, su))); - } - } - - (u, Vector2::new(v1, v2), v_t) - } - /* fn display_bidiag(b: &Bidiagonal, begin: usize, end: usize) { for i in begin .. end { @@ -338,11 +301,13 @@ where */ fn delimit_subproblem( - b: &mut Bidiagonal, + diagonal: &mut VectorN>, + off_diagonal: &mut VectorN, U1>>, u: &mut Option>>, v_t: &mut Option, C>>, + is_upper_diagonal: bool, end: usize, - eps: N, + eps: N::RealField, ) -> (usize, usize) { let mut n = end; @@ -350,20 +315,20 @@ where while n > 0 { let m = n - 1; - if b.off_diagonal[m].is_zero() - || b.off_diagonal[m].abs() <= eps * (b.diagonal[n].abs() + b.diagonal[m].abs()) + if off_diagonal[m].is_zero() + || off_diagonal[m].norm1() <= eps * (diagonal[n].norm1() + diagonal[m].norm1()) { - b.off_diagonal[m] = N::zero(); - } else if b.diagonal[m].abs() <= eps { - b.diagonal[m] = N::zero(); - Self::cancel_horizontal_off_diagonal_elt(b, u, v_t, m, m + 1); + 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); if m != 0 { - Self::cancel_vertical_off_diagonal_elt(b, u, v_t, m - 1); + Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m - 1); } - } else if b.diagonal[n].abs() <= eps { - b.diagonal[n] = N::zero(); - Self::cancel_vertical_off_diagonal_elt(b, u, v_t, m); + } 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); } else { break; } @@ -379,18 +344,18 @@ where while new_start > 0 { let m = new_start - 1; - if b.off_diagonal[m].abs() <= eps * (b.diagonal[new_start].abs() + b.diagonal[m].abs()) + if off_diagonal[m].norm1() <= eps * (diagonal[new_start].norm1() + diagonal[m].norm1()) { - b.off_diagonal[m] = N::zero(); + off_diagonal[m] = N::RealField::zero(); break; } // FIXME: write a test that enters this case. - else if b.diagonal[m].abs() <= eps { - b.diagonal[m] = N::zero(); - Self::cancel_horizontal_off_diagonal_elt(b, u, v_t, m, n); + 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); if m != 0 { - Self::cancel_vertical_off_diagonal_elt(b, u, v_t, m - 1); + Self::cancel_vertical_off_diagonal_elt(diagonal, off_diagonal, u, v_t, is_upper_diagonal, m - 1); } break; } @@ -403,21 +368,24 @@ where // Cancels the i-th off-diagonal element using givens rotations. fn cancel_horizontal_off_diagonal_elt( - b: &mut Bidiagonal, + diagonal: &mut VectorN>, + off_diagonal: &mut VectorN, U1>>, u: &mut Option>>, v_t: &mut Option, C>>, + is_upper_diagonal: bool, i: usize, end: usize, ) { - let mut v = Vector2::new(b.off_diagonal[i], b.diagonal[i + 1]); - b.off_diagonal[i] = N::zero(); + let mut v = Vector2::new(off_diagonal[i], diagonal[i + 1]); + off_diagonal[i] = N::RealField::zero(); for k in i..end { - if let Some((rot, norm)) = givens::cancel_x(&v) { - b.diagonal[k + 1] = norm; + if let Some((rot, norm)) = GivensRotation::cancel_x(&v) { + let rot = GivensRotation::new_unchecked(rot.c(), N::from_real(rot.s())); + diagonal[k + 1] = norm; - if b.is_upper_diagonal() { + if is_upper_diagonal { if let Some(ref mut u) = *u { rot.inverse() .rotate_rows(&mut u.fixed_columns_with_step_mut::(i, k - i)); @@ -427,9 +395,9 @@ where } if k + 1 != end { - v.x = -rot.sin_angle() * b.off_diagonal[k + 1]; - v.y = b.diagonal[k + 2]; - b.off_diagonal[k + 1] *= rot.cos_angle(); + v.x = -rot.s().real() * off_diagonal[k + 1]; + v.y = diagonal[k + 2]; + off_diagonal[k + 1] *= rot.c(); } } else { break; @@ -439,20 +407,23 @@ where // Cancels the i-th off-diagonal element using givens rotations. fn cancel_vertical_off_diagonal_elt( - b: &mut Bidiagonal, + diagonal: &mut VectorN>, + off_diagonal: &mut VectorN, U1>>, u: &mut Option>>, v_t: &mut Option, C>>, + is_upper_diagonal: bool, i: usize, ) { - let mut v = Vector2::new(b.diagonal[i], b.off_diagonal[i]); - b.off_diagonal[i] = N::zero(); + let mut v = Vector2::new(diagonal[i], off_diagonal[i]); + off_diagonal[i] = N::RealField::zero(); for k in (0..i + 1).rev() { - if let Some((rot, norm)) = givens::cancel_y(&v) { - b.diagonal[k] = norm; + if let Some((rot, norm)) = GivensRotation::cancel_y(&v) { + let rot = GivensRotation::new_unchecked(rot.c(), N::from_real(rot.s())); + diagonal[k] = norm; - if b.is_upper_diagonal() { + if is_upper_diagonal { if let Some(ref mut v_t) = *v_t { rot.rotate(&mut v_t.fixed_rows_with_step_mut::(k, i - k)); } @@ -462,9 +433,9 @@ where } if k > 0 { - v.x = b.diagonal[k - 1]; - v.y = rot.sin_angle() * b.off_diagonal[k - 1]; - b.off_diagonal[k - 1] *= rot.cos_angle(); + v.x = diagonal[k - 1]; + v.y = rot.s().real() * off_diagonal[k - 1]; + off_diagonal[k - 1] *= rot.c(); } } else { break; @@ -474,9 +445,9 @@ where /// Computes the rank of the decomposed matrix, i.e., the number of singular values greater /// than `eps`. - pub fn rank(&self, eps: N) -> usize { + pub fn rank(&self, eps: N::RealField) -> usize { assert!( - eps >= N::zero(), + eps >= N::RealField::zero(), "SVD rank: the epsilon must be non-negative." ); self.singular_values.iter().filter(|e| **e > eps).count() @@ -492,7 +463,7 @@ where (Some(mut u), Some(v_t)) => { for i in 0..self.singular_values.len() { let val = self.singular_values[i]; - u.column_mut(i).mul_assign(val); + u.column_mut(i).scale_mut(val); } Ok(u * v_t) } @@ -507,11 +478,11 @@ where /// Any singular value smaller than `eps` is assumed to be zero. /// Returns `Err` if the right- and left- singular vectors have not /// been computed at construction-time. - pub fn pseudo_inverse(mut self, eps: N) -> Result, &'static str> + pub fn pseudo_inverse(mut self, eps: N::RealField) -> Result, &'static str> where DefaultAllocator: Allocator, { - if eps < N::zero() { + if eps < N::RealField::zero() { Err("SVD pseudo inverse: the epsilon must be non-negative.") } else { @@ -519,13 +490,13 @@ where let val = self.singular_values[i]; if val > eps { - self.singular_values[i] = N::one() / val; + self.singular_values[i] = N::RealField::one() / val; } else { - self.singular_values[i] = N::zero(); + self.singular_values[i] = N::RealField::zero(); } } - self.recompose().map(|m| m.transpose()) + self.recompose().map(|m| m.adjoint()) } } @@ -537,20 +508,20 @@ where pub fn solve( &self, b: &Matrix, - eps: N, + eps: N::RealField, ) -> Result, &'static str> where S2: Storage, DefaultAllocator: Allocator + Allocator, C2>, ShapeConstraint: SameNumberOfRows, { - if eps < N::zero() { + if eps < N::RealField::zero() { Err("SVD solve: the epsilon must be non-negative.") } else { match (&self.u, &self.v_t) { (Some(u), Some(v_t)) => { - let mut ut_b = u.tr_mul(b); + let mut ut_b = u.ad_mul(b); for j in 0..ut_b.ncols() { let mut col = ut_b.column_mut(j); @@ -558,14 +529,14 @@ where for i in 0..self.singular_values.len() { let val = self.singular_values[i]; if val > eps { - col[i] /= val; + col[i] = col[i].unscale(val); } else { col[i] = N::zero(); } } } - Ok(v_t.tr_mul(&ut_b)) + Ok(v_t.ad_mul(&ut_b)) } (None, None) => Err("SVD solve: U and V^t have not been computed."), (None, _) => Err("SVD solve: U has not been computed."), @@ -575,7 +546,7 @@ where } } -impl, C: Dim, S: Storage> Matrix +impl, C: Dim, S: Storage> Matrix where DimMinimum: DimSub, // for Bidiagonal. DefaultAllocator: Allocator @@ -584,7 +555,9 @@ where + Allocator, U1>> + Allocator, C> + Allocator> - + Allocator>, + + Allocator> + + Allocator> + + Allocator, U1>>, { /// Computes the Singular Value Decomposition using implicit shift. pub fn svd(self, compute_u: bool, compute_v: bool) -> SVD { @@ -605,7 +578,7 @@ where self, compute_u: bool, compute_v: bool, - eps: N, + eps: N::RealField, max_niter: usize, ) -> Option> { @@ -613,14 +586,14 @@ where } /// Computes the singular values of this matrix. - pub fn singular_values(&self) -> VectorN> { + pub fn singular_values(&self) -> VectorN> { SVD::new(self.clone_owned(), false, false).singular_values } /// Computes the rank of this matrix. /// /// All singular values below `eps` are considered equal to 0. - pub fn rank(&self, eps: N) -> usize { + pub fn rank(&self, eps: N::RealField) -> usize { let svd = SVD::new(self.clone_owned(), false, false); svd.rank(eps) } @@ -628,10 +601,60 @@ where /// Computes the pseudo-inverse of this matrix. /// /// All singular values below `eps` are considered equal to 0. - pub fn pseudo_inverse(self, eps: N) -> Result, &'static str> + pub fn pseudo_inverse(self, eps: N::RealField) -> Result, &'static str> where DefaultAllocator: Allocator, { SVD::new(self.clone_owned(), true, true).pseudo_inverse(eps) } } + + +// 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 +fn compute_2x2_uptrig_svd( + m11: N, + m12: N, + m22: N, + compute_u: bool, + compute_v: bool, +) -> (Option>, Vector2, Option>) +{ + let two: N::RealField = crate::convert(2.0f64); + let half: N::RealField = crate::convert(0.5f64); + + let denom = (m11 + m22).hypot(m12) + (m11 - m22).hypot(m12); + + // NOTE: v1 is the singular value that is the closest to m22. + // This prevents cancellation issues when constructing the vector `csv` below. If we chose + // otherwise, we would have v1 ~= m11 when m12 is small. This would cause catastrophic + // cancellation on `v1 * v1 - m11 * m11` below. + let mut v1 = m11 * m22 * two / denom; + let mut v2 = half * denom; + + let mut u = None; + let mut v_t = None; + + if compute_u || compute_v { + let (csv, sgn_v) = GivensRotation::new(m11 * m12, v1 * v1 - m11 * m11); + v1 *= sgn_v; + v2 *= sgn_v; + + if compute_v { + v_t = Some(csv); + } + + if compute_u { + let cu = (m11.scale(csv.c()) + m12 * csv.s()) / v1; + let su = (m22 * csv.s()) / v1; + let (csu, sgn_u) = GivensRotation::new(cu, su); + + v1 *= sgn_u; + v2 *= sgn_u; + u = Some(csu); + } + } + + (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 cd455b7c6..fc493dca2 100644 --- a/src/linalg/symmetric_eigen.rs +++ b/src/linalg/symmetric_eigen.rs @@ -1,18 +1,17 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use num_complex::Complex; -use std::ops::MulAssign; +use num::Zero; +use approx::AbsDiffEq; -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, Matrix2, MatrixN, SquareMatrix, Vector2, VectorN}; -use dimension::{Dim, DimDiff, DimSub, U1, U2}; -use storage::Storage; +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 geometry::UnitComplex; -use linalg::givens; -use linalg::SymmetricTridiagonal; +use crate::linalg::givens::GivensRotation; +use crate::linalg::SymmetricTridiagonal; /// Eigendecomposition of a symmetric matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -20,8 +19,8 @@ use linalg::SymmetricTridiagonal; feature = "serde-serialize", serde(bound( serialize = "DefaultAllocator: Allocator + - Allocator, - VectorN: Serialize, + Allocator, + VectorN: Serialize, MatrixN: Serialize" )) )] @@ -29,31 +28,31 @@ use linalg::SymmetricTridiagonal; feature = "serde-serialize", serde(bound( deserialize = "DefaultAllocator: Allocator + - Allocator, - VectorN: Deserialize<'de>, + Allocator, + VectorN: Deserialize<'de>, MatrixN: Deserialize<'de>" )) )] #[derive(Clone, Debug)] -pub struct SymmetricEigen -where DefaultAllocator: Allocator + Allocator +pub struct SymmetricEigen +where DefaultAllocator: Allocator + Allocator { /// The eigenvectors of the decomposed matrix. pub eigenvectors: MatrixN, /// The unsorted eigenvalues of the decomposed matrix. - pub eigenvalues: VectorN, + pub eigenvalues: VectorN, } -impl Copy for SymmetricEigen +impl Copy for SymmetricEigen where - DefaultAllocator: Allocator + Allocator, + DefaultAllocator: Allocator + Allocator, MatrixN: Copy, - VectorN: Copy, + VectorN: Copy, {} -impl SymmetricEigen -where DefaultAllocator: Allocator + Allocator +impl SymmetricEigen +where DefaultAllocator: Allocator + Allocator { /// Computes the eigendecomposition of the given symmetric matrix. /// @@ -61,9 +60,10 @@ where DefaultAllocator: Allocator + Allocator pub fn new(m: MatrixN) -> Self where D: DimSub, - DefaultAllocator: Allocator>, + DefaultAllocator: Allocator> + // For tridiagonalization + Allocator>, { - Self::try_new(m, N::default_epsilon(), 0).unwrap() + Self::try_new(m, N::RealField::default_epsilon(), 0).unwrap() } /// Computes the eigendecomposition of the given symmetric matrix with user-specified @@ -77,10 +77,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_new(m: MatrixN, eps: N, max_niter: usize) -> Option + pub fn try_new(m: MatrixN, eps: N::RealField, max_niter: usize) -> Option where D: DimSub, - DefaultAllocator: Allocator>, + DefaultAllocator: Allocator> + // For tridiagonalization + Allocator>, { Self::do_decompose(m, true, eps, max_niter).map(|(vals, vecs)| SymmetricEigen { eigenvectors: vecs.unwrap(), @@ -91,23 +92,23 @@ where DefaultAllocator: Allocator + Allocator fn do_decompose( mut m: MatrixN, eigenvectors: bool, - eps: N, + eps: N::RealField, max_niter: usize, - ) -> Option<(VectorN, Option>)> + ) -> Option<(VectorN, Option>)> where D: DimSub, - DefaultAllocator: Allocator>, + DefaultAllocator: Allocator> + // For tridiagonalization + Allocator>, { assert!( m.is_square(), "Unable to compute the eigendecomposition of a non-square matrix." ); let dim = m.nrows(); - - let m_amax = m.amax(); + let m_amax = m.camax(); if !m_amax.is_zero() { - m /= m_amax; + m.unscale_mut(m_amax); } let (mut q, mut diag, mut off_diag); @@ -125,7 +126,7 @@ where DefaultAllocator: Allocator + Allocator } if dim == 1 { - diag *= m_amax; + diag.scale_mut(m_amax); return Some((diag, q)); } @@ -147,21 +148,22 @@ where DefaultAllocator: Allocator + Allocator for i in start..n { let j = i + 1; - if let Some((rot, norm)) = givens::cancel_y(&v) { + if let Some((rot, norm)) = GivensRotation::cancel_y(&v) { if i > start { // Not the first iteration. off_diag[i - 1] = norm; } + let mii = diag[i]; let mjj = diag[j]; let mij = off_diag[i]; - let cc = rot.cos_angle() * rot.cos_angle(); - let ss = rot.sin_angle() * rot.sin_angle(); - let cs = rot.cos_angle() * rot.sin_angle(); + let cc = rot.c() * rot.c(); + let ss = rot.s() * rot.s(); + let cs = rot.c() * rot.s(); - let b = cs * ::convert(2.0) * mij; + let b = cs * crate::convert(2.0) * mij; diag[i] = (cc * mii + ss * mjj) - b; diag[j] = (ss * mii + cc * mjj) + b; @@ -169,11 +171,12 @@ where DefaultAllocator: Allocator + Allocator if i != n - 1 { v.x = off_diag[i]; - v.y = -rot.sin_angle() * off_diag[i + 1]; - off_diag[i + 1] *= rot.cos_angle(); + v.y = -rot.s() * off_diag[i + 1]; + off_diag[i + 1] *= rot.c(); } if let Some(ref mut q) = q { + let rot = GivensRotation::new_unchecked(rot.c(), N::from_real(rot.s())); rot.inverse().rotate_rows(&mut q.fixed_columns_mut::(i)); } } else { @@ -181,15 +184,13 @@ where DefaultAllocator: Allocator + Allocator } } - if off_diag[m].abs() <= eps * (diag[m].abs() + diag[n].abs()) { + if off_diag[m].norm1() <= eps * (diag[m].norm1() + diag[n].norm1()) { end -= 1; } } else if subdim == 2 { let m = Matrix2::new( - diag[start], - off_diag[start], - 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]); @@ -198,8 +199,8 @@ where DefaultAllocator: Allocator + Allocator diag[start + 1] = eigvals[1]; if let Some(ref mut q) = q { - if let Some(basis) = basis.try_normalize(eps) { - let rot = UnitComplex::new_unchecked(Complex::new(basis.x, basis.y)); + if let Some((rot, _)) = GivensRotation::try_new(basis.x, basis.y, eps) { + let rot = GivensRotation::new_unchecked(rot.c(), N::from_real(rot.s())); rot.rotate_rows(&mut q.fixed_columns_mut::(start)); } } @@ -219,27 +220,27 @@ where DefaultAllocator: Allocator + Allocator } } - diag *= m_amax; + diag.scale_mut(m_amax); Some((diag, q)) } fn delimit_subproblem( - diag: &VectorN, - off_diag: &mut VectorN>, + diag: &VectorN, + off_diag: &mut VectorN>, end: usize, - eps: N, + eps: N::RealField, ) -> (usize, usize) where D: DimSub, - DefaultAllocator: Allocator>, + DefaultAllocator: Allocator>, { let mut n = end; while n > 0 { let m = n - 1; - if off_diag[m].abs() > eps * (diag[n].abs() + diag[m].abs()) { + if off_diag[m].norm1() > eps * (diag[n].norm1() + diag[m].norm1()) { break; } @@ -255,9 +256,9 @@ where DefaultAllocator: Allocator + Allocator let m = new_start - 1; if off_diag[m].is_zero() - || off_diag[m].abs() <= eps * (diag[new_start].abs() + diag[m].abs()) + || off_diag[m].norm1() <= eps * (diag[new_start].norm1() + diag[m].norm1()) { - off_diag[m] = N::zero(); + off_diag[m] = N::RealField::zero(); break; } @@ -274,9 +275,9 @@ where DefaultAllocator: Allocator + Allocator let mut u_t = self.eigenvectors.clone(); for i in 0..self.eigenvalues.len() { let val = self.eigenvalues[i]; - u_t.column_mut(i).mul_assign(val); + u_t.column_mut(i).scale_mut(val); } - u_t.transpose_mut(); + u_t.adjoint_mut(); &self.eigenvectors * u_t } } @@ -287,11 +288,11 @@ where DefaultAllocator: Allocator + Allocator /// The inputs are interpreted as the 2x2 matrix: /// tmm tmn /// tmn tnn -pub fn wilkinson_shift(tmm: N, tnn: N, tmn: N) -> N { +pub fn wilkinson_shift(tmm: N, tnn: N, tmn: N) -> N { let sq_tmn = tmn * tmn; if !sq_tmn.is_zero() { // We have the guarantee that the denominator won't be zero. - let d = (tmm - tnn) * ::convert(0.5); + let d = (tmm - tnn) * crate::convert(0.5); tnn - sq_tmn / (d + d.signum() * (d * d + sq_tmn).sqrt()) } else { tnn @@ -303,8 +304,9 @@ pub fn wilkinson_shift(tmm: N, tnn: N, tmn: N) -> N { * Computations of eigenvalues for symmetric matrices. * */ -impl, S: Storage> SquareMatrix -where DefaultAllocator: Allocator + Allocator + Allocator> +impl, S: Storage> SquareMatrix +where DefaultAllocator: Allocator + Allocator> + + Allocator + Allocator> { /// Computes the eigendecomposition of this symmetric matrix. /// @@ -324,15 +326,15 @@ where DefaultAllocator: Allocator + Allocator + Allocator Option> { + pub fn try_symmetric_eigen(self, eps: N::RealField, max_niter: usize) -> Option> { SymmetricEigen::try_new(self.into_owned(), eps, max_niter) } /// Computes the eigenvalues of this symmetric matrix. /// /// Only the lower-triangular part of the matrix is read. - pub fn symmetric_eigenvalues(&self) -> VectorN { - SymmetricEigen::do_decompose(self.clone_owned(), false, N::default_epsilon(), 0) + pub fn symmetric_eigenvalues(&self) -> VectorN { + SymmetricEigen::do_decompose(self.clone_owned(), false, N::RealField::default_epsilon(), 0) .unwrap() .0 } @@ -340,7 +342,7 @@ where DefaultAllocator: Allocator + Allocator + Allocator) -> f64 { let vals = m.eigenvalues().unwrap(); @@ -360,7 +362,6 @@ mod test { let expected = expected_shift(m); let computed = super::wilkinson_shift(m.m11, m.m22, m.m12); - println!("{} {}", expected, computed); assert!(relative_eq!(expected, computed, epsilon = 1.0e-7)); } } diff --git a/src/linalg/symmetric_tridiagonal.rs b/src/linalg/symmetric_tridiagonal.rs index 2e4108aef..40da8677a 100644 --- a/src/linalg/symmetric_tridiagonal.rs +++ b/src/linalg/symmetric_tridiagonal.rs @@ -1,13 +1,13 @@ #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Serialize}; -use alga::general::Real; -use allocator::Allocator; -use base::{DefaultAllocator, MatrixMN, MatrixN, SquareMatrix, VectorN}; -use dimension::{DimDiff, DimSub, U1}; -use storage::Storage; +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 linalg::householder; +use crate::linalg::householder; /// Tridiagonalization of a symmetric matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] @@ -30,21 +30,21 @@ use linalg::householder; )) )] #[derive(Clone, Debug)] -pub struct SymmetricTridiagonal> +pub struct SymmetricTridiagonal> where DefaultAllocator: Allocator + Allocator> { tri: MatrixN, off_diagonal: VectorN>, } -impl> Copy for SymmetricTridiagonal +impl> Copy for SymmetricTridiagonal where DefaultAllocator: Allocator + Allocator>, MatrixN: Copy, VectorN>: Copy, {} -impl> SymmetricTridiagonal +impl> SymmetricTridiagonal where DefaultAllocator: Allocator + Allocator> { /// Computes the tridiagonalization of the symmetric matrix `m`. @@ -75,17 +75,18 @@ where DefaultAllocator: Allocator + Allocator> if not_zero { let mut p = p.rows_range_mut(i..); - p.gemv_symm(::convert(2.0), &m, &axis, N::zero()); - let dot = axis.dot(&p); - p.axpy(-dot, &axis, N::one()); - m.ger_symm(-N::one(), &p, &axis, N::one()); - m.ger_symm(-N::one(), &axis, &p, N::one()); + p.hegemv(crate::convert(2.0), &m, &axis, N::zero()); + + let dot = axis.dotc(&p); + m.hegerc(-N::one(), &p, &axis, N::one()); + m.hegerc(-N::one(), &axis, &p, N::one()); + m.hegerc(dot * crate::convert(2.0), &axis, &axis, N::one()); } } Self { tri: m, - off_diagonal: off_diagonal, + off_diagonal, } } @@ -97,37 +98,35 @@ 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 { + pub fn unpack(self) -> (MatrixN, VectorN, VectorN>) + where DefaultAllocator: Allocator + + Allocator> { let diag = self.diagonal(); let q = self.q(); - (q, diag, self.off_diagonal) + (q, diag, self.off_diagonal.map(N::modulus)) } /// Retrieve the diagonal, and off diagonal elements of this decomposition. - pub fn unpack_tridiagonal(self) -> (VectorN, VectorN>) - where DefaultAllocator: Allocator { - let diag = self.diagonal(); - - (diag, self.off_diagonal) + 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.diagonal() - } + pub fn diagonal(&self) -> VectorN + 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 { - &self.off_diagonal + pub fn off_diagonal(&self) -> VectorN> + where DefaultAllocator: Allocator> { + self.off_diagonal.map(N::modulus) } /// Computes the orthogonal matrix `Q` of this decomposition. pub fn q(&self) -> MatrixN { - householder::assemble_q(&self.tri) + householder::assemble_q(&self.tri, self.off_diagonal.as_slice()) } /// Recomputes the original symmetric matrix. @@ -137,15 +136,16 @@ where DefaultAllocator: Allocator + Allocator> self.tri.fill_upper_triangle(N::zero(), 2); for i in 0..self.off_diagonal.len() { - self.tri[(i + 1, i)] = self.off_diagonal[i]; - self.tri[(i, i + 1)] = self.off_diagonal[i]; + let val = N::from_real(self.off_diagonal[i].modulus()); + self.tri[(i + 1, i)] = val; + self.tri[(i, i + 1)] = val; } - &q * self.tri * q.transpose() + &q * self.tri * q.adjoint() } } -impl, S: Storage> SquareMatrix +impl, S: Storage> SquareMatrix 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 4c2983eb8..2fc571c76 100644 --- a/src/sparse/cs_matrix.rs +++ b/src/sparse/cs_matrix.rs @@ -5,9 +5,9 @@ use std::marker::PhantomData; use std::ops::Range; use std::slice; -use allocator::Allocator; -use sparse::cs_utils; -use { +use crate::allocator::Allocator; +use crate::sparse::cs_utils; +use crate::{ DefaultAllocator, Dim, Dynamic, Scalar, Vector, VectorN, U1 }; diff --git a/src/sparse/cs_matrix_cholesky.rs b/src/sparse/cs_matrix_cholesky.rs index 5d834ef21..4c3fffd82 100644 --- a/src/sparse/cs_matrix_cholesky.rs +++ b/src/sparse/cs_matrix_cholesky.rs @@ -1,12 +1,12 @@ use std::iter; use std::mem; -use allocator::Allocator; -use sparse::{CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsVecStorage}; -use {DefaultAllocator, Dim, Real, VectorN, U1}; +use crate::allocator::Allocator; +use crate::sparse::{CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsVecStorage}; +use crate::{DefaultAllocator, Dim, RealField, VectorN, U1}; /// The cholesky decomposition of a column compressed sparse matrix. -pub struct CsCholesky +pub struct CsCholesky where DefaultAllocator: Allocator + Allocator { // Non-zero pattern of the original matrix upper-triangular part. @@ -25,7 +25,7 @@ where DefaultAllocator: Allocator + Allocator work_c: VectorN, } -impl CsCholesky +impl CsCholesky where DefaultAllocator: Allocator + Allocator { /// Computes the cholesky decomposition of the sparse matrix `m`. diff --git a/src/sparse/cs_matrix_conversion.rs b/src/sparse/cs_matrix_conversion.rs index 0017340f0..31e537963 100644 --- a/src/sparse/cs_matrix_conversion.rs +++ b/src/sparse/cs_matrix_conversion.rs @@ -1,11 +1,11 @@ use alga::general::ClosedAdd; use num::Zero; -use allocator::Allocator; -use sparse::cs_utils; -use sparse::{CsMatrix, CsStorage}; -use storage::Storage; -use {DefaultAllocator, Dim, Dynamic, Matrix, MatrixMN, Scalar}; +use crate::allocator::Allocator; +use crate::sparse::cs_utils; +use crate::sparse::{CsMatrix, CsStorage}; +use crate::storage::Storage; +use crate::{DefaultAllocator, Dim, Dynamic, Matrix, MatrixMN, Scalar}; impl<'a, N: Scalar + Zero + ClosedAdd> CsMatrix { /// Creates a column-compressed sparse matrix from a sparse matrix in triplet form. diff --git a/src/sparse/cs_matrix_ops.rs b/src/sparse/cs_matrix_ops.rs index b944c4e2f..322ebb34c 100644 --- a/src/sparse/cs_matrix_ops.rs +++ b/src/sparse/cs_matrix_ops.rs @@ -2,11 +2,11 @@ use alga::general::{ClosedAdd, ClosedMul}; use num::{One, Zero}; use std::ops::{Add, Mul}; -use allocator::Allocator; -use constraint::{AreMultipliable, DimEq, ShapeConstraint}; -use sparse::{CsMatrix, CsStorage, CsStorageMut, CsVector}; -use storage::StorageMut; -use {DefaultAllocator, Dim, Scalar, Vector, VectorN, U1}; +use crate::allocator::Allocator; +use crate::constraint::{AreMultipliable, DimEq, ShapeConstraint}; +use crate::sparse::{CsMatrix, CsStorage, CsStorageMut, CsVector}; +use crate::storage::StorageMut; +use crate::{DefaultAllocator, Dim, Scalar, Vector, VectorN, U1}; impl> CsMatrix { fn scatter( diff --git a/src/sparse/cs_matrix_solve.rs b/src/sparse/cs_matrix_solve.rs index 2a13188e6..14ca9f781 100644 --- a/src/sparse/cs_matrix_solve.rs +++ b/src/sparse/cs_matrix_solve.rs @@ -1,10 +1,10 @@ -use allocator::Allocator; -use constraint::{SameNumberOfRows, ShapeConstraint}; -use sparse::{CsMatrix, CsStorage, CsVector}; -use storage::{Storage, StorageMut}; -use {DefaultAllocator, Dim, Matrix, MatrixMN, Real, VectorN, U1}; +use crate::allocator::Allocator; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::sparse::{CsMatrix, CsStorage, CsVector}; +use crate::storage::{Storage, StorageMut}; +use crate::{DefaultAllocator, Dim, Matrix, MatrixMN, RealField, VectorN, U1}; -impl> CsMatrix { +impl> CsMatrix { /// Solve a lower-triangular system with a dense right-hand-side. pub fn solve_lower_triangular( &self, @@ -78,7 +78,8 @@ impl> CsMatrix { } for (i, val) in column { - b[i] -= b[j] * val; + let bj = b[j]; + b[i] -= bj * val; } } } @@ -119,7 +120,8 @@ impl> CsMatrix { if let Some(diag) = diag { for (i, val) in column { - b[j] -= val * b[i]; + let bi = b[i]; + b[j] -= val * bi; } b[j] /= diag; @@ -178,7 +180,8 @@ impl> CsMatrix { } for (i, val) in column { - workspace[i] -= workspace[j] * val; + let wj = workspace[j]; + workspace[i] -= wj * val; } } diff --git a/src/sparse/cs_utils.rs b/src/sparse/cs_utils.rs index 3c5db43e4..a8a454eb6 100644 --- a/src/sparse/cs_utils.rs +++ b/src/sparse/cs_utils.rs @@ -1,5 +1,5 @@ -use allocator::Allocator; -use {DefaultAllocator, Dim, VectorN}; +use crate::allocator::Allocator; +use crate::{DefaultAllocator, Dim, VectorN}; pub fn cumsum(a: &mut VectorN, b: &mut VectorN) -> usize where DefaultAllocator: Allocator { diff --git a/tests/core/abomonation.rs b/tests/core/abomonation.rs index be3952cd6..01760e14a 100644 --- a/tests/core/abomonation.rs +++ b/tests/core/abomonation.rs @@ -40,7 +40,7 @@ fn assert_encode_and_decode(original_data: T // Encode let mut bytes = Vec::new(); unsafe { - encode(&original_data, &mut bytes); + let _ = encode(&original_data, &mut bytes); } // Drop the original, so that dangling pointers are revealed by the test diff --git a/tests/core/blas.rs b/tests/core/blas.rs index 00eac3a3f..38113c17d 100644 --- a/tests/core/blas.rs +++ b/tests/core/blas.rs @@ -19,14 +19,14 @@ quickcheck! { let mut y2 = y1.clone(); y1.gemv(alpha, &a, &x, beta); - y2.gemv_symm(alpha, &a.lower_triangle(), &x, beta); + y2.sygemv(alpha, &a.lower_triangle(), &x, beta); if !relative_eq!(y1, y2, epsilon = 1.0e-10) { return false; } y1.gemv(alpha, &a, &x, 0.0); - y2.gemv_symm(alpha, &a.lower_triangle(), &x, 0.0); + y2.sygemv(alpha, &a.lower_triangle(), &x, 0.0); relative_eq!(y1, y2, epsilon = 1.0e-10) } @@ -61,14 +61,14 @@ quickcheck! { let y = DVector::new_random(n); a1.ger(alpha, &x, &y, beta); - a2.ger_symm(alpha, &x, &y, beta); + a2.syger(alpha, &x, &y, beta); if !relative_eq!(a1.lower_triangle(), a2) { return false; } a1.ger(alpha, &x, &y, 0.0); - a2.ger_symm(alpha, &x, &y, 0.0); + a2.syger(alpha, &x, &y, 0.0); relative_eq!(a1.lower_triangle(), a2) } diff --git a/tests/core/helper.rs b/tests/core/helper.rs new file mode 100644 index 000000000..625a4a464 --- /dev/null +++ b/tests/core/helper.rs @@ -0,0 +1,54 @@ +// 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; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct RandComplex(pub Complex); + +impl Arbitrary for RandComplex { + #[inline] + fn arbitrary(rng: &mut G) -> Self { + let im = Arbitrary::arbitrary(rng); + let re = Arbitrary::arbitrary(rng); + RandComplex(Complex::new(re, im)) + } +} + +impl Distribution> for Standard + where + Standard: Distribution, +{ + #[inline] + fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> RandComplex { + let re = rng.gen(); + let im = rng.gen(); + RandComplex(Complex::new(re, im)) + } +} + +// This is a wrapper similar to RandComplex, but for non-complex. +// This exists only to make generic tests easier to write. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct RandScalar(pub N); + +impl Arbitrary for RandScalar { + #[inline] + fn arbitrary(rng: &mut G) -> Self { + RandScalar(Arbitrary::arbitrary(rng)) + } +} + +impl Distribution> for Standard + 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 9c6d468af..e4fb4d0c2 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; use na::dimension::{U15, U8}; use na::{ self, DMatrix, DVector, Matrix2, Matrix2x3, Matrix2x4, Matrix3, Matrix3x2, Matrix3x4, Matrix4, - Matrix4x3, Matrix4x5, Matrix5, Matrix6, MatrixMN, Real, RowVector3, RowVector4, RowVector5, + Matrix4x3, Matrix4x5, Matrix5, Matrix6, MatrixMN, RowVector3, RowVector4, RowVector5, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, }; @@ -417,7 +417,7 @@ fn simple_scalar_conversion() { #[test] fn apply() { let mut a = Matrix4::new( - 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 8.8, 7.7, 6.6, 5.5, 4.4, 3.3, 2.2, + 1.1f32, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 8.8, 7.7, 6.6, 5.5, 4.4, 3.3, 2.2, ); let expected = Matrix4::new( @@ -1022,7 +1022,7 @@ 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) { diff --git a/tests/core/mod.rs b/tests/core/mod.rs index 7e1f85919..c53493bdc 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -8,3 +8,7 @@ mod matrix_slice; #[cfg(feature = "mint")] mod mint; mod serde; + + +#[cfg(feature = "arbitrary")] +pub mod helper; \ No newline at end of file diff --git a/tests/geometry/isometry.rs b/tests/geometry/isometry.rs index a0e002722..ecf29e94e 100644 --- a/tests/geometry/isometry.rs +++ b/tests/geometry/isometry.rs @@ -1,7 +1,6 @@ #![cfg(feature = "arbitrary")] #![allow(non_snake_case)] -use alga::linear::{ProjectiveTransformation, Transformation}; use na::{ Isometry2, Isometry3, Point2, Point3, Rotation2, Rotation3, Translation2, Translation3, UnitComplex, UnitQuaternion, Vector2, Vector3, @@ -82,7 +81,7 @@ quickcheck!( r: Rotation2, t: Translation2, v: Vector2, - p: Point2, + p: Point2 ) -> bool { // (rotation × translation) * point = rotation × (translation * point) @@ -120,7 +119,7 @@ quickcheck!( r: Rotation3, t: Translation3, v: Vector3, - p: Point3, + p: Point3 ) -> bool { // (rotation × translation) * point = rotation × (translation * point) @@ -158,7 +157,7 @@ quickcheck!( t: Translation3, v: Vector3, p: Point3, - r: Rotation3, + r: Rotation3 ) -> bool { let iMi = i * i; diff --git a/tests/geometry/rotation.rs b/tests/geometry/rotation.rs index e4b1f9d75..c08867549 100644 --- a/tests/geometry/rotation.rs +++ b/tests/geometry/rotation.rs @@ -1,4 +1,4 @@ -use na::{Quaternion, Real, UnitQuaternion, Vector2, Vector3}; +use na::{Quaternion, RealField, UnitQuaternion, Vector2, Vector3}; #[test] fn angle_2() { @@ -32,7 +32,7 @@ fn quaternion_euler_angles_issue_494() { #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use alga::general::Real; + use alga::general::RealField; use na::{self, Rotation2, Rotation3, Unit, Vector2, Vector3}; use std::f64; diff --git a/tests/geometry/similarity.rs b/tests/geometry/similarity.rs index 68b86943d..a57368646 100644 --- a/tests/geometry/similarity.rs +++ b/tests/geometry/similarity.rs @@ -1,7 +1,6 @@ #![cfg(feature = "arbitrary")] #![allow(non_snake_case)] -use alga::linear::{ProjectiveTransformation, Transformation}; use na::{Isometry3, Point3, Similarity3, Translation3, UnitQuaternion, Vector3}; quickcheck!( @@ -19,7 +18,7 @@ quickcheck!( fn inverse_is_parts_inversion( t: Translation3, r: UnitQuaternion, - scaling: f64, + scaling: f64 ) -> bool { if relative_eq!(scaling, 0.0) { @@ -33,7 +32,7 @@ quickcheck!( fn multiply_equals_alga_transform( s: Similarity3, v: Vector3, - p: Point3, + p: Point3 ) -> bool { s * v == s.transform_vector(&v) @@ -56,7 +55,7 @@ quickcheck!( t: Translation3, v: Vector3, p: Point3, - scaling: f64, + scaling: f64 ) -> bool { if relative_eq!(scaling, 0.0) { @@ -152,7 +151,7 @@ quickcheck!( uq: UnitQuaternion, t: Translation3, v: Vector3, - p: Point3, + p: Point3 ) -> bool { let sMs = s * s; diff --git a/tests/geometry/unit_complex.rs b/tests/geometry/unit_complex.rs index 88988aa87..469980368 100644 --- a/tests/geometry/unit_complex.rs +++ b/tests/geometry/unit_complex.rs @@ -72,7 +72,7 @@ quickcheck!( uc: UnitComplex, v: Vector2, p: Point2, - r: Rotation2, + r: Rotation2 ) -> bool { let uv = Unit::new_normalize(v); diff --git a/tests/lib.rs b/tests/lib.rs index c32f40669..f6634d0fc 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -12,9 +12,10 @@ extern crate num_traits as num; extern crate quickcheck; extern crate rand; extern crate serde_json; +extern crate num_complex; mod core; mod geometry; mod linalg; -#[cfg(feature = "sparse")] -mod sparse; +//#[cfg(feature = "sparse")] +//mod sparse; diff --git a/tests/linalg/bidiagonal.rs b/tests/linalg/bidiagonal.rs index a7d5952fd..9778eea31 100644 --- a/tests/linalg/bidiagonal.rs +++ b/tests/linalg/bidiagonal.rs @@ -1,59 +1,78 @@ #![cfg(feature = "arbitrary")] -use na::{DMatrix, Matrix2, Matrix3x5, Matrix4, Matrix5x3}; - -quickcheck! { - fn bidiagonal(m: DMatrix) -> bool { - if m.len() == 0 { - return true; +macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::{DMatrix, Matrix2, Matrix3x5, Matrix4, Matrix5x3}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn bidiagonal(m: DMatrix<$scalar>) -> bool { + let m = m.map(|e| e.0); + if m.len() == 0 { + return true; + } + + let bidiagonal = m.clone().bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + + relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) + } + + fn bidiagonal_static_5_3(m: Matrix5x3<$scalar>) -> bool { + let m = m.map(|e| e.0); + let bidiagonal = m.bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + + relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) + } + + fn bidiagonal_static_3_5(m: Matrix3x5<$scalar>) -> bool { + let m = m.map(|e| e.0); + let bidiagonal = m.bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + + relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) + } + + fn bidiagonal_static_square(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let bidiagonal = m.bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + + relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) + } + + fn bidiagonal_static_square_2x2(m: Matrix2<$scalar>) -> bool { + let m = m.map(|e| e.0); + let bidiagonal = m.bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + + relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) + } + } } - - let bidiagonal = m.clone().bidiagonalize(); - let (u, d, v_t) = bidiagonal.unpack(); - - println!("{}{}{}", &u, &d, &v_t); - println!("{:.7}{:.7}", &u * &d * &v_t, m); - - relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) - } - - fn bidiagonal_static_5_3(m: Matrix5x3) -> bool { - let bidiagonal = m.bidiagonalize(); - let (u, d, v_t) = bidiagonal.unpack(); - - println!("{}{}{}", &u, &d, &v_t); - println!("{:.7}{:.7}", &u * &d * &v_t, m); - - relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) - } - - fn bidiagonal_static_3_5(m: Matrix3x5) -> bool { - let bidiagonal = m.bidiagonalize(); - let (u, d, v_t) = bidiagonal.unpack(); - - println!("{}{}{}", &u, &d, &v_t); - println!("{:.7}{:.7}", &u * &d * &v_t, m); - - relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) - } - - fn bidiagonal_static_square(m: Matrix4) -> bool { - let bidiagonal = m.bidiagonalize(); - let (u, d, v_t) = bidiagonal.unpack(); - - println!("{}{}{}", &u, &d, &v_t); - println!("{:.7}{:.7}", &u * &d * &v_t, m); - - relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) - } - - fn bidiagonal_static_square_2x2(m: Matrix2) -> bool { - let bidiagonal = m.bidiagonalize(); - let (u, d, v_t) = bidiagonal.unpack(); - - println!("{}{}{}", &u, &d, &v_t); - println!("{:.7}{:.7}", &u * &d * &v_t, m); - - relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7) } -} +); + +gen_tests!(complex, RandComplex); +gen_tests!(f64, RandScalar); + +#[test] +fn bidiagonal_identity() { + let m = na::DMatrix::::identity(10, 10); + let bidiagonal = m.clone().bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + assert_eq!(m, &u * d * &v_t); + + let m = na::DMatrix::::identity(10, 15); + let bidiagonal = m.clone().bidiagonalize(); + let (u, d, v_t) = bidiagonal.unpack(); + assert_eq!(m, &u * d * &v_t); + + let m = na::DMatrix::::identity(15, 10); + 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/cholesky.rs b/tests/linalg/cholesky.rs index 9fe086ff9..cefc26307 100644 --- a/tests/linalg/cholesky.rs +++ b/tests/linalg/cholesky.rs @@ -1,81 +1,87 @@ #![cfg(all(feature = "arbitrary", feature = "debug"))] -use na::debug::RandomSDP; -use na::dimension::U4; -use na::{DMatrix, DVector, Matrix4x3, Vector4}; -use std::cmp; -quickcheck! { - fn cholesky(m: RandomSDP) -> bool { - let mut m = m.unwrap(); - - // Put garbage on the upper triangle to make sure it is not read by the decomposition. - m.fill_upper_triangle(23.0, 1); - - let l = m.clone().cholesky().unwrap().unpack(); - m.fill_upper_triangle_with_lower_triangle(); - relative_eq!(m, &l * l.transpose(), epsilon = 1.0e-7) - } - - fn cholesky_static(m: RandomSDP) -> bool { - let m = m.unwrap(); - let chol = m.cholesky().unwrap(); - let l = chol.unpack(); - - if !relative_eq!(m, &l * l.transpose(), epsilon = 1.0e-7) { - false - } - else { - true +macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::debug::RandomSDP; + use na::dimension::{U4, Dynamic}; + use na::{DMatrix, DVector, Matrix4x3, Vector4}; + use rand::random; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + use std::cmp; + + quickcheck! { + fn cholesky(n: usize) -> bool { + let m = RandomSDP::new(Dynamic::new(n.max(1).min(50)), || random::<$scalar>().0).unwrap(); + let l = m.clone().cholesky().unwrap().unpack(); + relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7) + } + + fn cholesky_static(_m: RandomSDP) -> bool { + let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap(); + let chol = m.cholesky().unwrap(); + let l = chol.unpack(); + + if !relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7) { + false + } + else { + true + } + } + + fn cholesky_solve(n: usize, nb: usize) -> bool { + let n = n.max(1).min(50); + let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap(); + let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. + + let chol = m.clone().cholesky().unwrap(); + let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0); + let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0); + + let sol1 = chol.solve(&b1); + let sol2 = chol.solve(&b2); + + relative_eq!(&m * &sol1, b1, epsilon = 1.0e-7) && + relative_eq!(&m * &sol2, b2, epsilon = 1.0e-7) + } + + fn cholesky_solve_static(_n: usize) -> bool { + let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap(); + let chol = m.clone().cholesky().unwrap(); + let b1 = Vector4::<$scalar>::new_random().map(|e| e.0); + let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0); + + let sol1 = chol.solve(&b1); + let sol2 = chol.solve(&b2); + + relative_eq!(m * sol1, b1, epsilon = 1.0e-7) && + relative_eq!(m * sol2, b2, epsilon = 1.0e-7) + } + + fn cholesky_inverse(n: usize) -> bool { + let m = RandomSDP::new(Dynamic::new(n.max(1).min(50)), || random::<$scalar>().0).unwrap(); + let m1 = m.clone().cholesky().unwrap().inverse(); + let id1 = &m * &m1; + let id2 = &m1 * &m; + + id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7) + } + + fn cholesky_inverse_static(_n: usize) -> bool { + let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap(); + let m1 = m.clone().cholesky().unwrap().inverse(); + let id1 = &m * &m1; + let id2 = &m1 * &m; + + id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7) + } + } } } +); - - fn cholesky_solve(m: RandomSDP, nb: usize) -> bool { - let m = m.unwrap(); - let n = m.nrows(); - let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. - - let chol = m.clone().cholesky().unwrap(); - let b1 = DVector::new_random(n); - let b2 = DMatrix::new_random(n, nb); - - let sol1 = chol.solve(&b1); - let sol2 = chol.solve(&b2); - - relative_eq!(&m * &sol1, b1, epsilon = 1.0e-7) && - relative_eq!(&m * &sol2, b2, epsilon = 1.0e-7) - } - - fn cholesky_solve_static(m: RandomSDP) -> bool { - let m = m.unwrap(); - let chol = m.clone().cholesky().unwrap(); - let b1 = Vector4::new_random(); - let b2 = Matrix4x3::new_random(); - - let sol1 = chol.solve(&b1); - let sol2 = chol.solve(&b2); - - relative_eq!(m * sol1, b1, epsilon = 1.0e-7) && - relative_eq!(m * sol2, b2, epsilon = 1.0e-7) - } - - fn cholesky_inverse(m: RandomSDP) -> bool { - let m = m.unwrap(); - - let m1 = m.clone().cholesky().unwrap().inverse(); - let id1 = &m * &m1; - let id2 = &m1 * &m; - - id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7) - } - - fn cholesky_inverse_static(m: RandomSDP) -> bool { - let m = m.unwrap(); - let m1 = m.clone().cholesky().unwrap().inverse(); - let id1 = &m * &m1; - let id2 = &m1 * &m; - - id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7) - } -} +gen_tests!(complex, RandComplex); +gen_tests!(f64, RandScalar); diff --git a/tests/linalg/eigen.rs b/tests/linalg/eigen.rs index 36855acfe..8b2f8ed1d 100644 --- a/tests/linalg/eigen.rs +++ b/tests/linalg/eigen.rs @@ -4,61 +4,65 @@ use na::DMatrix; #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use na::{DMatrix, Matrix2, Matrix3, Matrix4}; - use std::cmp; - - quickcheck! { - fn symmetric_eigen(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 10)); - let m = DMatrix::::new_random(n, n); - let eig = m.clone().symmetric_eigen(); - let recomp = eig.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) - } - - fn symmetric_eigen_singular(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 10)); - let mut m = DMatrix::::new_random(n, n); - m.row_mut(n / 2).fill(0.0); - m.column_mut(n / 2).fill(0.0); - let eig = m.clone().symmetric_eigen(); - let recomp = eig.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) - } - - fn symmetric_eigen_static_square_4x4(m: Matrix4) -> bool { - let eig = m.symmetric_eigen(); - let recomp = eig.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) - } - - fn symmetric_eigen_static_square_3x3(m: Matrix3) -> bool { - let eig = m.symmetric_eigen(); - let recomp = eig.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) + macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::{DMatrix, Matrix2, Matrix3, Matrix4}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + use std::cmp; + + quickcheck! { + fn symmetric_eigen(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 10)); + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part(); + let eig = m.clone().symmetric_eigen(); + let recomp = eig.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) + } + + fn symmetric_eigen_singular(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 10)); + let mut m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part(); + m.row_mut(n / 2).fill(na::zero()); + m.column_mut(n / 2).fill(na::zero()); + let eig = m.clone().symmetric_eigen(); + let recomp = eig.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) + } + + fn symmetric_eigen_static_square_4x4(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0).hermitian_part(); + let eig = m.symmetric_eigen(); + let recomp = eig.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) + } + + fn symmetric_eigen_static_square_3x3(m: Matrix3<$scalar>) -> bool { + let m = m.map(|e| e.0).hermitian_part(); + let eig = m.symmetric_eigen(); + let recomp = eig.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) + } + + fn symmetric_eigen_static_square_2x2(m: Matrix2<$scalar>) -> bool { + let m = m.map(|e| e.0).hermitian_part(); + let eig = m.symmetric_eigen(); + let recomp = eig.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) + } + } + } } + ); - fn symmetric_eigen_static_square_2x2(m: Matrix2) -> bool { - let eig = m.symmetric_eigen(); - let recomp = eig.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5) - } - } + gen_tests!(complex, RandComplex); + gen_tests!(f64, RandScalar); } // Test proposed on the issue #176 of rulinalg. @@ -98,11 +102,11 @@ fn symmetric_eigen_singular_24x24() { let eig = m.clone().symmetric_eigen(); let recomp = eig.recompose(); - assert!(relative_eq!( + assert_relative_eq!( m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5 - )); + ); } // #[cfg(feature = "arbitrary")] diff --git a/tests/linalg/full_piv_lu.rs b/tests/linalg/full_piv_lu.rs index 5a0ad75b1..320fe241d 100644 --- a/tests/linalg/full_piv_lu.rs +++ b/tests/linalg/full_piv_lu.rs @@ -42,122 +42,140 @@ fn full_piv_lu_simple_with_pivot() { #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use std::cmp; - use na::{DMatrix, Matrix4, Matrix4x3, Matrix5x3, Matrix3x5, DVector, Vector4}; - - quickcheck! { - fn full_piv_lu(m: DMatrix) -> bool { - let mut m = m; - if m.len() == 0 { - m = DMatrix::new_random(1, 1); + macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use std::cmp; + use num::One; + use na::{DMatrix, Matrix4, Matrix4x3, Matrix5x3, Matrix3x5, DVector, Vector4}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn full_piv_lu(m: DMatrix<$scalar>) -> bool { + let mut m = m.map(|e| e.0); + if m.len() == 0 { + m = DMatrix::<$scalar>::new_random(1, 1).map(|e| e.0); + } + + let lu = m.clone().full_piv_lu(); + let (p, l, u, q) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + q.inv_permute_columns(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn full_piv_lu_static_3_5(m: Matrix3x5<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.full_piv_lu(); + let (p, l, u, q) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + q.inv_permute_columns(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn full_piv_lu_static_5_3(m: Matrix5x3<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.full_piv_lu(); + let (p, l, u, q) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + q.inv_permute_columns(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn full_piv_lu_static_square(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.full_piv_lu(); + let (p, l, u, q) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + q.inv_permute_columns(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn full_piv_lu_solve(n: usize, nb: usize) -> bool { + if n != 0 && nb != 0 { + let n = cmp::min(n, 50); // To avoid slowing down the test too much. + let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let lu = m.clone().full_piv_lu(); + let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0); + let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0); + + let sol1 = lu.solve(&b1); + let sol2 = lu.solve(&b2); + + return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && + (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) + } + + return true; + } + + fn full_piv_lu_solve_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.full_piv_lu(); + let b1 = Vector4::<$scalar>::new_random().map(|e| e.0); + let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0); + + let sol1 = lu.solve(&b1); + let sol2 = lu.solve(&b2); + + return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && + (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) + } + + fn full_piv_lu_inverse(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much. + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let mut l = m.lower_triangle(); + let mut u = m.upper_triangle(); + + // Ensure the matrix is well conditioned for inversion. + l.fill_diagonal(One::one()); + u.fill_diagonal(One::one()); + let m = l * u; + + let m1 = m.clone().full_piv_lu().try_inverse().unwrap(); + let id1 = &m * &m1; + let id2 = &m1 * &m; + + return id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5); + } + + fn full_piv_lu_inverse_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.full_piv_lu(); + + if let Some(m1) = lu.try_inverse() { + let id1 = &m * &m1; + let id2 = &m1 * &m; + + id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) + } + else { + true + } + } + } } - - let lu = m.clone().full_piv_lu(); - let (p, l, u, q) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - q.inv_permute_columns(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn full_piv_lu_static_3_5(m: Matrix3x5) -> bool { - let lu = m.full_piv_lu(); - let (p, l, u, q) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - q.inv_permute_columns(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn full_piv_lu_static_5_3(m: Matrix5x3) -> bool { - let lu = m.full_piv_lu(); - let (p, l, u, q) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - q.inv_permute_columns(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn full_piv_lu_static_square(m: Matrix4) -> bool { - let lu = m.full_piv_lu(); - let (p, l, u, q) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - q.inv_permute_columns(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn full_piv_lu_solve(n: usize, nb: usize) -> bool { - if n != 0 && nb != 0 { - let n = cmp::min(n, 50); // To avoid slowing down the test too much. - let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. - let m = DMatrix::::new_random(n, n); - - let lu = m.clone().full_piv_lu(); - let b1 = DVector::new_random(n); - let b2 = DMatrix::new_random(n, nb); - - let sol1 = lu.solve(&b1); - let sol2 = lu.solve(&b2); - - return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && - (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) - } - - return true; - } - - fn full_piv_lu_solve_static(m: Matrix4) -> bool { - let lu = m.full_piv_lu(); - let b1 = Vector4::new_random(); - let b2 = Matrix4x3::new_random(); - - let sol1 = lu.solve(&b1); - let sol2 = lu.solve(&b2); - - return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && - (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) } + ); - fn full_piv_lu_inverse(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much. - let m = DMatrix::::new_random(n, n); - - let mut l = m.lower_triangle(); - let mut u = m.upper_triangle(); - - // Ensure the matrix is well conditioned for inversion. - l.fill_diagonal(1.0); - u.fill_diagonal(1.0); - let m = l * u; - - let m1 = m.clone().full_piv_lu().try_inverse().unwrap(); - let id1 = &m * &m1; - let id2 = &m1 * &m; - - return id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5); - } - - fn full_piv_lu_inverse_static(m: Matrix4) -> bool { - let lu = m.full_piv_lu(); - - if let Some(m1) = lu.try_inverse() { - let id1 = &m * &m1; - let id2 = &m1 * &m; - - id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) - } - else { - true - } - } - } + gen_tests!(complex, RandComplex); + gen_tests!(f64, RandScalar); } + /* #[test] fn swap_rows() { diff --git a/tests/linalg/hessenberg.rs b/tests/linalg/hessenberg.rs index 22d62fbfa..378fbd877 100644 --- a/tests/linalg/hessenberg.rs +++ b/tests/linalg/hessenberg.rs @@ -1,7 +1,7 @@ #![cfg(feature = "arbitrary")] -use na::{DMatrix, Matrix2, Matrix4}; -use std::cmp; +use na::Matrix2; + #[test] fn hessenberg_simple() { @@ -11,25 +11,42 @@ fn hessenberg_simple() { assert!(relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7)) } -quickcheck! { - fn hessenberg(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 50)); - let m = DMatrix::::new_random(n, n); - let hess = m.clone().hessenberg(); - let (p, h) = hess.unpack(); - relative_eq!(m, &p * h * p.transpose(), epsilon = 1.0e-7) - } +macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::{DMatrix, Matrix2, Matrix4}; + use std::cmp; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; - fn hessenberg_static_mat2(m: Matrix2) -> bool { - let hess = m.hessenberg(); - let (p, h) = hess.unpack(); - relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7) - } + quickcheck! { + fn hessenberg(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 50)); + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let hess = m.clone().hessenberg(); + let (p, h) = hess.unpack(); + relative_eq!(m, &p * h * p.adjoint(), epsilon = 1.0e-7) + } - fn hessenberg_static(m: Matrix4) -> bool { - let hess = m.hessenberg(); - let (p, h) = hess.unpack(); - relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7) + fn hessenberg_static_mat2(m: Matrix2<$scalar>) -> bool { + let m = m.map(|e| e.0); + let hess = m.hessenberg(); + let (p, h) = hess.unpack(); + relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7) + } + + fn hessenberg_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let hess = m.hessenberg(); + let (p, h) = hess.unpack(); + relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7) + } + } + } } -} +); + +gen_tests!(complex, RandComplex); +gen_tests!(f64, RandScalar); \ No newline at end of file diff --git a/tests/linalg/lu.rs b/tests/linalg/lu.rs index 5069f7e57..69c387d2a 100644 --- a/tests/linalg/lu.rs +++ b/tests/linalg/lu.rs @@ -40,114 +40,135 @@ fn lu_simple_with_pivot() { #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use std::cmp; - use na::{DMatrix, Matrix4, Matrix4x3, Matrix5x3, Matrix3x5, DVector, Vector4}; - - quickcheck! { - fn lu(m: DMatrix) -> bool { - let mut m = m; - if m.len() == 0 { - m = DMatrix::new_random(1, 1); + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use std::cmp; + use na::{DMatrix, Matrix4, Matrix4x3, Matrix5x3, Matrix3x5, DVector, Vector4}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn lu(m: DMatrix<$scalar>) -> bool { + let mut m = m; + if m.len() == 0 { + m = DMatrix::<$scalar>::new_random(1, 1); + } + + let m = m.map(|e| e.0); + + let lu = m.clone().lu(); + let (p, l, u) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn lu_static_3_5(m: Matrix3x5<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.lu(); + let (p, l, u) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn lu_static_5_3(m: Matrix5x3<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.lu(); + let (p, l, u) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn lu_static_square(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.lu(); + let (p, l, u) = lu.unpack(); + let mut lu = l * u; + p.inv_permute_rows(&mut lu); + + relative_eq!(m, lu, epsilon = 1.0e-7) + } + + fn lu_solve(n: usize, nb: usize) -> bool { + if n != 0 && nb != 0 { + let n = cmp::min(n, 50); // To avoid slowing down the test too much. + let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let lu = m.clone().lu(); + let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0); + let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0); + + let sol1 = lu.solve(&b1); + let sol2 = lu.solve(&b2); + + return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && + (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) + } + + return true; + } + + fn lu_solve_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.lu(); + let b1 = Vector4::<$scalar>::new_random().map(|e| e.0); + let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0); + + let sol1 = lu.solve(&b1); + let sol2 = lu.solve(&b2); + + return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && + (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) + } + + fn lu_inverse(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much. + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let mut l = m.lower_triangle(); + let mut u = m.upper_triangle(); + + // Ensure the matrix is well conditioned for inversion. + l.fill_diagonal(na::one()); + u.fill_diagonal(na::one()); + let m = l * u; + + let m1 = m.clone().lu().try_inverse().unwrap(); + let id1 = &m * &m1; + let id2 = &m1 * &m; + + return id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5); + } + + fn lu_inverse_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let lu = m.lu(); + + if let Some(m1) = lu.try_inverse() { + let id1 = &m * &m1; + let id2 = &m1 * &m; + + id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) + } + else { + true + } + } + } } - - let lu = m.clone().lu(); - let (p, l, u) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn lu_static_3_5(m: Matrix3x5) -> bool { - let lu = m.lu(); - let (p, l, u) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) } + ); - fn lu_static_5_3(m: Matrix5x3) -> bool { - let lu = m.lu(); - let (p, l, u) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn lu_static_square(m: Matrix4) -> bool { - let lu = m.lu(); - let (p, l, u) = lu.unpack(); - let mut lu = l * u; - p.inv_permute_rows(&mut lu); - - relative_eq!(m, lu, epsilon = 1.0e-7) - } - - fn lu_solve(n: usize, nb: usize) -> bool { - if n != 0 && nb != 0 { - let n = cmp::min(n, 50); // To avoid slowing down the test too much. - let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. - let m = DMatrix::::new_random(n, n); - - let lu = m.clone().lu(); - let b1 = DVector::new_random(n); - let b2 = DMatrix::new_random(n, nb); - - let sol1 = lu.solve(&b1); - let sol2 = lu.solve(&b2); - - return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && - (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) - } - - return true; - } - - fn lu_solve_static(m: Matrix4) -> bool { - let lu = m.lu(); - let b1 = Vector4::new_random(); - let b2 = Matrix4x3::new_random(); - - let sol1 = lu.solve(&b1); - let sol2 = lu.solve(&b2); - - return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) && - (sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6)) - } - - fn lu_inverse(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much. - let m = DMatrix::::new_random(n, n); - - let mut l = m.lower_triangle(); - let mut u = m.upper_triangle(); - - // Ensure the matrix is well conditioned for inversion. - l.fill_diagonal(1.0); - u.fill_diagonal(1.0); - let m = l * u; - - let m1 = m.clone().lu().try_inverse().unwrap(); - let id1 = &m * &m1; - let id2 = &m1 * &m; - - return id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5); - } - - fn lu_inverse_static(m: Matrix4) -> bool { - let lu = m.lu(); - - if let Some(m1) = lu.try_inverse() { - let id1 = &m * &m1; - let id2 = &m1 * &m; - - id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) - } - else { - true - } - } - } + gen_tests!(complex, RandComplex); + gen_tests!(f64, RandScalar); } diff --git a/tests/linalg/mod.rs b/tests/linalg/mod.rs index 4e0bf2ebf..e881d9997 100644 --- a/tests/linalg/mod.rs +++ b/tests/linalg/mod.rs @@ -7,7 +7,7 @@ mod hessenberg; mod inverse; mod lu; mod qr; -mod real_schur; +mod schur; mod solve; mod svd; mod tridiagonal; diff --git a/tests/linalg/qr.rs b/tests/linalg/qr.rs index d7211623c..93cb49733 100644 --- a/tests/linalg/qr.rs +++ b/tests/linalg/qr.rs @@ -1,112 +1,133 @@ #![cfg(feature = "arbitrary")] -use na::{DMatrix, DVector, Matrix3x5, Matrix4, Matrix4x3, Matrix5x3, Vector4}; -use std::cmp; -quickcheck! { - fn qr(m: DMatrix) -> bool { - let qr = m.clone().qr(); - let q = qr.q(); - let r = qr.r(); - - relative_eq!(m, &q * r, epsilon = 1.0e-7) && - q.is_orthogonal(1.0e-7) - } - - fn qr_static_5_3(m: Matrix5x3) -> bool { - let qr = m.qr(); - let q = qr.q(); - let r = qr.r(); - - relative_eq!(m, q * r, epsilon = 1.0e-7) && - q.is_orthogonal(1.0e-7) - } - - fn qr_static_3_5(m: Matrix3x5) -> bool { - let qr = m.qr(); - let q = qr.q(); - let r = qr.r(); - - relative_eq!(m, q * r, epsilon = 1.0e-7) && - q.is_orthogonal(1.0e-7) - } - - fn qr_static_square(m: Matrix4) -> bool { - let qr = m.qr(); - let q = qr.q(); - let r = qr.r(); - - println!("{}{}{}{}", q, r, q * r, m); - - relative_eq!(m, q * r, epsilon = 1.0e-7) && - q.is_orthogonal(1.0e-7) - } - - fn qr_solve(n: usize, nb: usize) -> bool { - if n != 0 && nb != 0 { - let n = cmp::min(n, 50); // To avoid slowing down the test too much. - let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. - let m = DMatrix::::new_random(n, n); - - let qr = m.clone().qr(); - let b1 = DVector::new_random(n); - let b2 = DMatrix::new_random(n, nb); - - if qr.is_invertible() { - let sol1 = qr.solve(&b1).unwrap(); - let sol2 = qr.solve(&b2).unwrap(); - - return relative_eq!(&m * sol1, b1, epsilon = 1.0e-6) && - relative_eq!(&m * sol2, b2, epsilon = 1.0e-6) +macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::{DMatrix, DVector, Matrix3x5, Matrix4, Matrix4x3, Matrix5x3, Vector4}; + use std::cmp; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn qr(m: DMatrix<$scalar>) -> bool { + let m = m.map(|e| e.0); + let qr = m.clone().qr(); + let q = qr.q(); + let r = qr.r(); + + println!("m: {}", m); + println!("qr: {}", &q * &r); + + relative_eq!(m, &q * r, epsilon = 1.0e-7) && + q.is_orthogonal(1.0e-7) + } + + fn qr_static_5_3(m: Matrix5x3<$scalar>) -> bool { + let m = m.map(|e| e.0); + let qr = m.qr(); + let q = qr.q(); + let r = qr.r(); + + relative_eq!(m, q * r, epsilon = 1.0e-7) && + q.is_orthogonal(1.0e-7) + } + + fn qr_static_3_5(m: Matrix3x5<$scalar>) -> bool { + let m = m.map(|e| e.0); + let qr = m.qr(); + let q = qr.q(); + let r = qr.r(); + + relative_eq!(m, q * r, epsilon = 1.0e-7) && + q.is_orthogonal(1.0e-7) + } + + fn qr_static_square(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let qr = m.qr(); + let q = qr.q(); + let r = qr.r(); + + println!("{}{}{}{}", q, r, q * r, m); + + relative_eq!(m, q * r, epsilon = 1.0e-7) && + q.is_orthogonal(1.0e-7) + } + + fn qr_solve(n: usize, nb: usize) -> bool { + if n != 0 && nb != 0 { + let n = cmp::min(n, 50); // To avoid slowing down the test too much. + let nb = cmp::min(nb, 50); // To avoid slowing down the test too much. + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let qr = m.clone().qr(); + let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0); + let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0); + + if qr.is_invertible() { + let sol1 = qr.solve(&b1).unwrap(); + let sol2 = qr.solve(&b2).unwrap(); + + return relative_eq!(&m * sol1, b1, epsilon = 1.0e-6) && + relative_eq!(&m * sol2, b2, epsilon = 1.0e-6) + } + } + + return true; + } + + fn qr_solve_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let qr = m.qr(); + let b1 = Vector4::<$scalar>::new_random().map(|e| e.0); + let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0); + + if qr.is_invertible() { + let sol1 = qr.solve(&b1).unwrap(); + let sol2 = qr.solve(&b2).unwrap(); + + relative_eq!(m * sol1, b1, epsilon = 1.0e-6) && + relative_eq!(m * sol2, b2, epsilon = 1.0e-6) + } + else { + false + } + } + + fn qr_inverse(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much. + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + if let Some(m1) = m.clone().qr().try_inverse() { + let id1 = &m * &m1; + let id2 = &m1 * &m; + + id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) + } + else { + true + } + } + + fn qr_inverse_static(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let qr = m.qr(); + + if let Some(m1) = qr.try_inverse() { + let id1 = &m * &m1; + let id2 = &m1 * &m; + + id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) + } + else { + true + } + } } } - - return true; - } - - fn qr_solve_static(m: Matrix4) -> bool { - let qr = m.qr(); - let b1 = Vector4::new_random(); - let b2 = Matrix4x3::new_random(); - - if qr.is_invertible() { - let sol1 = qr.solve(&b1).unwrap(); - let sol2 = qr.solve(&b2).unwrap(); - - relative_eq!(m * sol1, b1, epsilon = 1.0e-6) && - relative_eq!(m * sol2, b2, epsilon = 1.0e-6) - } - else { - false - } } +); - fn qr_inverse(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much. - let m = DMatrix::::new_random(n, n); - - if let Some(m1) = m.clone().qr().try_inverse() { - let id1 = &m * &m1; - let id2 = &m1 * &m; - - id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) - } - else { - true - } - } - - fn qr_inverse_static(m: Matrix4) -> bool { - let qr = m.qr(); - - if let Some(m1) = qr.try_inverse() { - let id1 = &m * &m1; - let id2 = &m1 * &m; - - id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5) - } - else { - true - } - } -} +gen_tests!(complex, RandComplex); +gen_tests!(f64, RandScalar); diff --git a/tests/linalg/real_schur.rs b/tests/linalg/schur.rs similarity index 66% rename from tests/linalg/real_schur.rs rename to tests/linalg/schur.rs index 554bbdefa..f9c923a26 100644 --- a/tests/linalg/real_schur.rs +++ b/tests/linalg/schur.rs @@ -2,14 +2,13 @@ use na::{DMatrix, Matrix3, Matrix4}; - #[test] fn schur_simpl_mat3() { let m = Matrix3::new(-2.0, -4.0, 2.0, -2.0, 1.0, 2.0, 4.0, 2.0, 5.0); - let schur = m.real_schur(); + let schur = m.schur(); let (vecs, vals) = schur.unpack(); assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)); @@ -17,54 +16,70 @@ fn schur_simpl_mat3() { #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use std::cmp; - use na::{DMatrix, Matrix2, Matrix3, Matrix4}; - - quickcheck! { - fn schur(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 10)); - let m = DMatrix::::new_random(n, n); - - let (vecs, vals) = m.clone().real_schur().unpack(); - - if !relative_eq!(&vecs * &vals * vecs.transpose(), m, epsilon = 1.0e-7) { - println!("{:.5}{:.5}", m, &vecs * &vals * vecs.transpose()); - } - - relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7) - } - - fn schur_static_mat2(m: Matrix2) -> bool { - let (vecs, vals) = m.clone().real_schur().unpack(); - - let ok = relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7); - if !ok { - println!("{:.5}{:.5}", vecs, vals); - println!("Reconstruction:{}{}", m, &vecs * &vals * vecs.transpose()); - } - ok - } - - fn schur_static_mat3(m: Matrix3) -> bool { - let (vecs, vals) = m.clone().real_schur().unpack(); - - let ok = relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7); - if !ok { - println!("{:.5}{:.5}", m, &vecs * &vals * vecs.transpose()); + macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use std::cmp; + use na::{DMatrix, Matrix2, Matrix3, Matrix4}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn schur(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 10)); + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let (vecs, vals) = m.clone().schur().unpack(); + + if !relative_eq!(&vecs * &vals * vecs.adjoint(), m, epsilon = 1.0e-7) { + println!("{:.5}{:.5}", m, &vecs * &vals * vecs.adjoint()); + } + + relative_eq!(&vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7) + } + + fn schur_static_mat2(m: Matrix2<$scalar>) -> bool { + let m = m.map(|e| e.0); + let (vecs, vals) = m.clone().schur().unpack(); + + let ok = relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7); + if !ok { + println!("Vecs: {:.5} Vals: {:.5}", vecs, vals); + println!("Reconstruction:{}{}", m, &vecs * &vals * vecs.adjoint()); + } + ok + } + + fn schur_static_mat3(m: Matrix3<$scalar>) -> bool { + let m = m.map(|e| e.0); + let (vecs, vals) = m.clone().schur().unpack(); + + let ok = relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7); + if !ok { + println!("Vecs: {:.5} Vals: {:.5}", vecs, vals); + println!("{:.5}{:.5}", m, &vecs * &vals * vecs.adjoint()); + } + ok + } + + fn schur_static_mat4(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let (vecs, vals) = m.clone().schur().unpack(); + + let ok = relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7); + if !ok { + println!("{:.5}{:.5}", m, &vecs * &vals * vecs.adjoint()); + } + + ok + } + } } - ok } + ); - fn schur_static_mat4(m: Matrix4) -> bool { - let (vecs, vals) = m.clone().real_schur().unpack(); - - let ok = relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7); - if !ok { - println!("{:.5}{:.5}", m, &vecs * &vals * vecs.transpose()); - } - ok - } - } + gen_tests!(complex, RandComplex); + gen_tests!(f64, RandScalar); } #[test] @@ -75,8 +90,7 @@ fn schur_static_mat4_fail() { -94.61793793643038, -18.64216213611094, 88.32376703241675, -99.30169870309795, 90.62661897246733, 96.74200696130146, 34.7421322611369, 84.86773307198098); - let (vecs, vals) = m.clone().real_schur().unpack(); - println!("{:.6}{:.6}", m, &vecs * &vals * vecs.transpose()); + let (vecs, vals) = m.clone().schur().unpack(); assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)) } @@ -88,8 +102,7 @@ fn schur_static_mat4_fail2() { 27.932377940728202, 82.94220150938, -35.5898884705951, 67.56447552434219, 55.66754906908682, -42.14328890569226, -20.684709585152206, -87.9456949841046); - let (vecs, vals) = m.clone().real_schur().unpack(); - println!("{:.6}{:.6}", m, &vecs * &vals * vecs.transpose()); + let (vecs, vals) = m.clone().schur().unpack(); assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)) } @@ -100,8 +113,7 @@ fn schur_static_mat3_fail() { -7.525423104386547, -17.827350599642287, 11.297377444555849, 38.080736654870464, -84.27428302131528, -95.88198590331922); - let (vecs, vals) = m.clone().real_schur().unpack(); - println!("{:.6}{:.6}", m, &vecs * &vals * vecs.transpose()); + let (vecs, vals) = m.clone().schur().unpack(); assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)) } @@ -134,7 +146,6 @@ fn schur_singular() { 0.0, 0.0, 0.0, 0.0, 0.0, -4.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, -4.0, 0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, -4.0, 0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0]); - let (vecs, vals) = m.clone().real_schur().unpack(); - println!("{:.6}{:.6}", m, &vecs * &vals * vecs.transpose()); + let (vecs, vals) = m.clone().schur().unpack(); assert!(relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)) } diff --git a/tests/linalg/solve.rs b/tests/linalg/solve.rs index 76dc05b51..e917cfc54 100644 --- a/tests/linalg/solve.rs +++ b/tests/linalg/solve.rs @@ -1,57 +1,65 @@ #![cfg(feature = "arbitrary")] -use na::{Matrix4, Matrix4x5}; -fn unzero_diagonal(a: &mut Matrix4) { - for i in 0..4 { - if a[(i, i)] < 1.0e-7 { - a[(i, i)] = 1.0; - } - } -} +macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::{Matrix4, Matrix4x5, ComplexField}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; -quickcheck! { - fn solve_lower_triangular(a: Matrix4, b: Matrix4x5) -> bool { - let mut a = a; - unzero_diagonal(&mut a); - let tri = a.lower_triangle(); - let x = a.solve_lower_triangular(&b).unwrap(); + fn unzero_diagonal(a: &mut Matrix4) { + for i in 0..4 { + if a[(i, i)].norm1() < na::convert(1.0e-7) { + a[(i, i)] = N::one(); + } + } + } - println!("{}\n{}\n{}\n{}", tri, x, tri * x, b); + quickcheck! { + fn solve_lower_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool { + let b = b.map(|e| e.0); + let mut a = a.map(|e| e.0); + unzero_diagonal(&mut a); + let tri = a.lower_triangle(); + let x = a.solve_lower_triangular(&b).unwrap(); - relative_eq!(tri * x, b, epsilon = 1.0e-7) - } + relative_eq!(tri * x, b, epsilon = 1.0e-7) + } - fn solve_upper_triangular(a: Matrix4, b: Matrix4x5) -> bool { - let mut a = a; - unzero_diagonal(&mut a); - let tri = a.upper_triangle(); - let x = a.solve_upper_triangular(&b).unwrap(); + fn solve_upper_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool { + let b = b.map(|e| e.0); + let mut a = a.map(|e| e.0); + unzero_diagonal(&mut a); + let tri = a.upper_triangle(); + let x = a.solve_upper_triangular(&b).unwrap(); - println!("{}\n{}\n{}\n{}", tri, x, tri * x, b); + relative_eq!(tri * x, b, epsilon = 1.0e-7) + } - relative_eq!(tri * x, b, epsilon = 1.0e-7) - } + fn tr_solve_lower_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool { + let b = b.map(|e| e.0); + let mut a = a.map(|e| e.0); + unzero_diagonal(&mut a); + let tri = a.lower_triangle(); + let x = a.tr_solve_lower_triangular(&b).unwrap(); - fn tr_solve_lower_triangular(a: Matrix4, b: Matrix4x5) -> bool { - let mut a = a; - unzero_diagonal(&mut a); - let tri = a.lower_triangle(); - let x = a.tr_solve_lower_triangular(&b).unwrap(); + relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7) + } - println!("{}\n{}\n{}\n{}", tri, x, tri * x, b); + fn tr_solve_upper_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool { + let b = b.map(|e| e.0); + let mut a = a.map(|e| e.0); + unzero_diagonal(&mut a); + let tri = a.upper_triangle(); + let x = a.tr_solve_upper_triangular(&b).unwrap(); - relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7) + relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7) + } + } + } } +); - fn tr_solve_upper_triangular(a: Matrix4, b: Matrix4x5) -> bool { - let mut a = a; - unzero_diagonal(&mut a); - let tri = a.upper_triangle(); - let x = a.tr_solve_upper_triangular(&b).unwrap(); - - println!("{}\n{}\n{}\n{}", tri, x, tri * x, b); - - relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7) - } -} +gen_tests!(complex, RandComplex); +gen_tests!(f64, RandScalar); diff --git a/tests/linalg/svd.rs b/tests/linalg/svd.rs index e84108ed0..ca7bab4c5 100644 --- a/tests/linalg/svd.rs +++ b/tests/linalg/svd.rs @@ -3,146 +3,164 @@ use na::{DMatrix, Matrix6}; #[cfg(feature = "arbitrary")] mod quickcheck_tests { - use na::{ - DMatrix, DVector, Matrix2, Matrix2x5, Matrix3, Matrix3x5, Matrix4, Matrix5x2, Matrix5x3, - }; - use std::cmp; - - quickcheck! { - fn svd(m: DMatrix) -> bool { - if m.len() > 0 { - let svd = m.clone().svd(true, true); - let recomp_m = svd.clone().recompose().unwrap(); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - let ds = DMatrix::from_diagonal(&s); - - println!("{}{}", &m, &u * &ds * &v_t); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(&u * ds * &v_t, recomp_m, epsilon = 1.0e-5) && - relative_eq!(m, recomp_m, epsilon = 1.0e-5) - } - else { - true - } - } - - fn svd_static_5_3(m: Matrix5x3) -> bool { - let svd = m.svd(true, true); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - let ds = Matrix3::from_diagonal(&s); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5) && - u.is_orthogonal(1.0e-5) && - v_t.is_orthogonal(1.0e-5) - } - - fn svd_static_5_2(m: Matrix5x2) -> bool { - let svd = m.svd(true, true); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - let ds = Matrix2::from_diagonal(&s); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5) && - u.is_orthogonal(1.0e-5) && - v_t.is_orthogonal(1.0e-5) - } - - fn svd_static_3_5(m: Matrix3x5) -> bool { - let svd = m.svd(true, true); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - - let ds = Matrix3::from_diagonal(&s); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) - } - - fn svd_static_2_5(m: Matrix2x5) -> bool { - let svd = m.svd(true, true); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - let ds = Matrix2::from_diagonal(&s); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) - } - - fn svd_static_square(m: Matrix4) -> bool { - let svd = m.svd(true, true); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - let ds = Matrix4::from_diagonal(&s); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) && - u.is_orthogonal(1.0e-5) && - v_t.is_orthogonal(1.0e-5) - } - - fn svd_static_square_2x2(m: Matrix2) -> bool { - let svd = m.svd(true, true); - let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); - let ds = Matrix2::from_diagonal(&s); - - s.iter().all(|e| *e >= 0.0) && - relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) && - u.is_orthogonal(1.0e-5) && - v_t.is_orthogonal(1.0e-5) - } - - fn svd_pseudo_inverse(m: DMatrix) -> bool { - if m.len() > 0 { - let svd = m.clone().svd(true, true); - let pinv = svd.pseudo_inverse(1.0e-10).unwrap(); - - if m.nrows() > m.ncols() { - println!("{}", &pinv * &m); - (pinv * m).is_identity(1.0e-5) - } - else { - println!("{}", &m * &pinv); - (m * pinv).is_identity(1.0e-5) + macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use na::{ + DMatrix, DVector, Matrix2, Matrix2x5, Matrix3, Matrix3x5, Matrix4, Matrix5x2, Matrix5x3, + ComplexField + }; + use std::cmp; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn svd(m: DMatrix<$scalar>) -> bool { + let m = m.map(|e| e.0); + if m.len() > 0 { + let svd = m.clone().svd(true, true); + let recomp_m = svd.clone().recompose().unwrap(); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + let ds = DMatrix::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(&u * ds * &v_t, recomp_m, epsilon = 1.0e-5) && + relative_eq!(m, recomp_m, epsilon = 1.0e-5) + } + else { + true + } + } + + fn svd_static_5_3(m: Matrix5x3<$scalar>) -> bool { + let m = m.map(|e| e.0); + let svd = m.svd(true, true); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + let ds = Matrix3::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5) && + u.is_orthogonal(1.0e-5) && + v_t.is_orthogonal(1.0e-5) + } + + fn svd_static_5_2(m: Matrix5x2<$scalar>) -> bool { + let m = m.map(|e| e.0); + let svd = m.svd(true, true); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5) && + u.is_orthogonal(1.0e-5) && + v_t.is_orthogonal(1.0e-5) + } + + fn svd_static_3_5(m: Matrix3x5<$scalar>) -> bool { + let m = m.map(|e| e.0); + let svd = m.svd(true, true); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + + let ds = Matrix3::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) + } + + fn svd_static_2_5(m: Matrix2x5<$scalar>) -> bool { + let m = m.map(|e| e.0); + let svd = m.svd(true, true); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) + } + + fn svd_static_square(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0); + let svd = m.svd(true, true); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + let ds = Matrix4::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) && + u.is_orthogonal(1.0e-5) && + v_t.is_orthogonal(1.0e-5) + } + + fn svd_static_square_2x2(m: Matrix2<$scalar>) -> bool { + let m = m.map(|e| e.0); + let svd = m.svd(true, true); + let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); + let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e))); + + s.iter().all(|e| *e >= 0.0) && + relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) && + u.is_orthogonal(1.0e-5) && + v_t.is_orthogonal(1.0e-5) + } + + fn svd_pseudo_inverse(m: DMatrix<$scalar>) -> bool { + let m = m.map(|e| e.0); + + if m.len() > 0 { + let svd = m.clone().svd(true, true); + let pinv = svd.pseudo_inverse(1.0e-10).unwrap(); + + if m.nrows() > m.ncols() { + (pinv * m).is_identity(1.0e-5) + } + else { + (m * pinv).is_identity(1.0e-5) + } + } + else { + true + } + } + + fn svd_solve(n: usize, nb: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 10)); + let nb = cmp::min(nb, 10); + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0); + + let svd = m.clone().svd(true, true); + + if svd.rank(1.0e-7) == n { + let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0); + let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0); + + let sol1 = svd.solve(&b1, 1.0e-7).unwrap(); + let sol2 = svd.solve(&b2, 1.0e-7).unwrap(); + + let recomp = svd.recompose().unwrap(); + if !relative_eq!(m, recomp, epsilon = 1.0e-6) { + println!("{}{}", m, recomp); + } + + if !relative_eq!(&m * &sol1, b1, epsilon = 1.0e-6) { + println!("Problem 1: {:.6}{:.6}", b1, &m * sol1); + return false; + } + if !relative_eq!(&m * &sol2, b2, epsilon = 1.0e-6) { + println!("Problem 2: {:.6}{:.6}", b2, &m * sol2); + return false; + } + } + + true + } } } - else { - true - } } + ); - fn svd_solve(n: usize, nb: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 10)); - let nb = cmp::min(nb, 10); - let m = DMatrix::::new_random(n, n); - - let svd = m.clone().svd(true, true); - - if svd.rank(1.0e-7) == n { - let b1 = DVector::new_random(n); - let b2 = DMatrix::new_random(n, nb); - - let sol1 = svd.solve(&b1, 1.0e-7).unwrap(); - let sol2 = svd.solve(&b2, 1.0e-7).unwrap(); - - let recomp = svd.recompose().unwrap(); - if !relative_eq!(m, recomp, epsilon = 1.0e-6) { - println!("{}{}", m, recomp); - } - - if !relative_eq!(&m * &sol1, b1, epsilon = 1.0e-6) { - println!("Problem 1: {:.6}{:.6}", b1, &m * sol1); - return false; - } - if !relative_eq!(&m * &sol2, b2, epsilon = 1.0e-6) { - println!("Problem 2: {:.6}{:.6}", b2, &m * sol2); - return false; - } - } - - true - } - } + gen_tests!(complex, RandComplex); + gen_tests!(f64, RandScalar); } + // Test proposed on the issue #176 of rulinalg. #[test] fn svd_singular() { @@ -176,12 +194,10 @@ fn svd_singular() { let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap()); let ds = DMatrix::from_diagonal(&s); - println!("{:.5}", &u * &ds * &v_t); - assert!(s.iter().all(|e| *e >= 0.0)); assert!(u.is_orthogonal(1.0e-5)); assert!(v_t.is_orthogonal(1.0e-5)); - assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5)); + assert_relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5); } // Same as the previous test but with one additional row. @@ -220,7 +236,7 @@ fn svd_singular_vertical() { let ds = DMatrix::from_diagonal(&s); assert!(s.iter().all(|e| *e >= 0.0)); - assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5)); + assert_relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5); } // Same as the previous test but with one additional column. @@ -257,7 +273,7 @@ fn svd_singular_horizontal() { let ds = DMatrix::from_diagonal(&s); assert!(s.iter().all(|e| *e >= 0.0)); - assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5)); + assert_relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5); } #[test] @@ -296,7 +312,7 @@ fn svd_with_delimited_subproblem() { m[(8,8)] = 16.0; m[(3,9)] = 17.0; m[(9,9)] = 18.0; let svd = m.clone().svd(true, true); - assert!(relative_eq!(m, svd.recompose().unwrap(), epsilon = 1.0e-7)); + assert_relative_eq!(m, svd.recompose().unwrap(), epsilon = 1.0e-7); // Rectangular versions. let mut m = DMatrix::::from_element(15, 10, 0.0); @@ -311,10 +327,10 @@ fn svd_with_delimited_subproblem() { m[(8,8)] = 16.0; m[(3,9)] = 17.0; m[(9,9)] = 18.0; let svd = m.clone().svd(true, true); - assert!(relative_eq!(m, svd.recompose().unwrap(), epsilon = 1.0e-7)); + assert_relative_eq!(m, svd.recompose().unwrap(), epsilon = 1.0e-7); let svd = m.transpose().svd(true, true); - assert!(relative_eq!(m.transpose(), svd.recompose().unwrap(), epsilon = 1.0e-7)); + assert_relative_eq!(m.transpose(), svd.recompose().unwrap(), epsilon = 1.0e-7); } #[test] @@ -327,12 +343,8 @@ fn svd_fail() { 0.12293810556077789, 0.6617084679545999, 0.9002240700227326, 0.027153062135304884, 0.3630189466989524, 0.18207502727558866, 0.843196731466686, 0.08951878746549924, 0.7533450877576973, 0.009558876499740077, 0.9429679490873482, 0.9355764454129878); let svd = m.clone().svd(true, true); - println!("Singular values: {}", svd.singular_values); - println!("u: {:.5}", svd.u.unwrap()); - println!("v: {:.5}", svd.v_t.unwrap()); let recomp = svd.recompose().unwrap(); - println!("{:.5}{:.5}", m, recomp); - assert!(relative_eq!(m, recomp, epsilon = 1.0e-5)); + assert_relative_eq!(m, recomp, epsilon = 1.0e-5); } #[test] @@ -341,4 +353,4 @@ fn svd_err() { let svd = m.clone().svd(false, false); assert_eq!(Err("SVD recomposition: U and V^t have not been computed."), svd.clone().recompose()); assert_eq!(Err("SVD pseudo inverse: the epsilon must be non-negative."), svd.clone().pseudo_inverse(-1.0)); -} +} \ No newline at end of file diff --git a/tests/linalg/tridiagonal.rs b/tests/linalg/tridiagonal.rs index 6db86aefb..5d04587e0 100644 --- a/tests/linalg/tridiagonal.rs +++ b/tests/linalg/tridiagonal.rs @@ -1,35 +1,56 @@ #![cfg(feature = "arbitrary")] -use std::cmp; -use na::{DMatrix, Matrix2, Matrix4}; - -quickcheck! { - fn symm_tridiagonal(n: usize) -> bool { - let n = cmp::max(1, cmp::min(n, 50)); - let m = DMatrix::::new_random(n, n); - let tri = m.clone().symmetric_tridiagonalize(); - let recomp = tri.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) - } - - fn symm_tridiagonal_static_square(m: Matrix4) -> bool { - let tri = m.symmetric_tridiagonalize(); - println!("{}{}", tri.internal_tri(), tri.off_diagonal()); - let recomp = tri.recompose(); - - println!("{}{}", m.lower_triangle(), recomp.lower_triangle()); - - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) +macro_rules! gen_tests( + ($module: ident, $scalar: ty) => { + mod $module { + use std::cmp; + + use na::{DMatrix, Matrix2, Matrix4}; + #[allow(unused_imports)] + use crate::core::helper::{RandScalar, RandComplex}; + + quickcheck! { + fn symm_tridiagonal(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 50)); + let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part(); + let tri = m.clone().symmetric_tridiagonalize(); + let recomp = tri.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) + } + + fn symm_tridiagonal_singular(n: usize) -> bool { + let n = cmp::max(1, cmp::min(n, 4)); + let mut m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part(); + m.row_mut(n / 2).fill(na::zero()); + m.column_mut(n / 2).fill(na::zero()); + let tri = m.clone().symmetric_tridiagonalize(); + let recomp = tri.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) + } + + fn symm_tridiagonal_static_square(m: Matrix4<$scalar>) -> bool { + let m = m.map(|e| e.0).hermitian_part(); + let tri = m.symmetric_tridiagonalize(); + let recomp = tri.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) + } + + fn symm_tridiagonal_static_square_2x2(m: Matrix2<$scalar>) -> bool { + let m = m.map(|e| e.0).hermitian_part(); + let tri = m.symmetric_tridiagonalize(); + let recomp = tri.recompose(); + + relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) + } + } + } } +); - fn symm_tridiagonal_static_square_2x2(m: Matrix2) -> bool { - let tri = m.symmetric_tridiagonalize(); - let recomp = tri.recompose(); - relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7) - } -} +gen_tests!(complex, RandComplex); +gen_tests!(f64, RandScalar); diff --git a/tests/sparse/cs_cholesky.rs b/tests/sparse/cs_cholesky.rs index 72a9a08fa..314e34f6e 100644 --- a/tests/sparse/cs_cholesky.rs +++ b/tests/sparse/cs_cholesky.rs @@ -35,12 +35,12 @@ fn cs_cholesky() { 1.0, 1.0, 0.0, 0.0, 2.0 ); a.fill_upper_triangle_with_lower_triangle(); - // Test ::new, left_looking, and up_looking implementations. + // Test crate::new, left_looking, and up_looking implementations. test_cholesky(a); } fn test_cholesky(a: Matrix5) { - // Test ::new + // Test crate::new test_cholesky_variant(a, 0); // Test up-looking test_cholesky_variant(a, 1);