├── .github ├── FUNDING.yml └── workflows │ └── nalgebra-ci-build.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches ├── common │ └── macros.rs ├── core │ ├── matrix.rs │ ├── mod.rs │ └── vector.rs ├── geometry │ ├── mod.rs │ └── quaternion.rs ├── lib.rs └── linalg │ ├── bidiagonal.rs │ ├── cholesky.rs │ ├── eigen.rs │ ├── full_piv_lu.rs │ ├── hessenberg.rs │ ├── lu.rs │ ├── mod.rs │ ├── qr.rs │ ├── schur.rs │ ├── solve.rs │ ├── svd.rs │ └── symmetric_eigen.rs ├── clippy.toml ├── examples ├── cargo │ └── Cargo.toml ├── dimensional_genericity.rs ├── homogeneous_coordinates.rs ├── linear_system_resolution.rs ├── matrix_construction.rs ├── matrixcompare.rs ├── mvp.rs ├── point_construction.rs ├── raw_pointer.rs ├── reshaping.rs ├── scalar_genericity.rs ├── screen_to_view_coords.rs ├── transform_conversion.rs ├── transform_matrix4.rs ├── transform_vector_point.rs ├── transform_vector_point3.rs ├── transformation_pointer.rs └── unit_wrapper.rs ├── nalgebra-glm ├── Cargo.toml ├── LICENSE ├── src │ ├── aliases.rs │ ├── common.rs │ ├── constructors.rs │ ├── exponential.rs │ ├── ext │ │ ├── matrix_clip_space.rs │ │ ├── matrix_projection.rs │ │ ├── matrix_relationnal.rs │ │ ├── matrix_transform.rs │ │ ├── mod.rs │ │ ├── quaternion_common.rs │ │ ├── quaternion_geometric.rs │ │ ├── quaternion_relational.rs │ │ ├── quaternion_transform.rs │ │ ├── quaternion_trigonometric.rs │ │ ├── scalar_common.rs │ │ ├── scalar_constants.rs │ │ ├── vector_common.rs │ │ └── vector_relational.rs │ ├── geometric.rs │ ├── gtc │ │ ├── bitfield.rs │ │ ├── constants.rs │ │ ├── epsilon.rs │ │ ├── integer.rs │ │ ├── matrix_access.rs │ │ ├── matrix_inverse.rs │ │ ├── mod.rs │ │ ├── packing.rs │ │ ├── quaternion.rs │ │ ├── reciprocal.rs │ │ ├── round.rs │ │ ├── type_ptr.rs │ │ └── ulp.rs │ ├── gtx │ │ ├── component_wise.rs │ │ ├── euler_angles.rs │ │ ├── exterior_product.rs │ │ ├── handed_coordinate_space.rs │ │ ├── matrix_cross_product.rs │ │ ├── matrix_operation.rs │ │ ├── mod.rs │ │ ├── norm.rs │ │ ├── normal.rs │ │ ├── normalize_dot.rs │ │ ├── quaternion.rs │ │ ├── rotate_normalized_axis.rs │ │ ├── rotate_vector.rs │ │ ├── transform.rs │ │ ├── transform2.rs │ │ ├── transform2d.rs │ │ ├── vector_angle.rs │ │ └── vector_query.rs │ ├── integer.rs │ ├── lib.rs │ ├── matrix.rs │ ├── packing.rs │ ├── traits.rs │ ├── trigonometric.rs │ └── vector_relational.rs └── tests │ └── lib.rs ├── nalgebra-lapack ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── benches │ ├── lib.rs │ └── linalg │ │ ├── hessenberg.rs │ │ ├── lu.rs │ │ ├── mod.rs │ │ └── qr.rs ├── src │ ├── cholesky.rs │ ├── eigen.rs │ ├── generalized_eigenvalues.rs │ ├── hessenberg.rs │ ├── lapack_check.rs │ ├── lib.rs │ ├── lu.rs │ ├── qr.rs │ ├── qz.rs │ ├── schur.rs │ ├── svd.rs │ └── symmetric_eigen.rs └── tests │ ├── lib.rs │ └── linalg │ ├── cholesky.rs │ ├── complex_eigen.rs │ ├── generalized_eigenvalues.rs │ ├── hessenberg.rs │ ├── lu.rs │ ├── mod.rs │ ├── qr.rs │ ├── qz.rs │ ├── real_eigensystem.rs │ ├── schur.rs │ ├── svd.rs │ └── symmetric_eigen.rs ├── nalgebra-macros ├── Cargo.toml ├── LICENSE └── src │ ├── lib.rs │ ├── matrix_vector_impl.rs │ └── stack_impl.rs ├── nalgebra-sparse ├── Cargo.toml ├── LICENSE ├── src │ ├── convert │ │ ├── impl_std_ops.rs │ │ ├── mod.rs │ │ └── serial.rs │ ├── coo.rs │ ├── coo │ │ └── coo_serde.rs │ ├── cs.rs │ ├── csc.rs │ ├── csc │ │ └── csc_serde.rs │ ├── csr.rs │ ├── csr │ │ └── csr_serde.rs │ ├── factorization │ │ ├── cholesky.rs │ │ └── mod.rs │ ├── io │ │ ├── matrix_market.pest │ │ ├── matrix_market.rs │ │ └── mod.rs │ ├── lib.rs │ ├── matrixcompare.rs │ ├── ops │ │ ├── impl_std_ops.rs │ │ ├── mod.rs │ │ └── serial │ │ │ ├── cs.rs │ │ │ ├── csc.rs │ │ │ ├── csr.rs │ │ │ ├── mod.rs │ │ │ └── pattern.rs │ ├── pattern.rs │ ├── pattern │ │ └── pattern_serde.rs │ ├── proptest.rs │ └── utils.rs └── tests │ ├── common │ └── mod.rs │ ├── serde.rs │ ├── unit.rs │ └── unit_tests │ ├── cholesky.proptest-regressions │ ├── cholesky.rs │ ├── convert_serial.proptest-regressions │ ├── convert_serial.rs │ ├── coo.rs │ ├── csc.proptest-regressions │ ├── csc.rs │ ├── csr.rs │ ├── matrix_market.rs │ ├── mod.rs │ ├── ops.proptest-regressions │ ├── ops.rs │ ├── pattern.rs │ ├── proptest.rs │ └── test_data_examples.rs ├── rustfmt.toml ├── src ├── base │ ├── alias.rs │ ├── alias_slice.rs │ ├── alias_view.rs │ ├── allocator.rs │ ├── array_storage.rs │ ├── blas.rs │ ├── blas_uninit.rs │ ├── cg.rs │ ├── componentwise.rs │ ├── constraint.rs │ ├── construction.rs │ ├── construction_view.rs │ ├── conversion.rs │ ├── coordinates.rs │ ├── default_allocator.rs │ ├── dimension.rs │ ├── edition.rs │ ├── helper.rs │ ├── indexing.rs │ ├── interpolation.rs │ ├── iter.rs │ ├── matrix.rs │ ├── matrix_simba.rs │ ├── matrix_view.rs │ ├── min_max.rs │ ├── mod.rs │ ├── norm.rs │ ├── ops.rs │ ├── par_iter.rs │ ├── properties.rs │ ├── rkyv_wrappers.rs │ ├── scalar.rs │ ├── statistics.rs │ ├── storage.rs │ ├── swizzle.rs │ ├── uninit.rs │ ├── unit.rs │ └── vec_storage.rs ├── debug │ ├── mod.rs │ ├── random_orthogonal.rs │ └── random_sdp.rs ├── geometry │ ├── abstract_rotation.rs │ ├── dual_quaternion.rs │ ├── dual_quaternion_construction.rs │ ├── dual_quaternion_conversion.rs │ ├── dual_quaternion_ops.rs │ ├── isometry.rs │ ├── isometry_alias.rs │ ├── isometry_construction.rs │ ├── isometry_conversion.rs │ ├── isometry_interpolation.rs │ ├── isometry_ops.rs │ ├── isometry_simba.rs │ ├── mod.rs │ ├── op_macros.rs │ ├── orthographic.rs │ ├── perspective.rs │ ├── point.rs │ ├── point_alias.rs │ ├── point_construction.rs │ ├── point_conversion.rs │ ├── point_coordinates.rs │ ├── point_ops.rs │ ├── point_simba.rs │ ├── quaternion.rs │ ├── quaternion_construction.rs │ ├── quaternion_conversion.rs │ ├── quaternion_coordinates.rs │ ├── quaternion_ops.rs │ ├── quaternion_simba.rs │ ├── reflection.rs │ ├── reflection_alias.rs │ ├── rotation.rs │ ├── rotation_alias.rs │ ├── rotation_construction.rs │ ├── rotation_conversion.rs │ ├── rotation_interpolation.rs │ ├── rotation_ops.rs │ ├── rotation_simba.rs │ ├── rotation_specialization.rs │ ├── scale.rs │ ├── scale_alias.rs │ ├── scale_construction.rs │ ├── scale_conversion.rs │ ├── scale_coordinates.rs │ ├── scale_ops.rs │ ├── scale_simba.rs │ ├── similarity.rs │ ├── similarity_alias.rs │ ├── similarity_construction.rs │ ├── similarity_conversion.rs │ ├── similarity_ops.rs │ ├── similarity_simba.rs │ ├── swizzle.rs │ ├── transform.rs │ ├── transform_alias.rs │ ├── transform_construction.rs │ ├── transform_conversion.rs │ ├── transform_ops.rs │ ├── transform_simba.rs │ ├── translation.rs │ ├── translation_alias.rs │ ├── translation_construction.rs │ ├── translation_conversion.rs │ ├── translation_coordinates.rs │ ├── translation_ops.rs │ ├── translation_simba.rs │ ├── unit_complex.rs │ ├── unit_complex_construction.rs │ ├── unit_complex_conversion.rs │ ├── unit_complex_ops.rs │ └── unit_complex_simba.rs ├── io │ ├── matrix_market.pest │ ├── matrix_market.rs │ └── mod.rs ├── lib.rs ├── linalg │ ├── balancing.rs │ ├── bidiagonal.rs │ ├── cholesky.rs │ ├── col_piv_qr.rs │ ├── convolution.rs │ ├── decomposition.rs │ ├── determinant.rs │ ├── eigen.rs │ ├── exp.rs │ ├── full_piv_lu.rs │ ├── givens.rs │ ├── hessenberg.rs │ ├── householder.rs │ ├── inverse.rs │ ├── lu.rs │ ├── mod.rs │ ├── permutation_sequence.rs │ ├── pow.rs │ ├── qr.rs │ ├── schur.rs │ ├── solve.rs │ ├── svd.rs │ ├── svd2.rs │ ├── svd3.rs │ ├── symmetric_eigen.rs │ ├── symmetric_tridiagonal.rs │ └── udu.rs ├── proptest │ └── mod.rs ├── sparse │ ├── cs_matrix.rs │ ├── cs_matrix_cholesky.rs │ ├── cs_matrix_conversion.rs │ ├── cs_matrix_ops.rs │ ├── cs_matrix_solve.rs │ ├── cs_utils.rs │ └── mod.rs └── third_party │ ├── alga │ ├── alga_dual_quaternion.rs │ ├── alga_isometry.rs │ ├── alga_matrix.rs │ ├── alga_point.rs │ ├── alga_quaternion.rs │ ├── alga_rotation.rs │ ├── alga_similarity.rs │ ├── alga_transform.rs │ ├── alga_translation.rs │ ├── alga_unit_complex.rs │ └── mod.rs │ ├── glam │ ├── common │ │ ├── glam_isometry.rs │ │ ├── glam_matrix.rs │ │ ├── glam_point.rs │ │ ├── glam_quaternion.rs │ │ ├── glam_rotation.rs │ │ ├── glam_similarity.rs │ │ ├── glam_translation.rs │ │ └── glam_unit_complex.rs │ ├── mod.rs │ ├── v014 │ │ └── mod.rs │ ├── v015 │ │ └── mod.rs │ ├── v016 │ │ └── mod.rs │ ├── v017 │ │ └── mod.rs │ ├── v018 │ │ └── mod.rs │ ├── v019 │ │ └── mod.rs │ ├── v020 │ │ └── mod.rs │ ├── v021 │ │ └── mod.rs │ ├── v022 │ │ └── mod.rs │ ├── v023 │ │ └── mod.rs │ ├── v024 │ │ └── mod.rs │ ├── v025 │ │ └── mod.rs │ ├── v027 │ │ └── mod.rs │ ├── v028 │ │ └── mod.rs │ ├── v029 │ │ └── mod.rs │ └── v030 │ │ └── mod.rs │ ├── mint │ ├── mint_matrix.rs │ ├── mint_point.rs │ ├── mint_quaternion.rs │ ├── mint_rotation.rs │ └── mod.rs │ └── mod.rs └── tests ├── core ├── blas.rs ├── cg.rs ├── conversion.rs ├── edition.rs ├── empty.rs ├── helper.rs ├── macros.rs ├── matrix.rs ├── matrix_view.rs ├── matrixcompare.rs ├── mint.rs ├── mod.rs ├── reshape.rs ├── rkyv.rs ├── serde.rs └── variance.rs ├── geometry ├── dual_quaternion.rs ├── isometry.rs ├── mod.rs ├── point.rs ├── projection.rs ├── quaternion.rs ├── rotation.rs ├── similarity.rs └── unit_complex.rs ├── lib.rs ├── linalg ├── balancing.rs ├── bidiagonal.rs ├── cholesky.rs ├── col_piv_qr.rs ├── convolution.rs ├── eigen.rs ├── exp.rs ├── full_piv_lu.rs ├── hessenberg.rs ├── inverse.rs ├── lu.rs ├── mod.rs ├── pow.rs ├── qr.rs ├── schur.rs ├── solve.rs ├── svd.rs ├── tridiagonal.rs └── udu.rs ├── macros ├── matrix.rs ├── mod.rs ├── stack.rs └── trybuild │ ├── dmatrix_mismatched_dimensions.rs │ ├── dmatrix_mismatched_dimensions.stderr │ ├── matrix_mismatched_dimensions.rs │ ├── matrix_mismatched_dimensions.stderr │ ├── stack_empty_col.rs │ ├── stack_empty_col.stderr │ ├── stack_empty_row.rs │ ├── stack_empty_row.stderr │ ├── stack_incompatible_block_dimensions.rs │ ├── stack_incompatible_block_dimensions.stderr │ ├── stack_incompatible_block_dimensions2.rs │ └── stack_incompatible_block_dimensions2.stderr ├── proptest └── mod.rs └── sparse ├── cs_cholesky.rs ├── cs_construction.rs ├── cs_conversion.rs ├── cs_matrix.rs ├── cs_matrix_market.rs ├── cs_ops.rs ├── cs_solve.rs └── mod.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ "dimforge" ] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.html 3 | doc 4 | lib 5 | TODO 6 | target/ 7 | Cargo.lock 8 | *.orig 9 | *.swo 10 | site/ 11 | .vscode/ 12 | .idea/ 13 | proptest-regressions -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | crates.io 3 |

4 |

5 | 6 | 7 | 8 | 9 | crates.io 10 | 11 | 12 | 13 | 14 |

15 |

16 | 17 | Users guide | Documentation 18 | 19 |

20 | 21 | ----- 22 | 23 |

24 | Linear algebra library 25 | for the Rust programming language. 26 |

27 | 28 | ----- 29 | -------------------------------------------------------------------------------- /benches/core/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::matrix::matrix; 2 | pub use self::vector::vector; 3 | 4 | mod matrix; 5 | mod vector; 6 | -------------------------------------------------------------------------------- /benches/geometry/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::quaternion::quaternion; 2 | 3 | mod quaternion; 4 | -------------------------------------------------------------------------------- /benches/geometry/quaternion.rs: -------------------------------------------------------------------------------- 1 | use na::{Quaternion, UnitQuaternion, Vector3}; 2 | use rand::Rng; 3 | use rand_isaac::IsaacRng; 4 | use std::ops::{Add, Div, Mul, Sub}; 5 | 6 | #[path = "../common/macros.rs"] 7 | mod macros; 8 | 9 | bench_binop!(quaternion_add_q, Quaternion, Quaternion, add); 10 | bench_binop!(quaternion_sub_q, Quaternion, Quaternion, sub); 11 | bench_binop!(quaternion_mul_q, Quaternion, Quaternion, mul); 12 | 13 | bench_binop!( 14 | unit_quaternion_mul_v, 15 | UnitQuaternion, 16 | Vector3, 17 | mul 18 | ); 19 | 20 | bench_binop!(quaternion_mul_s, Quaternion, f32, mul); 21 | bench_binop!(quaternion_div_s, Quaternion, f32, div); 22 | 23 | bench_unop!(quaternion_inv, Quaternion, try_inverse); 24 | bench_unop!(unit_quaternion_inv, UnitQuaternion, inverse); 25 | 26 | // bench_unop_self!(quaternion_conjugate, Quaternion, conjugate); 27 | // bench_unop!(quaternion_normalize, Quaternion, normalize); 28 | 29 | criterion_group!( 30 | quaternion, 31 | quaternion_add_q, 32 | quaternion_sub_q, 33 | quaternion_mul_q, 34 | unit_quaternion_mul_v, 35 | quaternion_mul_s, 36 | quaternion_div_s, 37 | quaternion_inv, 38 | unit_quaternion_inv 39 | ); 40 | -------------------------------------------------------------------------------- /benches/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_macros)] 2 | 3 | extern crate nalgebra as na; 4 | extern crate rand_package as rand; 5 | 6 | #[macro_use] 7 | extern crate criterion; 8 | 9 | use na::DMatrix; 10 | use rand::Rng; 11 | use rand_isaac::IsaacRng; 12 | 13 | pub mod core; 14 | pub mod geometry; 15 | pub mod linalg; 16 | 17 | fn reproducible_dmatrix(nrows: usize, ncols: usize) -> DMatrix { 18 | use rand::SeedableRng; 19 | let mut rng = IsaacRng::seed_from_u64(0); 20 | DMatrix::::from_fn(nrows, ncols, |_, _| rng.gen()) 21 | } 22 | 23 | criterion_main!( 24 | core::matrix, 25 | core::vector, 26 | geometry::quaternion, 27 | linalg::bidiagonal, 28 | linalg::cholesky, 29 | linalg::full_piv_lu, 30 | linalg::hessenberg, 31 | linalg::lu, 32 | linalg::qr, 33 | linalg::schur, 34 | linalg::solve, 35 | linalg::svd, 36 | linalg::symmetric_eigen, 37 | ); 38 | -------------------------------------------------------------------------------- /benches/linalg/eigen.rs: -------------------------------------------------------------------------------- 1 | use na::{DMatrix, Eigen}; 2 | 3 | fn eigen_100x100(bh: &mut criterion::Criterion) { 4 | let m = DMatrix::::new_random(100, 100); 5 | 6 | bh.bench_function("eigen_100x100", move |bh| bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))); 7 | } 8 | 9 | fn eigen_500x500(bh: &mut criterion::Criterion) { 10 | let m = DMatrix::::new_random(500, 500); 11 | 12 | bh.bench_function("eigen_500x500", move |bh| bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))); 13 | } 14 | 15 | fn eigenvalues_100x100(bh: &mut criterion::Criterion) { 16 | let m = DMatrix::::new_random(100, 100); 17 | 18 | bh.bench_function("eigenvalues_100x100", move |bh| bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))); 19 | } 20 | 21 | fn eigenvalues_500x500(bh: &mut criterion::Criterion) { 22 | let m = DMatrix::::new_random(500, 500); 23 | 24 | bh.bench_function("eigenvalues_500x500", move |bh| bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))); 25 | } 26 | 27 | criterion_group!(eigen, 28 | eigen_100x100, 29 | // eigen_500x500, 30 | eigenvalues_100x100, 31 | // eigenvalues_500x500 32 | ); 33 | -------------------------------------------------------------------------------- /benches/linalg/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::bidiagonal::bidiagonal; 2 | pub use self::cholesky::cholesky; 3 | pub use self::full_piv_lu::full_piv_lu; 4 | pub use self::hessenberg::hessenberg; 5 | pub use self::lu::lu; 6 | pub use self::qr::qr; 7 | pub use self::schur::schur; 8 | pub use self::solve::solve; 9 | pub use self::svd::svd; 10 | pub use self::symmetric_eigen::symmetric_eigen; 11 | 12 | mod bidiagonal; 13 | mod cholesky; 14 | mod full_piv_lu; 15 | mod hessenberg; 16 | mod lu; 17 | mod qr; 18 | mod schur; 19 | mod solve; 20 | mod svd; 21 | mod symmetric_eigen; 22 | // mod eigen; 23 | -------------------------------------------------------------------------------- /benches/linalg/symmetric_eigen.rs: -------------------------------------------------------------------------------- 1 | use na::{Matrix4, SymmetricEigen}; 2 | 3 | fn symmetric_eigen_decompose_4x4(bh: &mut criterion::Criterion) { 4 | let m = Matrix4::::new_random(); 5 | bh.bench_function("symmetric_eigen_decompose_4x4", move |bh| { 6 | bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) 7 | }); 8 | } 9 | 10 | fn symmetric_eigen_decompose_10x10(bh: &mut criterion::Criterion) { 11 | let m = crate::reproducible_dmatrix(10, 10); 12 | bh.bench_function("symmetric_eigen_decompose_10x10", move |bh| { 13 | bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) 14 | }); 15 | } 16 | 17 | fn symmetric_eigen_decompose_100x100(bh: &mut criterion::Criterion) { 18 | let m = crate::reproducible_dmatrix(100, 100); 19 | bh.bench_function("symmetric_eigen_decompose_100x100", move |bh| { 20 | bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) 21 | }); 22 | } 23 | 24 | fn symmetric_eigen_decompose_200x200(bh: &mut criterion::Criterion) { 25 | let m = crate::reproducible_dmatrix(200, 200); 26 | bh.bench_function("symmetric_eigen_decompose_200x200", move |bh| { 27 | bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) 28 | }); 29 | } 30 | 31 | criterion_group!( 32 | symmetric_eigen, 33 | symmetric_eigen_decompose_4x4, 34 | symmetric_eigen_decompose_10x10, 35 | symmetric_eigen_decompose_100x100, 36 | symmetric_eigen_decompose_200x200 37 | ); 38 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | too-many-arguments-threshold = 8 2 | type-complexity-threshold = 675 3 | -------------------------------------------------------------------------------- /examples/cargo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example-using-nalgebra" 3 | version = "0.0.0" 4 | authors = ["You"] 5 | 6 | [dependencies] 7 | nalgebra = "0.33.0" 8 | 9 | [[bin]] 10 | name = "example" 11 | path = "./example.rs" 12 | -------------------------------------------------------------------------------- /examples/dimensional_genericity.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::allocator::Allocator; 4 | use na::dimension::Dim; 5 | use na::{DefaultAllocator, OVector, RealField, Unit, Vector2, Vector3}; 6 | 7 | /// Reflects a vector wrt. the hyperplane with normal `plane_normal`. 8 | fn reflect_wrt_hyperplane_with_dimensional_genericity( 9 | plane_normal: &Unit>, 10 | vector: &OVector, 11 | ) -> OVector 12 | where 13 | T: RealField, 14 | D: Dim, 15 | DefaultAllocator: Allocator, 16 | { 17 | let n = plane_normal.as_ref(); // Get the underlying V. 18 | vector - n * (n.dot(vector) * na::convert(2.0)) 19 | } 20 | 21 | /// Reflects a 2D vector wrt. the 2D line with normal `plane_normal`. 22 | fn reflect_wrt_hyperplane2(plane_normal: &Unit>, vector: &Vector2) -> Vector2 23 | where 24 | T: RealField, 25 | { 26 | let n = plane_normal.as_ref(); // Get the underlying Vector2 27 | vector - n * (n.dot(vector) * na::convert(2.0)) 28 | } 29 | 30 | /// Reflects a 3D vector wrt. the 3D plane with normal `plane_normal`. 31 | /// /!\ This is an exact replicate of `reflect_wrt_hyperplane2`, but for 3D. 32 | fn reflect_wrt_hyperplane3(plane_normal: &Unit>, vector: &Vector3) -> Vector3 33 | where 34 | T: RealField, 35 | { 36 | let n = plane_normal.as_ref(); // Get the underlying Vector3 37 | vector - n * (n.dot(vector) * na::convert(2.0)) 38 | } 39 | 40 | fn main() { 41 | let plane2 = Vector2::y_axis(); // 2D plane normal. 42 | let plane3 = Vector3::y_axis(); // 3D plane normal. 43 | 44 | let v2 = Vector2::new(1.0, 2.0); // 2D vector to be reflected. 45 | let v3 = Vector3::new(1.0, 2.0, 3.0); // 3D vector to be reflected. 46 | 47 | // We can call the same function for 2D and 3D. 48 | assert_eq!( 49 | reflect_wrt_hyperplane_with_dimensional_genericity(&plane2, &v2).y, 50 | -2.0 51 | ); 52 | assert_eq!( 53 | reflect_wrt_hyperplane_with_dimensional_genericity(&plane3, &v3).y, 54 | -2.0 55 | ); 56 | 57 | // Call each specific implementation depending on the dimension. 58 | assert_eq!(reflect_wrt_hyperplane2(&plane2, &v2).y, -2.0); 59 | assert_eq!(reflect_wrt_hyperplane3(&plane3, &v3).y, -2.0); 60 | } 61 | -------------------------------------------------------------------------------- /examples/homogeneous_coordinates.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate approx; 3 | extern crate nalgebra as na; 4 | 5 | use na::{Isometry2, Point2, Vector2}; 6 | use std::f32; 7 | 8 | fn use_dedicated_types() { 9 | let iso = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI); 10 | let pt = Point2::new(1.0, 0.0); 11 | let vec = Vector2::x(); 12 | 13 | let transformed_pt = iso * pt; 14 | let transformed_vec = iso * vec; 15 | 16 | assert_relative_eq!(transformed_pt, Point2::new(0.0, 1.0)); 17 | assert_relative_eq!(transformed_vec, Vector2::new(-1.0, 0.0)); 18 | } 19 | 20 | fn use_homogeneous_coordinates() { 21 | let iso = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI); 22 | let pt = Point2::new(1.0, 0.0); 23 | let vec = Vector2::x(); 24 | 25 | // Compute using homogeneous coordinates. 26 | let hom_iso = iso.to_homogeneous(); 27 | let hom_pt = pt.to_homogeneous(); 28 | let hom_vec = vec.to_homogeneous(); 29 | 30 | let hom_transformed_pt = hom_iso * hom_pt; 31 | let hom_transformed_vec = hom_iso * hom_vec; 32 | 33 | // Convert back to the cartesian coordinates. 34 | let transformed_pt = Point2::from_homogeneous(hom_transformed_pt).unwrap(); 35 | let transformed_vec = Vector2::from_homogeneous(hom_transformed_vec).unwrap(); 36 | 37 | assert_relative_eq!(transformed_pt, Point2::new(0.0, 1.0)); 38 | assert_relative_eq!(transformed_vec, Vector2::new(-1.0, 0.0)); 39 | } 40 | 41 | fn main() { 42 | use_dedicated_types(); 43 | use_homogeneous_coordinates(); 44 | } 45 | -------------------------------------------------------------------------------- /examples/linear_system_resolution.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | #[macro_use] 3 | extern crate approx; // for assert_relative_eq 4 | extern crate nalgebra as na; 5 | use na::{Matrix4, Matrix4x3, Vector4}; 6 | 7 | fn main() { 8 | let a = Matrix4::new( 9 | 1.0, 1.0, 2.0, -5.0, 10 | 2.0, 5.0, -1.0, -9.0, 11 | 2.0, 1.0, -1.0, 3.0, 12 | 1.0, 3.0, 2.0, 7.0, 13 | ); 14 | let mut b = Vector4::new(3.0, -3.0, -11.0, -5.0); 15 | let decomp = a.lu(); 16 | let x = decomp.solve(&b).expect("Linear resolution failed."); 17 | assert_relative_eq!(a * x, b); 18 | 19 | /* 20 | * It is possible to perform the resolution in-place. 21 | * This is particularly useful to avoid allocations when 22 | * `b` is a `DVector` or a `DMatrix`. 23 | */ 24 | assert!(decomp.solve_mut(&mut b), "Linear resolution failed."); 25 | assert_relative_eq!(x, b); 26 | 27 | /* 28 | * It is possible to solve multiple systems 29 | * simultaneously by using a matrix for `b`. 30 | */ 31 | let b = Matrix4x3::new( 32 | 3.0, 2.0, 0.0, 33 | -3.0, 0.0, 0.0, 34 | -11.0, 5.0, -3.0, 35 | -5.0, 10.0, 4.0, 36 | ); 37 | let x = decomp.solve(&b).expect("Linear resolution failed."); 38 | assert_relative_eq!(a * x, b); 39 | } 40 | -------------------------------------------------------------------------------- /examples/matrix_construction.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{DMatrix, Matrix2x3, RowVector3, Vector2}; 4 | 5 | fn main() { 6 | // All the following matrices are equal but constructed in different ways. 7 | let m = Matrix2x3::new(1.1, 1.2, 1.3, 2.1, 2.2, 2.3); 8 | 9 | let m1 = Matrix2x3::from_rows(&[ 10 | RowVector3::new(1.1, 1.2, 1.3), 11 | RowVector3::new(2.1, 2.2, 2.3), 12 | ]); 13 | 14 | let m2 = Matrix2x3::from_columns(&[ 15 | Vector2::new(1.1, 2.1), 16 | Vector2::new(1.2, 2.2), 17 | Vector2::new(1.3, 2.3), 18 | ]); 19 | 20 | let m3 = Matrix2x3::from_row_slice(&[1.1, 1.2, 1.3, 2.1, 2.2, 2.3]); 21 | 22 | let m4 = Matrix2x3::from_column_slice(&[1.1, 2.1, 1.2, 2.2, 1.3, 2.3]); 23 | 24 | let m5 = Matrix2x3::from_fn(|r, c| (r + 1) as f32 + (c + 1) as f32 / 10.0); 25 | 26 | let m6 = Matrix2x3::from_iterator([1.1f32, 2.1, 1.2, 2.2, 1.3, 2.3].iter().cloned()); 27 | 28 | assert_eq!(m, m1); 29 | assert_eq!(m, m2); 30 | assert_eq!(m, m3); 31 | assert_eq!(m, m4); 32 | assert_eq!(m, m5); 33 | assert_eq!(m, m6); 34 | 35 | // All the following matrices are equal but constructed in different ways. 36 | // This time, we used a dynamically-sized matrix to show the extra arguments 37 | // for the matrix shape. 38 | let dm = DMatrix::from_row_slice( 39 | 4, 40 | 3, 41 | &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0], 42 | ); 43 | 44 | let dm1 = DMatrix::from_diagonal_element(4, 3, 1.0); 45 | let dm2 = DMatrix::identity(4, 3); 46 | let dm3 = DMatrix::from_fn(4, 3, |r, c| if r == c { 1.0 } else { 0.0 }); 47 | let dm4 = DMatrix::from_iterator( 48 | 4, 49 | 3, 50 | [ 51 | // Components listed column-by-column. 52 | 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 53 | ] 54 | .iter() 55 | .cloned(), 56 | ); 57 | 58 | assert_eq!(dm, dm1); 59 | assert_eq!(dm, dm2); 60 | assert_eq!(dm, dm3); 61 | assert_eq!(dm, dm4); 62 | } 63 | -------------------------------------------------------------------------------- /examples/mvp.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | extern crate nalgebra as na; 4 | 5 | use na::{Isometry3, Perspective3, Point3, Vector3}; 6 | use std::f32::consts; 7 | 8 | fn main() { 9 | // Our object is translated along the x axis. 10 | let model = Isometry3::new(Vector3::x(), na::zero()); 11 | 12 | // Our camera looks toward the point (1.0, 0.0, 0.0). 13 | // It is located at (0.0, 0.0, 1.0). 14 | let eye = Point3::new(0.0, 0.0, 1.0); 15 | let target = Point3::new(1.0, 0.0, 0.0); 16 | let view = Isometry3::look_at_rh(&eye, &target, &Vector3::y()); 17 | 18 | // A perspective projection. 19 | let projection = Perspective3::new(16.0 / 9.0, consts::PI / 2.0, 1.0, 1000.0); 20 | 21 | // The combination of the model with the view is still an isometry. 22 | let model_view = view * model; 23 | 24 | // Convert everything to a `Matrix4` so that they can be combined. 25 | let mat_model_view = model_view.to_homogeneous(); 26 | 27 | // Combine everything. 28 | let model_view_projection = projection.as_matrix() * mat_model_view; 29 | } 30 | -------------------------------------------------------------------------------- /examples/point_construction.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{Point3, Vector3, Vector4}; 4 | 5 | fn main() { 6 | // Build using components directly. 7 | let p0 = Point3::new(2.0, 3.0, 4.0); 8 | 9 | // Build from a coordinates vector. 10 | let coords = Vector3::new(2.0, 3.0, 4.0); 11 | let p1 = Point3::from(coords); 12 | 13 | // Build by translating the origin. 14 | let translation = Vector3::new(2.0, 3.0, 4.0); 15 | let p2 = Point3::origin() + translation; 16 | 17 | // Build from homogeneous coordinates. The last component of the 18 | // vector will be removed and all other components divided by 10.0. 19 | let homogeneous_coords = Vector4::new(20.0, 30.0, 40.0, 10.0); 20 | let p3 = Point3::from_homogeneous(homogeneous_coords); 21 | 22 | assert_eq!(p0, p1); 23 | assert_eq!(p0, p2); 24 | assert_eq!(p0, p3.unwrap()); 25 | } 26 | -------------------------------------------------------------------------------- /examples/raw_pointer.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{Matrix3, Point3, Vector3}; 4 | 5 | fn main() { 6 | let v = Vector3::new(1.0f32, 0.0, 1.0); 7 | let p = Point3::new(1.0f32, 0.0, 1.0); 8 | let m = na::one::>(); 9 | 10 | // Convert to arrays. 11 | let v_array = v.as_slice(); 12 | let p_array = p.coords.as_slice(); 13 | let m_array = m.as_slice(); 14 | 15 | // Get data pointers. 16 | let v_pointer = v_array.as_ptr(); 17 | let p_pointer = p_array.as_ptr(); 18 | let m_pointer = m_array.as_ptr(); 19 | 20 | /* Then pass the raw pointers to some graphics API. */ 21 | 22 | #[allow(clippy::float_cmp)] 23 | unsafe { 24 | assert_eq!(*v_pointer, 1.0); 25 | assert_eq!(*v_pointer.offset(1), 0.0); 26 | assert_eq!(*v_pointer.offset(2), 1.0); 27 | 28 | assert_eq!(*p_pointer, 1.0); 29 | assert_eq!(*p_pointer.offset(1), 0.0); 30 | assert_eq!(*p_pointer.offset(2), 1.0); 31 | 32 | assert_eq!(*m_pointer, 1.0); 33 | assert_eq!(*m_pointer.offset(4), 1.0); 34 | assert_eq!(*m_pointer.offset(8), 1.0); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/reshaping.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | 3 | extern crate nalgebra as na; 4 | 5 | use na::{DMatrix, Dyn, Matrix2x3, Matrix3x2, Const}; 6 | 7 | fn main() { 8 | // Matrices can be reshaped in-place without moving or copying values. 9 | let m1 = Matrix2x3::new( 10 | 1.1, 1.2, 1.3, 11 | 2.1, 2.2, 2.3 12 | ); 13 | let m2 = Matrix3x2::new( 14 | 1.1, 2.2, 15 | 2.1, 1.3, 16 | 1.2, 2.3 17 | ); 18 | 19 | let m3 = m1.reshape_generic(Const::<3>, Const::<2>); 20 | assert_eq!(m3, m2); 21 | 22 | // Note that, for statically sized matrices, invalid reshapes will not compile: 23 | //let m4 = m3.reshape_generic(U3, U3); 24 | 25 | // If dynamically sized matrices are used, the reshaping is checked at run-time. 26 | let dm1 = DMatrix::from_row_slice( 27 | 4, 28 | 3, 29 | &[ 30 | 1.0, 0.0, 0.0, 31 | 0.0, 0.0, 1.0, 32 | 0.0, 0.0, 0.0, 33 | 0.0, 1.0, 0.0 34 | ], 35 | ); 36 | let dm2 = DMatrix::from_row_slice( 37 | 6, 38 | 2, 39 | &[ 40 | 1.0, 0.0, 41 | 0.0, 1.0, 42 | 0.0, 0.0, 43 | 0.0, 1.0, 44 | 0.0, 0.0, 45 | 0.0, 0.0, 46 | ], 47 | ); 48 | 49 | let dm3 = dm1.reshape_generic(Dyn(6), Dyn(2)); 50 | assert_eq!(dm3, dm2); 51 | 52 | // Invalid reshapings of dynamic matrices will panic at run-time. 53 | //let dm4 = dm3.reshape_generic(Dyn(6), Dyn(6)); 54 | } 55 | -------------------------------------------------------------------------------- /examples/scalar_genericity.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{Scalar, Vector3}; 4 | use simba::scalar::RealField; 5 | 6 | fn print_vector(m: &Vector3) { 7 | println!("{:?}", m) 8 | } 9 | 10 | fn print_norm(v: &Vector3) { 11 | // NOTE: alternatively, nalgebra already defines `v.norm()`. 12 | let norm = v.dot(v).sqrt(); 13 | 14 | // The RealField bound implies that T is Display so we can 15 | // use "{}" instead of "{:?}" for the format string. 16 | println!("{}", norm) 17 | } 18 | 19 | fn main() { 20 | let v1 = Vector3::new(1, 2, 3); 21 | let v2 = Vector3::new(1.0, 2.0, 3.0); 22 | 23 | print_vector(&v1); 24 | print_norm(&v2); 25 | } 26 | -------------------------------------------------------------------------------- /examples/screen_to_view_coords.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | extern crate nalgebra as na; 4 | 5 | use na::{Perspective3, Point2, Point3, Unit}; 6 | use std::f32::consts; 7 | 8 | fn main() { 9 | let projection = Perspective3::new(800.0 / 600.0, consts::PI / 2.0, 1.0, 1000.0); 10 | let screen_point = Point2::new(10.0f32, 20.0); 11 | 12 | // Compute two points in clip-space. 13 | // "ndc" = normalized device coordinates. 14 | let near_ndc_point = Point3::new(screen_point.x / 800.0, screen_point.y / 600.0, -1.0); 15 | let far_ndc_point = Point3::new(screen_point.x / 800.0, screen_point.y / 600.0, 1.0); 16 | 17 | // Unproject them to view-space. 18 | let near_view_point = projection.unproject_point(&near_ndc_point); 19 | let far_view_point = projection.unproject_point(&far_ndc_point); 20 | 21 | // Compute the view-space line parameters. 22 | let line_location = near_view_point; 23 | let line_direction = Unit::new_normalize(far_view_point - near_view_point); 24 | } 25 | -------------------------------------------------------------------------------- /examples/transform_conversion.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{Isometry2, Similarity2, Vector2}; 4 | use std::f32::consts; 5 | 6 | fn main() { 7 | // Isometry -> Similarity conversion always succeeds. 8 | let iso = Isometry2::new(Vector2::new(1.0f32, 2.0), na::zero()); 9 | let _: Similarity2 = na::convert(iso); 10 | 11 | // Similarity -> Isometry conversion fails if the scaling factor is not 1.0. 12 | let sim_without_scaling = Similarity2::new(Vector2::new(1.0f32, 2.0), consts::PI, 1.0); 13 | let sim_with_scaling = Similarity2::new(Vector2::new(1.0f32, 2.0), consts::PI, 2.0); 14 | 15 | let iso_success: Option> = na::try_convert(sim_without_scaling); 16 | let iso_fail: Option> = na::try_convert(sim_with_scaling); 17 | 18 | assert!(iso_success.is_some()); 19 | assert!(iso_fail.is_none()); 20 | 21 | // Similarity -> Isometry conversion can be forced at your own risks. 22 | let iso_forced: Isometry2 = na::convert_unchecked(sim_with_scaling); 23 | assert_eq!(iso_success.unwrap(), iso_forced); 24 | } 25 | -------------------------------------------------------------------------------- /examples/transform_matrix4.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate approx; 3 | extern crate nalgebra as na; 4 | 5 | use na::{Matrix4, Point3, Vector3}; 6 | use std::f32::consts; 7 | 8 | fn main() { 9 | // Create a uniform scaling matrix with scaling factor 2. 10 | let mut m = Matrix4::new_scaling(2.0); 11 | 12 | assert_eq!(m.transform_vector(&Vector3::x()), Vector3::x() * 2.0); 13 | assert_eq!(m.transform_vector(&Vector3::y()), Vector3::y() * 2.0); 14 | assert_eq!(m.transform_vector(&Vector3::z()), Vector3::z() * 2.0); 15 | 16 | // Append a nonuniform scaling in-place. 17 | m.append_nonuniform_scaling_mut(&Vector3::new(1.0, 2.0, 3.0)); 18 | 19 | assert_eq!(m.transform_vector(&Vector3::x()), Vector3::x() * 2.0); 20 | assert_eq!(m.transform_vector(&Vector3::y()), Vector3::y() * 4.0); 21 | assert_eq!(m.transform_vector(&Vector3::z()), Vector3::z() * 6.0); 22 | 23 | // Append a translation out-of-place. 24 | let m2 = m.append_translation(&Vector3::new(42.0, 0.0, 0.0)); 25 | 26 | assert_eq!( 27 | m2.transform_point(&Point3::new(1.0, 1.0, 1.0)), 28 | Point3::new(42.0 + 2.0, 4.0, 6.0) 29 | ); 30 | 31 | // Create rotation. 32 | let rot = Matrix4::from_scaled_axis(Vector3::x() * consts::PI); 33 | let rot_then_m = m * rot; // Right-multiplication is equivalent to prepending `rot` to `m`. 34 | let m_then_rot = rot * m; // Left-multiplication is equivalent to appending `rot` to `m`. 35 | 36 | let pt = Point3::new(1.0, 2.0, 3.0); 37 | 38 | assert_relative_eq!( 39 | m.transform_point(&rot.transform_point(&pt)), 40 | rot_then_m.transform_point(&pt) 41 | ); 42 | assert_relative_eq!( 43 | rot.transform_point(&m.transform_point(&pt)), 44 | m_then_rot.transform_point(&pt) 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /examples/transform_vector_point.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate approx; 3 | extern crate nalgebra as na; 4 | 5 | use na::{Isometry2, Point2, Vector2}; 6 | use std::f32; 7 | 8 | fn main() { 9 | let t = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI); 10 | let p = Point2::new(1.0, 0.0); // Will be affected by te rotation and the translation. 11 | let v = Vector2::x(); // Will *not* be affected by the translation. 12 | 13 | assert_relative_eq!(t * p, Point2::new(-1.0 + 1.0, 1.0)); 14 | // ^^^^ │ ^^^^^^^^ 15 | // rotated │ translated 16 | 17 | assert_relative_eq!(t * v, Vector2::new(-1.0, 0.0)); 18 | // ^^^^^ 19 | // rotated only 20 | } 21 | -------------------------------------------------------------------------------- /examples/transform_vector_point3.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{Matrix4, Point3, Vector3, Vector4}; 4 | 5 | fn main() { 6 | let mut m = Matrix4::new_rotation_wrt_point(Vector3::x() * 1.57, Point3::new(1.0, 2.0, 1.0)); 7 | m.append_scaling_mut(2.0); 8 | 9 | let point1 = Point3::new(2.0, 3.0, 4.0); 10 | let homogeneous_point2 = Vector4::new(2.0, 3.0, 4.0, 1.0); 11 | 12 | // First option: use the dedicated `.transform_point(...)` method. 13 | let transformed_point1 = m.transform_point(&point1); 14 | // Second option: use the homogeneous coordinates of the point. 15 | let transformed_homogeneous_point2 = m * homogeneous_point2; 16 | 17 | // Recover the 3D point from its 4D homogeneous coordinates. 18 | let transformed_point2 = Point3::from_homogeneous(transformed_homogeneous_point2); 19 | 20 | // Check that transforming the 3D point with the `.transform_point` method is 21 | // indeed equivalent to multiplying its 4D homogeneous coordinates by the 4x4 22 | // matrix. 23 | assert_eq!(transformed_point1, transformed_point2.unwrap()); 24 | } 25 | -------------------------------------------------------------------------------- /examples/transformation_pointer.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | 3 | use na::{Isometry3, Vector3}; 4 | 5 | fn main() { 6 | let iso = Isometry3::new(Vector3::new(1.0f32, 0.0, 1.0), na::zero()); 7 | 8 | // Compute the homogeneous coordinates first. 9 | let iso_matrix = iso.to_homogeneous(); 10 | let iso_array = iso_matrix.as_slice(); 11 | let iso_pointer = iso_array.as_ptr(); 12 | 13 | /* Then pass the raw pointer to some graphics API. */ 14 | 15 | #[allow(clippy::float_cmp)] 16 | unsafe { 17 | assert_eq!(*iso_pointer, 1.0); 18 | assert_eq!(*iso_pointer.offset(5), 1.0); 19 | assert_eq!(*iso_pointer.offset(10), 1.0); 20 | assert_eq!(*iso_pointer.offset(15), 1.0); 21 | 22 | assert_eq!(*iso_pointer.offset(12), 1.0); 23 | assert_eq!(*iso_pointer.offset(13), 0.0); 24 | assert_eq!(*iso_pointer.offset(14), 1.0); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/unit_wrapper.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::float_cmp)] 2 | extern crate nalgebra as na; 3 | 4 | use na::{Unit, Vector3}; 5 | 6 | fn length_on_direction_with_unit(v: &Vector3, dir: &Unit>) -> f32 { 7 | // No need to normalize `dir`: we know that it is non-zero and normalized. 8 | v.dot(dir.as_ref()) 9 | } 10 | 11 | fn length_on_direction_without_unit(v: &Vector3, dir: &Vector3) -> f32 { 12 | // Obligatory normalization of the direction vector (and test, for robustness). 13 | if let Some(unit_dir) = dir.try_normalize(1.0e-6) { 14 | v.dot(&unit_dir) 15 | } else { 16 | // Normalization failed because the norm was too small. 17 | panic!("Invalid input direction.") 18 | } 19 | } 20 | 21 | fn main() { 22 | let v = Vector3::new(1.0, 2.0, 3.0); 23 | 24 | let l1 = length_on_direction_with_unit(&v, &Vector3::y_axis()); 25 | let l2 = length_on_direction_without_unit(&v, &Vector3::y()); 26 | 27 | assert_eq!(l1, l2) 28 | } 29 | -------------------------------------------------------------------------------- /nalgebra-glm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nalgebra-glm" 3 | version = "0.19.0" 4 | authors = ["sebcrozet "] 5 | 6 | description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." 7 | documentation = "https://www.nalgebra.org/docs" 8 | homepage = "https://nalgebra.org" 9 | repository = "https://github.com/dimforge/nalgebra" 10 | readme = "../README.md" 11 | categories = ["science", "mathematics", "wasm", "no standard library"] 12 | keywords = ["linear", "algebra", "matrix", "vector", "math"] 13 | license = "Apache-2.0" 14 | edition = "2018" 15 | 16 | [badges] 17 | maintenance = { status = "actively-developed" } 18 | 19 | [features] 20 | default = ["std"] 21 | std = ["nalgebra/std", "simba/std"] 22 | arbitrary = ["nalgebra/arbitrary"] 23 | serde-serialize = ["nalgebra/serde-serialize-no-std"] 24 | 25 | # Conversion 26 | convert-mint = ["nalgebra/mint"] 27 | convert-bytemuck = ["nalgebra/bytemuck"] 28 | convert-glam014 = ["nalgebra/glam014"] 29 | convert-glam015 = ["nalgebra/glam015"] 30 | convert-glam016 = ["nalgebra/glam016"] 31 | convert-glam017 = ["nalgebra/glam017"] 32 | convert-glam018 = ["nalgebra/glam018"] 33 | 34 | [dependencies] 35 | num-traits = { version = "0.2", default-features = false } 36 | approx = { version = "0.5", default-features = false } 37 | simba = { version = "0.9", default-features = false } 38 | nalgebra = { path = "..", version = "0.33", default-features = false } 39 | -------------------------------------------------------------------------------- /nalgebra-glm/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /nalgebra-glm/src/exponential.rs: -------------------------------------------------------------------------------- 1 | use crate::aliases::TVec; 2 | use crate::RealNumber; 3 | 4 | /// Component-wise exponential. 5 | /// 6 | /// # See also: 7 | /// 8 | /// * [`exp2()`] 9 | pub fn exp(v: &TVec) -> TVec { 10 | v.map(|x| x.exp()) 11 | } 12 | 13 | /// Component-wise base-2 exponential. 14 | /// 15 | /// # See also: 16 | /// 17 | /// * [`exp()`] 18 | pub fn exp2(v: &TVec) -> TVec { 19 | v.map(|x| x.exp2()) 20 | } 21 | 22 | /// Compute the inverse of the square root of each component of `v`. 23 | /// 24 | /// # See also: 25 | /// 26 | /// * [`sqrt()`] 27 | pub fn inversesqrt(v: &TVec) -> TVec { 28 | v.map(|x| T::one() / x.sqrt()) 29 | } 30 | 31 | /// Component-wise logarithm. 32 | /// 33 | /// # See also: 34 | /// 35 | /// * [`log2()`] 36 | pub fn log(v: &TVec) -> TVec { 37 | v.map(|x| x.ln()) 38 | } 39 | 40 | /// Component-wise base-2 logarithm. 41 | /// 42 | /// # See also: 43 | /// 44 | /// * [`log()`] 45 | pub fn log2(v: &TVec) -> TVec { 46 | v.map(|x| x.log2()) 47 | } 48 | 49 | /// Component-wise power. 50 | pub fn pow(base: &TVec, exponent: &TVec) -> TVec { 51 | base.zip_map(exponent, |b, e| b.powf(e)) 52 | } 53 | 54 | /// Component-wise square root. 55 | /// 56 | /// # See also: 57 | /// 58 | /// * [`exp()`] 59 | /// * [`exp2()`] 60 | /// * [`inversesqrt()`] 61 | /// * [`pow`] 62 | pub fn sqrt(v: &TVec) -> TVec { 63 | v.map(|x| x.sqrt()) 64 | } 65 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/quaternion_common.rs: -------------------------------------------------------------------------------- 1 | use na::Unit; 2 | 3 | use crate::aliases::Qua; 4 | use crate::RealNumber; 5 | 6 | /// The conjugate of `q`. 7 | pub fn quat_conjugate(q: &Qua) -> Qua { 8 | q.conjugate() 9 | } 10 | 11 | /// The inverse of `q`. 12 | pub fn quat_inverse(q: &Qua) -> Qua { 13 | q.try_inverse().unwrap_or_else(na::zero) 14 | } 15 | 16 | //pub fn quat_isinf(x: &Qua) -> TVec { 17 | // x.coords.map(|e| e.is_inf()) 18 | //} 19 | 20 | //pub fn quat_isnan(x: &Qua) -> TVec { 21 | // x.coords.map(|e| e.is_nan()) 22 | //} 23 | 24 | /// Interpolate linearly between `x` and `y`. 25 | pub fn quat_lerp(x: &Qua, y: &Qua, a: T) -> Qua { 26 | x.lerp(y, a) 27 | } 28 | 29 | //pub fn quat_mix(x: &Qua, y: &Qua, a: T) -> Qua { 30 | // x * (T::one() - a) + y * a 31 | //} 32 | 33 | /// Interpolate spherically between `x` and `y`. 34 | pub fn quat_slerp(x: &Qua, y: &Qua, a: T) -> Qua { 35 | Unit::new_normalize(*x) 36 | .slerp(&Unit::new_normalize(*y), a) 37 | .into_inner() 38 | } 39 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/quaternion_geometric.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | 3 | use crate::aliases::Qua; 4 | 5 | /// Multiplies two quaternions. 6 | pub fn quat_cross(q1: &Qua, q2: &Qua) -> Qua { 7 | q1 * q2 8 | } 9 | 10 | /// The scalar product of two quaternions. 11 | pub fn quat_dot(x: &Qua, y: &Qua) -> T { 12 | x.dot(y) 13 | } 14 | 15 | /// The magnitude of the quaternion `q`. 16 | pub fn quat_length(q: &Qua) -> T { 17 | q.norm() 18 | } 19 | 20 | /// The magnitude of the quaternion `q`. 21 | pub fn quat_magnitude(q: &Qua) -> T { 22 | q.norm() 23 | } 24 | 25 | /// Normalizes the quaternion `q`. 26 | pub fn quat_normalize(q: &Qua) -> Qua { 27 | q.normalize() 28 | } 29 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/quaternion_relational.rs: -------------------------------------------------------------------------------- 1 | use crate::aliases::{Qua, TVec}; 2 | use crate::RealNumber; 3 | 4 | /// Component-wise equality comparison between two quaternions. 5 | pub fn quat_equal(x: &Qua, y: &Qua) -> TVec { 6 | crate::equal(&x.coords, &y.coords) 7 | } 8 | 9 | /// Component-wise approximate equality comparison between two quaternions. 10 | pub fn quat_equal_eps(x: &Qua, y: &Qua, epsilon: T) -> TVec { 11 | crate::equal_eps(&x.coords, &y.coords, epsilon) 12 | } 13 | 14 | /// Component-wise non-equality comparison between two quaternions. 15 | pub fn quat_not_equal(x: &Qua, y: &Qua) -> TVec { 16 | crate::not_equal(&x.coords, &y.coords) 17 | } 18 | 19 | /// Component-wise approximate non-equality comparison between two quaternions. 20 | pub fn quat_not_equal_eps(x: &Qua, y: &Qua, epsilon: T) -> TVec { 21 | crate::not_equal_eps(&x.coords, &y.coords, epsilon) 22 | } 23 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/quaternion_transform.rs: -------------------------------------------------------------------------------- 1 | use na::{Unit, UnitQuaternion}; 2 | 3 | use crate::aliases::{Qua, TVec3}; 4 | use crate::RealNumber; 5 | 6 | /// Computes the quaternion exponential. 7 | pub fn quat_exp(q: &Qua) -> Qua { 8 | q.exp() 9 | } 10 | 11 | /// Computes the quaternion logarithm. 12 | pub fn quat_log(q: &Qua) -> Qua { 13 | q.ln() 14 | } 15 | 16 | /// Raises the quaternion `q` to the power `y`. 17 | pub fn quat_pow(q: &Qua, y: T) -> Qua { 18 | q.powf(y) 19 | } 20 | 21 | /// Builds a quaternion from an axis and an angle, and right-multiply it to the quaternion `q`. 22 | pub fn quat_rotate(q: &Qua, angle: T, axis: &TVec3) -> Qua { 23 | q * UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner() 24 | } 25 | 26 | //pub fn quat_sqrt(q: &Qua) -> Qua { 27 | // unimplemented!() 28 | //} 29 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/quaternion_trigonometric.rs: -------------------------------------------------------------------------------- 1 | use na::{Unit, UnitQuaternion}; 2 | 3 | use crate::aliases::{Qua, TVec3}; 4 | use crate::RealNumber; 5 | 6 | /// The rotation angle of this quaternion assumed to be normalized. 7 | pub fn quat_angle(x: &Qua) -> T { 8 | UnitQuaternion::from_quaternion(*x).angle() 9 | } 10 | 11 | /// Creates a quaternion from an axis and an angle. 12 | pub fn quat_angle_axis(angle: T, axis: &TVec3) -> Qua { 13 | UnitQuaternion::from_axis_angle(&Unit::new_normalize(*axis), angle).into_inner() 14 | } 15 | 16 | /// The rotation axis of a quaternion assumed to be normalized. 17 | pub fn quat_axis(x: &Qua) -> TVec3 { 18 | if let Some(a) = UnitQuaternion::from_quaternion(*x).axis() { 19 | a.into_inner() 20 | } else { 21 | TVec3::zeros() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/scalar_constants.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | use approx::AbsDiffEq; 3 | 4 | /// Default epsilon value used for approximate comparison. 5 | pub fn epsilon>() -> T { 6 | T::default_epsilon() 7 | } 8 | 9 | /// The value of PI. 10 | /// 11 | /// # See also: 12 | /// 13 | /// * [`four_over_pi()`](crate::four_over_pi) 14 | /// * [`half_pi()`](crate::half_pi) 15 | /// * [`one_over_pi()`](crate::one_over_pi) 16 | /// * [`one_over_two_pi()`](crate::one_over_two_pi) 17 | /// * [`quarter_pi()`](crate::quarter_pi) 18 | /// * [`root_half_pi()`](crate::root_half_pi) 19 | /// * [`root_pi()`](crate::root_pi) 20 | /// * [`root_two_pi()`](crate::root_two_pi) 21 | /// * [`three_over_two_pi()`](crate::three_over_two_pi) 22 | /// * [`two_over_pi()`](crate::two_over_pi) 23 | /// * [`two_over_root_pi()`](crate::two_over_root_pi) 24 | /// * [`two_pi()`](crate::two_pi) 25 | pub fn pi() -> T { 26 | T::pi() 27 | } 28 | -------------------------------------------------------------------------------- /nalgebra-glm/src/ext/vector_relational.rs: -------------------------------------------------------------------------------- 1 | use crate::aliases::TVec; 2 | use crate::traits::Number; 3 | 4 | /// Component-wise approximate equality of two vectors, using a scalar epsilon. 5 | /// 6 | /// # See also: 7 | /// 8 | /// * [`equal_eps_vec()`] 9 | /// * [`not_equal_eps()`] 10 | /// * [`not_equal_eps_vec()`] 11 | pub fn equal_eps( 12 | x: &TVec, 13 | y: &TVec, 14 | epsilon: T, 15 | ) -> TVec { 16 | x.zip_map(y, |x, y| abs_diff_eq!(x, y, epsilon = epsilon)) 17 | } 18 | 19 | /// Component-wise approximate equality of two vectors, using a per-component epsilon. 20 | /// 21 | /// # See also: 22 | /// 23 | /// * [`equal_eps()`] 24 | /// * [`not_equal_eps()`] 25 | /// * [`not_equal_eps_vec()`] 26 | pub fn equal_eps_vec( 27 | x: &TVec, 28 | y: &TVec, 29 | epsilon: &TVec, 30 | ) -> TVec { 31 | x.zip_zip_map(y, epsilon, |x, y, eps| abs_diff_eq!(x, y, epsilon = eps)) 32 | } 33 | 34 | /// Component-wise approximate non-equality of two vectors, using a scalar epsilon. 35 | /// 36 | /// # See also: 37 | /// 38 | /// * [`equal_eps()`] 39 | /// * [`equal_eps_vec()`] 40 | /// * [`not_equal_eps_vec()`] 41 | pub fn not_equal_eps( 42 | x: &TVec, 43 | y: &TVec, 44 | epsilon: T, 45 | ) -> TVec { 46 | x.zip_map(y, |x, y| abs_diff_ne!(x, y, epsilon = epsilon)) 47 | } 48 | 49 | /// Component-wise approximate non-equality of two vectors, using a per-component epsilon. 50 | /// 51 | /// # See also: 52 | /// 53 | /// * [`equal_eps()`] 54 | /// * [`equal_eps_vec()`] 55 | /// * [`not_equal_eps()`] 56 | pub fn not_equal_eps_vec( 57 | x: &TVec, 58 | y: &TVec, 59 | epsilon: &TVec, 60 | ) -> TVec { 61 | x.zip_zip_map(y, epsilon, |x, y, eps| abs_diff_ne!(x, y, epsilon = eps)) 62 | } 63 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/epsilon.rs: -------------------------------------------------------------------------------- 1 | // NOTE those are actually duplicates of vector_relational.rs 2 | 3 | /* 4 | use approx::AbsDiffEq; 5 | use na::DefaultAllocator; 6 | 7 | use crate::traits::{Alloc, Number, Dimension}; 8 | use crate::aliases::TVec; 9 | 10 | /// Component-wise approximate equality between two vectors. 11 | pub fn epsilon_equal(x: &TVec, y: &TVec, epsilon: T) -> TVec 12 | where DefaultAllocator: Alloc { 13 | x.zip_map(y, |x, y| abs_diff_eq!(x, y, epsilon = epsilon)) 14 | } 15 | 16 | /// Component-wise approximate equality between two scalars. 17 | pub fn epsilon_equal2>(x: T, y: T, epsilon: T) -> bool { 18 | abs_diff_eq!(x, y, epsilon = epsilon) 19 | } 20 | 21 | /// Component-wise approximate non-equality between two vectors. 22 | pub fn epsilon_not_equal(x: &TVec, y: &TVec, epsilon: T) -> TVec 23 | where DefaultAllocator: Alloc { 24 | x.zip_map(y, |x, y| abs_diff_ne!(x, y, epsilon = epsilon)) 25 | } 26 | 27 | /// Component-wise approximate non-equality between two scalars. 28 | pub fn epsilon_not_equal2>(x: T, y: T, epsilon: T) -> bool { 29 | abs_diff_ne!(x, y, epsilon = epsilon) 30 | } 31 | */ 32 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/integer.rs: -------------------------------------------------------------------------------- 1 | //use na::Scalar; 2 | // 3 | // 4 | //use crate::aliases::TVec; 5 | 6 | //pub fn iround(x: &TVec) -> TVec { 7 | // x.map(|x| x.round()) 8 | //} 9 | // 10 | //pub fn log2(x: I) -> I { 11 | // unimplemented!() 12 | //} 13 | // 14 | //pub fn uround(x: &TVec) -> TVec { 15 | // unimplemented!() 16 | //} 17 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/matrix_access.rs: -------------------------------------------------------------------------------- 1 | use na::Scalar; 2 | 3 | use crate::aliases::{TMat, TVec}; 4 | 5 | /// The `index`-th column of the matrix `m`. 6 | /// 7 | /// # See also: 8 | /// 9 | /// * [`row()`] 10 | /// * [`set_column()`] 11 | /// * [`set_row()`] 12 | pub fn column( 13 | m: &TMat, 14 | index: usize, 15 | ) -> TVec { 16 | m.column(index).into_owned() 17 | } 18 | 19 | /// Sets to `x` the `index`-th column of the matrix `m`. 20 | /// 21 | /// # See also: 22 | /// 23 | /// * [`column()`] 24 | /// * [`row()`] 25 | /// * [`set_row()`] 26 | pub fn set_column( 27 | m: &TMat, 28 | index: usize, 29 | x: &TVec, 30 | ) -> TMat { 31 | let mut res = m.clone(); 32 | res.set_column(index, x); 33 | res 34 | } 35 | 36 | /// The `index`-th row of the matrix `m`. 37 | /// 38 | /// # See also: 39 | /// 40 | /// * [`column()`] 41 | /// * [`set_column()`] 42 | /// * [`set_row()`] 43 | pub fn row( 44 | m: &TMat, 45 | index: usize, 46 | ) -> TVec { 47 | m.row(index).into_owned().transpose() 48 | } 49 | 50 | /// Sets to `x` the `index`-th row of the matrix `m`. 51 | /// 52 | /// # See also: 53 | /// 54 | /// * [`column()`] 55 | /// * [`row()`] 56 | /// * [`set_column()`] 57 | pub fn set_row( 58 | m: &TMat, 59 | index: usize, 60 | x: &TVec, 61 | ) -> TMat { 62 | let mut res = m.clone(); 63 | res.set_row(index, &x.transpose()); 64 | res 65 | } 66 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/matrix_inverse.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | 3 | use crate::aliases::TMat; 4 | 5 | /// Fast matrix inverse for affine matrix. 6 | pub fn affine_inverse(m: TMat) -> TMat { 7 | // TODO: this should be optimized. 8 | m.try_inverse().unwrap_or_else(TMat::<_, D, D>::zeros) 9 | } 10 | 11 | /// Compute the transpose of the inverse of a matrix. 12 | pub fn inverse_transpose(m: TMat) -> TMat { 13 | m.try_inverse() 14 | .unwrap_or_else(TMat::<_, D, D>::zeros) 15 | .transpose() 16 | } 17 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/mod.rs: -------------------------------------------------------------------------------- 1 | //! (Reexported) Recommended features not specified by GLSL specification 2 | 3 | //pub use self::bitfield::*; 4 | pub use self::constants::{ 5 | e, euler, four_over_pi, golden_ratio, half_pi, ln_ln_two, ln_ten, ln_two, one, one_over_pi, 6 | one_over_root_two, one_over_two_pi, quarter_pi, root_five, root_half_pi, root_ln_four, root_pi, 7 | root_three, root_two, root_two_pi, third, three_over_two_pi, two_over_pi, two_over_root_pi, 8 | two_pi, two_thirds, zero, 9 | }; 10 | //pub use self::integer::*; 11 | pub use self::matrix_access::{column, row, set_column, set_row}; 12 | pub use self::matrix_inverse::{affine_inverse, inverse_transpose}; 13 | //pub use self::packing::*; 14 | //pub use self::reciprocal::*; 15 | //pub use self::round::*; 16 | pub use self::type_ptr::{ 17 | make_mat2, make_mat2x2, make_mat2x3, make_mat2x4, make_mat3, make_mat3x2, make_mat3x3, 18 | make_mat3x4, make_mat4, make_mat4x2, make_mat4x3, make_mat4x4, make_quat, make_vec1, make_vec2, 19 | make_vec3, make_vec4, mat2_to_mat3, mat2_to_mat4, mat3_to_mat2, mat3_to_mat4, mat4_to_mat2, 20 | mat4_to_mat3, value_ptr, value_ptr_mut, vec1_to_vec2, vec1_to_vec3, vec1_to_vec4, vec2_to_vec1, 21 | vec2_to_vec2, vec2_to_vec3, vec2_to_vec4, vec3_to_vec1, vec3_to_vec2, vec3_to_vec3, 22 | vec3_to_vec4, vec4_to_vec1, vec4_to_vec2, vec4_to_vec3, vec4_to_vec4, 23 | }; 24 | //pub use self::ulp::*; 25 | pub use self::quaternion::{ 26 | quat_cast, quat_euler_angles, quat_greater_than, quat_greater_than_equal, quat_less_than, 27 | quat_less_than_equal, quat_look_at, quat_look_at_lh, quat_look_at_rh, quat_pitch, quat_roll, 28 | quat_yaw, 29 | }; 30 | 31 | //mod bitfield; 32 | mod constants; 33 | mod epsilon; 34 | //mod integer; 35 | mod matrix_access; 36 | mod matrix_inverse; 37 | //mod packing; 38 | //mod reciprocal; 39 | //mod round; 40 | mod type_ptr; 41 | //mod ulp; 42 | mod quaternion; 43 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/reciprocal.rs: -------------------------------------------------------------------------------- 1 | pub fn acot(x: T) -> T { 2 | unimplemented!() 3 | } 4 | 5 | pub fn acoth(x: T) -> T { 6 | unimplemented!() 7 | } 8 | 9 | pub fn acsc(x: T) -> T { 10 | unimplemented!() 11 | } 12 | 13 | pub fn acsch(x: T) -> T { 14 | unimplemented!() 15 | } 16 | 17 | pub fn asec(x: T) -> T { 18 | unimplemented!() 19 | } 20 | 21 | pub fn asech(x: T) -> T { 22 | unimplemented!() 23 | } 24 | 25 | pub fn cot(angle: T) -> T { 26 | unimplemented!() 27 | } 28 | 29 | pub fn coth(angle: T) -> T { 30 | unimplemented!() 31 | } 32 | 33 | pub fn csc(angle: T) -> T { 34 | unimplemented!() 35 | } 36 | 37 | pub fn csch(angle: T) -> T { 38 | unimplemented!() 39 | } 40 | 41 | pub fn sec(angle: T) -> T { 42 | unimplemented!() 43 | } 44 | 45 | pub fn sech(angle: T) -> T { 46 | unimplemented!() 47 | } 48 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtc/ulp.rs: -------------------------------------------------------------------------------- 1 | use na::{Scalar, U2}; 2 | 3 | use crate::aliases::TVec; 4 | 5 | pub fn float_distance(x: T, y: T) -> u64 { 6 | unimplemented!() 7 | } 8 | 9 | pub fn float_distance2(x: &TVec2, y: &TVec2) -> TVec { 10 | unimplemented!() 11 | } 12 | 13 | pub fn next_float(x: T) -> T { 14 | unimplemented!() 15 | } 16 | 17 | pub fn next_float2(x: T, Distance: u64) -> T { 18 | unimplemented!() 19 | } 20 | 21 | pub fn prev_float(x: T) -> T { 22 | unimplemented!() 23 | } 24 | 25 | pub fn prev_float2(x: T, Distance: u64) -> T { 26 | unimplemented!() 27 | } 28 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/exterior_product.rs: -------------------------------------------------------------------------------- 1 | use crate::aliases::TVec2; 2 | use crate::traits::Number; 3 | 4 | /// The 2D perpendicular product between two vectors. 5 | pub fn cross2d(v: &TVec2, u: &TVec2) -> T { 6 | v.perp(u) 7 | } 8 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/handed_coordinate_space.rs: -------------------------------------------------------------------------------- 1 | use crate::aliases::TVec3; 2 | use crate::traits::Number; 3 | 4 | /// Returns `true` if `{a, b, c}` forms a left-handed trihedron. 5 | /// 6 | /// # See also: 7 | /// 8 | /// * [`right_handed()`] 9 | pub fn left_handed(a: &TVec3, b: &TVec3, c: &TVec3) -> bool { 10 | a.cross(b).dot(c) < T::zero() 11 | } 12 | 13 | /// Returns `true` if `{a, b, c}` forms a right-handed trihedron. 14 | /// 15 | /// # See also: 16 | /// 17 | /// * [`left_handed()`] 18 | pub fn right_handed(a: &TVec3, b: &TVec3, c: &TVec3) -> bool { 19 | a.cross(b).dot(c) > T::zero() 20 | } 21 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/matrix_cross_product.rs: -------------------------------------------------------------------------------- 1 | use crate::aliases::{TMat3, TMat4, TVec3}; 2 | use crate::RealNumber; 3 | 4 | /// Builds a 3x3 matrix `m` such that for any `v`: `m * v == cross(x, v)`. 5 | /// 6 | /// # See also: 7 | /// 8 | /// * [`matrix_cross()`] 9 | pub fn matrix_cross3(x: &TVec3) -> TMat3 { 10 | x.cross_matrix() 11 | } 12 | 13 | /// Builds a 4x4 matrix `m` such that for any `v`: `m * v == cross(x, v)`. 14 | /// 15 | /// # See also: 16 | /// 17 | /// * [`matrix_cross3()`] 18 | pub fn matrix_cross(x: &TVec3) -> TMat4 { 19 | crate::mat3_to_mat4(&x.cross_matrix()) 20 | } 21 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/mod.rs: -------------------------------------------------------------------------------- 1 | //! (Reexported) Experimental features not specified by GLSL specification. 2 | 3 | pub use self::component_wise::{comp_add, comp_max, comp_min, comp_mul}; 4 | //pub use self::euler_angles::*; 5 | pub use self::exterior_product::cross2d; 6 | pub use self::handed_coordinate_space::{left_handed, right_handed}; 7 | pub use self::matrix_cross_product::{matrix_cross, matrix_cross3}; 8 | pub use self::matrix_operation::{ 9 | diagonal2x2, diagonal2x3, diagonal2x4, diagonal3x2, diagonal3x3, diagonal3x4, diagonal4x2, 10 | diagonal4x3, diagonal4x4, 11 | }; 12 | pub use self::norm::{distance2, l1_distance, l1_norm, l2_distance, l2_norm, length2, magnitude2}; 13 | pub use self::normal::triangle_normal; 14 | pub use self::normalize_dot::{fast_normalize_dot, normalize_dot}; 15 | pub use self::quaternion::{ 16 | mat3_to_quat, quat_cross_vec, quat_extract_real_component, quat_fast_mix, quat_identity, 17 | quat_inv_cross_vec, quat_length2, quat_magnitude2, quat_rotate_vec, quat_rotate_vec3, 18 | quat_rotation, quat_short_mix, quat_to_mat3, quat_to_mat4, to_quat, 19 | }; 20 | pub use self::rotate_normalized_axis::{quat_rotate_normalized_axis, rotate_normalized_axis}; 21 | pub use self::rotate_vector::{ 22 | orientation, rotate_vec2, rotate_vec3, rotate_vec4, rotate_x_vec3, rotate_x_vec4, 23 | rotate_y_vec3, rotate_y_vec4, rotate_z_vec3, rotate_z_vec4, slerp, 24 | }; 25 | pub use self::transform::{rotation, rotation2d, scaling, scaling2d, translation, translation2d}; 26 | pub use self::transform2::{ 27 | proj, proj2d, reflect, reflect2d, scale_bias, scale_bias_matrix, shear2d_x, shear2d_y, shear_x, 28 | shear_y, shear_z, 29 | }; 30 | pub use self::transform2d::{rotate2d, scale2d, translate2d}; 31 | pub use self::vector_angle::angle; 32 | pub use self::vector_query::{ 33 | are_collinear, are_collinear2d, are_orthogonal, is_comp_null, is_normalized, is_null, 34 | }; 35 | 36 | mod component_wise; 37 | //mod euler_angles; 38 | mod exterior_product; 39 | mod handed_coordinate_space; 40 | mod matrix_cross_product; 41 | mod matrix_operation; 42 | mod norm; 43 | mod normal; 44 | mod normalize_dot; 45 | mod quaternion; 46 | mod rotate_normalized_axis; 47 | mod rotate_vector; 48 | mod transform; 49 | mod transform2; 50 | mod transform2d; 51 | mod vector_angle; 52 | mod vector_query; 53 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/normal.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | 3 | use crate::aliases::TVec3; 4 | 5 | /// The normal vector of the given triangle. 6 | /// 7 | /// The normal is computed as the normalized vector `cross(p2 - p1, p3 - p1)`. 8 | pub fn triangle_normal(p1: &TVec3, p2: &TVec3, p3: &TVec3) -> TVec3 { 9 | (p2 - p1).cross(&(p3 - p1)).normalize() 10 | } 11 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/normalize_dot.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | 3 | use crate::aliases::TVec; 4 | 5 | /// The dot product of the normalized version of `x` and `y`. 6 | /// 7 | /// This is currently the same as [`normalize_dot()`] 8 | /// 9 | /// # See also: 10 | /// 11 | /// * [`normalize_dot()`] 12 | pub fn fast_normalize_dot(x: &TVec, y: &TVec) -> T { 13 | // XXX: improve those. 14 | x.normalize().dot(&y.normalize()) 15 | } 16 | 17 | /// The dot product of the normalized version of `x` and `y`. 18 | /// 19 | /// # See also: 20 | /// 21 | /// * [`fast_normalize_dot()`] 22 | pub fn normalize_dot(x: &TVec, y: &TVec) -> T { 23 | // XXX: improve those. 24 | x.normalize().dot(&y.normalize()) 25 | } 26 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/rotate_normalized_axis.rs: -------------------------------------------------------------------------------- 1 | use na::{Rotation3, Unit, UnitQuaternion}; 2 | 3 | use crate::aliases::{Qua, TMat4, TVec3}; 4 | use crate::RealNumber; 5 | 6 | /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. 7 | /// 8 | /// # Parameters: 9 | /// 10 | /// * `m` - Input matrix multiplied by this rotation matrix. 11 | /// * `angle` - Rotation angle expressed in radians. 12 | /// * `axis` - Rotation axis, must be normalized. 13 | pub fn rotate_normalized_axis(m: &TMat4, angle: T, axis: &TVec3) -> TMat4 { 14 | m * Rotation3::from_axis_angle(&Unit::new_unchecked(*axis), angle).to_homogeneous() 15 | } 16 | 17 | /// Rotates a quaternion from a vector of 3 components normalized axis and an angle. 18 | /// 19 | /// # Parameters: 20 | /// 21 | /// * `q` - Source orientation. 22 | /// * `angle` - Angle expressed in radians. 23 | /// * `axis` - Normalized axis of the rotation, must be normalized. 24 | pub fn quat_rotate_normalized_axis(q: &Qua, angle: T, axis: &TVec3) -> Qua { 25 | q * UnitQuaternion::from_axis_angle(&Unit::new_unchecked(*axis), angle).into_inner() 26 | } 27 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/transform.rs: -------------------------------------------------------------------------------- 1 | use na::{Rotation2, Rotation3, Unit}; 2 | 3 | use crate::aliases::{TMat3, TMat4, TVec2, TVec3}; 4 | use crate::traits::{Number, RealNumber}; 5 | 6 | /// A rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. 7 | /// 8 | /// # See also: 9 | /// 10 | /// * [`scaling()`] 11 | /// * [`translation()`] 12 | /// * [`rotation2d()`] 13 | /// * [`scaling2d()`] 14 | /// * [`translation2d()`] 15 | pub fn rotation(angle: T, v: &TVec3) -> TMat4 { 16 | Rotation3::from_axis_angle(&Unit::new_normalize(*v), angle).to_homogeneous() 17 | } 18 | 19 | /// A 4 * 4 scale matrix created from a vector of 3 components. 20 | /// 21 | /// # See also: 22 | /// 23 | /// * [`rotation()`] 24 | /// * [`translation()`] 25 | /// * [`rotation2d()`] 26 | /// * [`scaling2d()`] 27 | /// * [`translation2d()`] 28 | pub fn scaling(v: &TVec3) -> TMat4 { 29 | TMat4::new_nonuniform_scaling(v) 30 | } 31 | 32 | /// A 4 * 4 translation matrix created from the scaling factor on each axis. 33 | /// 34 | /// # See also: 35 | /// 36 | /// * [`rotation()`] 37 | /// * [`scaling()`] 38 | /// * [`rotation2d()`] 39 | /// * [`scaling2d()`] 40 | /// * [`translation2d()`] 41 | pub fn translation(v: &TVec3) -> TMat4 { 42 | TMat4::new_translation(v) 43 | } 44 | 45 | /// A rotation 3 * 3 matrix created from an angle expressed in radians. 46 | /// 47 | /// # See also: 48 | /// 49 | /// * [`rotation()`] 50 | /// * [`scaling()`] 51 | /// * [`translation()`] 52 | /// * [`scaling2d()`] 53 | /// * [`translation2d()`] 54 | pub fn rotation2d(angle: T) -> TMat3 { 55 | Rotation2::new(angle).to_homogeneous() 56 | } 57 | 58 | /// A 3 * 3 scale matrix created from a vector of 2 components. 59 | /// 60 | /// # See also: 61 | /// 62 | /// * [`rotation()`] 63 | /// * [`scaling()`] 64 | /// * [`translation()`] 65 | /// * [`rotation2d()`] 66 | /// * [`translation2d()`] 67 | pub fn scaling2d(v: &TVec2) -> TMat3 { 68 | TMat3::new_nonuniform_scaling(v) 69 | } 70 | 71 | /// A 3 * 3 translation matrix created from the scaling factor on each axis. 72 | /// 73 | /// # See also: 74 | /// 75 | /// * [`rotation()`] 76 | /// * [`scaling()`] 77 | /// * [`translation()`] 78 | /// * [`rotation2d()`] 79 | /// * [`scaling2d()`] 80 | pub fn translation2d(v: &TVec2) -> TMat3 { 81 | TMat3::new_translation(v) 82 | } 83 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/transform2d.rs: -------------------------------------------------------------------------------- 1 | use na::UnitComplex; 2 | 3 | use crate::aliases::{TMat3, TVec2}; 4 | use crate::traits::{Number, RealNumber}; 5 | 6 | /// Builds a 2D rotation matrix from an angle and right-multiply it to `m`. 7 | /// 8 | /// # See also: 9 | /// 10 | /// * [`rotation2d()`](crate::rotation2d) 11 | /// * [`scale2d()`] 12 | /// * [`scaling2d()`](crate::scaling2d) 13 | /// * [`translate2d()`] 14 | /// * [`translation2d()`](crate::translation2d) 15 | pub fn rotate2d(m: &TMat3, angle: T) -> TMat3 { 16 | m * UnitComplex::new(angle).to_homogeneous() 17 | } 18 | 19 | /// Builds a 2D scaling matrix and right-multiply it to `m`. 20 | /// 21 | /// # See also: 22 | /// 23 | /// * [`rotate2d()`] 24 | /// * [`rotation2d()`](crate::rotation2d) 25 | /// * [`scaling2d()`](crate::scaling2d) 26 | /// * [`translate2d()`] 27 | /// * [`translation2d()`](crate::translation2d) 28 | pub fn scale2d(m: &TMat3, v: &TVec2) -> TMat3 { 29 | m.prepend_nonuniform_scaling(v) 30 | } 31 | 32 | /// Builds a translation matrix and right-multiply it to `m`. 33 | /// 34 | /// # See also: 35 | /// 36 | /// * [`rotate2d()`] 37 | /// * [`rotation2d()`](crate::rotation2d) 38 | /// * [`scale2d()`] 39 | /// * [`scaling2d()`](crate::scaling2d) 40 | /// * [`translation2d()`](crate::translation2d) 41 | pub fn translate2d(m: &TMat3, v: &TVec2) -> TMat3 { 42 | m.prepend_translation(v) 43 | } 44 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/vector_angle.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | 3 | use crate::aliases::TVec; 4 | 5 | /// The angle between two vectors. 6 | pub fn angle(x: &TVec, y: &TVec) -> T { 7 | x.angle(y) 8 | } 9 | 10 | //pub fn oriented_angle(x: &TVec2, y: &TVec2) -> T { 11 | // unimplemented!() 12 | //} 13 | // 14 | //pub fn oriented_angle_ref(x: &TVec3, y: &TVec3, refv: &TVec3) -> T { 15 | // unimplemented!() 16 | //} 17 | -------------------------------------------------------------------------------- /nalgebra-glm/src/gtx/vector_query.rs: -------------------------------------------------------------------------------- 1 | use crate::RealNumber; 2 | 3 | use crate::aliases::{TVec, TVec2, TVec3}; 4 | use crate::traits::Number; 5 | 6 | /// Returns `true` if two vectors are collinear (up to an epsilon). 7 | /// 8 | /// # See also: 9 | /// 10 | /// * [`are_collinear2d()`] 11 | pub fn are_collinear(v0: &TVec3, v1: &TVec3, epsilon: T) -> bool { 12 | abs_diff_eq!(v0.cross(v1), TVec3::::zeros(), epsilon = epsilon) 13 | } 14 | 15 | /// Returns `true` if two 2D vectors are collinear (up to an epsilon). 16 | /// 17 | /// # See also: 18 | /// 19 | /// * [`are_collinear()`] 20 | pub fn are_collinear2d(v0: &TVec2, v1: &TVec2, epsilon: T) -> bool { 21 | abs_diff_eq!(v0.perp(v1), T::zero(), epsilon = epsilon) 22 | } 23 | 24 | /// Returns `true` if two vectors are orthogonal (up to an epsilon). 25 | pub fn are_orthogonal( 26 | v0: &TVec, 27 | v1: &TVec, 28 | epsilon: T, 29 | ) -> bool { 30 | abs_diff_eq!(v0.dot(v1), T::zero(), epsilon = epsilon) 31 | } 32 | 33 | //pub fn are_orthonormal(v0: &TVec, v1: &TVec, epsilon: T) -> bool { 34 | // unimplemented!() 35 | //} 36 | 37 | /// Returns `true` if all the components of `v` are zero (up to an epsilon). 38 | pub fn is_comp_null(v: &TVec, epsilon: T) -> TVec { 39 | v.map(|x| abs_diff_eq!(x, T::zero(), epsilon = epsilon)) 40 | } 41 | 42 | /// Returns `true` if `v` has a magnitude of 1 (up to an epsilon). 43 | pub fn is_normalized(v: &TVec, epsilon: T) -> bool { 44 | // sqrt(1 + epsilon_{norm²} = 1 + epsilon_{norm} 45 | // ==> epsilon_{norm²} = epsilon_{norm}² + 2*epsilon_{norm} 46 | // For small epsilon, epsilon² is basically zero, so use 2*epsilon. 47 | abs_diff_eq!(v.norm_squared(), T::one(), epsilon = epsilon + epsilon) 48 | } 49 | 50 | /// Returns `true` if `v` is zero (up to an epsilon). 51 | pub fn is_null(v: &TVec, epsilon: T) -> bool { 52 | abs_diff_eq!(v.norm_squared(), T::zero(), epsilon = epsilon * epsilon) 53 | } 54 | -------------------------------------------------------------------------------- /nalgebra-glm/src/matrix.rs: -------------------------------------------------------------------------------- 1 | use na::{Const, DimMin, Scalar}; 2 | 3 | use crate::aliases::{TMat, TVec}; 4 | use crate::traits::{Number, RealNumber}; 5 | 6 | /// The determinant of the matrix `m`. 7 | pub fn determinant(m: &TMat) -> T 8 | where 9 | Const: DimMin, Output = Const>, 10 | { 11 | m.determinant() 12 | } 13 | 14 | /// The inverse of the matrix `m`. 15 | pub fn inverse(m: &TMat) -> TMat { 16 | m.clone() 17 | .try_inverse() 18 | .unwrap_or_else(TMat::::zeros) 19 | } 20 | 21 | /// Component-wise multiplication of two matrices. 22 | pub fn matrix_comp_mult( 23 | x: &TMat, 24 | y: &TMat, 25 | ) -> TMat { 26 | x.component_mul(y) 27 | } 28 | 29 | /// Treats the first parameter `c` as a column vector and the second parameter `r` as a row vector and does a linear algebraic matrix multiply `c * r`. 30 | pub fn outer_product( 31 | c: &TVec, 32 | r: &TVec, 33 | ) -> TMat { 34 | c * r.transpose() 35 | } 36 | 37 | /// The transpose of the matrix `m`. 38 | pub fn transpose(x: &TMat) -> TMat { 39 | x.transpose() 40 | } 41 | -------------------------------------------------------------------------------- /nalgebra-glm/src/packing.rs: -------------------------------------------------------------------------------- 1 | use na::Scalar; 2 | 3 | use crate::aliases::{UVec2, Vec2, Vec4}; 4 | 5 | pub fn packDouble2x32(v: &UVec2) -> f64 { 6 | unimplemented!() 7 | } 8 | 9 | pub fn packHalf2x16(v: &Vec2) -> u32 { 10 | unimplemented!() 11 | } 12 | 13 | pub fn packSnorm2x16(v: &Vec2) -> u32 { 14 | unimplemented!() 15 | } 16 | 17 | pub fn packSnorm4x8(v: &Vec4) -> u32 { 18 | unimplemented!() 19 | } 20 | 21 | pub fn packUnorm2x16(v: &Vec2) -> u32 { 22 | unimplemented!() 23 | } 24 | 25 | pub fn packUnorm4x8(v: &Vec4) -> u32 { 26 | unimplemented!() 27 | } 28 | 29 | pub fn unpackDouble2x32(v: f64) -> UVec2 { 30 | unimplemented!() 31 | } 32 | 33 | pub fn unpackHalf2x16(v: u32) -> Vec2 { 34 | unimplemented!() 35 | } 36 | 37 | pub fn unpackSnorm2x16(p: u32) -> Vec2 { 38 | unimplemented!() 39 | } 40 | 41 | pub fn unpackSnorm4x8(p: u32) -> Vec4 { 42 | unimplemented!() 43 | } 44 | 45 | pub fn unpackUnorm2x16(p: u32) -> Vec2 { 46 | unimplemented!() 47 | } 48 | 49 | pub fn unpackUnorm4x8(p: u32) -> Vec4 { 50 | unimplemented!() 51 | } 52 | -------------------------------------------------------------------------------- /nalgebra-glm/src/traits.rs: -------------------------------------------------------------------------------- 1 | use approx::AbsDiffEq; 2 | use num::{Bounded, Signed}; 3 | 4 | use na::Scalar; 5 | use simba::scalar::{ClosedAddAssign, ClosedMulAssign, ClosedSubAssign, RealField}; 6 | 7 | /// A number that can either be an integer or a float. 8 | pub trait Number: 9 | Scalar 10 | + Copy 11 | + PartialOrd 12 | + ClosedAddAssign 13 | + ClosedSubAssign 14 | + ClosedMulAssign 15 | + AbsDiffEq 16 | + Signed 17 | + Bounded 18 | { 19 | } 20 | 21 | impl< 22 | T: Scalar 23 | + Copy 24 | + PartialOrd 25 | + ClosedAddAssign 26 | + ClosedSubAssign 27 | + ClosedMulAssign 28 | + AbsDiffEq 29 | + Signed 30 | + Bounded, 31 | > Number for T 32 | { 33 | } 34 | 35 | /// A number that can be any float type. 36 | pub trait RealNumber: Number + RealField {} 37 | 38 | impl RealNumber for T {} 39 | -------------------------------------------------------------------------------- /nalgebra-glm/tests/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate nalgebra as na; 2 | extern crate nalgebra_glm as glm; 3 | 4 | use glm::Mat4; 5 | use glm::Vec4; 6 | use na::Orthographic3; 7 | use na::Perspective3; 8 | 9 | #[test] 10 | pub fn orthographic_glm_nalgebra_same() { 11 | let na_mat: Mat4 = 12 | Orthographic3::new(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner(); 13 | let gl_mat: Mat4 = glm::ortho(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32); 14 | 15 | assert_eq!(na_mat, gl_mat); 16 | } 17 | 18 | #[test] 19 | pub fn perspective_glm_nalgebra_same() { 20 | let na_mat: Mat4 = 21 | Perspective3::new(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32).into_inner(); 22 | let gl_mat: Mat4 = glm::perspective(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32); 23 | 24 | assert_eq!(na_mat, gl_mat); 25 | } 26 | 27 | #[test] 28 | pub fn orthographic_glm_nalgebra_project_same() { 29 | let point = Vec4::new(1.0, 0.0, -20.0, 1.0); 30 | 31 | let na_mat: Mat4 = 32 | Orthographic3::new(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32).into_inner(); 33 | let gl_mat: Mat4 = glm::ortho(-100.0f32, 100.0f32, -50.0f32, 50.0f32, 0.1f32, 100.0f32); 34 | 35 | let na_pt = na_mat * point; 36 | let gl_pt = gl_mat * point; 37 | 38 | assert_eq!(na_mat, gl_mat); 39 | assert_eq!(na_pt, gl_pt); 40 | } 41 | 42 | #[test] 43 | pub fn perspective_glm_nalgebra_project_same() { 44 | let point = Vec4::new(1.0, 0.0, -20.0, 1.0); 45 | 46 | let na_mat: Mat4 = 47 | Perspective3::new(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32).into_inner(); 48 | let gl_mat: Mat4 = glm::perspective(16.0f32 / 9.0f32, 3.14f32 / 2.0f32, 0.1f32, 100.0f32); 49 | 50 | let na_pt = na_mat * point; 51 | let gl_pt = gl_mat * point; 52 | 53 | assert_eq!(na_mat, gl_mat); 54 | assert_eq!(na_pt, gl_pt); 55 | } 56 | -------------------------------------------------------------------------------- /nalgebra-lapack/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [0.4.0] - 2016-09-07 4 | 5 | * Made all traits use associated types for their output type parameters. This 6 | simplifies usage of the traits and is consistent with the concept of 7 | associated types used as output type parameters (not input type parameters) as 8 | described in [the associated type 9 | RFC](https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md). 10 | * Implemented `check_info!` macro to check all LAPACK calls. 11 | * Implemented error handling with [error_chain](https://crates.io/crates/error-chain). 12 | 13 | ## [0.3.0] - 2016-09-06 14 | 15 | * Documentation is hosted at https://docs.rs/nalgebra-lapack/ 16 | * Updated `nalgebra` to 0.10. 17 | * Rename traits `HasSVD` to `SVD` and `HasEigensystem` to `Eigensystem`. 18 | * Added `Solve` trait for solving a linear matrix equation. 19 | * Added `Inverse` for computing the multiplicative inverse of a matrix. 20 | * Added `Cholesky` for decomposing a positive-definite matrix. 21 | * The `Eigensystem` and `SVD` traits are now generic over types. The 22 | associated types have been removed. 23 | -------------------------------------------------------------------------------- /nalgebra-lapack/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nalgebra-lapack" 3 | version = "0.25.0" 4 | authors = ["Sébastien Crozet ", "Andrew Straw "] 5 | 6 | description = "Matrix decompositions using nalgebra matrices and Lapack bindings." 7 | documentation = "https://www.nalgebra.org/docs" 8 | homepage = "https://nalgebra.org" 9 | repository = "https://github.com/dimforge/nalgebra" 10 | readme = "../README.md" 11 | categories = ["science", "mathematics"] 12 | keywords = ["linear", "algebra", "matrix", "vector", "lapack"] 13 | license = "MIT" 14 | edition = "2018" 15 | 16 | [badges] 17 | maintenance = { status = "actively-developed" } 18 | 19 | [features] 20 | serde-serialize = ["serde", "nalgebra/serde-serialize"] 21 | proptest-support = ["nalgebra/proptest-support"] 22 | arbitrary = ["nalgebra/arbitrary"] 23 | 24 | # For BLAS/LAPACK 25 | default = ["netlib"] 26 | openblas = ["lapack-src/openblas"] 27 | netlib = ["lapack-src/netlib"] 28 | accelerate = ["lapack-src/accelerate"] 29 | intel-mkl = ["lapack-src/intel-mkl"] 30 | 31 | [dependencies] 32 | nalgebra = { version = "0.33", path = ".." } 33 | num-traits = "0.2" 34 | num-complex = { version = "0.4", default-features = false } 35 | simba = "0.9" 36 | serde = { version = "1.0", features = ["derive"], optional = true } 37 | lapack = { version = "0.19", default-features = false } 38 | lapack-src = { version = "0.8", default-features = false } 39 | # clippy = "*" 40 | 41 | [dev-dependencies] 42 | nalgebra = { version = "0.33", features = ["arbitrary", "rand"], path = ".." } 43 | proptest = { version = "1", default-features = false, features = ["std"] } 44 | quickcheck = "1" 45 | approx = "0.5" 46 | rand = "0.8" 47 | 48 | -------------------------------------------------------------------------------- /nalgebra-lapack/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Andrew D. Straw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /nalgebra-lapack/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cargo build 3 | 4 | test: 5 | cargo test 6 | 7 | doc: 8 | cargo doc --all --no-deps 9 | 10 | bench: 11 | cargo bench 12 | -------------------------------------------------------------------------------- /nalgebra-lapack/benches/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate nalgebra as na; 4 | extern crate nalgebra_lapack as nl; 5 | extern crate rand; 6 | extern crate test; 7 | 8 | mod linalg; 9 | -------------------------------------------------------------------------------- /nalgebra-lapack/benches/linalg/hessenberg.rs: -------------------------------------------------------------------------------- 1 | use na::{DMatrix, Matrix4}; 2 | use nl::Hessenberg; 3 | use test::{self, Bencher}; 4 | 5 | #[bench] 6 | fn hessenberg_decompose_100x100(bh: &mut Bencher) { 7 | let m = DMatrix::::new_random(100, 100); 8 | bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) 9 | } 10 | 11 | #[bench] 12 | fn hessenberg_decompose_4x4(bh: &mut Bencher) { 13 | let m = Matrix4::::new_random(); 14 | bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) 15 | } 16 | 17 | #[bench] 18 | fn hessenberg_decompose_500x500(bh: &mut Bencher) { 19 | let m = DMatrix::::new_random(500, 500); 20 | bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) 21 | } 22 | -------------------------------------------------------------------------------- /nalgebra-lapack/benches/linalg/lu.rs: -------------------------------------------------------------------------------- 1 | use na::{DMatrix, Matrix4}; 2 | use nl::LU; 3 | use test::{self, Bencher}; 4 | 5 | #[bench] 6 | fn lu_decompose_100x100(bh: &mut Bencher) { 7 | let m = DMatrix::::new_random(100, 100); 8 | bh.iter(|| std::hint::black_box(LU::new(m.clone()))) 9 | } 10 | 11 | #[bench] 12 | fn lu_decompose_100x500(bh: &mut Bencher) { 13 | let m = DMatrix::::new_random(100, 500); 14 | bh.iter(|| std::hint::black_box(LU::new(m.clone()))) 15 | } 16 | 17 | #[bench] 18 | fn lu_decompose_4x4(bh: &mut Bencher) { 19 | let m = Matrix4::::new_random(); 20 | bh.iter(|| std::hint::black_box(LU::new(m.clone()))) 21 | } 22 | 23 | #[bench] 24 | fn lu_decompose_500x100(bh: &mut Bencher) { 25 | let m = DMatrix::::new_random(500, 100); 26 | bh.iter(|| std::hint::black_box(LU::new(m.clone()))) 27 | } 28 | 29 | #[bench] 30 | fn lu_decompose_500x500(bh: &mut Bencher) { 31 | let m = DMatrix::::new_random(500, 500); 32 | bh.iter(|| std::hint::black_box(LU::new(m.clone()))) 33 | } 34 | -------------------------------------------------------------------------------- /nalgebra-lapack/benches/linalg/mod.rs: -------------------------------------------------------------------------------- 1 | mod hessenberg; 2 | mod lu; 3 | mod qr; 4 | -------------------------------------------------------------------------------- /nalgebra-lapack/benches/linalg/qr.rs: -------------------------------------------------------------------------------- 1 | use na::{DMatrix, Matrix4}; 2 | use nl::QR; 3 | use test::{self, Bencher}; 4 | 5 | #[bench] 6 | fn qr_decompose_100x100(bh: &mut Bencher) { 7 | let m = DMatrix::::new_random(100, 100); 8 | bh.iter(|| std::hint::black_box(QR::new(m.clone()))) 9 | } 10 | 11 | #[bench] 12 | fn qr_decompose_100x500(bh: &mut Bencher) { 13 | let m = DMatrix::::new_random(100, 500); 14 | bh.iter(|| std::hint::black_box(QR::new(m.clone()))) 15 | } 16 | 17 | #[bench] 18 | fn qr_decompose_4x4(bh: &mut Bencher) { 19 | let m = Matrix4::::new_random(); 20 | bh.iter(|| std::hint::black_box(QR::new(m.clone()))) 21 | } 22 | 23 | #[bench] 24 | fn qr_decompose_500x100(bh: &mut Bencher) { 25 | let m = DMatrix::::new_random(500, 100); 26 | bh.iter(|| std::hint::black_box(QR::new(m.clone()))) 27 | } 28 | 29 | #[bench] 30 | fn qr_decompose_500x500(bh: &mut Bencher) { 31 | let m = DMatrix::::new_random(500, 500); 32 | bh.iter(|| std::hint::black_box(QR::new(m.clone()))) 33 | } 34 | -------------------------------------------------------------------------------- /nalgebra-lapack/src/lapack_check.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | 3 | macro_rules! lapack_check( 4 | ($info: expr) => ( 5 | // TODO: return a richer error. 6 | if $info != 0 { 7 | return None; 8 | } 9 | // if $info < 0 { 10 | // return Err(Error::from(ErrorKind::LapackIllegalArgument(-$info))); 11 | // } else if $info > 0 { 12 | // return Err(Error::from(ErrorKind::LapackFailure($info))); 13 | // } 14 | ); 15 | ); 16 | 17 | macro_rules! lapack_panic( 18 | ($info: expr) => ( 19 | assert!($info == 0, "Lapack error."); 20 | ); 21 | ); 22 | 23 | macro_rules! lapack_test( 24 | ($info: expr) => ( 25 | $info == 0 26 | ); 27 | ); 28 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate approx; 3 | #[cfg(not(feature = "proptest-support"))] 4 | compile_error!("Tests must be run with `proptest-support`"); 5 | 6 | extern crate nalgebra as na; 7 | extern crate nalgebra_lapack as nl; 8 | 9 | mod linalg; 10 | #[path = "../../tests/proptest/mod.rs"] 11 | mod proptest; 12 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/complex_eigen.rs: -------------------------------------------------------------------------------- 1 | use na::Matrix3; 2 | use nalgebra_lapack::Eigen; 3 | use num_complex::Complex; 4 | 5 | #[test] 6 | fn complex_eigen() { 7 | let m = Matrix3::::new( 8 | 4.0 / 5.0, 9 | -3.0 / 5.0, 10 | 0.0, 11 | 3.0 / 5.0, 12 | 4.0 / 5.0, 13 | 0.0, 14 | 1.0, 15 | 2.0, 16 | 2.0, 17 | ); 18 | let eigen = Eigen::new(m, true, true).expect("Eigen Creation Failed!"); 19 | let (some_eigenvalues, some_left_vec, some_right_vec) = eigen.get_complex_elements(); 20 | let eigenvalues = some_eigenvalues.expect("Eigenvalues Failed"); 21 | let _left_eigenvectors = some_left_vec.expect("Left Eigenvectors Failed"); 22 | let eigenvectors = some_right_vec.expect("Right Eigenvectors Failed"); 23 | 24 | assert_relative_eq!( 25 | eigenvalues[0].re, 26 | Complex::::new(4.0 / 5.0, 3.0 / 5.0).re 27 | ); 28 | assert_relative_eq!( 29 | eigenvalues[0].im, 30 | Complex::::new(4.0 / 5.0, 3.0 / 5.0).im 31 | ); 32 | assert_relative_eq!( 33 | eigenvalues[1].re, 34 | Complex::::new(4.0 / 5.0, -3.0 / 5.0).re 35 | ); 36 | assert_relative_eq!( 37 | eigenvalues[1].im, 38 | Complex::::new(4.0 / 5.0, -3.0 / 5.0).im 39 | ); 40 | 41 | assert_relative_eq!(eigenvectors[0][0].re, -12.0 / 32.7871926215100059134410999); 42 | assert_relative_eq!(eigenvectors[0][0].im, -9.0 / 32.7871926215100059134410999); 43 | assert_relative_eq!(eigenvectors[0][1].re, -9.0 / 32.7871926215100059134410999); 44 | assert_relative_eq!(eigenvectors[0][1].im, 12.0 / 32.7871926215100059134410999); 45 | assert_relative_eq!(eigenvectors[0][2].re, 25.0 / 32.7871926215100059134410999); 46 | assert_relative_eq!(eigenvectors[0][2].im, 0.0); 47 | } 48 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/hessenberg.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | 3 | use na::{DMatrix, Matrix4}; 4 | use nl::Hessenberg; 5 | 6 | use crate::proptest::*; 7 | use proptest::{prop_assert, proptest}; 8 | 9 | proptest! { 10 | #[test] 11 | fn hessenberg(n in PROPTEST_MATRIX_DIM) { 12 | let n = cmp::min(n, 25); 13 | let m = DMatrix::::new_random(n, n); 14 | 15 | if let Some(hess) = Hessenberg::new(m.clone()) { 16 | let h = hess.h(); 17 | let p = hess.p(); 18 | 19 | prop_assert!(relative_eq!(m, &p * h * p.transpose(), epsilon = 1.0e-7)) 20 | } 21 | } 22 | 23 | #[test] 24 | fn hessenberg_static(m in matrix4()) { 25 | if let Some(hess) = Hessenberg::new(m) { 26 | let h = hess.h(); 27 | let p = hess.p(); 28 | 29 | prop_assert!(relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7)) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/mod.rs: -------------------------------------------------------------------------------- 1 | mod cholesky; 2 | mod complex_eigen; 3 | mod generalized_eigenvalues; 4 | mod lu; 5 | mod qr; 6 | mod qz; 7 | mod real_eigensystem; 8 | mod schur; 9 | mod svd; 10 | mod symmetric_eigen; 11 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/qr.rs: -------------------------------------------------------------------------------- 1 | use nl::QR; 2 | 3 | use crate::proptest::*; 4 | use proptest::{prop_assert, proptest}; 5 | 6 | proptest! { 7 | #[test] 8 | fn qr(m in dmatrix()) { 9 | let qr = QR::new(m.clone()); 10 | let q = qr.q(); 11 | let r = qr.r(); 12 | 13 | prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7)) 14 | } 15 | 16 | #[test] 17 | fn qr_static(m in matrix5x3()) { 18 | let qr = QR::new(m); 19 | let q = qr.q(); 20 | let r = qr.r(); 21 | 22 | prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/qz.rs: -------------------------------------------------------------------------------- 1 | use na::DMatrix; 2 | use nl::QZ; 3 | 4 | use crate::proptest::*; 5 | use proptest::{prop_assert, prop_compose, proptest}; 6 | 7 | prop_compose! { 8 | fn f64_dynamic_dim_squares() 9 | (n in PROPTEST_MATRIX_DIM) 10 | (a in matrix(PROPTEST_F64,n,n), b in matrix(PROPTEST_F64,n,n)) -> (DMatrix, DMatrix){ 11 | (a,b) 12 | }} 13 | 14 | proptest! { 15 | #[test] 16 | fn qz((a,b) in f64_dynamic_dim_squares()) { 17 | 18 | let qz = QZ::new(a.clone(), b.clone()); 19 | let (vsl,s,t,vsr) = qz.clone().unpack(); 20 | 21 | prop_assert!(relative_eq!(&vsl * s * vsr.transpose(), a, epsilon = 1.0e-7)); 22 | prop_assert!(relative_eq!(vsl * t * vsr.transpose(), b, epsilon = 1.0e-7)); 23 | 24 | } 25 | 26 | #[test] 27 | fn qz_static(a in matrix4(), b in matrix4()) { 28 | let qz = QZ::new(a.clone(), b.clone()); 29 | let (vsl,s,t,vsr) = qz.unpack(); 30 | 31 | prop_assert!(relative_eq!(&vsl * s * vsr.transpose(), a, epsilon = 1.0e-7)); 32 | prop_assert!(relative_eq!(vsl * t * vsr.transpose(), b, epsilon = 1.0e-7)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/real_eigensystem.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | 3 | use na::{DMatrix, Matrix4}; 4 | use nl::Eigen; 5 | 6 | use crate::proptest::*; 7 | use proptest::{prop_assert, proptest}; 8 | 9 | proptest! { 10 | #[test] 11 | fn eigensystem(n in PROPTEST_MATRIX_DIM) { 12 | let n = cmp::min(n, 25); 13 | let m = DMatrix::::new_random(n, n); 14 | 15 | if let Some(eig) = Eigen::new(m.clone(), true, true) { 16 | // TODO: test the complex case too. 17 | if eig.eigenvalues_are_real() { 18 | let eigvals = DMatrix::from_diagonal(&eig.eigenvalues_re); 19 | let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap(); 20 | let scaled_eigvectors = eig.eigenvectors.as_ref().unwrap() * &eigvals; 21 | 22 | let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.as_ref().unwrap(); 23 | let scaled_left_eigvectors = eig.left_eigenvectors.as_ref().unwrap() * &eigvals; 24 | 25 | prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-5)); 26 | prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-5)); 27 | } 28 | } 29 | } 30 | 31 | #[test] 32 | fn eigensystem_static(m in matrix4()) { 33 | if let Some(eig) = Eigen::new(m, true, true) { 34 | // TODO: test the complex case too. 35 | if eig.eigenvalues_are_real() { 36 | let eigvals = Matrix4::from_diagonal(&eig.eigenvalues_re); 37 | let transformed_eigvectors = m * eig.eigenvectors.unwrap(); 38 | let scaled_eigvectors = eig.eigenvectors.unwrap() * eigvals; 39 | 40 | let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.unwrap(); 41 | let scaled_left_eigvectors = eig.left_eigenvectors.unwrap() * eigvals; 42 | 43 | prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-5)); 44 | prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-5)); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/schur.rs: -------------------------------------------------------------------------------- 1 | use na::DMatrix; 2 | use nl::Schur; 3 | use std::cmp; 4 | 5 | use crate::proptest::*; 6 | use proptest::{prop_assert, proptest}; 7 | 8 | proptest! { 9 | #[test] 10 | fn schur(n in PROPTEST_MATRIX_DIM) { 11 | let n = cmp::max(1, cmp::min(n, 10)); 12 | let m = DMatrix::::new_random(n, n); 13 | 14 | if let Some(schur) = Schur::try_new(m.clone()) { 15 | let (vecs, vals) = schur.unpack(); 16 | prop_assert!(relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-5)) 17 | } 18 | } 19 | 20 | #[test] 21 | fn schur_static(m in matrix4()) { 22 | if let Some(schur) = Schur::try_new(m.clone()) { 23 | let (vecs, vals) = schur.unpack(); 24 | prop_assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-5)) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/svd.rs: -------------------------------------------------------------------------------- 1 | use na::{DMatrix, Matrix3x5}; 2 | use nl::SVD; 3 | 4 | use crate::proptest::*; 5 | use proptest::{prop_assert, proptest}; 6 | 7 | proptest! { 8 | #[test] 9 | fn svd(m in dmatrix()) { 10 | let svd = SVD::new(m.clone()).unwrap(); 11 | let sm = DMatrix::from_partial_diagonal(m.nrows(), m.ncols(), svd.singular_values.as_slice()); 12 | 13 | let reconstructed_m = &svd.u * sm * &svd.vt; 14 | let reconstructed_m2 = svd.recompose(); 15 | 16 | prop_assert!(relative_eq!(reconstructed_m, m, epsilon = 1.0e-7)); 17 | prop_assert!(relative_eq!(reconstructed_m2, reconstructed_m, epsilon = 1.0e-7)); 18 | } 19 | 20 | #[test] 21 | fn svd_static(m in matrix3x5()) { 22 | let svd = SVD::new(m).unwrap(); 23 | let sm = Matrix3x5::from_partial_diagonal(svd.singular_values.as_slice()); 24 | 25 | let reconstructed_m = &svd.u * &sm * &svd.vt; 26 | let reconstructed_m2 = svd.recompose(); 27 | 28 | prop_assert!(relative_eq!(reconstructed_m, m, epsilon = 1.0e-7)); 29 | prop_assert!(relative_eq!(reconstructed_m2, m, epsilon = 1.0e-7)); 30 | } 31 | 32 | #[test] 33 | fn pseudo_inverse(m in dmatrix()) { 34 | let svd = SVD::new(m.clone()).unwrap(); 35 | let im = svd.pseudo_inverse(1.0e-7); 36 | 37 | if m.nrows() <= m.ncols() { 38 | prop_assert!((&m * &im).is_identity(1.0e-7)); 39 | } 40 | 41 | if m.nrows() >= m.ncols() { 42 | prop_assert!((im * m).is_identity(1.0e-7)); 43 | } 44 | } 45 | 46 | #[test] 47 | fn pseudo_inverse_static(m in matrix3x5()) { 48 | let svd = SVD::new(m).unwrap(); 49 | let im = svd.pseudo_inverse(1.0e-7); 50 | 51 | prop_assert!((m * im).is_identity(1.0e-7)) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /nalgebra-lapack/tests/linalg/symmetric_eigen.rs: -------------------------------------------------------------------------------- 1 | use std::cmp; 2 | 3 | use na::DMatrix; 4 | use nl::SymmetricEigen; 5 | 6 | use crate::proptest::*; 7 | use proptest::{prop_assert, proptest}; 8 | 9 | proptest! { 10 | #[test] 11 | fn symmetric_eigen(n in PROPTEST_MATRIX_DIM) { 12 | let n = cmp::max(1, cmp::min(n, 10)); 13 | let m = DMatrix::::new_random(n, n); 14 | let eig = SymmetricEigen::new(m.clone()); 15 | let recomp = eig.recompose(); 16 | prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)) 17 | } 18 | 19 | #[test] 20 | fn symmetric_eigen_static(m in matrix4()) { 21 | let eig = SymmetricEigen::new(m); 22 | let recomp = eig.recompose(); 23 | prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nalgebra-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nalgebra-macros" 3 | version = "0.2.2" 4 | authors = ["Andreas Longva", "Sébastien Crozet "] 5 | edition = "2018" 6 | description = "Procedural macros for nalgebra" 7 | documentation = "https://www.nalgebra.org/docs" 8 | homepage = "https://nalgebra.org" 9 | repository = "https://github.com/dimforge/nalgebra" 10 | readme = "../README.md" 11 | categories = ["science", "mathematics"] 12 | keywords = ["linear", "algebra", "matrix", "vector", "math"] 13 | license = "Apache-2.0" 14 | 15 | [lib] 16 | proc-macro = true 17 | 18 | [dependencies] 19 | syn = { version = "2.0", features = ["full"] } 20 | quote = "1.0" 21 | proc-macro2 = "1.0" 22 | 23 | [dev-dependencies] 24 | nalgebra = { version = "0.33", path = ".." } 25 | -------------------------------------------------------------------------------- /nalgebra-macros/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /nalgebra-sparse/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nalgebra-sparse" 3 | version = "0.10.0" 4 | authors = ["Andreas Longva", "Sébastien Crozet "] 5 | edition = "2018" 6 | description = "Sparse matrix computation based on nalgebra." 7 | documentation = "https://www.nalgebra.org/docs" 8 | homepage = "https://nalgebra.org" 9 | repository = "https://github.com/dimforge/nalgebra" 10 | readme = "../README.md" 11 | categories = ["science", "mathematics", "wasm", "no-std"] 12 | keywords = ["linear", "algebra", "matrix", "vector", "math"] 13 | license = "Apache-2.0" 14 | 15 | [features] 16 | proptest-support = ["proptest", "nalgebra/proptest-support"] 17 | compare = ["matrixcompare-core"] 18 | serde-serialize = ["serde/std"] 19 | 20 | # Enable matrix market I/O 21 | io = ["pest", "pest_derive"] 22 | 23 | # Enable to enable running some tests that take a lot of time to run 24 | slow-tests = [] 25 | 26 | [dependencies] 27 | nalgebra = { version = "0.33", path = "../" } 28 | num-traits = { version = "0.2", default-features = false } 29 | proptest = { version = "1.0", optional = true } 30 | matrixcompare-core = { version = "0.1.0", optional = true } 31 | pest = { version = "2", optional = true } 32 | pest_derive = { version = "2", optional = true } 33 | serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } 34 | 35 | [dev-dependencies] 36 | itertools = "0.13" 37 | matrixcompare = { version = "0.3.0", features = ["proptest-support"] } 38 | nalgebra = { version = "0.33", path = "../", features = ["compare"] } 39 | tempfile = "3.3" 40 | serde_json = "1.0" 41 | 42 | [package.metadata.docs.rs] 43 | # Enable certain features when building docs for docs.rs 44 | features = ["proptest-support", "compare", "io"] 45 | -------------------------------------------------------------------------------- /nalgebra-sparse/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /nalgebra-sparse/src/convert/mod.rs: -------------------------------------------------------------------------------- 1 | //! Routines for converting between sparse matrix formats. 2 | //! 3 | //! Most users should instead use the provided `From` implementations to convert between matrix 4 | //! formats. Note that `From` implementations may not be available between all combinations of 5 | //! sparse matrices. 6 | //! 7 | //! The following example illustrates how to convert between matrix formats with the `From` 8 | //! implementations. 9 | //! 10 | //! ``` 11 | //! use nalgebra_sparse::{csr::CsrMatrix, csc::CscMatrix, coo::CooMatrix}; 12 | //! use nalgebra::DMatrix; 13 | //! 14 | //! // Conversion from dense 15 | //! let dense = DMatrix::::identity(9, 8); 16 | //! let csr = CsrMatrix::from(&dense); 17 | //! let csc = CscMatrix::from(&dense); 18 | //! let coo = CooMatrix::from(&dense); 19 | //! 20 | //! // CSR <-> CSC 21 | //! let _ = CsrMatrix::from(&csc); 22 | //! let _ = CscMatrix::from(&csr); 23 | //! 24 | //! // CSR <-> COO 25 | //! let _ = CooMatrix::from(&csr); 26 | //! let _ = CsrMatrix::from(&coo); 27 | //! 28 | //! // CSC <-> COO 29 | //! let _ = CooMatrix::from(&csc); 30 | //! let _ = CscMatrix::from(&coo); 31 | //! ``` 32 | //! 33 | //! The routines available here are able to provide more specialized APIs, giving 34 | //! more control over the conversion process. The routines are organized by backends. 35 | //! Currently, only the [`serial`] backend is available. 36 | //! In the future, backends that offer parallel routines may become available. 37 | 38 | pub mod serial; 39 | 40 | mod impl_std_ops; 41 | -------------------------------------------------------------------------------- /nalgebra-sparse/src/factorization/mod.rs: -------------------------------------------------------------------------------- 1 | //! Matrix factorization for sparse matrices. 2 | //! 3 | //! Currently, the only factorization provided here is the [`CscCholesky`] factorization. 4 | mod cholesky; 5 | 6 | pub use cholesky::*; 7 | -------------------------------------------------------------------------------- /nalgebra-sparse/src/io/matrix_market.pest: -------------------------------------------------------------------------------- 1 | WHITESPACE = _{ " "|"\t" } 2 | 3 | // 4 | 5 | Sparsity = {^"coordinate" | ^"array"} 6 | DataType = {^"real" | ^"complex" | ^"pattern" | ^"integer" } 7 | StorageScheme = {^"symmetric" | ^"general" | ^"skew-symmetric" | ^"hermitian"} 8 | // Only consider matrices here. 9 | Header = { ^"%%matrixmarket matrix" ~ Sparsity ~ DataType ~ StorageScheme } 10 | 11 | // 12 | 13 | Comments = _{ "%" ~ (!NEWLINE ~ ANY)* } 14 | 15 | // 16 | 17 | Dimension = @{ ASCII_DIGIT+ } 18 | SparseShape = { Dimension ~ Dimension ~ Dimension} 19 | DenseShape = { Dimension ~ Dimension} 20 | Shape = {SparseShape | DenseShape } 21 | 22 | // 23 | 24 | // grammar from https://doc.rust-lang.org/std/primitive.f64.html#grammar 25 | 26 | Sign = {("+" | "-")} 27 | Exp = @{ ^"e" ~ Sign? ~ ASCII_DIGIT+} 28 | Number = @{ ((ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT*) | (ASCII_DIGIT* ~ "." ~ASCII_DIGIT+) | ASCII_DIGIT+ ) ~ Exp? } 29 | Real = @{ Sign? ~ ("inf" | "NaN" | Number) } 30 | 31 | 32 | SparseReal = {Dimension~ Dimension~ Real } 33 | SparseComplex = {Dimension ~ Dimension ~ Real ~ Real} 34 | SparsePattern = {Dimension ~ Dimension} 35 | 36 | DenseReal = {Real} 37 | DenseComplex = {Real ~ Real} 38 | 39 | 40 | Entry = { SparseComplex | SparseReal | SparsePattern | DenseComplex | DenseReal } 41 | 42 | // end of file, a silent way, see https://github.com/pest-parser/pest/issues/304#issuecomment-427198507 43 | eoi = _{ !ANY } 44 | 45 | Document = { 46 | SOI ~ 47 | NEWLINE* ~ 48 | Header ~ 49 | (NEWLINE ~ Comments)* ~ 50 | (NEWLINE ~ Shape) ~ 51 | (NEWLINE ~ Entry?)* ~ 52 | eoi 53 | } -------------------------------------------------------------------------------- /nalgebra-sparse/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Functionality for importing and exporting sparse matrices to and from files. 2 | //! 3 | //! **Available only when the `io` feature is enabled.** 4 | //! 5 | //! The following formats are currently supported: 6 | //! 7 | //! | Format | Import | Export | 8 | //! | ------------------------------------------------|------------|------------| 9 | //! | [Matrix market](#matrix-market-format) | Yes | Yes | 10 | //! 11 | //! [Matrix market]: https://math.nist.gov/MatrixMarket/formats.html 12 | //! 13 | //! ## Matrix Market format 14 | //! 15 | //! The Matrix Market format is a simple ASCII-based file format for sparse matrices, and was initially developed for 16 | //! the [NIST Matrix Market](https://math.nist.gov/MatrixMarket/), a repository of example sparse matrices. 17 | //! In later years it has largely been superseded by the 18 | //! [SuiteSparse Matrix Collection](https://sparse.tamu.edu/) (formerly University of Florida Sparse Matrix Collection), 19 | //! which also uses the Matrix Market file format. 20 | //! 21 | //! We currently offer functionality for importing a Matrix market file to an instance of a 22 | //! [CooMatrix](crate::CooMatrix) through the function [load_coo_from_matrix_market_file], 23 | //! as well as functionality for writing various sparse matrices to the matrix market format 24 | //! through [save_to_matrix_market_file]. It is also possible to load 25 | //! a matrix stored as a string in the matrix market format with the function 26 | //! [load_coo_from_matrix_market_str], or similarly write to a string with 27 | //! [save_to_matrix_market_str]. 28 | //! 29 | //! Our implementation is based on the [format description](https://math.nist.gov/MatrixMarket/formats.html) 30 | //! on the Matrix Market website and the 31 | //! [following NIST whitepaper](https://math.nist.gov/MatrixMarket/reports/MMformat.ps): 32 | //! 33 | //! > Boisvert, Ronald F., Roldan Pozo, and Karin A. Remington.
34 | //! > "*The Matrix Market Exchange Formats: Initial Design.*" (1996). 35 | 36 | pub use self::matrix_market::{ 37 | load_coo_from_matrix_market_file, load_coo_from_matrix_market_str, save_to_matrix_market, 38 | save_to_matrix_market_file, save_to_matrix_market_str, MatrixMarketError, 39 | MatrixMarketErrorKind, MatrixMarketExport, MatrixMarketScalar, 40 | }; 41 | mod matrix_market; 42 | -------------------------------------------------------------------------------- /nalgebra-sparse/src/matrixcompare.rs: -------------------------------------------------------------------------------- 1 | //! Implements core traits for use with `matrixcompare`. 2 | use crate::coo::CooMatrix; 3 | use crate::csc::CscMatrix; 4 | use crate::csr::CsrMatrix; 5 | use matrixcompare_core; 6 | use matrixcompare_core::{Access, SparseAccess}; 7 | 8 | macro_rules! impl_matrix_for_csr_csc { 9 | ($MatrixType:ident) => { 10 | impl SparseAccess for $MatrixType { 11 | fn nnz(&self) -> usize { 12 | $MatrixType::nnz(self) 13 | } 14 | 15 | fn fetch_triplets(&self) -> Vec<(usize, usize, T)> { 16 | self.triplet_iter() 17 | .map(|(i, j, v)| (i, j, v.clone())) 18 | .collect() 19 | } 20 | } 21 | 22 | impl matrixcompare_core::Matrix for $MatrixType { 23 | fn rows(&self) -> usize { 24 | self.nrows() 25 | } 26 | 27 | fn cols(&self) -> usize { 28 | self.ncols() 29 | } 30 | 31 | fn access(&self) -> Access<'_, T> { 32 | Access::Sparse(self) 33 | } 34 | } 35 | }; 36 | } 37 | 38 | impl_matrix_for_csr_csc!(CsrMatrix); 39 | impl_matrix_for_csr_csc!(CscMatrix); 40 | 41 | impl SparseAccess for CooMatrix { 42 | fn nnz(&self) -> usize { 43 | CooMatrix::nnz(self) 44 | } 45 | 46 | fn fetch_triplets(&self) -> Vec<(usize, usize, T)> { 47 | self.triplet_iter() 48 | .map(|(i, j, v)| (i, j, v.clone())) 49 | .collect() 50 | } 51 | } 52 | 53 | impl matrixcompare_core::Matrix for CooMatrix { 54 | fn rows(&self) -> usize { 55 | self.nrows() 56 | } 57 | 58 | fn cols(&self) -> usize { 59 | self.ncols() 60 | } 61 | 62 | fn access(&self) -> Access<'_, T> { 63 | Access::Sparse(self) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /nalgebra-sparse/src/utils.rs: -------------------------------------------------------------------------------- 1 | //! Helper functions for sparse matrix computations 2 | 3 | /// permutes entries of in_slice according to permutation slice and puts them to out_slice 4 | #[inline] 5 | pub fn apply_permutation(out_slice: &mut [T], in_slice: &[T], permutation: &[usize]) { 6 | assert_eq!(out_slice.len(), in_slice.len()); 7 | assert_eq!(out_slice.len(), permutation.len()); 8 | for (out_element, old_pos) in out_slice.iter_mut().zip(permutation) { 9 | *out_element = in_slice[*old_pos].clone(); 10 | } 11 | } 12 | 13 | /// computes permutation by using provided indices as keys 14 | #[inline] 15 | pub fn compute_sort_permutation(permutation: &mut [usize], indices: &[usize]) { 16 | assert_eq!(permutation.len(), indices.len()); 17 | // Set permutation to identity 18 | for (i, p) in permutation.iter_mut().enumerate() { 19 | *p = i; 20 | } 21 | 22 | // Compute permutation needed to bring minor indices into sorted order 23 | // Note: Using sort_unstable here avoids internal allocations, which is crucial since 24 | // each lane might have a small number of elements 25 | permutation.sort_unstable_by_key(|idx| indices[*idx]); 26 | } 27 | -------------------------------------------------------------------------------- /nalgebra-sparse/tests/unit.rs: -------------------------------------------------------------------------------- 1 | //! Unit tests 2 | #[cfg(not(all(feature = "proptest-support", feature = "compare", feature = "io",)))] 3 | compile_error!( 4 | "Please enable the `proptest-support`, `compare` and `io` features in order to compile and run the tests. 5 | Example: `cargo test -p nalgebra-sparse --features proptest-support,compare,io`" 6 | ); 7 | 8 | mod unit_tests; 9 | 10 | #[macro_use] 11 | pub mod common; 12 | -------------------------------------------------------------------------------- /nalgebra-sparse/tests/unit_tests/cholesky.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 3f71c8edc555965e521e3aaf58c736240a0e333c3a9d54e8a836d7768c371215 # shrinks to matrix = CscMatrix { cs: CsMatrix { sparsity_pattern: SparsityPattern { major_offsets: [0], minor_indices: [], minor_dim: 0 }, values: [] } } 8 | cc aef645e3184b814ef39fbb10234f12e6ff502ab515dabefafeedab5895e22b12 # shrinks to (matrix, rhs) = (CscMatrix { cs: CsMatrix { sparsity_pattern: SparsityPattern { major_offsets: [0, 4, 7, 11, 14], minor_indices: [0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 3, 0, 2, 3], minor_dim: 4 }, values: [1.0, 0.0, 0.0, 0.0, 0.0, 40.90124126326177, 36.975170911665906, 0.0, 36.975170911665906, 42.51062858727923, -12.984115201530539, 0.0, -12.984115201530539, 27.73953543265418] } }, Matrix { data: VecStorage { data: [0.0, 0.0, 0.0, -4.05763092330143], nrows: Dynamic { value: 4 }, ncols: Dynamic { value: 1 } } }) 9 | -------------------------------------------------------------------------------- /nalgebra-sparse/tests/unit_tests/convert_serial.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 07cb95127d2700ff2000157938e351ce2b43f3e6419d69b00726abfc03e682bd # shrinks to coo = CooMatrix { nrows: 4, ncols: 5, row_indices: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0], col_indices: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 3], values: [1, -5, -4, -5, 1, 2, 4, -4, -4, -5, 2, -2, 4, -4] } 8 | cc 8fdaf70d6091d89a6617573547745e9802bb9c1ce7c6ec7ad4f301cd05d54c5d # shrinks to dense = Matrix { data: VecStorage { data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1], nrows: Dynamic { value: 4 }, ncols: Dynamic { value: 5 } } } 9 | cc 6961760ac7915b57a28230524cea7e9bfcea4f31790e3c0569ea74af904c2d79 # shrinks to coo = CooMatrix { nrows: 6, ncols: 6, row_indices: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0], col_indices: [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, 0], values: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] } 10 | cc c9a1af218f7a974f1fda7b8909c2635d735eedbfe953082ef6b0b92702bf6d1b # shrinks to dense = Matrix { data: VecStorage { data: [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, 1], nrows: Dynamic { value: 6 }, ncols: Dynamic { value: 5 } } } 11 | -------------------------------------------------------------------------------- /nalgebra-sparse/tests/unit_tests/csc.proptest-regressions: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc a71b4654827840ed539b82cd7083615b0fb3f75933de6a7d91d8148a2bf34960 # shrinks to (csc, triplet_subset) = (CscMatrix { cs: CsMatrix { sparsity_pattern: SparsityPattern { major_offsets: [0, 1, 1, 1, 1, 1, 1], minor_indices: [0], minor_dim: 4 }, values: [0] } }, {}) 8 | -------------------------------------------------------------------------------- /nalgebra-sparse/tests/unit_tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod cholesky; 2 | mod convert_serial; 3 | mod coo; 4 | mod csc; 5 | mod csr; 6 | mod matrix_market; 7 | mod ops; 8 | mod pattern; 9 | mod proptest; 10 | mod test_data_examples; 11 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | use_try_shorthand = true 3 | use_field_init_shorthand = true 4 | -------------------------------------------------------------------------------- /src/base/helper.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "arbitrary")] 2 | use quickcheck::{Arbitrary, Gen}; 3 | 4 | #[cfg(feature = "rand-no-std")] 5 | use rand::{ 6 | distr::{Distribution, StandardUniform}, 7 | Rng, 8 | }; 9 | 10 | /// Simple helper function for rejection sampling 11 | #[cfg(feature = "arbitrary")] 12 | #[doc(hidden)] 13 | #[inline] 14 | pub fn reject bool, T: Arbitrary>(g: &mut Gen, f: F) -> T { 15 | use std::iter; 16 | iter::repeat(()) 17 | .map(|_| Arbitrary::arbitrary(g)) 18 | .find(f) 19 | .unwrap() 20 | } 21 | 22 | #[doc(hidden)] 23 | #[inline] 24 | #[cfg(feature = "rand-no-std")] 25 | pub fn reject_rand bool, T>(g: &mut G, f: F) -> T 26 | where 27 | StandardUniform: Distribution, 28 | { 29 | use std::iter; 30 | iter::repeat(()).map(|_| g.random()).find(f).unwrap() 31 | } 32 | -------------------------------------------------------------------------------- /src/base/matrix_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::base::allocator::Allocator; 4 | use crate::base::dimension::Dim; 5 | use crate::base::{DefaultAllocator, OMatrix, Scalar}; 6 | 7 | /* 8 | * 9 | * Simd structures. 10 | * 11 | */ 12 | impl SimdValue for OMatrix 13 | where 14 | T: Scalar + SimdValue, 15 | R: Dim, 16 | C: Dim, 17 | T::Element: Scalar, 18 | DefaultAllocator: Allocator, 19 | { 20 | const LANES: usize = T::LANES; 21 | type Element = OMatrix; 22 | type SimdBool = T::SimdBool; 23 | 24 | #[inline] 25 | fn splat(val: Self::Element) -> Self { 26 | val.map(T::splat) 27 | } 28 | 29 | #[inline] 30 | fn extract(&self, i: usize) -> Self::Element { 31 | self.map(|e| e.extract(i)) 32 | } 33 | 34 | #[inline] 35 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 36 | self.map(|e| e.extract_unchecked(i)) 37 | } 38 | 39 | #[inline] 40 | fn replace(&mut self, i: usize, val: Self::Element) { 41 | self.zip_apply(&val, |a, b| { 42 | a.replace(i, b); 43 | }) 44 | } 45 | 46 | #[inline] 47 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 48 | self.zip_apply(&val, |a, b| { 49 | a.replace_unchecked(i, b); 50 | }) 51 | } 52 | 53 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 54 | self.zip_map(&other, |a, b| a.select(cond, b)) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/base/mod.rs: -------------------------------------------------------------------------------- 1 | //! [Reexported at the root of this crate.] Data structures for vector and matrix computations. 2 | 3 | pub mod allocator; 4 | mod blas; 5 | pub mod constraint; 6 | pub mod coordinates; 7 | pub mod default_allocator; 8 | pub mod dimension; 9 | pub mod iter; 10 | mod ops; 11 | pub mod storage; 12 | 13 | mod alias; 14 | mod alias_slice; 15 | mod alias_view; 16 | mod array_storage; 17 | mod cg; 18 | mod componentwise; 19 | #[macro_use] 20 | mod construction; 21 | mod construction_view; 22 | mod conversion; 23 | mod edition; 24 | pub mod indexing; 25 | mod matrix; 26 | mod matrix_simba; 27 | mod matrix_view; 28 | mod norm; 29 | mod properties; 30 | mod scalar; 31 | mod statistics; 32 | mod swizzle; 33 | mod unit; 34 | #[cfg(any(feature = "std", feature = "alloc"))] 35 | mod vec_storage; 36 | 37 | mod blas_uninit; 38 | #[doc(hidden)] 39 | pub mod helper; 40 | mod interpolation; 41 | mod min_max; 42 | /// Mechanisms for working with values that may not be initialized. 43 | pub mod uninit; 44 | 45 | #[cfg(feature = "rayon")] 46 | pub mod par_iter; 47 | 48 | #[cfg(feature = "rkyv-serialize-no-std")] 49 | mod rkyv_wrappers; 50 | 51 | pub use self::matrix::*; 52 | pub use self::norm::*; 53 | pub use self::scalar::*; 54 | pub use self::unit::*; 55 | 56 | pub use self::default_allocator::*; 57 | pub use self::dimension::*; 58 | 59 | pub use self::alias::*; 60 | pub use self::alias_slice::*; 61 | pub use self::alias_view::*; 62 | pub use self::array_storage::*; 63 | pub use self::matrix_view::*; 64 | pub use self::storage::*; 65 | #[cfg(any(feature = "std", feature = "alloc"))] 66 | pub use self::vec_storage::*; 67 | -------------------------------------------------------------------------------- /src/base/rkyv_wrappers.rs: -------------------------------------------------------------------------------- 1 | //! Wrapper that allows changing the generic type of a `PhantomData` 2 | //! 3 | //! Copied from (MIT-Apache2 licences) which isn’t published yet. 4 | 5 | use rkyv::{ 6 | with::{ArchiveWith, DeserializeWith, SerializeWith}, 7 | Fallible, 8 | }; 9 | use std::marker::PhantomData; 10 | 11 | /// A wrapper that allows for changing the generic type of a `PhantomData`. 12 | pub struct CustomPhantom { 13 | _data: PhantomData<*const NT>, 14 | } 15 | 16 | impl ArchiveWith> for CustomPhantom { 17 | type Archived = PhantomData; 18 | type Resolver = (); 19 | 20 | #[inline] 21 | unsafe fn resolve_with( 22 | _: &PhantomData, 23 | _: usize, 24 | _: Self::Resolver, 25 | _: *mut Self::Archived, 26 | ) { 27 | } 28 | } 29 | 30 | impl SerializeWith, S> 31 | for CustomPhantom 32 | { 33 | #[inline] 34 | fn serialize_with(_: &PhantomData, _: &mut S) -> Result { 35 | Ok(()) 36 | } 37 | } 38 | 39 | impl 40 | DeserializeWith, PhantomData, D> for CustomPhantom 41 | { 42 | #[inline] 43 | fn deserialize_with(_: &PhantomData, _: &mut D) -> Result, D::Error> { 44 | Ok(PhantomData) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/base/scalar.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | /// The basic scalar type for all structures of `nalgebra`. 4 | /// 5 | /// This does not make any assumption on the algebraic properties of `Self`. 6 | pub trait Scalar: 'static + Clone + PartialEq + Debug {} 7 | 8 | impl Scalar for T {} 9 | -------------------------------------------------------------------------------- /src/debug/mod.rs: -------------------------------------------------------------------------------- 1 | //! Various tools useful for testing/debugging/benchmarking. 2 | 3 | mod random_orthogonal; 4 | mod random_sdp; 5 | 6 | pub use self::random_orthogonal::*; 7 | pub use self::random_sdp::*; 8 | -------------------------------------------------------------------------------- /src/debug/random_orthogonal.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "arbitrary")] 2 | use crate::base::storage::Owned; 3 | #[cfg(feature = "arbitrary")] 4 | use quickcheck::{Arbitrary, Gen}; 5 | 6 | use crate::base::allocator::Allocator; 7 | use crate::base::dimension::{Dim, Dyn}; 8 | use crate::base::Scalar; 9 | use crate::base::{DefaultAllocator, OMatrix}; 10 | use crate::linalg::givens::GivensRotation; 11 | use simba::scalar::ComplexField; 12 | 13 | /// A random orthogonal matrix. 14 | #[derive(Clone, Debug)] 15 | pub struct RandomOrthogonal 16 | where 17 | DefaultAllocator: Allocator, 18 | { 19 | m: OMatrix, 20 | } 21 | 22 | impl RandomOrthogonal 23 | where 24 | DefaultAllocator: Allocator, 25 | { 26 | /// Retrieve the generated matrix. 27 | pub fn unwrap(self) -> OMatrix { 28 | self.m 29 | } 30 | 31 | /// Creates a new random orthogonal matrix from its dimension and a random reals generators. 32 | pub fn new T>(dim: D, mut rand: Rand) -> Self { 33 | let mut res = OMatrix::identity_generic(dim, dim); 34 | 35 | // Create an orthogonal matrix by composing random Givens rotations rotations. 36 | for i in 0..dim.value() - 1 { 37 | let rot = GivensRotation::new(rand(), rand()).0; 38 | rot.rotate(&mut res.fixed_rows_mut::<2>(i)); 39 | } 40 | 41 | RandomOrthogonal { m: res } 42 | } 43 | } 44 | 45 | #[cfg(feature = "arbitrary")] 46 | impl Arbitrary for RandomOrthogonal 47 | where 48 | DefaultAllocator: Allocator, 49 | Owned: Clone + Send, 50 | { 51 | fn arbitrary(g: &mut Gen) -> Self { 52 | let dim = D::try_to_usize().unwrap_or(1 + usize::arbitrary(g) % 50); 53 | Self::new(D::from_usize(dim), || T::arbitrary(g)) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/debug/random_sdp.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "arbitrary")] 2 | use crate::base::storage::Owned; 3 | #[cfg(feature = "arbitrary")] 4 | use quickcheck::{Arbitrary, Gen}; 5 | 6 | use crate::base::allocator::Allocator; 7 | use crate::base::dimension::{Dim, Dyn}; 8 | use crate::base::Scalar; 9 | use crate::base::{DefaultAllocator, OMatrix}; 10 | use simba::scalar::ComplexField; 11 | 12 | use crate::debug::RandomOrthogonal; 13 | 14 | /// A random, well-conditioned, symmetric definite-positive matrix. 15 | #[derive(Clone, Debug)] 16 | pub struct RandomSDP 17 | where 18 | DefaultAllocator: Allocator, 19 | { 20 | m: OMatrix, 21 | } 22 | 23 | impl RandomSDP 24 | where 25 | DefaultAllocator: Allocator, 26 | { 27 | /// Retrieve the generated matrix. 28 | pub fn unwrap(self) -> OMatrix { 29 | self.m 30 | } 31 | 32 | /// Creates a new well conditioned symmetric definite-positive matrix from its dimension and a 33 | /// random reals generators. 34 | pub fn new T>(dim: D, mut rand: Rand) -> Self { 35 | let mut m = RandomOrthogonal::new(dim, &mut rand).unwrap(); 36 | let mt = m.adjoint(); 37 | 38 | for i in 0..dim.value() { 39 | let mut col = m.column_mut(i); 40 | let eigenval = T::one() + T::from_real(rand().modulus()); 41 | col *= eigenval; 42 | } 43 | 44 | RandomSDP { m: m * mt } 45 | } 46 | } 47 | 48 | #[cfg(feature = "arbitrary")] 49 | impl Arbitrary for RandomSDP 50 | where 51 | DefaultAllocator: Allocator, 52 | Owned: Clone + Send, 53 | { 54 | fn arbitrary(g: &mut Gen) -> Self { 55 | let dim = D::try_to_usize().unwrap_or(1 + usize::arbitrary(g) % 50); 56 | Self::new(D::from_usize(dim), || T::arbitrary(g)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/geometry/isometry_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::{Isometry, Rotation2, Rotation3, UnitComplex, UnitQuaternion}; 2 | 3 | /// A 2-dimensional direct isometry using a unit complex number for its rotational part. 4 | /// 5 | /// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** 6 | /// 7 | /// Also known as a 2D rigid-body motion, or as an element of SE(2). 8 | pub type Isometry2 = Isometry, 2>; 9 | 10 | /// A 3-dimensional direct isometry using a unit quaternion for its rotational part. 11 | /// 12 | /// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** 13 | /// 14 | /// Also known as a rigid-body motion, or as an element of SE(3). 15 | pub type Isometry3 = Isometry, 3>; 16 | 17 | /// A 2-dimensional direct isometry using a rotation matrix for its rotational part. 18 | /// 19 | /// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** 20 | /// 21 | /// Also known as a rigid-body motion, or as an element of SE(2). 22 | pub type IsometryMatrix2 = Isometry, 2>; 23 | 24 | /// A 3-dimensional direct isometry using a rotation matrix for its rotational part. 25 | /// 26 | /// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** 27 | /// 28 | /// Also known as a rigid-body motion, or as an element of SE(3). 29 | pub type IsometryMatrix3 = Isometry, 3>; 30 | 31 | // This tests that the types correctly implement `Copy`, without having to run tests 32 | // (when targeting no-std for example). 33 | #[allow(dead_code)] 34 | fn ensure_copy() { 35 | fn is_copy() {} 36 | 37 | is_copy::>(); 38 | is_copy::>(); 39 | is_copy::>(); 40 | is_copy::>(); 41 | } 42 | -------------------------------------------------------------------------------- /src/geometry/isometry_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::SimdRealField; 4 | 5 | use crate::geometry::{AbstractRotation, Isometry, Translation}; 6 | 7 | impl SimdValue for Isometry 8 | where 9 | T::Element: SimdRealField, 10 | R: SimdValue + AbstractRotation, 11 | R::Element: AbstractRotation, 12 | { 13 | const LANES: usize = T::LANES; 14 | type Element = Isometry; 15 | type SimdBool = T::SimdBool; 16 | 17 | #[inline] 18 | fn splat(val: Self::Element) -> Self { 19 | Isometry::from_parts(Translation::splat(val.translation), R::splat(val.rotation)) 20 | } 21 | 22 | #[inline] 23 | fn extract(&self, i: usize) -> Self::Element { 24 | Isometry::from_parts(self.translation.extract(i), self.rotation.extract(i)) 25 | } 26 | 27 | #[inline] 28 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 29 | Isometry::from_parts( 30 | self.translation.extract_unchecked(i), 31 | self.rotation.extract_unchecked(i), 32 | ) 33 | } 34 | 35 | #[inline] 36 | fn replace(&mut self, i: usize, val: Self::Element) { 37 | self.translation.replace(i, val.translation); 38 | self.rotation.replace(i, val.rotation); 39 | } 40 | 41 | #[inline] 42 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 43 | self.translation.replace_unchecked(i, val.translation); 44 | self.rotation.replace_unchecked(i, val.rotation); 45 | } 46 | 47 | #[inline] 48 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 49 | Isometry::from_parts( 50 | self.translation.select(cond, other.translation), 51 | self.rotation.select(cond, other.rotation), 52 | ) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/geometry/point_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::OPoint; 2 | use crate::Const; 3 | 4 | /// A point with `D` elements. 5 | pub type Point = OPoint>; 6 | 7 | /// A statically sized 1-dimensional column point. 8 | /// 9 | /// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** 10 | pub type Point1 = Point; 11 | /// A statically sized 2-dimensional column point. 12 | /// 13 | /// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** 14 | pub type Point2 = Point; 15 | /// A statically sized 3-dimensional column point. 16 | /// 17 | /// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** 18 | pub type Point3 = Point; 19 | /// A statically sized 4-dimensional column point. 20 | /// 21 | /// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** 22 | pub type Point4 = Point; 23 | /// A statically sized 5-dimensional column point. 24 | /// 25 | /// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** 26 | pub type Point5 = Point; 27 | /// A statically sized 6-dimensional column point. 28 | /// 29 | /// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** 30 | pub type Point6 = Point; 31 | -------------------------------------------------------------------------------- /src/geometry/point_coordinates.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; 4 | use crate::base::{Scalar, U1, U2, U3, U4, U5, U6}; 5 | 6 | use crate::geometry::OPoint; 7 | 8 | /* 9 | * 10 | * Give coordinates to Point{1 .. 6} 11 | * 12 | */ 13 | 14 | macro_rules! deref_impl( 15 | ($D: ty, $Target: ident $(, $comps: ident)*) => { 16 | impl Deref for OPoint 17 | { 18 | type Target = $Target; 19 | 20 | #[inline] 21 | fn deref(&self) -> &Self::Target { 22 | &*self.coords 23 | } 24 | } 25 | 26 | impl DerefMut for OPoint 27 | { 28 | #[inline] 29 | fn deref_mut(&mut self) -> &mut Self::Target { 30 | &mut *self.coords 31 | } 32 | } 33 | } 34 | ); 35 | 36 | deref_impl!(U1, X, x); 37 | deref_impl!(U2, XY, x, y); 38 | deref_impl!(U3, XYZ, x, y, z); 39 | deref_impl!(U4, XYZW, x, y, z, w); 40 | deref_impl!(U5, XYZWA, x, y, z, w, a); 41 | deref_impl!(U6, XYZWAB, x, y, z, w, a, b); 42 | -------------------------------------------------------------------------------- /src/geometry/point_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::base::{OVector, Scalar}; 4 | 5 | use crate::geometry::Point; 6 | 7 | impl SimdValue for Point 8 | where 9 | T::Element: Scalar, 10 | { 11 | const LANES: usize = T::LANES; 12 | type Element = Point; 13 | type SimdBool = T::SimdBool; 14 | 15 | #[inline] 16 | fn splat(val: Self::Element) -> Self { 17 | OVector::splat(val.coords).into() 18 | } 19 | 20 | #[inline] 21 | fn extract(&self, i: usize) -> Self::Element { 22 | self.coords.extract(i).into() 23 | } 24 | 25 | #[inline] 26 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 27 | self.coords.extract_unchecked(i).into() 28 | } 29 | 30 | #[inline] 31 | fn replace(&mut self, i: usize, val: Self::Element) { 32 | self.coords.replace(i, val.coords) 33 | } 34 | 35 | #[inline] 36 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 37 | self.coords.replace_unchecked(i, val.coords) 38 | } 39 | 40 | #[inline] 41 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 42 | self.coords.select(cond, other.coords).into() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/geometry/quaternion_coordinates.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | use simba::simd::SimdValue; 4 | 5 | use crate::base::coordinates::IJKW; 6 | use crate::Scalar; 7 | 8 | use crate::geometry::Quaternion; 9 | 10 | impl Deref for Quaternion { 11 | type Target = IJKW; 12 | 13 | #[inline] 14 | fn deref(&self) -> &Self::Target { 15 | unsafe { &*(self as *const Self as *const Self::Target) } 16 | } 17 | } 18 | 19 | impl DerefMut for Quaternion { 20 | #[inline] 21 | fn deref_mut(&mut self) -> &mut Self::Target { 22 | unsafe { &mut *(self as *mut Self as *mut Self::Target) } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/geometry/reflection_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::base::ArrayStorage; 2 | use crate::geometry::Reflection; 3 | use crate::Const; 4 | 5 | /// A 1-dimensional reflection. 6 | pub type Reflection1 = Reflection, ArrayStorage>; 7 | 8 | /// A 2-dimensional reflection. 9 | pub type Reflection2 = Reflection, ArrayStorage>; 10 | 11 | /// A 3-dimensional reflection. 12 | pub type Reflection3 = Reflection, ArrayStorage>; 13 | 14 | /// A 4-dimensional reflection. 15 | pub type Reflection4 = Reflection, ArrayStorage>; 16 | 17 | /// A 5-dimensional reflection. 18 | pub type Reflection5 = Reflection, ArrayStorage>; 19 | 20 | /// A 6-dimensional reflection. 21 | pub type Reflection6 = Reflection, ArrayStorage>; 22 | -------------------------------------------------------------------------------- /src/geometry/rotation_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::Rotation; 2 | 3 | /// A 2-dimensional rotation matrix. 4 | /// 5 | /// **Because this is an alias, not all its methods are listed here. See the [`Rotation`](crate::Rotation) type too.** 6 | pub type Rotation2 = Rotation; 7 | 8 | /// A 3-dimensional rotation matrix. 9 | /// 10 | /// **Because this is an alias, not all its methods are listed here. See the [`Rotation`](crate::Rotation) type too.** 11 | pub type Rotation3 = Rotation; 12 | -------------------------------------------------------------------------------- /src/geometry/rotation_construction.rs: -------------------------------------------------------------------------------- 1 | use num::{One, Zero}; 2 | 3 | use simba::scalar::{ClosedAddAssign, ClosedMulAssign, SupersetOf}; 4 | 5 | use crate::base::{SMatrix, Scalar}; 6 | 7 | use crate::geometry::Rotation; 8 | 9 | impl Default for Rotation 10 | where 11 | T: Scalar + Zero + One, 12 | { 13 | fn default() -> Self { 14 | Self::identity() 15 | } 16 | } 17 | 18 | /// # Identity 19 | impl Rotation 20 | where 21 | T: Scalar + Zero + One, 22 | { 23 | /// Creates a new square identity rotation of the given `dimension`. 24 | /// 25 | /// # Example 26 | /// ``` 27 | /// # use nalgebra::{Rotation2, Rotation3}; 28 | /// # use nalgebra::Vector3; 29 | /// let rot1 = Rotation2::identity(); 30 | /// let rot2 = Rotation2::new(std::f32::consts::FRAC_PI_2); 31 | /// 32 | /// assert_eq!(rot1 * rot2, rot2); 33 | /// assert_eq!(rot2 * rot1, rot2); 34 | /// 35 | /// let rot1 = Rotation3::identity(); 36 | /// let rot2 = Rotation3::from_axis_angle(&Vector3::z_axis(), std::f32::consts::FRAC_PI_2); 37 | /// 38 | /// assert_eq!(rot1 * rot2, rot2); 39 | /// assert_eq!(rot2 * rot1, rot2); 40 | /// ``` 41 | #[inline] 42 | pub fn identity() -> Rotation { 43 | Self::from_matrix_unchecked(SMatrix::::identity()) 44 | } 45 | } 46 | 47 | impl Rotation { 48 | /// Cast the components of `self` to another type. 49 | /// 50 | /// # Example 51 | /// ``` 52 | /// # use nalgebra::Rotation2; 53 | /// let rot = Rotation2::::identity(); 54 | /// let rot2 = rot.cast::(); 55 | /// assert_eq!(rot2, Rotation2::::identity()); 56 | /// ``` 57 | pub fn cast(self) -> Rotation 58 | where 59 | Rotation: SupersetOf, 60 | { 61 | crate::convert(self) 62 | } 63 | } 64 | 65 | impl One for Rotation 66 | where 67 | T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, 68 | { 69 | #[inline] 70 | fn one() -> Self { 71 | Self::identity() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/geometry/rotation_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::base::{OMatrix, Scalar}; 4 | 5 | use crate::geometry::Rotation; 6 | 7 | impl SimdValue for Rotation 8 | where 9 | T: Scalar + SimdValue, 10 | T::Element: Scalar, 11 | { 12 | const LANES: usize = T::LANES; 13 | type Element = Rotation; 14 | type SimdBool = T::SimdBool; 15 | 16 | #[inline] 17 | fn splat(val: Self::Element) -> Self { 18 | Rotation::from_matrix_unchecked(OMatrix::splat(val.into_inner())) 19 | } 20 | 21 | #[inline] 22 | fn extract(&self, i: usize) -> Self::Element { 23 | Rotation::from_matrix_unchecked(self.matrix().extract(i)) 24 | } 25 | 26 | #[inline] 27 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 28 | Rotation::from_matrix_unchecked(self.matrix().extract_unchecked(i)) 29 | } 30 | 31 | #[inline] 32 | fn replace(&mut self, i: usize, val: Self::Element) { 33 | self.matrix_mut_unchecked().replace(i, val.into_inner()) 34 | } 35 | 36 | #[inline] 37 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 38 | self.matrix_mut_unchecked() 39 | .replace_unchecked(i, val.into_inner()) 40 | } 41 | 42 | #[inline] 43 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 44 | Rotation::from_matrix_unchecked(self.into_inner().select(cond, other.into_inner())) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/geometry/scale_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::Scale; 2 | 3 | /// A 1-dimensional scale. 4 | pub type Scale1 = Scale; 5 | 6 | /// A 2-dimensional scale. 7 | pub type Scale2 = Scale; 8 | 9 | /// A 3-dimensional scale. 10 | pub type Scale3 = Scale; 11 | 12 | /// A 4-dimensional scale. 13 | pub type Scale4 = Scale; 14 | 15 | /// A 5-dimensional scale. 16 | pub type Scale5 = Scale; 17 | 18 | /// A 6-dimensional scale. 19 | pub type Scale6 = Scale; 20 | -------------------------------------------------------------------------------- /src/geometry/scale_coordinates.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; 4 | use crate::base::Scalar; 5 | 6 | use crate::geometry::Scale; 7 | 8 | /* 9 | * 10 | * Give coordinates to Scale{1 .. 6} 11 | * 12 | */ 13 | 14 | macro_rules! deref_impl( 15 | ($D: expr, $Target: ident $(, $comps: ident)*) => { 16 | impl Deref for Scale { 17 | type Target = $Target; 18 | 19 | #[inline] 20 | fn deref(&self) -> &Self::Target { 21 | self.vector.deref() 22 | } 23 | } 24 | 25 | impl DerefMut for Scale { 26 | #[inline] 27 | fn deref_mut(&mut self) -> &mut Self::Target { 28 | self.vector.deref_mut() 29 | } 30 | } 31 | } 32 | ); 33 | 34 | deref_impl!(1, X, x); 35 | deref_impl!(2, XY, x, y); 36 | deref_impl!(3, XYZ, x, y, z); 37 | deref_impl!(4, XYZW, x, y, z, w); 38 | deref_impl!(5, XYZWA, x, y, z, w, a); 39 | deref_impl!(6, XYZWAB, x, y, z, w, a, b); 40 | -------------------------------------------------------------------------------- /src/geometry/scale_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::base::OVector; 4 | use crate::Scalar; 5 | 6 | use crate::geometry::Scale; 7 | 8 | impl SimdValue for Scale 9 | where 10 | T::Element: Scalar, 11 | { 12 | const LANES: usize = T::LANES; 13 | type Element = Scale; 14 | type SimdBool = T::SimdBool; 15 | 16 | #[inline] 17 | fn splat(val: Self::Element) -> Self { 18 | OVector::splat(val.vector).into() 19 | } 20 | 21 | #[inline] 22 | fn extract(&self, i: usize) -> Self::Element { 23 | self.vector.extract(i).into() 24 | } 25 | 26 | #[inline] 27 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 28 | self.vector.extract_unchecked(i).into() 29 | } 30 | 31 | #[inline] 32 | fn replace(&mut self, i: usize, val: Self::Element) { 33 | self.vector.replace(i, val.vector) 34 | } 35 | 36 | #[inline] 37 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 38 | self.vector.replace_unchecked(i, val.vector) 39 | } 40 | 41 | #[inline] 42 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 43 | self.vector.select(cond, other.vector).into() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/geometry/similarity_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::{Rotation2, Rotation3, Similarity, UnitComplex, UnitQuaternion}; 2 | 3 | /// A 2-dimensional similarity. 4 | pub type Similarity2 = Similarity, 2>; 5 | 6 | /// A 3-dimensional similarity. 7 | pub type Similarity3 = Similarity, 3>; 8 | 9 | /// A 2-dimensional similarity using a rotation matrix for its rotation part. 10 | pub type SimilarityMatrix2 = Similarity, 2>; 11 | 12 | /// A 3-dimensional similarity using a rotation matrix for its rotation part. 13 | pub type SimilarityMatrix3 = Similarity, 3>; 14 | -------------------------------------------------------------------------------- /src/geometry/similarity_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::{SimdRealField, SimdValue}; 2 | 3 | use crate::geometry::{AbstractRotation, Isometry, Similarity}; 4 | 5 | impl SimdValue for Similarity 6 | where 7 | T::Element: SimdRealField, 8 | R: SimdValue + AbstractRotation, 9 | R::Element: AbstractRotation, 10 | { 11 | const LANES: usize = T::LANES; 12 | type Element = Similarity; 13 | type SimdBool = T::SimdBool; 14 | 15 | #[inline] 16 | fn splat(val: Self::Element) -> Self { 17 | let scaling = T::splat(val.scaling()); 18 | Similarity::from_isometry(Isometry::splat(val.isometry), scaling) 19 | } 20 | 21 | #[inline] 22 | fn extract(&self, i: usize) -> Self::Element { 23 | Similarity::from_isometry(self.isometry.extract(i), self.scaling().extract(i)) 24 | } 25 | 26 | #[inline] 27 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 28 | Similarity::from_isometry( 29 | self.isometry.extract_unchecked(i), 30 | self.scaling().extract_unchecked(i), 31 | ) 32 | } 33 | 34 | #[inline] 35 | fn replace(&mut self, i: usize, val: Self::Element) { 36 | let mut s = self.scaling(); 37 | s.replace(i, val.scaling()); 38 | self.set_scaling(s); 39 | self.isometry.replace(i, val.isometry); 40 | } 41 | 42 | #[inline] 43 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 44 | let mut s = self.scaling(); 45 | s.replace_unchecked(i, val.scaling()); 46 | self.set_scaling(s); 47 | self.isometry.replace_unchecked(i, val.isometry); 48 | } 49 | 50 | #[inline] 51 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 52 | let scaling = self.scaling().select(cond, other.scaling()); 53 | Similarity::from_isometry(self.isometry.select(cond, other.isometry), scaling) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/geometry/transform_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::{TAffine, TGeneral, TProjective, Transform}; 2 | 3 | /// A 2D general transformation that may not be invertible. Stored as a homogeneous 3x3 matrix. 4 | pub type Transform2 = Transform; 5 | /// An invertible 2D general transformation. Stored as a homogeneous 3x3 matrix. 6 | pub type Projective2 = Transform; 7 | /// A 2D affine transformation. Stored as a homogeneous 3x3 matrix. 8 | pub type Affine2 = Transform; 9 | 10 | /// A 3D general transformation that may not be inversible. Stored as a homogeneous 4x4 matrix. 11 | pub type Transform3 = Transform; 12 | /// An invertible 3D general transformation. Stored as a homogeneous 4x4 matrix. 13 | pub type Projective3 = Transform; 14 | /// A 3D affine transformation. Stored as a homogeneous 4x4 matrix. 15 | pub type Affine3 = Transform; 16 | -------------------------------------------------------------------------------- /src/geometry/transform_construction.rs: -------------------------------------------------------------------------------- 1 | use num::One; 2 | 3 | use simba::scalar::RealField; 4 | 5 | use crate::base::allocator::Allocator; 6 | use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; 7 | use crate::base::{Const, DefaultAllocator, OMatrix}; 8 | 9 | use crate::geometry::{TCategory, Transform}; 10 | 11 | impl Default for Transform 12 | where 13 | Const: DimNameAdd, 14 | DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, 15 | { 16 | fn default() -> Self { 17 | Self::identity() 18 | } 19 | } 20 | 21 | impl Transform 22 | where 23 | Const: DimNameAdd, 24 | DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, 25 | { 26 | /// Creates a new identity transform. 27 | /// 28 | /// # Example 29 | /// 30 | /// ``` 31 | /// # use nalgebra::{Transform2, Projective2, Affine2, Transform3, Projective3, Affine3, Point2, Point3}; 32 | /// 33 | /// let pt = Point2::new(1.0, 2.0); 34 | /// let t = Projective2::identity(); 35 | /// assert_eq!(t * pt, pt); 36 | /// 37 | /// let aff = Affine2::identity(); 38 | /// assert_eq!(aff * pt, pt); 39 | /// 40 | /// let aff = Transform2::identity(); 41 | /// assert_eq!(aff * pt, pt); 42 | /// 43 | /// // Also works in 3D. 44 | /// let pt = Point3::new(1.0, 2.0, 3.0); 45 | /// let t = Projective3::identity(); 46 | /// assert_eq!(t * pt, pt); 47 | /// 48 | /// let aff = Affine3::identity(); 49 | /// assert_eq!(aff * pt, pt); 50 | /// 51 | /// let aff = Transform3::identity(); 52 | /// assert_eq!(aff * pt, pt); 53 | /// ``` 54 | #[inline] 55 | pub fn identity() -> Self { 56 | Self::from_matrix_unchecked(OMatrix::< 57 | _, 58 | DimNameSum, U1>, 59 | DimNameSum, U1>, 60 | >::identity()) 61 | } 62 | } 63 | 64 | impl One for Transform 65 | where 66 | Const: DimNameAdd, 67 | DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, 68 | { 69 | /// Creates a new identity transform. 70 | #[inline] 71 | fn one() -> Self { 72 | Self::identity() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/geometry/transform_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::base::allocator::Allocator; 4 | use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; 5 | use crate::base::{Const, DefaultAllocator, OMatrix, Scalar}; 6 | use crate::RealField; 7 | 8 | use crate::geometry::{TCategory, Transform}; 9 | 10 | impl SimdValue for Transform 11 | where 12 | T::Element: Scalar, 13 | C: TCategory, 14 | Const: DimNameAdd, 15 | DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, 16 | { 17 | const LANES: usize = T::LANES; 18 | type Element = Transform; 19 | type SimdBool = T::SimdBool; 20 | 21 | #[inline] 22 | fn splat(val: Self::Element) -> Self { 23 | Transform::from_matrix_unchecked(OMatrix::splat(val.into_inner())) 24 | } 25 | 26 | #[inline] 27 | fn extract(&self, i: usize) -> Self::Element { 28 | Transform::from_matrix_unchecked(self.matrix().extract(i)) 29 | } 30 | 31 | #[inline] 32 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 33 | Transform::from_matrix_unchecked(self.matrix().extract_unchecked(i)) 34 | } 35 | 36 | #[inline] 37 | fn replace(&mut self, i: usize, val: Self::Element) { 38 | self.matrix_mut_unchecked().replace(i, val.into_inner()) 39 | } 40 | 41 | #[inline] 42 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 43 | self.matrix_mut_unchecked() 44 | .replace_unchecked(i, val.into_inner()) 45 | } 46 | 47 | #[inline] 48 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 49 | Transform::from_matrix_unchecked(self.into_inner().select(cond, other.into_inner())) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/geometry/translation_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::Translation; 2 | 3 | /// A 1-dimensional translation. 4 | pub type Translation1 = Translation; 5 | 6 | /// A 2-dimensional translation. 7 | pub type Translation2 = Translation; 8 | 9 | /// A 3-dimensional translation. 10 | pub type Translation3 = Translation; 11 | 12 | /// A 4-dimensional translation. 13 | pub type Translation4 = Translation; 14 | 15 | /// A 5-dimensional translation. 16 | pub type Translation5 = Translation; 17 | 18 | /// A 6-dimensional translation. 19 | pub type Translation6 = Translation; 20 | -------------------------------------------------------------------------------- /src/geometry/translation_coordinates.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Deref, DerefMut}; 2 | 3 | use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; 4 | use crate::base::Scalar; 5 | 6 | use crate::geometry::Translation; 7 | 8 | /* 9 | * 10 | * Give coordinates to Translation{1 .. 6} 11 | * 12 | */ 13 | 14 | macro_rules! deref_impl( 15 | ($D: expr, $Target: ident $(, $comps: ident)*) => { 16 | impl Deref for Translation { 17 | type Target = $Target; 18 | 19 | #[inline] 20 | fn deref(&self) -> &Self::Target { 21 | unsafe { &*(self as *const Translation as *const Self::Target) } 22 | } 23 | } 24 | 25 | impl DerefMut for Translation { 26 | #[inline] 27 | fn deref_mut(&mut self) -> &mut Self::Target { 28 | unsafe { &mut *(self as *mut Translation as *mut Self::Target) } 29 | } 30 | } 31 | } 32 | ); 33 | 34 | deref_impl!(1, X, x); 35 | deref_impl!(2, XY, x, y); 36 | deref_impl!(3, XYZ, x, y, z); 37 | deref_impl!(4, XYZW, x, y, z, w); 38 | deref_impl!(5, XYZWA, x, y, z, w, a); 39 | deref_impl!(6, XYZWAB, x, y, z, w, a, b); 40 | -------------------------------------------------------------------------------- /src/geometry/translation_simba.rs: -------------------------------------------------------------------------------- 1 | use simba::simd::SimdValue; 2 | 3 | use crate::base::OVector; 4 | use crate::Scalar; 5 | 6 | use crate::geometry::Translation; 7 | 8 | impl SimdValue for Translation 9 | where 10 | T::Element: Scalar, 11 | { 12 | const LANES: usize = T::LANES; 13 | type Element = Translation; 14 | type SimdBool = T::SimdBool; 15 | 16 | #[inline] 17 | fn splat(val: Self::Element) -> Self { 18 | OVector::splat(val.vector).into() 19 | } 20 | 21 | #[inline] 22 | fn extract(&self, i: usize) -> Self::Element { 23 | self.vector.extract(i).into() 24 | } 25 | 26 | #[inline] 27 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 28 | self.vector.extract_unchecked(i).into() 29 | } 30 | 31 | #[inline] 32 | fn replace(&mut self, i: usize, val: Self::Element) { 33 | self.vector.replace(i, val.vector) 34 | } 35 | 36 | #[inline] 37 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 38 | self.vector.replace_unchecked(i, val.vector) 39 | } 40 | 41 | #[inline] 42 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 43 | self.vector.select(cond, other.vector).into() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/geometry/unit_complex_simba.rs: -------------------------------------------------------------------------------- 1 | use num_complex::Complex; 2 | use simba::simd::SimdValue; 3 | use std::ops::Deref; 4 | 5 | use crate::base::Unit; 6 | use crate::geometry::UnitComplex; 7 | use crate::SimdRealField; 8 | 9 | impl SimdValue for UnitComplex 10 | where 11 | T::Element: SimdRealField, 12 | { 13 | const LANES: usize = T::LANES; 14 | type Element = UnitComplex; 15 | type SimdBool = T::SimdBool; 16 | 17 | #[inline] 18 | fn splat(val: Self::Element) -> Self { 19 | Unit::new_unchecked(Complex::splat(val.into_inner())) 20 | } 21 | 22 | #[inline] 23 | fn extract(&self, i: usize) -> Self::Element { 24 | Unit::new_unchecked(self.deref().extract(i)) 25 | } 26 | 27 | #[inline] 28 | unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { 29 | Unit::new_unchecked(self.deref().extract_unchecked(i)) 30 | } 31 | 32 | #[inline] 33 | fn replace(&mut self, i: usize, val: Self::Element) { 34 | self.as_mut_unchecked().replace(i, val.into_inner()) 35 | } 36 | 37 | #[inline] 38 | unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { 39 | self.as_mut_unchecked() 40 | .replace_unchecked(i, val.into_inner()) 41 | } 42 | 43 | #[inline] 44 | fn select(self, cond: Self::SimdBool, other: Self) -> Self { 45 | Unit::new_unchecked(self.into_inner().select(cond, other.into_inner())) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/io/matrix_market.pest: -------------------------------------------------------------------------------- 1 | WHITESPACE = _{ " " } 2 | 3 | Comments = _{ "%" ~ (!NEWLINE ~ ANY)* } 4 | Header = { "%%" ~ (!NEWLINE ~ ANY)* } 5 | Shape = { Dimension ~ Dimension ~ Dimension } 6 | Document = { 7 | SOI ~ 8 | NEWLINE* ~ 9 | Header ~ 10 | (NEWLINE ~ Comments)* ~ 11 | (NEWLINE ~ Shape) ~ 12 | (NEWLINE ~ Entry?)* 13 | } 14 | Dimension = @{ ASCII_DIGIT+ } 15 | Value = @{ ("+" | "-")? ~ NUMBER+ ~ ("." ~ NUMBER+)? ~ ("e" ~ ("+" | "-")? ~ NUMBER+)? } 16 | Entry = { Dimension ~ Dimension ~ Value } -------------------------------------------------------------------------------- /src/io/matrix_market.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::Path; 3 | 4 | use crate::sparse::CsMatrix; 5 | use crate::RealField; 6 | use pest::Parser; 7 | 8 | #[derive(Parser)] 9 | #[grammar = "io/matrix_market.pest"] 10 | struct MatrixMarketParser; 11 | 12 | // TODO: return an Error instead of an Option. 13 | /// Parses a Matrix Market file at the given path, and returns the corresponding sparse matrix. 14 | pub fn cs_matrix_from_matrix_market>(path: P) -> Option> { 15 | let file = fs::read_to_string(path).ok()?; 16 | cs_matrix_from_matrix_market_str(&file) 17 | } 18 | 19 | // TODO: return an Error instead of an Option. 20 | /// Parses a Matrix Market file described by the given string, and returns the corresponding sparse matrix. 21 | pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option> { 22 | let file = MatrixMarketParser::parse(Rule::Document, data) 23 | .unwrap() 24 | .next()?; 25 | let mut shape = (0, 0, 0); 26 | let mut rows: Vec = Vec::new(); 27 | let mut cols: Vec = Vec::new(); 28 | let mut data: Vec = Vec::new(); 29 | 30 | for line in file.into_inner() { 31 | match line.as_rule() { 32 | Rule::Header => {} 33 | Rule::Shape => { 34 | let mut inner = line.into_inner(); 35 | shape.0 = inner.next()?.as_str().parse::().ok()?; 36 | shape.1 = inner.next()?.as_str().parse::().ok()?; 37 | shape.2 = inner.next()?.as_str().parse::().ok()?; 38 | } 39 | Rule::Entry => { 40 | let mut inner = line.into_inner(); 41 | // NOTE: indices are 1-based. 42 | rows.push(inner.next()?.as_str().parse::().ok()? - 1); 43 | cols.push(inner.next()?.as_str().parse::().ok()? - 1); 44 | data.push(crate::convert(inner.next()?.as_str().parse::().ok()?)); 45 | } 46 | _ => return None, // TODO: return an Err instead. 47 | } 48 | } 49 | 50 | Some(CsMatrix::from_triplet( 51 | shape.0, shape.1, &rows, &cols, &data, 52 | )) 53 | } 54 | -------------------------------------------------------------------------------- /src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Parsers for various matrix formats. 2 | 3 | pub use self::matrix_market::{cs_matrix_from_matrix_market, cs_matrix_from_matrix_market_str}; 4 | 5 | mod matrix_market; 6 | -------------------------------------------------------------------------------- /src/linalg/mod.rs: -------------------------------------------------------------------------------- 1 | //! [Reexported at the root of this crate.] Factorization of real matrices. 2 | 3 | pub mod balancing; 4 | mod bidiagonal; 5 | mod cholesky; 6 | mod convolution; 7 | mod determinant; 8 | // TODO: this should not be needed. However, the exp uses 9 | // explicit float operations on `f32` and `f64`. We need to 10 | // get rid of these to allow exp to be used on a no-std context. 11 | mod col_piv_qr; 12 | mod decomposition; 13 | #[cfg(feature = "std")] 14 | mod exp; 15 | mod full_piv_lu; 16 | pub mod givens; 17 | mod hessenberg; 18 | pub mod householder; 19 | mod inverse; 20 | mod lu; 21 | mod permutation_sequence; 22 | mod pow; 23 | mod qr; 24 | mod schur; 25 | mod solve; 26 | mod svd; 27 | mod svd2; 28 | mod svd3; 29 | mod symmetric_eigen; 30 | mod symmetric_tridiagonal; 31 | mod udu; 32 | 33 | // TODO: Not complete enough for publishing. 34 | // This handles only cases where each eigenvalue has multiplicity one. 35 | // mod eigen; 36 | 37 | pub use self::bidiagonal::*; 38 | pub use self::cholesky::*; 39 | pub use self::col_piv_qr::*; 40 | pub use self::full_piv_lu::*; 41 | pub use self::hessenberg::*; 42 | pub use self::lu::*; 43 | pub use self::permutation_sequence::*; 44 | pub use self::qr::*; 45 | pub use self::schur::*; 46 | pub use self::svd::*; 47 | pub use self::symmetric_eigen::*; 48 | pub use self::symmetric_tridiagonal::*; 49 | pub use self::udu::*; 50 | -------------------------------------------------------------------------------- /src/linalg/svd2.rs: -------------------------------------------------------------------------------- 1 | use crate::{Matrix2, RealField, Vector2, SVD, U2}; 2 | 3 | // Implementation of the 2D SVD from https://ieeexplore.ieee.org/document/486688 4 | // See also https://scicomp.stackexchange.com/questions/8899/robust-algorithm-for-2-times-2-svd 5 | pub fn svd_ordered2( 6 | m: &Matrix2, 7 | compute_u: bool, 8 | compute_v: bool, 9 | ) -> SVD { 10 | let half: T = crate::convert(0.5); 11 | let one: T = crate::convert(1.0); 12 | 13 | let e = (m.m11.clone() + m.m22.clone()) * half.clone(); 14 | let f = (m.m11.clone() - m.m22.clone()) * half.clone(); 15 | let g = (m.m21.clone() + m.m12.clone()) * half.clone(); 16 | let h = (m.m21.clone() - m.m12.clone()) * half.clone(); 17 | let q = (e.clone() * e.clone() + h.clone() * h.clone()).sqrt(); 18 | let r = (f.clone() * f.clone() + g.clone() * g.clone()).sqrt(); 19 | 20 | // Note that the singular values are always sorted because sx >= sy 21 | // because q >= 0 and r >= 0. 22 | let sx = q.clone() + r.clone(); 23 | let sy = q - r; 24 | let sy_sign = if sy < T::zero() { -one } else { one }; 25 | let singular_values = Vector2::new(sx, sy * sy_sign.clone()); 26 | 27 | if compute_u || compute_v { 28 | let a1 = g.atan2(f); 29 | let a2 = h.atan2(e); 30 | let theta = (a2.clone() - a1.clone()) * half.clone(); 31 | let phi = (a2 + a1) * half; 32 | let (st, ct) = theta.sin_cos(); 33 | let (sp, cp) = phi.sin_cos(); 34 | 35 | let u = Matrix2::new(cp.clone(), -sp.clone(), sp, cp); 36 | let v_t = Matrix2::new(ct.clone(), -st.clone(), st * sy_sign.clone(), ct * sy_sign); 37 | 38 | SVD { 39 | u: if compute_u { Some(u) } else { None }, 40 | singular_values, 41 | v_t: if compute_v { Some(v_t) } else { None }, 42 | } 43 | } else { 44 | SVD { 45 | u: None, 46 | singular_values, 47 | v_t: None, 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/linalg/svd3.rs: -------------------------------------------------------------------------------- 1 | use crate::{Matrix3, SVD, U3}; 2 | use simba::scalar::RealField; 3 | 4 | // For the 3x3 case, on the GPU, it is much more efficient to compute the SVD 5 | // using an eigendecomposition followed by a QR decomposition. 6 | // 7 | // This is based on the paper "Computing the Singular Value Decomposition of 3 x 3 matrices with 8 | // minimal branching and elementary floating point operations" from McAdams, et al. 9 | pub fn svd_ordered3( 10 | m: &Matrix3, 11 | compute_u: bool, 12 | compute_v: bool, 13 | eps: T, 14 | niter: usize, 15 | ) -> Option> { 16 | let s = m.tr_mul(m); 17 | let mut v = s.try_symmetric_eigen(eps, niter)?.eigenvectors; 18 | let mut b = m * &v; 19 | 20 | // Sort singular values. This is a necessary step to ensure that 21 | // the QR decompositions R matrix ends up diagonal. 22 | let mut rho0 = b.column(0).norm_squared(); 23 | let mut rho1 = b.column(1).norm_squared(); 24 | let mut rho2 = b.column(2).norm_squared(); 25 | 26 | if rho0 < rho1 { 27 | b.swap_columns(0, 1); 28 | b.column_mut(1).neg_mut(); 29 | v.swap_columns(0, 1); 30 | v.column_mut(1).neg_mut(); 31 | std::mem::swap(&mut rho0, &mut rho1); 32 | } 33 | if rho0 < rho2 { 34 | b.swap_columns(0, 2); 35 | b.column_mut(2).neg_mut(); 36 | v.swap_columns(0, 2); 37 | v.column_mut(2).neg_mut(); 38 | std::mem::swap(&mut rho0, &mut rho2); 39 | } 40 | if rho1 < rho2 { 41 | b.swap_columns(1, 2); 42 | b.column_mut(2).neg_mut(); 43 | v.swap_columns(1, 2); 44 | v.column_mut(2).neg_mut(); 45 | std::mem::swap(&mut rho0, &mut rho2); 46 | } 47 | 48 | let qr = b.qr(); 49 | 50 | Some(SVD { 51 | u: if compute_u { Some(qr.q()) } else { None }, 52 | singular_values: qr.diag_internal().map(|e| e.abs()), 53 | v_t: if compute_v { Some(v.transpose()) } else { None }, 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /src/sparse/cs_utils.rs: -------------------------------------------------------------------------------- 1 | use crate::allocator::Allocator; 2 | use crate::{DefaultAllocator, Dim, OVector}; 3 | 4 | pub fn cumsum(a: &mut OVector, b: &mut OVector) -> usize 5 | where 6 | DefaultAllocator: Allocator, 7 | { 8 | assert!(a.len() == b.len()); 9 | let mut sum = 0; 10 | 11 | for i in 0..a.len() { 12 | b[i] = sum; 13 | sum += a[i]; 14 | a[i] = b[i]; 15 | } 16 | 17 | sum 18 | } 19 | -------------------------------------------------------------------------------- /src/sparse/mod.rs: -------------------------------------------------------------------------------- 1 | //! Sparse matrices. 2 | 3 | pub use self::cs_matrix::{ 4 | CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsStorageMut, CsVecStorage, CsVector, 5 | }; 6 | pub use self::cs_matrix_cholesky::CsCholesky; 7 | 8 | mod cs_matrix; 9 | mod cs_matrix_cholesky; 10 | mod cs_matrix_conversion; 11 | mod cs_matrix_ops; 12 | mod cs_matrix_solve; 13 | pub(crate) mod cs_utils; 14 | -------------------------------------------------------------------------------- /src/third_party/alga/alga_point.rs: -------------------------------------------------------------------------------- 1 | use alga::general::{Field, JoinSemilattice, Lattice, MeetSemilattice, RealField}; 2 | use alga::linear::{AffineSpace, EuclideanSpace}; 3 | 4 | use crate::base::{SVector, Scalar}; 5 | 6 | use crate::geometry::Point; 7 | 8 | impl AffineSpace for Point 9 | where 10 | T: Scalar + Field, 11 | { 12 | type Translation = SVector; 13 | } 14 | 15 | impl EuclideanSpace for Point { 16 | type Coordinates = SVector; 17 | type RealField = T; 18 | 19 | #[inline] 20 | fn origin() -> Self { 21 | Self::origin() 22 | } 23 | 24 | #[inline] 25 | fn coordinates(&self) -> Self::Coordinates { 26 | self.coords 27 | } 28 | 29 | #[inline] 30 | fn from_coordinates(coords: Self::Coordinates) -> Self { 31 | Self::from(coords) 32 | } 33 | 34 | #[inline] 35 | fn scale_by(&self, n: T) -> Self { 36 | self * n 37 | } 38 | } 39 | 40 | /* 41 | * 42 | * Ordering 43 | * 44 | */ 45 | impl MeetSemilattice for Point 46 | where 47 | T: Scalar + MeetSemilattice, 48 | { 49 | #[inline] 50 | fn meet(&self, other: &Self) -> Self { 51 | Self::from(self.coords.meet(&other.coords)) 52 | } 53 | } 54 | 55 | impl JoinSemilattice for Point 56 | where 57 | T: Scalar + JoinSemilattice, 58 | { 59 | #[inline] 60 | fn join(&self, other: &Self) -> Self { 61 | Self::from(self.coords.join(&other.coords)) 62 | } 63 | } 64 | 65 | impl Lattice for Point 66 | where 67 | T: Scalar + Lattice, 68 | { 69 | #[inline] 70 | fn meet_join(&self, other: &Self) -> (Self, Self) { 71 | let (meet, join) = self.coords.meet_join(&other.coords); 72 | 73 | (Self::from(meet), Self::from(join)) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/third_party/alga/mod.rs: -------------------------------------------------------------------------------- 1 | mod alga_dual_quaternion; 2 | mod alga_isometry; 3 | mod alga_matrix; 4 | mod alga_point; 5 | mod alga_quaternion; 6 | mod alga_rotation; 7 | mod alga_similarity; 8 | mod alga_transform; 9 | mod alga_translation; 10 | mod alga_unit_complex; 11 | -------------------------------------------------------------------------------- /src/third_party/glam/common/glam_point.rs: -------------------------------------------------------------------------------- 1 | use super::glam::{ 2 | BVec2, BVec3, BVec4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, Vec2, Vec3, 3 | Vec3A, Vec4, 4 | }; 5 | use crate::{Point2, Point3, Point4}; 6 | 7 | macro_rules! impl_point_conversion( 8 | ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { 9 | impl From<$Vec2> for Point2<$N> { 10 | #[inline] 11 | fn from(e: $Vec2) -> Point2<$N> { 12 | <[$N;2]>::from(e).into() 13 | } 14 | } 15 | 16 | impl From> for $Vec2 { 17 | #[inline] 18 | fn from(e: Point2<$N>) -> $Vec2 { 19 | <$Vec2>::new(e[0], e[1]) 20 | } 21 | } 22 | 23 | impl From<$Vec3> for Point3<$N> { 24 | #[inline] 25 | fn from(e: $Vec3) -> Point3<$N> { 26 | <[$N;3]>::from(e).into() 27 | } 28 | } 29 | 30 | impl From> for $Vec3 { 31 | #[inline] 32 | fn from(e: Point3<$N>) -> $Vec3 { 33 | <$Vec3>::new(e[0], e[1], e[2]) 34 | } 35 | } 36 | 37 | impl From<$Vec4> for Point4<$N> { 38 | #[inline] 39 | fn from(e: $Vec4) -> Point4<$N> { 40 | <[$N;4]>::from(e).into() 41 | } 42 | } 43 | 44 | impl From> for $Vec4 { 45 | #[inline] 46 | fn from(e: Point4<$N>) -> $Vec4 { 47 | <$Vec4>::new(e[0], e[1], e[2], e[3]) 48 | } 49 | } 50 | } 51 | ); 52 | 53 | impl_point_conversion!(f32, Vec2, Vec3, Vec4); 54 | impl_point_conversion!(f64, DVec2, DVec3, DVec4); 55 | impl_point_conversion!(i32, IVec2, IVec3, IVec4); 56 | impl_point_conversion!(u32, UVec2, UVec3, UVec4); 57 | impl_point_conversion!(bool, BVec2, BVec3, BVec4); 58 | 59 | impl From for Point3 { 60 | #[inline] 61 | fn from(e: Vec3A) -> Point3 { 62 | (*e.as_ref()).into() 63 | } 64 | } 65 | 66 | impl From> for Vec3A { 67 | #[inline] 68 | fn from(e: Point3) -> Vec3A { 69 | Vec3A::new(e[0], e[1], e[2]) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/third_party/glam/common/glam_quaternion.rs: -------------------------------------------------------------------------------- 1 | use super::glam::{DQuat, Quat}; 2 | use crate::{Quaternion, UnitQuaternion}; 3 | 4 | impl From for Quaternion { 5 | #[inline] 6 | fn from(e: Quat) -> Quaternion { 7 | Quaternion::new(e.w, e.x, e.y, e.z) 8 | } 9 | } 10 | 11 | impl From> for Quat { 12 | #[inline] 13 | fn from(e: Quaternion) -> Quat { 14 | Quat::from_xyzw(e.i, e.j, e.k, e.w) 15 | } 16 | } 17 | 18 | impl From> for Quat { 19 | #[inline] 20 | fn from(e: UnitQuaternion) -> Quat { 21 | Quat::from_xyzw(e.i, e.j, e.k, e.w) 22 | } 23 | } 24 | 25 | impl From for Quaternion { 26 | #[inline] 27 | fn from(e: DQuat) -> Quaternion { 28 | Quaternion::new(e.w, e.x, e.y, e.z) 29 | } 30 | } 31 | 32 | impl From> for DQuat { 33 | #[inline] 34 | fn from(e: Quaternion) -> DQuat { 35 | DQuat::from_xyzw(e.i, e.j, e.k, e.w) 36 | } 37 | } 38 | 39 | impl From> for DQuat { 40 | #[inline] 41 | fn from(e: UnitQuaternion) -> DQuat { 42 | DQuat::from_xyzw(e.i, e.j, e.k, e.w) 43 | } 44 | } 45 | 46 | impl From for UnitQuaternion { 47 | #[inline] 48 | fn from(e: Quat) -> UnitQuaternion { 49 | UnitQuaternion::new_normalize(Quaternion::from(e)) 50 | } 51 | } 52 | 53 | impl From for UnitQuaternion { 54 | #[inline] 55 | fn from(e: DQuat) -> UnitQuaternion { 56 | UnitQuaternion::new_normalize(Quaternion::from(e)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/third_party/glam/common/glam_rotation.rs: -------------------------------------------------------------------------------- 1 | use super::glam::{DMat2, DQuat, Mat2, Quat}; 2 | use crate::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; 3 | 4 | impl From> for Mat2 { 5 | #[inline] 6 | fn from(e: Rotation2) -> Mat2 { 7 | e.into_inner().into() 8 | } 9 | } 10 | 11 | impl From> for DMat2 { 12 | #[inline] 13 | fn from(e: Rotation2) -> DMat2 { 14 | e.into_inner().into() 15 | } 16 | } 17 | 18 | impl From> for Quat { 19 | #[inline] 20 | fn from(e: Rotation3) -> Quat { 21 | UnitQuaternion::from(e).into() 22 | } 23 | } 24 | 25 | impl From> for DQuat { 26 | #[inline] 27 | fn from(e: Rotation3) -> DQuat { 28 | UnitQuaternion::from(e).into() 29 | } 30 | } 31 | 32 | impl From for Rotation2 { 33 | #[inline] 34 | fn from(e: Mat2) -> Rotation2 { 35 | UnitComplex::from(e).to_rotation_matrix() 36 | } 37 | } 38 | 39 | impl From for Rotation2 { 40 | #[inline] 41 | fn from(e: DMat2) -> Rotation2 { 42 | UnitComplex::from(e).to_rotation_matrix() 43 | } 44 | } 45 | 46 | impl From for Rotation3 { 47 | #[inline] 48 | fn from(e: Quat) -> Rotation3 { 49 | Rotation3::from(UnitQuaternion::from(e)) 50 | } 51 | } 52 | 53 | impl From for Rotation3 { 54 | #[inline] 55 | fn from(e: DQuat) -> Rotation3 { 56 | Rotation3::from(UnitQuaternion::from(e)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/third_party/glam/common/glam_similarity.rs: -------------------------------------------------------------------------------- 1 | use super::glam::{DMat3, DMat4, Mat3, Mat4}; 2 | use crate::{Matrix3, Matrix4, Similarity2, Similarity3}; 3 | use std::convert::TryFrom; 4 | 5 | impl From> for Mat3 { 6 | fn from(iso: Similarity2) -> Mat3 { 7 | iso.to_homogeneous().into() 8 | } 9 | } 10 | impl From> for Mat4 { 11 | fn from(iso: Similarity3) -> Mat4 { 12 | iso.to_homogeneous().into() 13 | } 14 | } 15 | 16 | impl From> for DMat3 { 17 | fn from(iso: Similarity2) -> DMat3 { 18 | iso.to_homogeneous().into() 19 | } 20 | } 21 | impl From> for DMat4 { 22 | fn from(iso: Similarity3) -> DMat4 { 23 | iso.to_homogeneous().into() 24 | } 25 | } 26 | 27 | impl TryFrom for Similarity2 { 28 | type Error = (); 29 | fn try_from(mat3: Mat3) -> Result, ()> { 30 | crate::try_convert(Matrix3::from(mat3)).ok_or(()) 31 | } 32 | } 33 | 34 | impl TryFrom for Similarity3 { 35 | type Error = (); 36 | fn try_from(mat4: Mat4) -> Result, ()> { 37 | crate::try_convert(Matrix4::from(mat4)).ok_or(()) 38 | } 39 | } 40 | 41 | impl TryFrom for Similarity2 { 42 | type Error = (); 43 | fn try_from(mat3: DMat3) -> Result, ()> { 44 | crate::try_convert(Matrix3::from(mat3)).ok_or(()) 45 | } 46 | } 47 | 48 | impl TryFrom for Similarity3 { 49 | type Error = (); 50 | fn try_from(mat4: DMat4) -> Result, ()> { 51 | crate::try_convert(Matrix4::from(mat4)).ok_or(()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/third_party/glam/common/glam_translation.rs: -------------------------------------------------------------------------------- 1 | use super::glam::{DVec2, DVec3, DVec4, Vec2, Vec3, Vec3A, Vec4}; 2 | use crate::{Translation2, Translation3, Translation4}; 3 | 4 | macro_rules! impl_translation_conversion( 5 | ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { 6 | impl From<$Vec2> for Translation2<$N> { 7 | #[inline] 8 | fn from(e: $Vec2) -> Translation2<$N> { 9 | (*e.as_ref()).into() 10 | } 11 | } 12 | 13 | impl From> for $Vec2 { 14 | #[inline] 15 | fn from(e: Translation2<$N>) -> $Vec2 { 16 | e.vector.into() 17 | } 18 | } 19 | 20 | impl From<$Vec3> for Translation3<$N> { 21 | #[inline] 22 | fn from(e: $Vec3) -> Translation3<$N> { 23 | (*e.as_ref()).into() 24 | } 25 | } 26 | 27 | impl From> for $Vec3 { 28 | #[inline] 29 | fn from(e: Translation3<$N>) -> $Vec3 { 30 | e.vector.into() 31 | } 32 | } 33 | 34 | impl From<$Vec4> for Translation4<$N> { 35 | #[inline] 36 | fn from(e: $Vec4) -> Translation4<$N> { 37 | (*e.as_ref()).into() 38 | } 39 | } 40 | 41 | impl From> for $Vec4 { 42 | #[inline] 43 | fn from(e: Translation4<$N>) -> $Vec4 { 44 | e.vector.into() 45 | } 46 | } 47 | } 48 | ); 49 | 50 | impl_translation_conversion!(f32, Vec2, Vec3, Vec4); 51 | impl_translation_conversion!(f64, DVec2, DVec3, DVec4); 52 | 53 | impl From for Translation3 { 54 | #[inline] 55 | fn from(e: Vec3A) -> Translation3 { 56 | (*e.as_ref()).into() 57 | } 58 | } 59 | 60 | impl From> for Vec3A { 61 | #[inline] 62 | fn from(e: Translation3) -> Vec3A { 63 | e.vector.into() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/third_party/glam/common/glam_unit_complex.rs: -------------------------------------------------------------------------------- 1 | use super::glam::{DMat2, Mat2}; 2 | use crate::{Complex, UnitComplex}; 3 | 4 | impl From> for Mat2 { 5 | #[inline] 6 | fn from(e: UnitComplex) -> Mat2 { 7 | e.to_rotation_matrix().into_inner().into() 8 | } 9 | } 10 | 11 | impl From> for DMat2 { 12 | #[inline] 13 | fn from(e: UnitComplex) -> DMat2 { 14 | e.to_rotation_matrix().into_inner().into() 15 | } 16 | } 17 | 18 | impl From for UnitComplex { 19 | #[inline] 20 | fn from(e: Mat2) -> UnitComplex { 21 | UnitComplex::new_normalize(Complex::new(e.x_axis.x, e.x_axis.y)) 22 | } 23 | } 24 | 25 | impl From for UnitComplex { 26 | #[inline] 27 | fn from(e: DMat2) -> UnitComplex { 28 | UnitComplex::new_normalize(Complex::new(e.x_axis.x, e.x_axis.y)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/third_party/glam/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "glam014")] 2 | mod v014; 3 | #[cfg(feature = "glam015")] 4 | mod v015; 5 | #[cfg(feature = "glam016")] 6 | mod v016; 7 | #[cfg(feature = "glam017")] 8 | mod v017; 9 | #[cfg(feature = "glam018")] 10 | mod v018; 11 | #[cfg(feature = "glam019")] 12 | mod v019; 13 | #[cfg(feature = "glam020")] 14 | mod v020; 15 | #[cfg(feature = "glam021")] 16 | mod v021; 17 | #[cfg(feature = "glam022")] 18 | mod v022; 19 | #[cfg(feature = "glam023")] 20 | mod v023; 21 | #[cfg(feature = "glam024")] 22 | mod v024; 23 | #[cfg(feature = "glam025")] 24 | mod v025; 25 | #[cfg(feature = "glam027")] 26 | mod v027; 27 | #[cfg(feature = "glam028")] 28 | mod v028; 29 | #[cfg(feature = "glam029")] 30 | mod v029; 31 | #[cfg(feature = "glam030")] 32 | mod v030; 33 | -------------------------------------------------------------------------------- /src/third_party/glam/v014/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam014 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v015/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam015 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v016/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam016 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v017/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam017 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v018/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam018 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v019/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam019 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v020/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam020 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v021/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam021 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v022/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam022 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v023/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam023 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v024/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam024 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v025/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam025 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v027/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam027 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v028/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam028 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v029/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam029 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/glam/v030/mod.rs: -------------------------------------------------------------------------------- 1 | #[path = "../common/glam_isometry.rs"] 2 | mod glam_isometry; 3 | #[path = "../common/glam_matrix.rs"] 4 | mod glam_matrix; 5 | #[path = "../common/glam_point.rs"] 6 | mod glam_point; 7 | #[path = "../common/glam_quaternion.rs"] 8 | mod glam_quaternion; 9 | #[path = "../common/glam_rotation.rs"] 10 | mod glam_rotation; 11 | #[path = "../common/glam_similarity.rs"] 12 | mod glam_similarity; 13 | #[path = "../common/glam_translation.rs"] 14 | mod glam_translation; 15 | #[path = "../common/glam_unit_complex.rs"] 16 | mod glam_unit_complex; 17 | 18 | pub(self) use glam030 as glam; 19 | -------------------------------------------------------------------------------- /src/third_party/mint/mint_point.rs: -------------------------------------------------------------------------------- 1 | use crate::base::storage::{RawStorage, RawStorageMut}; 2 | use crate::{OVector, Point, Scalar}; 3 | use std::convert::{AsMut, AsRef}; 4 | 5 | macro_rules! impl_from_into_mint_1D( 6 | ($($NRows: expr => $PT:ident, $VT:ident [$SZ: expr]);* $(;)*) => {$( 7 | impl From> for Point 8 | where T: Scalar { 9 | #[inline] 10 | fn from(p: mint::$PT) -> Self { 11 | Self { 12 | coords: OVector::from(mint::$VT::from(p)), 13 | } 14 | } 15 | } 16 | 17 | impl Into> for Point 18 | where T: Scalar { 19 | #[inline] 20 | fn into(self) -> mint::$PT { 21 | let mint_vec: mint::$VT = self.coords.into(); 22 | mint::$PT::from(mint_vec) 23 | } 24 | } 25 | 26 | impl AsRef> for Point 27 | where T: Scalar { 28 | #[inline] 29 | fn as_ref(&self) -> &mint::$PT { 30 | unsafe { 31 | &*(self.coords.data.ptr() as *const mint::$PT) 32 | } 33 | } 34 | } 35 | 36 | impl AsMut> for Point 37 | where T: Scalar { 38 | #[inline] 39 | fn as_mut(&mut self) -> &mut mint::$PT { 40 | unsafe { 41 | &mut *(self.coords.data.ptr_mut() as *mut mint::$PT) 42 | } 43 | } 44 | } 45 | )*} 46 | ); 47 | 48 | // Implement for points of dimension 2, 3. 49 | impl_from_into_mint_1D!( 50 | 2 => Point2, Vector2[2]; 51 | 3 => Point3, Vector3[3]; 52 | ); 53 | -------------------------------------------------------------------------------- /src/third_party/mint/mint_quaternion.rs: -------------------------------------------------------------------------------- 1 | use crate::{Quaternion, Scalar, SimdValue, UnitQuaternion}; 2 | 3 | impl From> for Quaternion { 4 | fn from(q: mint::Quaternion) -> Self { 5 | Self::new(q.s, q.v.x, q.v.y, q.v.z) 6 | } 7 | } 8 | 9 | impl Into> for Quaternion { 10 | fn into(self) -> mint::Quaternion { 11 | mint::Quaternion { 12 | v: mint::Vector3 { 13 | x: self[0].clone(), 14 | y: self[1].clone(), 15 | z: self[2].clone(), 16 | }, 17 | s: self[3].clone(), 18 | } 19 | } 20 | } 21 | 22 | impl Into> for UnitQuaternion { 23 | fn into(self) -> mint::Quaternion { 24 | mint::Quaternion { 25 | v: mint::Vector3 { 26 | x: self[0].clone(), 27 | y: self[1].clone(), 28 | z: self[2].clone(), 29 | }, 30 | s: self[3].clone(), 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/third_party/mint/mint_rotation.rs: -------------------------------------------------------------------------------- 1 | use crate::{RealField, Rotation3}; 2 | 3 | impl From> for Rotation3 { 4 | fn from(euler: mint::EulerAngles) -> Self { 5 | Self::from_euler_angles(euler.a, euler.b, euler.c) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/third_party/mint/mod.rs: -------------------------------------------------------------------------------- 1 | mod mint_matrix; 2 | mod mint_point; 3 | mod mint_quaternion; 4 | mod mint_rotation; 5 | -------------------------------------------------------------------------------- /src/third_party/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "alga")] 2 | mod alga; 3 | mod glam; 4 | #[cfg(feature = "mint")] 5 | mod mint; 6 | -------------------------------------------------------------------------------- /tests/core/cg.rs: -------------------------------------------------------------------------------- 1 | use na::{Matrix3, Matrix4, Point2, Point3, Vector2, Vector3}; 2 | 3 | /// See Example 3.4 of "Graphics and Visualization: Principles & Algorithms" 4 | /// by Theoharis, Papaioannou, Platis, Patrikalakis. 5 | #[test] 6 | fn test_scaling_wrt_point_1() { 7 | let a = Point2::new(0.0, 0.0); 8 | let b = Point2::new(1.0, 1.0); 9 | let c = Point2::new(5.0, 2.0); 10 | 11 | let scaling = Vector2::new(2.0, 2.0); 12 | let scale_about = Matrix3::new_nonuniform_scaling_wrt_point(&scaling, &c); 13 | 14 | let expected_a = Point2::new(-5.0, -2.0); 15 | let expected_b = Point2::new(-3.0, 0.0); 16 | let result_a = scale_about.transform_point(&a); 17 | let result_b = scale_about.transform_point(&b); 18 | let result_c = scale_about.transform_point(&c); 19 | 20 | assert!(expected_a == result_a); 21 | assert!(expected_b == result_b); 22 | assert!(c == result_c); 23 | } 24 | 25 | /// Based on the same example as the test above. 26 | #[test] 27 | fn test_scaling_wrt_point_2() { 28 | let a = Point3::new(0.0, 0.0, 1.0); 29 | let b = Point3::new(1.0, 1.0, 1.0); 30 | let c = Point3::new(5.0, 2.0, 1.0); 31 | 32 | let scaling = Vector3::new(2.0, 2.0, 1.0); 33 | let scale_about = Matrix4::new_nonuniform_scaling_wrt_point(&scaling, &c); 34 | 35 | let expected_a = Point3::new(-5.0, -2.0, 1.0); 36 | let expected_b = Point3::new(-3.0, 0.0, 1.0); 37 | 38 | let result_a = scale_about.transform_point(&a); 39 | let result_b = scale_about.transform_point(&b); 40 | let result_c = scale_about.transform_point(&c); 41 | 42 | assert!(expected_a == result_a); 43 | assert!(expected_b == result_b); 44 | assert!(c == result_c); 45 | } 46 | 47 | /// Based on https://github.com/emlowry/AiE/blob/50bae4068edb686cf8ffacdf6fab8e7cb22e7eb1/Year%201%20Classwork/MathTest/Matrix4x4TestGroup.cpp#L145 48 | #[test] 49 | fn test_scaling_wrt_point_3() { 50 | let about = Point3::new(2.0, 1.0, -2.0); 51 | let scale = Vector3::new(2.0, 0.5, -1.0); 52 | let pt = Point3::new(1.0, 2.0, 3.0); 53 | let scale_about = Matrix4::new_nonuniform_scaling_wrt_point(&scale, &about); 54 | 55 | let expected = Point3::new(0.0, 1.5, -7.0); 56 | let result = scale_about.transform_point(&pt); 57 | 58 | assert!(result == expected); 59 | } 60 | -------------------------------------------------------------------------------- /tests/core/empty.rs: -------------------------------------------------------------------------------- 1 | use na::{DMatrix, DVector}; 2 | 3 | #[test] 4 | fn empty_matrix_mul_vector() { 5 | // Issue #644 6 | let m = DMatrix::::zeros(8, 0); 7 | let v = DVector::::zeros(0); 8 | assert_eq!(m * v, DVector::zeros(8)); 9 | } 10 | 11 | #[test] 12 | fn empty_matrix_mul_matrix() { 13 | let m1 = DMatrix::::zeros(3, 0); 14 | let m2 = DMatrix::::zeros(0, 4); 15 | assert_eq!(m1 * m2, DMatrix::zeros(3, 4)); 16 | 17 | // Still works with larger matrices. 18 | let m1 = DMatrix::::zeros(13, 0); 19 | let m2 = DMatrix::::zeros(0, 14); 20 | assert_eq!(m1 * m2, DMatrix::zeros(13, 14)); 21 | } 22 | 23 | #[test] 24 | fn empty_matrix_tr_mul_vector() { 25 | let m = DMatrix::::zeros(0, 5); 26 | let v = DVector::::zeros(0); 27 | assert_eq!(m.tr_mul(&v), DVector::zeros(5)); 28 | } 29 | 30 | #[test] 31 | fn empty_matrix_tr_mul_matrix() { 32 | let m1 = DMatrix::::zeros(0, 3); 33 | let m2 = DMatrix::::zeros(0, 4); 34 | assert_eq!(m1.tr_mul(&m2), DMatrix::zeros(3, 4)); 35 | } 36 | 37 | #[test] 38 | fn empty_matrix_gemm() { 39 | let mut res = DMatrix::repeat(3, 4, 1.0); 40 | let m1 = DMatrix::::zeros(3, 0); 41 | let m2 = DMatrix::::zeros(0, 4); 42 | res.gemm(1.0, &m1, &m2, 0.5); 43 | assert_eq!(res, DMatrix::repeat(3, 4, 0.5)); 44 | 45 | // Still works with lager matrices. 46 | let mut res = DMatrix::repeat(13, 14, 1.0); 47 | let m1 = DMatrix::::zeros(13, 0); 48 | let m2 = DMatrix::::zeros(0, 14); 49 | res.gemm(1.0, &m1, &m2, 0.5); 50 | assert_eq!(res, DMatrix::repeat(13, 14, 0.5)); 51 | } 52 | 53 | #[test] 54 | fn empty_matrix_gemm_tr() { 55 | let mut res = DMatrix::repeat(3, 4, 1.0); 56 | let m1 = DMatrix::::zeros(0, 3); 57 | let m2 = DMatrix::::zeros(0, 4); 58 | res.gemm_tr(1.0, &m1, &m2, 0.5); 59 | assert_eq!(res, DMatrix::repeat(3, 4, 0.5)); 60 | } 61 | -------------------------------------------------------------------------------- /tests/core/helper.rs: -------------------------------------------------------------------------------- 1 | // This module implement several methods to fill some 2 | // missing features of num-complex when it comes to randomness. 3 | 4 | use na::RealField; 5 | use num_complex::Complex; 6 | use quickcheck::{Arbitrary, Gen}; 7 | use rand::distr::{Distribution, StandardUniform}; 8 | use rand::Rng; 9 | 10 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 11 | pub struct RandComplex(pub Complex); 12 | 13 | impl Arbitrary for RandComplex { 14 | #[inline] 15 | fn arbitrary(rng: &mut Gen) -> Self { 16 | let im = Arbitrary::arbitrary(rng); 17 | let re = Arbitrary::arbitrary(rng); 18 | RandComplex(Complex::new(re, im)) 19 | } 20 | } 21 | 22 | impl Distribution> for StandardUniform 23 | where 24 | StandardUniform: Distribution, 25 | { 26 | #[inline] 27 | fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> RandComplex { 28 | let re = rng.random(); 29 | let im = rng.random(); 30 | RandComplex(Complex::new(re, im)) 31 | } 32 | } 33 | 34 | // This is a wrapper similar to RandComplex, but for non-complex. 35 | // This exists only to make generic tests easier to write. 36 | // 37 | // Generates variates in the range [0, 1). 38 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 39 | pub struct RandScalar(pub T); 40 | 41 | impl Arbitrary for RandScalar { 42 | #[inline] 43 | fn arbitrary(rng: &mut Gen) -> Self { 44 | RandScalar(Arbitrary::arbitrary(rng)) 45 | } 46 | } 47 | 48 | impl Distribution> for StandardUniform 49 | where 50 | StandardUniform: Distribution, 51 | { 52 | #[inline] 53 | fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> RandScalar { 54 | RandScalar(self.sample(rng)) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/core/macros.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::{dmatrix, dvector, matrix, point, vector}; 2 | 3 | #[test] 4 | fn sanity_test() { 5 | // The macros are already tested in `nalgebra-macros`. Here we just test that they compile fine. 6 | 7 | let _ = matrix![1, 2, 3; 4, 5, 6]; 8 | let _ = dmatrix![1, 2, 3; 4, 5, 6]; 9 | let _ = point![1, 2, 3, 4, 5, 6]; 10 | let _ = vector![1, 2, 3, 4, 5, 6]; 11 | let _ = dvector![1, 2, 3, 4, 5, 6]; 12 | } 13 | -------------------------------------------------------------------------------- /tests/core/mod.rs: -------------------------------------------------------------------------------- 1 | mod blas; 2 | mod cg; 3 | mod conversion; 4 | mod edition; 5 | mod empty; 6 | mod matrix; 7 | mod matrix_view; 8 | #[cfg(feature = "mint")] 9 | mod mint; 10 | mod reshape; 11 | #[cfg(feature = "rkyv-serialize-no-std")] 12 | mod rkyv; 13 | mod serde; 14 | mod variance; 15 | 16 | #[cfg(feature = "compare")] 17 | mod matrixcompare; 18 | 19 | #[cfg(feature = "arbitrary")] 20 | pub mod helper; 21 | 22 | #[cfg(feature = "macros")] 23 | mod macros; 24 | -------------------------------------------------------------------------------- /tests/core/variance.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::DVector; 2 | 3 | #[test] 4 | fn test_variance_catastrophic_cancellation() { 5 | let long_repeating_vector = DVector::repeat(10_000, 100000000.0); 6 | assert_eq!(long_repeating_vector.variance(), 0.0); 7 | 8 | let short_vec = DVector::from_vec(vec![1., 2., 3.]); 9 | assert_eq!(short_vec.variance(), 2.0 / 3.0); 10 | 11 | let short_vec = 12 | DVector::::from_vec(vec![1.0e8 + 4.0, 1.0e8 + 7.0, 1.0e8 + 13.0, 1.0e8 + 16.0]); 13 | assert_eq!(short_vec.variance(), 22.5); 14 | 15 | let short_vec = 16 | DVector::::from_vec(vec![1.0e9 + 4.0, 1.0e9 + 7.0, 1.0e9 + 13.0, 1.0e9 + 16.0]); 17 | assert_eq!(short_vec.variance(), 22.5); 18 | } 19 | -------------------------------------------------------------------------------- /tests/geometry/mod.rs: -------------------------------------------------------------------------------- 1 | mod dual_quaternion; 2 | mod isometry; 3 | mod point; 4 | mod projection; 5 | mod quaternion; 6 | mod rotation; 7 | mod similarity; 8 | mod unit_complex; 9 | -------------------------------------------------------------------------------- /tests/geometry/projection.rs: -------------------------------------------------------------------------------- 1 | use na::{Orthographic3, Perspective3, Point3}; 2 | 3 | #[test] 4 | fn perspective_inverse() { 5 | let proj = Perspective3::new(800.0 / 600.0, 3.14 / 2.0, 1.0, 1000.0); 6 | let inv = proj.inverse(); 7 | 8 | let id = inv * proj.into_inner(); 9 | 10 | assert!(id.is_identity(1.0e-7)); 11 | } 12 | 13 | #[test] 14 | fn orthographic_inverse() { 15 | let proj = Orthographic3::new(1.0, 2.0, -3.0, -2.5, 10.0, 900.0); 16 | let inv = proj.inverse(); 17 | 18 | let id = inv * proj.into_inner(); 19 | 20 | assert!(id.is_identity(1.0e-7)); 21 | } 22 | 23 | #[test] 24 | fn perspective_matrix_point_transformation() { 25 | // https://github.com/dimforge/nalgebra/issues/640 26 | let proj = Perspective3::new(4.0 / 3.0, 90.0, 0.1, 100.0); 27 | let perspective_inv = proj.as_matrix().try_inverse().unwrap(); 28 | let some_point = Point3::new(1.0, 2.0, 0.0); 29 | 30 | assert_eq!( 31 | perspective_inv.transform_point(&some_point), 32 | Point3::from_homogeneous(perspective_inv * some_point.coords.push(1.0)).unwrap() 33 | ); 34 | } 35 | 36 | #[cfg(feature = "proptest-support")] 37 | mod proptest_tests { 38 | use na::{Orthographic3, Perspective3}; 39 | 40 | use crate::proptest::*; 41 | use proptest::{prop_assert, proptest}; 42 | 43 | proptest! { 44 | #[test] 45 | fn perspective_project_unproject(pt in point3()) { 46 | let proj = Perspective3::new(800.0 / 600.0, 3.14 / 2.0, 1.0, 1000.0); 47 | 48 | let projected = proj.project_point(&pt); 49 | let unprojected = proj.unproject_point(&projected); 50 | 51 | prop_assert!(relative_eq!(pt, unprojected, epsilon = 1.0e-7)) 52 | } 53 | 54 | #[test] 55 | fn orthographic_project_unproject(pt in point3()) { 56 | let proj = Orthographic3::new(1.0, 2.0, -3.0, -2.5, 10.0, 900.0); 57 | 58 | let projected = proj.project_point(&pt); 59 | let unprojected = proj.unproject_point(&projected); 60 | 61 | prop_assert!(relative_eq!(pt, unprojected, epsilon = 1.0e-7)) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(all( 2 | feature = "debug", 3 | feature = "compare", 4 | feature = "rand", 5 | feature = "macros" 6 | )))] 7 | compile_error!( 8 | "Please enable the `debug`, `compare`, `rand` and `macros` features in order to compile and run the tests. 9 | Example: `cargo test --features debug,compare,rand,macros`" 10 | ); 11 | 12 | #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] 13 | #[macro_use] 14 | extern crate approx; 15 | extern crate nalgebra as na; 16 | extern crate num_traits as num; 17 | #[cfg(feature = "rand")] 18 | extern crate rand_package as rand; 19 | 20 | #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] 21 | mod core; 22 | #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] 23 | mod geometry; 24 | #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] 25 | mod linalg; 26 | 27 | #[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] 28 | #[cfg(feature = "proptest-support")] 29 | mod proptest; 30 | 31 | #[cfg(feature = "macros")] 32 | mod macros; 33 | 34 | //#[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] 35 | //#[cfg(feature = "sparse")] 36 | //mod sparse; 37 | 38 | mod utils { 39 | /// Checks if a slice is sorted in descending order. 40 | pub fn is_sorted_descending(slice: &[T]) -> bool { 41 | slice.windows(2).all(|elts| elts[0] >= elts[1]) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/linalg/balancing.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "proptest-support")] 2 | 3 | use na::balancing; 4 | use na::DMatrix; 5 | 6 | use crate::proptest::*; 7 | use proptest::{prop_assert_eq, proptest}; 8 | 9 | proptest! { 10 | #[test] 11 | fn balancing_parlett_reinsch(n in PROPTEST_MATRIX_DIM) { 12 | let m = DMatrix::::new_random(n, n); 13 | let mut balanced = m.clone(); 14 | let d = balancing::balance_parlett_reinsch(&mut balanced); 15 | balancing::unbalance(&mut balanced, &d); 16 | 17 | prop_assert_eq!(balanced, m); 18 | } 19 | 20 | #[test] 21 | fn balancing_parlett_reinsch_static(m in matrix4()) { 22 | let mut balanced = m; 23 | let d = balancing::balance_parlett_reinsch(&mut balanced); 24 | balancing::unbalance(&mut balanced, &d); 25 | 26 | prop_assert_eq!(balanced, m); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/linalg/hessenberg.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "proptest-support")] 2 | 3 | use na::Matrix2; 4 | 5 | #[test] 6 | fn hessenberg_simple() { 7 | let m = Matrix2::new(1.0, 0.0, 1.0, 3.0); 8 | let hess = m.hessenberg(); 9 | let (p, h) = hess.unpack(); 10 | assert!(relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7)) 11 | } 12 | 13 | macro_rules! gen_tests( 14 | ($module: ident, $scalar: expr, $scalar_type: ty) => { 15 | mod $module { 16 | use na::DMatrix; 17 | #[allow(unused_imports)] 18 | use crate::core::helper::{RandScalar, RandComplex}; 19 | 20 | use crate::proptest::*; 21 | use proptest::{prop_assert, proptest}; 22 | 23 | proptest! { 24 | #[test] 25 | fn hessenberg(n in PROPTEST_MATRIX_DIM) { 26 | let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0); 27 | let hess = m.clone().hessenberg(); 28 | let (p, h) = hess.unpack(); 29 | prop_assert!(relative_eq!(m, &p * h * p.adjoint(), epsilon = 1.0e-7)) 30 | } 31 | 32 | #[test] 33 | fn hessenberg_static_mat2(m in matrix2_($scalar)) { 34 | let hess = m.hessenberg(); 35 | let (p, h) = hess.unpack(); 36 | prop_assert!(relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7)) 37 | } 38 | 39 | #[test] 40 | fn hessenberg_static(m in matrix4_($scalar)) { 41 | let hess = m.hessenberg(); 42 | let (p, h) = hess.unpack(); 43 | prop_assert!(relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7)) 44 | } 45 | } 46 | } 47 | } 48 | ); 49 | 50 | gen_tests!(complex, complex_f64(), RandComplex); 51 | gen_tests!(f64, PROPTEST_F64, RandScalar); 52 | -------------------------------------------------------------------------------- /tests/linalg/mod.rs: -------------------------------------------------------------------------------- 1 | mod balancing; 2 | mod bidiagonal; 3 | mod cholesky; 4 | mod col_piv_qr; 5 | mod convolution; 6 | mod eigen; 7 | mod exp; 8 | mod full_piv_lu; 9 | mod hessenberg; 10 | mod inverse; 11 | mod lu; 12 | mod pow; 13 | mod qr; 14 | mod schur; 15 | mod solve; 16 | mod svd; 17 | mod tridiagonal; 18 | mod udu; 19 | -------------------------------------------------------------------------------- /tests/linalg/pow.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "proptest-support")] 2 | mod proptest_tests { 3 | macro_rules! gen_tests( 4 | ($module: ident, $scalar: expr, $scalar_type: ty) => { 5 | mod $module { 6 | use na::DMatrix; 7 | #[allow(unused_imports)] 8 | use crate::core::helper::{RandScalar, RandComplex}; 9 | use std::cmp; 10 | 11 | use crate::proptest::*; 12 | use proptest::{prop_assert, proptest}; 13 | 14 | proptest! { 15 | #[test] 16 | fn pow(n in PROPTEST_MATRIX_DIM, p in 0u32..=4) { 17 | let n = cmp::max(1, cmp::min(n, 10)); 18 | let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0); 19 | let m_pow = m.pow(p); 20 | let mut expected = m.clone(); 21 | expected.fill_with_identity(); 22 | 23 | for _ in 0..p { 24 | expected = &m * &expected; 25 | } 26 | 27 | prop_assert!(relative_eq!(m_pow, expected, epsilon = 1.0e-5)) 28 | } 29 | 30 | #[test] 31 | fn pow_static_square_4x4(m in matrix4_($scalar), p in 0u32..=4) { 32 | let mut expected = m.clone(); 33 | let m_pow = m.pow(p); 34 | expected.fill_with_identity(); 35 | 36 | for _ in 0..p { 37 | expected = &m * &expected; 38 | } 39 | 40 | prop_assert!(relative_eq!(m_pow, expected, epsilon = 1.0e-5)) 41 | } 42 | } 43 | } 44 | } 45 | ); 46 | 47 | gen_tests!(complex, complex_f64(), RandComplex); 48 | gen_tests!(f64, PROPTEST_F64, RandScalar); 49 | } 50 | -------------------------------------------------------------------------------- /tests/linalg/tridiagonal.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "proptest-support")] 2 | 3 | macro_rules! gen_tests( 4 | ($module: ident, $scalar: expr) => { 5 | mod $module { 6 | #[allow(unused_imports)] 7 | use crate::core::helper::{RandScalar, RandComplex}; 8 | use crate::proptest::*; 9 | use proptest::{prop_assert, proptest}; 10 | 11 | proptest! { 12 | #[test] 13 | fn symm_tridiagonal(m in dmatrix_($scalar)) { 14 | let m = &m * m.adjoint(); 15 | let tri = m.clone().symmetric_tridiagonalize(); 16 | let recomp = tri.recompose(); 17 | 18 | prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)); 19 | } 20 | 21 | #[test] 22 | fn symm_tridiagonal_singular(m in dmatrix_($scalar)) { 23 | let mut m = &m * m.adjoint(); 24 | let n = m.nrows(); 25 | m.row_mut(n / 2).fill(na::zero()); 26 | m.column_mut(n / 2).fill(na::zero()); 27 | let tri = m.clone().symmetric_tridiagonalize(); 28 | let recomp = tri.recompose(); 29 | 30 | prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)); 31 | } 32 | 33 | #[test] 34 | fn symm_tridiagonal_static_square(m in matrix4_($scalar)) { 35 | let m = m.hermitian_part(); 36 | let tri = m.symmetric_tridiagonalize(); 37 | let recomp = tri.recompose(); 38 | 39 | prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)); 40 | } 41 | 42 | #[test] 43 | fn symm_tridiagonal_static_square_2x2(m in matrix2_($scalar)) { 44 | let m = m.hermitian_part(); 45 | let tri = m.symmetric_tridiagonalize(); 46 | let recomp = tri.recompose(); 47 | 48 | prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)); 49 | } 50 | } 51 | } 52 | } 53 | ); 54 | 55 | gen_tests!(complex, complex_f64()); 56 | gen_tests!(f64, PROPTEST_F64); 57 | -------------------------------------------------------------------------------- /tests/linalg/udu.rs: -------------------------------------------------------------------------------- 1 | use na::Matrix3; 2 | 3 | #[test] 4 | #[rustfmt::skip] 5 | fn udu_simple() { 6 | let m = Matrix3::new( 7 | 2.0, -1.0, 0.0, 8 | -1.0, 2.0, -1.0, 9 | 0.0, -1.0, 2.0); 10 | 11 | let udu = m.udu().unwrap(); 12 | 13 | // Rebuild 14 | let p = udu.u * udu.d_matrix() * udu.u.transpose(); 15 | 16 | assert!(relative_eq!(m, p, epsilon = 3.0e-16)); 17 | } 18 | 19 | #[test] 20 | #[should_panic] 21 | #[rustfmt::skip] 22 | fn udu_non_sym_panic() { 23 | let m = Matrix3::new( 24 | 2.0, -1.0, 0.0, 25 | 1.0, -2.0, 3.0, 26 | -2.0, 1.0, 0.3); 27 | 28 | let udu = m.udu().unwrap(); 29 | // Rebuild 30 | let p = udu.u * udu.d_matrix() * udu.u.transpose(); 31 | 32 | assert!(relative_eq!(m, p, epsilon = 3.0e-16)); 33 | } 34 | 35 | #[cfg(feature = "proptest-support")] 36 | mod proptest_tests { 37 | #[allow(unused_imports)] 38 | use crate::core::helper::{RandComplex, RandScalar}; 39 | 40 | macro_rules! gen_tests( 41 | ($module: ident, $scalar: expr) => { 42 | mod $module { 43 | #[allow(unused_imports)] 44 | use crate::core::helper::{RandScalar, RandComplex}; 45 | use crate::proptest::*; 46 | use proptest::{prop_assert, proptest}; 47 | 48 | proptest! { 49 | #[test] 50 | fn udu(m in dmatrix_($scalar)) { 51 | let m = &m * m.adjoint(); 52 | 53 | if let Some(udu) = m.clone().udu() { 54 | let p = &udu.u * &udu.d_matrix() * &udu.u.transpose(); 55 | println!("m: {}, p: {}", m, p); 56 | 57 | prop_assert!(relative_eq!(m, p, epsilon = 1.0e-7)); 58 | } 59 | } 60 | 61 | #[test] 62 | fn udu_static(m in matrix4_($scalar)) { 63 | let m = m.hermitian_part(); 64 | 65 | if let Some(udu) = m.udu() { 66 | let p = udu.u * udu.d_matrix() * udu.u.transpose(); 67 | prop_assert!(relative_eq!(m, p, epsilon = 1.0e-7)); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | ); 74 | 75 | gen_tests!(f64, PROPTEST_F64); 76 | } 77 | -------------------------------------------------------------------------------- /tests/macros/mod.rs: -------------------------------------------------------------------------------- 1 | mod matrix; 2 | mod stack; 3 | 4 | /// Wrapper for `assert_eq` that also asserts that the types are the same 5 | // For some reason, rustfmt totally messes up the formatting of this macro. 6 | // For now we skip, but once https://github.com/rust-lang/rustfmt/issues/6131 7 | // is fixed, we can perhaps remove the skip attribute 8 | #[rustfmt::skip] 9 | macro_rules! assert_eq_and_type { 10 | ($left:expr, $right:expr $(,)?) => { 11 | { 12 | fn check_statically_same_type(_: &T, _: &T) {} 13 | check_statically_same_type(&$left, &$right); 14 | } 15 | assert_eq!($left, $right); 16 | }; 17 | } 18 | 19 | pub(crate) use assert_eq_and_type; 20 | -------------------------------------------------------------------------------- /tests/macros/trybuild/dmatrix_mismatched_dimensions.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::dmatrix; 2 | 3 | fn main() { 4 | dmatrix![1, 2, 3; 5 | 4, 5]; 6 | } -------------------------------------------------------------------------------- /tests/macros/trybuild/dmatrix_mismatched_dimensions.stderr: -------------------------------------------------------------------------------- 1 | error: Unexpected number of entries in row 1. Expected 3, found 2 entries. 2 | --> tests/macros/trybuild/dmatrix_mismatched_dimensions.rs:5:13 3 | | 4 | 5 | 4, 5]; 5 | | ^ 6 | -------------------------------------------------------------------------------- /tests/macros/trybuild/matrix_mismatched_dimensions.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::matrix; 2 | 3 | fn main() { 4 | matrix![1, 2, 3; 5 | 4, 5]; 6 | } -------------------------------------------------------------------------------- /tests/macros/trybuild/matrix_mismatched_dimensions.stderr: -------------------------------------------------------------------------------- 1 | error: Unexpected number of entries in row 1. Expected 3, found 2 entries. 2 | --> tests/macros/trybuild/matrix_mismatched_dimensions.rs:5:13 3 | | 4 | 5 | 4, 5]; 5 | | ^ 6 | -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_empty_col.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::{matrix, stack}; 2 | 3 | fn main() { 4 | let m = matrix![1, 2; 3, 4]; 5 | stack![0, m]; 6 | } 7 | -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_empty_col.stderr: -------------------------------------------------------------------------------- 1 | error: Block column 0 cannot consist entirely of implicit zero blocks. 2 | --> tests/macros/trybuild/stack_empty_col.rs:5:5 3 | | 4 | 5 | stack![0, m]; 5 | | ^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_empty_row.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::{matrix, stack}; 2 | 3 | fn main() { 4 | let m = matrix![1, 2; 3, 4]; 5 | stack![0; m]; 6 | } 7 | -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_empty_row.stderr: -------------------------------------------------------------------------------- 1 | error: Block row 0 cannot consist entirely of implicit zero blocks. 2 | --> tests/macros/trybuild/stack_empty_row.rs:5:5 3 | | 4 | 5 | stack![0; m]; 5 | | ^^^^^^^^^^^^ 6 | | 7 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_incompatible_block_dimensions.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::{matrix, stack}; 2 | 3 | fn main() { 4 | // Use multi-letter names for checking that the reported span comes out correctly 5 | let a11 = matrix![1, 2; 6 | 3, 4]; 7 | let a12 = matrix![5, 6; 8 | 7, 8]; 9 | let a21 = matrix![9, 10, 11]; 10 | let a22 = matrix![12, 13]; 11 | stack![a11, a12; 12 | a21, a22]; 13 | } -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_incompatible_block_dimensions.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `ShapeConstraint: SameNumberOfColumns, Const<3>>` is not satisfied 2 | --> tests/macros/trybuild/stack_incompatible_block_dimensions.rs:12:12 3 | | 4 | 12 | a21, a22]; 5 | | ^^^ the trait `SameNumberOfColumns, Const<3>>` is not implemented for `ShapeConstraint` 6 | | 7 | = help: the following other types implement trait `SameNumberOfColumns`: 8 | `ShapeConstraint` implements `SameNumberOfColumns` 9 | `ShapeConstraint` implements `SameNumberOfColumns` 10 | `ShapeConstraint` implements `SameNumberOfColumns` 11 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 12 | 13 | error[E0282]: type annotations needed 14 | --> tests/macros/trybuild/stack_incompatible_block_dimensions.rs:11:5 15 | | 16 | 11 | / stack![a11, a12; 17 | 12 | | a21, a22]; 18 | | |____________________^ cannot infer type 19 | | 20 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 21 | 22 | error[E0599]: no method named `generic_view_mut` found for struct `Matrix<_, Const<3>, _, _>` in the current scope 23 | --> tests/macros/trybuild/stack_incompatible_block_dimensions.rs:11:5 24 | | 25 | 11 | stack![a11, a12; 26 | | _____^ 27 | 12 | | a21, a22]; 28 | | |____________________^ method not found in `Matrix<_, Const<3>, _, _>` 29 | | 30 | = note: the method was found for 31 | - `Matrix` 32 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 33 | -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_incompatible_block_dimensions2.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::{matrix, stack}; 2 | 3 | fn main() { 4 | // Use multi-letter names for checking that the reported span comes out correctly 5 | let a11 = matrix![1, 2; 6 | 3, 4]; 7 | let a12 = matrix![5, 6; 8 | 7, 8]; 9 | let a21 = matrix![9, 10]; 10 | let a22 = matrix![11, 12; 11 | 13, 14]; 12 | stack![a11, a12; 13 | a21, a22]; 14 | } -------------------------------------------------------------------------------- /tests/macros/trybuild/stack_incompatible_block_dimensions2.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `ShapeConstraint: SameNumberOfRows, Const<2>>` is not satisfied 2 | --> tests/macros/trybuild/stack_incompatible_block_dimensions2.rs:13:17 3 | | 4 | 13 | a21, a22]; 5 | | ^^^ the trait `SameNumberOfRows, Const<2>>` is not implemented for `ShapeConstraint` 6 | | 7 | = help: the following other types implement trait `SameNumberOfRows`: 8 | `ShapeConstraint` implements `SameNumberOfRows` 9 | `ShapeConstraint` implements `SameNumberOfRows` 10 | `ShapeConstraint` implements `SameNumberOfRows` 11 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 12 | 13 | error[E0282]: type annotations needed 14 | --> tests/macros/trybuild/stack_incompatible_block_dimensions2.rs:12:5 15 | | 16 | 12 | / stack![a11, a12; 17 | 13 | | a21, a22]; 18 | | |____________________^ cannot infer type 19 | | 20 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 21 | 22 | error[E0599]: no method named `generic_view_mut` found for struct `Matrix<_, _, Const<4>, _>` in the current scope 23 | --> tests/macros/trybuild/stack_incompatible_block_dimensions2.rs:12:5 24 | | 25 | 12 | stack![a11, a12; 26 | | _____^ 27 | 13 | | a21, a22]; 28 | | |____________________^ method not found in `Matrix<_, _, Const<4>, _>` 29 | | 30 | = note: the method was found for 31 | - `Matrix` 32 | = note: this error originates in the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info) 33 | -------------------------------------------------------------------------------- /tests/sparse/cs_cholesky.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | 3 | use na::{CsMatrix, CsVector, CsCholesky, Cholesky, Matrix5, Vector5}; 4 | 5 | #[test] 6 | fn cs_cholesky() { 7 | let mut a = Matrix5::new( 8 | 40.0, 0.0, 0.0, 0.0, 0.0, 9 | 2.0, 60.0, 0.0, 0.0, 0.0, 10 | 1.0, 0.0, 11.0, 0.0, 0.0, 11 | 0.0, 0.0, 0.0, 50.0, 0.0, 12 | 1.0, 0.0, 0.0, 4.0, 10.0 13 | ); 14 | a.fill_upper_triangle_with_lower_triangle(); 15 | test_cholesky(a); 16 | 17 | let a = Matrix5::from_diagonal(&Vector5::new(40.0, 60.0, 11.0, 50.0, 10.0)); 18 | test_cholesky(a); 19 | 20 | let mut a = Matrix5::new( 21 | 40.0, 0.0, 0.0, 0.0, 0.0, 22 | 2.0, 60.0, 0.0, 0.0, 0.0, 23 | 1.0, 0.0, 11.0, 0.0, 0.0, 24 | 1.0, 0.0, 0.0, 50.0, 0.0, 25 | 0.0, 0.0, 0.0, 4.0, 10.0 26 | ); 27 | a.fill_upper_triangle_with_lower_triangle(); 28 | test_cholesky(a); 29 | 30 | let mut a = Matrix5::new( 31 | 2.0, 0.0, 0.0, 0.0, 0.0, 32 | 0.0, 2.0, 0.0, 0.0, 0.0, 33 | 1.0, 1.0, 2.0, 0.0, 0.0, 34 | 0.0, 0.0, 0.0, 2.0, 0.0, 35 | 1.0, 1.0, 0.0, 0.0, 2.0 36 | ); 37 | a.fill_upper_triangle_with_lower_triangle(); 38 | // Test crate::new, left_looking, and up_looking implementations. 39 | test_cholesky(a); 40 | } 41 | 42 | fn test_cholesky(a: Matrix5) { 43 | // Test crate::new 44 | test_cholesky_variant(a, 0); 45 | // Test up-looking 46 | test_cholesky_variant(a, 1); 47 | // Test left-looking 48 | test_cholesky_variant(a, 2); 49 | } 50 | 51 | fn test_cholesky_variant(a: Matrix5, option: usize) { 52 | let cs_a: CsMatrix<_, _, _> = a.into(); 53 | 54 | let chol_a = Cholesky::new(a).unwrap(); 55 | let mut chol_cs_a; 56 | 57 | match option { 58 | 0 => chol_cs_a = CsCholesky::new(&cs_a), 59 | 1 => { 60 | chol_cs_a = CsCholesky::new_symbolic(&cs_a); 61 | chol_cs_a.decompose_up_looking(cs_a.data.values()); 62 | } 63 | _ => { 64 | chol_cs_a = CsCholesky::new_symbolic(&cs_a); 65 | chol_cs_a.decompose_left_looking(cs_a.data.values()); 66 | } 67 | }; 68 | 69 | let l = chol_a.l(); 70 | let cs_l = chol_cs_a.unwrap_l().unwrap(); 71 | assert!(cs_l.is_sorted()); 72 | 73 | let cs_l_mat: Matrix5<_> = cs_l.into(); 74 | assert_relative_eq!(l, cs_l_mat); 75 | } 76 | -------------------------------------------------------------------------------- /tests/sparse/cs_construction.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/sparse/cs_matrix.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | 3 | use na::{Matrix4x5, Matrix5x4, CsMatrix}; 4 | 5 | #[test] 6 | fn cs_transpose() { 7 | let m = Matrix4x5::new( 8 | 4.0, 1.0, 4.0, 0.0, 9.0, 9 | 5.0, 6.0, 0.0, 8.0, 10.0, 10 | 9.0, 10.0, 11.0, 12.0, 0.0, 11 | 0.0, 0.0, 1.0, 0.0, 10.0 12 | ); 13 | 14 | let cs: CsMatrix<_, _, _> = m.into(); 15 | assert!(cs.is_sorted()); 16 | 17 | let cs_transposed = cs.transpose(); 18 | assert!(cs_transposed.is_sorted()); 19 | 20 | let cs_transposed_mat: Matrix5x4<_> = cs_transposed.into(); 21 | assert_eq!(cs_transposed_mat, m.transpose()) 22 | } 23 | -------------------------------------------------------------------------------- /tests/sparse/cs_matrix_market.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | 3 | 4 | use na::io; 5 | use na::DMatrix; 6 | 7 | #[test] 8 | fn cs_matrix_market() { 9 | let file_str = r#" 10 | %%MatrixMarket matrix coordinate real general 11 | %================================================================================= 12 | % 13 | % This ASCII file represents a sparse MxN matrix with L 14 | % nonzeros in the following Matrix Market format: 15 | % 16 | % +----------------------------------------------+ 17 | % |%%MatrixMarket matrix coordinate real general | <--- header line 18 | % |% | <--+ 19 | % |% comments | |-- 0 or more comment lines 20 | % |% | <--+ 21 | % | M T L | <--- rows, columns, entries 22 | % | I1 J1 A(I1, J1) | <--+ 23 | % | I2 J2 A(I2, J2) | | 24 | % | I3 J3 A(I3, J3) | |-- L lines 25 | % | . . . | | 26 | % | IL JL A(IL, JL) | <--+ 27 | % +----------------------------------------------+ 28 | % 29 | % Indices are 1-based, i.e. A(1,1) is the first element. 30 | % 31 | %================================================================================= 32 | 5 5 8 33 | 1 1 1.000e+00 34 | 2 2 1.050e+01 35 | 3 3 1.500e-02 36 | 1 4 6.000e+00 37 | 4 2 2.505e+02 38 | 4 4 -2.800e+02 39 | 4 5 3.332e+01 40 | 5 5 1.200e+01 41 | "#; 42 | 43 | let cs_mat = io::cs_matrix_from_matrix_market_str(file_str).unwrap(); 44 | let mat: DMatrix<_> = cs_mat.into(); 45 | let expected = DMatrix::from_row_slice(5, 5, &[ 46 | 1.0, 0.0, 0.0, 6.0, 0.0, 47 | 0.0, 10.5, 0.0, 0.0, 0.0, 48 | 0.0, 0.0, 0.015, 0.0, 0.0, 49 | 0.0, 250.5, 0.0, -280.0, 33.32, 50 | 0.0, 0.0, 0.0, 0.0, 12.0, 51 | ]); 52 | 53 | assert_eq!(mat, expected); 54 | } 55 | -------------------------------------------------------------------------------- /tests/sparse/cs_ops.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(rustfmt, rustfmt_skip)] 2 | 3 | 4 | use na::{Matrix3x4, Matrix4x5, Matrix3x5, CsMatrix, Vector5, CsVector}; 5 | 6 | #[test] 7 | fn axpy_cs() { 8 | let mut v1 = Vector5::new(1.0, 2.0, 3.0, 4.0, 5.0); 9 | let v2 = Vector5::new(10.0, 0.0, 30.0, 0.0, 50.0); 10 | let expected = 5.0 * v2 + 10.0 * v1; 11 | 12 | let cs: CsVector<_, _> = v2.into(); 13 | v1.axpy_cs(5.0, &cs, 10.0); 14 | 15 | assert!(cs.is_sorted()); 16 | assert_eq!(v1, expected) 17 | } 18 | 19 | 20 | #[test] 21 | fn cs_mat_mul() { 22 | let m1 = Matrix3x4::new( 23 | 0.0, 1.0, 4.0, 0.0, 24 | 5.0, 6.0, 0.0, 8.0, 25 | 9.0, 10.0, 11.0, 12.0, 26 | ); 27 | 28 | let m2 = Matrix4x5::new( 29 | 5.0, 6.0, 0.0, 8.0, 15.0, 30 | 9.0, 10.0, 11.0, 12.0, 0.0, 31 | 0.0, 0.0, 13.0, 0.0, 0.0, 32 | 0.0, 1.0, 4.0, 0.0, 14.0, 33 | ); 34 | 35 | let sm1: CsMatrix<_, _, _> = m1.into(); 36 | let sm2: CsMatrix<_, _, _> = m2.into(); 37 | 38 | let mul = &sm1 * &sm2; 39 | 40 | assert!(sm1.is_sorted()); 41 | assert!(sm2.is_sorted()); 42 | assert!(mul.is_sorted()); 43 | assert_eq!(Matrix3x5::from(mul), m1 * m2); 44 | } 45 | 46 | 47 | #[test] 48 | fn cs_mat_add() { 49 | let m1 = Matrix4x5::new( 50 | 4.0, 1.0, 4.0, 0.0, 0.0, 51 | 5.0, 6.0, 0.0, 8.0, 0.0, 52 | 9.0, 10.0, 11.0, 12.0, 0.0, 53 | 0.0, 0.0, 1.0, 0.0, 10.0 54 | ); 55 | 56 | let m2 = Matrix4x5::new( 57 | 0.0, 1.0, 4.0, 0.0, 14.0, 58 | 5.0, 6.0, 0.0, 8.0, 15.0, 59 | 9.0, 10.0, 11.0, 12.0, 0.0, 60 | 0.0, 0.0, 13.0, 0.0, 0.0, 61 | ); 62 | 63 | let sm1: CsMatrix<_, _, _> = m1.into(); 64 | let sm2: CsMatrix<_, _, _> = m2.into(); 65 | 66 | let sum = &sm1 + &sm2; 67 | 68 | assert!(sm1.is_sorted()); 69 | assert!(sm2.is_sorted()); 70 | assert!(sum.is_sorted()); 71 | assert_eq!(Matrix4x5::from(sum), m1 + m2); 72 | } 73 | -------------------------------------------------------------------------------- /tests/sparse/mod.rs: -------------------------------------------------------------------------------- 1 | mod cs_cholesky; 2 | mod cs_construction; 3 | mod cs_conversion; 4 | mod cs_matrix; 5 | #[cfg(feature = "io")] 6 | mod cs_matrix_market; 7 | mod cs_ops; 8 | mod cs_solve; 9 | --------------------------------------------------------------------------------