From 61c952897b9174e3c5b5c271057057b11d797cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 13 Sep 2024 14:42:40 +0000 Subject: [PATCH 1/2] add `nalgebra-0.33.0` benchmark code --- .../nalgebra-0.33.0/.cargo_vcs_info.json | 6 + .../nalgebra-0.33.0/.github/FUNDING.yml | 12 + .../nalgebra-0.33.0/.github/Xargo.toml | 5 + .../.github/workflows/nalgebra-ci-build.yml | 135 + .../nalgebra-0.33.0/.gitignore | 13 + .../nalgebra-0.33.0/CHANGELOG.md | 1115 ++++++++ .../nalgebra-0.33.0/Cargo.toml | 327 +++ .../nalgebra-0.33.0/LICENSE | 201 ++ .../nalgebra-0.33.0/README.md | 28 + .../nalgebra-0.33.0/benches/common/macros.rs | 113 + .../nalgebra-0.33.0/benches/core/matrix.rs | 270 ++ .../nalgebra-0.33.0/benches/core/mod.rs | 5 + .../nalgebra-0.33.0/benches/core/vector.rs | 168 ++ .../nalgebra-0.33.0/benches/geometry/mod.rs | 3 + .../benches/geometry/quaternion.rs | 39 + .../nalgebra-0.33.0/benches/lib.rs | 37 + .../benches/linalg/bidiagonal.rs | 94 + .../benches/linalg/cholesky.rs | 132 + .../nalgebra-0.33.0/benches/linalg/eigen.rs | 32 + .../benches/linalg/full_piv_lu.rs | 129 + .../benches/linalg/hessenberg.rs | 75 + .../nalgebra-0.33.0/benches/linalg/lu.rs | 127 + .../nalgebra-0.33.0/benches/linalg/mod.rs | 22 + .../nalgebra-0.33.0/benches/linalg/qr.rs | 163 ++ .../nalgebra-0.33.0/benches/linalg/schur.rs | 69 + .../nalgebra-0.33.0/benches/linalg/solve.rs | 101 + .../nalgebra-0.33.0/benches/linalg/svd.rs | 149 ++ .../benches/linalg/symmetric_eigen.rs | 37 + .../nalgebra-0.33.0/clippy.toml | 2 + .../examples/dimensional_genericity.rs | 60 + .../examples/homogeneous_coordinates.rs | 44 + .../examples/linear_system_resolution.rs | 39 + .../examples/matrix_construction.rs | 62 + .../nalgebra-0.33.0/examples/matrixcompare.rs | 82 + .../nalgebra-0.33.0/examples/mvp.rs | 29 + .../examples/point_construction.rs | 25 + .../nalgebra-0.33.0/examples/raw_pointer.rs | 36 + .../nalgebra-0.33.0/examples/reshaping.rs | 54 + .../examples/scalar_genericity.rs | 25 + .../examples/screen_to_view_coords.rs | 24 + .../examples/transform_conversion.rs | 24 + .../examples/transform_matrix4.rs | 46 + .../examples/transform_vector_point.rs | 20 + .../examples/transform_vector_point3.rs | 24 + .../examples/transformation_pointer.rs | 26 + .../nalgebra-0.33.0/examples/unit_wrapper.rs | 28 + .../nalgebra-0.33.0/rustfmt.toml | 3 + .../nalgebra-0.33.0/src/base/alias.rs | 358 +++ .../nalgebra-0.33.0/src/base/alias_slice.rs | 721 +++++ .../nalgebra-0.33.0/src/base/alias_view.rs | 875 ++++++ .../nalgebra-0.33.0/src/base/allocator.rs | 149 ++ .../nalgebra-0.33.0/src/base/array_storage.rs | 295 ++ .../nalgebra-0.33.0/src/base/blas.rs | 1205 +++++++++ .../nalgebra-0.33.0/src/base/blas_uninit.rs | 322 +++ .../nalgebra-0.33.0/src/base/cg.rs | 471 ++++ .../nalgebra-0.33.0/src/base/componentwise.rs | 353 +++ .../nalgebra-0.33.0/src/base/constraint.rs | 108 + .../nalgebra-0.33.0/src/base/construction.rs | 1269 +++++++++ .../src/base/construction_view.rs | 318 +++ .../nalgebra-0.33.0/src/base/conversion.rs | 657 +++++ .../nalgebra-0.33.0/src/base/coordinates.rs | 236 ++ .../src/base/default_allocator.rs | 339 +++ .../nalgebra-0.33.0/src/base/dimension.rs | 340 +++ .../nalgebra-0.33.0/src/base/edition.rs | 1300 +++++++++ .../nalgebra-0.33.0/src/base/helper.rs | 31 + .../nalgebra-0.33.0/src/base/indexing.rs | 770 ++++++ .../nalgebra-0.33.0/src/base/interpolation.rs | 130 + .../nalgebra-0.33.0/src/base/iter.rs | 572 ++++ .../nalgebra-0.33.0/src/base/matrix.rs | 2362 +++++++++++++++++ .../nalgebra-0.33.0/src/base/matrix_simba.rs | 56 + .../nalgebra-0.33.0/src/base/matrix_view.rs | 1246 +++++++++ .../nalgebra-0.33.0/src/base/min_max.rs | 405 +++ .../nalgebra-0.33.0/src/base/mod.rs | 66 + .../nalgebra-0.33.0/src/base/norm.rs | 640 +++++ .../nalgebra-0.33.0/src/base/ops.rs | 856 ++++++ .../nalgebra-0.33.0/src/base/par_iter.rs | 285 ++ .../nalgebra-0.33.0/src/base/properties.rs | 122 + .../nalgebra-0.33.0/src/base/rkyv_wrappers.rs | 46 + .../nalgebra-0.33.0/src/base/scalar.rs | 8 + .../nalgebra-0.33.0/src/base/statistics.rs | 522 ++++ .../nalgebra-0.33.0/src/base/storage.rs | 302 +++ .../nalgebra-0.33.0/src/base/swizzle.rs | 66 + .../nalgebra-0.33.0/src/base/uninit.rs | 76 + .../nalgebra-0.33.0/src/base/unit.rs | 385 +++ .../nalgebra-0.33.0/src/base/vec_storage.rs | 526 ++++ .../nalgebra-0.33.0/src/debug/mod.rs | 7 + .../src/debug/random_orthogonal.rs | 55 + .../nalgebra-0.33.0/src/debug/random_sdp.rs | 58 + .../src/geometry/abstract_rotation.rs | 151 ++ .../src/geometry/dual_quaternion.rs | 1028 +++++++ .../geometry/dual_quaternion_construction.rs | 259 ++ .../geometry/dual_quaternion_conversion.rs | 187 ++ .../src/geometry/dual_quaternion_ops.rs | 1256 +++++++++ .../nalgebra-0.33.0/src/geometry/isometry.rs | 569 ++++ .../src/geometry/isometry_alias.rs | 42 + .../src/geometry/isometry_construction.rs | 477 ++++ .../src/geometry/isometry_conversion.rs | 356 +++ .../src/geometry/isometry_interpolation.rs | 234 ++ .../src/geometry/isometry_ops.rs | 536 ++++ .../src/geometry/isometry_simba.rs | 54 + .../nalgebra-0.33.0/src/geometry/mod.rs | 122 + .../nalgebra-0.33.0/src/geometry/op_macros.rs | 209 ++ .../src/geometry/orthographic.rs | 785 ++++++ .../src/geometry/perspective.rs | 348 +++ .../nalgebra-0.33.0/src/geometry/point.rs | 515 ++++ .../src/geometry/point_alias.rs | 30 + .../src/geometry/point_construction.rs | 237 ++ .../src/geometry/point_conversion.rs | 191 ++ .../src/geometry/point_coordinates.rs | 41 + .../nalgebra-0.33.0/src/geometry/point_ops.rs | 297 +++ .../src/geometry/point_simba.rs | 44 + .../src/geometry/quaternion.rs | 1707 ++++++++++++ .../src/geometry/quaternion_construction.rs | 928 +++++++ .../src/geometry/quaternion_conversion.rs | 410 +++ .../src/geometry/quaternion_coordinates.rs | 24 + .../src/geometry/quaternion_ops.rs | 677 +++++ .../src/geometry/quaternion_simba.rs | 84 + .../src/geometry/reflection.rs | 125 + .../src/geometry/reflection_alias.rs | 21 + .../nalgebra-0.33.0/src/geometry/rotation.rs | 586 ++++ .../src/geometry/rotation_alias.rs | 11 + .../src/geometry/rotation_construction.rs | 73 + .../src/geometry/rotation_conversion.rs | 337 +++ .../src/geometry/rotation_interpolation.rs | 81 + .../src/geometry/rotation_ops.rs | 195 ++ .../src/geometry/rotation_simba.rs | 46 + .../src/geometry/rotation_specialization.rs | 1210 +++++++++ .../nalgebra-0.33.0/src/geometry/scale.rs | 390 +++ .../src/geometry/scale_alias.rs | 19 + .../src/geometry/scale_construction.rs | 123 + .../src/geometry/scale_conversion.rs | 231 ++ .../src/geometry/scale_coordinates.rs | 39 + .../nalgebra-0.33.0/src/geometry/scale_ops.rs | 125 + .../src/geometry/scale_simba.rs | 45 + .../src/geometry/similarity.rs | 417 +++ .../src/geometry/similarity_alias.rs | 13 + .../src/geometry/similarity_construction.rs | 401 +++ .../src/geometry/similarity_conversion.rs | 315 +++ .../src/geometry/similarity_ops.rs | 602 +++++ .../src/geometry/similarity_simba.rs | 55 + .../nalgebra-0.33.0/src/geometry/swizzle.rs | 66 + .../nalgebra-0.33.0/src/geometry/transform.rs | 662 +++++ .../src/geometry/transform_alias.rs | 15 + .../src/geometry/transform_construction.rs | 74 + .../src/geometry/transform_conversion.rs | 77 + .../src/geometry/transform_ops.rs | 704 +++++ .../src/geometry/transform_simba.rs | 51 + .../src/geometry/translation.rs | 302 +++ .../src/geometry/translation_alias.rs | 19 + .../src/geometry/translation_construction.rs | 129 + .../src/geometry/translation_conversion.rs | 303 +++ .../src/geometry/translation_coordinates.rs | 39 + .../src/geometry/translation_ops.rs | 119 + .../src/geometry/translation_simba.rs | 45 + .../src/geometry/unit_complex.rs | 465 ++++ .../src/geometry/unit_complex_construction.rs | 436 +++ .../src/geometry/unit_complex_conversion.rs | 264 ++ .../src/geometry/unit_complex_ops.rs | 450 ++++ .../src/geometry/unit_complex_simba.rs | 47 + .../nalgebra-0.33.0/src/io/matrix_market.pest | 16 + .../nalgebra-0.33.0/src/io/matrix_market.rs | 53 + .../nalgebra-0.33.0/src/io/mod.rs | 5 + .../nalgebra-0.33.0/src/lib.rs | 549 ++++ .../nalgebra-0.33.0/src/linalg/balancing.rs | 84 + .../nalgebra-0.33.0/src/linalg/bidiagonal.rs | 384 +++ .../nalgebra-0.33.0/src/linalg/cholesky.rs | 441 +++ .../nalgebra-0.33.0/src/linalg/col_piv_qr.rs | 337 +++ .../nalgebra-0.33.0/src/linalg/convolution.rs | 144 + .../src/linalg/decomposition.rs | 364 +++ .../nalgebra-0.33.0/src/linalg/determinant.rs | 61 + .../nalgebra-0.33.0/src/linalg/eigen.rs | 112 + .../nalgebra-0.33.0/src/linalg/exp.rs | 560 ++++ .../nalgebra-0.33.0/src/linalg/full_piv_lu.rs | 267 ++ .../nalgebra-0.33.0/src/linalg/givens.rs | 165 ++ .../nalgebra-0.33.0/src/linalg/hessenberg.rs | 154 ++ .../nalgebra-0.33.0/src/linalg/householder.rs | 150 ++ .../nalgebra-0.33.0/src/linalg/inverse.rs | 284 ++ .../nalgebra-0.33.0/src/linalg/lu.rs | 388 +++ .../nalgebra-0.33.0/src/linalg/mod.rs | 49 + .../src/linalg/permutation_sequence.rs | 164 ++ .../nalgebra-0.33.0/src/linalg/pow.rs | 71 + .../nalgebra-0.33.0/src/linalg/qr.rs | 307 +++ .../nalgebra-0.33.0/src/linalg/schur.rs | 578 ++++ .../nalgebra-0.33.0/src/linalg/solve.rs | 780 ++++++ .../nalgebra-0.33.0/src/linalg/svd.rs | 891 +++++++ .../nalgebra-0.33.0/src/linalg/svd2.rs | 50 + .../nalgebra-0.33.0/src/linalg/svd3.rs | 55 + .../src/linalg/symmetric_eigen.rs | 423 +++ .../src/linalg/symmetric_tridiagonal.rs | 170 ++ .../nalgebra-0.33.0/src/linalg/udu.rs | 98 + .../nalgebra-0.33.0/src/proptest/mod.rs | 476 ++++ .../nalgebra-0.33.0/src/sparse/cs_matrix.rs | 542 ++++ .../src/sparse/cs_matrix_cholesky.rs | 412 +++ .../src/sparse/cs_matrix_conversion.rs | 113 + .../src/sparse/cs_matrix_ops.rs | 306 +++ .../src/sparse/cs_matrix_solve.rs | 289 ++ .../nalgebra-0.33.0/src/sparse/cs_utils.rs | 18 + .../nalgebra-0.33.0/src/sparse/mod.rs | 13 + .../third_party/alga/alga_dual_quaternion.rs | 324 +++ .../src/third_party/alga/alga_isometry.rs | 199 ++ .../src/third_party/alga/alga_matrix.rs | 454 ++++ .../src/third_party/alga/alga_point.rs | 75 + .../src/third_party/alga/alga_quaternion.rs | 309 +++ .../src/third_party/alga/alga_rotation.rs | 272 ++ .../src/third_party/alga/alga_similarity.rs | 186 ++ .../src/third_party/alga/alga_transform.rs | 152 ++ .../src/third_party/alga/alga_translation.rs | 196 ++ .../src/third_party/alga/alga_unit_complex.rs | 170 ++ .../src/third_party/alga/mod.rs | 10 + .../third_party/glam/common/glam_isometry.rs | 145 + .../third_party/glam/common/glam_matrix.rs | 286 ++ .../src/third_party/glam/common/glam_point.rs | 71 + .../glam/common/glam_quaternion.rs | 58 + .../third_party/glam/common/glam_rotation.rs | 58 + .../glam/common/glam_similarity.rs | 53 + .../glam/common/glam_translation.rs | 65 + .../glam/common/glam_unit_complex.rs | 30 + .../src/third_party/glam/mod.rs | 28 + .../src/third_party/glam/v014/mod.rs | 18 + .../src/third_party/glam/v015/mod.rs | 18 + .../src/third_party/glam/v016/mod.rs | 18 + .../src/third_party/glam/v017/mod.rs | 18 + .../src/third_party/glam/v018/mod.rs | 18 + .../src/third_party/glam/v019/mod.rs | 18 + .../src/third_party/glam/v020/mod.rs | 18 + .../src/third_party/glam/v021/mod.rs | 18 + .../src/third_party/glam/v022/mod.rs | 18 + .../src/third_party/glam/v023/mod.rs | 18 + .../src/third_party/glam/v024/mod.rs | 18 + .../src/third_party/glam/v025/mod.rs | 18 + .../src/third_party/glam/v027/mod.rs | 18 + .../src/third_party/glam/v028/mod.rs | 18 + .../src/third_party/mint/mint_matrix.rs | 131 + .../src/third_party/mint/mint_point.rs | 52 + .../src/third_party/mint/mint_quaternion.rs | 33 + .../src/third_party/mint/mint_rotation.rs | 7 + .../src/third_party/mint/mod.rs | 4 + .../nalgebra-0.33.0/src/third_party/mod.rs | 5 + 238 files changed, 58641 insertions(+) create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/.cargo_vcs_info.json create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/.github/FUNDING.yml create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/.github/Xargo.toml create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/.github/workflows/nalgebra-ci-build.yml create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/.gitignore create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/CHANGELOG.md create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/LICENSE create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/README.md create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/common/macros.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/core/matrix.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/core/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/core/vector.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/lib.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/bidiagonal.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/cholesky.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/eigen.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/full_piv_lu.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/hessenberg.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/lu.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/qr.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/schur.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/solve.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/svd.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/symmetric_eigen.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/clippy.toml create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/dimensional_genericity.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/homogeneous_coordinates.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/linear_system_resolution.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/matrix_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/matrixcompare.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/mvp.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/point_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/raw_pointer.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/reshaping.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/scalar_genericity.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/screen_to_view_coords.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_matrix4.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point3.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/transformation_pointer.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/examples/unit_wrapper.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/rustfmt.toml create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_slice.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_view.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/allocator.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/array_storage.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas_uninit.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/cg.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/componentwise.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/constraint.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction_view.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/coordinates.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/default_allocator.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/dimension.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/edition.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/helper.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/indexing.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/interpolation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/iter.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_view.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/min_max.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/norm.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/par_iter.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/properties.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/rkyv_wrappers.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/scalar.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/statistics.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/storage.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/swizzle.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/uninit.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/unit.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/base/vec_storage.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/debug/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_orthogonal.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_sdp.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/abstract_rotation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_interpolation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/op_macros.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/orthographic.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/perspective.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_coordinates.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_coordinates.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_interpolation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_specialization.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_coordinates.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/swizzle.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_alias.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_coordinates.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_construction.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_simba.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.pest create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/io/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/lib.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/balancing.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/bidiagonal.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/cholesky.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/col_piv_qr.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/convolution.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/decomposition.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/determinant.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/eigen.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/exp.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/full_piv_lu.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/givens.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/hessenberg.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/householder.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/inverse.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/lu.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/permutation_sequence.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/pow.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/qr.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/schur.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/solve.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd2.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd3.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_eigen.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_tridiagonal.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/udu.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/proptest/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_cholesky.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_conversion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_ops.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_solve.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_utils.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_dual_quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_isometry.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_matrix.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_point.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_rotation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_similarity.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_transform.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_translation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_unit_complex.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_isometry.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_matrix.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_point.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_rotation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_similarity.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_translation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_unit_complex.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v014/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v015/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v016/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v017/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v018/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v019/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v020/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v021/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v022/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v023/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v024/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v025/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v027/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v028/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_matrix.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_point.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_quaternion.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_rotation.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mod.rs create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mod.rs diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/.cargo_vcs_info.json b/collector/compile-benchmarks/nalgebra-0.33.0/.cargo_vcs_info.json new file mode 100644 index 000000000..4104ae755 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "48c8f6a5053fac48e305f5e5e0004a332811d092" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/.github/FUNDING.yml b/collector/compile-benchmarks/nalgebra-0.33.0/.github/FUNDING.yml new file mode 100644 index 000000000..0e946cb00 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [ "dimforge" ] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/.github/Xargo.toml b/collector/compile-benchmarks/nalgebra-0.33.0/.github/Xargo.toml new file mode 100644 index 000000000..dee29c3f5 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/.github/Xargo.toml @@ -0,0 +1,5 @@ +[target.x86_64-unknown-linux-gnu.dependencies] +alloc = {} + +[target.thumbv7em-none-eabihf.dependencies] +alloc = {} \ No newline at end of file diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/.github/workflows/nalgebra-ci-build.yml b/collector/compile-benchmarks/nalgebra-0.33.0/.github/workflows/nalgebra-ci-build.yml new file mode 100644 index 000000000..eab249c9e --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/.github/workflows/nalgebra-ci-build.yml @@ -0,0 +1,135 @@ +name: nalgebra CI build + +on: + push: + branches: [ dev, master ] + pull_request: + branches: [ dev, master ] + +env: + CARGO_TERM_COLOR: always + +jobs: + check-fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Check formatting + run: cargo fmt -- --check + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install clippy + run: rustup component add clippy + - name: Run clippy + run: cargo clippy + build-nalgebra: + runs-on: ubuntu-latest + # env: + # RUSTFLAGS: -D warnings + steps: + - uses: actions/checkout@v2 + - name: Build --no-default-feature + run: cargo build --no-default-features; + - name: Build (default features) + run: cargo build; + - name: Build --features serde-serialize + run: cargo build --features serde-serialize + - name: Build nalgebra-lapack + run: cd nalgebra-lapack; cargo build; + - name: Build nalgebra-sparse --no-default-features + run: cd nalgebra-sparse; cargo build --no-default-features; + - name: Build nalgebra-sparse (default features) + run: cd nalgebra-sparse; cargo build; + - name: Build nalgebra-sparse --all-features + run: cd nalgebra-sparse; cargo build --all-features; + # Run this on it’s own job because it alone takes a lot of time. + # So it’s best to let it run in parallel to the other jobs. + build-nalgebra-all-features: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: cargo build --all-features; + - run: cargo build -p nalgebra-glm --all-features; + test-nalgebra: + runs-on: ubuntu-latest + # env: + # RUSTFLAGS: -D warnings + steps: + # Tests are run with a specific version of the compiler to avoid + # trybuild errors when a new compiler version is out. This can be + # bumped as needed after running the tests with TRYBUILD=overwrite + # to re-generate the error reference. + - name: Select rustc version + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.79.0 + override: true + - uses: actions/checkout@v2 + - name: test + run: cargo test --features arbitrary,rand,serde-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests,rkyv-safe-deser,rayon; + test-nalgebra-glm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: test nalgebra-glm + run: cargo test -p nalgebra-glm --features arbitrary,serde-serialize; + test-nalgebra-sparse: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: test nalgebra-sparse + # Manifest-path is necessary because cargo otherwise won't correctly forward features + # We increase number of proptest cases to hopefully catch more potential bugs + run: PROPTEST_CASES=10000 cargo test --manifest-path=nalgebra-sparse/Cargo.toml --features compare,proptest-support,io,serde-serialize + - name: test nalgebra-sparse (slow tests) + # Unfortunately, the "slow-tests" take so much time that we need to run them with --release + run: PROPTEST_CASES=10000 cargo test --release --manifest-path=nalgebra-sparse/Cargo.toml --features compare,proptest-support,io,serde-serialize,slow-tests slow + test-nalgebra-macros: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: test nalgebra-macros + run: cargo test -p nalgebra-macros + build-wasm: + runs-on: ubuntu-latest + # env: + # RUSTFLAGS: -D warnings + steps: + - uses: actions/checkout@v2 + - run: rustup target add wasm32-unknown-unknown + - name: build nalgebra + run: cargo build --verbose --target wasm32-unknown-unknown; + - name: build nalgebra-glm + run: cargo build -p nalgebra-glm --verbose --target wasm32-unknown-unknown; + build-no-std: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + components: rustfmt + - name: install xargo + run: cp .github/Xargo.toml .; rustup component add rust-src; cargo install -f xargo; + - name: build x86_64-unknown-linux-gnu + run: xargo build --verbose --no-default-features --target=x86_64-unknown-linux-gnu; + - name: build x86_64-unknown-linux-gnu --features rand-no-std + run: xargo build --verbose --no-default-features --target=x86_64-unknown-linux-gnu; + - name: build x86_64-unknown-linux-gnu --features alloc + run: xargo build --verbose --no-default-features --features alloc --target=x86_64-unknown-linux-gnu; + - name: build thumbv7em-none-eabihf + run: xargo build --verbose --no-default-features --target=thumbv7em-none-eabihf; + - name: build x86_64-unknown-linux-gnu nalgebra-glm + run: xargo build --verbose --no-default-features -p nalgebra-glm --target=x86_64-unknown-linux-gnu; + - name: build thumbv7em-none-eabihf nalgebra-glm + run: xargo build --verbose --no-default-features -p nalgebra-glm --target=thumbv7em-none-eabihf; + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Generate documentation + run: cargo doc diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore b/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore new file mode 100644 index 000000000..6984ee171 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore @@ -0,0 +1,13 @@ +*.swp +*.html +doc +lib +TODO +target/ +Cargo.lock +*.orig +*.swo +site/ +.vscode/ +.idea/ +proptest-regressions \ No newline at end of file diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/CHANGELOG.md b/collector/compile-benchmarks/nalgebra-0.33.0/CHANGELOG.md new file mode 100644 index 000000000..8fcc1c7c3 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/CHANGELOG.md @@ -0,0 +1,1115 @@ +# Change Log + +All notable changes to `nalgebra`, starting with the version 0.6.0 will be +documented here. + +This project adheres to [Semantic Versioning](https://semver.org/). + +## [0.33.0] (23 June 2024) + +### Fixed + +- Fix a memory leak in `Matrix::generic_resize`. +- Fix `glm::is_null` to check the vector magnitude instead of individual components. +- Ensure that inverting a 4x4 matrix leaves it unchanged if the inversion fails. + +### Added + +- Add the `glam-0.28` feature to enable conversion from/to types from `glam` v0.28. +- Add a `stack!` macro for concatenating matrices. See [#1375](https://github.com/dimforge/nalgebra/pull/1375). + +### Modified + +- The `cuda` feature has been removed, as the toolchain it depends on is long abandoned. +- Update to `simba` 0.9. See the [changelog](https://github.com/dimforge/simba/blob/master/CHANGELOG) of `simba` for + details. +- Update the `nalgebra-macros` crate to `syn` 2.0. +- Remove the scalar type `T` from the `Allocator` trait parameters. Instead of `Allocator`, use the simpler + `Allocator`. + +## [0.32.6] (12 June 2024) + +### Added + +- Add the `glam-0.27` feature to enable conversion from/to types from `glam` v0.27. + +## [0.32.5] (28 March 2024) + +## Fixed + +- Fix numerical issue on SVD with near-identity matrix. + +## [0.32.4] (19 Feb 2023) + +### Added + +- Add the `glam-0.25` feature to enable conversion from/to types from `glam` v0.25. + +## [0.32.3] (09 July 2023) + +### Modified + +- Statically sized matrices are now serialized as tuples to match how serde + serialized plain arrays. +- Don’t require `Scalar` for matrix `PartialEq` and `Eq`. + +### Added + +- Allow trailing punctuation in macros `vector!`, `matrix!`, `point!`, etc. +- Add the methods `Matrix1::as_scalar`, `::as_scalar_mut`, `::to_scalar`, `::into_scalar`. +- Add `Rotation3::euler_angles_ordered`, a generalized euler angles calculation. +- Add the `glam-0.24` feature to enable conversion from/to types from `glam` v0.24. +- Add the `glam-0.25` feature to enable conversion from/to types from `glam` v0.25. +- Add the `lerp` method to points. +- Implement `Clone` for `MatrixIter`. + +### Fixed + +- Fixed severe catastrophic cancellation issue in variance calculation. + +## [0.32.2] (07 March 2023) + +### Added + +- Add the `glam-0.23` to enable conversion from/to type from `glam` v0.23. + +## [0.32.1] (14 Jan. 2023) + +### Modified + +- Updated `nalgebra-macros` to use the new `Dyn`, avoiding macro-generated deprecation warnings. + +## [0.32.0] (14 Jan. 2023) + +### Modified + +- Renamed all `MatrixSlice` types to `MatrixView`. In general all occurrences of the world `Slice` or `slice` have been + replaced by `View` or `view`. +- Deprecated all the types involving `Slice` in its name, in favor of the word `View`. +- Make it so that most `nalgebra` objects archive as themselves (when using `rkyv` for serialization). +- Renamed `Dynamic` to `Dyn` and make `Dyn` a tuple struct. + +### Added + +- Add `Cholesky::ln_determinant` to compute the natural logarithm of the determinant of a matrix decomposed + with Cholesky. This can be more numerically stable than computing the determinant itself when very small and/or + large values are involved. +- Added new methods `Matrix::as_view` and `Matrix::as_view_mut`, which are very useful when working with view-based + APIs. +- Added parallel column iterator using `rayon`: `Matrix::par_column_iter` and `Matrix::par_column_iter_mut`. The `rayon` + feature must be enabled to access these methods. +- Implement `ReshapableStorage` for matrix slices (only for unit strides at the moment). +- Add `U0, U1, …` constants alongside the `U0, U1, …` types. This lets us write `U4` instead of `U4::name()` or + `Const::<4>` when we need const dimensions. + +### Fixed + +- Fixed the implementation of `Rotation3::euler_angles` to return the angles in the documented order (roll, pitch, yaw). + +## [0.31.4] (13 Nov. 2022) + +### Added + +- Add a `convert-glam022` feature to enable conversion between `nalgebra` and `glam v0.22`. + +## [0.31.3] (30 Oct. 2022) + +### Added + +- Add `Matrix::try_cast` to attempt casting the inner scalar types when that cast may fail. + +### Fixed + +- Fixed the usage of `CheckBytes` with `rkyv`. + +## [0.31.2] (09 Oct. 2022) + +### Modified + +- Use `#[inline]` on the `Dim` implementation for `Const` to improve opt-level 1 performance. +- Make the `Point::new` constructions const-fn. + +### Added + +- Add `UnitVector::cast` to change the underlying scalar type. + +## [0.31.1] (31 July 2022) + +### Modified + +- Improve performances of multiplication of two sparse matrices. + +### Added + +- Add `Matrix::from_row_iterator` to build a matrix from an iterator yielding components in row-major order. +- Add support for conversion from/to types of `glam` 0.21. +- `nalgebra-sparse`: add support for the matrix-market export of sparse matrices. +- `nalgebra-lapack`: add a `GE` for solving the generalized eigenvalues problem. + +### Fixed + +- Fix `Rotation3::from_matrix` and `UnitQuaternion::from_matrix` when the input matrix is already a valid + rotation matrix. + +## [0.31.0] (30 Apr. 2022) + +### Breaking changes + +- Switch to `cust` 0.3 (for CUDA support). +- Switch to `rkyv` 0.7 +- Remove support for serialization based on `abomonation`. +- Remove support for conversions between `nalgebra` types and `glam` 0.13. + +### Modified + +- The aliases for `Const` types have been simplified to help `rust-analyzer`. + +### Added + +- Add `TryFrom` conversion between `UnitVector2/3/4` and `glam`’s `Vec2/3/4`. +- `nalgebra-sparse`: added support for serialization of sparse matrices with `serde`. +- `nalgebra-sparse`: add a CSC matrix constructor from unsorted (but valid) data. +- `nalgebra-lapack`: add generalized eigenvalues/eigenvectors calculation + QZ decomposition. + +### Fixed + +- Improve stability of SVD. +- Fix slerp for `UnitComplex`. + +## [0.30.1] (09 Jan. 2022) + +### Added + +- Add conversion from/to types of `glam` 0.19 and 0.20. + +## [0.30.0] (02 Jan. 2022) + +### Breaking changes + +- The `Dim` trait is now marked as unsafe. +- The `Matrix::pow` and `Matrix::pow_mut` methods only allow positive integer exponents now. To compute negative + exponents, the user is free to invert the matrix before calling `pow` with the exponent’s absolute value. +- Remove the `Bounded` requirement from `RealField`. Replace it by methods returning `Option` so that they can + still be implemented by unbounded types (by returning `None`). +- The `ComplexField` trait derives from `FromPrimitive` again. We can actually keep this because all its methods + return `Option`, meaning that it could be implemented by any type. + +### Modified + +- Use more concise debug impls for matrices and geometric transformation types. +- The singular values computed by the SVD are now sorted in increasing order by default. Use `SVD::new_unordered` + instead to reproduce the older behavior without the sorting overhead. +- The `UnitDualQuaternion::sclerp` method will no longer panic when given two equal rotations. +- The `Matrix::select_rows` and `Matrix::select_columns` methods no longer require the matrix components to implement + the trait `Zero`. +- The `Matrix::pow` and `Matrix::pow_mut` methods will now also work with integer matrices. + +### Added + +- Added the conversion trait `From>` and method `from_vec_storage` for `RowDVector`. +- Added implementation of `From` and `Into` for converting between `nalgebra` types and types from + `glam 0.18`. These can be enabled by enabling the `convert-glam018` cargo features. +- Added the methods `Matrix::product`, `::row_product`, `::row_product_tr`, and `::column_product` to compute the + product of the components, rows, or columns, of a single matrix or vector. +- The `Default` trait is now implemented for most geometric types: `Point`, `Isometry`, `Rotation`, `Similarity`, + `Transform`, `UnitComplex`, and `UnitQuaternion`. +- Added the `Scale` geometric type for representing non-uniform scaling. +- Added `Cholesky::new_with_substitute` that will replace diagonal elements by a given constant whenever `Cholesky` + meets a non-definite-positiveness. +- Re-added the conversion from a vector/matrix slice to a static array. +- Added the `cuda` feature that enables the support of [rust-cuda](https://github.com/Rust-GPU/Rust-CUDA) for using + `nalgebra` features with CUDA kernels written in Rust. +- Added special-cases implementations for the 2x2 and 3x3 SVDs for better accuracy and performances. +- Added the methods `Matrix::polar`, `Matrix::try_polar`, and `SVD::to_polar` to compute the polar decomposition of + a matrix, based on its SVD. +- `nalgebra-sparse`: provide constructors for unsorted but otherwise valid data using the CSR format. +- `nalgebra-sparse`: added reading MatrixMarked data files to a sparse `CooMatrix`. + +### Fixed + +- Fixed a potential unsoundness with `matrix.get(i)` and `matrix.get_mut(i)` where `i` is an `usize`, and `matrix` + is a matrix slice with non-default strides. +- Fixed potential unsoundness with `vector.perp` where `vector` isn’t actually a 2D vector as expected. +- Fixed linkage issue with `nalgebra-lapack`: the user of `nalgebra-lapack` no longer have to add + `extern crate lapack-src` to their `main.rs`. +- Fixed the `no-std` build of `nalgebra-glm`. +- Fix the `pow` and `pow_mut` functions (the result was incorrect for some exponent values). + +## [0.29.0] + +### Breaking changes + +- We updated to the version 0.6 of `simba`. This means that the trait bounds `T: na::RealField`, `na::ComplexField`, + `na::SimdRealField`, `na:SimdComplexField` no imply that `T: Copy` (they only imply that `T: Clone`). This may affect + generic code. +- The closure given to `apply`, `zip_apply`, `zip_zip_apply` must now modify the + first argument inplace, instead of returning a new value. This makes these + methods more versatile, and avoid useless clones when using non-Copy scalar + types. +- The `Allocator` trait signature has been significantly modified in order to handle uninitialized matrices in a sound + way. + +### Modified + +- `Orthographic3::from_matrix_unchecked` is now `const fn`. +- `Perspective3::from_matrix_unchecked` is now `const fn`. +- `Rotation::from_matrix_unchecked` is now `const fn`. +- The `Scalar` is now automatically implemented for most `'static + Clone` types. Type that implement `Clone` but not + `Copy` are now much safer to work with thanks to the refactoring of the `Allocator` system. + +### Added + +- The conversion traits form the `bytemuck` crates are now implemented for the geometric types too. +- Added operator overloading for `Transform * UnitComplex`, `UnitComplex * Transform`, `Transform ×= UnitComplex`, + `Transform ÷= UnitComplex`. +- Added `Reflection::bias()` to retrieve the bias of the reflection. +- Added `Reflection1..Reflection6` aliases for 1D to 6D reflections. +- Added implementation of `From` and `Into` for converting between `nalgebra` types and types from + `glam 0.16` and `glam 0.17`. These can be enabled by enabling the `convert-glam016`, and/or `convert-glam017` + cargo features. + +## [0.28.0] + +### Added + +- Implement `Hash` for `Transform`. +- Implement `Borrow` and `BorrowMut` for contiguous slices. + +### Modified + +- The `OPoint` type has been added. It takes the dimension number as a type-level integer (e.g. `Const<3>`) + instead + of a const-generic. The type `Point` is now an alias for `OPoint`. This changes doesn't affect any + of the existing code using `Point`. However, it will allow the use `OPoint` in a generic context where the dimension + cannot be easily expressed as a const-generic (because of the current limitation of const-generics in Rust). +- Several clippy warnings were fixed. This results in some method signature changes (e.g. taking `self` instead + of `&self`) + but this should not have any practical infulances on existing codebase. +- The `Point::new` constructors are no longer const-fn. This is due to some limitations in const-fn + not allowing custom trait-bounds. Use the `point!` macro instead to build points in const environments. +- `Dynamic::new` and `Unit::new_unchecked` are now const-fn. +- Methods returning `Result<(), ()>` now return `bool` instead. + +### Fixed + +- Fixed a potential unsoundess issue when converting a mutable slice to a `&mut[T]`. + +## [0.27.1] + +### Fixed + +- Fixed a bug in the conversion from `glam::Vec2` or `glam::DVec2` to `Isometry2`. + +## [0.27.0] + +This removes the `convert-glam` and `convert-glam-unchecked` optional features. +Instead, this adds the `convert-glam013`, `convert-glam014`, and `convert-glam015` optional features for +conversions targeting the versions 0.13, 0.14, and 0.15 of `glam`. + +### Added + +- Add macros `matrix!`, `dmatrix!`, `vector!`, `dvector!`, `point!` for constructing matrices/vectors/points in a + more convenient way. See [#886](https://github.com/dimforge/nalgebra/pull/886) + and [#899](https://github.com/dimforge/nalgebra/pull/899). +- Add `CooMatrix::reserve` to `nalgebra-sparse`. +- Add basic support for serialization using `rkyv`. Can be enabled with the features `rkyv-serialize` or + `rkyv-serialize-no-std`. + +### Fixed + +- Fixed a potential unsoundness issue after deserializing an invalid `DVector` using `serde`. + +## [0.26.2] + +### Added + +- Conversion from an array `[T; D]` to an isometry `Isometry` (as a translation). +- Conversion from a static vector `SVector` to an isometry `Isometry` (as a translation). +- Conversion from a point `Point` to an isometry `Isometry` (as a translation). +- Conversion of an array `[T; D]` from/to a translation `Translation`. +- Conversion of a point `Point` to a translation `Translation`. +- Conversion of the tuple of glam types `(Vec3, Quat)` from/to an `Isometry2` or `Isometry3`. +- Conversion of a glam type `Vec2/3/4` from/to a `Translation2/3/4`. + +## [0.26.1] + +Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized with `serde`. + +## [0.26.0] + +This release integrates `min-const-generics` to nalgebra. See +[our blog post](https://www.dimforge.com/blog/2021/04/12/integrating-const-generics-to-nalgebra) +for details about this release. + +### Added + +- Add type aliases for unit vector, e.g., `UnitVector3`. +- Add a `pow` and `pow_mut` function to square matrices. +- Add `Cholesky::determinant` to compute the determinant of a matrix decomposed + with Cholesky. +- Add the `serde-serialize-no-std` feature to enable serialization of static matrices/vectors + with serde, but without requiring `std`. + +### Modified + +- The `serde` crate isn't enabled by default now. Enable the `serde-serialize` or the + `serde-serialize-no-std` features instead. +- The `Const` type has been introduced to represent dimensions known + at compile-time. This replaces the type-level integers from `typenum` as well as + the `U1, U2, ..., U127` types from `nalgebra`. These `U1, U2, ..., U127` are now + just aliases for `Const`, e.g., `type U2 = Const<2>`. +- The `ArrayStorage` now uses a standard array `[[T; R]; C]` instead of a `GenericArray`. +- Many trait bounds were changed to accommodate const-generics. Most of these changes + should be transparent wrt. non-generic code. +- The `MatrixMN` alias has been deprecated. Use `OMatrix` or `SMatrix` instead. +- The `MatrixN` alias has been deprecated. Use `OMatrix` or `SMatrix` instead. +- The `VectorN` alias has been deprecated. Use `OVector` or `SVector` instead. +- The `Point`, `Translation`, `Isometry`, `Similarity`, and `Transformation` types now take an + integer for their dimension (instead of a type-level integer). +- The type parameter order of `Isometry`, `Similarity`, `Transformation` changed to put + the integer dimensions in the last position (this is required by the compiler). +- The `::new` constructors of translations, points, matrices, and vectors of dimensions `<= 6` + are now `const fn`, making them usable to define constant globals. The `Quaternion::new` + constructor is also a `const fn` now. + +## [0.25.4] + +### Fixed + +- Fix a compilation error when only the `serde-serialize` feature is enabled. + +## [0.25.3] + +### Added + +- The `Vector::simd_cap_magnitude` method to cap the magnitude of the vector with + SIMD components. + +## [0.25.2] + +### Added + +- A `convert-glam` cargo feature to enable implementations of `From` traits to convert + between `glam` types and `nalgebra` types. +- A `convert-glam-unchecked` cargo feature to enable some extra `glam`/`nalgebra` conversions that may + lead to unexpected results if used improperly. For example, this enables the conversion from a + `glam::Mat4` to a `na::Isometry3`. This conversion will be cheap (without any check) but willlead to + unexpected results if the glam matrix contains non-isometric components (like scaling for example). +- A `cast` method has been added to most types. This can be used to change the + type of the components of a given entity. Example: `vector.cast::()`. + +## [0.25.1] + +This release replaces the version 0.25.0 which has been yanked. The 0.25.0 version +added significant complication to build `nalgebra` targeting a `#[no-std]` platform +not supported by `rand`. + +The `rand` dependency is now optional (and disabled by default). You may enable it with: + +- The `rand-no-std` cargo feature when targeting a `#[no-std]` environment. +- The `rand` cargo feature when targeting a `std` environment. + +## [0.25.0] - Yanked + +This updates all the dependencies of nalgebra to their latest version, including: + +- rand 0.8 +- proptest 1.0 +- simba 0.4 + +### New crate: nalgebra-sparse + +Alongside this release of `nalgebra`, we are releasing `nalgebra-sparse`: a crate dedicated to sparse matrix +computation with `nalgebra`. The `sparse` module of `nalgebra`itself still exists for backward compatibility, +but it will be deprecated soon in favor of the `nalgebra-sparse` crate. + +### Added + +* Add `UnitDualQuaternion`, a dual-quaternion with unit magnitude which can be used as an isometry transformation. +* Add `UDU::new()` and `matrix.udu()` to compute the UDU factorization of a matrix. +* Add `ColPivQR::new()` and `matrix.col_piv_qr()` to compute the QR decomposition with column pivoting of a matrix. +* Add `from_basis_unchecked` to all the rotation types. This builds a rotation from a set of basis vectors (representing + the columns of the corresponding rotation matrix). +* Add `Matrix::cap_magnitude` to cap the magnitude of a vector. +* Add `UnitQuaternion::append_axisangle_linearized` to approximately append a rotation represented as an axis-angle to a + rotation represented as an unit quaternion. +* Mark the iterators on matrix components as `DoubleEndedIter`. +* Re-export `simba::simd::SimdValue` at the root of the `nalgebra` crate. + +## [0.24.0] + +### Added + +* The `DualQuaternion` type. It is still work-in-progress, but the basics are here: + creation from its real and dual part, multiplication of two dual quaternions, + and normalization. + +### Removed + +* There is no blanket `impl PartialEq for Unit` anymore. Instead, it is + implemented specifically for `UnitComplex`, `UnitQuaternion` and `Unit`. + +## [0.23.2] + +In this release, we improved the documentation of some of the geometric types +by applying changes similar to what we did in the version 0.23.1 for matrices. + +### Added + +* The `Isometry::inv_mul` method which is a more efficient way of doing + `isometry1.inverse() * isometry2`. + +## [0.23.1] + +In this release we improved the documentation of the matrix and vector types by: + +- Grouping `impl` bocks logically, adding a title comment to these impl blocks. +- Reference these impl blocks docs at the top of the documentation page for `Matrix`. +- Reduce the depth of type aliasing. Now all vector and matrix types are aliases of `Matrix` + directly (instead of being aliases for other aliases). + +## [0.23.0] + +### Added + +* The `.inverse_transform_unit_vector(v)` was added to `Rotation2/3`, `Isometry2/3`, `UnitQuaternion`, + and `UnitComplex`. + It applies the corresponding rotation to a unit vector `Unit`. +* The `Point.map(f)` and `Point.apply(f)` to apply a function to each component of the point, similarly + to `Vector.map(f)` + and `Vector.apply(f)`. +* The `Quaternion::from([N; 4])` conversion to build a quaternion from an array of four elements. +* The `Isometry::from(Translation)` conversion to build an isometry from a translation. +* The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit>` with its i-th component set to 1.0, + and the + others set to zero. +* The `Isometry.lerp_slerp` and `Isometry.try_lerp_slerp` methods to interpolate between two isometries using linear + interpolation for the translational part, and spherical interpolation for the rotational part. +* The `Rotation2.slerp`, `Rotation3.slerp`, and `UnitQuaternion.slerp` method for + spherical interpolation. + +## [0.22.0] + +In this release, we are using the new version 0.2 of simba. One major change of that version is that the +use of `libm` is now opt-in when building targeting `no-std` environment. If you are using floating-point +operations with nalgebra in a `no-std` environment, you will need to enable the new `libm` feature +of nalgebra for your code to compile again. + +### Added + +* The `libm` feature that enables `libm` when building for `no-std` environment. +* The `libm-force` feature that enables `libm` even when building for a not `no-std` environment. +* `Cholesky::new_unchecked` which build a Cholesky decomposition without checking that its input is + positive-definite. It can be used with SIMD types. +* The `Default` trait is now implemented for matrices, and quaternions. They are all filled with zeros, + except for `UnitQuaternion` which is initialized with the identity. +* Matrix exponential `matrix.exp()`. +* The `Vector::ith(i, x)` that builds a vector filled with zeros except for the `i`-th component set to `x`. + +## [0.21.0] + +In this release, we are no longer relying on traits from the __alga__ crate for our generic code. +Instead, we use traits from the new [simba](https://crates.io/crates/simba) crate which are both +simpler, and allow for significant optimizations like AoSoA SIMD. + +Refer to the [monthly dimforge blogpost](https://www.dimforge.org/blog/2020/04/01/this-month-in-dimforge/) +for details about this switch and its benefits. + +### Added + +* It is now possible to use SIMD types like `simba::f32x4` as scalar types for nalgebra's matrices and + geometric types. + +### Modified + +* Use of traits like `alga::general::{RealField, ComplexField}` have now been replaced by + `simba::scalar::{RealField, ComplexField}`. +* The implementation of traits from the __alga__ crate (and well as the dependency to _alga__) are now + omitted unless the `alga` cargo feature is activated. + +### Removed + +* The `Neg` unary operator is no longer implemented for `UnitComplex` and `UnitQuaternion`. This caused + hard-to-track errors when we mistakenly write, e.g., `-q * v` instead of `-(q * v)`. +* The `na::convert_unchecked` is no longer marked as unsafe. + +## [0.20.0] + +### Added + +* `cholesky.rank_one_update(...)` which performs a rank-one update on the cholesky decomposition of a matrix. +* `From<&Matrix>` is now implemented for matrix slices. +* `.try_set_magnitude(...)` which sets the magnitude of a vector, while keeping its direction. +* Implementations of `From` and `Into` for the conversion between matrix slices and standard (`&[N]` `&mut [N]`) slices. + +### Modified + +* We started some major changes in order to allow non-Copy types to be used as scalar types inside of matrices/vectors. + +## [0.19.0] + +### Added + +* `.remove_rows_at` and `remove_columns_at` which removes a set of rows or columns (specified by indices) from a matrix. +* Several formatting traits have been implemented for all matrices/vectors: `LowerExp`, `UpperExp`, `Octal`, `LowerHex`, + `UpperHex`, `Binary`, `Pointer`. +* `UnitQuaternion::quaternions_mean(...)` which computes the mean rotation of a set of unit quaternions. This implements + the algorithm from _Oshman, Yaakov, and Avishy Carmi, "Attitude estimation from vector observations using a + genetic-algorithm-embedded quaternion particle filter." + +### Modified + +* It is now possible to get the `min/max` element of unsigned integer matrices. + +### Added to nalgebra-glm + +* Some infinite and reversed perspectives: `::infinite_perspective_rh_no`, `::infinite_perspective_rh_zo`, + `::reversed_perspective_rh_zo`, and `::reversed_infinite_perspective_rh_zo`. + +## [0.18.0] + +This release adds full complex number support to nalgebra. This includes all common vector/matrix operations as well +as matrix decomposition. This excludes geometric type (like `Isometry`, `Rotation`, `Translation`, etc.) from the +`geometry` module. + +### Added + +#### Quaternion and geometric operations + +* Add trigonometric functions for + quaternions: `.cos, .sin, .tan, .acos, .asin, .atan, .cosh, .sinh, .tanh, .acosh, .asinh, .atanh`. +* Add geometric algebra operations for quaternions: `.inner, .outer, .project, .rejection` +* Add `.left_div, .right_div` for quaternions. +* Add `.renormalize` to `Unit<...>` and `Rotation3` to correct potential drift due to repeated operations. + Those drifts could cause them not to be pure rotations anymore. + +#### Convolution + +* `.convolve_full(kernel)` returns the convolution of `self` by `kernel`. +* `.convolve_valid(kernel)` returns the convolution of `self` by `kernel` after removal of all the elements relying on + zero-padding. +* `.convolve_same(kernel)` returns the convolution of `self` by `kernel` with a result of the same size as `self`. + +#### Complex number support + +* Add the `::from_matrix` constructor too all rotation types to extract a rotation from a raw matrix. +* Add the `::from_matrix_eps` constructor too all rotation types to extract a rotation from a raw matrix. This takes + more argument than `::from_matrix` to control the convergence of the underlying optimization algorithm. +* Add `.camax()` which returns the matrix component with the greatest L1-norm. +* Add `.camin()` which returns the matrix component with the smallest L1-norm. +* Add `.ad_mul(b)` for matrix-multiplication of `self.adjoint() * b`. +* Add `.ad_mul_to(b)` which is the same as `.ad_mul` but with a provided matrix to be filled with the result of the + multiplication. +* Add BLAS operations involving complex conjugation (following similar names as the original BLAS spec): + * `.dotc(rhs)` equal to `self.adjoint() * rhs`. + * `.gerc(alpha, x, y, beta)` equivalent to `self = alpha * x * y.adjoint() + beta * self` + * `.hegerc` which is like `gerc` but for Hermitian matrices. + * `.syger` which is the new name of `.ger_symm` which is equivalent + to `self = alpha * x * y.transpose() + beta * self`. + * `.sygemv` which is the new name of `.gemv_symm` which is equivalent to `self = alpha * a * x + beta * self` + with `a` symmetric. + * `.hegemv(alpha, a, x, beta)` which is like `.sygemv` but with `a` Hermitian. + * `.gemv_ad(alpha, a, x, beta)` which is equivalent to `self = alpha * a.adjoint() * x + beta * self`. + * `.gemm_ad(alpha, a, b, beta)` which is equivalent to `self = alpha * a.adjoint() * b + beta * self`. + * `.icamax()` which returns the index of the complex vector component with the greatest L1-norm. + +Note that all the other BLAS operation will continue to work for all fields, including floats and complex numbers. + +### Renamed + +* `RealSchur` has been renamed `Schur` because it can now work with complex matrices. + +## [0.17.0] + +### Added + +* Add swizzling up to dimension 3 for vectors. For example, you can do `v.zxy()` as an equivalent + to `Vector3::new(v.z, v.x, v.y)`. +* Add swizzling up to dimension 3 for points. For example, you can do `p.zxy()` as an equivalent + to `Point3::new(p.z, p.x, p.y)`. +* Add `.copy_from_slice` to copy matrix components from a slice in column-major order. +* Add `.dot` to quaternions. +* Add `.zip_zip_map` for iterating on three matrices simultaneously, and applying a closure to them. +* Add `.slerp` and `.try_slerp` to unit vectors. +* Add `.lerp` to vectors. +* Add `.to_projective` and `.as_projective` to `Perspective3` and `Orthographic3` in order to + use them as `Projective3` structures. +* Add `From/Into` impls to allow the conversion of any transformation type to a matrix. +* Add `Into` impls to convert a matrix slice into an owned matrix. +* Add `Point*::from_slice` to create a point from a slice. +* Add `.map_with_location` to matrices to apply a map which passes the component indices to the user-defined closure + alongside + the component itself. +* Add impl `From` for `Point`. +* Add impl `From` for `Quaternion`. +* Add impl `From` for `Translation`. +* Add the `::from_vec` constructor to construct a matrix from a `Vec` (a `DMatrix` will reuse the original `Vec` + as-is for its storage). +* Add `.to_homogeneous` to square matrices (and with dimensions higher than 1x1). This will increase their number of row + and columns by 1. The new column and row are filled with 0, except for the diagonal element which is set to 1. +* Implement `Extend` for matrices with a dynamic storage. The provided `Vec` is assumed to represent a column-major + matrix with the same number of rows as the one being extended. This will effectively append new columns on the right + of + the matrix being extended. +* Implement `Extend` for vectors with a dynamic storage. This will concatenate the vector with the given `Vec`. +* Implement `Extend>` for matrices with dynamic storage. This will concatenate the columns of both matrices. +* Implement `Into` for the `MatrixVec` storage. +* Implement `Hash` for all matrices. +* Add a `.len()` method to retrieve the size of a `MatrixVec`. + +### Modified + +* The orthographic projection no longer require that `bottom < top`, that `left < right`, and that `znear < zfar`. The + only restriction now ith that they must not be equal (in which case the projection would be singular). +* The `Point::from_coordinates` methods is deprecated. Use `Point::from` instead. +* The `.transform_point` and `.transform_vector` methods are now inherent methods for matrices so that the user does not + have to + explicitly import the `Transform` trait from the alga crate. +* Renamed the matrix storage types: `MatrixArray` -> `ArrayStorage` and `MatrixVec` -> `VecStorage`. +* Renamed `.unwrap()` to `.into_inner()` for geometric types that wrap another type. + This is for the case of `Unit`, `Transform`, `Orthographic3`, `Perspective3`, `Rotation`. +* Deprecate several functions at the root of the crate (replaced by methods). + +### Removed + + * Remove the `Deref` impl for `MatrixVec` as it could cause hard-to-understand compilation errors. + +### nalgebra-glm + +* Add several alternative projection computations, e.g., `ortho_lh`, `ortho_lh_no`, `perspective_lh`, etc. +* Add features matching those of nalgebra, in particular:`serde-serialize`, `abmonation-serialize`, std` (enabled by + default). + +## [0.16.0] + +All dependencies have been updated to their latest versions. + +## Modified + +* Adjust `UnitQuaternion`s, `Rotation3`s, and `Rotation2`s generated from the `Standard` distribution to be uniformly + distributed. + +### Added + +* Add a feature `stdweb` to activate the dependency feature `rand/stdweb`. +* Add blas-like methods `.imin()` and `.imax()` that return the index of the minimum and maximum entry of a vector. +* Add construction of a `Point` from an array by implementing the `From` trait. +* Add support for generating uniformly distributed random unit column vectors using the `Standard` distribution. + +## [0.15.0] + +The most notable change of this release is the support for using part of the library without the rust standard +library (i.e. it supports `#![no_std]`). See the +corresponding [documentation](https://nalgebra.org/wasm_and_embedded_programming/). + +### Modified + +* Rename the `core` module to `base` to avoid conflicts with the `core` crate implicitly imported when + `#![no_std]` is enabled. +* Constructors of the `MatrixSlice*` types have been renamed from `new_*` to `from_slice_*`. This was + necessary to avoid the `incoherent_fundamental_impls` lint that is going to become a hard error. + +### Added + +* Add `UnitQuaternion` constructor `::new_eps(...)` and `::from_scaled_axis_eps(...)` that return the + identity if the magnitude of the input axisangle is smaller than the epsilon provided. +* Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex` + to compute the rotation matrix between two 2D **unit** vectors. +* Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the + unit rotation axis, and the rotation angle simultaneously. +* Add functions to construct a random matrix with a user-defined distribution: `::from_distribution(...)`. + +## [0.14.0] + +### Modified + +* Allow the `Isometry * Unit` multiplication. + +### Added + +* Add blas-like operations: `.quadform(...)` and `.quadform_tr(...)` to compute respectively + the quadratic forms `self = alpha * A.transpose() * B * A + beta * self` and + `alpha * A * B * A.transpose() + beta * self`. Here, `A, B` are matrices with + `B` square, and `alpha, beta` are reals. +* Add blas-like operations: `.gemv_tr(...)` that behaves like `.gemv` except that the + provided matrix is assumed to be transposed. +* Add blas-like operations: `cmpy, cdpy` for component-wise multiplications and + division with scalar factors: + - `self <- alpha * self + beta * a * b` + - `self <- alpha * self + beta * a / b` +* `.cross_matrix()` returns the cross-product matrix of a given 3D vector, i.e., + the matrix `M` such that for all vector `v` we have + `M * v == self.cross(&v)`. +* `.iamin()` that returns the index of the vector entry with + the smallest absolute value. +* The `mint` feature that can be enabled in order to allow conversions from + and to types of the [mint](https://crates.io/crates/mint) crate. +* Aliases for matrix and vector slices. Their are named by adding `Slice` + before the dimension numbers, i.e., a 3x5 matrix slice with dimensions known + at compile-time is called `MatrixSlice3x5`. A vector slice with dimensions + unknown at compile-time is called `DVectorSlice`. +* Add functions for constructing matrix slices from a slice `&[N]`, e.g., + `MatrixSlice2::new(...)` and `MatrixSlice2::new_with_strides(...)`. +* The `::repeat(...)` constructor that is an alternative name to + `::from_element(...)`. +* `UnitQuaternion::scaled_rotation_between_axis(...)` and + `UnitQuaternion::rotation_between_axis(...)` that take Unit vectors instead of + Vector as arguments. + +## [0.13.0] + +The **nalgebra-lapack** crate has been updated. This now includes a broad range +matrix decompositions using LAPACK bindings. + +This adds support for serialization using the +[abomonation](https://crates.io/crates/abomonation) crate. + +### Breaking semantic change + +* The implementation of slicing with steps now matches the documentation. + Before, step identified the number to add to pass from one column/row index + to the next one. This made 0 step invalid. Now (and on the documentation so + far), the step is the number of ignored row/columns between each + row/column. Thus, a step of 0 means that no row/column is ignored. For + example, a step of, say, 3 on previous versions should now bet set to 2. + +### Modified + +* The trait `Axpy` has been replaced by a method `.axpy`. +* The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we + reordered M and N to be in alphabetical order). +* In-place componentwise multiplication and division + `.component_mul_mut(...)` and `.component_div_mut(...)` have been deprecated + for a future renaming. Use `.component_mul_assign(...)` and + `.component_div_assign(...)` instead. + +### Added + +* `alga::general::Real` is now re-exported by nalgebra. + elements.) +* `::zeros(...)` that creates a matrix filled with zeroes. +* `::from_partial_diagonal(...)` that creates a matrix from diagonal elements. + The matrix can be rectangular. If not enough elements are provided, the rest + of the diagonal is set to 0. +* `.conjugate_transpose()` computes the transposed conjugate of a + complex matrix. +* `.conjugate_transpose_to(...)` computes the transposed conjugate of a + complex matrix. The result written into a user-provided matrix. +* `.transpose_to(...)` is the same as `.transpose()` but stores the result in + the provided matrix. +* `.conjugate_transpose_to(...)` is the same as `.conjugate_transpose()` but + stores the result in the provided matrix. +* Implements `IntoIterator` for `&Matrix`, `&mut Matrix` and `Matrix`. +* `.mul_to(...)` multiplies two matrices and stores the result to the given buffer. +* `.tr_mul_to(...)` left-multiplies `self.transpose()` to another matrix and stores the result to the given buffer. +* `.add_scalar(...)` that adds a scalar to each component of a matrix. +* `.add_scalar_mut(...)` that adds in-place a scalar to each component of a matrix. +* `.kronecker(a, b)` computes the kronecker product (i.e. matrix tensor + product) of two matrices. +* `.apply(f)` replaces each component of a matrix with the results of the + closure `f` called on each of them. + +Pure Rust implementation of some Blas operations: + +* `.iamax()` returns the index of the maximum value of a vector. +* `.axpy(...)` computes `self = a * x + b * self`. +* `.gemv(...)` computes `self = alpha * a * x + beta * self` with a matrix and vector `a` and `x`. +* `.ger(...)` computes `self = alpha * x^t * y + beta * self` where `x` and `y` are vectors. +* `.gemm(...)` computes `self = alpha * a * b + beta * self` where `a` and `b` are matrices. +* `.gemv_symm(...)` is the same as `.gemv` except that `self` is assumed symmetric. +* `.ger_symm(...)` is the same as `.ger` except that `self` is assumed symmetric. + +New slicing methods: + +* `.rows_range(...)` that retrieves a reference to a range of rows. +* `.rows_range_mut(...)` that retrieves a mutable reference to a range of rows. +* `.columns_range(...)` that retrieves a reference to a range of columns. +* `.columns_range_mut(...)` that retrieves a mutable reference to a range of columns. + +Matrix decompositions implemented in pure Rust: + +* Cholesky, SVD, LU, QR, Hessenberg, Schur, Symmetric eigendecompositions, + Bidiagonal, Symmetric tridiagonal +* Computation of householder reflectors and givens rotations. + +Matrix edition: + +* `.upper_triangle()` extracts the upper triangle of a matrix, including the diagonal. +* `.lower_triangle()` extracts the lower triangle of a matrix, including the diagonal. +* `.fill(...)` fills the matrix with a single value. +* `.fill_with_identity(...)` fills the matrix with the identity. +* `.fill_diagonal(...)` fills the matrix diagonal with a single value. +* `.fill_row(...)` fills a selected matrix row with a single value. +* `.fill_column(...)` fills a selected matrix column with a single value. +* `.set_diagonal(...)` sets the matrix diagonal. +* `.set_row(...)` sets a selected row. +* `.set_column(...)` sets a selected column. +* `.fill_lower_triangle(...)` fills some sub-diagonals below the main diagonal with a value. +* `.fill_upper_triangle(...)` fills some sub-diagonals above the main diagonal with a value. +* `.swap_rows(...)` swaps two rows. +* `.swap_columns(...)` swaps two columns. + +Column removal: + +* `.remove_column(...)` removes one column. +* `.remove_fixed_columns(...)` removes `D` columns. +* `.remove_columns(...)` removes a number of columns known at run-time. + +Row removal: + +* `.remove_row(...)` removes one row. +* `.remove_fixed_rows(...)` removes `D` rows. +* `.remove_rows(...)` removes a number of rows known at run-time. + +Column insertion: + +* `.insert_column(...)` adds one column at the given position. +* `.insert_fixed_columns(...)` adds `D` columns at the given position. +* `.insert_columns(...)` adds at the given position a number of columns known at run-time. + +Row insertion: + +* `.insert_row(...)` adds one row at the given position. +* `.insert_fixed_rows(...)` adds `D` rows at the given position. +* `.insert_rows(...)` adds at the given position a number of rows known at run-time. + +## [0.12.0] + +The main change of this release is the update of the dependency serde to 1.0. + +### Added + +* `.trace()` that computes the trace of a matrix (the sum of its diagonal + elements.) + +## [0.11.0] + +The [website](https://nalgebra.org) has been fully rewritten and gives a good +overview of all the added/modified features. + +This version is a major rewrite of the library. Major changes are: + +* Algebraic traits are now defined by the [alga](https://crates.io/crates/alga) crate. + All other mathematical traits, except `Axpy` have been removed from + **nalgebra**. +* Methods are now preferred to free functions because they do not require any + trait to be used anymore. +* Most algebraic entities can be parametrized by type-level integers + to specify their dimensions. Using `Dynamic` instead of a type-level + integer indicates that the dimension known at run-time only. +* Statically-sized **rectangular** matrices. +* More transformation types have been added: unit-sized complex numbers (for + 2D rotations), affine/projective/general transformations with `Affine2/3`, + `Projective2/3`, and `Transform2/3`. +* Serde serialization is now supported instead of `rustc_serialize`. Enable + it with the `serde-serialize` feature. +* Matrix **slices** are now implemented. + +### Added + +Lots of features including rectangular matrices, slices, and Serde +serialization. Refer to the brand new [website](https://nalgebra.org) for more +details. The following free-functions have been added as well: + +* `::id()` that returns the universal [identity element](https://nalgebra.org/performance_tricks/#the-id-type) + of type `Id`. +* `::inf_sup()` that returns both the infimum and supremum of a value at the + same time. +* `::partial_sort2()` that attempts to sort two values in increasing order. +* `::wrap()` that moves a value to the given interval by adding or removing + the interval width to it. + +### Modified + +* `::cast` -> `::convert` +* `point.as_vector()` -> `point.coords` +* `na::origin` -> `P::origin()` +* `na::is_zero` -> `.is_zero()` (from num::Zero) +* `.transform` -> `.transform_point`/`.transform_vector` +* `.translate` -> `.translate_point` +* `::dimension::

` -> `::dimension::` +* `::angle_between` -> `::angle` + +Componentwise multiplication and division has been replaced by methods: + +* multiplication -> `.componentwise_mul`, `.componentwise_mul_mut`. +* division -> `.componentwise_div`, `.componentwise_div_mut`. + +The following free-functions are now replaced by methods (with the same names) +only: +`::cross`, `::cholesky`, `::determinant`, `::diagonal`, `::eigen_qr` (becomes +`.eig`), `::hessenberg`, `::qr`, `::to_homogeneous`, `::to_rotation_matrix`, +`::transpose`, `::shape`. + +The following free-functions are now replaced by static methods only: + +* `::householder_matrix` under the name `::new_householder_generic` +* `::identity` +* `::new_identity` under the name `::identity` +* `::from_homogeneous` +* `::repeat` under the name `::from_element` + +The following free-function are now replaced methods accessible through traits +only: + +* `::transform` -> methods `.transform_point` and `.transform_vector` of the `alga::linear::Transformation` trait. +* `::inverse_transform` -> methods `.inverse_transform_point` and + `.inverse_transform_vector` of the `alga::linear::ProjectiveTransformation` + trait. +* `::translate`, `::inverse_translate`, `::rotate`, `::inverse_rotate` -> + methods from the `alga::linear::Similarity` trait instead. Those have the + same names but end with `_point` or `_vector`, e.g., `.translate_point` and + `.translate_vector`. +* `::orthonormal_subspace_basis` -> method with the same name from + `alga::linear::FiniteDimInnerSpace`. +* `::canonical_basis_element` and `::canonical_basis` -> methods with the + same names from `alga::linear::FiniteDimVectorSpace`. +* `::rotation_between` -> method with the same name from the + `alga::linear::Rotation` trait. +* `::is_zero` -> method with the same name from `num::Zero`. + +### Removed + +* The free functions `::prepend_rotation`, `::append_rotation`, + `::append_rotation_wrt_center`, `::append_rotation_wrt_point`, + `::append_transformation`, and `::append_translation ` have been removed. + Instead, create the rotation or translation object explicitly and use + multiplication to compose it with anything else. + +* The free function `::outer` has been removed. Use column-vector × + row-vector multiplication instead. + +* `::approx_eq`, `::approx_eq_eps` have been removed. Use the `relative_eq!` + macro from the [approx](https://crates.io/crates/approx) crate instead. + +* `::covariance` has been removed. There is no replacement for now. +* `::mean` has been removed. There is no replacement for now. +* `::sample_sphere` has been removed. There is no replacement for now. +* `::cross_matrix` has been removed. There is no replacement for now. +* `::absolute_rotate` has been removed. There is no replacement for now. +* `::rotation`, `::transformation`, `::translation`, `::inverse_rotation`, + `::inverse_transformation`, `::inverse_translation` have been removed. Use + the appropriate methods/field of each transformation type, e.g., + `rotation.angle()` and `rotation.axis()`. + +## [0.10.0] + +### Added + +Binary operations are now allowed between references as well. For example +`Vector3 + &Vector3` is now possible. + +### Modified + +Removed unused parameters to methods from the `ApproxEq` trait. Those were +required before rust 1.0 to help type inference. They are not needed any more +since it now allowed to write for a type `T` that implements `ApproxEq`: +`::approx_epsilon()`. This replaces the old form: +`ApproxEq::approx_epsilon(None::)`. + +## [0.9.0] + +### Modified + +* Renamed: + - `::from_col_vector` -> `::from_column_vector` + - `::from_col_iter` -> `::from_column_iter` + - `.col_slice` -> `.column_slice` + - `.set_col` -> `.set_column` + - `::canonical_basis_with_dim` -> `::canonical_basis_with_dimension` + - `::from_elem` -> `::from_element` + - `DiagMut` -> `DiagonalMut` + - `UnitQuaternion::new` becomes `UnitQuaternion::from_scaled_axis` or + `UnitQuaternion::from_axisangle`. The new `::new` method now requires a + not-normalized quaternion. + +Method names starting with `new_with_` now start with `from_`. This is more +idiomatic in Rust. + +The `Norm` trait now uses an associated type instead of a type parameter. +Other similar trait changes are to be expected in the future, e.g., for the +`Diagonal` trait. + +Methods marked `unsafe` for reasons unrelated to memory safety are no +longer unsafe. Instead, their name end with `_unchecked`. In particular: + +* `Rotation3::new_with_matrix` -> `Rotation3::from_matrix_unchecked` +* `PerspectiveMatrix3::new_with_matrix` -> `PerspectiveMatrix3::from_matrix_unchecked` +* `OrthographicMatrix3::new_with_matrix` -> `OrthographicMatrix3::from_matrix_unchecked` + +### Added + +- A `Unit` type that wraps normalized values. In particular, + `UnitQuaternion` is now an alias for `Unit>`. +- `.ln()`, `.exp()` and `.powf(..)` for quaternions and unit quaternions. +- `::from_parts(...)` to build a quaternion from its scalar and vector + parts. +- The `Norm` trait now has a `try_normalize()` that returns `None` if the + norm is too small. +- The `BaseFloat` and `FloatVector` traits now inherit from `ApproxEq` as + well. It is clear that performing computations with floats requires + approximate equality. + +Still WIP: add implementations of abstract algebra traits from the `algebra` +crate for vectors, rotations and points. To enable them, activate the +`abstract_algebra` feature. + +## [0.8.0] + +### Modified + +* Almost everything (types, methods, and traits) now use fulls names instead + of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are obvious. + Note however that: + - `::sqnorm` becomes `::norm_squared`. + - `::sqdist` becomes `::distance_squared`. + - `::abs`, `::min`, etc. did not change as this is a common name for + absolute values on, e.g., the libc. + - Dynamically sized structures keep the `D` prefix, e.g., `DMat` becomes + `DMatrix`. +* All files with abbreviated names have been renamed to their full version, + e.g., `vec.rs` becomes `vector.rs`. + +## [0.7.0] + +### Added + +* Added implementation of assignment operators (+=, -=, etc.) for + everything. + +### Modified + +* Points and vectors are now linked to each other with associated types + (on the PointAsVector trait). + +## [0.6.0] + +**Announcement:** a users forum has been created for `nalgebra`, `ncollide`, and `nphysics`. See +you [there](https://users.nphysics.org)! + +### Added + +* Added a dependency to [generic-array](https://crates.io/crates/generic-array). Feature-gated: + requires `features="generic_sizes"`. +* Added statically sized vectors with user-defined sizes: `VectorN`. Feature-gated: requires + `features="generic_sizes"`. +* Added similarity transformations (an uniform scale followed by a rotation followed by a + translation): `Similarity2`, `Similarity3`. + +### Removed + +* Removed zero-sized elements `Vector0`, `Point0`. +* Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation too incomplete to be + useful). + +### Modified + +* Vectors are now multipliable with isometries. This will result into a pure rotation (this is how + vectors differ from point semantically: they design directions, so they are not translatable). +* `{Isometry3, Rotation3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree + with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh` + variant to build a view matrix that + may be successfully used with `Persp` and `Ortho`. +* The old `{Isometry3, Rotation3}::look_at` implementations are now called `::new_observer_frame`. +* Rename every `fov` on `Persp` to `fovy`. +* Fixed the perspective and orthographic projection matrices. diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml b/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml new file mode 100644 index 000000000..83548c341 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml @@ -0,0 +1,327 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "nalgebra" +version = "0.33.0" +authors = ["Sébastien Crozet "] +exclude = [ + "/ci/*", + "/.travis.yml", + "/Makefile", +] +description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." +homepage = "https://nalgebra.org" +documentation = "https://www.nalgebra.org/docs" +readme = "README.md" +keywords = [ + "linear", + "algebra", + "matrix", + "vector", + "math", +] +categories = [ + "science", + "mathematics", + "wasm", + "no-std", +] +license = "Apache-2.0" +repository = "https://github.com/dimforge/nalgebra" +resolver = "2" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[profile.bench] +lto = true + +[lib] +name = "nalgebra" +path = "src/lib.rs" + +[[example]] +name = "matrixcompare" +required-features = ["compare"] + +[[bench]] +name = "nalgebra_bench" +path = "benches/lib.rs" +harness = false +required-features = ["rand"] + +[dependencies.alga] +version = "0.9" +optional = true +default-features = false + +[dependencies.approx] +version = "0.5" +default-features = false + +[dependencies.bytemuck] +version = "1.5" +optional = true + +[dependencies.glam014] +version = "0.14" +optional = true +package = "glam" + +[dependencies.glam015] +version = "0.15" +optional = true +package = "glam" + +[dependencies.glam016] +version = "0.16" +optional = true +package = "glam" + +[dependencies.glam017] +version = "0.17" +optional = true +package = "glam" + +[dependencies.glam018] +version = "0.18" +optional = true +package = "glam" + +[dependencies.glam019] +version = "0.19" +optional = true +package = "glam" + +[dependencies.glam020] +version = "0.20" +optional = true +package = "glam" + +[dependencies.glam021] +version = "0.21" +optional = true +package = "glam" + +[dependencies.glam022] +version = "0.22" +optional = true +package = "glam" + +[dependencies.glam023] +version = "0.23" +optional = true +package = "glam" + +[dependencies.glam024] +version = "0.24" +optional = true +package = "glam" + +[dependencies.glam025] +version = "0.25" +optional = true +package = "glam" + +[dependencies.glam027] +version = "0.27" +optional = true +package = "glam" + +[dependencies.glam028] +version = "0.28" +optional = true +package = "glam" + +[dependencies.matrixcompare-core] +version = "0.1" +optional = true + +[dependencies.matrixmultiply] +version = "0.3" +optional = true + +[dependencies.mint] +version = "0.5" +optional = true + +[dependencies.nalgebra-macros] +version = "0.2.2" +optional = true + +[dependencies.num-complex] +version = "0.4" +default-features = false + +[dependencies.num-rational] +version = "0.4" +default-features = false + +[dependencies.num-traits] +version = "0.2" +default-features = false + +[dependencies.pest] +version = "2" +optional = true + +[dependencies.pest_derive] +version = "2" +optional = true + +[dependencies.proptest] +version = "1" +features = ["std"] +optional = true +default-features = false + +[dependencies.quickcheck] +version = "1" +optional = true + +[dependencies.rand-package] +version = "0.8" +optional = true +default-features = false +package = "rand" + +[dependencies.rand_distr] +version = "0.4" +optional = true +default-features = false + +[dependencies.rayon] +version = "1.6" +optional = true + +[dependencies.rkyv] +version = "0.7.41" +optional = true +default-features = false + +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true +default-features = false + +[dependencies.simba] +version = "0.9" +default-features = false + +[dependencies.typenum] +version = "1.12" + +[dev-dependencies.cool_asserts] +version = "2.0.3" + +[dev-dependencies.criterion] +version = "0.4" +features = ["html_reports"] + +[dev-dependencies.itertools] +version = "0.13" + +[dev-dependencies.matrixcompare] +version = "0.3.0" + +[dev-dependencies.rand_isaac] +version = "0.3" + +[dev-dependencies.rand_xorshift] +version = "0.3" + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.trybuild] +version = "1.0.90" + +[features] +alloc = [] +arbitrary = ["quickcheck"] +compare = ["matrixcompare-core"] +convert-bytemuck = ["bytemuck"] +convert-glam014 = ["glam014"] +convert-glam015 = ["glam015"] +convert-glam016 = ["glam016"] +convert-glam017 = ["glam017"] +convert-glam018 = ["glam018"] +convert-glam019 = ["glam019"] +convert-glam020 = ["glam020"] +convert-glam021 = ["glam021"] +convert-glam022 = ["glam022"] +convert-glam023 = ["glam023"] +convert-glam024 = ["glam024"] +convert-glam025 = ["glam025"] +convert-glam027 = ["glam027"] +convert-glam028 = ["glam028"] +convert-mint = ["mint"] +debug = [ + "approx/num-complex", + "rand", +] +default = [ + "std", + "macros", +] +io = [ + "pest", + "pest_derive", +] +libm = ["simba/libm"] +libm-force = ["simba/libm_force"] +macros = ["nalgebra-macros"] +proptest-support = ["proptest"] +rand = [ + "rand-no-std", + "rand-package/std", + "rand-package/std_rng", + "rand_distr", +] +rand-no-std = ["rand-package"] +rkyv-safe-deser = [ + "rkyv-serialize", + "rkyv/validation", +] +rkyv-serialize = [ + "rkyv-serialize-no-std", + "rkyv/std", + "rkyv/validation", +] +rkyv-serialize-no-std = ["rkyv/size_32"] +serde-serialize = [ + "serde-serialize-no-std", + "serde/std", +] +serde-serialize-no-std = [ + "serde", + "num-complex/serde", +] +slow-tests = [] +sparse = [] +std = [ + "matrixmultiply", + "num-traits/std", + "num-complex/std", + "num-rational/std", + "approx/std", + "simba/std", +] + +[badges.maintenance] +status = "actively-developed" diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/LICENSE b/collector/compile-benchmarks/nalgebra-0.33.0/LICENSE new file mode 100644 index 000000000..40eb0d611 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Sébastien Crozet + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/README.md b/collector/compile-benchmarks/nalgebra-0.33.0/README.md new file mode 100644 index 000000000..2f3aac9c0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/README.md @@ -0,0 +1,28 @@ +

+ crates.io +

+

+ + + + + crates.io + + + + +

+

+ + Users guide | Documentation + +

+ +----- + +

+Linear algebra library +for the Rust programming language. +

+ +----- diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/common/macros.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/common/macros.rs new file mode 100644 index 000000000..a58de67ef --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/common/macros.rs @@ -0,0 +1,113 @@ +#![macro_use] + +macro_rules! bench_binop( + ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { + fn $name(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let a = rng.gen::<$t1>(); + let b = rng.gen::<$t2>(); + + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { + a.$binop(b) + })); + } + } +); + +macro_rules! bench_binop_ref( + ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { + fn $name(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let a = rng.gen::<$t1>(); + let b = rng.gen::<$t2>(); + + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { + a.$binop(&b) + })); + } + } +); + +macro_rules! bench_binop_fn( + ($name: ident, $t1: ty, $t2: ty, $binop: path) => { + fn $name(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let a = rng.gen::<$t1>(); + let b = rng.gen::<$t2>(); + + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { + $binop(&a, &b) + })); + } + } +); + +macro_rules! bench_unop_na( + ($name: ident, $t: ty, $unop: ident) => { + fn $name(bh: &mut criterion::Criterion) { + const LEN: usize = 1 << 13; + + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + + let elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect(); + let mut i = 0; + + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { + i = (i + 1) & (LEN - 1); + + unsafe { + std::hint::black_box(na::$unop(elems.get_unchecked(i))) + } + })); + } + } +); + +macro_rules! bench_unop( + ($name: ident, $t: ty, $unop: ident) => { + fn $name(bh: &mut criterion::Criterion) { + const LEN: usize = 1 << 13; + + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + + let mut elems: Vec<$t> = (0usize .. LEN).map(|_| rng.gen::<$t>()).collect(); + let mut i = 0; + + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { + i = (i + 1) & (LEN - 1); + + unsafe { + std::hint::black_box(elems.get_unchecked_mut(i).$unop()) + } + })); + } + } +); + +macro_rules! bench_construction( + ($name: ident, $constructor: path, $( $args: ident: $types: ty),*) => { + fn $name(bh: &mut criterion::Criterion) { + const LEN: usize = 1 << 13; + + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + + $(let $args: Vec<$types> = (0usize .. LEN).map(|_| rng.gen::<$types>()).collect();)* + let mut i = 0; + + bh.bench_function(stringify!($name), move |bh| bh.iter(|| { + i = (i + 1) & (LEN - 1); + + unsafe { + let res = $constructor($(*$args.get_unchecked(i),)*); + std::hint::black_box(res) + } + })); + } + } +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/matrix.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/matrix.rs new file mode 100644 index 000000000..43758fe34 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/matrix.rs @@ -0,0 +1,270 @@ +use na::{DMatrix, DVector, Matrix2, Matrix3, Matrix4, OMatrix, Vector2, Vector3, Vector4, U10}; +use rand::Rng; +use rand_isaac::IsaacRng; +use std::ops::{Add, Div, Mul, Sub}; + +#[path = "../common/macros.rs"] +mod macros; + +bench_binop!(mat2_mul_m, Matrix2, Matrix2, mul); +bench_binop!(mat3_mul_m, Matrix3, Matrix3, mul); +bench_binop!(mat4_mul_m, Matrix4, Matrix4, mul); + +bench_binop_ref!(mat2_tr_mul_m, Matrix2, Matrix2, tr_mul); +bench_binop_ref!(mat3_tr_mul_m, Matrix3, Matrix3, tr_mul); +bench_binop_ref!(mat4_tr_mul_m, Matrix4, Matrix4, tr_mul); + +bench_binop!(mat2_add_m, Matrix2, Matrix2, add); +bench_binop!(mat3_add_m, Matrix3, Matrix3, add); +bench_binop!(mat4_add_m, Matrix4, Matrix4, add); + +bench_binop!(mat2_sub_m, Matrix2, Matrix2, sub); +bench_binop!(mat3_sub_m, Matrix3, Matrix3, sub); +bench_binop!(mat4_sub_m, Matrix4, Matrix4, sub); + +bench_binop!(mat2_mul_v, Matrix2, Vector2, mul); +bench_binop!(mat3_mul_v, Matrix3, Vector3, mul); +bench_binop!(mat4_mul_v, Matrix4, Vector4, mul); + +bench_binop_ref!(mat2_tr_mul_v, Matrix2, Vector2, tr_mul); +bench_binop_ref!(mat3_tr_mul_v, Matrix3, Vector3, tr_mul); +bench_binop_ref!(mat4_tr_mul_v, Matrix4, Vector4, tr_mul); + +bench_binop!(mat2_mul_s, Matrix2, f32, mul); +bench_binop!(mat3_mul_s, Matrix3, f32, mul); +bench_binop!(mat4_mul_s, Matrix4, f32, mul); + +bench_binop!(mat2_div_s, Matrix2, f32, div); +bench_binop!(mat3_div_s, Matrix3, f32, div); +bench_binop!(mat4_div_s, Matrix4, f32, div); + +bench_unop!(mat2_inv, Matrix2, try_inverse); +bench_unop!(mat3_inv, Matrix3, try_inverse); +bench_unop!(mat4_inv, Matrix4, try_inverse); + +bench_unop!(mat2_transpose, Matrix2, transpose); +bench_unop!(mat3_transpose, Matrix3, transpose); +bench_unop!(mat4_transpose, Matrix4, transpose); + +fn mat_div_scalar(b: &mut criterion::Criterion) { + let a = DMatrix::from_row_slice(1000, 1000, &vec![2.0; 1000000]); + let n = 42.0; + + b.bench_function("mat_div_scalar", move |bh| { + bh.iter(|| { + let mut aa = a.clone(); + let mut b = aa.view_mut((0, 0), (1000, 1000)); + b /= n + }) + }); +} + +fn mat100_add_mat100(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(100, 100); + let b = DMatrix::::new_random(100, 100); + + bench.bench_function("mat100_add_mat100", move |bh| bh.iter(|| &a + &b)); +} + +fn mat4_mul_mat4(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(4, 4); + let b = DMatrix::::new_random(4, 4); + + bench.bench_function("mat4_mul_mat4", move |bh| bh.iter(|| &a * &b)); +} + +fn mat5_mul_mat5(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(5, 5); + let b = DMatrix::::new_random(5, 5); + + bench.bench_function("mat5_mul_mat5", move |bh| bh.iter(|| &a * &b)); +} + +fn mat6_mul_mat6(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(6, 6); + let b = DMatrix::::new_random(6, 6); + + bench.bench_function("mat6_mul_mat6", move |bh| bh.iter(|| &a * &b)); +} + +fn mat7_mul_mat7(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(7, 7); + let b = DMatrix::::new_random(7, 7); + + bench.bench_function("mat7_mul_mat7", move |bh| bh.iter(|| &a * &b)); +} + +fn mat8_mul_mat8(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(8, 8); + let b = DMatrix::::new_random(8, 8); + + bench.bench_function("mat8_mul_mat8", move |bh| bh.iter(|| &a * &b)); +} + +fn mat9_mul_mat9(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(9, 9); + let b = DMatrix::::new_random(9, 9); + + bench.bench_function("mat9_mul_mat9", move |bh| bh.iter(|| &a * &b)); +} + +fn mat10_mul_mat10(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(10, 10); + let b = DMatrix::::new_random(10, 10); + + bench.bench_function("mat10_mul_mat10", move |bh| bh.iter(|| &a * &b)); +} + +fn mat10_mul_mat10_static(bench: &mut criterion::Criterion) { + let a = OMatrix::::new_random(); + let b = OMatrix::::new_random(); + + bench.bench_function("mat10_mul_mat10_static", move |bh| bh.iter(|| &a * &b)); +} + +fn mat100_mul_mat100(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(100, 100); + let b = DMatrix::::new_random(100, 100); + + bench.bench_function("mat100_mul_mat100", move |bh| bh.iter(|| &a * &b)); +} + +fn mat500_mul_mat500(bench: &mut criterion::Criterion) { + let a = DMatrix::::from_element(500, 500, 5f64); + let b = DMatrix::::from_element(500, 500, 6f64); + + bench.bench_function("mat500_mul_mat500", move |bh| bh.iter(|| &a * &b)); +} + +fn iter(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(1000, 1000); + + bench.bench_function("iter", move |bh| { + bh.iter(|| { + for value in a.iter() { + std::hint::black_box(value); + } + }) + }); +} + +fn iter_rev(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(1000, 1000); + + bench.bench_function("iter_rev", move |bh| { + bh.iter(|| { + for value in a.iter().rev() { + std::hint::black_box(value); + } + }) + }); +} + +fn copy_from(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(1000, 1000); + let mut b = DMatrix::::new_random(1000, 1000); + + bench.bench_function("copy_from", move |bh| { + bh.iter(|| { + b.copy_from(&a); + }) + }); +} + +fn axpy(bench: &mut criterion::Criterion) { + let x = DVector::::from_element(100000, 2.0); + let mut y = DVector::::from_element(100000, 3.0); + let a = 42.0; + + bench.bench_function("axpy", move |bh| { + bh.iter(|| { + y.axpy(a, &x, 1.0); + }) + }); +} + +fn tr_mul_to(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(1000, 1000); + let b = DVector::::new_random(1000); + let mut c = DVector::from_element(1000, 0.0); + + bench.bench_function("tr_mul_to", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c))); +} + +fn mat_mul_mat(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(100, 100); + let b = DMatrix::::new_random(100, 100); + let mut ab = DMatrix::::from_element(100, 100, 0.0); + + bench.bench_function("mat_mul_mat", move |bh| { + bh.iter(|| { + std::hint::black_box(a.mul_to(&b, &mut ab)); + }) + }); +} + +fn mat100_from_fn(bench: &mut criterion::Criterion) { + bench.bench_function("mat100_from_fn", move |bh| { + bh.iter(|| DMatrix::from_fn(100, 100, |a, b| a + b)) + }); +} + +fn mat500_from_fn(bench: &mut criterion::Criterion) { + bench.bench_function("mat500_from_fn", move |bh| { + bh.iter(|| DMatrix::from_fn(500, 500, |a, b| a + b)) + }); +} + +criterion_group!( + matrix, + mat2_mul_m, + mat3_mul_m, + mat4_mul_m, + mat2_tr_mul_m, + mat3_tr_mul_m, + mat4_tr_mul_m, + mat2_add_m, + mat3_add_m, + mat4_add_m, + mat2_sub_m, + mat3_sub_m, + mat4_sub_m, + mat2_mul_v, + mat3_mul_v, + mat4_mul_v, + mat2_tr_mul_v, + mat3_tr_mul_v, + mat4_tr_mul_v, + mat2_mul_s, + mat3_mul_s, + mat4_mul_s, + mat2_div_s, + mat3_div_s, + mat4_div_s, + mat2_inv, + mat3_inv, + mat4_inv, + mat2_transpose, + mat3_transpose, + mat4_transpose, + mat_div_scalar, + mat100_add_mat100, + mat4_mul_mat4, + mat5_mul_mat5, + mat6_mul_mat6, + mat7_mul_mat7, + mat8_mul_mat8, + mat9_mul_mat9, + mat10_mul_mat10, + mat10_mul_mat10_static, + mat100_mul_mat100, + mat500_mul_mat500, + iter, + iter_rev, + copy_from, + axpy, + tr_mul_to, + mat_mul_mat, + mat100_from_fn, + mat500_from_fn, +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/mod.rs new file mode 100644 index 000000000..1d88093d8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/mod.rs @@ -0,0 +1,5 @@ +pub use self::matrix::matrix; +pub use self::vector::vector; + +mod matrix; +mod vector; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/vector.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/vector.rs new file mode 100644 index 000000000..6c72a0692 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/core/vector.rs @@ -0,0 +1,168 @@ +use na::{DVector, SVector, Vector2, Vector3, Vector4}; +use rand::Rng; +use rand_isaac::IsaacRng; +use std::ops::{Add, Div, Mul, Sub}; + +#[path = "../common/macros.rs"] +mod macros; + +bench_binop!(vec2_add_v_f32, Vector2, Vector2, add); +bench_binop!(vec3_add_v_f32, Vector3, Vector3, add); +bench_binop!(vec4_add_v_f32, Vector4, Vector4, add); + +bench_binop!(vec2_add_v_f64, Vector2, Vector2, add); +bench_binop!(vec3_add_v_f64, Vector3, Vector3, add); +bench_binop!(vec4_add_v_f64, Vector4, Vector4, add); + +bench_binop!(vec2_sub_v, Vector2, Vector2, sub); +bench_binop!(vec3_sub_v, Vector3, Vector3, sub); +bench_binop!(vec4_sub_v, Vector4, Vector4, sub); + +bench_binop!(vec2_mul_s, Vector2, f32, mul); +bench_binop!(vec3_mul_s, Vector3, f32, mul); +bench_binop!(vec4_mul_s, Vector4, f32, mul); + +bench_binop!(vec2_div_s, Vector2, f32, div); +bench_binop!(vec3_div_s, Vector3, f32, div); +bench_binop!(vec4_div_s, Vector4, f32, div); + +bench_binop_ref!(vec2_dot_f32, Vector2, Vector2, dot); +bench_binop_ref!(vec3_dot_f32, Vector3, Vector3, dot); +bench_binop_ref!(vec4_dot_f32, Vector4, Vector4, dot); + +bench_binop_ref!(vec2_dot_f64, Vector2, Vector2, dot); +bench_binop_ref!(vec3_dot_f64, Vector3, Vector3, dot); +bench_binop_ref!(vec4_dot_f64, Vector4, Vector4, dot); + +bench_binop_ref!(vec3_cross, Vector3, Vector3, cross); + +bench_unop!(vec2_norm, Vector2, norm); +bench_unop!(vec3_norm, Vector3, norm); +bench_unop!(vec4_norm, Vector4, norm); + +bench_unop!(vec2_normalize, Vector2, normalize); +bench_unop!(vec3_normalize, Vector3, normalize); +bench_unop!(vec4_normalize, Vector4, normalize); + +bench_binop_ref!(vec10000_dot_f64, SVector, SVector, dot); +bench_binop_ref!(vec10000_dot_f32, SVector, SVector, dot); + +fn vec10000_axpy_f64(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + + bh.bench_function("vec10000_axpy_f64", move |bh| { + bh.iter(|| a.axpy(n, &b, 1.0)) + }); +} + +fn vec10000_axpy_beta_f64(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + let beta = rng.gen::(); + + bh.bench_function("vec10000_axpy_beta_f64", move |bh| { + bh.iter(|| a.axpy(n, &b, beta)) + }); +} + +fn vec10000_axpy_f64_slice(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + + bh.bench_function("vec10000_axpy_f64_slice", move |bh| { + bh.iter(|| { + let mut a = a.fixed_rows_mut::<10000>(0); + let b = b.fixed_rows::<10000>(0); + + a.axpy(n, &b, 1.0) + }) + }); +} + +fn vec10000_axpy_f64_static(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let mut a = SVector::::new_random(); + let b = SVector::::new_random(); + let n = rng.gen::(); + + // NOTE: for some reasons, it is much faster if the arument are boxed (Box::new(OVector...)). + bh.bench_function("vec10000_axpy_f64_static", move |bh| { + bh.iter(|| a.axpy(n, &b, 1.0)) + }); +} + +fn vec10000_axpy_f32(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + + bh.bench_function("vec10000_axpy_f32", move |bh| { + bh.iter(|| a.axpy(n, &b, 1.0)) + }); +} + +fn vec10000_axpy_beta_f32(bh: &mut criterion::Criterion) { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + let mut a = DVector::new_random(10000); + let b = DVector::new_random(10000); + let n = rng.gen::(); + let beta = rng.gen::(); + + bh.bench_function("vec10000_axpy_beta_f32", move |bh| { + bh.iter(|| a.axpy(n, &b, beta)) + }); +} + +criterion_group!( + vector, + vec2_add_v_f32, + vec3_add_v_f32, + vec4_add_v_f32, + vec2_add_v_f64, + vec3_add_v_f64, + vec4_add_v_f64, + vec2_sub_v, + vec3_sub_v, + vec4_sub_v, + vec2_mul_s, + vec3_mul_s, + vec4_mul_s, + vec2_div_s, + vec3_div_s, + vec4_div_s, + vec2_dot_f32, + vec3_dot_f32, + vec4_dot_f32, + vec2_dot_f64, + vec3_dot_f64, + vec4_dot_f64, + vec3_cross, + vec2_norm, + vec3_norm, + vec4_norm, + vec2_normalize, + vec3_normalize, + vec4_normalize, + vec10000_dot_f64, + vec10000_dot_f32, + vec10000_axpy_f64, + vec10000_axpy_beta_f64, + vec10000_axpy_f64_slice, + vec10000_axpy_f64_static, + vec10000_axpy_f32, + vec10000_axpy_beta_f32 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/mod.rs new file mode 100644 index 000000000..f5b6da491 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/mod.rs @@ -0,0 +1,3 @@ +pub use self::quaternion::quaternion; + +mod quaternion; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/quaternion.rs new file mode 100644 index 000000000..cb0418409 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/geometry/quaternion.rs @@ -0,0 +1,39 @@ +use na::{Quaternion, UnitQuaternion, Vector3}; +use rand::Rng; +use rand_isaac::IsaacRng; +use std::ops::{Add, Div, Mul, Sub}; + +#[path = "../common/macros.rs"] +mod macros; + +bench_binop!(quaternion_add_q, Quaternion, Quaternion, add); +bench_binop!(quaternion_sub_q, Quaternion, Quaternion, sub); +bench_binop!(quaternion_mul_q, Quaternion, Quaternion, mul); + +bench_binop!( + unit_quaternion_mul_v, + UnitQuaternion, + Vector3, + mul +); + +bench_binop!(quaternion_mul_s, Quaternion, f32, mul); +bench_binop!(quaternion_div_s, Quaternion, f32, div); + +bench_unop!(quaternion_inv, Quaternion, try_inverse); +bench_unop!(unit_quaternion_inv, UnitQuaternion, inverse); + +// bench_unop_self!(quaternion_conjugate, Quaternion, conjugate); +// bench_unop!(quaternion_normalize, Quaternion, normalize); + +criterion_group!( + quaternion, + quaternion_add_q, + quaternion_sub_q, + quaternion_mul_q, + unit_quaternion_mul_v, + quaternion_mul_s, + quaternion_div_s, + quaternion_inv, + unit_quaternion_inv +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/lib.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/lib.rs new file mode 100644 index 000000000..21c504d2f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/lib.rs @@ -0,0 +1,37 @@ +#![allow(unused_macros)] + +extern crate nalgebra as na; +extern crate rand_package as rand; + +#[macro_use] +extern crate criterion; + +use na::DMatrix; +use rand::Rng; +use rand_isaac::IsaacRng; + +pub mod core; +pub mod geometry; +pub mod linalg; + +fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix { + use rand::SeedableRng; + let mut rng = IsaacRng::seed_from_u64(0); + DMatrix::::from_fn(nrows, ncols, |_, _| rng.gen()) +} + +criterion_main!( + core::matrix, + core::vector, + geometry::quaternion, + linalg::bidiagonal, + linalg::cholesky, + linalg::full_piv_lu, + linalg::hessenberg, + linalg::lu, + linalg::qr, + linalg::schur, + linalg::solve, + linalg::svd, + linalg::symmetric_eigen, +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/bidiagonal.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/bidiagonal.rs new file mode 100644 index 000000000..fffdf87d0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/bidiagonal.rs @@ -0,0 +1,94 @@ +use na::{Bidiagonal, DMatrix, Matrix4}; + +#[path = "../common/macros.rs"] +mod macros; + +// Without unpack. +fn bidiagonalize_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("bidiagonalize_100x100", move |bh| { + bh.iter(|| std::hint::black_box(Bidiagonal::new(m.clone()))) + }); +} + +fn bidiagonalize_100x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 500); + bh.bench_function("bidiagonalize_100x500", move |bh| { + bh.iter(|| std::hint::black_box(Bidiagonal::new(m.clone()))) + }); +} + +fn bidiagonalize_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("bidiagonalize_4x4", move |bh| { + bh.iter(|| std::hint::black_box(Bidiagonal::new(m.clone()))) + }); +} + +fn bidiagonalize_500x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 100); + bh.bench_function("bidiagonalize_500x100", move |bh| { + bh.iter(|| std::hint::black_box(Bidiagonal::new(m.clone()))) + }); +} + +fn bidiagonalize_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("bidiagonalize_500x500", move |bh| { + bh.iter(|| std::hint::black_box(Bidiagonal::new(m.clone()))) + }); +} + +// With unpack. +fn bidiagonalize_unpack_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("bidiagonalize_unpack_100x100", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); +} + +fn bidiagonalize_unpack_100x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 500); + bh.bench_function("bidiagonalize_unpack_100x500", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); +} + +fn bidiagonalize_unpack_500x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 100); + bh.bench_function("bidiagonalize_unpack_500x100", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); +} + +fn bidiagonalize_unpack_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("bidiagonalize_unpack_500x500", move |bh| { + bh.iter(|| { + let bidiag = Bidiagonal::new(m.clone()); + let _ = bidiag.unpack(); + }) + }); +} + +criterion_group!( + bidiagonal, + bidiagonalize_100x100, + bidiagonalize_100x500, + bidiagonalize_4x4, + bidiagonalize_500x100, + // bidiagonalize_500x500, // too long + bidiagonalize_unpack_100x100, + bidiagonalize_unpack_100x500, + bidiagonalize_unpack_500x100, + // bidiagonalize_unpack_500x500 // too long +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/cholesky.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/cholesky.rs new file mode 100644 index 000000000..25b0d605b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/cholesky.rs @@ -0,0 +1,132 @@ +use na::{Cholesky, DMatrix, DVector}; + +fn cholesky_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + + bh.bench_function("cholesky_100x100", move |bh| { + bh.iter(|| std::hint::black_box(Cholesky::new(m.clone()))) + }); +} + +fn cholesky_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + + bh.bench_function("cholesky_500x500", move |bh| { + bh.iter(|| std::hint::black_box(Cholesky::new(m.clone()))) + }); +} + +// With unpack. +fn cholesky_decompose_unpack_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + + bh.bench_function("cholesky_decompose_unpack_100x100", move |bh| { + bh.iter(|| { + let chol = Cholesky::new(m.clone()).unwrap(); + let _ = chol.unpack(); + }) + }); +} +fn cholesky_decompose_unpack_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + + bh.bench_function("cholesky_decompose_unpack_500x500", move |bh| { + bh.iter(|| { + let chol = Cholesky::new(m.clone()).unwrap(); + let _ = chol.unpack(); + }) + }); +} + +fn cholesky_solve_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let m = &m * m.transpose(); + let v = DVector::::new_random(10); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.bench_function("cholesky_solve_10x10", move |bh| { + bh.iter(|| { + let _ = chol.solve(&v); + }) + }); +} + +fn cholesky_solve_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + let v = DVector::::new_random(100); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.bench_function("cholesky_solve_100x100", move |bh| { + bh.iter(|| { + let _ = chol.solve(&v); + }) + }); +} + +fn cholesky_solve_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + let v = DVector::::new_random(500); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.bench_function("cholesky_solve_500x500", move |bh| { + bh.iter(|| { + let _ = chol.solve(&v); + }) + }); +} + +fn cholesky_inverse_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let m = &m * m.transpose(); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.bench_function("cholesky_inverse_10x10", move |bh| { + bh.iter(|| { + let _ = chol.inverse(); + }) + }); +} + +fn cholesky_inverse_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let m = &m * m.transpose(); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.bench_function("cholesky_inverse_100x100", move |bh| { + bh.iter(|| { + let _ = chol.inverse(); + }) + }); +} + +fn cholesky_inverse_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let m = &m * m.transpose(); + let chol = Cholesky::new(m.clone()).unwrap(); + + bh.bench_function("cholesky_inverse_500x500", move |bh| { + bh.iter(|| { + let _ = chol.inverse(); + }) + }); +} + +criterion_group!( + cholesky, + cholesky_100x100, + cholesky_500x500, + cholesky_decompose_unpack_100x100, + cholesky_decompose_unpack_500x500, + cholesky_solve_10x10, + cholesky_solve_100x100, + cholesky_solve_500x500, + cholesky_inverse_10x10, + cholesky_inverse_100x100, + cholesky_inverse_500x500 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/eigen.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/eigen.rs new file mode 100644 index 000000000..7b793ec11 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/eigen.rs @@ -0,0 +1,32 @@ +use na::{DMatrix, Eigen}; + +fn eigen_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + + bh.bench_function("eigen_100x100", move |bh| bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))); +} + +fn eigen_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + + bh.bench_function("eigen_500x500", move |bh| bh.iter(|| Eigen::new(m.clone(), 1.0e-7, 0))); +} + +fn eigenvalues_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + + bh.bench_function("eigenvalues_100x100", move |bh| bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))); +} + +fn eigenvalues_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + + bh.bench_function("eigenvalues_500x500", move |bh| bh.iter(|| m.clone().eigenvalues(1.0e-7, 0))); +} + +criterion_group!(eigen, + eigen_100x100, +// eigen_500x500, + eigenvalues_100x100, +// eigenvalues_500x500 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/full_piv_lu.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/full_piv_lu.rs new file mode 100644 index 000000000..c02f35c7a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/full_piv_lu.rs @@ -0,0 +1,129 @@ +use na::{DMatrix, DVector, FullPivLU}; + +// Without unpack. +fn full_piv_lu_decompose_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + bh.bench_function("full_piv_lu_decompose_10x10", move |bh| { + bh.iter(|| std::hint::black_box(FullPivLU::new(m.clone()))) + }); +} + +fn full_piv_lu_decompose_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("full_piv_lu_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(FullPivLU::new(m.clone()))) + }); +} + +fn full_piv_lu_decompose_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("full_piv_lu_decompose_500x500", move |bh| { + bh.iter(|| std::hint::black_box(FullPivLU::new(m.clone()))) + }); +} + +fn full_piv_lu_solve_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_solve_10x10", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + lu.solve(&mut b); + }) + }); +} + +fn full_piv_lu_solve_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_solve_100x100", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + lu.solve(&mut b); + }) + }); +} + +fn full_piv_lu_solve_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_solve_500x500", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + lu.solve(&mut b); + }) + }); +} + +fn full_piv_lu_inverse_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_inverse_10x10", move |bh| { + bh.iter(|| std::hint::black_box(lu.try_inverse())) + }); +} + +fn full_piv_lu_inverse_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_inverse_100x100", move |bh| { + bh.iter(|| std::hint::black_box(lu.try_inverse())) + }); +} + +fn full_piv_lu_inverse_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_inverse_500x500", move |bh| { + bh.iter(|| std::hint::black_box(lu.try_inverse())) + }); +} + +fn full_piv_lu_determinant_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_determinant_10x10", move |bh| { + bh.iter(|| std::hint::black_box(lu.determinant())) + }); +} + +fn full_piv_lu_determinant_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_determinant_100x100", move |bh| { + bh.iter(|| std::hint::black_box(lu.determinant())) + }); +} + +fn full_piv_lu_determinant_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let lu = FullPivLU::new(m.clone()); + + bh.bench_function("full_piv_lu_determinant_500x500", move |bh| { + bh.iter(|| std::hint::black_box(lu.determinant())) + }); +} + +criterion_group!( + full_piv_lu, + full_piv_lu_decompose_10x10, + full_piv_lu_decompose_100x100, + // full_piv_lu_decompose_500x500, + full_piv_lu_solve_10x10, + full_piv_lu_solve_100x100, + // full_piv_lu_solve_500x500, + full_piv_lu_inverse_10x10, + full_piv_lu_inverse_100x100, + // full_piv_lu_inverse_500x500, + full_piv_lu_determinant_10x10, + full_piv_lu_determinant_100x100, + // full_piv_lu_determinant_500x500 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/hessenberg.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/hessenberg.rs new file mode 100644 index 000000000..8cfbb9e2e --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/hessenberg.rs @@ -0,0 +1,75 @@ +use na::{DMatrix, Hessenberg, Matrix4}; + +#[path = "../common/macros.rs"] +mod macros; + +// Without unpack. +fn hessenberg_decompose_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("hessenberg_decompose_4x4", move |bh| { + bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) + }); +} + +fn hessenberg_decompose_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("hessenberg_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) + }); +} + +fn hessenberg_decompose_200x200(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(200, 200); + bh.bench_function("hessenberg_decompose_200x200", move |bh| { + bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) + }); +} + +fn hessenberg_decompose_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("hessenberg_decompose_500x500", move |bh| { + bh.iter(|| std::hint::black_box(Hessenberg::new(m.clone()))) + }); +} + +// With unpack. +fn hessenberg_decompose_unpack_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("hessenberg_decompose_unpack_100x100", move |bh| { + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) + }); +} + +fn hessenberg_decompose_unpack_200x200(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(200, 200); + bh.bench_function("hessenberg_decompose_unpack_200x200", move |bh| { + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) + }); +} + +fn hessenberg_decompose_unpack_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("hessenberg_decompose_unpack_500x500", move |bh| { + bh.iter(|| { + let hess = Hessenberg::new(m.clone()); + let _ = hess.unpack(); + }) + }); +} + +criterion_group!( + hessenberg, + hessenberg_decompose_4x4, + hessenberg_decompose_100x100, + hessenberg_decompose_200x200, + // hessenberg_decompose_500x500, + hessenberg_decompose_unpack_100x100, + hessenberg_decompose_unpack_200x200, + // hessenberg_decompose_unpack_500x500 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/lu.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/lu.rs new file mode 100644 index 000000000..95da17d6b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/lu.rs @@ -0,0 +1,127 @@ +use na::{DMatrix, DVector, LU}; + +// Without unpack. +fn lu_decompose_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + bh.bench_function("lu_decompose_10x10", move |bh| { + bh.iter(|| std::hint::black_box(LU::new(m.clone()))) + }); +} + +fn lu_decompose_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("lu_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(LU::new(m.clone()))) + }); +} + +fn lu_decompose_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("lu_decompose_500x500", move |bh| { + bh.iter(|| std::hint::black_box(LU::new(m.clone()))) + }); +} + +fn lu_solve_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_solve_10x10", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + lu.solve(&mut b); + }) + }); +} + +fn lu_solve_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_solve_100x100", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + lu.solve(&mut b); + }) + }); +} + +fn lu_solve_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let lu = LU::new(m.clone()); + + bh.bench_function("", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + lu.solve(&mut b); + }) + }); +} + +fn lu_inverse_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_inverse_10x10", move |bh| { + bh.iter(|| std::hint::black_box(lu.try_inverse())) + }); +} + +fn lu_inverse_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_inverse_100x100", move |bh| { + bh.iter(|| std::hint::black_box(lu.try_inverse())) + }); +} + +fn lu_inverse_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_inverse_500x500", move |bh| { + bh.iter(|| std::hint::black_box(lu.try_inverse())) + }); +} + +fn lu_determinant_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_determinant_10x10", move |bh| { + bh.iter(|| std::hint::black_box(lu.determinant())) + }); +} + +fn lu_determinant_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let lu = LU::new(m.clone()); + + bh.bench_function("lu_determinant_100x100", move |bh| { + bh.iter(|| std::hint::black_box(lu.determinant())) + }); +} + +fn lu_determinant_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let lu = LU::new(m.clone()); + + bh.bench_function("", move |bh| { + bh.iter(|| std::hint::black_box(lu.determinant())) + }); +} + +criterion_group!( + lu, + lu_decompose_10x10, + lu_decompose_100x100, + // lu_decompose_500x500, + lu_solve_10x10, + lu_solve_100x100, + lu_inverse_10x10, + lu_inverse_100x100, + // lu_inverse_500x500, + lu_determinant_10x10, + lu_determinant_100x100 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/mod.rs new file mode 100644 index 000000000..8fda10fda --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/mod.rs @@ -0,0 +1,22 @@ +pub use self::bidiagonal::bidiagonal; +pub use self::cholesky::cholesky; +pub use self::full_piv_lu::full_piv_lu; +pub use self::hessenberg::hessenberg; +pub use self::lu::lu; +pub use self::qr::qr; +pub use self::schur::schur; +pub use self::solve::solve; +pub use self::svd::svd; +pub use self::symmetric_eigen::symmetric_eigen; + +mod bidiagonal; +mod cholesky; +mod full_piv_lu; +mod hessenberg; +mod lu; +mod qr; +mod schur; +mod solve; +mod svd; +mod symmetric_eigen; +// mod eigen; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/qr.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/qr.rs new file mode 100644 index 000000000..4fd0c37a1 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/qr.rs @@ -0,0 +1,163 @@ +use na::{DMatrix, DVector, Matrix4, QR}; + +#[path = "../common/macros.rs"] +mod macros; + +// Without unpack. +fn qr_decompose_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("qr_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(QR::new(m.clone()))) + }); +} + +fn qr_decompose_100x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 500); + bh.bench_function("qr_decompose_100x500", move |bh| { + bh.iter(|| std::hint::black_box(QR::new(m.clone()))) + }); +} + +fn qr_decompose_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("qr_decompose_4x4", move |bh| { + bh.iter(|| std::hint::black_box(QR::new(m.clone()))) + }); +} + +fn qr_decompose_500x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 100); + bh.bench_function("qr_decompose_500x100", move |bh| { + bh.iter(|| std::hint::black_box(QR::new(m.clone()))) + }); +} + +fn qr_decompose_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("qr_decompose_500x500", move |bh| { + bh.iter(|| std::hint::black_box(QR::new(m.clone()))) + }); +} + +// With unpack. +fn qr_decompose_unpack_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + bh.bench_function("qr_decompose_unpack_100x100", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); +} + +fn qr_decompose_unpack_100x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 500); + bh.bench_function("qr_decompose_unpack_100x500", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); +} + +fn qr_decompose_unpack_500x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 100); + bh.bench_function("qr_decompose_unpack_500x100", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); +} + +fn qr_decompose_unpack_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + bh.bench_function("qr_decompose_unpack_500x500", move |bh| { + bh.iter(|| { + let qr = QR::new(m.clone()); + let _ = qr.unpack(); + }) + }); +} + +fn qr_solve_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let qr = QR::new(m.clone()); + + bh.bench_function("qr_solve_10x10", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(10, 1.0); + qr.solve(&mut b); + }) + }); +} + +fn qr_solve_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let qr = QR::new(m.clone()); + + bh.bench_function("qr_solve_100x100", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(100, 1.0); + qr.solve(&mut b); + }) + }); +} + +fn qr_solve_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let qr = QR::new(m.clone()); + + bh.bench_function("qr_solve_500x500", move |bh| { + bh.iter(|| { + let mut b = DVector::::from_element(500, 1.0); + qr.solve(&mut b); + }) + }); +} + +fn qr_inverse_10x10(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(10, 10); + let qr = QR::new(m.clone()); + + bh.bench_function("qr_inverse_10x10", move |bh| { + bh.iter(|| std::hint::black_box(qr.try_inverse())) + }); +} + +fn qr_inverse_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let qr = QR::new(m.clone()); + + bh.bench_function("qr_inverse_100x100", move |bh| { + bh.iter(|| std::hint::black_box(qr.try_inverse())) + }); +} + +fn qr_inverse_500x500(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(500, 500); + let qr = QR::new(m.clone()); + + bh.bench_function("qr_inverse_500x500", move |bh| { + bh.iter(|| std::hint::black_box(qr.try_inverse())) + }); +} + +criterion_group!( + qr, + qr_decompose_100x100, + qr_decompose_100x500, + qr_decompose_4x4, + qr_decompose_500x100, + // qr_decompose_500x500, + qr_decompose_unpack_100x100, + qr_decompose_unpack_100x500, + qr_decompose_unpack_500x100, + // qr_decompose_unpack_500x500, + qr_solve_10x10, + qr_solve_100x100, + // qr_solve_500x500, + qr_inverse_10x10, + qr_inverse_100x100, + // qr_inverse_500x500 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/schur.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/schur.rs new file mode 100644 index 000000000..e442fcab2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/schur.rs @@ -0,0 +1,69 @@ +use na::{Matrix4, Schur}; + +fn schur_decompose_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("schur_decompose_4x4", move |bh| { + bh.iter(|| std::hint::black_box(Schur::new(m.clone()))) + }); +} + +fn schur_decompose_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("schur_decompose_10x10", move |bh| { + bh.iter(|| std::hint::black_box(Schur::new(m.clone()))) + }); +} + +fn schur_decompose_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("schur_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(Schur::new(m.clone()))) + }); +} + +fn schur_decompose_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("schur_decompose_200x200", move |bh| { + bh.iter(|| std::hint::black_box(Schur::new(m.clone()))) + }); +} + +fn eigenvalues_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("eigenvalues_4x4", move |bh| { + bh.iter(|| std::hint::black_box(m.complex_eigenvalues())) + }); +} + +fn eigenvalues_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("eigenvalues_10x10", move |bh| { + bh.iter(|| std::hint::black_box(m.complex_eigenvalues())) + }); +} + +fn eigenvalues_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("eigenvalues_100x100", move |bh| { + bh.iter(|| std::hint::black_box(m.complex_eigenvalues())) + }); +} + +fn eigenvalues_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("eigenvalues_200x200", move |bh| { + bh.iter(|| std::hint::black_box(m.complex_eigenvalues())) + }); +} + +criterion_group!( + schur, + schur_decompose_4x4, + schur_decompose_10x10, + schur_decompose_100x100, + schur_decompose_200x200, + eigenvalues_4x4, + eigenvalues_10x10, + eigenvalues_100x100, + eigenvalues_200x200 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/solve.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/solve.rs new file mode 100644 index 000000000..cddfef28b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/solve.rs @@ -0,0 +1,101 @@ +use na::{DMatrix, DVector}; + +fn solve_l_triangular_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.bench_function("solve_l_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.solve_lower_triangular(&v); + }) + }); +} + +fn solve_l_triangular_1000x1000(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.bench_function("solve_l_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.solve_lower_triangular(&v); + }) + }); +} + +fn tr_solve_l_triangular_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.bench_function("tr_solve_l_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_lower_triangular(&v); + }) + }); +} + +fn tr_solve_l_triangular_1000x1000(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.bench_function("tr_solve_l_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_lower_triangular(&v); + }) + }); +} + +fn solve_u_triangular_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.bench_function("solve_u_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.solve_upper_triangular(&v); + }) + }); +} + +fn solve_u_triangular_1000x1000(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.bench_function("solve_u_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.solve_upper_triangular(&v); + }) + }); +} + +fn tr_solve_u_triangular_100x100(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(100, 100); + let v = DVector::::new_random(100); + + bh.bench_function("tr_solve_u_triangular_100x100", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_upper_triangular(&v); + }) + }); +} + +fn tr_solve_u_triangular_1000x1000(bh: &mut criterion::Criterion) { + let m = DMatrix::::new_random(1000, 1000); + let v = DVector::::new_random(1000); + + bh.bench_function("tr_solve_u_triangular_1000x1000", move |bh| { + bh.iter(|| { + let _ = m.tr_solve_upper_triangular(&v); + }) + }); +} + +criterion_group!( + solve, + solve_l_triangular_100x100, + solve_l_triangular_1000x1000, + tr_solve_l_triangular_100x100, + tr_solve_l_triangular_1000x1000, + solve_u_triangular_100x100, + solve_u_triangular_1000x1000, + tr_solve_u_triangular_100x100, + tr_solve_u_triangular_1000x1000 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/svd.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/svd.rs new file mode 100644 index 000000000..a8e464208 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/svd.rs @@ -0,0 +1,149 @@ +use na::{Matrix2, Matrix3, Matrix4, SVD}; + +fn svd_decompose_2x2_f32(bh: &mut criterion::Criterion) { + let m = Matrix2::::new_random(); + bh.bench_function("svd_decompose_2x2", move |bh| { + bh.iter(|| std::hint::black_box(SVD::new_unordered(m.clone(), true, true))) + }); +} + +fn svd_decompose_3x3_f32(bh: &mut criterion::Criterion) { + let m = Matrix3::::new_random(); + bh.bench_function("svd_decompose_3x3", move |bh| { + bh.iter(|| std::hint::black_box(SVD::new_unordered(m.clone(), true, true))) + }); +} + +fn svd_decompose_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("svd_decompose_4x4", move |bh| { + bh.iter(|| std::hint::black_box(SVD::new(m.clone(), true, true))) + }); +} + +fn svd_decompose_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("svd_decompose_10x10", move |bh| { + bh.iter(|| std::hint::black_box(SVD::new(m.clone(), true, true))) + }); +} + +fn svd_decompose_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("svd_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(SVD::new(m.clone(), true, true))) + }); +} + +fn svd_decompose_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("svd_decompose_200x200", move |bh| { + bh.iter(|| std::hint::black_box(SVD::new(m.clone(), true, true))) + }); +} + +fn rank_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("rank_4x4", move |bh| { + bh.iter(|| std::hint::black_box(m.rank(1.0e-10))) + }); +} + +fn rank_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("rank_10x10", move |bh| { + bh.iter(|| std::hint::black_box(m.rank(1.0e-10))) + }); +} + +fn rank_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("rank_100x100", move |bh| { + bh.iter(|| std::hint::black_box(m.rank(1.0e-10))) + }); +} + +fn rank_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("rank_200x200", move |bh| { + bh.iter(|| std::hint::black_box(m.rank(1.0e-10))) + }); +} + +fn singular_values_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("singular_values_4x4", move |bh| { + bh.iter(|| std::hint::black_box(m.singular_values())) + }); +} + +fn singular_values_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("singular_values_10x10", move |bh| { + bh.iter(|| std::hint::black_box(m.singular_values())) + }); +} + +fn singular_values_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("singular_values_100x100", move |bh| { + bh.iter(|| std::hint::black_box(m.singular_values())) + }); +} + +fn singular_values_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("singular_values_200x200", move |bh| { + bh.iter(|| std::hint::black_box(m.singular_values())) + }); +} + +fn pseudo_inverse_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("pseudo_inverse_4x4", move |bh| { + bh.iter(|| std::hint::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); +} + +fn pseudo_inverse_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("pseudo_inverse_10x10", move |bh| { + bh.iter(|| std::hint::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); +} + +fn pseudo_inverse_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("pseudo_inverse_100x100", move |bh| { + bh.iter(|| std::hint::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); +} + +fn pseudo_inverse_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("pseudo_inverse_200x200", move |bh| { + bh.iter(|| std::hint::black_box(m.clone().pseudo_inverse(1.0e-10))) + }); +} + +criterion_group!( + svd, + svd_decompose_2x2_f32, + svd_decompose_3x3_f32, + svd_decompose_4x4, + svd_decompose_10x10, + svd_decompose_100x100, + svd_decompose_200x200, + rank_4x4, + rank_10x10, + rank_100x100, + rank_200x200, + singular_values_4x4, + singular_values_10x10, + singular_values_100x100, + singular_values_200x200, + pseudo_inverse_4x4, + pseudo_inverse_10x10, + pseudo_inverse_100x100, + pseudo_inverse_200x200 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/symmetric_eigen.rs b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/symmetric_eigen.rs new file mode 100644 index 000000000..eeb5253fc --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/benches/linalg/symmetric_eigen.rs @@ -0,0 +1,37 @@ +use na::{Matrix4, SymmetricEigen}; + +fn symmetric_eigen_decompose_4x4(bh: &mut criterion::Criterion) { + let m = Matrix4::::new_random(); + bh.bench_function("symmetric_eigen_decompose_4x4", move |bh| { + bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) + }); +} + +fn symmetric_eigen_decompose_10x10(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(10, 10); + bh.bench_function("symmetric_eigen_decompose_10x10", move |bh| { + bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) + }); +} + +fn symmetric_eigen_decompose_100x100(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(100, 100); + bh.bench_function("symmetric_eigen_decompose_100x100", move |bh| { + bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) + }); +} + +fn symmetric_eigen_decompose_200x200(bh: &mut criterion::Criterion) { + let m = crate::reproductible_dmatrix(200, 200); + bh.bench_function("symmetric_eigen_decompose_200x200", move |bh| { + bh.iter(|| std::hint::black_box(SymmetricEigen::new(m.clone()))) + }); +} + +criterion_group!( + symmetric_eigen, + symmetric_eigen_decompose_4x4, + symmetric_eigen_decompose_10x10, + symmetric_eigen_decompose_100x100, + symmetric_eigen_decompose_200x200 +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/clippy.toml b/collector/compile-benchmarks/nalgebra-0.33.0/clippy.toml new file mode 100644 index 000000000..8169845ce --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/clippy.toml @@ -0,0 +1,2 @@ +too-many-arguments-threshold = 8 +type-complexity-threshold = 675 diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/dimensional_genericity.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/dimensional_genericity.rs new file mode 100644 index 000000000..e6c11fc6f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/dimensional_genericity.rs @@ -0,0 +1,60 @@ +extern crate nalgebra as na; + +use na::allocator::Allocator; +use na::dimension::Dim; +use na::{DefaultAllocator, OVector, RealField, Unit, Vector2, Vector3}; + +/// Reflects a vector wrt. the hyperplane with normal `plane_normal`. +fn reflect_wrt_hyperplane_with_dimensional_genericity( + plane_normal: &Unit>, + vector: &OVector, +) -> OVector +where + T: RealField, + D: Dim, + DefaultAllocator: Allocator, +{ + let n = plane_normal.as_ref(); // Get the underlying V. + vector - n * (n.dot(vector) * na::convert(2.0)) +} + +/// Reflects a 2D vector wrt. the 2D line with normal `plane_normal`. +fn reflect_wrt_hyperplane2(plane_normal: &Unit>, vector: &Vector2) -> Vector2 +where + T: RealField, +{ + let n = plane_normal.as_ref(); // Get the underlying Vector2 + vector - n * (n.dot(vector) * na::convert(2.0)) +} + +/// Reflects a 3D vector wrt. the 3D plane with normal `plane_normal`. +/// /!\ This is an exact replicate of `reflect_wrt_hyperplane2`, but for 3D. +fn reflect_wrt_hyperplane3(plane_normal: &Unit>, vector: &Vector3) -> Vector3 +where + T: RealField, +{ + let n = plane_normal.as_ref(); // Get the underlying Vector3 + vector - n * (n.dot(vector) * na::convert(2.0)) +} + +fn main() { + let plane2 = Vector2::y_axis(); // 2D plane normal. + let plane3 = Vector3::y_axis(); // 3D plane normal. + + let v2 = Vector2::new(1.0, 2.0); // 2D vector to be reflected. + let v3 = Vector3::new(1.0, 2.0, 3.0); // 3D vector to be reflected. + + // We can call the same function for 2D and 3D. + assert_eq!( + reflect_wrt_hyperplane_with_dimensional_genericity(&plane2, &v2).y, + -2.0 + ); + assert_eq!( + reflect_wrt_hyperplane_with_dimensional_genericity(&plane3, &v3).y, + -2.0 + ); + + // Call each specific implementation depending on the dimension. + assert_eq!(reflect_wrt_hyperplane2(&plane2, &v2).y, -2.0); + assert_eq!(reflect_wrt_hyperplane3(&plane3, &v3).y, -2.0); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/homogeneous_coordinates.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/homogeneous_coordinates.rs new file mode 100644 index 000000000..35aabfa31 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/homogeneous_coordinates.rs @@ -0,0 +1,44 @@ +#[macro_use] +extern crate approx; +extern crate nalgebra as na; + +use na::{Isometry2, Point2, Vector2}; +use std::f32; + +fn use_dedicated_types() { + let iso = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI); + let pt = Point2::new(1.0, 0.0); + let vec = Vector2::x(); + + let transformed_pt = iso * pt; + let transformed_vec = iso * vec; + + assert_relative_eq!(transformed_pt, Point2::new(0.0, 1.0)); + assert_relative_eq!(transformed_vec, Vector2::new(-1.0, 0.0)); +} + +fn use_homogeneous_coordinates() { + let iso = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI); + let pt = Point2::new(1.0, 0.0); + let vec = Vector2::x(); + + // Compute using homogeneous coordinates. + let hom_iso = iso.to_homogeneous(); + let hom_pt = pt.to_homogeneous(); + let hom_vec = vec.to_homogeneous(); + + let hom_transformed_pt = hom_iso * hom_pt; + let hom_transformed_vec = hom_iso * hom_vec; + + // Convert back to the cartesian coordinates. + let transformed_pt = Point2::from_homogeneous(hom_transformed_pt).unwrap(); + let transformed_vec = Vector2::from_homogeneous(hom_transformed_vec).unwrap(); + + assert_relative_eq!(transformed_pt, Point2::new(0.0, 1.0)); + assert_relative_eq!(transformed_vec, Vector2::new(-1.0, 0.0)); +} + +fn main() { + use_dedicated_types(); + use_homogeneous_coordinates(); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/linear_system_resolution.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/linear_system_resolution.rs new file mode 100644 index 000000000..91624418c --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/linear_system_resolution.rs @@ -0,0 +1,39 @@ +#![cfg_attr(rustfmt, rustfmt_skip)] +#[macro_use] +extern crate approx; // for assert_relative_eq +extern crate nalgebra as na; +use na::{Matrix4, Matrix4x3, Vector4}; + +fn main() { + let a = Matrix4::new( + 1.0, 1.0, 2.0, -5.0, + 2.0, 5.0, -1.0, -9.0, + 2.0, 1.0, -1.0, 3.0, + 1.0, 3.0, 2.0, 7.0, + ); + let mut b = Vector4::new(3.0, -3.0, -11.0, -5.0); + let decomp = a.lu(); + let x = decomp.solve(&b).expect("Linear resolution failed."); + assert_relative_eq!(a * x, b); + + /* + * It is possible to perform the resolution in-place. + * This is particularly useful to avoid allocations when + * `b` is a `DVector` or a `DMatrix`. + */ + assert!(decomp.solve_mut(&mut b), "Linear resolution failed."); + assert_relative_eq!(x, b); + + /* + * It is possible to solve multiple systems + * simultaneously by using a matrix for `b`. + */ + let b = Matrix4x3::new( + 3.0, 2.0, 0.0, + -3.0, 0.0, 0.0, + -11.0, 5.0, -3.0, + -5.0, 10.0, 4.0, + ); + let x = decomp.solve(&b).expect("Linear resolution failed."); + assert_relative_eq!(a * x, b); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/matrix_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/matrix_construction.rs new file mode 100644 index 000000000..0dc5cbac6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/matrix_construction.rs @@ -0,0 +1,62 @@ +extern crate nalgebra as na; + +use na::{DMatrix, Matrix2x3, RowVector3, Vector2}; + +fn main() { + // All the following matrices are equal but constructed in different ways. + let m = Matrix2x3::new(1.1, 1.2, 1.3, 2.1, 2.2, 2.3); + + let m1 = Matrix2x3::from_rows(&[ + RowVector3::new(1.1, 1.2, 1.3), + RowVector3::new(2.1, 2.2, 2.3), + ]); + + let m2 = Matrix2x3::from_columns(&[ + Vector2::new(1.1, 2.1), + Vector2::new(1.2, 2.2), + Vector2::new(1.3, 2.3), + ]); + + let m3 = Matrix2x3::from_row_slice(&[1.1, 1.2, 1.3, 2.1, 2.2, 2.3]); + + let m4 = Matrix2x3::from_column_slice(&[1.1, 2.1, 1.2, 2.2, 1.3, 2.3]); + + let m5 = Matrix2x3::from_fn(|r, c| (r + 1) as f32 + (c + 1) as f32 / 10.0); + + let m6 = Matrix2x3::from_iterator([1.1f32, 2.1, 1.2, 2.2, 1.3, 2.3].iter().cloned()); + + assert_eq!(m, m1); + assert_eq!(m, m2); + assert_eq!(m, m3); + assert_eq!(m, m4); + assert_eq!(m, m5); + assert_eq!(m, m6); + + // All the following matrices are equal but constructed in different ways. + // This time, we used a dynamically-sized matrix to show the extra arguments + // for the matrix shape. + let dm = DMatrix::from_row_slice( + 4, + 3, + &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0], + ); + + let dm1 = DMatrix::from_diagonal_element(4, 3, 1.0); + let dm2 = DMatrix::identity(4, 3); + let dm3 = DMatrix::from_fn(4, 3, |r, c| if r == c { 1.0 } else { 0.0 }); + let dm4 = DMatrix::from_iterator( + 4, + 3, + [ + // Components listed column-by-column. + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, + ] + .iter() + .cloned(), + ); + + assert_eq!(dm, dm1); + assert_eq!(dm, dm2); + assert_eq!(dm, dm3); + assert_eq!(dm, dm4); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/matrixcompare.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/matrixcompare.rs new file mode 100644 index 000000000..6809763c5 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/matrixcompare.rs @@ -0,0 +1,82 @@ +extern crate nalgebra as na; + +use matrixcompare::comparators::{AbsoluteElementwiseComparator, ExactElementwiseComparator}; +use matrixcompare::compare_matrices; +use na::{OMatrix, U3, U4}; + +fn compare_integers_fail() { + println!("Comparing two integer matrices."); + + #[rustfmt::skip] + let a = OMatrix::<_, U3, U4>::from_row_slice(&[ + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, -2, 11 + ]); + + #[rustfmt::skip] + let b = OMatrix::<_, U3, U4>::from_row_slice(&[ + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11 + ]); + + if let Err(err) = compare_matrices(a, b, &ExactElementwiseComparator) { + println!("{}", err); + } +} + +fn compare_different_size() { + println!("Comparing matrices of different size."); + #[rustfmt::skip] + let a = OMatrix::<_, U3, U3>::from_row_slice(&[ + 0, 1, 2, + 4, 5, 6, + 8, 9, 10, + ]); + + #[rustfmt::skip] + let b = OMatrix::<_, U3, U4>::from_row_slice(&[ + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11 + ]); + + if let Err(err) = compare_matrices(a, b, &ExactElementwiseComparator) { + println!("{}", err); + } +} + +fn compare_f64_abs_tol_fail() { + println!("Comparing two f64 matrices."); + + #[rustfmt::skip] + let a = OMatrix::::from_row_slice(&[ + 0.0, 1.0, 2.0 + 1e-10, + 4.0, 5.0, 6.0, + 8.0, 9.0, 10.0, + ]); + + #[rustfmt::skip] + let b = OMatrix::<_, U3, U3>::from_row_slice(&[ + 0.0, 1.0, 2.0, + 4.0, 5.0, 6.0, + 8.0, 9.0, 10.0 + ]); + + let cmp = AbsoluteElementwiseComparator { tol: 1e-12 }; + if let Err(err) = compare_matrices(a, b, &cmp) { + println!("{}", err); + } +} + +fn main() { + // This example mostly serves the purpose of demonstrating the kind of error messages + // that are given upon comparison failure. + // The more typical use case is using `assert_matrix_eq!` in tests. + compare_integers_fail(); + println!("======================================================"); + compare_f64_abs_tol_fail(); + println!("======================================================"); + compare_different_size(); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/mvp.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/mvp.rs new file mode 100644 index 000000000..639359138 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/mvp.rs @@ -0,0 +1,29 @@ +#![allow(unused_variables)] + +extern crate nalgebra as na; + +use na::{Isometry3, Perspective3, Point3, Vector3}; +use std::f32::consts; + +fn main() { + // Our object is translated along the x axis. + let model = Isometry3::new(Vector3::x(), na::zero()); + + // Our camera looks toward the point (1.0, 0.0, 0.0). + // It is located at (0.0, 0.0, 1.0). + let eye = Point3::new(0.0, 0.0, 1.0); + let target = Point3::new(1.0, 0.0, 0.0); + let view = Isometry3::look_at_rh(&eye, &target, &Vector3::y()); + + // A perspective projection. + let projection = Perspective3::new(16.0 / 9.0, consts::PI / 2.0, 1.0, 1000.0); + + // The combination of the model with the view is still an isometry. + let model_view = view * model; + + // Convert everything to a `Matrix4` so that they can be combined. + let mat_model_view = model_view.to_homogeneous(); + + // Combine everything. + let model_view_projection = projection.as_matrix() * mat_model_view; +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/point_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/point_construction.rs new file mode 100644 index 000000000..55c50fc2d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/point_construction.rs @@ -0,0 +1,25 @@ +extern crate nalgebra as na; + +use na::{Point3, Vector3, Vector4}; + +fn main() { + // Build using components directly. + let p0 = Point3::new(2.0, 3.0, 4.0); + + // Build from a coordinates vector. + let coords = Vector3::new(2.0, 3.0, 4.0); + let p1 = Point3::from(coords); + + // Build by translating the origin. + let translation = Vector3::new(2.0, 3.0, 4.0); + let p2 = Point3::origin() + translation; + + // Build from homogeneous coordinates. The last component of the + // vector will be removed and all other components divided by 10.0. + let homogeneous_coords = Vector4::new(20.0, 30.0, 40.0, 10.0); + let p3 = Point3::from_homogeneous(homogeneous_coords); + + assert_eq!(p0, p1); + assert_eq!(p0, p2); + assert_eq!(p0, p3.unwrap()); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/raw_pointer.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/raw_pointer.rs new file mode 100644 index 000000000..c4d7824b4 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/raw_pointer.rs @@ -0,0 +1,36 @@ +extern crate nalgebra as na; + +use na::{Matrix3, Point3, Vector3}; + +fn main() { + let v = Vector3::new(1.0f32, 0.0, 1.0); + let p = Point3::new(1.0f32, 0.0, 1.0); + let m = na::one::>(); + + // Convert to arrays. + let v_array = v.as_slice(); + let p_array = p.coords.as_slice(); + let m_array = m.as_slice(); + + // Get data pointers. + let v_pointer = v_array.as_ptr(); + let p_pointer = p_array.as_ptr(); + let m_pointer = m_array.as_ptr(); + + /* Then pass the raw pointers to some graphics API. */ + + #[allow(clippy::float_cmp)] + unsafe { + assert_eq!(*v_pointer, 1.0); + assert_eq!(*v_pointer.offset(1), 0.0); + assert_eq!(*v_pointer.offset(2), 1.0); + + assert_eq!(*p_pointer, 1.0); + assert_eq!(*p_pointer.offset(1), 0.0); + assert_eq!(*p_pointer.offset(2), 1.0); + + assert_eq!(*m_pointer, 1.0); + assert_eq!(*m_pointer.offset(4), 1.0); + assert_eq!(*m_pointer.offset(8), 1.0); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/reshaping.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/reshaping.rs new file mode 100644 index 000000000..c1cbbba54 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/reshaping.rs @@ -0,0 +1,54 @@ +#![cfg_attr(rustfmt, rustfmt_skip)] + +extern crate nalgebra as na; + +use na::{DMatrix, Dyn, Matrix2x3, Matrix3x2, Const}; + +fn main() { + // Matrices can be reshaped in-place without moving or copying values. + let m1 = Matrix2x3::new( + 1.1, 1.2, 1.3, + 2.1, 2.2, 2.3 + ); + let m2 = Matrix3x2::new( + 1.1, 2.2, + 2.1, 1.3, + 1.2, 2.3 + ); + + let m3 = m1.reshape_generic(Const::<3>, Const::<2>); + assert_eq!(m3, m2); + + // Note that, for statically sized matrices, invalid reshapes will not compile: + //let m4 = m3.reshape_generic(U3, U3); + + // If dynamically sized matrices are used, the reshaping is checked at run-time. + let dm1 = DMatrix::from_row_slice( + 4, + 3, + &[ + 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0 + ], + ); + let dm2 = DMatrix::from_row_slice( + 6, + 2, + &[ + 1.0, 0.0, + 0.0, 1.0, + 0.0, 0.0, + 0.0, 1.0, + 0.0, 0.0, + 0.0, 0.0, + ], + ); + + let dm3 = dm1.reshape_generic(Dyn(6), Dyn(2)); + assert_eq!(dm3, dm2); + + // Invalid reshapings of dynamic matrices will panic at run-time. + //let dm4 = dm3.reshape_generic(Dyn(6), Dyn(6)); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/scalar_genericity.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/scalar_genericity.rs new file mode 100644 index 000000000..1c93305e0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/scalar_genericity.rs @@ -0,0 +1,25 @@ +extern crate nalgebra as na; + +use na::{Scalar, Vector3}; +use simba::scalar::RealField; + +fn print_vector(m: &Vector3) { + println!("{:?}", m) +} + +fn print_norm(v: &Vector3) { + // NOTE: alternatively, nalgebra already defines `v.norm()`. + let norm = v.dot(v).sqrt(); + + // The RealField bound implies that T is Display so we can + // use "{}" instead of "{:?}" for the format string. + println!("{}", norm) +} + +fn main() { + let v1 = Vector3::new(1, 2, 3); + let v2 = Vector3::new(1.0, 2.0, 3.0); + + print_vector(&v1); + print_norm(&v2); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/screen_to_view_coords.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/screen_to_view_coords.rs new file mode 100644 index 000000000..f66db48ba --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/screen_to_view_coords.rs @@ -0,0 +1,24 @@ +#![allow(unused_variables)] + +extern crate nalgebra as na; + +use na::{Perspective3, Point2, Point3, Unit}; +use std::f32::consts; + +fn main() { + let projection = Perspective3::new(800.0 / 600.0, consts::PI / 2.0, 1.0, 1000.0); + let screen_point = Point2::new(10.0f32, 20.0); + + // Compute two points in clip-space. + // "ndc" = normalized device coordinates. + let near_ndc_point = Point3::new(screen_point.x / 800.0, screen_point.y / 600.0, -1.0); + let far_ndc_point = Point3::new(screen_point.x / 800.0, screen_point.y / 600.0, 1.0); + + // Unproject them to view-space. + let near_view_point = projection.unproject_point(&near_ndc_point); + let far_view_point = projection.unproject_point(&far_ndc_point); + + // Compute the view-space line parameters. + let line_location = near_view_point; + let line_direction = Unit::new_normalize(far_view_point - near_view_point); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_conversion.rs new file mode 100644 index 000000000..a56237ab6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_conversion.rs @@ -0,0 +1,24 @@ +extern crate nalgebra as na; + +use na::{Isometry2, Similarity2, Vector2}; +use std::f32::consts; + +fn main() { + // Isometry -> Similarity conversion always succeeds. + let iso = Isometry2::new(Vector2::new(1.0f32, 2.0), na::zero()); + let _: Similarity2 = na::convert(iso); + + // Similarity -> Isometry conversion fails if the scaling factor is not 1.0. + let sim_without_scaling = Similarity2::new(Vector2::new(1.0f32, 2.0), consts::PI, 1.0); + let sim_with_scaling = Similarity2::new(Vector2::new(1.0f32, 2.0), consts::PI, 2.0); + + let iso_success: Option> = na::try_convert(sim_without_scaling); + let iso_fail: Option> = na::try_convert(sim_with_scaling); + + assert!(iso_success.is_some()); + assert!(iso_fail.is_none()); + + // Similarity -> Isometry conversion can be forced at your own risks. + let iso_forced: Isometry2 = na::convert_unchecked(sim_with_scaling); + assert_eq!(iso_success.unwrap(), iso_forced); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_matrix4.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_matrix4.rs new file mode 100644 index 000000000..85cb9bad0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_matrix4.rs @@ -0,0 +1,46 @@ +#[macro_use] +extern crate approx; +extern crate nalgebra as na; + +use na::{Matrix4, Point3, Vector3}; +use std::f32::consts; + +fn main() { + // Create a uniform scaling matrix with scaling factor 2. + let mut m = Matrix4::new_scaling(2.0); + + assert_eq!(m.transform_vector(&Vector3::x()), Vector3::x() * 2.0); + assert_eq!(m.transform_vector(&Vector3::y()), Vector3::y() * 2.0); + assert_eq!(m.transform_vector(&Vector3::z()), Vector3::z() * 2.0); + + // Append a nonuniform scaling in-place. + m.append_nonuniform_scaling_mut(&Vector3::new(1.0, 2.0, 3.0)); + + assert_eq!(m.transform_vector(&Vector3::x()), Vector3::x() * 2.0); + assert_eq!(m.transform_vector(&Vector3::y()), Vector3::y() * 4.0); + assert_eq!(m.transform_vector(&Vector3::z()), Vector3::z() * 6.0); + + // Append a translation out-of-place. + let m2 = m.append_translation(&Vector3::new(42.0, 0.0, 0.0)); + + assert_eq!( + m2.transform_point(&Point3::new(1.0, 1.0, 1.0)), + Point3::new(42.0 + 2.0, 4.0, 6.0) + ); + + // Create rotation. + let rot = Matrix4::from_scaled_axis(Vector3::x() * consts::PI); + let rot_then_m = m * rot; // Right-multiplication is equivalent to prepending `rot` to `m`. + let m_then_rot = rot * m; // Left-multiplication is equivalent to appending `rot` to `m`. + + let pt = Point3::new(1.0, 2.0, 3.0); + + assert_relative_eq!( + m.transform_point(&rot.transform_point(&pt)), + rot_then_m.transform_point(&pt) + ); + assert_relative_eq!( + rot.transform_point(&m.transform_point(&pt)), + m_then_rot.transform_point(&pt) + ); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point.rs new file mode 100644 index 000000000..37827cc62 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point.rs @@ -0,0 +1,20 @@ +#[macro_use] +extern crate approx; +extern crate nalgebra as na; + +use na::{Isometry2, Point2, Vector2}; +use std::f32; + +fn main() { + let t = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI); + let p = Point2::new(1.0, 0.0); // Will be affected by te rotation and the translation. + let v = Vector2::x(); // Will *not* be affected by the translation. + + assert_relative_eq!(t * p, Point2::new(-1.0 + 1.0, 1.0)); + // ^^^^ │ ^^^^^^^^ + // rotated │ translated + + assert_relative_eq!(t * v, Vector2::new(-1.0, 0.0)); + // ^^^^^ + // rotated only +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point3.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point3.rs new file mode 100644 index 000000000..72267f63b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transform_vector_point3.rs @@ -0,0 +1,24 @@ +extern crate nalgebra as na; + +use na::{Matrix4, Point3, Vector3, Vector4}; + +fn main() { + let mut m = Matrix4::new_rotation_wrt_point(Vector3::x() * 1.57, Point3::new(1.0, 2.0, 1.0)); + m.append_scaling_mut(2.0); + + let point1 = Point3::new(2.0, 3.0, 4.0); + let homogeneous_point2 = Vector4::new(2.0, 3.0, 4.0, 1.0); + + // First option: use the dedicated `.transform_point(...)` method. + let transformed_point1 = m.transform_point(&point1); + // Second option: use the homogeneous coordinates of the point. + let transformed_homogeneous_point2 = m * homogeneous_point2; + + // Recover the 3D point from its 4D homogeneous coordinates. + let transformed_point2 = Point3::from_homogeneous(transformed_homogeneous_point2); + + // Check that transforming the 3D point with the `.transform_point` method is + // indeed equivalent to multiplying its 4D homogeneous coordinates by the 4x4 + // matrix. + assert_eq!(transformed_point1, transformed_point2.unwrap()); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/transformation_pointer.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transformation_pointer.rs new file mode 100644 index 000000000..5d9de5728 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/transformation_pointer.rs @@ -0,0 +1,26 @@ +extern crate nalgebra as na; + +use na::{Isometry3, Vector3}; + +fn main() { + let iso = Isometry3::new(Vector3::new(1.0f32, 0.0, 1.0), na::zero()); + + // Compute the homogeneous coordinates first. + let iso_matrix = iso.to_homogeneous(); + let iso_array = iso_matrix.as_slice(); + let iso_pointer = iso_array.as_ptr(); + + /* Then pass the raw pointer to some graphics API. */ + + #[allow(clippy::float_cmp)] + unsafe { + assert_eq!(*iso_pointer, 1.0); + assert_eq!(*iso_pointer.offset(5), 1.0); + assert_eq!(*iso_pointer.offset(10), 1.0); + assert_eq!(*iso_pointer.offset(15), 1.0); + + assert_eq!(*iso_pointer.offset(12), 1.0); + assert_eq!(*iso_pointer.offset(13), 0.0); + assert_eq!(*iso_pointer.offset(14), 1.0); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/examples/unit_wrapper.rs b/collector/compile-benchmarks/nalgebra-0.33.0/examples/unit_wrapper.rs new file mode 100644 index 000000000..bd9cedf00 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/examples/unit_wrapper.rs @@ -0,0 +1,28 @@ +#![allow(clippy::float_cmp)] +extern crate nalgebra as na; + +use na::{Unit, Vector3}; + +fn length_on_direction_with_unit(v: &Vector3, dir: &Unit>) -> f32 { + // No need to normalize `dir`: we know that it is non-zero and normalized. + v.dot(dir.as_ref()) +} + +fn length_on_direction_without_unit(v: &Vector3, dir: &Vector3) -> f32 { + // Obligatory normalization of the direction vector (and test, for robustness). + if let Some(unit_dir) = dir.try_normalize(1.0e-6) { + v.dot(&unit_dir) + } else { + // Normalization failed because the norm was too small. + panic!("Invalid input direction.") + } +} + +fn main() { + let v = Vector3::new(1.0, 2.0, 3.0); + + let l1 = length_on_direction_with_unit(&v, &Vector3::y_axis()); + let l2 = length_on_direction_without_unit(&v, &Vector3::y()); + + assert_eq!(l1, l2) +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/rustfmt.toml b/collector/compile-benchmarks/nalgebra-0.33.0/rustfmt.toml new file mode 100644 index 000000000..ef693b4e6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/rustfmt.toml @@ -0,0 +1,3 @@ +edition = "2018" +use_try_shorthand = true +use_field_init_shorthand = true diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias.rs new file mode 100644 index 000000000..921f986e0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias.rs @@ -0,0 +1,358 @@ +#[cfg(any(feature = "alloc", feature = "std"))] +use crate::base::dimension::Dyn; +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::storage::Owned; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::vec_storage::VecStorage; +use crate::base::{ArrayStorage, Const, Matrix, Unit}; +use crate::storage::OwnedUninit; +use std::mem::MaybeUninit; + +/* + * + * + * Column-major matrices. + * + * + */ + +/// An owned matrix column-major matrix with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type OMatrix = Matrix>; + +/// An owned matrix with uninitialized data. +pub type UninitMatrix = Matrix, R, C, OwnedUninit>; + +/// An owned matrix column-major matrix with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated( + note = "use SMatrix for a statically-sized matrix using integer dimensions, or OMatrix for an owned matrix using types as dimensions." +)] +pub type MatrixMN = Matrix>; + +/// An owned matrix column-major matrix with `D` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated(note = "use OMatrix or SMatrix instead.")] +pub type MatrixN = Matrix>; + +/// A statically sized column-major matrix with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SMatrix = + Matrix, Const, ArrayStorage>; + +/// A dynamically sized column-major matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type DMatrix = Matrix>; + +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 1 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx1 = Matrix>; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 2 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx2 = Matrix>; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 3 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx3 = Matrix>; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 4 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx4 = Matrix>; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 5 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx5 = Matrix>; +/// A heap-allocated, column-major, matrix with a dynamic number of rows and 6 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type MatrixXx6 = Matrix>; + +/// A heap-allocated, column-major, matrix with 1 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix1xX = Matrix>; +/// A heap-allocated, column-major, matrix with 2 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix2xX = Matrix>; +/// A heap-allocated, column-major, matrix with 3 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix3xX = Matrix>; +/// A heap-allocated, column-major, matrix with 4 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix4xX = Matrix>; +/// A heap-allocated, column-major, matrix with 5 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix5xX = Matrix>; +/// A heap-allocated, column-major, matrix with 6 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[cfg(any(feature = "std", feature = "alloc"))] +pub type Matrix6xX = Matrix>; + +/// A stack-allocated, column-major, 1x1 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix1 = Matrix>; +/// A stack-allocated, column-major, 2x2 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix2 = Matrix>; +/// A stack-allocated, column-major, 3x3 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix3 = Matrix>; +/// A stack-allocated, column-major, 4x4 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix4 = Matrix>; +/// A stack-allocated, column-major, 5x5 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix5 = Matrix>; +/// A stack-allocated, column-major, 6x6 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix6 = Matrix>; + +/// A stack-allocated, column-major, 1x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix1x2 = Matrix>; +/// A stack-allocated, column-major, 1x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix1x3 = Matrix>; +/// A stack-allocated, column-major, 1x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix1x4 = Matrix>; +/// A stack-allocated, column-major, 1x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix1x5 = Matrix>; +/// A stack-allocated, column-major, 1x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix1x6 = Matrix>; + +/// A stack-allocated, column-major, 2x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix2x3 = Matrix>; +/// A stack-allocated, column-major, 2x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix2x4 = Matrix>; +/// A stack-allocated, column-major, 2x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix2x5 = Matrix>; +/// A stack-allocated, column-major, 2x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix2x6 = Matrix>; + +/// A stack-allocated, column-major, 3x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix3x4 = Matrix>; +/// A stack-allocated, column-major, 3x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix3x5 = Matrix>; +/// A stack-allocated, column-major, 3x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix3x6 = Matrix>; + +/// A stack-allocated, column-major, 4x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix4x5 = Matrix>; +/// A stack-allocated, column-major, 4x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix4x6 = Matrix>; + +/// A stack-allocated, column-major, 5x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix5x6 = Matrix>; + +/// A stack-allocated, column-major, 2x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix2x1 = Matrix>; +/// A stack-allocated, column-major, 3x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix3x1 = Matrix>; +/// A stack-allocated, column-major, 4x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix4x1 = Matrix>; +/// A stack-allocated, column-major, 5x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix5x1 = Matrix>; +/// A stack-allocated, column-major, 6x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix6x1 = Matrix>; + +/// A stack-allocated, column-major, 3x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix3x2 = Matrix>; +/// A stack-allocated, column-major, 4x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix4x2 = Matrix>; +/// A stack-allocated, column-major, 5x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix5x2 = Matrix>; +/// A stack-allocated, column-major, 6x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix6x2 = Matrix>; + +/// A stack-allocated, column-major, 4x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix4x3 = Matrix>; +/// A stack-allocated, column-major, 5x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix5x3 = Matrix>; +/// A stack-allocated, column-major, 6x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix6x3 = Matrix>; + +/// A stack-allocated, column-major, 5x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix5x4 = Matrix>; +/// A stack-allocated, column-major, 6x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix6x4 = Matrix>; + +/// A stack-allocated, column-major, 6x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type Matrix6x5 = Matrix>; + +/* + * + * + * Column vectors. + * + * + */ +/// A dynamically sized column vector. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type DVector = Matrix>; + +/// An owned D-dimensional column vector. +pub type OVector = Matrix>; +/// A statically sized D-dimensional column vector. +pub type SVector = Matrix, U1, ArrayStorage>; // Owned, U1>>; + +/// An owned matrix with uninitialized data. +pub type UninitVector = Matrix, D, U1, OwnedUninit>; + +/// An owned matrix column-major matrix with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated( + note = "use SVector for a statically-sized matrix using integer dimensions, or OVector for an owned matrix using types as dimensions." +)] +pub type VectorN = Matrix>; + +/// A stack-allocated, 1-dimensional column vector. +pub type Vector1 = Matrix>; +/// A stack-allocated, 2-dimensional column vector. +pub type Vector2 = Matrix>; +/// A stack-allocated, 3-dimensional column vector. +pub type Vector3 = Matrix>; +/// A stack-allocated, 4-dimensional column vector. +pub type Vector4 = Matrix>; +/// A stack-allocated, 5-dimensional column vector. +pub type Vector5 = Matrix>; +/// A stack-allocated, 6-dimensional column vector. +pub type Vector6 = Matrix>; + +/* + * + * + * Row vectors. + * + * + */ +/// A dynamically sized row vector. +#[cfg(any(feature = "std", feature = "alloc"))] +pub type RowDVector = Matrix>; + +/// An owned D-dimensional row vector. +pub type RowOVector = Matrix>; + +/// A statically sized D-dimensional row vector. +pub type RowSVector = Matrix, ArrayStorage>; + +/// A stack-allocated, 1-dimensional row vector. +pub type RowVector1 = Matrix>; +/// A stack-allocated, 2-dimensional row vector. +pub type RowVector2 = Matrix>; +/// A stack-allocated, 3-dimensional row vector. +pub type RowVector3 = Matrix>; +/// A stack-allocated, 4-dimensional row vector. +pub type RowVector4 = Matrix>; +/// A stack-allocated, 5-dimensional row vector. +pub type RowVector5 = Matrix>; +/// A stack-allocated, 6-dimensional row vector. +pub type RowVector6 = Matrix>; + +/* + * + * + * Unit Vector. + * + * + */ +/// A stack-allocated, 1-dimensional unit vector. +pub type UnitVector1 = Unit>>; +/// A stack-allocated, 2-dimensional unit vector. +pub type UnitVector2 = Unit>>; +/// A stack-allocated, 3-dimensional unit vector. +pub type UnitVector3 = Unit>>; +/// A stack-allocated, 4-dimensional unit vector. +pub type UnitVector4 = Unit>>; +/// A stack-allocated, 5-dimensional unit vector. +pub type UnitVector5 = Unit>>; +/// A stack-allocated, 6-dimensional unit vector. +pub type UnitVector6 = Unit>>; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_slice.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_slice.rs new file mode 100644 index 000000000..8534fa8a6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_slice.rs @@ -0,0 +1,721 @@ +use crate::base::dimension::{Dyn, U1, U2, U3, U4, U5, U6}; +use crate::base::matrix_view::{ViewStorage, ViewStorageMut}; +use crate::base::{Const, Matrix}; +use crate::slice_deprecation_note; + +/* + * + * + * Matrix slice aliases. + * + * + */ +// NOTE: we can't provide defaults for the strides because it's not supported yet by min_const_generics. +/// A column-major matrix slice with dimensions known at compile-time. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SMatrixView)] +pub type SMatrixSlice<'a, T, const R: usize, const C: usize> = + Matrix, Const, ViewStorage<'a, T, Const, Const, Const<1>, Const>>; + +/// A column-major matrix slice dynamic numbers of rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(DMatrixView)] +pub type DMatrixSlice<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A column-major 1x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1)] +pub type MatrixSlice1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 2x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2)] +pub type MatrixSlice2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 3x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3)] +pub type MatrixSlice3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 4x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4)] +pub type MatrixSlice4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 5x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5)] +pub type MatrixSlice5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 6x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6)] +pub type MatrixSlice6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A column-major 1x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x2)] +pub type MatrixSlice1x2<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x3)] +pub type MatrixSlice1x3<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x4)] +pub type MatrixSlice1x4<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x5)] +pub type MatrixSlice1x5<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView1x6)] +pub type MatrixSlice1x6<'a, T, RStride = U1, CStride = U1> = + Matrix>; + +/// A column-major 2x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x1)] +pub type MatrixSlice2x1<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x3)] +pub type MatrixSlice2x3<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x4)] +pub type MatrixSlice2x4<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x5)] +pub type MatrixSlice2x5<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView2x6)] +pub type MatrixSlice2x6<'a, T, RStride = U1, CStride = U2> = + Matrix>; + +/// A column-major 3x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x1)] +pub type MatrixSlice3x1<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x2)] +pub type MatrixSlice3x2<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x4)] +pub type MatrixSlice3x4<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x5)] +pub type MatrixSlice3x5<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView3x6)] +pub type MatrixSlice3x6<'a, T, RStride = U1, CStride = U3> = + Matrix>; + +/// A column-major 4x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x1)] +pub type MatrixSlice4x1<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x2)] +pub type MatrixSlice4x2<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x3)] +pub type MatrixSlice4x3<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x5)] +pub type MatrixSlice4x5<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView4x6)] +pub type MatrixSlice4x6<'a, T, RStride = U1, CStride = U4> = + Matrix>; + +/// A column-major 5x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x1)] +pub type MatrixSlice5x1<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x2)] +pub type MatrixSlice5x2<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x3)] +pub type MatrixSlice5x3<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x4)] +pub type MatrixSlice5x4<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView5x6)] +pub type MatrixSlice5x6<'a, T, RStride = U1, CStride = U5> = + Matrix>; + +/// A column-major 6x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x1)] +pub type MatrixSlice6x1<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x2)] +pub type MatrixSlice6x2<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x3)] +pub type MatrixSlice6x3<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x4)] +pub type MatrixSlice6x4<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixView6x5)] +pub type MatrixSlice6x5<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A column-major matrix slice with 1 row and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView1xX)] +pub type MatrixSlice1xX<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major matrix slice with 2 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView2xX)] +pub type MatrixSlice2xX<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major matrix slice with 3 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView3xX)] +pub type MatrixSlice3xX<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major matrix slice with 4 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView4xX)] +pub type MatrixSlice4xX<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major matrix slice with 5 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView5xX)] +pub type MatrixSlice5xX<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major matrix slice with 6 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixView6xX)] +pub type MatrixSlice6xX<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A column-major matrix slice with a number of rows chosen at runtime and 1 column. +#[deprecated = slice_deprecation_note!(MatrixViewXx1)] +pub type MatrixSliceXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 2 columns. +#[deprecated = slice_deprecation_note!(MatrixViewXx2)] +pub type MatrixSliceXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 3 columns. +#[deprecated = slice_deprecation_note!(MatrixViewXx3)] +pub type MatrixSliceXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 4 columns. +#[deprecated = slice_deprecation_note!(MatrixViewXx4)] +pub type MatrixSliceXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 5 columns. +#[deprecated = slice_deprecation_note!(MatrixViewXx5)] +pub type MatrixSliceXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 6 columns. +#[deprecated = slice_deprecation_note!(MatrixViewXx6)] +pub type MatrixSliceXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A column vector slice with dimensions known at compile-time. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView)] +pub type VectorSlice<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// A column vector slice with dimensions known at compile-time. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SVectorView)] +pub type SVectorSlice<'a, T, const D: usize> = + Matrix, Const<1>, ViewStorage<'a, T, Const, Const<1>, Const<1>, Const>>; + +/// A column vector slice dynamic numbers of rows and columns. +#[deprecated = slice_deprecation_note!(DVectorView)] +pub type DVectorSlice<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A 1D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView1)] +pub type VectorSlice1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A 2D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView2)] +pub type VectorSlice2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A 3D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView3)] +pub type VectorSlice3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A 4D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView4)] +pub type VectorSlice4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A 5D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView5)] +pub type VectorSlice5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A 6D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorView6)] +pub type VectorSlice6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/* + * + * + * Same thing, but for mutable slices. + * + * + */ +/// A column-major matrix slice with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = "Use MatrixViewMut instead, which has an identical definition."] +pub type MatrixSliceMutMN<'a, T, R, C, RStride = U1, CStride = R> = + Matrix>; + +/// A column-major matrix slice with `D` rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = "Use MatrixViewMut instead."] +pub type MatrixSliceMutN<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// A column-major matrix slice with dimensions known at compile-time. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SMatrixViewMut)] +pub type SMatrixSliceMut<'a, T, const R: usize, const C: usize> = + Matrix, Const, ViewStorageMut<'a, T, Const, Const, Const<1>, Const>>; + +/// A column-major matrix slice dynamic numbers of rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(DMatrixViewMut)] +pub type DMatrixSliceMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A column-major 1x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1)] +pub type MatrixSliceMut1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 2x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2)] +pub type MatrixSliceMut2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 3x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3)] +pub type MatrixSliceMut3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 4x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4)] +pub type MatrixSliceMut4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 5x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5)] +pub type MatrixSliceMut5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 6x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6)] +pub type MatrixSliceMut6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A column-major 1x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x2)] +pub type MatrixSliceMut1x2<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x3)] +pub type MatrixSliceMut1x3<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x4)] +pub type MatrixSliceMut1x4<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x5)] +pub type MatrixSliceMut1x5<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major 1x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut1x6)] +pub type MatrixSliceMut1x6<'a, T, RStride = U1, CStride = U1> = + Matrix>; + +/// A column-major 2x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x1)] +pub type MatrixSliceMut2x1<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x3)] +pub type MatrixSliceMut2x3<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x4)] +pub type MatrixSliceMut2x4<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x5)] +pub type MatrixSliceMut2x5<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major 2x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut2x6)] +pub type MatrixSliceMut2x6<'a, T, RStride = U1, CStride = U2> = + Matrix>; + +/// A column-major 3x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x1)] +pub type MatrixSliceMut3x1<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x2)] +pub type MatrixSliceMut3x2<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x4)] +pub type MatrixSliceMut3x4<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x5)] +pub type MatrixSliceMut3x5<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major 3x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut3x6)] +pub type MatrixSliceMut3x6<'a, T, RStride = U1, CStride = U3> = + Matrix>; + +/// A column-major 4x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x1)] +pub type MatrixSliceMut4x1<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x2)] +pub type MatrixSliceMut4x2<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x3)] +pub type MatrixSliceMut4x3<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x5)] +pub type MatrixSliceMut4x5<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major 4x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut4x6)] +pub type MatrixSliceMut4x6<'a, T, RStride = U1, CStride = U4> = + Matrix>; + +/// A column-major 5x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x1)] +pub type MatrixSliceMut5x1<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x2)] +pub type MatrixSliceMut5x2<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x3)] +pub type MatrixSliceMut5x3<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x4)] +pub type MatrixSliceMut5x4<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major 5x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut5x6)] +pub type MatrixSliceMut5x6<'a, T, RStride = U1, CStride = U5> = + Matrix>; + +/// A column-major 6x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x1)] +pub type MatrixSliceMut6x1<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x2)] +pub type MatrixSliceMut6x2<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x3)] +pub type MatrixSliceMut6x3<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x4)] +pub type MatrixSliceMut6x4<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A column-major 6x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(MatrixViewMut6x5)] +pub type MatrixSliceMut6x5<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A column-major matrix slice with 1 row and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut1xX)] +pub type MatrixSliceMut1xX<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A column-major matrix slice with 2 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut2xX)] +pub type MatrixSliceMut2xX<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A column-major matrix slice with 3 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut3xX)] +pub type MatrixSliceMut3xX<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A column-major matrix slice with 4 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut4xX)] +pub type MatrixSliceMut4xX<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A column-major matrix slice with 5 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut5xX)] +pub type MatrixSliceMut5xX<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A column-major matrix slice with 6 rows and a number of columns chosen at runtime. +#[deprecated = slice_deprecation_note!(MatrixViewMut6xX)] +pub type MatrixSliceMut6xX<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A column-major matrix slice with a number of rows chosen at runtime and 1 column. +#[deprecated = slice_deprecation_note!(MatrixViewMutXx1)] +pub type MatrixSliceMutXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 2 columns. +#[deprecated = slice_deprecation_note!(MatrixViewMutXx2)] +pub type MatrixSliceMutXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 3 columns. +#[deprecated = slice_deprecation_note!(MatrixViewMutXx3)] +pub type MatrixSliceMutXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 4 columns. +#[deprecated = slice_deprecation_note!(MatrixViewMutXx4)] +pub type MatrixSliceMutXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 5 columns. +#[deprecated = slice_deprecation_note!(MatrixViewMutXx5)] +pub type MatrixSliceMutXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A column-major matrix slice with a number of rows chosen at runtime and 6 columns. +#[deprecated = slice_deprecation_note!(MatrixViewMutXx6)] +pub type MatrixSliceMutXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A column vector slice with dimensions known at compile-time. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut)] +pub type VectorSliceMut<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// A column vector slice with dimensions known at compile-time. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(SVectorViewMut)] +pub type SVectorSliceMut<'a, T, const D: usize> = + Matrix, Const<1>, ViewStorageMut<'a, T, Const, Const<1>, Const<1>, Const>>; + +/// A column vector slice dynamic numbers of rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(DVectorViewMut)] +pub type DVectorSliceMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A 1D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut1)] +pub type VectorSliceMut1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A 2D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut2)] +pub type VectorSliceMut2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A 3D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut3)] +pub type VectorSliceMut3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A 4D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut4)] +pub type VectorSliceMut4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A 5D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut5)] +pub type VectorSliceMut5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A 6D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +#[deprecated = slice_deprecation_note!(VectorViewMut6)] +pub type VectorSliceMut6<'a, T, RStride = U1, CStride = U6> = + Matrix>; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_view.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_view.rs new file mode 100644 index 000000000..c769e0987 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/alias_view.rs @@ -0,0 +1,875 @@ +use crate::base::dimension::{Dyn, U1, U2, U3, U4, U5, U6}; +use crate::base::matrix_view::{ViewStorage, ViewStorageMut}; +use crate::base::{Const, Matrix}; + +/* + * + * + * Matrix view aliases. + * + * + */ +// NOTE: we can't provide defaults for the strides because it's not supported yet by min_const_generics. +/// An immutable column-major matrix view with dimensions known at compile-time. +/// +/// See [`SMatrixViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SMatrixView<'a, T, const R: usize, const C: usize> = + Matrix, Const, ViewStorage<'a, T, Const, Const, Const<1>, Const>>; + +/// An immutable column-major matrix view dynamic numbers of rows and columns. +/// +/// See [`DMatrixViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DMatrixView<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// An immutable column-major 1x1 matrix view. +/// +/// See [`MatrixViewMut1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 2x2 matrix view. +/// +/// See [`MatrixViewMut2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 3x3 matrix view. +/// +/// See [`MatrixViewMut3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 4x4 matrix view. +/// +/// See [`MatrixViewMut4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 5x5 matrix view. +/// +/// See [`MatrixViewMut5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 6x6 matrix view. +/// +/// See [`MatrixViewMut6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// An immutable column-major 1x2 matrix view. +/// +/// See [`MatrixViewMut1x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x2<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x3 matrix view. +/// +/// See [`MatrixViewMut1x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x3<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x4 matrix view. +/// +/// See [`MatrixViewMut1x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x4<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x5 matrix view. +/// +/// See [`MatrixViewMut1x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x5<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major 1x6 matrix view. +/// +/// See [`MatrixViewMut1x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1x6<'a, T, RStride = U1, CStride = U1> = + Matrix>; + +/// An immutable column-major 2x1 matrix view. +/// +/// See [`MatrixViewMut2x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x1<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x3 matrix view. +/// +/// See [`MatrixViewMut2x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x3<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x4 matrix view. +/// +/// See [`MatrixViewMut2x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x4<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x5 matrix view. +/// +/// See [`MatrixViewMut2x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x5<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major 2x6 matrix view. +/// +/// See [`MatrixViewMut2x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2x6<'a, T, RStride = U1, CStride = U2> = + Matrix>; + +/// An immutable column-major 3x1 matrix view. +/// +/// See [`MatrixViewMut3x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x1<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x2 matrix view. +/// +/// See [`MatrixViewMut3x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x2<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x4 matrix view. +/// +/// See [`MatrixViewMut3x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x4<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x5 matrix view. +/// +/// See [`MatrixViewMut3x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x5<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major 3x6 matrix view. +/// +/// See [`MatrixViewMut3x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3x6<'a, T, RStride = U1, CStride = U3> = + Matrix>; + +/// An immutable column-major 4x1 matrix view. +/// +/// See [`MatrixViewMut4x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x1<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x2 matrix view. +/// +/// See [`MatrixViewMut4x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x2<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x3 matrix view. +/// +/// See [`MatrixViewMut4x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x3<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x5 matrix view. +/// +/// See [`MatrixViewMut4x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x5<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major 4x6 matrix view. +/// +/// See [`MatrixViewMut4x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4x6<'a, T, RStride = U1, CStride = U4> = + Matrix>; + +/// An immutable column-major 5x1 matrix view. +/// +/// See [`MatrixViewMut5x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x1<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x2 matrix view. +/// +/// See [`MatrixViewMut5x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x2<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x3 matrix view. +/// +/// See [`MatrixViewMut5x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x3<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x4 matrix view. +/// +/// See [`MatrixViewMut5x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x4<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major 5x6 matrix view. +/// +/// See [`MatrixViewMut5x6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5x6<'a, T, RStride = U1, CStride = U5> = + Matrix>; + +/// An immutable column-major 6x1 matrix view. +/// +/// See [`MatrixViewMut6x1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x1<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x2 matrix view. +/// +/// See [`MatrixViewMut6x2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x2<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x3 matrix view. +/// +/// See [`MatrixViewMut6x3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x3<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x4 matrix view. +/// +/// See [`MatrixViewMut6x4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x4<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// An immutable column-major 6x5 matrix view. +/// +/// See [`MatrixViewMut6x5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6x5<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// An immutable column-major matrix view with 1 row and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut1xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView1xX<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable column-major matrix view with 2 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut2xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView2xX<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable column-major matrix view with 3 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut3xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView3xX<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable column-major matrix view with 4 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut4xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView4xX<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable column-major matrix view with 5 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut5xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView5xX<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable column-major matrix view with 6 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixViewMut6xX`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixView6xX<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// An immutable column-major matrix view with a number of rows chosen at runtime and 1 column. +/// +/// See [`MatrixViewMutXx1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 2 columns. +/// +/// See [`MatrixViewMutXx2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 3 columns. +/// +/// See [`MatrixViewMutXx3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 4 columns. +/// +/// See [`MatrixViewMutXx4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 5 columns. +/// +/// See [`MatrixViewMutXx5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// An immutable column-major matrix view with a number of rows chosen at runtime and 6 columns. +/// +/// See [`MatrixViewMutXx6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// An immutable column vector view with dimensions known at compile-time. +/// +/// See [`VectorViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// An immutable column vector view with dimensions known at compile-time. +/// +/// See [`SVectorViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SVectorView<'a, T, const D: usize> = + Matrix, Const<1>, ViewStorage<'a, T, Const, Const<1>, Const<1>, Const>>; + +/// An immutable column vector view dynamic numbers of rows and columns. +/// +/// See [`DVectorViewMut`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DVectorView<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// An immutable 1D column vector view. +/// +/// See [`VectorViewMut1`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// An immutable 2D column vector view. +/// +/// See [`VectorViewMut2`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// An immutable 3D column vector view. +/// +/// See [`VectorViewMut3`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// An immutable 4D column vector view. +/// +/// See [`VectorViewMut4`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// An immutable 5D column vector view. +/// +/// See [`VectorViewMut5`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// An immutable 6D column vector view. +/// +/// See [`VectorViewMut6`] for a mutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorView6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/* + * + * + * Same thing, but for mutable views. + * + * + */ + +/// A mutable column-major matrix view with dimensions known at compile-time. +/// +/// See [`SMatrixView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SMatrixViewMut<'a, T, const R: usize, const C: usize> = + Matrix, Const, ViewStorageMut<'a, T, Const, Const, Const<1>, Const>>; + +/// A mutable column-major matrix view dynamic numbers of rows and columns. +/// +/// See [`DMatrixView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DMatrixViewMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A mutable column-major 1x1 matrix view. +/// +/// See [`MatrixView1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 2x2 matrix view. +/// +/// See [`MatrixView2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 3x3 matrix view. +/// +/// See [`MatrixView3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 4x4 matrix view. +/// +/// See [`MatrixView4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 5x5 matrix view. +/// +/// See [`MatrixView5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 6x6 matrix view. +/// +/// See [`MatrixView6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A mutable column-major 1x2 matrix view. +/// +/// See [`MatrixView1x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x2<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x3 matrix view. +/// +/// See [`MatrixView1x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x3<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x4 matrix view. +/// +/// See [`MatrixView1x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x4<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x5 matrix view. +/// +/// See [`MatrixView1x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x5<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major 1x6 matrix view. +/// +/// See [`MatrixView1x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1x6<'a, T, RStride = U1, CStride = U1> = + Matrix>; + +/// A mutable column-major 2x1 matrix view. +/// +/// See [`MatrixView2x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x1<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x3 matrix view. +/// +/// See [`MatrixView2x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x3<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x4 matrix view. +/// +/// See [`MatrixView2x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x4<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x5 matrix view. +/// +/// See [`MatrixView2x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x5<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major 2x6 matrix view. +/// +/// See [`MatrixView2x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2x6<'a, T, RStride = U1, CStride = U2> = + Matrix>; + +/// A mutable column-major 3x1 matrix view. +/// +/// See [`MatrixView3x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x1<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x2 matrix view. +/// +/// See [`MatrixView3x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x2<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x4 matrix view. +/// +/// See [`MatrixView3x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x4<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x5 matrix view. +/// +/// See [`MatrixView3x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x5<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major 3x6 matrix view. +/// +/// See [`MatrixView3x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3x6<'a, T, RStride = U1, CStride = U3> = + Matrix>; + +/// A mutable column-major 4x1 matrix view. +/// +/// See [`MatrixView4x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x1<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x2 matrix view. +/// +/// See [`MatrixView4x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x2<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x3 matrix view. +/// +/// See [`MatrixView4x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x3<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x5 matrix view. +/// +/// See [`MatrixView4x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x5<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major 4x6 matrix view. +/// +/// See [`MatrixView4x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4x6<'a, T, RStride = U1, CStride = U4> = + Matrix>; + +/// A mutable column-major 5x1 matrix view. +/// +/// See [`MatrixView5x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x1<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x2 matrix view. +/// +/// See [`MatrixView5x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x2<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x3 matrix view. +/// +/// See [`MatrixView5x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x3<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x4 matrix view. +/// +/// See [`MatrixView5x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x4<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major 5x6 matrix view. +/// +/// See [`MatrixView5x6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5x6<'a, T, RStride = U1, CStride = U5> = + Matrix>; + +/// A mutable column-major 6x1 matrix view. +/// +/// See [`MatrixView6x1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x1<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x2 matrix view. +/// +/// See [`MatrixView6x2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x2<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x3 matrix view. +/// +/// See [`MatrixView6x3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x3<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x4 matrix view. +/// +/// See [`MatrixView6x4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x4<'a, T, RStride = U1, CStride = U6> = + Matrix>; +/// A mutable column-major 6x5 matrix view. +/// +/// See [`MatrixView6x5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6x5<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A mutable column-major matrix view with 1 row and a number of columns chosen at runtime. +/// +/// See [`MatrixView1xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut1xX<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable column-major matrix view with 2 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView2xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut2xX<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable column-major matrix view with 3 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView3xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut3xX<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable column-major matrix view with 4 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView4xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut4xX<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable column-major matrix view with 5 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView5xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut5xX<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable column-major matrix view with 6 rows and a number of columns chosen at runtime. +/// +/// See [`MatrixView6xX`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMut6xX<'a, T, RStride = U1, CStride = U6> = + Matrix>; + +/// A mutable column-major matrix view with a number of rows chosen at runtime and 1 column. +/// +/// See [`MatrixViewXx1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx1<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 2 columns. +/// +/// See [`MatrixViewXx2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx2<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 3 columns. +/// +/// See [`MatrixViewXx3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx3<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 4 columns. +/// +/// See [`MatrixViewXx4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx4<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 5 columns. +/// +/// See [`MatrixViewXx5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx5<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; +/// A mutable column-major matrix view with a number of rows chosen at runtime and 6 columns. +/// +/// See [`MatrixViewXx6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type MatrixViewMutXx6<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A mutable column vector view with dimensions known at compile-time. +/// +/// See [`VectorView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut<'a, T, D, RStride = U1, CStride = D> = + Matrix>; + +/// A mutable column vector view with dimensions known at compile-time. +/// +/// See [`SVectorView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type SVectorViewMut<'a, T, const D: usize> = + Matrix, Const<1>, ViewStorageMut<'a, T, Const, Const<1>, Const<1>, Const>>; + +/// A mutable column vector view dynamic numbers of rows and columns. +/// +/// See [`DVectorView`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type DVectorViewMut<'a, T, RStride = U1, CStride = Dyn> = + Matrix>; + +/// A mutable 1D column vector view. +/// +/// See [`VectorView1`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut1<'a, T, RStride = U1, CStride = U1> = + Matrix>; +/// A mutable 2D column vector view. +/// +/// See [`VectorView2`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut2<'a, T, RStride = U1, CStride = U2> = + Matrix>; +/// A mutable 3D column vector view. +/// +/// See [`VectorView3`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut3<'a, T, RStride = U1, CStride = U3> = + Matrix>; +/// A mutable 4D column vector view. +/// +/// See [`VectorView4`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut4<'a, T, RStride = U1, CStride = U4> = + Matrix>; +/// A mutable 5D column vector view. +/// +/// See [`VectorView5`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut5<'a, T, RStride = U1, CStride = U5> = + Matrix>; +/// A mutable 6D column vector view. +/// +/// See [`VectorView6`] for an immutable version of this type. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** +pub type VectorViewMut6<'a, T, RStride = U1, CStride = U6> = + Matrix>; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/allocator.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/allocator.rs new file mode 100644 index 000000000..9ad3c1c1f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/allocator.rs @@ -0,0 +1,149 @@ +//! Abstract definition of a matrix data storage allocator. + +use std::any::Any; + +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{Dim, U1}; +use crate::base::{DefaultAllocator, Scalar}; +use crate::storage::{IsContiguous, RawStorageMut}; +use crate::StorageMut; +use std::fmt::Debug; +use std::mem::MaybeUninit; + +/// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()` +/// elements of type `T`. +/// +/// An allocator is said to be: +/// − static: if `R` and `C` both implement `DimName`. +/// − dynamic: if either one (or both) of `R` or `C` is equal to `Dyn`. +/// +/// Every allocator must be both static and dynamic. Though not all implementations may share the +/// same `Buffer` type. +pub trait Allocator: Any + Sized { + /// The type of buffer this allocator can instantiate. + type Buffer: StorageMut + IsContiguous + Clone + Debug; + /// The type of buffer with uninitialized components this allocator can instantiate. + type BufferUninit: RawStorageMut, R, C> + IsContiguous; + + /// Allocates a buffer with the given number of rows and columns without initializing its content. + fn allocate_uninit(nrows: R, ncols: C) -> Self::BufferUninit; + + /// Assumes a data buffer to be initialized. + /// + /// # Safety + /// The user must make sure that every single entry of the buffer has been initialized, + /// or Undefined Behavior will immediately occur. + unsafe fn assume_init(uninit: Self::BufferUninit) -> Self::Buffer; + + /// Allocates a buffer initialized with the content of the given iterator. + fn allocate_from_iterator>( + nrows: R, + ncols: C, + iter: I, + ) -> Self::Buffer; + + #[inline] + /// Allocates a buffer initialized with the content of the given row-major order iterator. + fn allocate_from_row_iterator>( + nrows: R, + ncols: C, + iter: I, + ) -> Self::Buffer { + let mut res = Self::allocate_uninit(nrows, ncols); + let mut count = 0; + + unsafe { + // OK because the allocated buffer is guaranteed to be contiguous. + let res_ptr = res.as_mut_slice_unchecked(); + + for (k, e) in iter + .into_iter() + .take(ncols.value() * nrows.value()) + .enumerate() + { + let i = k / ncols.value(); + let j = k % ncols.value(); + // result[(i, j)] = e; + *res_ptr.get_unchecked_mut(i + j * nrows.value()) = MaybeUninit::new(e); + count += 1; + } + + assert!( + count == nrows.value() * ncols.value(), + "Matrix init. from row iterator: iterator not long enough." + ); + + >::assume_init(res) + } + } +} + +/// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` × +/// `CFrom`) elements to a smaller or larger size (`RTo`, `CTo`). +pub trait Reallocator: + Allocator + Allocator +{ + /// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer + /// `buf`. Data stored by `buf` are linearly copied to the output: + /// + /// # Safety + /// The following invariants must be respected by the implementors of this method: + /// * The copy is performed as if both were just arrays (without taking into account the matrix structure). + /// * If the underlying buffer is being shrunk, the removed elements must **not** be dropped + /// by this method. Dropping them is the responsibility of the caller. + unsafe fn reallocate_copy( + nrows: RTo, + ncols: CTo, + buf: >::Buffer, + ) -> >::BufferUninit; +} + +/// The number of rows of the result of a componentwise operation on two matrices. +pub type SameShapeR = >::Representative; + +/// The number of columns of the result of a componentwise operation on two matrices. +pub type SameShapeC = >::Representative; + +// TODO: Bad name. +/// Restricts the given number of rows and columns to be respectively the same. +pub trait SameShapeAllocator: + Allocator + Allocator, SameShapeC> +where + R1: Dim, + R2: Dim, + C1: Dim, + C2: Dim, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, +{ +} + +impl SameShapeAllocator for DefaultAllocator +where + R1: Dim, + R2: Dim, + C1: Dim, + C2: Dim, + DefaultAllocator: Allocator + Allocator, SameShapeC>, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, +{ +} + +// XXX: Bad name. +/// Restricts the given number of rows to be equal. +pub trait SameShapeVectorAllocator: + Allocator + Allocator> + SameShapeAllocator +where + R1: Dim, + R2: Dim, + ShapeConstraint: SameNumberOfRows, +{ +} + +impl SameShapeVectorAllocator for DefaultAllocator +where + R1: Dim, + R2: Dim, + DefaultAllocator: Allocator + Allocator>, + ShapeConstraint: SameNumberOfRows, +{ +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/array_storage.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/array_storage.rs new file mode 100644 index 000000000..c261ade04 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/array_storage.rs @@ -0,0 +1,295 @@ +use std::fmt::{self, Debug, Formatter}; +// use std::hash::{Hash, Hasher}; +use std::ops::Mul; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::de::{Error, SeqAccess, Visitor}; +#[cfg(feature = "serde-serialize-no-std")] +use serde::ser::SerializeTuple; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "serde-serialize-no-std")] +use std::marker::PhantomData; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Const, ToTypenum}; +use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage}; +use crate::base::Scalar; +use crate::Storage; +use std::mem; + +/* + * + * Static RawStorage. + * + */ +/// An array-based statically sized matrix data storage. +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "ArrayStorage", + bound(archive = " + T: rkyv::Archive, + [[T; R]; C]: rkyv::Archive + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +pub struct ArrayStorage(pub [[T; R]; C]); + +impl ArrayStorage { + /// Converts this array storage to a slice. + #[inline] + pub fn as_slice(&self) -> &[T] { + // SAFETY: this is OK because ArrayStorage is contiguous. + unsafe { self.as_slice_unchecked() } + } + + /// Converts this array storage to a mutable slice. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: this is OK because ArrayStorage is contiguous. + unsafe { self.as_mut_slice_unchecked() } + } +} + +// TODO: remove this once the stdlib implements Default for arrays. +impl Default for ArrayStorage +where + [[T; R]; C]: Default, +{ + #[inline] + fn default() -> Self { + Self(Default::default()) + } +} + +impl Debug for ArrayStorage { + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + +unsafe impl RawStorage, Const> + for ArrayStorage +{ + type RStride = Const<1>; + type CStride = Const; + + #[inline] + fn ptr(&self) -> *const T { + self.0.as_ptr() as *const T + } + + #[inline] + fn shape(&self) -> (Const, Const) { + (Const, Const) + } + + #[inline] + fn strides(&self) -> (Self::RStride, Self::CStride) { + (Const, Const) + } + + #[inline] + fn is_contiguous(&self) -> bool { + true + } + + #[inline] + unsafe fn as_slice_unchecked(&self) -> &[T] { + std::slice::from_raw_parts(self.ptr(), R * C) + } +} + +unsafe impl Storage, Const> + for ArrayStorage +where + DefaultAllocator: Allocator, Const, Buffer = Self>, +{ + #[inline] + fn into_owned(self) -> Owned, Const> + where + DefaultAllocator: Allocator, Const>, + { + self + } + + #[inline] + fn clone_owned(&self) -> Owned, Const> + where + DefaultAllocator: Allocator, Const>, + { + self.clone() + } + + #[inline] + fn forget_elements(self) { + // No additional cleanup required. + std::mem::forget(self); + } +} + +unsafe impl RawStorageMut, Const> + for ArrayStorage +{ + #[inline] + fn ptr_mut(&mut self) -> *mut T { + self.0.as_mut_ptr() as *mut T + } + + #[inline] + unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] { + std::slice::from_raw_parts_mut(self.ptr_mut(), R * C) + } +} + +unsafe impl IsContiguous for ArrayStorage {} + +impl + ReshapableStorage, Const, Const, Const> for ArrayStorage +where + T: Scalar, + Const: ToTypenum, + Const: ToTypenum, + Const: ToTypenum, + Const: ToTypenum, + as ToTypenum>::Typenum: Mul< as ToTypenum>::Typenum>, + as ToTypenum>::Typenum: Mul< + as ToTypenum>::Typenum, + Output = typenum::Prod< + as ToTypenum>::Typenum, + as ToTypenum>::Typenum, + >, + >, +{ + type Output = ArrayStorage; + + fn reshape_generic(self, _: Const, _: Const) -> Self::Output { + unsafe { + let data: [[T; R2]; C2] = mem::transmute_copy(&self.0); + mem::forget(self.0); + ArrayStorage(data) + } + } +} + +/* + * + * Serialization. + * + */ +// XXX: open an issue for serde so that it allows the serialization/deserialization of all arrays? +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for ArrayStorage +where + T: Scalar + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut serializer = serializer.serialize_tuple(R * C)?; + + for e in self.as_slice().iter() { + serializer.serialize_element(e)?; + } + + serializer.end() + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T, const R: usize, const C: usize> Deserialize<'a> for ArrayStorage +where + T: Scalar + Deserialize<'a>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + deserializer.deserialize_tuple(R * C, ArrayStorageVisitor::new()) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +/// A visitor that produces a matrix array. +struct ArrayStorageVisitor { + marker: PhantomData, +} + +#[cfg(feature = "serde-serialize-no-std")] +impl ArrayStorageVisitor +where + T: Scalar, +{ + /// Construct a new sequence visitor. + pub fn new() -> Self { + ArrayStorageVisitor { + marker: PhantomData, + } + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T, const R: usize, const C: usize> Visitor<'a> for ArrayStorageVisitor +where + T: Scalar + Deserialize<'a>, +{ + type Value = ArrayStorage; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + formatter.write_str("a matrix array") + } + + #[inline] + fn visit_seq(self, mut visitor: V) -> Result, V::Error> + where + V: SeqAccess<'a>, + { + let mut out: ArrayStorage, R, C> = + >::allocate_uninit(Const::, Const::); + let mut curr = 0; + + while let Some(value) = visitor.next_element()? { + *out.as_mut_slice() + .get_mut(curr) + .ok_or_else(|| V::Error::invalid_length(curr, &self))? = + core::mem::MaybeUninit::new(value); + curr += 1; + } + + if curr == R * C { + // Safety: all the elements have been initialized. + unsafe { Ok(, Const>>::assume_init(out)) } + } else { + for i in 0..curr { + // Safety: + // - We couldn’t initialize the whole storage. Drop the ones we initialized. + unsafe { std::ptr::drop_in_place(out.as_mut_slice()[i].as_mut_ptr()) }; + } + + Err(V::Error::invalid_length(curr, &self)) + } + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl + bytemuck::Zeroable for ArrayStorage +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod + for ArrayStorage +{ +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas.rs new file mode 100644 index 000000000..dc3fa0684 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas.rs @@ -0,0 +1,1205 @@ +use crate::{RawStorage, SimdComplexField}; +use num::{One, Zero}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; + +use crate::base::allocator::Allocator; +use crate::base::blas_uninit::{axcpy_uninit, gemm_uninit, gemv_uninit}; +use crate::base::constraint::{ + AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, +}; +use crate::base::dimension::{Const, Dim, Dyn, U1, U2, U3, U4}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::uninit::Init; +use crate::base::{ + DVectorView, DefaultAllocator, Matrix, Scalar, SquareMatrix, Vector, VectorView, +}; + +/// # Dot/scalar product +impl> Matrix +where + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, +{ + #[inline(always)] + fn dotx( + &self, + rhs: &Matrix, + conjugate: impl Fn(T) -> T, + ) -> T + where + SB: RawStorage, + ShapeConstraint: DimEq + DimEq, + { + assert!( + self.nrows() == rhs.nrows(), + "Dot product dimensions mismatch for shapes {:?} and {:?}: left rows != right rows.", + self.shape(), + rhs.shape(), + ); + + assert!( + self.ncols() == rhs.ncols(), + "Dot product dimensions mismatch for shapes {:?} and {:?}: left cols != right cols.", + self.shape(), + rhs.shape(), + ); + + // So we do some special cases for common fixed-size vectors of dimension lower than 8 + // because the `for` loop below won't be very efficient on those. + if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { + unsafe { + let a = conjugate(self.get_unchecked((0, 0)).clone()) + * rhs.get_unchecked((0, 0)).clone(); + let b = conjugate(self.get_unchecked((1, 0)).clone()) + * rhs.get_unchecked((1, 0)).clone(); + + return a + b; + } + } + if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { + unsafe { + let a = conjugate(self.get_unchecked((0, 0)).clone()) + * rhs.get_unchecked((0, 0)).clone(); + let b = conjugate(self.get_unchecked((1, 0)).clone()) + * rhs.get_unchecked((1, 0)).clone(); + let c = conjugate(self.get_unchecked((2, 0)).clone()) + * rhs.get_unchecked((2, 0)).clone(); + + return a + b + c; + } + } + if (R::is::() || R2::is::()) && (C::is::() || C2::is::()) { + unsafe { + let mut a = conjugate(self.get_unchecked((0, 0)).clone()) + * rhs.get_unchecked((0, 0)).clone(); + let mut b = conjugate(self.get_unchecked((1, 0)).clone()) + * rhs.get_unchecked((1, 0)).clone(); + let c = conjugate(self.get_unchecked((2, 0)).clone()) + * rhs.get_unchecked((2, 0)).clone(); + let d = conjugate(self.get_unchecked((3, 0)).clone()) + * rhs.get_unchecked((3, 0)).clone(); + + a += c; + b += d; + + return a + b; + } + } + + // All this is inspired from the "unrolled version" discussed in: + // https://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/ + // + // And this comment from bluss: + // https://users.rust-lang.org/t/how-to-zip-two-slices-efficiently/2048/12 + let mut res = T::zero(); + + // We have to define them outside of the loop (and not inside at first assignment) + // otherwise vectorization won't kick in for some reason. + let mut acc0; + let mut acc1; + let mut acc2; + let mut acc3; + let mut acc4; + let mut acc5; + let mut acc6; + let mut acc7; + + for j in 0..self.ncols() { + let mut i = 0; + + acc0 = T::zero(); + acc1 = T::zero(); + acc2 = T::zero(); + acc3 = T::zero(); + acc4 = T::zero(); + acc5 = T::zero(); + acc6 = T::zero(); + acc7 = T::zero(); + + while self.nrows() - i >= 8 { + acc0 += unsafe { + conjugate(self.get_unchecked((i, j)).clone()) + * rhs.get_unchecked((i, j)).clone() + }; + acc1 += unsafe { + conjugate(self.get_unchecked((i + 1, j)).clone()) + * rhs.get_unchecked((i + 1, j)).clone() + }; + acc2 += unsafe { + conjugate(self.get_unchecked((i + 2, j)).clone()) + * rhs.get_unchecked((i + 2, j)).clone() + }; + acc3 += unsafe { + conjugate(self.get_unchecked((i + 3, j)).clone()) + * rhs.get_unchecked((i + 3, j)).clone() + }; + acc4 += unsafe { + conjugate(self.get_unchecked((i + 4, j)).clone()) + * rhs.get_unchecked((i + 4, j)).clone() + }; + acc5 += unsafe { + conjugate(self.get_unchecked((i + 5, j)).clone()) + * rhs.get_unchecked((i + 5, j)).clone() + }; + acc6 += unsafe { + conjugate(self.get_unchecked((i + 6, j)).clone()) + * rhs.get_unchecked((i + 6, j)).clone() + }; + acc7 += unsafe { + conjugate(self.get_unchecked((i + 7, j)).clone()) + * rhs.get_unchecked((i + 7, j)).clone() + }; + i += 8; + } + + res += acc0 + acc4; + res += acc1 + acc5; + res += acc2 + acc6; + res += acc3 + acc7; + + for k in i..self.nrows() { + res += unsafe { + conjugate(self.get_unchecked((k, j)).clone()) + * rhs.get_unchecked((k, j)).clone() + } + } + } + + res + } + + /// The dot product between two vectors or matrices (seen as vectors). + /// + /// This is equal to `self.transpose() * rhs`. For the sesquilinear complex dot product, use + /// `self.dotc(rhs)`. + /// + /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix + /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Matrix2x3}; + /// let vec1 = Vector3::new(1.0, 2.0, 3.0); + /// let vec2 = Vector3::new(0.1, 0.2, 0.3); + /// assert_eq!(vec1.dot(&vec2), 1.4); + /// + /// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// let mat2 = Matrix2x3::new(0.1, 0.2, 0.3, + /// 0.4, 0.5, 0.6); + /// assert_eq!(mat1.dot(&mat2), 9.1); + /// ``` + /// + #[inline] + #[must_use] + pub fn dot(&self, rhs: &Matrix) -> T + where + SB: RawStorage, + ShapeConstraint: DimEq + DimEq, + { + self.dotx(rhs, |e| e) + } + + /// The conjugate-linear dot product between two vectors or matrices (seen as vectors). + /// + /// This is equal to `self.adjoint() * rhs`. + /// For real vectors, this is identical to `self.dot(&rhs)`. + /// Note that this is **not** the matrix multiplication as in, e.g., numpy. For matrix + /// multiplication, use one of: `.gemm`, `.mul_to`, `.mul`, the `*` operator. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector2, Complex}; + /// let vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.4, 0.3), Complex::new(0.2, 0.1)); + /// assert_eq!(vec1.dotc(&vec2), Complex::new(2.0, -1.0)); + /// + /// // Note that for complex vectors, we generally have: + /// // vec1.dotc(&vec2) != vec2.dot(&vec2) + /// assert_ne!(vec1.dotc(&vec2), vec1.dot(&vec2)); + /// ``` + #[inline] + #[must_use] + pub fn dotc(&self, rhs: &Matrix) -> T + where + T: SimdComplexField, + SB: RawStorage, + ShapeConstraint: DimEq + DimEq, + { + self.dotx(rhs, T::simd_conjugate) + } + + /// The dot product between the transpose of `self` and `rhs`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector3, RowVector3, Matrix2x3, Matrix3x2}; + /// let vec1 = Vector3::new(1.0, 2.0, 3.0); + /// let vec2 = RowVector3::new(0.1, 0.2, 0.3); + /// assert_eq!(vec1.tr_dot(&vec2), 1.4); + /// + /// let mat1 = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// let mat2 = Matrix3x2::new(0.1, 0.4, + /// 0.2, 0.5, + /// 0.3, 0.6); + /// assert_eq!(mat1.tr_dot(&mat2), 9.1); + /// ``` + #[inline] + #[must_use] + pub fn tr_dot(&self, rhs: &Matrix) -> T + where + SB: RawStorage, + ShapeConstraint: DimEq + DimEq, + { + let (nrows, ncols) = self.shape(); + assert_eq!( + (ncols, nrows), + rhs.shape(), + "Transposed dot product dimension mismatch." + ); + + let mut res = T::zero(); + + for j in 0..self.nrows() { + for i in 0..self.ncols() { + res += unsafe { + self.get_unchecked((j, i)).clone() * rhs.get_unchecked((i, j)).clone() + } + } + } + + res + } +} + +/// # BLAS functions +impl Vector +where + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, + S: StorageMut, +{ + /// Computes `self = a * x * c + b * self`. + /// + /// If `b` is zero, `self` is never read from. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let mut vec1 = Vector3::new(1.0, 2.0, 3.0); + /// let vec2 = Vector3::new(0.1, 0.2, 0.3); + /// vec1.axcpy(5.0, &vec2, 2.0, 5.0); + /// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0)); + /// ``` + #[inline] + #[allow(clippy::many_single_char_names)] + pub fn axcpy(&mut self, a: T, x: &Vector, c: T, b: T) + where + SB: Storage, + ShapeConstraint: DimEq, + { + unsafe { axcpy_uninit(Init, self, a, x, c, b) }; + } + + /// Computes `self = a * x + b * self`. + /// + /// If `b` is zero, `self` is never read from. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let mut vec1 = Vector3::new(1.0, 2.0, 3.0); + /// let vec2 = Vector3::new(0.1, 0.2, 0.3); + /// vec1.axpy(10.0, &vec2, 5.0); + /// assert_eq!(vec1, Vector3::new(6.0, 12.0, 18.0)); + /// ``` + #[inline] + pub fn axpy(&mut self, a: T, x: &Vector, b: T) + where + T: One, + SB: Storage, + ShapeConstraint: DimEq, + { + assert_eq!(self.nrows(), x.nrows(), "Axpy: mismatched vector shapes."); + self.axcpy(a, x, T::one(), b) + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is a matrix, `x` a vector, and + /// `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mut vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// let mat = Matrix2::new(1.0, 2.0, + /// 3.0, 4.0); + /// vec1.gemv(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, Vector2::new(10.0, 21.0)); + /// ``` + #[inline] + pub fn gemv( + &mut self, + alpha: T, + a: &Matrix, + x: &Vector, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + // Safety: this is safe because we are passing Status == Init. + unsafe { gemv_uninit(Init, self, alpha, a, x, beta) } + } + + #[inline(always)] + fn xxgemv( + &mut self, + alpha: T, + a: &SquareMatrix, + x: &Vector, + beta: T, + dot: impl Fn( + &DVectorView<'_, T, SB::RStride, SB::CStride>, + &DVectorView<'_, T, SC::RStride, SC::CStride>, + ) -> T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + let dim1 = self.nrows(); + let dim2 = a.nrows(); + let dim3 = x.nrows(); + + assert!( + a.is_square(), + "Symmetric cgemv: the input matrix must be square." + ); + assert!( + dim2 == dim3 && dim1 == dim2, + "Symmetric cgemv: dimensions mismatch." + ); + + if dim2 == 0 { + return; + } + + // TODO: avoid bound checks. + let col2 = a.column(0); + let val = unsafe { x.vget_unchecked(0).clone() }; + self.axpy(alpha.clone() * val, &col2, beta); + self[0] += alpha.clone() * dot(&a.view_range(1.., 0), &x.rows_range(1..)); + + for j in 1..dim2 { + let col2 = a.column(j); + let dot = dot(&col2.rows_range(j..), &x.rows_range(j..)); + + let val; + unsafe { + val = x.vget_unchecked(j).clone(); + *self.vget_unchecked_mut(j) += alpha.clone() * dot; + } + self.rows_range_mut(j + 1..).axpy( + alpha.clone() * val, + &col2.rows_range(j + 1..), + T::one(), + ); + } + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is a **symmetric** matrix, `x` a + /// vector, and `alpha, beta` two scalars. + /// + /// For hermitian matrices, use `.hegemv` instead. + /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part + /// (including the diagonal) is actually read. + /// + /// # Examples + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mat = Matrix2::new(1.0, 2.0, + /// 2.0, 4.0); + /// let mut vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// vec1.sygemv(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); + /// + /// + /// // The matrix upper-triangular elements can be garbage because it is never + /// // read by this method. Therefore, it is not necessary for the caller to + /// // fill the matrix struct upper-triangle. + /// let mat = Matrix2::new(1.0, 9999999.9999999, + /// 2.0, 4.0); + /// let mut vec1 = Vector2::new(1.0, 2.0); + /// vec1.sygemv(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, Vector2::new(10.0, 20.0)); + /// ``` + #[inline] + pub fn sygemv( + &mut self, + alpha: T, + a: &SquareMatrix, + x: &Vector, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.xxgemv(alpha, a, x, beta, |a, b| a.dot(b)) + } + + /// Computes `self = alpha * a * x + beta * self`, where `a` is an **hermitian** matrix, `x` a + /// vector, and `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. If `self` is read, only its lower-triangular part + /// (including the diagonal) is actually read. + /// + /// # Examples + /// ``` + /// # use nalgebra::{Matrix2, Vector2, Complex}; + /// let mat = Matrix2::new(Complex::new(1.0, 0.0), Complex::new(2.0, -0.1), + /// Complex::new(2.0, 1.0), Complex::new(4.0, 0.0)); + /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); + /// vec1.sygemv(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(vec1, Vector2::new(Complex::new(-48.0, 44.0), Complex::new(-75.0, 110.0))); + /// + /// + /// // The matrix upper-triangular elements can be garbage because it is never + /// // read by this method. Therefore, it is not necessary for the caller to + /// // fill the matrix struct upper-triangle. + /// + /// let mat = Matrix2::new(Complex::new(1.0, 0.0), Complex::new(99999999.9, 999999999.9), + /// Complex::new(2.0, 1.0), Complex::new(4.0, 0.0)); + /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); + /// vec1.sygemv(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(vec1, Vector2::new(Complex::new(-48.0, 44.0), Complex::new(-75.0, 110.0))); + /// ``` + #[inline] + pub fn hegemv( + &mut self, + alpha: T, + a: &SquareMatrix, + x: &Vector, + beta: T, + ) where + T: SimdComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.xxgemv(alpha, a, x, beta, |a, b| a.dotc(b)) + } + + #[inline(always)] + fn gemv_xx( + &mut self, + alpha: T, + a: &Matrix, + x: &Vector, + beta: T, + dot: impl Fn(&VectorView<'_, T, R2, SB::RStride, SB::CStride>, &Vector) -> T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + let dim1 = self.nrows(); + let (nrows2, ncols2) = a.shape(); + let dim3 = x.nrows(); + + assert!( + nrows2 == dim3 && dim1 == ncols2, + "Gemv: dimensions mismatch." + ); + + if ncols2 == 0 { + return; + } + + if beta.is_zero() { + for j in 0..ncols2 { + let val = unsafe { self.vget_unchecked_mut(j) }; + *val = alpha.clone() * dot(&a.column(j), x) + } + } else { + for j in 0..ncols2 { + let val = unsafe { self.vget_unchecked_mut(j) }; + *val = alpha.clone() * dot(&a.column(j), x) + beta.clone() * val.clone(); + } + } + } + + /// Computes `self = alpha * a.transpose() * x + beta * self`, where `a` is a matrix, `x` a vector, and + /// `alpha, beta` two scalars. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mat = Matrix2::new(1.0, 3.0, + /// 2.0, 4.0); + /// let mut vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// let expected = mat.transpose() * vec2 * 10.0 + vec1 * 5.0; + /// + /// vec1.gemv_tr(10.0, &mat, &vec2, 5.0); + /// assert_eq!(vec1, expected); + /// ``` + #[inline] + pub fn gemv_tr( + &mut self, + alpha: T, + a: &Matrix, + x: &Vector, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.gemv_xx(alpha, a, x, beta, |a, b| a.dot(b)) + } + + /// Computes `self = alpha * a.adjoint() * x + beta * self`, where `a` is a matrix, `x` a vector, and + /// `alpha, beta` two scalars. + /// + /// For real matrices, this is the same as `.gemv_tr`. + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2, Vector2, Complex}; + /// let mat = Matrix2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0), + /// Complex::new(5.0, 6.0), Complex::new(7.0, 8.0)); + /// let mut vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.1, 0.2), Complex::new(0.3, 0.4)); + /// let expected = mat.adjoint() * vec2 * Complex::new(10.0, 20.0) + vec1 * Complex::new(5.0, 15.0); + /// + /// vec1.gemv_ad(Complex::new(10.0, 20.0), &mat, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(vec1, expected); + /// ``` + #[inline] + pub fn gemv_ad( + &mut self, + alpha: T, + a: &Matrix, + x: &Vector, + beta: T, + ) where + T: SimdComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + AreMultipliable, + { + self.gemv_xx(alpha, a, x, beta, |a, b| a.dotc(b)) + } +} + +impl> Matrix +where + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, +{ + #[inline(always)] + fn gerx( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + conjugate: impl Fn(T) -> T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + let (nrows1, ncols1) = self.shape(); + let dim2 = x.nrows(); + let dim3 = y.nrows(); + + assert!( + nrows1 == dim2 && ncols1 == dim3, + "ger: dimensions mismatch." + ); + + for j in 0..ncols1 { + // TODO: avoid bound checks. + let val = unsafe { conjugate(y.vget_unchecked(j).clone()) }; + self.column_mut(j) + .axpy(alpha.clone() * val, x, beta.clone()); + } + } + + /// Computes `self = alpha * x * y.transpose() + beta * self`. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector2, Vector3}; + /// let mut mat = Matrix2x3::repeat(4.0); + /// let vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector3::new(0.1, 0.2, 0.3); + /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; + /// + /// mat.ger(10.0, &vec1, &vec2, 5.0); + /// assert_eq!(mat, expected); + /// ``` + #[inline] + pub fn ger( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.gerx(alpha, x, y, beta, |e| e) + } + + /// Computes `self = alpha * x * y.adjoint() + beta * self`. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix2x3, Vector2, Vector3, Complex}; + /// let mut mat = Matrix2x3::repeat(Complex::new(4.0, 5.0)); + /// let vec1 = Vector2::new(Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)); + /// let vec2 = Vector3::new(Complex::new(0.6, 0.5), Complex::new(0.4, 0.5), Complex::new(0.2, 0.1)); + /// let expected = vec1 * vec2.adjoint() * Complex::new(10.0, 20.0) + mat * Complex::new(5.0, 15.0); + /// + /// mat.gerc(Complex::new(10.0, 20.0), &vec1, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(mat, expected); + /// ``` + #[inline] + pub fn gerc( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + ) where + T: SimdComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.gerx(alpha, x, y, beta, SimdComplexField::simd_conjugate) + } + + /// Computes `self = alpha * a * b + beta * self`, where `a, b, self` are matrices. + /// `alpha` and `beta` are scalar. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix2x3, Matrix3x4, Matrix2x4}; + /// let mut mat1 = Matrix2x4::identity(); + /// let mat2 = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4, + /// 0.5, 0.6, 0.7, 0.8, + /// 0.9, 1.0, 1.1, 1.2); + /// let expected = mat2 * mat3 * 10.0 + mat1 * 5.0; + /// + /// mat1.gemm(10.0, &mat2, &mat3, 5.0); + /// assert_relative_eq!(mat1, expected); + /// ``` + #[inline] + pub fn gemm( + &mut self, + alpha: T, + a: &Matrix, + b: &Matrix, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable, + { + // SAFETY: this is valid because our matrices are initialized and + // we are using status = Init. + unsafe { gemm_uninit(Init, self, alpha, a, b, beta) } + } + + /// Computes `self = alpha * a.transpose() * b + beta * self`, where `a, b, self` are matrices. + /// `alpha` and `beta` are scalar. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4}; + /// let mut mat1 = Matrix2x4::identity(); + /// let mat2 = Matrix3x2::new(1.0, 4.0, + /// 2.0, 5.0, + /// 3.0, 6.0); + /// let mat3 = Matrix3x4::new(0.1, 0.2, 0.3, 0.4, + /// 0.5, 0.6, 0.7, 0.8, + /// 0.9, 1.0, 1.1, 1.2); + /// let expected = mat2.transpose() * mat3 * 10.0 + mat1 * 5.0; + /// + /// mat1.gemm_tr(10.0, &mat2, &mat3, 5.0); + /// assert_eq!(mat1, expected); + /// ``` + #[inline] + pub fn gemm_tr( + &mut self, + alpha: T, + a: &Matrix, + b: &Matrix, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable, + { + let (nrows1, ncols1) = self.shape(); + let (nrows2, ncols2) = a.shape(); + let (nrows3, ncols3) = b.shape(); + + assert_eq!( + nrows2, nrows3, + "gemm: dimensions mismatch for multiplication." + ); + assert_eq!( + (nrows1, ncols1), + (ncols2, ncols3), + "gemm: dimensions mismatch for addition." + ); + + for j1 in 0..ncols1 { + // TODO: avoid bound checks. + self.column_mut(j1) + .gemv_tr(alpha.clone(), a, &b.column(j1), beta.clone()); + } + } + + /// Computes `self = alpha * a.adjoint() * b + beta * self`, where `a, b, self` are matrices. + /// `alpha` and `beta` are scalar. + /// + /// If `beta` is zero, `self` is never read. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3x2, Matrix3x4, Matrix2x4, Complex}; + /// let mut mat1 = Matrix2x4::identity(); + /// let mat2 = Matrix3x2::new(Complex::new(1.0, 4.0), Complex::new(7.0, 8.0), + /// Complex::new(2.0, 5.0), Complex::new(9.0, 10.0), + /// Complex::new(3.0, 6.0), Complex::new(11.0, 12.0)); + /// let mat3 = Matrix3x4::new(Complex::new(0.1, 1.3), Complex::new(0.2, 1.4), Complex::new(0.3, 1.5), Complex::new(0.4, 1.6), + /// Complex::new(0.5, 1.7), Complex::new(0.6, 1.8), Complex::new(0.7, 1.9), Complex::new(0.8, 2.0), + /// Complex::new(0.9, 2.1), Complex::new(1.0, 2.2), Complex::new(1.1, 2.3), Complex::new(1.2, 2.4)); + /// let expected = mat2.adjoint() * mat3 * Complex::new(10.0, 20.0) + mat1 * Complex::new(5.0, 15.0); + /// + /// mat1.gemm_ad(Complex::new(10.0, 20.0), &mat2, &mat3, Complex::new(5.0, 15.0)); + /// assert_eq!(mat1, expected); + /// ``` + #[inline] + pub fn gemm_ad( + &mut self, + alpha: T, + a: &Matrix, + b: &Matrix, + beta: T, + ) where + T: SimdComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable, + { + let (nrows1, ncols1) = self.shape(); + let (nrows2, ncols2) = a.shape(); + let (nrows3, ncols3) = b.shape(); + + assert_eq!( + nrows2, nrows3, + "gemm: dimensions mismatch for multiplication." + ); + assert_eq!( + (nrows1, ncols1), + (ncols2, ncols3), + "gemm: dimensions mismatch for addition." + ); + + for j1 in 0..ncols1 { + // TODO: avoid bound checks. + self.column_mut(j1) + .gemv_ad(alpha.clone(), a, &b.column(j1), beta.clone()); + } + } +} + +impl> Matrix +where + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, +{ + #[inline(always)] + fn xxgerx( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + conjugate: impl Fn(T) -> T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + let dim1 = self.nrows(); + let dim2 = x.nrows(); + let dim3 = y.nrows(); + + assert!( + self.is_square(), + "Symmetric ger: the input matrix must be square." + ); + assert!(dim1 == dim2 && dim1 == dim3, "ger: dimensions mismatch."); + + for j in 0..dim1 { + let val = unsafe { conjugate(y.vget_unchecked(j).clone()) }; + let subdim = Dyn(dim1 - j); + // TODO: avoid bound checks. + self.generic_view_mut((j, j), (subdim, Const::<1>)).axpy( + alpha.clone() * val, + &x.rows_range(j..), + beta.clone(), + ); + } + } + + /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** + /// matrix. + /// + /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular + /// (including the diagonal) part of `self` is read/written. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mut mat = Matrix2::identity(); + /// let vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; + /// mat.m12 = 99999.99999; // This component is on the upper-triangular part and will not be read/written. + /// + /// mat.ger_symm(10.0, &vec1, &vec2, 5.0); + /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); + /// assert_eq!(mat.m12, 99999.99999); // This was untouched. + /// ``` + #[inline] + #[deprecated(note = "This is renamed `syger` to match the original BLAS terminology.")] + pub fn ger_symm( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.syger(alpha, x, y, beta) + } + + /// Computes `self = alpha * x * y.transpose() + beta * self`, where `self` is a **symmetric** + /// matrix. + /// + /// For hermitian complex matrices, use `.hegerc` instead. + /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular + /// (including the diagonal) part of `self` is read/written. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2, Vector2}; + /// let mut mat = Matrix2::identity(); + /// let vec1 = Vector2::new(1.0, 2.0); + /// let vec2 = Vector2::new(0.1, 0.2); + /// let expected = vec1 * vec2.transpose() * 10.0 + mat * 5.0; + /// mat.m12 = 99999.99999; // This component is on the upper-triangular part and will not be read/written. + /// + /// mat.syger(10.0, &vec1, &vec2, 5.0); + /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); + /// assert_eq!(mat.m12, 99999.99999); // This was untouched. + /// ``` + #[inline] + pub fn syger( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + ) where + T: One, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.xxgerx(alpha, x, y, beta, |e| e) + } + + /// Computes `self = alpha * x * y.adjoint() + beta * self`, where `self` is an **hermitian** + /// matrix. + /// + /// If `beta` is zero, `self` is never read. The result is symmetric. Only the lower-triangular + /// (including the diagonal) part of `self` is read/written. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2, Vector2, Complex}; + /// let mut mat = Matrix2::identity(); + /// let vec1 = Vector2::new(Complex::new(1.0, 3.0), Complex::new(2.0, 4.0)); + /// let vec2 = Vector2::new(Complex::new(0.2, 0.4), Complex::new(0.1, 0.3)); + /// let expected = vec1 * vec2.adjoint() * Complex::new(10.0, 20.0) + mat * Complex::new(5.0, 15.0); + /// mat.m12 = Complex::new(99999.99999, 88888.88888); // This component is on the upper-triangular part and will not be read/written. + /// + /// mat.hegerc(Complex::new(10.0, 20.0), &vec1, &vec2, Complex::new(5.0, 15.0)); + /// assert_eq!(mat.lower_triangle(), expected.lower_triangle()); + /// assert_eq!(mat.m12, Complex::new(99999.99999, 88888.88888)); // This was untouched. + /// ``` + #[inline] + pub fn hegerc( + &mut self, + alpha: T, + x: &Vector, + y: &Vector, + beta: T, + ) where + T: SimdComplexField, + SB: Storage, + SC: Storage, + ShapeConstraint: DimEq + DimEq, + { + self.xxgerx(alpha, x, y, beta, SimdComplexField::simd_conjugate) + } +} + +impl> SquareMatrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, +{ + /// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`. + /// + /// This uses the provided workspace `work` to avoid allocations for intermediate results. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{DMatrix, DVector}; + /// // Note that all those would also work with statically-sized matrices. + /// // We use DMatrix/DVector since that's the only case where pre-allocating the + /// // workspace is actually useful (assuming the same workspace is re-used for + /// // several computations) because it avoids repeated dynamic allocations. + /// let mut mat = DMatrix::identity(2, 2); + /// let lhs = DMatrix::from_row_slice(2, 3, &[1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0]); + /// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3, + /// 0.5, 0.6, 0.7, + /// 0.9, 1.0, 1.1]); + /// // The random shows that values on the workspace do not + /// // matter as they will be overwritten. + /// let mut workspace = DVector::new_random(2); + /// let expected = &lhs * &mid * lhs.transpose() * 10.0 + &mat * 5.0; + /// + /// mat.quadform_tr_with_workspace(&mut workspace, 10.0, &lhs, &mid, 5.0); + /// assert_relative_eq!(mat, expected); + /// ``` + pub fn quadform_tr_with_workspace( + &mut self, + work: &mut Vector, + alpha: T, + lhs: &Matrix, + mid: &SquareMatrix, + beta: T, + ) where + D2: Dim, + R3: Dim, + C3: Dim, + D4: Dim, + S2: StorageMut, + S3: Storage, + S4: Storage, + ShapeConstraint: DimEq + DimEq + DimEq + DimEq, + { + work.gemv(T::one(), lhs, &mid.column(0), T::zero()); + self.ger(alpha.clone(), work, &lhs.column(0), beta); + + for j in 1..mid.ncols() { + work.gemv(T::one(), lhs, &mid.column(j), T::zero()); + self.ger(alpha.clone(), work, &lhs.column(j), T::one()); + } + } + + /// Computes the quadratic form `self = alpha * lhs * mid * lhs.transpose() + beta * self`. + /// + /// This allocates a workspace vector of dimension D1 for intermediate results. + /// If `D1` is a type-level integer, then the allocation is performed on the stack. + /// Use `.quadform_tr_with_workspace(...)` instead to avoid allocations. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix2, Matrix3, Matrix2x3, Vector2}; + /// let mut mat = Matrix2::identity(); + /// let lhs = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// let mid = Matrix3::new(0.1, 0.2, 0.3, + /// 0.5, 0.6, 0.7, + /// 0.9, 1.0, 1.1); + /// let expected = lhs * mid * lhs.transpose() * 10.0 + mat * 5.0; + /// + /// mat.quadform_tr(10.0, &lhs, &mid, 5.0); + /// assert_relative_eq!(mat, expected); + /// ``` + pub fn quadform_tr( + &mut self, + alpha: T, + lhs: &Matrix, + mid: &SquareMatrix, + beta: T, + ) where + R3: Dim, + C3: Dim, + D4: Dim, + S3: Storage, + S4: Storage, + ShapeConstraint: DimEq + DimEq + DimEq, + DefaultAllocator: Allocator, + { + // TODO: would it be useful to avoid the zero-initialization of the workspace data? + let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>); + self.quadform_tr_with_workspace(&mut work, alpha, lhs, mid, beta) + } + + /// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`. + /// + /// This uses the provided workspace `work` to avoid allocations for intermediate results. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{DMatrix, DVector}; + /// // Note that all those would also work with statically-sized matrices. + /// // We use DMatrix/DVector since that's the only case where pre-allocating the + /// // workspace is actually useful (assuming the same workspace is re-used for + /// // several computations) because it avoids repeated dynamic allocations. + /// let mut mat = DMatrix::identity(2, 2); + /// let rhs = DMatrix::from_row_slice(3, 2, &[1.0, 2.0, + /// 3.0, 4.0, + /// 5.0, 6.0]); + /// let mid = DMatrix::from_row_slice(3, 3, &[0.1, 0.2, 0.3, + /// 0.5, 0.6, 0.7, + /// 0.9, 1.0, 1.1]); + /// // The random shows that values on the workspace do not + /// // matter as they will be overwritten. + /// let mut workspace = DVector::new_random(3); + /// let expected = rhs.transpose() * &mid * &rhs * 10.0 + &mat * 5.0; + /// + /// mat.quadform_with_workspace(&mut workspace, 10.0, &mid, &rhs, 5.0); + /// assert_relative_eq!(mat, expected); + /// ``` + pub fn quadform_with_workspace( + &mut self, + work: &mut Vector, + alpha: T, + mid: &SquareMatrix, + rhs: &Matrix, + beta: T, + ) where + D2: Dim, + D3: Dim, + R4: Dim, + C4: Dim, + S2: StorageMut, + S3: Storage, + S4: Storage, + ShapeConstraint: + DimEq + DimEq + DimEq + AreMultipliable, + { + work.gemv(T::one(), mid, &rhs.column(0), T::zero()); + self.column_mut(0) + .gemv_tr(alpha.clone(), rhs, work, beta.clone()); + + for j in 1..rhs.ncols() { + work.gemv(T::one(), mid, &rhs.column(j), T::zero()); + self.column_mut(j) + .gemv_tr(alpha.clone(), rhs, work, beta.clone()); + } + } + + /// Computes the quadratic form `self = alpha * rhs.transpose() * mid * rhs + beta * self`. + /// + /// This allocates a workspace vector of dimension D2 for intermediate results. + /// If `D2` is a type-level integer, then the allocation is performed on the stack. + /// Use `.quadform_with_workspace(...)` instead to avoid allocations. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix2, Matrix3x2, Matrix3}; + /// let mut mat = Matrix2::identity(); + /// let rhs = Matrix3x2::new(1.0, 2.0, + /// 3.0, 4.0, + /// 5.0, 6.0); + /// let mid = Matrix3::new(0.1, 0.2, 0.3, + /// 0.5, 0.6, 0.7, + /// 0.9, 1.0, 1.1); + /// let expected = rhs.transpose() * mid * rhs * 10.0 + mat * 5.0; + /// + /// mat.quadform(10.0, &mid, &rhs, 5.0); + /// assert_relative_eq!(mat, expected); + /// ``` + pub fn quadform( + &mut self, + alpha: T, + mid: &SquareMatrix, + rhs: &Matrix, + beta: T, + ) where + D2: Dim, + R3: Dim, + C3: Dim, + S2: Storage, + S3: Storage, + ShapeConstraint: DimEq + DimEq + AreMultipliable, + DefaultAllocator: Allocator, + { + // TODO: would it be useful to avoid the zero-initialization of the workspace data? + let mut work = Vector::zeros_generic(mid.shape_generic().0, Const::<1>); + self.quadform_with_workspace(&mut work, alpha, mid, rhs, beta) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas_uninit.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas_uninit.rs new file mode 100644 index 000000000..1dfb313b8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/blas_uninit.rs @@ -0,0 +1,322 @@ +/* + * This file implements some BLAS operations in such a way that they work + * even if the first argument (the output parameter) is an uninitialized matrix. + * + * Because doing this makes the code harder to read, we only implemented the operations that we + * know would benefit from this performance-wise, namely, GEMM (which we use for our matrix + * multiplication code). If we identify other operations like that in the future, we could add + * them here. + */ + +#[cfg(feature = "std")] +use matrixmultiply; +use num::{One, Zero}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; +#[cfg(feature = "std")] +use std::{any::TypeId, mem}; + +use crate::base::constraint::{ + AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, +}; +#[cfg(feature = "std")] +use crate::base::dimension::Dyn; +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::{RawStorage, RawStorageMut}; +use crate::base::uninit::InitStatus; +use crate::base::{Matrix, Scalar, Vector}; + +// # Safety +// The content of `y` must only contain values for which +// `Status::assume_init_mut` is sound. +#[allow(clippy::too_many_arguments)] +unsafe fn array_axcpy( + _: Status, + y: &mut [Status::Value], + a: T, + x: &[T], + c: T, + beta: T, + stride1: usize, + stride2: usize, + len: usize, +) where + Status: InitStatus, + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, +{ + for i in 0..len { + let y = Status::assume_init_mut(y.get_unchecked_mut(i * stride1)); + *y = + a.clone() * x.get_unchecked(i * stride2).clone() * c.clone() + beta.clone() * y.clone(); + } +} + +fn array_axc( + _: Status, + y: &mut [Status::Value], + a: T, + x: &[T], + c: T, + stride1: usize, + stride2: usize, + len: usize, +) where + Status: InitStatus, + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, +{ + for i in 0..len { + unsafe { + Status::init( + y.get_unchecked_mut(i * stride1), + a.clone() * x.get_unchecked(i * stride2).clone() * c.clone(), + ); + } + } +} + +/// Computes `y = a * x * c + b * y`. +/// +/// If `b` is zero, `y` is never read from and may be uninitialized. +/// +/// # Safety +/// This is UB if b != 0 and any component of `y` is uninitialized. +#[inline(always)] +#[allow(clippy::many_single_char_names)] +pub unsafe fn axcpy_uninit( + status: Status, + y: &mut Vector, + a: T, + x: &Vector, + c: T, + b: T, +) where + T: Scalar + Zero + ClosedAddAssign + ClosedMulAssign, + SA: RawStorageMut, + SB: RawStorage, + ShapeConstraint: DimEq, + Status: InitStatus, +{ + assert_eq!(y.nrows(), x.nrows(), "Axcpy: mismatched vector shapes."); + + let rstride1 = y.strides().0; + let rstride2 = x.strides().0; + + // SAFETY: the conversion to slices is OK because we access the + // elements taking the strides into account. + let y = y.data.as_mut_slice_unchecked(); + let x = x.data.as_slice_unchecked(); + + if !b.is_zero() { + array_axcpy(status, y, a, x, c, b, rstride1, rstride2, x.len()); + } else { + array_axc(status, y, a, x, c, rstride1, rstride2, x.len()); + } +} + +/// Computes `y = alpha * a * x + beta * y`, where `a` is a matrix, `x` a vector, and +/// `alpha, beta` two scalars. +/// +/// If `beta` is zero, `y` is never read from and may be uninitialized. +/// +/// # Safety +/// This is UB if beta != 0 and any component of `y` is uninitialized. +#[inline(always)] +pub unsafe fn gemv_uninit( + status: Status, + y: &mut Vector, + alpha: T, + a: &Matrix, + x: &Vector, + beta: T, +) where + Status: InitStatus, + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SA: RawStorageMut, + SB: RawStorage, + SC: RawStorage, + ShapeConstraint: DimEq + AreMultipliable, +{ + let dim1 = y.nrows(); + let (nrows2, ncols2) = a.shape(); + let dim3 = x.nrows(); + + assert!( + ncols2 == dim3 && dim1 == nrows2, + "Gemv: dimensions mismatch." + ); + + if ncols2 == 0 { + if beta.is_zero() { + y.apply(|e| Status::init(e, T::zero())); + } else { + // SAFETY: this is UB if y is uninitialized. + y.apply(|e| *Status::assume_init_mut(e) *= beta.clone()); + } + return; + } + + // TODO: avoid bound checks. + let col2 = a.column(0); + let val = x.vget_unchecked(0).clone(); + + // SAFETY: this is the call that makes this method unsafe: it is UB if Status = Uninit and beta != 0. + axcpy_uninit(status, y, alpha.clone(), &col2, val, beta); + + for j in 1..ncols2 { + let col2 = a.column(j); + let val = x.vget_unchecked(j).clone(); + + // SAFETY: safe because y was initialized above. + axcpy_uninit(status, y, alpha.clone(), &col2, val, T::one()); + } +} + +/// Computes `y = alpha * a * b + beta * y`, where `a, b, y` are matrices. +/// `alpha` and `beta` are scalar. +/// +/// If `beta` is zero, `y` is never read from and may be uninitialized. +/// +/// # Safety +/// This is UB if beta != 0 and any component of `y` is uninitialized. +#[inline(always)] +pub unsafe fn gemm_uninit< + Status, + T, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, + R3: Dim, + C3: Dim, + SA, + SB, + SC, +>( + status: Status, + y: &mut Matrix, + alpha: T, + a: &Matrix, + b: &Matrix, + beta: T, +) where + Status: InitStatus, + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SA: RawStorageMut, + SB: RawStorage, + SC: RawStorage, + ShapeConstraint: + SameNumberOfRows + SameNumberOfColumns + AreMultipliable, +{ + let ncols1 = y.ncols(); + + #[cfg(feature = "std")] + { + // We assume large matrices will be Dyn but small matrices static. + // We could use matrixmultiply for large statically-sized matrices but the performance + // threshold to activate it would be different from SMALL_DIM because our code optimizes + // better for statically-sized matrices. + if R1::is::() + || C1::is::() + || R2::is::() + || C2::is::() + || R3::is::() + || C3::is::() + { + // matrixmultiply can be used only if the std feature is available. + let nrows1 = y.nrows(); + let (nrows2, ncols2) = a.shape(); + let (nrows3, ncols3) = b.shape(); + + // Threshold determined empirically. + const SMALL_DIM: usize = 5; + + if nrows1 > SMALL_DIM && ncols1 > SMALL_DIM && nrows2 > SMALL_DIM && ncols2 > SMALL_DIM + { + assert_eq!( + ncols2, nrows3, + "gemm: dimensions mismatch for multiplication." + ); + assert_eq!( + (nrows1, ncols1), + (nrows2, ncols3), + "gemm: dimensions mismatch for addition." + ); + + // NOTE: this case should never happen because we enter this + // codepath only when ncols2 > SMALL_DIM. Though we keep this + // here just in case if in the future we change the conditions to + // enter this codepath. + if ncols2 == 0 { + // NOTE: we can't just always multiply by beta + // because we documented the guaranty that `self` is + // never read if `beta` is zero. + if beta.is_zero() { + y.apply(|e| Status::init(e, T::zero())); + } else { + // SAFETY: this is UB if Status = Uninit + y.apply(|e| *Status::assume_init_mut(e) *= beta.clone()); + } + return; + } + + if TypeId::of::() == TypeId::of::() { + let (rsa, csa) = a.strides(); + let (rsb, csb) = b.strides(); + let (rsc, csc) = y.strides(); + + matrixmultiply::sgemm( + nrows2, + ncols2, + ncols3, + mem::transmute_copy(&alpha), + a.data.ptr() as *const f32, + rsa as isize, + csa as isize, + b.data.ptr() as *const f32, + rsb as isize, + csb as isize, + mem::transmute_copy(&beta), + y.data.ptr_mut() as *mut f32, + rsc as isize, + csc as isize, + ); + return; + } else if TypeId::of::() == TypeId::of::() { + let (rsa, csa) = a.strides(); + let (rsb, csb) = b.strides(); + let (rsc, csc) = y.strides(); + + matrixmultiply::dgemm( + nrows2, + ncols2, + ncols3, + mem::transmute_copy(&alpha), + a.data.ptr() as *const f64, + rsa as isize, + csa as isize, + b.data.ptr() as *const f64, + rsb as isize, + csb as isize, + mem::transmute_copy(&beta), + y.data.ptr_mut() as *mut f64, + rsc as isize, + csc as isize, + ); + return; + } + } + } + } + + for j1 in 0..ncols1 { + // TODO: avoid bound checks. + // SAFETY: this is UB if Status = Uninit && beta != 0 + gemv_uninit( + status, + &mut y.column_mut(j1), + alpha.clone(), + a, + &b.column(j1), + beta.clone(), + ); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/cg.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/cg.rs new file mode 100644 index 000000000..c2f91ef30 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/cg.rs @@ -0,0 +1,471 @@ +/* + * + * Computer-graphics specific implementations. + * Currently, it is mostly implemented for homogeneous matrices in 2- and 3-space. + * + */ + +use num::{One, Zero}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameDiff, DimNameSub, U1}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{ + Const, DefaultAllocator, Matrix3, Matrix4, OMatrix, OVector, Scalar, SquareMatrix, Unit, + Vector, Vector2, Vector3, +}; +use crate::geometry::{ + Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point2, Point3, Rotation2, + Rotation3, +}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, RealField}; + +/// # Translation and scaling in any dimension +impl OMatrix +where + T: Scalar + Zero + One, + DefaultAllocator: Allocator, +{ + /// Creates a new homogeneous matrix that applies the same scaling factor on each dimension. + #[inline] + pub fn new_scaling(scaling: T) -> Self { + let mut res = Self::from_diagonal_element(scaling); + res[(D::dim() - 1, D::dim() - 1)] = T::one(); + + res + } + + /// Creates a new homogeneous matrix that applies a distinct scaling factor for each dimension. + #[inline] + pub fn new_nonuniform_scaling(scaling: &Vector, SB>) -> Self + where + D: DimNameSub, + SB: Storage>, + { + let mut res = Self::identity(); + for i in 0..scaling.len() { + res[(i, i)] = scaling[i].clone(); + } + + res + } + + /// Creates a new homogeneous matrix that applies a pure translation. + #[inline] + pub fn new_translation(translation: &Vector, SB>) -> Self + where + D: DimNameSub, + SB: Storage>, + { + let mut res = Self::identity(); + res.generic_view_mut( + (0, D::dim() - 1), + (DimNameDiff::::name(), Const::<1>), + ) + .copy_from(translation); + + res + } +} + +/// # 2D transformations as a Matrix3 +impl Matrix3 { + /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian. + #[inline] + pub fn new_rotation(angle: T) -> Self { + Rotation2::new(angle).to_homogeneous() + } + + /// Creates a new homogeneous matrix that applies a scaling factor for each dimension with respect to point. + /// + /// Can be used to implement `zoom_to` functionality. + #[inline] + pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector2, pt: &Point2) -> Self { + let zero = T::zero(); + let one = T::one(); + Matrix3::new( + scaling.x.clone(), + zero.clone(), + pt.x.clone() - pt.x.clone() * scaling.x.clone(), + zero.clone(), + scaling.y.clone(), + pt.y.clone() - pt.y.clone() * scaling.y.clone(), + zero.clone(), + zero, + one, + ) + } +} + +/// # 3D transformations as a Matrix4 +impl Matrix4 { + /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). + /// + /// Returns the identity matrix if the given argument is zero. + #[inline] + pub fn new_rotation(axisangle: Vector3) -> Self { + Rotation3::new(axisangle).to_homogeneous() + } + + /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). + /// + /// Returns the identity matrix if the given argument is zero. + #[inline] + pub fn new_rotation_wrt_point(axisangle: Vector3, pt: Point3) -> Self { + let rot = Rotation3::from_scaled_axis(axisangle); + Isometry::rotation_wrt_point(rot, pt).to_homogeneous() + } + + /// Creates a new homogeneous matrix that applies a scaling factor for each dimension with respect to point. + /// + /// Can be used to implement `zoom_to` functionality. + #[inline] + pub fn new_nonuniform_scaling_wrt_point(scaling: &Vector3, pt: &Point3) -> Self { + let zero = T::zero(); + let one = T::one(); + Matrix4::new( + scaling.x.clone(), + zero.clone(), + zero.clone(), + pt.x.clone() - pt.x.clone() * scaling.x.clone(), + zero.clone(), + scaling.y.clone(), + zero.clone(), + pt.y.clone() - pt.y.clone() * scaling.y.clone(), + zero.clone(), + zero.clone(), + scaling.z.clone(), + pt.z.clone() - pt.z.clone() * scaling.z.clone(), + zero.clone(), + zero.clone(), + zero, + one, + ) + } + + /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together). + /// + /// Returns the identity matrix if the given argument is zero. + /// This is identical to `Self::new_rotation`. + #[inline] + pub fn from_scaled_axis(axisangle: Vector3) -> Self { + Rotation3::from_scaled_axis(axisangle).to_homogeneous() + } + + /// Creates a new rotation from Euler angles. + /// + /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw. + pub fn from_euler_angles(roll: T, pitch: T, yaw: T) -> Self { + Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous() + } + + /// Builds a 3D homogeneous rotation matrix from an axis and a rotation angle. + pub fn from_axis_angle(axis: &Unit>, angle: T) -> Self { + Rotation3::from_axis_angle(axis, angle).to_homogeneous() + } + + /// Creates a new homogeneous matrix for an orthographic projection. + #[inline] + pub fn new_orthographic(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self { + Orthographic3::new(left, right, bottom, top, znear, zfar).into_inner() + } + + /// Creates a new homogeneous matrix for a perspective projection. + #[inline] + pub fn new_perspective(aspect: T, fovy: T, znear: T, zfar: T) -> Self { + Perspective3::new(aspect, fovy, znear, zfar).into_inner() + } + + /// Creates an isometry that corresponds to the local frame of an observer standing at the + /// point `eye` and looking toward `target`. + /// + /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the + /// `eye`. + #[inline] + pub fn face_towards(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + IsometryMatrix3::face_towards(eye, target, up).to_homogeneous() + } + + /// Deprecated: Use [`Matrix4::face_towards`] instead. + #[deprecated(note = "renamed to `face_towards`")] + pub fn new_observer_frame(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + Matrix4::face_towards(eye, target, up) + } + + /// Builds a right-handed look-at view matrix. + #[inline] + pub fn look_at_rh(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous() + } + + /// Builds a left-handed look-at view matrix. + #[inline] + pub fn look_at_lh(eye: &Point3, target: &Point3, up: &Vector3) -> Self { + IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous() + } +} + +/// # Append/prepend translation and scaling +impl< + T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign, + D: DimName, + S: Storage, + > SquareMatrix +{ + /// Computes the transformation equal to `self` followed by an uniform scaling factor. + #[inline] + #[must_use = "Did you mean to use append_scaling_mut()?"] + pub fn append_scaling(&self, scaling: T) -> OMatrix + where + D: DimNameSub, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.append_scaling_mut(scaling); + res + } + + /// Computes the transformation equal to an uniform scaling factor followed by `self`. + #[inline] + #[must_use = "Did you mean to use prepend_scaling_mut()?"] + pub fn prepend_scaling(&self, scaling: T) -> OMatrix + where + D: DimNameSub, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.prepend_scaling_mut(scaling); + res + } + + /// Computes the transformation equal to `self` followed by a non-uniform scaling factor. + #[inline] + #[must_use = "Did you mean to use append_nonuniform_scaling_mut()?"] + pub fn append_nonuniform_scaling( + &self, + scaling: &Vector, SB>, + ) -> OMatrix + where + D: DimNameSub, + SB: Storage>, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.append_nonuniform_scaling_mut(scaling); + res + } + + /// Computes the transformation equal to a non-uniform scaling factor followed by `self`. + #[inline] + #[must_use = "Did you mean to use prepend_nonuniform_scaling_mut()?"] + pub fn prepend_nonuniform_scaling( + &self, + scaling: &Vector, SB>, + ) -> OMatrix + where + D: DimNameSub, + SB: Storage>, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.prepend_nonuniform_scaling_mut(scaling); + res + } + + /// Computes the transformation equal to `self` followed by a translation. + #[inline] + #[must_use = "Did you mean to use append_translation_mut()?"] + pub fn append_translation( + &self, + shift: &Vector, SB>, + ) -> OMatrix + where + D: DimNameSub, + SB: Storage>, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.append_translation_mut(shift); + res + } + + /// Computes the transformation equal to a translation followed by `self`. + #[inline] + #[must_use = "Did you mean to use prepend_translation_mut()?"] + pub fn prepend_translation( + &self, + shift: &Vector, SB>, + ) -> OMatrix + where + D: DimNameSub, + SB: Storage>, + DefaultAllocator: Allocator + Allocator>, + { + let mut res = self.clone_owned(); + res.prepend_translation_mut(shift); + res + } + + /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor. + #[inline] + pub fn append_scaling_mut(&mut self, scaling: T) + where + S: StorageMut, + D: DimNameSub, + { + let mut to_scale = self.rows_generic_mut(0, DimNameDiff::::name()); + to_scale *= scaling; + } + + /// Computes in-place the transformation equal to an uniform scaling factor followed by `self`. + #[inline] + pub fn prepend_scaling_mut(&mut self, scaling: T) + where + S: StorageMut, + D: DimNameSub, + { + let mut to_scale = self.columns_generic_mut(0, DimNameDiff::::name()); + to_scale *= scaling; + } + + /// Computes in-place the transformation equal to `self` followed by a non-uniform scaling factor. + #[inline] + pub fn append_nonuniform_scaling_mut(&mut self, scaling: &Vector, SB>) + where + S: StorageMut, + D: DimNameSub, + SB: Storage>, + { + for i in 0..scaling.len() { + let mut to_scale = self.fixed_rows_mut::<1>(i); + to_scale *= scaling[i].clone(); + } + } + + /// Computes in-place the transformation equal to a non-uniform scaling factor followed by `self`. + #[inline] + pub fn prepend_nonuniform_scaling_mut( + &mut self, + scaling: &Vector, SB>, + ) where + S: StorageMut, + D: DimNameSub, + SB: Storage>, + { + for i in 0..scaling.len() { + let mut to_scale = self.fixed_columns_mut::<1>(i); + to_scale *= scaling[i].clone(); + } + } + + /// Computes the transformation equal to `self` followed by a translation. + #[inline] + pub fn append_translation_mut(&mut self, shift: &Vector, SB>) + where + S: StorageMut, + D: DimNameSub, + SB: Storage>, + { + for i in 0..D::dim() { + for j in 0..D::dim() - 1 { + let add = shift[j].clone() * self[(D::dim() - 1, i)].clone(); + self[(j, i)] += add; + } + } + } + + /// Computes the transformation equal to a translation followed by `self`. + #[inline] + pub fn prepend_translation_mut(&mut self, shift: &Vector, SB>) + where + D: DimNameSub, + S: StorageMut, + SB: Storage>, + DefaultAllocator: Allocator>, + { + let scale = self + .generic_view( + (D::dim() - 1, 0), + (Const::<1>, DimNameDiff::::name()), + ) + .tr_dot(shift); + let post_translation = self.generic_view( + (0, 0), + (DimNameDiff::::name(), DimNameDiff::::name()), + ) * shift; + + self[(D::dim() - 1, D::dim() - 1)] += scale; + + let mut translation = self.generic_view_mut( + (0, D::dim() - 1), + (DimNameDiff::::name(), Const::<1>), + ); + translation += post_translation; + } +} + +/// # Transformation of vectors and points +impl, S: Storage> SquareMatrix +where + DefaultAllocator: Allocator + + Allocator> + + Allocator, DimNameDiff>, +{ + /// Transforms the given vector, assuming the matrix `self` uses homogeneous coordinates. + #[inline] + pub fn transform_vector( + &self, + v: &OVector>, + ) -> OVector> { + let transform = self.generic_view( + (0, 0), + (DimNameDiff::::name(), DimNameDiff::::name()), + ); + let normalizer = self.generic_view( + (D::dim() - 1, 0), + (Const::<1>, DimNameDiff::::name()), + ); + let n = normalizer.tr_dot(v); + + if !n.is_zero() { + return transform * (v / n); + } + + transform * v + } +} + +impl, Const<3>>> SquareMatrix, S> { + /// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates. + #[inline] + pub fn transform_point(&self, pt: &Point) -> Point { + let transform = self.fixed_view::<2, 2>(0, 0); + let translation = self.fixed_view::<2, 1>(0, 2); + let normalizer = self.fixed_view::<1, 2>(2, 0); + let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((2, 2)).clone() }; + + if !n.is_zero() { + (transform * pt + translation) / n + } else { + transform * pt + translation + } + } +} + +impl, Const<4>>> SquareMatrix, S> { + /// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates. + #[inline] + pub fn transform_point(&self, pt: &Point) -> Point { + let transform = self.fixed_view::<3, 3>(0, 0); + let translation = self.fixed_view::<3, 1>(0, 3); + let normalizer = self.fixed_view::<1, 3>(3, 0); + let n = normalizer.tr_dot(&pt.coords) + unsafe { self.get_unchecked((3, 3)).clone() }; + + if !n.is_zero() { + (transform * pt + translation) / n + } else { + transform * pt + translation + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/componentwise.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/componentwise.rs new file mode 100644 index 000000000..3d7941d70 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/componentwise.rs @@ -0,0 +1,353 @@ +// Non-conventional component-wise operators. + +use num::{Signed, Zero}; +use std::ops::{Add, Mul}; + +use simba::scalar::{ClosedDivAssign, ClosedMulAssign}; +use simba::simd::SimdPartialOrd; + +use crate::base::allocator::{Allocator, SameShapeAllocator}; +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::Dim; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar}; +use crate::ClosedAddAssign; + +/// The type of the result of a matrix component-wise operation. +pub type MatrixComponentOp = MatrixSum; + +impl> Matrix { + /// Computes the component-wise absolute value. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let a = Matrix2::new(0.0, 1.0, + /// -2.0, -3.0); + /// assert_eq!(a.abs(), Matrix2::new(0.0, 1.0, 2.0, 3.0)) + /// ``` + #[inline] + #[must_use] + pub fn abs(&self) -> OMatrix + where + T: Signed, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + + for e in res.iter_mut() { + *e = e.abs(); + } + + res + } + + // TODO: add other operators like component_ln, component_pow, etc. ? +} + +macro_rules! component_binop_impl( + ($($binop: ident, $binop_mut: ident, $binop_assign: ident, $cmpy: ident, $Trait: ident . $op: ident . $op_assign: ident, $desc:expr, $desc_cmpy:expr, $desc_mut:expr);* $(;)*) => {$( + #[doc = $desc] + #[inline] + #[must_use] + pub fn $binop(&self, rhs: &Matrix) -> MatrixComponentOp + where T: $Trait, + R2: Dim, C2: Dim, + SB: Storage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + let mut res = self.clone_owned_sum(); + + for j in 0 .. res.ncols() { + for i in 0 .. res.nrows() { + unsafe { + res.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).clone()); + } + } + } + + res + } + + // componentwise binop plus Y. + #[doc = $desc_cmpy] + #[inline] + pub fn $cmpy(&mut self, alpha: T, a: &Matrix, b: &Matrix, beta: T) + where T: $Trait + Zero + Mul + Add, + R2: Dim, C2: Dim, + R3: Dim, C3: Dim, + SA: StorageMut, + SB: Storage, + SC: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + + SameNumberOfRows + SameNumberOfColumns { + assert_eq!(self.shape(), a.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + assert_eq!(self.shape(), b.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + + if beta.is_zero() { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + let res = alpha.clone() * a.get_unchecked((i, j)).clone().$op(b.get_unchecked((i, j)).clone()); + *self.get_unchecked_mut((i, j)) = res; + } + } + } + } + else { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + let res = alpha.clone() * a.get_unchecked((i, j)).clone().$op(b.get_unchecked((i, j)).clone()); + *self.get_unchecked_mut((i, j)) = beta.clone() * self.get_unchecked((i, j)).clone() + res; + } + } + } + } + } + + #[doc = $desc_mut] + #[inline] + pub fn $binop_assign(&mut self, rhs: &Matrix) + where T: $Trait, + R2: Dim, + C2: Dim, + SA: StorageMut, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + assert_eq!(self.shape(), rhs.shape(), "Componentwise mul/div: mismatched matrix dimensions."); + + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { + self.get_unchecked_mut((i, j)).$op_assign(rhs.get_unchecked((i, j)).clone()); + } + } + } + } + + #[doc = $desc_mut] + #[inline] + #[deprecated(note = "This is renamed using the `_assign` suffix instead of the `_mut` suffix.")] + pub fn $binop_mut(&mut self, rhs: &Matrix) + where T: $Trait, + R2: Dim, + C2: Dim, + SA: StorageMut, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + self.$binop_assign(rhs) + } + )*} +); + +/// # Componentwise operations +impl> Matrix { + component_binop_impl!( + component_mul, component_mul_mut, component_mul_assign, cmpy, ClosedMulAssign.mul.mul_assign, + r" + Componentwise matrix or vector multiplication. + + # Example + + ``` + # use nalgebra::Matrix2; + let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); + + assert_eq!(a.component_mul(&b), expected); + ``` + ", + r" + Computes componentwise `self[i] = alpha * a[i] * b[i] + beta * self[i]`. + + # Example + ``` + # use nalgebra::Matrix2; + let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = (a.component_mul(&b) * 5.0) + m * 10.0; + + m.cmpy(5.0, &a, &b, 10.0); + assert_eq!(m, expected); + ``` + ", + r" + Inplace componentwise matrix or vector multiplication. + + # Example + ``` + # use nalgebra::Matrix2; + let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 5.0, 12.0, 21.0); + + a.component_mul_assign(&b); + + assert_eq!(a, expected); + ``` + "; + component_div, component_div_mut, component_div_assign, cdpy, ClosedDivAssign.div.div_assign, + r" + Componentwise matrix or vector division. + + # Example + + ``` + # use nalgebra::Matrix2; + let a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); + + assert_eq!(a.component_div(&b), expected); + ``` + ", + r" + Computes componentwise `self[i] = alpha * a[i] / b[i] + beta * self[i]`. + + # Example + ``` + # use nalgebra::Matrix2; + let mut m = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let a = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = (a.component_div(&b) * 5.0) + m * 10.0; + + m.cdpy(5.0, &a, &b, 10.0); + assert_eq!(m, expected); + ``` + ", + r" + Inplace componentwise matrix or vector division. + + # Example + ``` + # use nalgebra::Matrix2; + let mut a = Matrix2::new(0.0, 1.0, 2.0, 3.0); + let b = Matrix2::new(4.0, 5.0, 6.0, 7.0); + let expected = Matrix2::new(0.0, 1.0 / 5.0, 2.0 / 6.0, 3.0 / 7.0); + + a.component_div_assign(&b); + + assert_eq!(a, expected); + ``` + "; + // TODO: add other operators like bitshift, etc. ? + ); + + /// Computes the infimum (aka. componentwise min) of two matrices/vectors. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); + /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); + /// let expected = Matrix2::new(2.0, 2.0, -2.0, -2.0); + /// assert_eq!(u.inf(&v), expected) + /// ``` + #[inline] + #[must_use] + pub fn inf(&self, other: &Self) -> OMatrix + where + T: SimdPartialOrd, + DefaultAllocator: Allocator, + { + self.zip_map(other, |a, b| a.simd_min(b)) + } + + /// Computes the supremum (aka. componentwise max) of two matrices/vectors. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); + /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); + /// let expected = Matrix2::new(4.0, 4.0, 1.0, 1.0); + /// assert_eq!(u.sup(&v), expected) + /// ``` + #[inline] + #[must_use] + pub fn sup(&self, other: &Self) -> OMatrix + where + T: SimdPartialOrd, + DefaultAllocator: Allocator, + { + self.zip_map(other, |a, b| a.simd_max(b)) + } + + /// Computes the (infimum, supremum) of two matrices/vectors. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); + /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); + /// let expected = (Matrix2::new(2.0, 2.0, -2.0, -2.0), Matrix2::new(4.0, 4.0, 1.0, 1.0)); + /// assert_eq!(u.inf_sup(&v), expected) + /// ``` + #[inline] + #[must_use] + pub fn inf_sup(&self, other: &Self) -> (OMatrix, OMatrix) + where + T: SimdPartialOrd, + DefaultAllocator: Allocator, + { + // TODO: can this be optimized? + (self.inf(other), self.sup(other)) + } + + /// Adds a scalar to `self`. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(1.0, 2.0, 3.0, 4.0); + /// let s = 10.0; + /// let expected = Matrix2::new(11.0, 12.0, 13.0, 14.0); + /// assert_eq!(u.add_scalar(s), expected) + /// ``` + #[inline] + #[must_use = "Did you mean to use add_scalar_mut()?"] + pub fn add_scalar(&self, rhs: T) -> OMatrix + where + T: ClosedAddAssign, + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.add_scalar_mut(rhs); + res + } + + /// Adds a scalar to `self` in-place. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let mut u = Matrix2::new(1.0, 2.0, 3.0, 4.0); + /// let s = 10.0; + /// u.add_scalar_mut(s); + /// let expected = Matrix2::new(11.0, 12.0, 13.0, 14.0); + /// assert_eq!(u, expected) + /// ``` + #[inline] + pub fn add_scalar_mut(&mut self, rhs: T) + where + T: ClosedAddAssign, + SA: StorageMut, + { + for e in self.iter_mut() { + *e += rhs.clone() + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/constraint.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/constraint.rs new file mode 100644 index 000000000..c9418f080 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/constraint.rs @@ -0,0 +1,108 @@ +//! Compatibility constraints between matrix shapes, e.g., for addition or multiplication. + +use crate::base::dimension::{Dim, DimName, Dyn}; + +/// A type used in `where` clauses for enforcing constraints. +#[derive(Copy, Clone, Debug)] +pub struct ShapeConstraint; + +/// Constrains `C1` and `R2` to be equivalent. +pub trait AreMultipliable: DimEq {} + +impl AreMultipliable for ShapeConstraint where + ShapeConstraint: DimEq +{ +} + +/// Constrains `D1` and `D2` to be equivalent. +pub trait DimEq { + /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level + /// constant. + type Representative: Dim; + + /// This constructs a value of type `Representative` with the + /// correct value + fn representative(d1: D1, d2: D2) -> Option { + if d1.value() != d2.value() { + None + } else { + Some(Self::Representative::from_usize(d1.value())) + } + } +} + +impl DimEq for ShapeConstraint { + type Representative = D; +} + +impl DimEq for ShapeConstraint { + type Representative = D; +} + +impl DimEq for ShapeConstraint { + type Representative = D; +} + +macro_rules! equality_trait_decl( + ($($doc: expr, $Trait: ident),* $(,)*) => {$( + // XXX: we can't do something like `DimEq for D2` because we would require a blanket impl… + #[doc = $doc] + pub trait $Trait: DimEq + DimEq { + /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level + /// constant. + type Representative: Dim; + + /// Returns a representative dimension instance if the two are equal, + /// otherwise `None`. + fn representative(d1: D1, d2: D2) -> Option<>::Representative> { + >::representative(d1, d2) + .map(|common_dim| >::Representative::from_usize(common_dim.value())) + } + } + + impl $Trait for ShapeConstraint { + type Representative = D; + } + + impl $Trait for ShapeConstraint { + type Representative = D; + } + + impl $Trait for ShapeConstraint { + type Representative = D; + } + )*} +); + +equality_trait_decl!( + "Constrains `D1` and `D2` to be equivalent. \ + They are both assumed to be the number of \ + rows of a matrix.", + SameNumberOfRows, + "Constrains `D1` and `D2` to be equivalent. \ + They are both assumed to be the number of \ + columns of a matrix.", + SameNumberOfColumns +); + +/// Constrains D1 and D2 to be equivalent, where they both designate dimensions of algebraic +/// entities (e.g. square matrices). +pub trait SameDimension: + SameNumberOfRows + SameNumberOfColumns +{ + /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level + /// constant. + type Representative: Dim; +} + +impl SameDimension for ShapeConstraint { + type Representative = D; +} + +impl SameDimension for ShapeConstraint { + type Representative = D; +} + +impl SameDimension for ShapeConstraint { + type Representative = D; +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction.rs new file mode 100644 index 000000000..ae32ad416 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction.rs @@ -0,0 +1,1269 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::{Bounded, One, Zero}; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use std::iter; +use typenum::{self, Cmp, Greater}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, DimName, Dyn, ToTypenum}; +use crate::base::storage::RawStorage; +use crate::base::{ + ArrayStorage, Const, DefaultAllocator, Matrix, OMatrix, OVector, Scalar, Unit, Vector, +}; +use crate::UninitMatrix; +use std::mem::MaybeUninit; + +impl UninitMatrix +where + DefaultAllocator: Allocator, +{ + /// Builds a matrix with uninitialized elements of type `MaybeUninit`. + #[inline(always)] + pub fn uninit(nrows: R, ncols: C) -> Self { + // SAFETY: this is OK because the dimension automatically match the storage + // because we are building an owned storage. + unsafe { + Self::from_data_statically_unchecked(DefaultAllocator::allocate_uninit(nrows, ncols)) + } + } +} + +/// # Generic constructors +/// This set of matrix and vector construction functions are all generic +/// with-regard to the matrix dimensions. They all expect to be given +/// the dimension as inputs. +/// +/// These functions should only be used when working on dimension-generic code. +impl OMatrix +where + DefaultAllocator: Allocator, +{ + /// Creates a matrix with all its elements set to `elem`. + #[inline] + pub fn from_element_generic(nrows: R, ncols: C, elem: T) -> Self { + let len = nrows.value() * ncols.value(); + Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len)) + } + + /// Creates a matrix with all its elements set to `elem`. + /// + /// Same as `from_element_generic`. + #[inline] + pub fn repeat_generic(nrows: R, ncols: C, elem: T) -> Self { + let len = nrows.value() * ncols.value(); + Self::from_iterator_generic(nrows, ncols, iter::repeat(elem).take(len)) + } + + /// Creates a matrix with all its elements set to 0. + #[inline] + pub fn zeros_generic(nrows: R, ncols: C) -> Self + where + T: Zero, + { + Self::from_element_generic(nrows, ncols, T::zero()) + } + + /// Creates a matrix with all its elements filled by an iterator. + #[inline] + pub fn from_iterator_generic(nrows: R, ncols: C, iter: I) -> Self + where + I: IntoIterator, + { + Self::from_data(DefaultAllocator::allocate_from_iterator(nrows, ncols, iter)) + } + + /// Creates a matrix with all its elements filled by an row-major order iterator. + #[inline] + pub fn from_row_iterator_generic(nrows: R, ncols: C, iter: I) -> Self + where + I: IntoIterator, + { + Self::from_data(DefaultAllocator::allocate_from_row_iterator( + nrows, ncols, iter, + )) + } + + /// Creates a matrix with its elements filled with the components provided by a slice in + /// row-major order. + /// + /// The order of elements in the slice must follow the usual mathematic writing, i.e., + /// row-by-row. + #[inline] + pub fn from_row_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self { + assert!( + slice.len() == nrows.value() * ncols.value(), + "Matrix init. error: the slice did not contain the right number of elements." + ); + + let mut res = Matrix::uninit(nrows, ncols); + let mut iter = slice.iter(); + + unsafe { + for i in 0..nrows.value() { + for j in 0..ncols.value() { + *res.get_unchecked_mut((i, j)) = MaybeUninit::new(iter.next().unwrap().clone()) + } + } + + // SAFETY: the result has been fully initialized above. + res.assume_init() + } + } + + /// Creates a matrix with its elements filled with the components provided by a slice. The + /// components must have the same layout as the matrix data storage (i.e. column-major). + #[inline] + pub fn from_column_slice_generic(nrows: R, ncols: C, slice: &[T]) -> Self { + Self::from_iterator_generic(nrows, ncols, slice.iter().cloned()) + } + + /// Creates a matrix filled with the results of a function applied to each of its component + /// coordinates. + #[inline] + pub fn from_fn_generic(nrows: R, ncols: C, mut f: F) -> Self + where + F: FnMut(usize, usize) -> T, + { + let mut res = Matrix::uninit(nrows, ncols); + + unsafe { + for j in 0..ncols.value() { + for i in 0..nrows.value() { + *res.get_unchecked_mut((i, j)) = MaybeUninit::new(f(i, j)); + } + } + + // SAFETY: the result has been fully initialized above. + res.assume_init() + } + } + + /// Creates a new identity matrix. + /// + /// If the matrix is not square, the largest square submatrix starting at index `(0, 0)` is set + /// to the identity matrix. All other entries are set to zero. + #[inline] + pub fn identity_generic(nrows: R, ncols: C) -> Self + where + T: Zero + One, + { + Self::from_diagonal_element_generic(nrows, ncols, T::one()) + } + + /// Creates a new matrix with its diagonal filled with copies of `elt`. + /// + /// If the matrix is not square, the largest square submatrix starting at index `(0, 0)` is set + /// to the identity matrix. All other entries are set to zero. + #[inline] + pub fn from_diagonal_element_generic(nrows: R, ncols: C, elt: T) -> Self + where + T: Zero + One, + { + let mut res = Self::zeros_generic(nrows, ncols); + + for i in 0..crate::min(nrows.value(), ncols.value()) { + unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() } + } + + res + } + + /// Creates a new matrix that may be rectangular. The first `elts.len()` diagonal elements are + /// filled with the content of `elts`. Others are set to 0. + /// + /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. + #[inline] + pub fn from_partial_diagonal_generic(nrows: R, ncols: C, elts: &[T]) -> Self + where + T: Zero, + { + let mut res = Self::zeros_generic(nrows, ncols); + assert!( + elts.len() <= crate::min(nrows.value(), ncols.value()), + "Too many diagonal elements provided." + ); + + for (i, elt) in elts.iter().enumerate() { + unsafe { *res.get_unchecked_mut((i, i)) = elt.clone() } + } + + res + } + + /// Builds a new matrix from its rows. + /// + /// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do + /// not have the same dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::{RowVector3, Matrix3}; + /// # use std::iter; + /// + /// let m = Matrix3::from_rows(&[ RowVector3::new(1.0, 2.0, 3.0), RowVector3::new(4.0, 5.0, 6.0), RowVector3::new(7.0, 8.0, 9.0) ]); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 2.0 && m.m13 == 3.0 && + /// m.m21 == 4.0 && m.m22 == 5.0 && m.m23 == 6.0 && + /// m.m31 == 7.0 && m.m32 == 8.0 && m.m33 == 9.0); + /// ``` + #[inline] + pub fn from_rows(rows: &[Matrix, C, SB>]) -> Self + where + SB: RawStorage, C>, + { + assert!(!rows.is_empty(), "At least one row must be given."); + let nrows = R::try_to_usize().unwrap_or(rows.len()); + let ncols = rows[0].len(); + assert!( + rows.len() == nrows, + "Invalid number of rows provided to build this matrix." + ); + + if C::try_to_usize().is_none() { + assert!( + rows.iter().all(|r| r.len() == ncols), + "The provided rows must all have the same dimension." + ); + } + + // TODO: optimize that. + Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| { + rows[i][(0, j)].clone() + }) + } + + /// Builds a new matrix from its columns. + /// + /// Panics if not enough columns are provided (for statically-sized matrices), or if all + /// columns do not have the same dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Matrix3}; + /// # use std::iter; + /// + /// let m = Matrix3::from_columns(&[ Vector3::new(1.0, 2.0, 3.0), Vector3::new(4.0, 5.0, 6.0), Vector3::new(7.0, 8.0, 9.0) ]); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 4.0 && m.m13 == 7.0 && + /// m.m21 == 2.0 && m.m22 == 5.0 && m.m23 == 8.0 && + /// m.m31 == 3.0 && m.m32 == 6.0 && m.m33 == 9.0); + /// ``` + #[inline] + pub fn from_columns(columns: &[Vector]) -> Self + where + SB: RawStorage, + { + assert!(!columns.is_empty(), "At least one column must be given."); + let ncols = C::try_to_usize().unwrap_or(columns.len()); + let nrows = columns[0].len(); + assert!( + columns.len() == ncols, + "Invalid number of columns provided to build this matrix." + ); + + if R::try_to_usize().is_none() { + assert!( + columns.iter().all(|r| r.len() == nrows), + "The columns provided must all have the same dimension." + ); + } + + // TODO: optimize that. + Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| { + columns[j][i].clone() + }) + } + + /// Creates a matrix filled with random values. + #[inline] + #[cfg(feature = "rand")] + pub fn new_random_generic(nrows: R, ncols: C) -> Self + where + Standard: Distribution, + { + let mut rng = rand::thread_rng(); + Self::from_fn_generic(nrows, ncols, |_, _| rng.gen()) + } + + /// Creates a matrix filled with random values from the given distribution. + #[inline] + #[cfg(feature = "rand-no-std")] + pub fn from_distribution_generic + ?Sized, G: Rng + ?Sized>( + nrows: R, + ncols: C, + distribution: &Distr, + rng: &mut G, + ) -> Self { + Self::from_fn_generic(nrows, ncols, |_, _| distribution.sample(rng)) + } + + /// Creates a matrix backed by a given `Vec`. + /// + /// The output matrix is filled column-by-column. + /// + /// # Example + /// ``` + /// # use nalgebra::{Dyn, DMatrix, Matrix, Const}; + /// + /// let vec = vec![0, 1, 2, 3, 4, 5]; + /// let vec_ptr = vec.as_ptr(); + /// + /// let matrix = Matrix::from_vec_generic(Dyn(vec.len()), Const::<1>, vec); + /// let matrix_storage_ptr = matrix.data.as_vec().as_ptr(); + /// + /// // `matrix` is backed by exactly the same `Vec` as it was constructed from. + /// assert_eq!(matrix_storage_ptr, vec_ptr); + /// ``` + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn from_vec_generic(nrows: R, ncols: C, data: Vec) -> Self { + Self::from_iterator_generic(nrows, ncols, data) + } +} + +impl OMatrix +where + T: Scalar, + DefaultAllocator: Allocator, +{ + /// Creates a square matrix with its diagonal set to `diag` and all other entries set to 0. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector3, DVector, Matrix3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix3::from_diagonal(&Vector3::new(1.0, 2.0, 3.0)); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_diagonal(&DVector::from_row_slice(&[1.0, 2.0, 3.0])); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 && + /// m.m31 == 0.0 && m.m32 == 0.0 && m.m33 == 3.0); + /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 0.0 && + /// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 3.0); + /// ``` + #[inline] + pub fn from_diagonal>(diag: &Vector) -> Self + where + T: Zero, + { + let (dim, _) = diag.shape_generic(); + let mut res = Self::zeros_generic(dim, dim); + + for i in 0..diag.len() { + unsafe { + *res.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone(); + } + } + + res + } +} + +/* + * + * Generate constructors with varying number of arguments, depending on the object type. + * + */ +macro_rules! impl_constructors( + ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { + /// Creates a matrix or vector with all its elements set to `elem`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// + /// let v = Vector3::from_element(2.0); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_element(3, 2.0); + /// let m = Matrix2x3::from_element(2.0); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_element(2, 3, 2.0); + /// + /// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0); + /// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0); + /// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 && + /// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0); + /// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 && + /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); + /// ``` + #[inline] + pub fn from_element($($args: usize,)* elem: T) -> Self { + Self::from_element_generic($($gargs, )* elem) + } + + /// Creates a matrix or vector with all its elements set to `elem`. + /// + /// Same as `.from_element`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// + /// let v = Vector3::repeat(2.0); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::repeat(3, 2.0); + /// let m = Matrix2x3::repeat(2.0); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::repeat(2, 3, 2.0); + /// + /// assert!(v.x == 2.0 && v.y == 2.0 && v.z == 2.0); + /// assert!(dv[0] == 2.0 && dv[1] == 2.0 && dv[2] == 2.0); + /// assert!(m.m11 == 2.0 && m.m12 == 2.0 && m.m13 == 2.0 && + /// m.m21 == 2.0 && m.m22 == 2.0 && m.m23 == 2.0); + /// assert!(dm[(0, 0)] == 2.0 && dm[(0, 1)] == 2.0 && dm[(0, 2)] == 2.0 && + /// dm[(1, 0)] == 2.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 2.0); + /// ``` + #[inline] + pub fn repeat($($args: usize,)* elem: T) -> Self { + Self::repeat_generic($($gargs, )* elem) + } + + /// Creates a matrix or vector with all its elements set to `0`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// + /// let v = Vector3::::zeros(); + /// // The argument represents the vector dimension. + /// let dv = DVector::::zeros(3); + /// let m = Matrix2x3::::zeros(); + /// // The two arguments represent the matrix dimensions. + /// let dm = DMatrix::::zeros(2, 3); + /// + /// assert!(v.x == 0.0 && v.y == 0.0 && v.z == 0.0); + /// assert!(dv[0] == 0.0 && dv[1] == 0.0 && dv[2] == 0.0); + /// assert!(m.m11 == 0.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 0.0 && m.m23 == 0.0); + /// assert!(dm[(0, 0)] == 0.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 0.0 && dm[(1, 2)] == 0.0); + /// ``` + #[inline] + pub fn zeros($($args: usize),*) -> Self + where T: Zero { + Self::zeros_generic($($gargs),*) + } + + /// Creates a matrix or vector with all its elements filled by an iterator. + /// + /// The output matrix is filled column-by-column. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_iterator((0..3).into_iter()); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_iterator(3, (0..3).into_iter()); + /// let m = Matrix2x3::from_iterator((0..6).into_iter()); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_iterator(2, 3, (0..6).into_iter()); + /// + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 && + /// m.m21 == 1 && m.m22 == 3 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 && + /// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_iterator($($args: usize,)* iter: I) -> Self + where I: IntoIterator { + Self::from_iterator_generic($($gargs, )* iter) + } + + /// Creates a matrix or vector with all its elements filled by a row-major iterator. + /// + /// The output matrix is filled row-by-row. + /// + /// ## Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_row_iterator((0..3).into_iter()); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_row_iterator(3, (0..3).into_iter()); + /// let m = Matrix2x3::from_row_iterator((0..6).into_iter()); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_row_iterator(2, 3, (0..6).into_iter()); + /// + /// // For Vectors from_row_iterator is identical to from_iterator + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 && + /// m.m21 == 3 && m.m22 == 4 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 && + /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_row_iterator($($args: usize,)* iter: I) -> Self + where I: IntoIterator { + Self::from_row_iterator_generic($($gargs, )* iter) + } + + /// Creates a matrix or vector filled with the results of a function applied to each of its + /// component coordinates. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_fn(|i, _| i); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_fn(3, |i, _| i); + /// let m = Matrix2x3::from_fn(|i, j| i * 3 + j); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_fn(2, 3, |i, j| i * 3 + j); + /// + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 && + /// m.m21 == 3 && m.m22 == 4 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 && + /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_fn($($args: usize,)* f: F) -> Self + where F: FnMut(usize, usize) -> T { + Self::from_fn_generic($($gargs, )* f) + } + + /// Creates an identity matrix. If the matrix is not square, the largest square + /// submatrix (starting at the first row and column) is set to the identity while all + /// other entries are set to zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix2x3::::identity(); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::::identity(2, 3); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 1.0 && m.m23 == 0.0); + /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 1.0 && dm[(1, 2)] == 0.0); + /// ``` + #[inline] + pub fn identity($($args: usize,)*) -> Self + where T: Zero + One { + Self::identity_generic($($gargs),* ) + } + + /// Creates a matrix filled with its diagonal filled with `elt` and all other + /// components set to zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix2x3::from_diagonal_element(5.0); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_diagonal_element(2, 3, 5.0); + /// + /// assert!(m.m11 == 5.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 5.0 && m.m23 == 0.0); + /// assert!(dm[(0, 0)] == 5.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 5.0 && dm[(1, 2)] == 0.0); + /// ``` + #[inline] + pub fn from_diagonal_element($($args: usize,)* elt: T) -> Self + where T: Zero + One { + Self::from_diagonal_element_generic($($gargs, )* elt) + } + + /// Creates a new matrix that may be rectangular. The first `elts.len()` diagonal + /// elements are filled with the content of `elts`. Others are set to 0. + /// + /// Panics if `elts.len()` is larger than the minimum among `nrows` and `ncols`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix3, DMatrix}; + /// # use std::iter; + /// + /// let m = Matrix3::from_partial_diagonal(&[1.0, 2.0]); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_partial_diagonal(3, 3, &[1.0, 2.0]); + /// + /// assert!(m.m11 == 1.0 && m.m12 == 0.0 && m.m13 == 0.0 && + /// m.m21 == 0.0 && m.m22 == 2.0 && m.m23 == 0.0 && + /// m.m31 == 0.0 && m.m32 == 0.0 && m.m33 == 0.0); + /// assert!(dm[(0, 0)] == 1.0 && dm[(0, 1)] == 0.0 && dm[(0, 2)] == 0.0 && + /// dm[(1, 0)] == 0.0 && dm[(1, 1)] == 2.0 && dm[(1, 2)] == 0.0 && + /// dm[(2, 0)] == 0.0 && dm[(2, 1)] == 0.0 && dm[(2, 2)] == 0.0); + /// ``` + #[inline] + pub fn from_partial_diagonal($($args: usize,)* elts: &[T]) -> Self + where T: Zero { + Self::from_partial_diagonal_generic($($gargs, )* elts) + } + + /// Creates a matrix or vector filled with random values from the given distribution. + #[inline] + #[cfg(feature = "rand-no-std")] + pub fn from_distribution + ?Sized, G: Rng + ?Sized>( + $($args: usize,)* + distribution: &Distr, + rng: &mut G, + ) -> Self { + Self::from_distribution_generic($($gargs, )* distribution, rng) + } + + /// Creates a matrix filled with random values. + #[inline] + #[cfg(feature = "rand")] + pub fn new_random($($args: usize),*) -> Self + where Standard: Distribution { + Self::new_random_generic($($gargs),*) + } + } +); + +/// # Constructors of statically-sized vectors or statically-sized matrices +impl OMatrix +where + DefaultAllocator: Allocator, +{ + // TODO: this is not very pretty. We could find a better call syntax. + impl_constructors!(R, C; // Arguments for Matrix + => R: DimName, => C: DimName; // Type parameters for impl + R::name(), C::name(); // Arguments for `_generic` constructors. + ); // Arguments for non-generic constructors. +} + +/// # Constructors of matrices with a dynamic number of columns +impl OMatrix +where + DefaultAllocator: Allocator, +{ + impl_constructors!(R, Dyn; + => R: DimName; + R::name(), Dyn(ncols); + ncols); +} + +/// # Constructors of dynamic vectors and matrices with a dynamic number of rows +impl OMatrix +where + DefaultAllocator: Allocator, +{ + impl_constructors!(Dyn, C; + => C: DimName; + Dyn(nrows), C::name(); + nrows); +} + +/// # Constructors of fully dynamic matrices +#[cfg(any(feature = "std", feature = "alloc"))] +impl OMatrix +where + DefaultAllocator: Allocator, +{ + impl_constructors!(Dyn, Dyn; + ; + Dyn(nrows), Dyn(ncols); + nrows, ncols); +} + +/* + * + * Constructors that don't necessarily require all dimensions + * to be specified when one dimension is already known. + * + */ +macro_rules! impl_constructors_from_data( + ($data: ident; $($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { + impl OMatrix + where DefaultAllocator: Allocator<$($Dims),*> { + /// Creates a matrix with its elements filled with the components provided by a slice + /// in row-major order. + /// + /// The order of elements in the slice must follow the usual mathematic writing, i.e., + /// row-by-row. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_row_slice(&[0, 1, 2]); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_row_slice(&[0, 1, 2]); + /// let m = Matrix2x3::from_row_slice(&[0, 1, 2, 3, 4, 5]); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_row_slice(2, 3, &[0, 1, 2, 3, 4, 5]); + /// + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 && + /// m.m21 == 3 && m.m22 == 4 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 && + /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_row_slice($($args: usize,)* $data: &[T]) -> Self { + Self::from_row_slice_generic($($gargs, )* $data) + } + + /// Creates a matrix with its elements filled with the components provided by a slice + /// in column-major order. + /// + /// # Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_column_slice(&[0, 1, 2]); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_column_slice(&[0, 1, 2]); + /// let m = Matrix2x3::from_column_slice(&[0, 1, 2, 3, 4, 5]); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_column_slice(2, 3, &[0, 1, 2, 3, 4, 5]); + /// + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 && + /// m.m21 == 1 && m.m22 == 3 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 && + /// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_column_slice($($args: usize,)* $data: &[T]) -> Self { + Self::from_column_slice_generic($($gargs, )* $data) + } + + /// Creates a matrix backed by a given `Vec`. + /// + /// The output matrix is filled column-by-column. + /// + /// # Example + /// ``` + /// # use nalgebra::{DMatrix, Matrix2x3}; + /// + /// let m = Matrix2x3::from_vec(vec![0, 1, 2, 3, 4, 5]); + /// + /// assert!(m.m11 == 0 && m.m12 == 2 && m.m13 == 4 && + /// m.m21 == 1 && m.m22 == 3 && m.m23 == 5); + /// + /// + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]); + /// + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 2 && dm[(0, 2)] == 4 && + /// dm[(1, 0)] == 1 && dm[(1, 1)] == 3 && dm[(1, 2)] == 5); + /// ``` + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn from_vec($($args: usize,)* $data: Vec) -> Self { + Self::from_vec_generic($($gargs, )* $data) + } + } + } +); + +// TODO: this is not very pretty. We could find a better call syntax. +impl_constructors_from_data!(data; R, C; // Arguments for Matrix +=> R: DimName, => C: DimName; // Type parameters for impl +R::name(), C::name(); // Arguments for `_generic` constructors. +); // Arguments for non-generic constructors. + +impl_constructors_from_data!(data; R, Dyn; +=> R: DimName; +R::name(), Dyn(data.len() / R::dim()); +); + +impl_constructors_from_data!(data; Dyn, C; +=> C: DimName; +Dyn(data.len() / C::dim()), C::name(); +); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl_constructors_from_data!(data; Dyn, Dyn; + ; + Dyn(nrows), Dyn(ncols); + nrows, ncols); + +/* + * + * Zero, One, Rand traits. + * + */ +impl Zero for OMatrix +where + T: Scalar + Zero + ClosedAddAssign, + DefaultAllocator: Allocator, +{ + #[inline] + fn zero() -> Self { + Self::from_element(T::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + self.iter().all(|e| e.is_zero()) + } +} + +impl One for OMatrix +where + T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign, + DefaultAllocator: Allocator, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} + +impl Bounded for OMatrix +where + T: Scalar + Bounded, + DefaultAllocator: Allocator, +{ + #[inline] + fn max_value() -> Self { + Self::from_element(T::max_value()) + } + + #[inline] + fn min_value() -> Self { + Self::from_element(T::min_value()) + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + DefaultAllocator: Allocator, + Standard: Distribution, +{ + #[inline] + fn sample(&self, rng: &mut G) -> OMatrix { + let nrows = R::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10)); + let ncols = C::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10)); + + OMatrix::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |_, _| rng.gen()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for OMatrix +where + R: Dim, + C: Dim, + T: Scalar + Arbitrary + Send, + DefaultAllocator: Allocator, + Owned: Clone + Send, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + let nrows = R::try_to_usize().unwrap_or(usize::arbitrary(g) % 10); + let ncols = C::try_to_usize().unwrap_or(usize::arbitrary(g) % 10); + + Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |_, _| { + T::arbitrary(g) + }) + } +} + +// TODO(specialization): faster impls possible for D≤4 (see rand_distr::{UnitCircle, UnitSphere}) +#[cfg(feature = "rand")] +impl Distribution>> for Standard +where + DefaultAllocator: Allocator, + rand_distr::StandardNormal: Distribution, +{ + /// Generate a uniformly distributed random unit vector. + #[inline] + fn sample(&self, rng: &mut G) -> Unit> { + Unit::new_normalize(OVector::from_distribution_generic( + D::name(), + Const::<1>, + &rand_distr::StandardNormal, + rng, + )) + } +} + +/* + * + * Constructors for small matrices and vectors. + * + */ + +macro_rules! transpose_array( + [$($a: ident),*;] => { + [$([$a]),*] + }; + [$($a: ident),*; $($b: ident),*;] => { + [$([$a, $b]),*] + }; + [$($a: ident),*; $($b: ident),*; $($c: ident),*;] => { + [$([$a, $b, $c]),*] + }; + [$($a: ident),*; $($b: ident),*; $($c: ident),*; $($d: ident),*;] => { + [$([$a, $b, $c, $d]),*] + }; + [$($a: ident),*; $($b: ident),*; $($c: ident),*; $($d: ident),*; $($e: ident),*;] => { + [$([$a, $b, $c, $d, $e]),*] + }; + [$($a: ident),*; $($b: ident),*; $($c: ident),*; $($d: ident),*; $($e: ident),*; $($f: ident),*;] => { + [$([$a, $b, $c, $d, $e, $f]),*] + }; +); + +macro_rules! componentwise_constructors_impl( + ($($R: expr, $C: expr, [$($($args: ident),*);*] $(;)*)*) => {$( + impl Matrix, Const<$C>, ArrayStorage> { + /// Initializes this matrix from its components. + #[inline] + #[allow(clippy::too_many_arguments)] + pub const fn new($($($args: T),*),*) -> Self { + unsafe { + Self::from_data_statically_unchecked( + ArrayStorage( + transpose_array![ + $( + $($args),* + ;)* + ] + ) + ) + } + } + } + )*} +); + +componentwise_constructors_impl!( + /* + * Square matrices 1 .. 6. + */ + 2, 2, [m11, m12; + m21, m22]; + 3, 3, [m11, m12, m13; + m21, m22, m23; + m31, m32, m33]; + 4, 4, [m11, m12, m13, m14; + m21, m22, m23, m24; + m31, m32, m33, m34; + m41, m42, m43, m44]; + 5, 5, [m11, m12, m13, m14, m15; + m21, m22, m23, m24, m25; + m31, m32, m33, m34, m35; + m41, m42, m43, m44, m45; + m51, m52, m53, m54, m55]; + 6, 6, [m11, m12, m13, m14, m15, m16; + m21, m22, m23, m24, m25, m26; + m31, m32, m33, m34, m35, m36; + m41, m42, m43, m44, m45, m46; + m51, m52, m53, m54, m55, m56; + m61, m62, m63, m64, m65, m66]; + + /* + * Rectangular matrices with 2 rows. + */ + 2, 3, [m11, m12, m13; + m21, m22, m23]; + 2, 4, [m11, m12, m13, m14; + m21, m22, m23, m24]; + 2, 5, [m11, m12, m13, m14, m15; + m21, m22, m23, m24, m25]; + 2, 6, [m11, m12, m13, m14, m15, m16; + m21, m22, m23, m24, m25, m26]; + + /* + * Rectangular matrices with 3 rows. + */ + 3, 2, [m11, m12; + m21, m22; + m31, m32]; + 3, 4, [m11, m12, m13, m14; + m21, m22, m23, m24; + m31, m32, m33, m34]; + 3, 5, [m11, m12, m13, m14, m15; + m21, m22, m23, m24, m25; + m31, m32, m33, m34, m35]; + 3, 6, [m11, m12, m13, m14, m15, m16; + m21, m22, m23, m24, m25, m26; + m31, m32, m33, m34, m35, m36]; + + /* + * Rectangular matrices with 4 rows. + */ + 4, 2, [m11, m12; + m21, m22; + m31, m32; + m41, m42]; + 4, 3, [m11, m12, m13; + m21, m22, m23; + m31, m32, m33; + m41, m42, m43]; + 4, 5, [m11, m12, m13, m14, m15; + m21, m22, m23, m24, m25; + m31, m32, m33, m34, m35; + m41, m42, m43, m44, m45]; + 4, 6, [m11, m12, m13, m14, m15, m16; + m21, m22, m23, m24, m25, m26; + m31, m32, m33, m34, m35, m36; + m41, m42, m43, m44, m45, m46]; + + /* + * Rectangular matrices with 5 rows. + */ + 5, 2, [m11, m12; + m21, m22; + m31, m32; + m41, m42; + m51, m52]; + 5, 3, [m11, m12, m13; + m21, m22, m23; + m31, m32, m33; + m41, m42, m43; + m51, m52, m53]; + 5, 4, [m11, m12, m13, m14; + m21, m22, m23, m24; + m31, m32, m33, m34; + m41, m42, m43, m44; + m51, m52, m53, m54]; + 5, 6, [m11, m12, m13, m14, m15, m16; + m21, m22, m23, m24, m25, m26; + m31, m32, m33, m34, m35, m36; + m41, m42, m43, m44, m45, m46; + m51, m52, m53, m54, m55, m56]; + + /* + * Rectangular matrices with 6 rows. + */ + 6, 2, [m11, m12; + m21, m22; + m31, m32; + m41, m42; + m51, m52; + m61, m62]; + 6, 3, [m11, m12, m13; + m21, m22, m23; + m31, m32, m33; + m41, m42, m43; + m51, m52, m53; + m61, m62, m63]; + 6, 4, [m11, m12, m13, m14; + m21, m22, m23, m24; + m31, m32, m33, m34; + m41, m42, m43, m44; + m51, m52, m53, m54; + m61, m62, m63, m64]; + 6, 5, [m11, m12, m13, m14, m15; + m21, m22, m23, m24, m25; + m31, m32, m33, m34, m35; + m41, m42, m43, m44, m45; + m51, m52, m53, m54, m55; + m61, m62, m63, m64, m65]; + + /* + * Row vectors 1 .. 6. + */ + 1, 1, [x]; + 1, 2, [x, y]; + 1, 3, [x, y, z]; + 1, 4, [x, y, z, w]; + 1, 5, [x, y, z, w, a]; + 1, 6, [x, y, z, w, a, b]; + + /* + * Column vectors 1 .. 6. + */ + 2, 1, [x; y]; + 3, 1, [x; y; z]; + 4, 1, [x; y; z; w]; + 5, 1, [x; y; z; w; a]; + 6, 1, [x; y; z; w; a; b]; +); + +/* + * + * Axis constructors. + * + */ +impl OVector +where + R: ToTypenum, + T: Scalar + Zero + One, + DefaultAllocator: Allocator, +{ + /// The column vector with `val` as its i-th component. + #[inline] + pub fn ith(i: usize, val: T) -> Self { + let mut res = Self::zeros(); + res[i] = val; + res + } + + /// The column unit vector with `T::one()` as its i-th component. + #[inline] + pub fn ith_axis(i: usize) -> Unit { + Unit::new_unchecked(Self::ith(i, T::one())) + } + + /// The column vector with a 1 as its first component, and zero elsewhere. + #[inline] + pub fn x() -> Self + where + R::Typenum: Cmp, + { + let mut res = Self::zeros(); + unsafe { + *res.vget_unchecked_mut(0) = T::one(); + } + + res + } + + /// The column vector with a 1 as its second component, and zero elsewhere. + #[inline] + pub fn y() -> Self + where + R::Typenum: Cmp, + { + let mut res = Self::zeros(); + unsafe { + *res.vget_unchecked_mut(1) = T::one(); + } + + res + } + + /// The column vector with a 1 as its third component, and zero elsewhere. + #[inline] + pub fn z() -> Self + where + R::Typenum: Cmp, + { + let mut res = Self::zeros(); + unsafe { + *res.vget_unchecked_mut(2) = T::one(); + } + + res + } + + /// The column vector with a 1 as its fourth component, and zero elsewhere. + #[inline] + pub fn w() -> Self + where + R::Typenum: Cmp, + { + let mut res = Self::zeros(); + unsafe { + *res.vget_unchecked_mut(3) = T::one(); + } + + res + } + + /// The column vector with a 1 as its fifth component, and zero elsewhere. + #[inline] + pub fn a() -> Self + where + R::Typenum: Cmp, + { + let mut res = Self::zeros(); + unsafe { + *res.vget_unchecked_mut(4) = T::one(); + } + + res + } + + /// The column vector with a 1 as its sixth component, and zero elsewhere. + #[inline] + pub fn b() -> Self + where + R::Typenum: Cmp, + { + let mut res = Self::zeros(); + unsafe { + *res.vget_unchecked_mut(5) = T::one(); + } + + res + } + + /// The unit column vector with a 1 as its first component, and zero elsewhere. + #[inline] + pub fn x_axis() -> Unit + where + R::Typenum: Cmp, + { + Unit::new_unchecked(Self::x()) + } + + /// The unit column vector with a 1 as its second component, and zero elsewhere. + #[inline] + pub fn y_axis() -> Unit + where + R::Typenum: Cmp, + { + Unit::new_unchecked(Self::y()) + } + + /// The unit column vector with a 1 as its third component, and zero elsewhere. + #[inline] + pub fn z_axis() -> Unit + where + R::Typenum: Cmp, + { + Unit::new_unchecked(Self::z()) + } + + /// The unit column vector with a 1 as its fourth component, and zero elsewhere. + #[inline] + pub fn w_axis() -> Unit + where + R::Typenum: Cmp, + { + Unit::new_unchecked(Self::w()) + } + + /// The unit column vector with a 1 as its fifth component, and zero elsewhere. + #[inline] + pub fn a_axis() -> Unit + where + R::Typenum: Cmp, + { + Unit::new_unchecked(Self::a()) + } + + /// The unit column vector with a 1 as its sixth component, and zero elsewhere. + #[inline] + pub fn b_axis() -> Unit + where + R::Typenum: Cmp, + { + Unit::new_unchecked(Self::b()) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction_view.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction_view.rs new file mode 100644 index 000000000..60c5051eb --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/construction_view.rs @@ -0,0 +1,318 @@ +use crate::base::dimension::{Const, Dim, DimName, Dyn}; +use crate::base::matrix_view::{ViewStorage, ViewStorageMut}; +use crate::base::{MatrixView, MatrixViewMut, Scalar}; + +use num_rational::Ratio; + +/// # Creating matrix views from `&[T]` +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + MatrixView<'a, T, R, C, RStride, CStride> +{ + /// Creates, without bounds checking, a matrix view from an array and with dimensions and strides specified by generic types instances. + /// + /// # Safety + /// This method is unsafe because the input data array is not checked to contain enough elements. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub unsafe fn from_slice_with_strides_generic_unchecked( + data: &'a [T], + start: usize, + nrows: R, + ncols: C, + rstride: RStride, + cstride: CStride, + ) -> Self { + let data = ViewStorage::from_raw_parts( + data.as_ptr().add(start), + (nrows, ncols), + (rstride, cstride), + ); + Self::from_data(data) + } + + /// Creates a matrix view from an array and with dimensions and strides specified by generic types instances. + /// + /// Panics if the input data array dose not contain enough elements. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub fn from_slice_with_strides_generic( + data: &'a [T], + nrows: R, + ncols: C, + rstride: RStride, + cstride: CStride, + ) -> Self { + // NOTE: The assertion implements the following formula, but without subtractions to avoid + // underflow panics: + // len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1 + assert!( + data.len() + cstride.value() + rstride.value() + >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1, + "Matrix view: input data buffer too small." + ); + + unsafe { + Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride) + } + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim> MatrixView<'a, T, R, C> { + /// Creates, without bound-checking, a matrix view from an array and with dimensions specified by generic types instances. + /// + /// # Safety + /// This method is unsafe because the input data array is not checked to contain enough elements. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub unsafe fn from_slice_generic_unchecked( + data: &'a [T], + start: usize, + nrows: R, + ncols: C, + ) -> Self { + Self::from_slice_with_strides_generic_unchecked( + data, start, nrows, ncols, Const::<1>, nrows, + ) + } + + /// Creates a matrix view from an array and with dimensions and strides specified by generic types instances. + /// + /// Panics if the input data array dose not contain enough elements. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub fn from_slice_generic(data: &'a [T], nrows: R, ncols: C) -> Self { + Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows) + } +} + +macro_rules! impl_constructors( + ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { + impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixView<'a, T, $($Dims),*> { + /// Creates a new matrix view from the given data array. + /// + /// Panics if `data` does not contain enough elements. + #[inline] + pub fn from_slice(data: &'a [T], $($args: usize),*) -> Self { + Self::from_slice_generic(data, $($gargs),*) + } + + /// Creates, without bound checking, a new matrix view from the given data array. + /// # Safety + /// `data[start..start+rstride * cstride]` must be within bounds. + #[inline] + pub unsafe fn from_slice_unchecked(data: &'a [T], start: usize, $($args: usize),*) -> Self { + Self::from_slice_generic_unchecked(data, start, $($gargs),*) + } + } + + impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixView<'a, T, $($Dims,)* Dyn, Dyn> { + /// Creates a new matrix view with the specified strides from the given data array. + /// + /// Panics if `data` does not contain enough elements. + #[inline] + pub fn from_slice_with_strides(data: &'a [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self { + Self::from_slice_with_strides_generic(data, $($gargs,)* Dyn(rstride), Dyn(cstride)) + } + + /// Creates, without bound checking, a new matrix view with the specified strides from the given data array. + /// + /// # Safety + /// + /// `start`, `rstride`, and `cstride`, with the given matrix size will not index + /// outside of `data`. + #[inline] + pub unsafe fn from_slice_with_strides_unchecked(data: &'a [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { + Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dyn(rstride), Dyn(cstride)) + } + } + } +); + +// TODO: this is not very pretty. We could find a better call syntax. +impl_constructors!(R, C; // Arguments for Matrix +=> R: DimName, => C: DimName; // Type parameters for impl +R::name(), C::name(); // Arguments for `_generic` constructors. +); // Arguments for non-generic constructors. + +impl_constructors!(R, Dyn; + => R: DimName; + R::name(), Dyn(ncols); + ncols); + +impl_constructors!(Dyn, C; + => C: DimName; + Dyn(nrows), C::name(); + nrows); + +impl_constructors!(Dyn, Dyn; + ; + Dyn(nrows), Dyn(ncols); + nrows, ncols); + +/// # Creating mutable matrix views from `&mut [T]` +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + MatrixViewMut<'a, T, R, C, RStride, CStride> +{ + /// Creates, without bound-checking, a mutable matrix view from an array and with dimensions and strides specified by generic types instances. + /// + /// # Safety + /// This method is unsafe because the input data array is not checked to contain enough elements. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub unsafe fn from_slice_with_strides_generic_unchecked( + data: &'a mut [T], + start: usize, + nrows: R, + ncols: C, + rstride: RStride, + cstride: CStride, + ) -> Self { + let data = ViewStorageMut::from_raw_parts( + data.as_mut_ptr().add(start), + (nrows, ncols), + (rstride, cstride), + ); + Self::from_data(data) + } + + /// Creates a mutable matrix view from an array and with dimensions and strides specified by generic types instances. + /// + /// Panics if the input data array dose not contain enough elements. + /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub fn from_slice_with_strides_generic( + data: &'a mut [T], + nrows: R, + ncols: C, + rstride: RStride, + cstride: CStride, + ) -> Self { + // NOTE: The assertion implements the following formula, but without subtractions to avoid + // underflow panics: + // len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1 + assert!( + data.len() + cstride.value() + rstride.value() + >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1, + "Matrix view: input data buffer too small." + ); + + assert!( + { + let nrows = nrows.value(); + let ncols = ncols.value(); + let rstride = rstride.value(); + let cstride = cstride.value(); + + nrows * ncols <= 1 + || match (rstride, cstride) { + (0, 0) => false, // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)], + (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)], + (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)], + (_, _) => { + // otherwise: matrix[(0, numer)] == index[(denom, 0)] + let ratio = Ratio::new(rstride, cstride); + nrows <= *ratio.denom() || ncols <= *ratio.numer() + } + } + }, + "Matrix view: dimensions and strides result in aliased indices." + ); + + unsafe { + Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride) + } + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim> MatrixViewMut<'a, T, R, C> { + /// Creates, without bound-checking, a mutable matrix view from an array and with dimensions specified by generic types instances. + /// + /// # Safety + /// This method is unsafe because the input data array is not checked to contain enough elements. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub unsafe fn from_slice_generic_unchecked( + data: &'a mut [T], + start: usize, + nrows: R, + ncols: C, + ) -> Self { + Self::from_slice_with_strides_generic_unchecked( + data, start, nrows, ncols, Const::<1>, nrows, + ) + } + + /// Creates a mutable matrix view from an array and with dimensions and strides specified by generic types instances. + /// + /// Panics if the input data array dose not contain enough elements. + /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`. + #[inline] + pub fn from_slice_generic(data: &'a mut [T], nrows: R, ncols: C) -> Self { + Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows) + } +} + +macro_rules! impl_constructors_mut( + ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => { + impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixViewMut<'a, T, $($Dims),*> { + /// Creates a new mutable matrix view from the given data array. + /// + /// Panics if `data` does not contain enough elements. + #[inline] + pub fn from_slice(data: &'a mut [T], $($args: usize),*) -> Self { + Self::from_slice_generic(data, $($gargs),*) + } + + /// Creates, without bound checking, a new mutable matrix view from the given data array. + /// + /// # Safety + /// + /// `data[start..start+(R * C)]` must be within bounds. + #[inline] + pub unsafe fn from_slice_unchecked(data: &'a mut [T], start: usize, $($args: usize),*) -> Self { + Self::from_slice_generic_unchecked(data, start, $($gargs),*) + } + } + + impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixViewMut<'a, T, $($Dims,)* Dyn, Dyn> { + /// Creates a new mutable matrix view with the specified strides from the given data array. + /// + /// Panics if `data` does not contain enough elements. + #[inline] + pub fn from_slice_with_strides_mut(data: &'a mut [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self { + Self::from_slice_with_strides_generic( + data, $($gargs,)* Dyn(rstride), Dyn(cstride)) + } + + /// Creates, without bound checking, a new mutable matrix view with the specified strides from the given data array. + /// # Safety + /// `data[start..start+rstride * cstride]` must be within bounds. + #[inline] + pub unsafe fn from_slice_with_strides_unchecked(data: &'a mut [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { + Self::from_slice_with_strides_generic_unchecked( + data, start, $($gargs,)* Dyn(rstride), Dyn(cstride)) + } + } + } +); + +// TODO: this is not very pretty. We could find a better call syntax. +impl_constructors_mut!(R, C; // Arguments for Matrix +=> R: DimName, => C: DimName; // Type parameters for impl +R::name(), C::name(); // Arguments for `_generic` constructors. +); // Arguments for non-generic constructors. + +impl_constructors_mut!(R, Dyn; + => R: DimName; + R::name(), Dyn(ncols); + ncols); + +impl_constructors_mut!(Dyn, C; + => C: DimName; + Dyn(nrows), C::name(); + nrows); + +impl_constructors_mut!(Dyn, Dyn; + ; + Dyn(nrows), Dyn(ncols); + nrows, ncols); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/conversion.rs new file mode 100644 index 000000000..e765f8e89 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/conversion.rs @@ -0,0 +1,657 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; +use simba::scalar::{SubsetOf, SupersetOf}; +use std::borrow::{Borrow, BorrowMut}; +use std::convert::{AsMut, AsRef, From, Into}; + +use simba::simd::{PrimitiveSimdValue, SimdValue}; + +use crate::base::allocator::{Allocator, SameShapeAllocator}; +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{ + Const, Dim, U1, U10, U11, U12, U13, U14, U15, U16, U2, U3, U4, U5, U6, U7, U8, U9, +}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::dimension::{DimName, Dyn}; +use crate::base::iter::{MatrixIter, MatrixIterMut}; +use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut}; +use crate::base::{ + ArrayStorage, DVectorView, DVectorViewMut, DefaultAllocator, Matrix, MatrixView, MatrixViewMut, + OMatrix, Scalar, +}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::{DVector, RowDVector, VecStorage}; +use crate::base::{ViewStorage, ViewStorageMut}; +use crate::constraint::DimEq; +use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector, VectorView, VectorViewMut}; +use std::mem::MaybeUninit; + +// TODO: too bad this won't work for slice conversions. +impl SubsetOf> for OMatrix +where + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, + T1: Scalar, + T2: Scalar + SupersetOf, + DefaultAllocator: Allocator + Allocator + SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, +{ + #[inline] + fn to_superset(&self) -> OMatrix { + let (nrows, ncols) = self.shape(); + let nrows2 = R2::from_usize(nrows); + let ncols2 = C2::from_usize(ncols); + let mut res = Matrix::uninit(nrows2, ncols2); + + for i in 0..nrows { + for j in 0..ncols { + // Safety: all indices are in range. + unsafe { + *res.get_unchecked_mut((i, j)) = + MaybeUninit::new(T2::from_subset(self.get_unchecked((i, j)))); + } + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + #[inline] + fn is_in_subset(m: &OMatrix) -> bool { + m.iter().all(|e| e.is_in_subset()) + } + + #[inline] + fn from_superset_unchecked(m: &OMatrix) -> Self { + let (nrows2, ncols2) = m.shape(); + let nrows = R1::from_usize(nrows2); + let ncols = C1::from_usize(ncols2); + let mut res = Matrix::uninit(nrows, ncols); + + for i in 0..nrows2 { + for j in 0..ncols2 { + // Safety: all indices are in range. + unsafe { + *res.get_unchecked_mut((i, j)) = + MaybeUninit::new(m.get_unchecked((i, j)).to_subset_unchecked()) + } + } + } + + unsafe { res.assume_init() } + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorage> IntoIterator + for &'a Matrix +{ + type Item = &'a T; + type IntoIter = MatrixIter<'a, T, R, C, S>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> IntoIterator + for Matrix> +{ + type Item = &'a T; + type IntoIter = MatrixIter<'a, T, R, C, ViewStorage<'a, T, R, C, RStride, CStride>>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + MatrixIter::new_owned(self.data) + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: RawStorageMut> IntoIterator + for &'a mut Matrix +{ + type Item = &'a mut T; + type IntoIter = MatrixIterMut<'a, T, R, C, S>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> IntoIterator + for Matrix> +{ + type Item = &'a mut T; + type IntoIter = MatrixIterMut<'a, T, R, C, ViewStorageMut<'a, T, R, C, RStride, CStride>>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + MatrixIterMut::new_owned_mut(self.data) + } +} + +impl From<[T; D]> for SVector { + #[inline] + fn from(arr: [T; D]) -> Self { + unsafe { Self::from_data_statically_unchecked(ArrayStorage([arr; 1])) } + } +} + +impl From> for [T; D] { + #[inline] + fn from(vec: SVector) -> Self { + // TODO: unfortunately, we must clone because we can move out of an array. + vec.data.0[0].clone() + } +} + +impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const D: usize> + From, RStride, CStride>> for [T; D] +{ + #[inline] + fn from(vec: VectorView<'a, T, Const, RStride, CStride>) -> Self { + vec.into_owned().into() + } +} + +impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const D: usize> + From, RStride, CStride>> for [T; D] +{ + #[inline] + fn from(vec: VectorViewMut<'a, T, Const, RStride, CStride>) -> Self { + vec.into_owned().into() + } +} + +impl From<[T; D]> for RowSVector +where + Const: IsNotStaticOne, +{ + #[inline] + fn from(arr: [T; D]) -> Self { + SVector::::from(arr).transpose() + } +} + +impl From> for [T; D] +where + Const: IsNotStaticOne, +{ + #[inline] + fn from(vec: RowSVector) -> [T; D] { + vec.transpose().into() + } +} + +macro_rules! impl_from_into_asref_1D( + ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$( + impl AsRef<[T; $SZ]> for Matrix + where T: Scalar, + S: RawStorage + IsContiguous { + #[inline] + fn as_ref(&self) -> &[T; $SZ] { + // Safety: this is OK thanks to the IsContiguous trait. + unsafe { + &*(self.data.ptr() as *const [T; $SZ]) + } + } + } + + impl AsMut<[T; $SZ]> for Matrix + where T: Scalar, + S: RawStorageMut + IsContiguous { + #[inline] + fn as_mut(&mut self) -> &mut [T; $SZ] { + // Safety: this is OK thanks to the IsContiguous trait. + unsafe { + &mut *(self.data.ptr_mut() as *mut [T; $SZ]) + } + } + } + )*} +); + +// Implement for vectors of dimension 1 .. 16. +impl_from_into_asref_1D!( + // Row vectors. + (U1, U1 ) => 1; (U1, U2 ) => 2; (U1, U3 ) => 3; (U1, U4 ) => 4; + (U1, U5 ) => 5; (U1, U6 ) => 6; (U1, U7 ) => 7; (U1, U8 ) => 8; + (U1, U9 ) => 9; (U1, U10) => 10; (U1, U11) => 11; (U1, U12) => 12; + (U1, U13) => 13; (U1, U14) => 14; (U1, U15) => 15; (U1, U16) => 16; + + // Column vectors. + (U2 , U1) => 2; (U3 , U1) => 3; (U4 , U1) => 4; + (U5 , U1) => 5; (U6 , U1) => 6; (U7 , U1) => 7; (U8 , U1) => 8; + (U9 , U1) => 9; (U10, U1) => 10; (U11, U1) => 11; (U12, U1) => 12; + (U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16; +); + +impl From<[[T; R]; C]> for SMatrix { + #[inline] + fn from(arr: [[T; R]; C]) -> Self { + unsafe { Self::from_data_statically_unchecked(ArrayStorage(arr)) } + } +} + +impl From> for [[T; R]; C] { + #[inline] + fn from(mat: SMatrix) -> Self { + mat.data.0 + } +} + +impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const R: usize, const C: usize> + From, Const, RStride, CStride>> for [[T; R]; C] +{ + #[inline] + fn from(mat: MatrixView<'a, T, Const, Const, RStride, CStride>) -> Self { + mat.into_owned().into() + } +} + +impl<'a, T: Scalar, RStride: Dim, CStride: Dim, const R: usize, const C: usize> + From, Const, RStride, CStride>> for [[T; R]; C] +{ + #[inline] + fn from(mat: MatrixViewMut<'a, T, Const, Const, RStride, CStride>) -> Self { + mat.into_owned().into() + } +} + +macro_rules! impl_from_into_asref_borrow_2D( + + //does the impls on one case for either AsRef/AsMut and Borrow/BorrowMut + ( + ($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr); + $Ref:ident.$ref:ident(), $Mut:ident.$mut:ident() + ) => { + impl $Ref<[[T; $SZRows]; $SZCols]> for Matrix + where S: RawStorage + IsContiguous { + #[inline] + fn $ref(&self) -> &[[T; $SZRows]; $SZCols] { + // Safety: OK thanks to the IsContiguous trait. + unsafe { + &*(self.data.ptr() as *const [[T; $SZRows]; $SZCols]) + } + } + } + + impl $Mut<[[T; $SZRows]; $SZCols]> for Matrix + where S: RawStorageMut + IsContiguous { + #[inline] + fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] { + // Safety: OK thanks to the IsContiguous trait. + unsafe { + &mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols]) + } + } + } + }; + + //collects the mappings from typenum pairs to consts + ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( + impl_from_into_asref_borrow_2D!( + ($NRows, $NCols) => ($SZRows, $SZCols); AsRef.as_ref(), AsMut.as_mut() + ); + impl_from_into_asref_borrow_2D!( + ($NRows, $NCols) => ($SZRows, $SZCols); Borrow.borrow(), BorrowMut.borrow_mut() + ); + )*} +); + +// Implement for matrices with shape 2x2 .. 6x6. +impl_from_into_asref_borrow_2D!( + (U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6); + (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6); + (U4, U2) => (4, 2); (U4, U3) => (4, 3); (U4, U4) => (4, 4); (U4, U5) => (4, 5); (U4, U6) => (4, 6); + (U5, U2) => (5, 2); (U5, U3) => (5, 3); (U5, U4) => (5, 4); (U5, U5) => (5, 5); (U5, U6) => (5, 6); + (U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6); +); + +impl<'a, T, RStride, CStride, const R: usize, const C: usize> + From, Const, RStride, CStride>> + for Matrix, Const, ArrayStorage> +where + T: Scalar, + RStride: Dim, + CStride: Dim, +{ + fn from(matrix_view: MatrixView<'a, T, Const, Const, RStride, CStride>) -> Self { + matrix_view.into_owned() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, T, C, RStride, CStride> From> + for Matrix> +where + T: Scalar, + C: Dim, + RStride: Dim, + CStride: Dim, +{ + fn from(matrix_view: MatrixView<'a, T, Dyn, C, RStride, CStride>) -> Self { + matrix_view.into_owned() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, T, R, RStride, CStride> From> + for Matrix> +where + T: Scalar, + R: DimName, + RStride: Dim, + CStride: Dim, +{ + fn from(matrix_view: MatrixView<'a, T, R, Dyn, RStride, CStride>) -> Self { + matrix_view.into_owned() + } +} + +impl<'a, T, RStride, CStride, const R: usize, const C: usize> + From, Const, RStride, CStride>> + for Matrix, Const, ArrayStorage> +where + T: Scalar, + RStride: Dim, + CStride: Dim, +{ + fn from(matrix_view: MatrixViewMut<'a, T, Const, Const, RStride, CStride>) -> Self { + matrix_view.into_owned() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, T, C, RStride, CStride> From> + for Matrix> +where + T: Scalar, + C: Dim, + RStride: Dim, + CStride: Dim, +{ + fn from(matrix_view: MatrixViewMut<'a, T, Dyn, C, RStride, CStride>) -> Self { + matrix_view.into_owned() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, T, R, RStride, CStride> From> + for Matrix> +where + T: Scalar, + R: DimName, + RStride: Dim, + CStride: Dim, +{ + fn from(matrix_view: MatrixViewMut<'a, T, R, Dyn, RStride, CStride>) -> Self { + matrix_view.into_owned() + } +} + +impl<'a, T, R, C, RView, CView, RStride, CStride, S> From<&'a Matrix> + for MatrixView<'a, T, RView, CView, RStride, CStride> +where + R: Dim, + C: Dim, + RView: Dim, + CView: Dim, + RStride: Dim, + CStride: Dim, + S: RawStorage, + ShapeConstraint: + DimEq + DimEq + DimEq + DimEq, +{ + fn from(m: &'a Matrix) -> Self { + let (row, col) = m.shape_generic(); + let rows_result = RView::from_usize(row.value()); + let cols_result = CView::from_usize(col.value()); + + let (rstride, cstride) = m.strides(); + + let rstride_result = RStride::from_usize(rstride); + let cstride_result = CStride::from_usize(cstride); + + unsafe { + let data = ViewStorage::from_raw_parts( + m.data.ptr(), + (rows_result, cols_result), + (rstride_result, cstride_result), + ); + Matrix::from_data_statically_unchecked(data) + } + } +} + +impl<'a, T, R, C, RView, CView, RStride, CStride, S> From<&'a mut Matrix> + for MatrixView<'a, T, RView, CView, RStride, CStride> +where + R: Dim, + C: Dim, + RView: Dim, + CView: Dim, + RStride: Dim, + CStride: Dim, + S: RawStorage, + ShapeConstraint: + DimEq + DimEq + DimEq + DimEq, +{ + fn from(m: &'a mut Matrix) -> Self { + let (row, col) = m.shape_generic(); + let rows_result = RView::from_usize(row.value()); + let cols_result = CView::from_usize(col.value()); + + let (rstride, cstride) = m.strides(); + + let rstride_result = RStride::from_usize(rstride); + let cstride_result = CStride::from_usize(cstride); + + unsafe { + let data = ViewStorage::from_raw_parts( + m.data.ptr(), + (rows_result, cols_result), + (rstride_result, cstride_result), + ); + Matrix::from_data_statically_unchecked(data) + } + } +} + +impl<'a, T, R, C, RView, CView, RStride, CStride, S> From<&'a mut Matrix> + for MatrixViewMut<'a, T, RView, CView, RStride, CStride> +where + R: Dim, + C: Dim, + RView: Dim, + CView: Dim, + RStride: Dim, + CStride: Dim, + S: RawStorageMut, + ShapeConstraint: + DimEq + DimEq + DimEq + DimEq, +{ + fn from(m: &'a mut Matrix) -> Self { + let (row, col) = m.shape_generic(); + let rows_result = RView::from_usize(row.value()); + let cols_result = CView::from_usize(col.value()); + + let (rstride, cstride) = m.strides(); + + let rstride_result = RStride::from_usize(rstride); + let cstride_result = CStride::from_usize(cstride); + + unsafe { + let data = ViewStorageMut::from_raw_parts( + m.data.ptr_mut(), + (rows_result, cols_result), + (rstride_result, cstride_result), + ); + Matrix::from_data_statically_unchecked(data) + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl From> for DVector { + #[inline] + fn from(vec: Vec) -> Self { + Self::from_vec(vec) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl From> for RowDVector { + #[inline] + fn from(vec: Vec) -> Self { + Self::from_vec(vec) + } +} + +impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorage + IsContiguous> + From<&'a Matrix> for &'a [T] +{ + #[inline] + fn from(matrix: &'a Matrix) -> Self { + matrix.as_slice() + } +} + +impl<'a, T: Scalar + Copy, R: Dim, C: Dim, S: RawStorageMut + IsContiguous> + From<&'a mut Matrix> for &'a mut [T] +{ + #[inline] + fn from(matrix: &'a mut Matrix) -> Self { + matrix.as_mut_slice() + } +} + +impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorView<'a, T> { + #[inline] + fn from(slice: &'a [T]) -> Self { + Self::from_slice(slice, slice.len()) + } +} + +impl<'a, T: Scalar> From> for &'a [T] { + fn from(vec: DVectorView<'a, T>) -> &'a [T] { + vec.data.into_slice() + } +} + +impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorViewMut<'a, T> { + #[inline] + fn from(slice: &'a mut [T]) -> Self { + Self::from_slice(slice, slice.len()) + } +} + +impl<'a, T: Scalar> From> for &'a mut [T] { + fn from(vec: DVectorViewMut<'a, T>) -> &'a mut [T] { + vec.data.into_slice_mut() + } +} + +impl From<[OMatrix; 2]> + for OMatrix +where + T: From<[::Element; 2]>, + T::Element: Scalar + SimdValue, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [OMatrix; 2]) -> Self { + let (nrows, ncols) = arr[0].shape_generic(); + + Self::from_fn_generic(nrows, ncols, |i, j| { + [arr[0][(i, j)].clone(), arr[1][(i, j)].clone()].into() + }) + } +} + +impl From<[OMatrix; 4]> + for OMatrix +where + T: From<[::Element; 4]>, + T::Element: Scalar + SimdValue, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [OMatrix; 4]) -> Self { + let (nrows, ncols) = arr[0].shape_generic(); + + Self::from_fn_generic(nrows, ncols, |i, j| { + [ + arr[0][(i, j)].clone(), + arr[1][(i, j)].clone(), + arr[2][(i, j)].clone(), + arr[3][(i, j)].clone(), + ] + .into() + }) + } +} + +impl From<[OMatrix; 8]> + for OMatrix +where + T: From<[::Element; 8]>, + T::Element: Scalar + SimdValue, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [OMatrix; 8]) -> Self { + let (nrows, ncols) = arr[0].shape_generic(); + + Self::from_fn_generic(nrows, ncols, |i, j| { + [ + arr[0][(i, j)].clone(), + arr[1][(i, j)].clone(), + arr[2][(i, j)].clone(), + arr[3][(i, j)].clone(), + arr[4][(i, j)].clone(), + arr[5][(i, j)].clone(), + arr[6][(i, j)].clone(), + arr[7][(i, j)].clone(), + ] + .into() + }) + } +} + +impl From<[OMatrix; 16]> + for OMatrix +where + T: From<[::Element; 16]>, + T::Element: Scalar + SimdValue, + DefaultAllocator: Allocator, +{ + fn from(arr: [OMatrix; 16]) -> Self { + let (nrows, ncols) = arr[0].shape_generic(); + + Self::from_fn_generic(nrows, ncols, |i, j| { + [ + arr[0][(i, j)].clone(), + arr[1][(i, j)].clone(), + arr[2][(i, j)].clone(), + arr[3][(i, j)].clone(), + arr[4][(i, j)].clone(), + arr[5][(i, j)].clone(), + arr[6][(i, j)].clone(), + arr[7][(i, j)].clone(), + arr[8][(i, j)].clone(), + arr[9][(i, j)].clone(), + arr[10][(i, j)].clone(), + arr[11][(i, j)].clone(), + arr[12][(i, j)].clone(), + arr[13][(i, j)].clone(), + arr[14][(i, j)].clone(), + arr[15][(i, j)].clone(), + ] + .into() + }) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/coordinates.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/coordinates.rs new file mode 100644 index 000000000..a2cabd1d0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/coordinates.rs @@ -0,0 +1,236 @@ +#![allow(missing_docs)] + +//! Structures to which matrices and vector can be auto-dereferenced (through `Deref`) to access +//! components using their names. For example, if `v` is a 3D vector, one can write `v.z` instead +//! of `v[2]`. + +use std::ops::{Deref, DerefMut}; + +use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; +use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut}; +use crate::base::{Matrix, Scalar}; + +/* + * + * Give coordinates to owned Vector{1 .. 6} and Matrix{1 .. 6} + * + */ + +macro_rules! coords_impl( + ($T: ident; $($comps: ident),*) => { + /// Data structure used to provide access to matrix and vector coordinates with the dot + /// notation, e.g., `v.x` is the same as `v[0]` for a vector. + #[repr(C)] + #[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)] + #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] + pub struct $T { + $(pub $comps: T),* + } + } +); + +macro_rules! deref_impl( + ($R: ty, $C: ty; $Target: ident) => { + impl Deref for Matrix + where S: RawStorage + IsContiguous { + type Target = $Target; + + #[inline] + fn deref(&self) -> &Self::Target { + // Safety: this is OK because of the IsContiguous trait. + unsafe { &*(self.data.ptr() as *const Self::Target) } + } + } + + impl DerefMut for Matrix + where S: RawStorageMut + IsContiguous { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + // Safety: this is OK because of the IsContiguous trait. + unsafe { &mut *(self.data.ptr_mut() as *mut Self::Target) } + } + } + } +); + +/* + * + * Vector coordinates. + * + */ +coords_impl!(X; x); +coords_impl!(XY; x, y); +coords_impl!(XYZ; x, y, z); +coords_impl!(XYZW; x, y, z, w); +coords_impl!(XYZWA; x, y, z, w, a); +coords_impl!(XYZWAB; x, y, z, w, a, b); +coords_impl!(IJKW; i, j, k, w); + +/* + * Rectangular matrices with 2 rows. + */ +coords_impl!(M2x2; m11, m21, + m12, m22); +coords_impl!(M2x3; m11, m21, + m12, m22, + m13, m23); +coords_impl!(M2x4; m11, m21, + m12, m22, + m13, m23, + m14, m24); +coords_impl!(M2x5; m11, m21, + m12, m22, + m13, m23, + m14, m24, + m15, m25); +coords_impl!(M2x6; m11, m21, + m12, m22, + m13, m23, + m14, m24, + m15, m25, + m16, m26); + +/* + * Rectangular matrices with 3 rows. + */ +coords_impl!(M3x2; m11, m21, m31, + m12, m22, m32); +coords_impl!(M3x3; m11, m21, m31, + m12, m22, m32, + m13, m23, m33); +coords_impl!(M3x4; m11, m21, m31, + m12, m22, m32, + m13, m23, m33, + m14, m24, m34); +coords_impl!(M3x5; m11, m21, m31, + m12, m22, m32, + m13, m23, m33, + m14, m24, m34, + m15, m25, m35); +coords_impl!(M3x6; m11, m21, m31, + m12, m22, m32, + m13, m23, m33, + m14, m24, m34, + m15, m25, m35, + m16, m26, m36); + +/* + * Rectangular matrices with 4 rows. + */ +coords_impl!(M4x2; m11, m21, m31, m41, + m12, m22, m32, m42); +coords_impl!(M4x3; m11, m21, m31, m41, + m12, m22, m32, m42, + m13, m23, m33, m43); +coords_impl!(M4x4; m11, m21, m31, m41, + m12, m22, m32, m42, + m13, m23, m33, m43, + m14, m24, m34, m44); +coords_impl!(M4x5; m11, m21, m31, m41, + m12, m22, m32, m42, + m13, m23, m33, m43, + m14, m24, m34, m44, + m15, m25, m35, m45); +coords_impl!(M4x6; m11, m21, m31, m41, + m12, m22, m32, m42, + m13, m23, m33, m43, + m14, m24, m34, m44, + m15, m25, m35, m45, + m16, m26, m36, m46); + +/* + * Rectangular matrices with 5 rows. + */ +coords_impl!(M5x2; m11, m21, m31, m41, m51, + m12, m22, m32, m42, m52); +coords_impl!(M5x3; m11, m21, m31, m41, m51, + m12, m22, m32, m42, m52, + m13, m23, m33, m43, m53); +coords_impl!(M5x4; m11, m21, m31, m41, m51, + m12, m22, m32, m42, m52, + m13, m23, m33, m43, m53, + m14, m24, m34, m44, m54); +coords_impl!(M5x5; m11, m21, m31, m41, m51, + m12, m22, m32, m42, m52, + m13, m23, m33, m43, m53, + m14, m24, m34, m44, m54, + m15, m25, m35, m45, m55); +coords_impl!(M5x6; m11, m21, m31, m41, m51, + m12, m22, m32, m42, m52, + m13, m23, m33, m43, m53, + m14, m24, m34, m44, m54, + m15, m25, m35, m45, m55, + m16, m26, m36, m46, m56); + +/* + * Rectangular matrices with 6 rows. + */ + +coords_impl!(M6x2; m11, m21, m31, m41, m51, m61, + m12, m22, m32, m42, m52, m62); +coords_impl!(M6x3; m11, m21, m31, m41, m51, m61, + m12, m22, m32, m42, m52, m62, + m13, m23, m33, m43, m53, m63); +coords_impl!(M6x4; m11, m21, m31, m41, m51, m61, + m12, m22, m32, m42, m52, m62, + m13, m23, m33, m43, m53, m63, + m14, m24, m34, m44, m54, m64); +coords_impl!(M6x5; m11, m21, m31, m41, m51, m61, + m12, m22, m32, m42, m52, m62, + m13, m23, m33, m43, m53, m63, + m14, m24, m34, m44, m54, m64, + m15, m25, m35, m45, m55, m65); +coords_impl!(M6x6; m11, m21, m31, m41, m51, m61, + m12, m22, m32, m42, m52, m62, + m13, m23, m33, m43, m53, m63, + m14, m24, m34, m44, m54, m64, + m15, m25, m35, m45, m55, m65, + m16, m26, m36, m46, m56, m66); + +/* + * + * Attach coordinates to matrices. + * + */ +deref_impl!(U1, U1; X); +deref_impl!(U2, U1; XY); +deref_impl!(U3, U1; XYZ); +deref_impl!(U4, U1; XYZW); +deref_impl!(U5, U1; XYZWA); +deref_impl!(U6, U1; XYZWAB); + +deref_impl!(U1, U2; XY); +deref_impl!(U1, U3; XYZ); +deref_impl!(U1, U4; XYZW); +deref_impl!(U1, U5; XYZWA); +deref_impl!(U1, U6; XYZWAB); + +deref_impl!(U2, U2; M2x2); +deref_impl!(U2, U3; M2x3); +deref_impl!(U2, U4; M2x4); +deref_impl!(U2, U5; M2x5); +deref_impl!(U2, U6; M2x6); + +deref_impl!(U3, U2; M3x2); +deref_impl!(U3, U3; M3x3); +deref_impl!(U3, U4; M3x4); +deref_impl!(U3, U5; M3x5); +deref_impl!(U3, U6; M3x6); + +deref_impl!(U4, U2; M4x2); +deref_impl!(U4, U3; M4x3); +deref_impl!(U4, U4; M4x4); +deref_impl!(U4, U5; M4x5); +deref_impl!(U4, U6; M4x6); + +deref_impl!(U5, U2; M5x2); +deref_impl!(U5, U3; M5x3); +deref_impl!(U5, U4; M5x4); +deref_impl!(U5, U5; M5x5); +deref_impl!(U5, U6; M5x6); + +deref_impl!(U6, U2; M6x2); +deref_impl!(U6, U3; M6x3); +deref_impl!(U6, U4; M6x4); +deref_impl!(U6, U5; M6x5); +deref_impl!(U6, U6; M6x6); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/default_allocator.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/default_allocator.rs new file mode 100644 index 000000000..86545e6b3 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/default_allocator.rs @@ -0,0 +1,339 @@ +//! The default matrix data storage allocator. +//! +//! This will use stack-allocated buffers for matrices with dimensions known at compile-time, and +//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time. + +use std::cmp; +use std::ptr; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + +use super::Const; +use crate::base::allocator::{Allocator, Reallocator}; +use crate::base::array_storage::ArrayStorage; +use crate::base::dimension::Dim; +#[cfg(any(feature = "alloc", feature = "std"))] +use crate::base::dimension::{DimName, Dyn}; +use crate::base::storage::{RawStorage, RawStorageMut, Storage}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::vec_storage::VecStorage; +use crate::base::Scalar; +#[cfg(any(feature = "std", feature = "alloc"))] +use std::mem::ManuallyDrop; +use std::mem::MaybeUninit; + +/* + * + * Allocator. + * + */ +/// An allocator based on [`ArrayStorage`] and [`VecStorage`] for statically-sized and dynamically-sized +/// matrices respectively. +#[derive(Copy, Clone, Debug)] +pub struct DefaultAllocator; + +// Static - Static +impl Allocator, Const> for DefaultAllocator { + type Buffer = ArrayStorage; + type BufferUninit = ArrayStorage, R, C>; + + #[inline(always)] + fn allocate_uninit(_: Const, _: Const) -> ArrayStorage, R, C> { + // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. + let array: [[MaybeUninit; R]; C] = unsafe { MaybeUninit::uninit().assume_init() }; + ArrayStorage(array) + } + + #[inline(always)] + unsafe fn assume_init( + uninit: ArrayStorage, R, C>, + ) -> ArrayStorage { + // Safety: + // * The caller guarantees that all elements of the array are initialized + // * `MaybeUninit` and T are guaranteed to have the same layout + // * `MaybeUninit` does not drop, so there are no double-frees + // And thus the conversion is safe + ArrayStorage((&uninit as *const _ as *const [_; C]).read()) + } + + #[inline] + fn allocate_from_iterator>( + nrows: Const, + ncols: Const, + iter: I, + ) -> Self::Buffer { + let mut res = Self::allocate_uninit(nrows, ncols); + let mut count = 0; + + // Safety: conversion to a slice is OK because the Buffer is known to be contiguous. + let res_slice = unsafe { res.as_mut_slice_unchecked() }; + for (res, e) in res_slice.iter_mut().zip(iter.into_iter()) { + *res = MaybeUninit::new(e); + count += 1; + } + + assert!( + count == nrows.value() * ncols.value(), + "Matrix init. from iterator: iterator not long enough." + ); + + // Safety: the assertion above made sure that the iterator + // yielded enough elements to initialize our matrix. + unsafe { , Const>>::assume_init(res) } + } +} + +// Dyn - Static +// Dyn - Dyn +#[cfg(any(feature = "std", feature = "alloc"))] +impl Allocator for DefaultAllocator { + type Buffer = VecStorage; + type BufferUninit = VecStorage, Dyn, C>; + + #[inline] + fn allocate_uninit(nrows: Dyn, ncols: C) -> VecStorage, Dyn, C> { + let mut data = Vec::new(); + let length = nrows.value() * ncols.value(); + data.reserve_exact(length); + data.resize_with(length, MaybeUninit::uninit); + VecStorage::new(nrows, ncols, data) + } + + #[inline] + unsafe fn assume_init( + uninit: VecStorage, Dyn, C>, + ) -> VecStorage { + // Avoids a double-drop. + let (nrows, ncols) = uninit.shape(); + let vec: Vec<_> = uninit.into(); + let mut md = ManuallyDrop::new(vec); + + // Safety: + // - MaybeUninit has the same alignment and layout as T. + // - The length and capacity come from a valid vector. + let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()); + + VecStorage::new(nrows, ncols, new_data) + } + + #[inline] + fn allocate_from_iterator>( + nrows: Dyn, + ncols: C, + iter: I, + ) -> Self::Buffer { + let it = iter.into_iter(); + let res: Vec = it.collect(); + assert!(res.len() == nrows.value() * ncols.value(), + "Allocation from iterator error: the iterator did not yield the correct number of elements."); + + VecStorage::new(nrows, ncols, res) + } +} + +// Static - Dyn +#[cfg(any(feature = "std", feature = "alloc"))] +impl Allocator for DefaultAllocator { + type Buffer = VecStorage; + type BufferUninit = VecStorage, R, Dyn>; + + #[inline] + fn allocate_uninit(nrows: R, ncols: Dyn) -> VecStorage, R, Dyn> { + let mut data = Vec::new(); + let length = nrows.value() * ncols.value(); + data.reserve_exact(length); + data.resize_with(length, MaybeUninit::uninit); + + VecStorage::new(nrows, ncols, data) + } + + #[inline] + unsafe fn assume_init( + uninit: VecStorage, R, Dyn>, + ) -> VecStorage { + // Avoids a double-drop. + let (nrows, ncols) = uninit.shape(); + let vec: Vec<_> = uninit.into(); + let mut md = ManuallyDrop::new(vec); + + // Safety: + // - MaybeUninit has the same alignment and layout as T. + // - The length and capacity come from a valid vector. + let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()); + + VecStorage::new(nrows, ncols, new_data) + } + + #[inline] + fn allocate_from_iterator>( + nrows: R, + ncols: Dyn, + iter: I, + ) -> Self::Buffer { + let it = iter.into_iter(); + let res: Vec = it.collect(); + assert!(res.len() == nrows.value() * ncols.value(), + "Allocation from iterator error: the iterator did not yield the correct number of elements."); + + VecStorage::new(nrows, ncols, res) + } +} + +/* + * + * Reallocator. + * + */ +// Anything -> Static × Static +impl + Reallocator, Const> for DefaultAllocator +where + RFrom: Dim, + CFrom: Dim, + Self: Allocator, +{ + #[inline] + unsafe fn reallocate_copy( + rto: Const, + cto: Const, + buf: >::Buffer, + ) -> ArrayStorage, RTO, CTO> { + let mut res = , Const>>::allocate_uninit(rto, cto); + + let (rfrom, cfrom) = buf.shape(); + + let len_from = rfrom.value() * cfrom.value(); + let len_to = rto.value() * cto.value(); + let len_copied = cmp::min(len_from, len_to); + ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied); + + // Safety: + // - We don’t care about dropping elements because the caller is responsible for dropping things. + // - We forget `buf` so that we don’t drop the other elements, but ensure the buffer itself is cleaned up. + buf.forget_elements(); + + res + } +} + +// Static × Static -> Dyn × Any +#[cfg(any(feature = "std", feature = "alloc"))] +impl + Reallocator, Const, Dyn, CTo> for DefaultAllocator +where + CTo: Dim, +{ + #[inline] + unsafe fn reallocate_copy( + rto: Dyn, + cto: CTo, + buf: ArrayStorage, + ) -> VecStorage, Dyn, CTo> { + let mut res = >::allocate_uninit(rto, cto); + + let (rfrom, cfrom) = buf.shape(); + + let len_from = rfrom.value() * cfrom.value(); + let len_to = rto.value() * cto.value(); + let len_copied = cmp::min(len_from, len_to); + ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied); + + // Safety: + // - We don’t care about dropping elements because the caller is responsible for dropping things. + // - We forget `buf` so that we don’t drop the other elements, but ensure the buffer itself is cleaned up. + buf.forget_elements(); + + res + } +} + +// Static × Static -> Static × Dyn +#[cfg(any(feature = "std", feature = "alloc"))] +impl + Reallocator, Const, RTo, Dyn> for DefaultAllocator +where + RTo: DimName, +{ + #[inline] + unsafe fn reallocate_copy( + rto: RTo, + cto: Dyn, + buf: ArrayStorage, + ) -> VecStorage, RTo, Dyn> { + let mut res = >::allocate_uninit(rto, cto); + + let (rfrom, cfrom) = buf.shape(); + + let len_from = rfrom.value() * cfrom.value(); + let len_to = rto.value() * cto.value(); + let len_copied = cmp::min(len_from, len_to); + ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied); + + // Safety: + // - We don’t care about dropping elements because the caller is responsible for dropping things. + // - We forget `buf` so that we don’t drop the other elements, but ensure the buffer itself is cleaned up. + buf.forget_elements(); + + res + } +} + +// All conversion from a dynamic buffer to a dynamic buffer. +#[cfg(any(feature = "std", feature = "alloc"))] +impl Reallocator for DefaultAllocator { + #[inline] + unsafe fn reallocate_copy( + rto: Dyn, + cto: CTo, + buf: VecStorage, + ) -> VecStorage, Dyn, CTo> { + let new_buf = buf.resize(rto.value() * cto.value()); + VecStorage::new(rto, cto, new_buf) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Reallocator + for DefaultAllocator +{ + #[inline] + unsafe fn reallocate_copy( + rto: RTo, + cto: Dyn, + buf: VecStorage, + ) -> VecStorage, RTo, Dyn> { + let new_buf = buf.resize(rto.value() * cto.value()); + VecStorage::new(rto, cto, new_buf) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Reallocator + for DefaultAllocator +{ + #[inline] + unsafe fn reallocate_copy( + rto: Dyn, + cto: CTo, + buf: VecStorage, + ) -> VecStorage, Dyn, CTo> { + let new_buf = buf.resize(rto.value() * cto.value()); + VecStorage::new(rto, cto, new_buf) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Reallocator + for DefaultAllocator +{ + #[inline] + unsafe fn reallocate_copy( + rto: RTo, + cto: Dyn, + buf: VecStorage, + ) -> VecStorage, RTo, Dyn> { + let new_buf = buf.resize(rto.value() * cto.value()); + VecStorage::new(rto, cto, new_buf) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/dimension.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/dimension.rs new file mode 100644 index 000000000..5226be581 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/dimension.rs @@ -0,0 +1,340 @@ +#![allow(missing_docs)] + +//! Traits and tags for identifying the dimension of all algebraic entities. + +use std::any::{Any, TypeId}; +use std::cmp; +use std::fmt::Debug; +use std::ops::{Add, Div, Mul, Sub}; +use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Dim of dynamically-sized algebraic entities. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) +)] +#[cfg_attr( + feature = "rkyv-serialize", + archive_attr(derive(bytecheck::CheckBytes)) +)] +pub struct Dyn(pub usize); + +#[deprecated(note = "use Dyn instead.")] +pub type Dynamic = Dyn; + +impl Dyn { + /// A dynamic size equal to `value`. + #[inline] + #[deprecated(note = "use Dyn(value) instead.")] + pub const fn new(value: usize) -> Self { + Self(value) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Dyn { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'de> Deserialize<'de> for Dyn { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + usize::deserialize(deserializer).map(|x| Dyn(x)) + } +} + +/// Trait implemented by `Dyn`. +pub trait IsDynamic {} +/// Trait implemented by `Dyn` and type-level integers different from `U1`. +pub trait IsNotStaticOne {} + +impl IsDynamic for Dyn {} +impl IsNotStaticOne for Dyn {} + +/// Trait implemented by any type that can be used as a dimension. This includes type-level +/// integers and `Dyn` (for dimensions not known at compile-time). +/// +/// # Safety +/// +/// Hoists integers to the type level, including binary operations. +pub unsafe trait Dim: Any + Debug + Copy + PartialEq + Send + Sync { + #[inline(always)] + fn is() -> bool { + TypeId::of::() == TypeId::of::() + } + + /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self = + /// Dyn`. + fn try_to_usize() -> Option; + + /// Gets the run-time value of `self`. For type-level integers, this is the same as + /// `Self::try_to_usize().unwrap()`. + fn value(&self) -> usize; + + /// Builds an instance of `Self` from a run-time value. Panics if `Self` is a type-level + /// integer and `dim != Self::try_to_usize().unwrap()`. + fn from_usize(dim: usize) -> Self; +} + +unsafe impl Dim for Dyn { + #[inline] + fn try_to_usize() -> Option { + None + } + + #[inline] + fn from_usize(dim: usize) -> Self { + Self(dim) + } + + #[inline] + fn value(&self) -> usize { + self.0 + } +} + +impl Add for Dyn { + type Output = Dyn; + + #[inline] + fn add(self, rhs: usize) -> Self { + Self(self.0 + rhs) + } +} + +impl Sub for Dyn { + type Output = Dyn; + + #[inline] + fn sub(self, rhs: usize) -> Self { + Self(self.0 - rhs) + } +} + +/* + * + * Operations. + * + */ + +macro_rules! dim_ops( + ($($DimOp: ident, $DimNameOp: ident, + $Op: ident, $op: ident, $op_path: path, + $DimResOp: ident, $DimNameResOp: ident, + $ResOp: ident);* $(;)*) => {$( + pub type $DimResOp = >::Output; + + pub trait $DimOp: Dim { + type Output: Dim; + + fn $op(self, other: D) -> Self::Output; + } + + impl $DimOp> for Const + where + Const: ToTypenum, + Const: ToTypenum, + as ToTypenum>::Typenum: $Op< as ToTypenum>::Typenum>, + $ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum>: ToConst, + { + type Output = + <$ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum> as ToConst>::Const; + + fn $op(self, _: Const) -> Self::Output { + Self::Output::name() + } + } + + impl $DimOp for Dyn { + type Output = Dyn; + + #[inline] + fn $op(self, other: D) -> Dyn { + Dyn($op_path(self.value(), other.value())) + } + } + + // TODO: use Const instead of D: DimName? + impl $DimOp for D { + type Output = Dyn; + + #[inline] + fn $op(self, other: Dyn) -> Dyn { + Dyn($op_path(self.value(), other.value())) + } + } + + pub type $DimNameResOp = >::Output; + + pub trait $DimNameOp: DimName { + type Output: DimName; + + fn $op(self, other: D) -> Self::Output; + } + + impl $DimNameOp> for Const + where + Const: ToTypenum, + Const: ToTypenum, + as ToTypenum>::Typenum: $Op< as ToTypenum>::Typenum>, + $ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum>: ToConst, + { + type Output = + <$ResOp< as ToTypenum>::Typenum, as ToTypenum>::Typenum> as ToConst>::Const; + + fn $op(self, _: Const) -> Self::Output { + Self::Output::name() + } + } + )*} +); + +dim_ops!( + DimAdd, DimNameAdd, Add, add, Add::add, DimSum, DimNameSum, Sum; + DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd, DimNameProd, Prod; + DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff, DimNameDiff, Diff; + DimDiv, DimNameDiv, Div, div, Div::div, DimQuot, DimNameQuot, Quot; + DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum; + DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum; +); + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive(as = "Self") +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +pub struct Const; + +/// Trait implemented exclusively by type-level integers. +pub trait DimName: Dim { + const USIZE: usize; + + /// The name of this dimension, i.e., the singleton `Self`. + fn name() -> Self; + + // TODO: this is not a very idiomatic name. + /// The value of this dimension. + fn dim() -> usize; +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Const { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + ().serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'de, const D: usize> Deserialize<'de> for Const { + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'de>, + { + <()>::deserialize(deserializer).map(|_| Const::) + } +} + +pub trait ToConst { + type Const: DimName; +} + +pub trait ToTypenum { + type Typenum: Unsigned; +} + +unsafe impl Dim for Const { + #[inline] + fn try_to_usize() -> Option { + Some(T) + } + + #[inline] + fn value(&self) -> usize { + T + } + + #[inline] + fn from_usize(dim: usize) -> Self { + assert_eq!(dim, T); + Self + } +} + +impl DimName for Const { + const USIZE: usize = T; + + #[inline] + fn name() -> Self { + Self + } + + #[inline] + fn dim() -> usize { + T + } +} + +pub type U1 = Const<1>; + +impl ToTypenum for Const<1> { + type Typenum = typenum::U1; +} + +impl ToConst for typenum::U1 { + type Const = Const<1>; +} + +macro_rules! from_to_typenum ( + ($($D: ident, $VAL: expr);* $(;)*) => {$( + pub type $D = Const<$VAL>; + + impl ToTypenum for Const<$VAL> { + type Typenum = typenum::$D; + } + + impl ToConst for typenum::$D { + type Const = Const<$VAL>; + } + + impl IsNotStaticOne for $D { } + + /// The constant dimension + #[doc = stringify!($VAL)] + /// . + pub const $D: $D = Const::<$VAL>; + )*} +); + +from_to_typenum!( + U0, 0; /*U1,1;*/ U2, 2; U3, 3; U4, 4; U5, 5; U6, 6; U7, 7; U8, 8; U9, 9; U10, 10; U11, 11; U12, 12; U13, 13; U14, 14; U15, 15; U16, 16; U17, 17; U18, 18; + U19, 19; U20, 20; U21, 21; U22, 22; U23, 23; U24, 24; U25, 25; U26, 26; U27, 27; U28, 28; U29, 29; U30, 30; U31, 31; U32, 32; U33, 33; U34, 34; U35, 35; U36, 36; U37, 37; + U38, 38; U39, 39; U40, 40; U41, 41; U42, 42; U43, 43; U44, 44; U45, 45; U46, 46; U47, 47; U48, 48; U49, 49; U50, 50; U51, 51; U52, 52; U53, 53; U54, 54; U55, 55; U56, 56; + U57, 57; U58, 58; U59, 59; U60, 60; U61, 61; U62, 62; U63, 63; U64, 64; U65, 65; U66, 66; U67, 67; U68, 68; U69, 69; U70, 70; U71, 71; U72, 72; U73, 73; U74, 74; U75, 75; + U76, 76; U77, 77; U78, 78; U79, 79; U80, 80; U81, 81; U82, 82; U83, 83; U84, 84; U85, 85; U86, 86; U87, 87; U88, 88; U89, 89; U90, 90; U91, 91; U92, 92; U93, 93; U94, 94; + U95, 95; U96, 96; U97, 97; U98, 98; U99, 99; U100, 100; U101, 101; U102, 102; U103, 103; U104, 104; U105, 105; U106, 106; U107, 107; U108, 108; U109, 109; U110, 110; + U111, 111; U112, 112; U113, 113; U114, 114; U115, 115; U116, 116; U117, 117; U118, 118; U119, 119; U120, 120; U121, 121; U122, 122; U123, 123; U124, 124; U125, 125; U126, 126; + U127, 127 +); + +/// The constant dimension 1. +// Note: We add U1 separately since it's not covered by the from_to_typenum! macro. +pub const U1: U1 = Const::<1>; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/edition.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/edition.rs new file mode 100644 index 000000000..210e19eba --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/edition.rs @@ -0,0 +1,1300 @@ +use num::{One, Zero}; +use std::cmp; +#[cfg(any(feature = "std", feature = "alloc"))] +use std::iter::ExactSizeIterator; +use std::ptr; + +use crate::base::allocator::{Allocator, Reallocator}; +use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::dimension::Dyn; +use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimSub, DimSum, U1}; +use crate::base::storage::{RawStorage, RawStorageMut, ReshapableStorage}; +use crate::base::{DefaultAllocator, Matrix, OMatrix, RowVector, Scalar, Vector}; +use crate::{Storage, UninitMatrix}; +use std::mem::MaybeUninit; + +/// # Triangular matrix extraction +impl> Matrix { + /// Extracts the upper triangular part of this matrix (including the diagonal). + #[inline] + #[must_use] + pub fn upper_triangle(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.fill_lower_triangle(T::zero(), 1); + + res + } + + /// Extracts the lower triangular part of this matrix (including the diagonal). + #[inline] + #[must_use] + pub fn lower_triangle(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.fill_upper_triangle(T::zero(), 1); + + res + } +} + +/// # Rows and columns extraction +impl> Matrix { + /// Creates a new matrix by extracting the given set of rows from `self`. + #[cfg(any(feature = "std", feature = "alloc"))] + #[must_use] + pub fn select_rows<'a, I>(&self, irows: I) -> OMatrix + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone, + DefaultAllocator: Allocator, + { + let irows = irows.into_iter(); + let ncols = self.shape_generic().1; + let mut res = Matrix::uninit(Dyn(irows.len()), ncols); + + // First, check that all the indices from irows are valid. + // This will allow us to use unchecked access in the inner loop. + for i in irows.clone() { + assert!(*i < self.nrows(), "Row index out of bounds.") + } + + for j in 0..ncols.value() { + // TODO: use unchecked column indexing + let mut res = res.column_mut(j); + let src = self.column(j); + + for (destination, source) in irows.clone().enumerate() { + // Safety: all indices are in range. + unsafe { + *res.vget_unchecked_mut(destination) = + MaybeUninit::new(src.vget_unchecked(*source).clone()); + } + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Creates a new matrix by extracting the given set of columns from `self`. + #[cfg(any(feature = "std", feature = "alloc"))] + #[must_use] + pub fn select_columns<'a, I>(&self, icols: I) -> OMatrix + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + DefaultAllocator: Allocator, + { + let icols = icols.into_iter(); + let nrows = self.shape_generic().0; + let mut res = Matrix::uninit(nrows, Dyn(icols.len())); + + for (destination, source) in icols.enumerate() { + // NOTE: this is basically a copy_frow but wrapping the values insnide of MaybeUninit. + res.column_mut(destination) + .zip_apply(&self.column(*source), |out, e| *out = MaybeUninit::new(e)); + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } +} + +/// # Set rows, columns, and diagonal +impl> Matrix { + /// Fills the diagonal of this matrix with the content of the given vector. + #[inline] + pub fn set_diagonal(&mut self, diag: &Vector) + where + R: DimMin, + S2: RawStorage, + ShapeConstraint: DimEq, R2>, + { + let (nrows, ncols) = self.shape(); + let min_nrows_ncols = cmp::min(nrows, ncols); + assert_eq!(diag.len(), min_nrows_ncols, "Mismatched dimensions."); + + for i in 0..min_nrows_ncols { + unsafe { *self.get_unchecked_mut((i, i)) = diag.vget_unchecked(i).clone() } + } + } + + /// Fills the diagonal of this matrix with the content of the given iterator. + /// + /// This will fill as many diagonal elements as the iterator yields, up to the + /// minimum of the number of rows and columns of `self`, and starting with the + /// diagonal element at index (0, 0). + #[inline] + pub fn set_partial_diagonal(&mut self, diag: impl Iterator) { + let (nrows, ncols) = self.shape(); + let min_nrows_ncols = cmp::min(nrows, ncols); + + for (i, val) in diag.enumerate().take(min_nrows_ncols) { + unsafe { *self.get_unchecked_mut((i, i)) = val } + } + } + + /// Fills the selected row of this matrix with the content of the given vector. + #[inline] + pub fn set_row(&mut self, i: usize, row: &RowVector) + where + S2: RawStorage, + ShapeConstraint: SameNumberOfColumns, + { + self.row_mut(i).copy_from(row); + } + + /// Fills the selected column of this matrix with the content of the given vector. + #[inline] + pub fn set_column(&mut self, i: usize, column: &Vector) + where + S2: RawStorage, + ShapeConstraint: SameNumberOfRows, + { + self.column_mut(i).copy_from(column); + } +} + +/// # In-place filling +impl> Matrix { + /// Sets all the elements of this matrix to the value returned by the closure. + #[inline] + pub fn fill_with(&mut self, val: impl Fn() -> T) { + for e in self.iter_mut() { + *e = val() + } + } + + /// Sets all the elements of this matrix to `val`. + #[inline] + pub fn fill(&mut self, val: T) + where + T: Scalar, + { + for e in self.iter_mut() { + *e = val.clone() + } + } + + /// Fills `self` with the identity matrix. + #[inline] + pub fn fill_with_identity(&mut self) + where + T: Scalar + Zero + One, + { + self.fill(T::zero()); + self.fill_diagonal(T::one()); + } + + /// Sets all the diagonal elements of this matrix to `val`. + #[inline] + pub fn fill_diagonal(&mut self, val: T) + where + T: Scalar, + { + let (nrows, ncols) = self.shape(); + let n = cmp::min(nrows, ncols); + + for i in 0..n { + unsafe { *self.get_unchecked_mut((i, i)) = val.clone() } + } + } + + /// Sets all the elements of the selected row to `val`. + #[inline] + pub fn fill_row(&mut self, i: usize, val: T) + where + T: Scalar, + { + assert!(i < self.nrows(), "Row index out of bounds."); + for j in 0..self.ncols() { + unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } + } + } + + /// Sets all the elements of the selected column to `val`. + #[inline] + pub fn fill_column(&mut self, j: usize, val: T) + where + T: Scalar, + { + assert!(j < self.ncols(), "Row index out of bounds."); + for i in 0..self.nrows() { + unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } + } + } + + /// Sets all the elements of the lower-triangular part of this matrix to `val`. + /// + /// The parameter `shift` allows some subdiagonals to be left untouched: + /// * If `shift = 0` then the diagonal is overwritten as well. + /// * If `shift = 1` then the diagonal is left untouched. + /// * If `shift > 1`, then the diagonal and the first `shift - 1` subdiagonals are left + /// untouched. + #[inline] + pub fn fill_lower_triangle(&mut self, val: T, shift: usize) + where + T: Scalar, + { + for j in 0..self.ncols() { + for i in (j + shift)..self.nrows() { + unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } + } + } + } + + /// Sets all the elements of the lower-triangular part of this matrix to `val`. + /// + /// The parameter `shift` allows some superdiagonals to be left untouched: + /// * If `shift = 0` then the diagonal is overwritten as well. + /// * If `shift = 1` then the diagonal is left untouched. + /// * If `shift > 1`, then the diagonal and the first `shift - 1` superdiagonals are left + /// untouched. + #[inline] + pub fn fill_upper_triangle(&mut self, val: T, shift: usize) + where + T: Scalar, + { + for j in shift..self.ncols() { + // TODO: is there a more efficient way to avoid the min ? + // (necessary for rectangular matrices) + for i in 0..cmp::min(j + 1 - shift, self.nrows()) { + unsafe { *self.get_unchecked_mut((i, j)) = val.clone() } + } + } + } +} + +impl> Matrix { + /// Copies the upper-triangle of this matrix to its lower-triangular part. + /// + /// This makes the matrix symmetric. Panics if the matrix is not square. + pub fn fill_lower_triangle_with_upper_triangle(&mut self) { + assert!(self.is_square(), "The input matrix should be square."); + + let dim = self.nrows(); + for j in 0..dim { + for i in j + 1..dim { + unsafe { + *self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone(); + } + } + } + } + + /// Copies the upper-triangle of this matrix to its upper-triangular part. + /// + /// This makes the matrix symmetric. Panics if the matrix is not square. + pub fn fill_upper_triangle_with_lower_triangle(&mut self) { + assert!(self.is_square(), "The input matrix should be square."); + + for j in 1..self.ncols() { + for i in 0..j { + unsafe { + *self.get_unchecked_mut((i, j)) = self.get_unchecked((j, i)).clone(); + } + } + } + } +} + +/// # In-place swapping +impl> Matrix { + /// Swaps two rows in-place. + #[inline] + pub fn swap_rows(&mut self, irow1: usize, irow2: usize) { + assert!(irow1 < self.nrows() && irow2 < self.nrows()); + + if irow1 != irow2 { + // TODO: optimize that. + for i in 0..self.ncols() { + unsafe { self.swap_unchecked((irow1, i), (irow2, i)) } + } + } + // Otherwise do nothing. + } + + /// Swaps two columns in-place. + #[inline] + pub fn swap_columns(&mut self, icol1: usize, icol2: usize) { + assert!(icol1 < self.ncols() && icol2 < self.ncols()); + + if icol1 != icol2 { + // TODO: optimize that. + for i in 0..self.nrows() { + unsafe { self.swap_unchecked((i, icol1), (i, icol2)) } + } + } + // Otherwise do nothing. + } +} + +/* + * + * TODO: specialize all the following for slices. + * + */ +/// # Rows and columns removal +impl> Matrix { + /* + * + * Column removal. + * + */ + /// Removes the `i`-th column from this matrix. + #[inline] + pub fn remove_column(self, i: usize) -> OMatrix> + where + C: DimSub, + DefaultAllocator: Reallocator>, + { + self.remove_fixed_columns::<1>(i) + } + + /// Removes all columns in `indices` + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn remove_columns_at(self, indices: &[usize]) -> OMatrix + where + C: DimSub, + DefaultAllocator: Reallocator, + { + let mut m = self.into_owned(); + let (nrows, ncols) = m.shape_generic(); + let mut offset: usize = 0; + let mut target: usize = 0; + while offset + target < ncols.value() { + if indices.contains(&(target + offset)) { + // Safety: the resulting pointer is within range. + let col_ptr = unsafe { m.data.ptr_mut().add((target + offset) * nrows.value()) }; + // Drop every element in the column we are about to overwrite. + // We use the a similar technique as in `Vec::truncate`. + let s = ptr::slice_from_raw_parts_mut(col_ptr, nrows.value()); + // Safety: we drop the column in-place, which is OK because we will overwrite these + // entries later in the loop, or discard them with the `reallocate_copy` + // afterwards. + unsafe { ptr::drop_in_place(s) }; + + offset += 1; + } else { + unsafe { + let ptr_source = m.data.ptr().add((target + offset) * nrows.value()); + let ptr_target = m.data.ptr_mut().add(target * nrows.value()); + + // Copy the data, overwriting what we dropped. + ptr::copy(ptr_source, ptr_target, nrows.value()); + target += 1; + } + } + } + + // Safety: The new size is smaller than the old size, so + // DefaultAllocator::reallocate_copy will initialize + // every element of the new matrix which can then + // be assumed to be initialized. + unsafe { + let new_data = DefaultAllocator::reallocate_copy( + nrows, + ncols.sub(Dyn::from_usize(offset)), + m.data, + ); + + Matrix::from_data(new_data).assume_init() + } + } + + /// Removes all rows in `indices` + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn remove_rows_at(self, indices: &[usize]) -> OMatrix + where + R: DimSub, + DefaultAllocator: Reallocator, + { + let mut m = self.into_owned(); + let (nrows, ncols) = m.shape_generic(); + let mut offset: usize = 0; + let mut target: usize = 0; + while offset + target < nrows.value() * ncols.value() { + if indices.contains(&((target + offset) % nrows.value())) { + // Safety: the resulting pointer is within range. + unsafe { + let elt_ptr = m.data.ptr_mut().add(target + offset); + // Safety: we drop the component in-place, which is OK because we will overwrite these + // entries later in the loop, or discard them with the `reallocate_copy` + // afterwards. + ptr::drop_in_place(elt_ptr) + }; + offset += 1; + } else { + unsafe { + let ptr_source = m.data.ptr().add(target + offset); + let ptr_target = m.data.ptr_mut().add(target); + + // Copy the data, overwriting what we dropped in the previous iterations. + ptr::copy(ptr_source, ptr_target, 1); + target += 1; + } + } + } + + // Safety: The new size is smaller than the old size, so + // DefaultAllocator::reallocate_copy will initialize + // every element of the new matrix which can then + // be assumed to be initialized. + unsafe { + let new_data = DefaultAllocator::reallocate_copy( + nrows.sub(Dyn::from_usize(offset / ncols.value())), + ncols, + m.data, + ); + + Matrix::from_data(new_data).assume_init() + } + } + + /// Removes `D::dim()` consecutive columns from this matrix, starting with the `i`-th + /// (included). + #[inline] + pub fn remove_fixed_columns( + self, + i: usize, + ) -> OMatrix>> + where + C: DimSub>, + DefaultAllocator: Reallocator>>, + { + self.remove_columns_generic(i, Const::) + } + + /// Removes `n` consecutive columns from this matrix, starting with the `i`-th (included). + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn remove_columns(self, i: usize, n: usize) -> OMatrix + where + C: DimSub, + DefaultAllocator: Reallocator, + { + self.remove_columns_generic(i, Dyn(n)) + } + + /// Removes `nremove.value()` columns from this matrix, starting with the `i`-th (included). + /// + /// This is the generic implementation of `.remove_columns(...)` and + /// `.remove_fixed_columns(...)` which have nicer API interfaces. + #[inline] + pub fn remove_columns_generic(self, i: usize, nremove: D) -> OMatrix> + where + D: Dim, + C: DimSub, + DefaultAllocator: Reallocator>, + { + let mut m = self.into_owned(); + let (nrows, ncols) = m.shape_generic(); + assert!( + i + nremove.value() <= ncols.value(), + "Column index out of range." + ); + + let need_column_shifts = nremove.value() != 0 && i + nremove.value() < ncols.value(); + if need_column_shifts { + // The first `deleted_i * nrows` are left untouched. + let copied_value_start = i + nremove.value(); + + unsafe { + let ptr_in = m.data.ptr().add(copied_value_start * nrows.value()); + let ptr_out = m.data.ptr_mut().add(i * nrows.value()); + + // Drop all the elements of the columns we are about to overwrite. + // We use the a similar technique as in `Vec::truncate`. + let s = ptr::slice_from_raw_parts_mut(ptr_out, nremove.value() * nrows.value()); + // Safety: we drop the column in-place, which is OK because we will overwrite these + // entries with `ptr::copy` afterward. + ptr::drop_in_place(s); + + ptr::copy( + ptr_in, + ptr_out, + (ncols.value() - copied_value_start) * nrows.value(), + ); + } + } else { + // All the columns to remove are at the end of the buffer. Drop them. + unsafe { + let ptr = m.data.ptr_mut().add(i * nrows.value()); + let s = ptr::slice_from_raw_parts_mut(ptr, nremove.value() * nrows.value()); + ptr::drop_in_place(s) + }; + } + + // Safety: The new size is smaller than the old size, so + // DefaultAllocator::reallocate_copy will initialize + // every element of the new matrix which can then + // be assumed to be initialized. + unsafe { + let new_data = DefaultAllocator::reallocate_copy(nrows, ncols.sub(nremove), m.data); + Matrix::from_data(new_data).assume_init() + } + } + + /* + * + * Row removal. + * + */ + /// Removes the `i`-th row from this matrix. + #[inline] + pub fn remove_row(self, i: usize) -> OMatrix, C> + where + R: DimSub, + DefaultAllocator: Reallocator, C>, + { + self.remove_fixed_rows::<1>(i) + } + + /// Removes `D::dim()` consecutive rows from this matrix, starting with the `i`-th (included). + #[inline] + pub fn remove_fixed_rows(self, i: usize) -> OMatrix>, C> + where + R: DimSub>, + DefaultAllocator: Reallocator>, C>, + { + self.remove_rows_generic(i, Const::) + } + + /// Removes `n` consecutive rows from this matrix, starting with the `i`-th (included). + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn remove_rows(self, i: usize, n: usize) -> OMatrix + where + R: DimSub, + DefaultAllocator: Reallocator, + { + self.remove_rows_generic(i, Dyn(n)) + } + + /// Removes `nremove.value()` rows from this matrix, starting with the `i`-th (included). + /// + /// This is the generic implementation of `.remove_rows(...)` and `.remove_fixed_rows(...)` + /// which have nicer API interfaces. + #[inline] + pub fn remove_rows_generic(self, i: usize, nremove: D) -> OMatrix, C> + where + D: Dim, + R: DimSub, + DefaultAllocator: Reallocator, C>, + { + let mut m = self.into_owned(); + let (nrows, ncols) = m.shape_generic(); + assert!( + i + nremove.value() <= nrows.value(), + "Row index out of range." + ); + + if nremove.value() != 0 { + unsafe { + compress_rows( + m.as_mut_slice(), + nrows.value(), + ncols.value(), + i, + nremove.value(), + ); + } + } + + // Safety: The new size is smaller than the old size, so + // DefaultAllocator::reallocate_copy will initialize + // every element of the new matrix which can then + // be assumed to be initialized. + unsafe { + let new_data = DefaultAllocator::reallocate_copy(nrows.sub(nremove), ncols, m.data); + Matrix::from_data(new_data).assume_init() + } + } +} + +/// # Rows and columns insertion +impl> Matrix { + /* + * + * Columns insertion. + * + */ + /// Inserts a column filled with `val` at the `i-th` position. + #[inline] + pub fn insert_column(self, i: usize, val: T) -> OMatrix> + where + C: DimAdd, + DefaultAllocator: Reallocator>, + { + self.insert_fixed_columns::<1>(i, val) + } + + /// Inserts `D` columns filled with `val` starting at the `i-th` position. + #[inline] + pub fn insert_fixed_columns( + self, + i: usize, + val: T, + ) -> OMatrix>> + where + C: DimAdd>, + DefaultAllocator: Reallocator>>, + { + let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Const::) }; + res.fixed_columns_mut::(i) + .fill_with(|| MaybeUninit::new(val.clone())); + + // Safety: the result is now fully initialized. The added columns have + // been initialized by the `fill_with` above, and the rest have + // been initialized by `insert_columns_generic_uninitialized`. + unsafe { res.assume_init() } + } + + /// Inserts `n` columns filled with `val` starting at the `i-th` position. + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn insert_columns(self, i: usize, n: usize, val: T) -> OMatrix + where + C: DimAdd, + DefaultAllocator: Reallocator, + { + let mut res = unsafe { self.insert_columns_generic_uninitialized(i, Dyn(n)) }; + res.columns_mut(i, n) + .fill_with(|| MaybeUninit::new(val.clone())); + + // Safety: the result is now fully initialized. The added columns have + // been initialized by the `fill_with` above, and the rest have + // been initialized by `insert_columns_generic_uninitialized`. + unsafe { res.assume_init() } + } + + /// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix. + /// + /// # Safety + /// The output matrix has all its elements initialized except for the the components of the + /// added columns. + #[inline] + pub unsafe fn insert_columns_generic_uninitialized( + self, + i: usize, + ninsert: D, + ) -> UninitMatrix> + where + D: Dim, + C: DimAdd, + DefaultAllocator: Reallocator>, + { + let m = self.into_owned(); + let (nrows, ncols) = m.shape_generic(); + let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy( + nrows, + ncols.add(ninsert), + m.data, + )); + + assert!(i <= ncols.value(), "Column insertion index out of range."); + + if ninsert.value() != 0 && i != ncols.value() { + let ptr_in = res.data.ptr().add(i * nrows.value()); + let ptr_out = res + .data + .ptr_mut() + .add((i + ninsert.value()) * nrows.value()); + + ptr::copy(ptr_in, ptr_out, (ncols.value() - i) * nrows.value()) + } + + res + } + + /* + * + * Rows insertion. + * + */ + /// Inserts a row filled with `val` at the `i-th` position. + #[inline] + pub fn insert_row(self, i: usize, val: T) -> OMatrix, C> + where + R: DimAdd, + DefaultAllocator: Reallocator, C>, + { + self.insert_fixed_rows::<1>(i, val) + } + + /// Inserts `D::dim()` rows filled with `val` starting at the `i-th` position. + #[inline] + pub fn insert_fixed_rows( + self, + i: usize, + val: T, + ) -> OMatrix>, C> + where + R: DimAdd>, + DefaultAllocator: Reallocator>, C>, + { + let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Const::) }; + res.fixed_rows_mut::(i) + .fill_with(|| MaybeUninit::new(val.clone())); + + // Safety: the result is now fully initialized. The added rows have + // been initialized by the `fill_with` above, and the rest have + // been initialized by `insert_rows_generic_uninitialized`. + unsafe { res.assume_init() } + } + + /// Inserts `n` rows filled with `val` starting at the `i-th` position. + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn insert_rows(self, i: usize, n: usize, val: T) -> OMatrix + where + R: DimAdd, + DefaultAllocator: Reallocator, + { + let mut res = unsafe { self.insert_rows_generic_uninitialized(i, Dyn(n)) }; + res.rows_mut(i, n) + .fill_with(|| MaybeUninit::new(val.clone())); + + // Safety: the result is now fully initialized. The added rows have + // been initialized by the `fill_with` above, and the rest have + // been initialized by `insert_rows_generic_uninitialized`. + unsafe { res.assume_init() } + } + + /// Inserts `ninsert.value()` rows at the `i-th` place of this matrix. + /// + /// # Safety + /// The added rows values are not initialized. + /// This is the generic implementation of `.insert_rows(...)` and + /// `.insert_fixed_rows(...)` which have nicer API interfaces. + #[inline] + pub unsafe fn insert_rows_generic_uninitialized( + self, + i: usize, + ninsert: D, + ) -> UninitMatrix, C> + where + D: Dim, + R: DimAdd, + DefaultAllocator: Reallocator, C>, + { + let m = self.into_owned(); + let (nrows, ncols) = m.shape_generic(); + let mut res = Matrix::from_data(DefaultAllocator::reallocate_copy( + nrows.add(ninsert), + ncols, + m.data, + )); + + assert!(i <= nrows.value(), "Row insertion index out of range."); + + if ninsert.value() != 0 { + extend_rows( + res.as_mut_slice(), + nrows.value(), + ncols.value(), + i, + ninsert.value(), + ); + } + + res + } +} + +/// # Resizing and reshaping +impl> Matrix { + /// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn resize(self, new_nrows: usize, new_ncols: usize, val: T) -> OMatrix + where + DefaultAllocator: Reallocator, + { + self.resize_generic(Dyn(new_nrows), Dyn(new_ncols), val) + } + + /// Resizes this matrix vertically, i.e., so that it contains `new_nrows` rows while keeping the same number of columns. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows than `self`, then the extra rows are filled with `val`. + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn resize_vertically(self, new_nrows: usize, val: T) -> OMatrix + where + DefaultAllocator: Reallocator, + { + let ncols = self.shape_generic().1; + self.resize_generic(Dyn(new_nrows), ncols, val) + } + + /// Resizes this matrix horizontally, i.e., so that it contains `new_ncolumns` columns while keeping the same number of columns. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// columns than `self`, then the extra columns are filled with `val`. + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn resize_horizontally(self, new_ncols: usize, val: T) -> OMatrix + where + DefaultAllocator: Reallocator, + { + let nrows = self.shape_generic().0; + self.resize_generic(nrows, Dyn(new_ncols), val) + } + + /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. + pub fn fixed_resize( + self, + val: T, + ) -> OMatrix, Const> + where + DefaultAllocator: Reallocator, Const>, + { + self.resize_generic(Const::, Const::, val) + } + + /// Resizes `self` such that it has dimensions `new_nrows × new_ncols`. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. + #[inline] + pub fn resize_generic( + self, + new_nrows: R2, + new_ncols: C2, + val: T, + ) -> OMatrix + where + DefaultAllocator: Reallocator, + { + let (nrows, ncols) = self.shape(); + let mut data = self.into_owned(); + + if new_nrows.value() == nrows { + if new_ncols.value() < ncols { + unsafe { + let num_cols_to_delete = ncols - new_ncols.value(); + let col_ptr = data.data.ptr_mut().add(new_ncols.value() * nrows); + let s = ptr::slice_from_raw_parts_mut(col_ptr, num_cols_to_delete * nrows); + // Safety: drop the elements of the deleted columns. + // these are the elements that will be truncated + // by the `reallocate_copy` afterward. + ptr::drop_in_place(s) + }; + } + + let res = unsafe { DefaultAllocator::reallocate_copy(new_nrows, new_ncols, data.data) }; + let mut res = Matrix::from_data(res); + + if new_ncols.value() > ncols { + res.columns_range_mut(ncols..) + .fill_with(|| MaybeUninit::new(val.clone())); + } + + // Safety: the result is now fully initialized by `reallocate_copy` and + // `fill_with` (if the output has more columns than the input). + unsafe { res.assume_init() } + } else { + let mut res; + + unsafe { + if new_nrows.value() < nrows { + compress_rows( + data.as_mut_slice(), + nrows, + ncols, + new_nrows.value(), + nrows - new_nrows.value(), + ); + res = Matrix::from_data(DefaultAllocator::reallocate_copy( + new_nrows, new_ncols, data.data, + )); + } else { + res = Matrix::from_data(DefaultAllocator::reallocate_copy( + new_nrows, new_ncols, data.data, + )); + extend_rows( + res.as_mut_slice(), + nrows, + new_ncols.value(), + nrows, + new_nrows.value() - nrows, + ); + } + } + + if new_ncols.value() > ncols { + res.columns_range_mut(ncols..) + .fill_with(|| MaybeUninit::new(val.clone())); + } + + if new_nrows.value() > nrows { + res.view_range_mut(nrows.., ..cmp::min(ncols, new_ncols.value())) + .fill_with(|| MaybeUninit::new(val.clone())); + } + + // Safety: the result is now fully initialized by `reallocate_copy` and + // `fill_with` (whenever applicable). + unsafe { res.assume_init() } + } + } + + /// Reshapes `self` such that it has dimensions `new_nrows × new_ncols`. + /// + /// This will reinterpret `self` as if it is a matrix with `new_nrows` rows and `new_ncols` + /// columns. The arrangements of the component in the output matrix are the same as what + /// would be obtained by `Matrix::from_slice_generic(self.as_slice(), new_nrows, new_ncols)`. + /// + /// If `self` is a dynamically-sized matrix, then its components are neither copied nor moved. + /// If `self` is staticyll-sized, then a copy may happen in some situations. + /// This function will panic if the given dimensions are such that the number of elements of + /// the input matrix are not equal to the number of elements of the output matrix. + /// + /// # Examples + /// + /// ``` + /// # use nalgebra::{Matrix3x2, Matrix2x3, DMatrix, Const, Dyn}; + /// + /// let m1 = Matrix2x3::new( + /// 1.1, 1.2, 1.3, + /// 2.1, 2.2, 2.3 + /// ); + /// let m2 = Matrix3x2::new( + /// 1.1, 2.2, + /// 2.1, 1.3, + /// 1.2, 2.3 + /// ); + /// let reshaped = m1.reshape_generic(Const::<3>, Const::<2>); + /// assert_eq!(reshaped, m2); + /// + /// let dm1 = DMatrix::from_row_slice( + /// 4, + /// 3, + /// &[ + /// 1.0, 0.0, 0.0, + /// 0.0, 0.0, 1.0, + /// 0.0, 0.0, 0.0, + /// 0.0, 1.0, 0.0 + /// ], + /// ); + /// let dm2 = DMatrix::from_row_slice( + /// 6, + /// 2, + /// &[ + /// 1.0, 0.0, + /// 0.0, 1.0, + /// 0.0, 0.0, + /// 0.0, 1.0, + /// 0.0, 0.0, + /// 0.0, 0.0, + /// ], + /// ); + /// let reshaped = dm1.reshape_generic(Dyn(6), Dyn(2)); + /// assert_eq!(reshaped, dm2); + /// ``` + pub fn reshape_generic( + self, + new_nrows: R2, + new_ncols: C2, + ) -> Matrix + where + R2: Dim, + C2: Dim, + S: ReshapableStorage, + { + let data = self.data.reshape_generic(new_nrows, new_ncols); + Matrix::from_data(data) + } +} + +/// # In-place resizing +#[cfg(any(feature = "std", feature = "alloc"))] +impl OMatrix { + /// Resizes this matrix in-place. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. + /// + /// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`. + pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: T) + where + DefaultAllocator: Reallocator, + { + // TODO: avoid the clone. + *self = self.clone().resize(new_nrows, new_ncols, val); + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl OMatrix +where + DefaultAllocator: Allocator, +{ + /// Changes the number of rows of this matrix in-place. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows than `self`, then the extra rows are filled with `val`. + /// + /// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`). + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: T) + where + DefaultAllocator: Reallocator, + { + // TODO: avoid the clone. + *self = self.clone().resize_vertically(new_nrows, val); + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl OMatrix +where + DefaultAllocator: Allocator, +{ + /// Changes the number of column of this matrix in-place. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// columns than `self`, then the extra columns are filled with `val`. + /// + /// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`). + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: T) + where + DefaultAllocator: Reallocator, + { + // TODO: avoid the clone. + *self = self.clone().resize_horizontally(new_ncols, val); + } +} + +// Move the elements of `data` in such a way that the matrix with +// the rows `[i, i + nremove[` deleted is represented in a contiguous +// way in `data` after this method completes. +// Every deleted element are manually dropped by this method. +unsafe fn compress_rows( + data: &mut [T], + nrows: usize, + ncols: usize, + i: usize, + nremove: usize, +) { + let new_nrows = nrows - nremove; + + if nremove == 0 { + return; // Nothing to remove or drop. + } + + if new_nrows == 0 || ncols == 0 { + // The output matrix is empty, drop everything. + ptr::drop_in_place(data); + return; + } + + // Safety: because `nremove != 0`, the pointers given to `ptr::copy` + // won’t alias. + let ptr_in = data.as_ptr(); + let ptr_out = data.as_mut_ptr(); + + let mut curr_i = i; + + for k in 0..ncols - 1 { + // Safety: we drop the row elements in-place because we will overwrite these + // entries later with the `ptr::copy`. + let s = ptr::slice_from_raw_parts_mut(ptr_out.add(curr_i), nremove); + ptr::drop_in_place(s); + ptr::copy( + ptr_in.add(curr_i + (k + 1) * nremove), + ptr_out.add(curr_i), + new_nrows, + ); + + curr_i += new_nrows; + } + + /* + * Deal with the last column from which less values have to be copied. + */ + // Safety: we drop the row elements in-place because we will overwrite these + // entries later with the `ptr::copy`. + let s = ptr::slice_from_raw_parts_mut(ptr_out.add(curr_i), nremove); + ptr::drop_in_place(s); + let remaining_len = nrows - i - nremove; + ptr::copy( + ptr_in.add(nrows * ncols - remaining_len), + ptr_out.add(curr_i), + remaining_len, + ); +} + +// Moves entries of a matrix buffer to make place for `ninsert` empty rows starting at the `i-th` row index. +// The `data` buffer is assumed to contained at least `(nrows + ninsert) * ncols` elements. +unsafe fn extend_rows(data: &mut [T], nrows: usize, ncols: usize, i: usize, ninsert: usize) { + let new_nrows = nrows + ninsert; + + if new_nrows == 0 || ncols == 0 { + return; // Nothing to do as the output matrix is empty. + } + + let ptr_in = data.as_ptr(); + let ptr_out = data.as_mut_ptr(); + + let remaining_len = nrows - i; + let mut curr_i = new_nrows * ncols - remaining_len; + + // Deal with the last column from which less values have to be copied. + ptr::copy( + ptr_in.add(nrows * ncols - remaining_len), + ptr_out.add(curr_i), + remaining_len, + ); + + for k in (0..ncols - 1).rev() { + curr_i -= new_nrows; + + ptr::copy(ptr_in.add(k * nrows + i), ptr_out.add(curr_i), nrows); + } +} + +/// Extend the number of columns of the `Matrix` with elements from +/// a given iterator. +#[cfg(any(feature = "std", feature = "alloc"))] +impl Extend for Matrix +where + T: Scalar, + R: Dim, + S: Extend, +{ + /// Extend the number of columns of the `Matrix` with elements + /// from the given iterator. + /// + /// # Example + /// ``` + /// # use nalgebra::{DMatrix, Dyn, Matrix, OMatrix, Matrix3}; + /// + /// let data = vec![0, 1, 2, // column 1 + /// 3, 4, 5]; // column 2 + /// + /// let mut matrix = DMatrix::from_vec(3, 2, data); + /// + /// matrix.extend(vec![6, 7, 8]); // column 3 + /// + /// assert!(matrix.eq(&Matrix3::new(0, 3, 6, + /// 1, 4, 7, + /// 2, 5, 8))); + /// ``` + /// + /// # Panics + /// This function panics if the number of elements yielded by the + /// given iterator is not a multiple of the number of rows of the + /// `Matrix`. + /// + /// ```should_panic + /// # use nalgebra::{DMatrix, Dyn, OMatrix}; + /// let data = vec![0, 1, 2, // column 1 + /// 3, 4, 5]; // column 2 + /// + /// let mut matrix = DMatrix::from_vec(3, 2, data); + /// + /// // The following panics because the vec length is not a multiple of 3. + /// matrix.extend(vec![6, 7, 8, 9]); + /// ``` + fn extend>(&mut self, iter: I) { + self.data.extend(iter); + } +} + +/// Extend the number of rows of the `Vector` with elements from +/// a given iterator. +#[cfg(any(feature = "std", feature = "alloc"))] +impl Extend for Matrix +where + T: Scalar, + S: Extend, +{ + /// Extend the number of rows of a `Vector` with elements + /// from the given iterator. + /// + /// # Example + /// ``` + /// # use nalgebra::DVector; + /// let mut vector = DVector::from_vec(vec![0, 1, 2]); + /// vector.extend(vec![3, 4, 5]); + /// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5]))); + /// ``` + fn extend>(&mut self, iter: I) { + self.data.extend(iter); + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Extend> for Matrix +where + T: Scalar, + R: Dim, + S: Extend>, + RV: Dim, + SV: RawStorage, + ShapeConstraint: SameNumberOfRows, +{ + /// Extends the number of columns of a `Matrix` with `Vector`s + /// from a given iterator. + /// + /// # Example + /// ``` + /// # use nalgebra::{DMatrix, Vector3, Matrix3x4}; + /// + /// let data = vec![0, 1, 2, // column 1 + /// 3, 4, 5]; // column 2 + /// + /// let mut matrix = DMatrix::from_vec(3, 2, data); + /// + /// matrix.extend( + /// vec![Vector3::new(6, 7, 8), // column 3 + /// Vector3::new(9, 10, 11)]); // column 4 + /// + /// assert!(matrix.eq(&Matrix3x4::new(0, 3, 6, 9, + /// 1, 4, 7, 10, + /// 2, 5, 8, 11))); + /// ``` + /// + /// # Panics + /// This function panics if the dimension of each `Vector` yielded + /// by the given iterator is not equal to the number of rows of + /// this `Matrix`. + /// + /// ```should_panic + /// # use nalgebra::{DMatrix, Vector2, Matrix3x4}; + /// let mut matrix = + /// DMatrix::from_vec(3, 2, + /// vec![0, 1, 2, // column 1 + /// 3, 4, 5]); // column 2 + /// + /// // The following panics because this matrix can only be extended with 3-dimensional vectors. + /// matrix.extend( + /// vec![Vector2::new(6, 7)]); // too few dimensions! + /// ``` + /// + /// ```should_panic + /// # use nalgebra::{DMatrix, Vector4, Matrix3x4}; + /// let mut matrix = + /// DMatrix::from_vec(3, 2, + /// vec![0, 1, 2, // column 1 + /// 3, 4, 5]); // column 2 + /// + /// // The following panics because this matrix can only be extended with 3-dimensional vectors. + /// matrix.extend( + /// vec![Vector4::new(6, 7, 8, 9)]); // too few dimensions! + /// ``` + fn extend>>(&mut self, iter: I) { + self.data.extend(iter); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/helper.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/helper.rs new file mode 100644 index 000000000..7391f8d4a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/helper.rs @@ -0,0 +1,31 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +/// Simple helper function for rejection sampling +#[cfg(feature = "arbitrary")] +#[doc(hidden)] +#[inline] +pub fn reject bool, T: Arbitrary>(g: &mut Gen, f: F) -> T { + use std::iter; + iter::repeat(()) + .map(|_| Arbitrary::arbitrary(g)) + .find(f) + .unwrap() +} + +#[doc(hidden)] +#[inline] +#[cfg(feature = "rand-no-std")] +pub fn reject_rand bool, T>(g: &mut G, f: F) -> T +where + Standard: Distribution, +{ + use std::iter; + iter::repeat(()).map(|_| g.gen()).find(f).unwrap() +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/indexing.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/indexing.rs new file mode 100644 index 000000000..702e3234f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/indexing.rs @@ -0,0 +1,770 @@ +//! Indexing +#![allow(clippy::reversed_empty_ranges)] + +use crate::base::storage::{RawStorage, RawStorageMut}; +use crate::base::{ + Const, Dim, DimDiff, DimName, DimSub, Dyn, Matrix, MatrixView, MatrixViewMut, Scalar, U1, +}; + +use std::ops; + +// N.B.: Not a public trait! +trait DimRange { + /// The number of elements indexed by this range. + type Length: Dim; + + /// The lower bound of the range, inclusive. + fn lower(&self, dimension: D) -> usize; + + /// The number of elements included in the range. + fn length(&self, dimension: D) -> Self::Length; + + /// Produces true if `Self` is contained within `dimension`. + fn contained_by(&self, dimension: D) -> bool; +} + +impl DimRange for usize { + type Length = U1; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + *self + } + + #[inline(always)] + fn length(&self, _: D) -> Self::Length { + Const::<1> + } + + #[inline(always)] + fn contained_by(&self, dimension: D) -> bool { + *self < dimension.value() + } +} + +#[test] +fn dimrange_usize() { + assert!(!DimRange::contained_by(&0, Const::<0>)); + assert!(DimRange::contained_by(&0, Const::<1>)); +} + +impl DimRange for ops::Range { + type Length = Dyn; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn length(&self, _: D) -> Self::Length { + Dyn(self.end.saturating_sub(self.start)) + } + + #[inline(always)] + fn contained_by(&self, dimension: D) -> bool { + (self.start < dimension.value()) && (self.end <= dimension.value()) + } +} + +#[test] +fn dimrange_range_usize() { + assert!(!DimRange::contained_by(&(0..0), Const::<0>)); + assert!(!DimRange::contained_by(&(0..1), Const::<0>)); + assert!(DimRange::contained_by(&(0..1), Const::<1>)); + assert!(DimRange::contained_by( + &((usize::MAX - 1)..usize::MAX), + Dyn(usize::MAX) + )); + assert_eq!( + DimRange::length(&((usize::MAX - 1)..usize::MAX), Dyn(usize::MAX)), + Dyn(1) + ); + assert_eq!( + DimRange::length(&(usize::MAX..(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(0) + ); + assert_eq!( + DimRange::length(&(usize::MAX..usize::MAX), Dyn(usize::MAX)), + Dyn(0) + ); +} + +impl DimRange for ops::RangeFrom { + type Length = Dyn; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn length(&self, dimension: D) -> Self::Length { + (self.start..dimension.value()).length(dimension) + } + + #[inline(always)] + fn contained_by(&self, dimension: D) -> bool { + self.start < dimension.value() + } +} + +#[test] +fn dimrange_rangefrom_usize() { + assert!(!DimRange::contained_by(&(0..), Const::<0>)); + assert!(!DimRange::contained_by(&(0..), Const::<0>)); + assert!(DimRange::contained_by(&(0..), Const::<1>)); + assert!(DimRange::contained_by( + &((usize::MAX - 1)..), + Dyn(usize::MAX) + )); + assert_eq!( + DimRange::length(&((usize::MAX - 1)..), Dyn(usize::MAX)), + Dyn(1) + ); + assert_eq!(DimRange::length(&(usize::MAX..), Dyn(usize::MAX)), Dyn(0)); +} + +impl DimRange for ops::RangeFrom +where + D: DimSub, +{ + type Length = DimDiff; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + self.start.value() + } + + #[inline(always)] + fn length(&self, dimension: D) -> Self::Length { + dimension.sub(self.start) + } + + #[inline(always)] + fn contained_by(&self, _: D) -> bool { + true + } +} + +#[test] +fn dimrange_rangefrom_dimname() { + assert_eq!(DimRange::length(&(Const::<1>..), Const::<5>), Const::<4>); +} + +impl DimRange for ops::RangeFull { + type Length = D; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn length(&self, dimension: D) -> Self::Length { + dimension + } + + #[inline(always)] + fn contained_by(&self, _: D) -> bool { + true + } +} + +#[test] +fn dimrange_rangefull() { + assert!(DimRange::contained_by(&(..), Const::<0>)); + assert_eq!(DimRange::length(&(..), Const::<1>), Const::<1>); +} + +impl DimRange for ops::RangeInclusive { + type Length = Dyn; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + *self.start() + } + + #[inline(always)] + fn length(&self, _: D) -> Self::Length { + Dyn(if self.end() < self.start() { + 0 + } else { + self.end().wrapping_sub(self.start().wrapping_sub(1)) + }) + } + + #[inline(always)] + fn contained_by(&self, dimension: D) -> bool { + (*self.start() < dimension.value()) && (*self.end() < dimension.value()) + } +} + +#[test] +fn dimrange_rangeinclusive_usize() { + assert!(!DimRange::contained_by(&(0..=0), Const::<0>)); + assert!(DimRange::contained_by(&(0..=0), Const::<1>)); + assert!(!DimRange::contained_by( + &(usize::MAX..=usize::MAX), + Dyn(usize::MAX) + )); + assert!(!DimRange::contained_by( + &((usize::MAX - 1)..=usize::MAX), + Dyn(usize::MAX) + )); + assert!(DimRange::contained_by( + &((usize::MAX - 1)..=(usize::MAX - 1)), + Dyn(usize::MAX) + )); + assert_eq!(DimRange::length(&(0..=0), Const::<1>), Dyn(1)); + assert_eq!( + DimRange::length(&((usize::MAX - 1)..=usize::MAX), Dyn(usize::MAX)), + Dyn(2) + ); + assert_eq!( + DimRange::length(&(usize::MAX..=(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(0) + ); + assert_eq!( + DimRange::length(&(usize::MAX..=usize::MAX), Dyn(usize::MAX)), + Dyn(1) + ); +} + +impl DimRange for ops::RangeTo { + type Length = Dyn; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn length(&self, _: D) -> Self::Length { + Dyn(self.end) + } + + #[inline(always)] + fn contained_by(&self, dimension: D) -> bool { + self.end <= dimension.value() + } +} + +#[test] +fn dimrange_rangeto_usize() { + assert!(DimRange::contained_by(&(..0), Const::<0>)); + assert!(!DimRange::contained_by(&(..1), Const::<0>)); + assert!(DimRange::contained_by(&(..0), Const::<1>)); + assert!(DimRange::contained_by( + &(..(usize::MAX - 1)), + Dyn(usize::MAX) + )); + assert_eq!( + DimRange::length(&(..(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(usize::MAX - 1) + ); + assert_eq!( + DimRange::length(&(..usize::MAX), Dyn(usize::MAX)), + Dyn(usize::MAX) + ); +} + +impl DimRange for ops::RangeToInclusive { + type Length = Dyn; + + #[inline(always)] + fn lower(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn length(&self, _: D) -> Self::Length { + Dyn(self.end + 1) + } + + #[inline(always)] + fn contained_by(&self, dimension: D) -> bool { + self.end < dimension.value() + } +} + +#[test] +fn dimrange_rangetoinclusive_usize() { + assert!(!DimRange::contained_by(&(..=0), Const::<0>)); + assert!(!DimRange::contained_by(&(..=1), Const::<0>)); + assert!(DimRange::contained_by(&(..=0), Const::<1>)); + assert!(!DimRange::contained_by(&(..=(usize::MAX)), Dyn(usize::MAX))); + assert!(DimRange::contained_by( + &(..=(usize::MAX - 1)), + Dyn(usize::MAX) + )); + assert_eq!( + DimRange::length(&(..=(usize::MAX - 1)), Dyn(usize::MAX)), + Dyn(usize::MAX) + ); +} + +/// A helper trait used for indexing operations. +pub trait MatrixIndex<'a, T, R: Dim, C: Dim, S: RawStorage>: Sized { + /// The output type returned by methods. + type Output: 'a; + + /// Produces true if the given matrix is contained by this index. + #[doc(hidden)] + fn contained_by(&self, matrix: &Matrix) -> bool; + + /// Produces a shared view of the data at this location if in bounds, + /// or `None`, otherwise. + #[doc(hidden)] + #[inline(always)] + fn get(self, matrix: &'a Matrix) -> Option { + if self.contained_by(matrix) { + Some(unsafe { self.get_unchecked(matrix) }) + } else { + None + } + } + + /// Produces a shared view of the data at this location if in bounds + /// without any bounds checking. + #[doc(hidden)] + unsafe fn get_unchecked(self, matrix: &'a Matrix) -> Self::Output; + + /// Produces a shared view to the data at this location, or panics + /// if out of bounds. + #[doc(hidden)] + #[inline(always)] + fn index(self, matrix: &'a Matrix) -> Self::Output { + self.get(matrix).expect("Index out of bounds.") + } +} + +/// A helper trait used for indexing operations. +pub trait MatrixIndexMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>: + MatrixIndex<'a, T, R, C, S> +{ + /// The output type returned by methods. + type OutputMut: 'a; + + /// Produces a mutable view of the data at this location, without + /// performing any bounds checking. + #[doc(hidden)] + unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut; + + /// Produces a mutable view of the data at this location, if in + /// bounds. + #[doc(hidden)] + #[inline(always)] + fn get_mut(self, matrix: &'a mut Matrix) -> Option { + if self.contained_by(matrix) { + Some(unsafe { self.get_unchecked_mut(matrix) }) + } else { + None + } + } + + /// Produces a mutable view of the data at this location, or panics + /// if out of bounds. + #[doc(hidden)] + #[inline(always)] + fn index_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut { + self.get_mut(matrix).expect("Index out of bounds.") + } +} + +/// # Views based on ranges +/// ## Indices to Individual Elements +/// ### Two-Dimensional Indices +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix2::new(0, 2, +/// 1, 3); +/// +/// assert_eq!(matrix.index((0, 0)), &0); +/// assert_eq!(matrix.index((1, 0)), &1); +/// assert_eq!(matrix.index((0, 1)), &2); +/// assert_eq!(matrix.index((1, 1)), &3); +/// ``` +/// +/// ### Linear Address Indexing +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix2::new(0, 2, +/// 1, 3); +/// +/// assert_eq!(matrix.get(0), Some(&0)); +/// assert_eq!(matrix.get(1), Some(&1)); +/// assert_eq!(matrix.get(2), Some(&2)); +/// assert_eq!(matrix.get(3), Some(&3)); +/// ``` +/// +/// ## Indices to Individual Rows and Columns +/// ### Index to a Row +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix2::new(0, 2, +/// 1, 3); +/// +/// assert!(matrix.index((0, ..)) +/// .eq(&Matrix1x2::new(0, 2))); +/// ``` +/// +/// ### Index to a Column +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix2::new(0, 2, +/// 1, 3); +/// +/// assert!(matrix.index((.., 0)) +/// .eq(&Matrix2x1::new(0, +/// 1))); +/// ``` +/// +/// ## Indices to Parts of Individual Rows and Columns +/// ### Index to a Partial Row +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix3::new(0, 3, 6, +/// 1, 4, 7, +/// 2, 5, 8); +/// +/// assert!(matrix.index((0, ..2)) +/// .eq(&Matrix1x2::new(0, 3))); +/// ``` +/// +/// ### Index to a Partial Column +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix3::new(0, 3, 6, +/// 1, 4, 7, +/// 2, 5, 8); +/// +/// assert!(matrix.index((..2, 0)) +/// .eq(&Matrix2x1::new(0, +/// 1))); +/// +/// assert!(matrix.index((Const::<1>.., 0)) +/// .eq(&Matrix2x1::new(1, +/// 2))); +/// ``` +/// ## Indices to Ranges of Rows and Columns +/// ### Index to a Range of Rows +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix3::new(0, 3, 6, +/// 1, 4, 7, +/// 2, 5, 8); +/// +/// assert!(matrix.index((1..3, ..)) +/// .eq(&Matrix2x3::new(1, 4, 7, +/// 2, 5, 8))); +/// ``` +/// ### Index to a Range of Columns +/// ``` +/// # use nalgebra::*; +/// let matrix = Matrix3::new(0, 3, 6, +/// 1, 4, 7, +/// 2, 5, 8); +/// +/// assert!(matrix.index((.., 1..3)) +/// .eq(&Matrix3x2::new(3, 6, +/// 4, 7, +/// 5, 8))); +/// ``` +impl> Matrix { + /// Produces a view of the data at the given index, or + /// `None` if the index is out of bounds. + #[inline] + #[must_use] + pub fn get<'a, I>(&'a self, index: I) -> Option + where + I: MatrixIndex<'a, T, R, C, S>, + { + index.get(self) + } + + /// Produces a mutable view of the data at the given index, or + /// `None` if the index is out of bounds. + #[inline] + #[must_use] + pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option + where + S: RawStorageMut, + I: MatrixIndexMut<'a, T, R, C, S>, + { + index.get_mut(self) + } + + /// Produces a view of the data at the given index, or + /// panics if the index is out of bounds. + #[inline] + #[must_use] + pub fn index<'a, I>(&'a self, index: I) -> I::Output + where + I: MatrixIndex<'a, T, R, C, S>, + { + index.index(self) + } + + /// Produces a mutable view of the data at the given index, or + /// panics if the index is out of bounds. + #[inline] + pub fn index_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut + where + S: RawStorageMut, + I: MatrixIndexMut<'a, T, R, C, S>, + { + index.index_mut(self) + } + + /// Produces a view of the data at the given index, without doing + /// any bounds checking. + /// + /// # Safety + /// + /// `index` must within bounds of the array. + #[inline] + #[must_use] + pub unsafe fn get_unchecked<'a, I>(&'a self, index: I) -> I::Output + where + I: MatrixIndex<'a, T, R, C, S>, + { + index.get_unchecked(self) + } + + /// Returns a mutable view of the data at the given index, without doing + /// any bounds checking. + /// # Safety + /// + /// `index` must within bounds of the array. + #[inline] + #[must_use] + pub unsafe fn get_unchecked_mut<'a, I>(&'a mut self, index: I) -> I::OutputMut + where + S: RawStorageMut, + I: MatrixIndexMut<'a, T, R, C, S>, + { + index.get_unchecked_mut(self) + } +} + +// EXTRACT A SINGLE ELEMENT BY 1D LINEAR ADDRESS + +impl<'a, T, R, C, S> MatrixIndex<'a, T, R, C, S> for usize +where + T: Scalar, + R: Dim, + C: Dim, + S: RawStorage, +{ + type Output = &'a T; + + #[doc(hidden)] + #[inline(always)] + fn contained_by(&self, matrix: &Matrix) -> bool { + *self < matrix.len() + } + + #[doc(hidden)] + #[inline(always)] + unsafe fn get_unchecked(self, matrix: &'a Matrix) -> Self::Output { + let nrows = matrix.shape().0; + let row = self % nrows; + let col = self / nrows; + matrix.data.get_unchecked(row, col) + } +} + +impl<'a, T, R, C, S> MatrixIndexMut<'a, T, R, C, S> for usize +where + T: Scalar, + R: Dim, + C: Dim, + S: RawStorageMut, +{ + type OutputMut = &'a mut T; + + #[doc(hidden)] + #[inline(always)] + unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut + where + S: RawStorageMut, + { + let nrows = matrix.shape().0; + let row = self % nrows; + let col = self / nrows; + matrix.data.get_unchecked_mut(row, col) + } +} + +// EXTRACT A SINGLE ELEMENT BY 2D COORDINATES + +impl<'a, T: 'a, R, C, S> MatrixIndex<'a, T, R, C, S> for (usize, usize) +where + R: Dim, + C: Dim, + S: RawStorage, +{ + type Output = &'a T; + + #[doc(hidden)] + #[inline(always)] + fn contained_by(&self, matrix: &Matrix) -> bool { + let (rows, cols) = self; + let (nrows, ncols) = matrix.shape_generic(); + DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols) + } + + #[doc(hidden)] + #[inline(always)] + unsafe fn get_unchecked(self, matrix: &'a Matrix) -> Self::Output { + let (row, col) = self; + matrix.data.get_unchecked(row, col) + } +} + +impl<'a, T: 'a, R, C, S> MatrixIndexMut<'a, T, R, C, S> for (usize, usize) +where + R: Dim, + C: Dim, + S: RawStorageMut, +{ + type OutputMut = &'a mut T; + + #[doc(hidden)] + #[inline(always)] + unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut + where + S: RawStorageMut, + { + let (row, col) = self; + matrix.data.get_unchecked_mut(row, col) + } +} + +macro_rules! impl_index_pair { + ( + $R: ident, + $C: ident, + [<$($RTyP: ident : $RTyPB: ty,)*> usize => $ROut: ty + $(where $RConstraintType: ty: $RConstraintBound: ident<$($RConstraintBoundParams: ty $( = $REqBound: ty )*),*>)*], + [<$($CTyP: ident : $CTyPB: ty,)*> usize => $COut: ty + $(where $CConstraintType: ty: $CConstraintBound: ident<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)*] + ) => {}; + + ( + $R: ident, + $C: ident, + [<$($RTyP: ident: $RTyPB: tt),*> $RIdx: ty => $ROut: ty + $(where $RConstraintType: ty: $RConstraintBound: ident $(<$($RConstraintBoundParams: ty $( = $REqBound: ty )*),*>)* )*], + [<$($CTyP: ident: $CTyPB: tt),*> $CIdx: ty => $COut: ty + $(where $CConstraintType: ty: $CConstraintBound: ident $(<$($CConstraintBoundParams: ty $( = $CEqBound: ty )*),*>)* )*] + ) => + { + impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndex<'a, T, $R, $C, S> for ($RIdx, $CIdx) + where + T: Scalar, + $R: Dim, + $C: Dim, + S: RawStorage, + $( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)* + $( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),* + { + type Output = MatrixView<'a, T, $ROut, $COut, S::RStride, S::CStride>; + + #[doc(hidden)] + #[inline(always)] + fn contained_by(&self, matrix: &Matrix) -> bool { + let (rows, cols) = self; + let (nrows, ncols) = matrix.shape_generic(); + DimRange::contained_by(rows, nrows) && DimRange::contained_by(cols, ncols) + } + + #[doc(hidden)] + #[inline(always)] + unsafe fn get_unchecked(self, matrix: &'a Matrix) -> Self::Output { + use crate::base::ViewStorage; + + let (rows, cols) = self; + let (nrows, ncols) = matrix.shape_generic(); + + let data = + ViewStorage::new_unchecked(&matrix.data, + (rows.lower(nrows), cols.lower(ncols)), + (rows.length(nrows), cols.length(ncols))); + + Matrix::from_data_statically_unchecked(data) + } + } + + impl<'a, T, $R, $C, S, $($RTyP : $RTyPB,)* $($CTyP : $CTyPB),*> MatrixIndexMut<'a, T, $R, $C, S> for ($RIdx, $CIdx) + where + T: Scalar, + $R: Dim, + $C: Dim, + S: RawStorageMut, + $( $RConstraintType: $RConstraintBound $(<$( $RConstraintBoundParams $( = $REqBound )*),*>)* ,)* + $( $CConstraintType: $CConstraintBound $(<$( $CConstraintBoundParams $( = $CEqBound )*),*>)* ),* + { + type OutputMut = MatrixViewMut<'a, T, $ROut, $COut, S::RStride, S::CStride>; + + #[doc(hidden)] + #[inline(always)] + unsafe fn get_unchecked_mut(self, matrix: &'a mut Matrix) -> Self::OutputMut { + use crate::base::ViewStorageMut; + + let (rows, cols) = self; + let (nrows, ncols) = matrix.shape_generic(); + + let data = + ViewStorageMut::new_unchecked(&mut matrix.data, + (rows.lower(nrows), cols.lower(ncols)), + (rows.length(nrows), cols.length(ncols))); + + Matrix::from_data_statically_unchecked(data) + } + } + } +} + +macro_rules! impl_index_pairs { + (index $R: ident with {} index $C: ident with {$($r: tt,)* }) => {}; + + (index $R: ident with {$lh : tt, $($lt : tt,)*} + index $C: ident with { $($r: tt,)* }) => + { + $( + impl_index_pair!{$R, $C, $lh, $r} + )* + impl_index_pairs!{index $R with {$($lt,)*} index $C with {$($r,)*}} + } +} + +impl_index_pairs! { + index R with { + [<> usize => U1], + [<> ops::Range => Dyn], + [<> ops::RangeFrom => Dyn], + [<> ops::RangeFull => R], + [<> ops::RangeInclusive => Dyn], + [<> ops::RangeTo => Dyn], + [<> ops::RangeToInclusive => Dyn], + + [ ops::RangeFrom + => DimDiff + where R: DimSub], + } + index C with { + [<> usize => U1], + [<> ops::Range => Dyn], + [<> ops::RangeFrom => Dyn], + [<> ops::RangeFull => C], + [<> ops::RangeInclusive => Dyn], + [<> ops::RangeTo => Dyn], + [<> ops::RangeToInclusive => Dyn], + + [ ops::RangeFrom + => DimDiff + where C: DimSub], + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/interpolation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/interpolation.rs new file mode 100644 index 000000000..cd722a5ed --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/interpolation.rs @@ -0,0 +1,130 @@ +use crate::storage::Storage; +use crate::{ + Allocator, DefaultAllocator, Dim, OVector, One, RealField, Scalar, Unit, Vector, Zero, +}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, ClosedSubAssign}; + +/// # Interpolation +impl< + T: Scalar + Zero + One + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign, + D: Dim, + S: Storage, + > Vector +{ + /// Returns `self * (1.0 - t) + rhs * t`, i.e., the linear blend of the vectors x and y using the scalar value a. + /// + /// The value for a is not restricted to the range `[0, 1]`. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let x = Vector3::new(1.0, 2.0, 3.0); + /// let y = Vector3::new(10.0, 20.0, 30.0); + /// assert_eq!(x.lerp(&y, 0.1), Vector3::new(1.9, 3.8, 5.7)); + /// ``` + #[must_use] + pub fn lerp>(&self, rhs: &Vector, t: T) -> OVector + where + DefaultAllocator: Allocator, + { + let mut res = self.clone_owned(); + res.axpy(t.clone(), rhs, T::one() - t); + res + } + + /// Computes the spherical linear interpolation between two non-zero vectors. + /// + /// The result is a unit vector. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Unit, Vector2}; + /// + /// let v1 =Vector2::new(1.0, 2.0); + /// let v2 = Vector2::new(2.0, -3.0); + /// + /// let v = v1.slerp(&v2, 1.0); + /// + /// assert_eq!(v, v2.normalize()); + /// ``` + #[must_use] + pub fn slerp>(&self, rhs: &Vector, t: T) -> OVector + where + T: RealField, + DefaultAllocator: Allocator, + { + let me = Unit::new_normalize(self.clone_owned()); + let rhs = Unit::new_normalize(rhs.clone_owned()); + me.slerp(&rhs, t).into_inner() + } +} + +/// # Interpolation between two unit vectors +impl> Unit> { + /// Computes the spherical linear interpolation between two unit vectors. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Unit, Vector2}; + /// + /// let v1 = Unit::new_normalize(Vector2::new(1.0, 2.0)); + /// let v2 = Unit::new_normalize(Vector2::new(2.0, -3.0)); + /// + /// let v = v1.slerp(&v2, 1.0); + /// + /// assert_eq!(v, v2); + /// ``` + #[must_use] + pub fn slerp>( + &self, + rhs: &Unit>, + t: T, + ) -> Unit> + where + DefaultAllocator: Allocator, + { + // TODO: the result is wrong when self and rhs are collinear with opposite direction. + self.try_slerp(rhs, t, T::default_epsilon()) + .unwrap_or_else(|| Unit::new_unchecked(self.clone_owned())) + } + + /// Computes the spherical linear interpolation between two unit vectors. + /// + /// Returns `None` if the two vectors are almost collinear and with opposite direction + /// (in this case, there is an infinity of possible results). + #[must_use] + pub fn try_slerp>( + &self, + rhs: &Unit>, + t: T, + epsilon: T, + ) -> Option>> + where + DefaultAllocator: Allocator, + { + let c_hang = self.dot(rhs); + + // self == other + if c_hang >= T::one() { + return Some(Unit::new_unchecked(self.clone_owned())); + } + + let hang = c_hang.clone().acos(); + let s_hang = (T::one() - c_hang.clone() * c_hang).sqrt(); + + // TODO: what if s_hang is 0.0 ? The result is not well-defined. + if relative_eq!(s_hang, T::zero(), epsilon = epsilon) { + None + } else { + let ta = ((T::one() - t.clone()) * hang.clone()).sin() / s_hang.clone(); + let tb = (t * hang).sin() / s_hang; + let mut res = self.scale(ta); + res.axpy(tb, &**rhs, T::one()); + + Some(Unit::new_unchecked(res)) + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/iter.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/iter.rs new file mode 100644 index 000000000..d74a30b5e --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/iter.rs @@ -0,0 +1,572 @@ +//! Matrix iterators. + +// only enables the `doc_cfg` feature when +// the `docsrs` configuration attribute is defined +#![cfg_attr(docsrs, feature(doc_cfg))] + +use core::fmt::Debug; +use core::ops::Range; +use std::iter::FusedIterator; +use std::marker::PhantomData; +use std::mem; + +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::{RawStorage, RawStorageMut}; +use crate::base::{Matrix, MatrixView, MatrixViewMut, Scalar, ViewStorage, ViewStorageMut}; + +#[derive(Clone, Debug)] +struct RawIter { + ptr: Ptr, + inner_ptr: Ptr, + inner_end: Ptr, + size: usize, + strides: (RStride, CStride), + _phantoms: PhantomData<(fn() -> T, R, C)>, +} + +macro_rules! iterator { + (struct $Name:ident for $Storage:ident.$ptr: ident -> $Ptr:ty, $Ref:ty, $SRef: ty, $($derives:ident),* $(,)?) => { + // TODO: we need to specialize for the case where the matrix storage is owned (in which + // case the iterator is trivial because it does not have any stride). + impl + RawIter<$Ptr, T, R, C, RStride, CStride> + { + /// Creates a new iterator for the given matrix storage. + fn new<'a, S: $Storage>( + storage: $SRef, + ) -> Self { + let shape = storage.shape(); + let strides = storage.strides(); + let inner_offset = shape.0.value() * strides.0.value(); + let size = shape.0.value() * shape.1.value(); + let ptr = storage.$ptr(); + + // If we have a size of 0, 'ptr' must be + // dangling. However, 'inner_offset' might + // not be zero if only one dimension is zero, so + // we don't want to call 'offset'. + // This pointer will never actually get used + // if our size is '0', so it's fine to use + // 'ptr' for both the start and end. + let inner_end = if size == 0 { + ptr + } else { + // Safety: + // If 'size' is non-zero, we know that 'ptr' + // is not dangling, and 'inner_offset' must lie + // within the allocation + unsafe { ptr.add(inner_offset) } + }; + + RawIter { + ptr, + inner_ptr: ptr, + inner_end, + size: shape.0.value() * shape.1.value(), + strides, + _phantoms: PhantomData, + } + } + } + + impl Iterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + type Item = $Ptr; + + #[inline] + fn next(&mut self) -> Option { + unsafe { + if self.size == 0 { + None + } else { + self.size -= 1; + + // Jump to the next outer dimension if needed. + if self.ptr == self.inner_end { + let stride = self.strides.1.value() as isize; + // This might go past the end of the allocation, + // depending on the value of 'size'. We use + // `wrapping_offset` to avoid UB + self.inner_end = self.ptr.wrapping_offset(stride); + // This will always be in bounds, since + // we're going to dereference it + self.ptr = self.inner_ptr.offset(stride); + self.inner_ptr = self.ptr; + } + + // Go to the next element. + let old = self.ptr; + + // Don't offset `self.ptr` for the last element, + // as this will be out of bounds. Iteration is done + // at this point (the next call to `next` will return `None`) + // so this is not observable. + if self.size != 0 { + let stride = self.strides.0.value(); + self.ptr = self.ptr.add(stride); + } + + Some(old) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.size, Some(self.size)) + } + + #[inline] + fn count(self) -> usize { + self.size_hint().0 + } + } + + impl DoubleEndedIterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + #[inline] + fn next_back(&mut self) -> Option { + unsafe { + if self.size == 0 { + None + } else { + // Pre-decrement `size` such that it now counts to the + // element we want to return. + self.size -= 1; + + // Fetch strides + let inner_stride = self.strides.0.value(); + let outer_stride = self.strides.1.value(); + + // Compute number of rows + // Division should be exact + let inner_raw_size = self.inner_end.offset_from(self.inner_ptr) as usize; + let inner_size = inner_raw_size / inner_stride; + + // Compute rows and cols remaining + let outer_remaining = self.size / inner_size; + let inner_remaining = self.size % inner_size; + + // Compute pointer to last element + let last = self + .ptr + .add((outer_remaining * outer_stride + inner_remaining * inner_stride)); + + Some(last) + } + } + } + } + + impl ExactSizeIterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + #[inline] + fn len(&self) -> usize { + self.size + } + } + + impl FusedIterator + for RawIter<$Ptr, T, R, C, RStride, CStride> + { + } + + /// An iterator through a dense matrix with arbitrary strides matrix. + #[derive($($derives),*)] + pub struct $Name<'a, T, R: Dim, C: Dim, S: 'a + $Storage> { + inner: RawIter<$Ptr, T, R, C, S::RStride, S::CStride>, + _marker: PhantomData<$Ref>, + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> $Name<'a, T, R, C, S> { + /// Creates a new iterator for the given matrix storage. + pub fn new(storage: $SRef) -> Self { + Self { + inner: RawIter::<$Ptr, T, R, C, S::RStride, S::CStride>::new(storage), + _marker: PhantomData, + } + } + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> Iterator for $Name<'a, T, R, C, S> { + type Item = $Ref; + + #[inline(always)] + fn next(&mut self) -> Option { + // We want either `& *last` or `&mut *last` here, depending + // on the mutability of `$Ref`. + #[allow(clippy::transmute_ptr_to_ref)] + self.inner.next().map(|ptr| unsafe { mem::transmute(ptr) }) + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + #[inline(always)] + fn count(self) -> usize { + self.inner.count() + } + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> DoubleEndedIterator + for $Name<'a, T, R, C, S> + { + #[inline(always)] + fn next_back(&mut self) -> Option { + // We want either `& *last` or `&mut *last` here, depending + // on the mutability of `$Ref`. + #[allow(clippy::transmute_ptr_to_ref)] + self.inner + .next_back() + .map(|ptr| unsafe { mem::transmute(ptr) }) + } + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> ExactSizeIterator + for $Name<'a, T, R, C, S> + { + #[inline(always)] + fn len(&self) -> usize { + self.inner.len() + } + } + + impl<'a, T, R: Dim, C: Dim, S: 'a + $Storage> FusedIterator + for $Name<'a, T, R, C, S> + { + } + }; +} + +iterator!(struct MatrixIter for RawStorage.ptr -> *const T, &'a T, &'a S, Clone, Debug); +iterator!(struct MatrixIterMut for RawStorageMut.ptr_mut -> *mut T, &'a mut T, &'a mut S, Debug); + +impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + MatrixIter<'a, T, R, C, ViewStorage<'a, T, R, C, RStride, CStride>> +{ + /// Creates a new iterator for the given matrix storage view. + pub fn new_owned(storage: ViewStorage<'a, T, R, C, RStride, CStride>) -> Self { + Self { + inner: RawIter::<*const T, T, R, C, RStride, CStride>::new(&storage), + _marker: PhantomData, + } + } +} + +impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + MatrixIterMut<'a, T, R, C, ViewStorageMut<'a, T, R, C, RStride, CStride>> +{ + /// Creates a new iterator for the given matrix storage view. + pub fn new_owned_mut(mut storage: ViewStorageMut<'a, T, R, C, RStride, CStride>) -> Self { + Self { + inner: RawIter::<*mut T, T, R, C, RStride, CStride>::new(&mut storage), + _marker: PhantomData, + } + } +} + +/* + * + * Row iterators. + * + */ +#[derive(Clone, Debug)] +/// An iterator through the rows of a matrix. +pub struct RowIter<'a, T, R: Dim, C: Dim, S: RawStorage> { + mat: &'a Matrix, + curr: usize, +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> RowIter<'a, T, R, C, S> { + pub(crate) fn new(mat: &'a Matrix) -> Self { + RowIter { mat, curr: 0 } + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for RowIter<'a, T, R, C, S> { + type Item = MatrixView<'a, T, U1, C, S::RStride, S::CStride>; + + #[inline] + fn next(&mut self) -> Option { + if self.curr < self.mat.nrows() { + let res = self.mat.row(self.curr); + self.curr += 1; + Some(res) + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + ( + self.mat.nrows() - self.curr, + Some(self.mat.nrows() - self.curr), + ) + } + + #[inline] + fn count(self) -> usize { + self.mat.nrows() - self.curr + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterator + for RowIter<'a, T, R, C, S> +{ + #[inline] + fn len(&self) -> usize { + self.mat.nrows() - self.curr + } +} + +/// An iterator through the mutable rows of a matrix. +#[derive(Debug)] +pub struct RowIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { + mat: *mut Matrix, + curr: usize, + phantom: PhantomData<&'a mut Matrix>, +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> RowIterMut<'a, T, R, C, S> { + pub(crate) fn new(mat: &'a mut Matrix) -> Self { + RowIterMut { + mat, + curr: 0, + phantom: PhantomData, + } + } + + fn nrows(&self) -> usize { + unsafe { (*self.mat).nrows() } + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator + for RowIterMut<'a, T, R, C, S> +{ + type Item = MatrixViewMut<'a, T, U1, C, S::RStride, S::CStride>; + + #[inline] + fn next(&mut self) -> Option { + if self.curr < self.nrows() { + let res = unsafe { (*self.mat).row_mut(self.curr) }; + self.curr += 1; + Some(res) + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.nrows() - self.curr, Some(self.nrows() - self.curr)) + } + + #[inline] + fn count(self) -> usize { + self.nrows() - self.curr + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIterator + for RowIterMut<'a, T, R, C, S> +{ + #[inline] + fn len(&self) -> usize { + self.nrows() - self.curr + } +} + +/* + * Column iterators. + * + */ +#[derive(Clone, Debug)] +/// An iterator through the columns of a matrix. +pub struct ColumnIter<'a, T, R: Dim, C: Dim, S: RawStorage> { + mat: &'a Matrix, + range: Range, +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> ColumnIter<'a, T, R, C, S> { + /// a new column iterator covering all columns of the matrix + pub(crate) fn new(mat: &'a Matrix) -> Self { + ColumnIter { + mat, + range: 0..mat.ncols(), + } + } + + #[cfg(feature = "rayon")] + pub(crate) fn split_at(self, index: usize) -> (Self, Self) { + // SAFETY: this makes sure the generated ranges are valid. + let split_pos = (self.range.start + index).min(self.range.end); + + let left_iter = ColumnIter { + mat: self.mat, + range: self.range.start..split_pos, + }; + + let right_iter = ColumnIter { + mat: self.mat, + range: split_pos..self.range.end, + }; + + (left_iter, right_iter) + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> Iterator for ColumnIter<'a, T, R, C, S> { + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; + + #[inline] + fn next(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if self.range.start < self.range.end { + let res = self.mat.column(self.range.start); + self.range.start += 1; + Some(res) + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let hint = self.range.len(); + (hint, Some(hint)) + } + + #[inline] + fn count(self) -> usize { + self.range.len() + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorage> DoubleEndedIterator + for ColumnIter<'a, T, R, C, S> +{ + fn next_back(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if !self.range.is_empty() { + self.range.end -= 1; + debug_assert!(self.range.end < self.mat.ncols()); + debug_assert!(self.range.end >= self.range.start); + Some(self.mat.column(self.range.end)) + } else { + None + } + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorage> ExactSizeIterator + for ColumnIter<'a, T, R, C, S> +{ + #[inline] + fn len(&self) -> usize { + self.range.end - self.range.start + } +} + +/// An iterator through the mutable columns of a matrix. +#[derive(Debug)] +pub struct ColumnIterMut<'a, T, R: Dim, C: Dim, S: RawStorageMut> { + mat: *mut Matrix, + range: Range, + phantom: PhantomData<&'a mut Matrix>, +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> ColumnIterMut<'a, T, R, C, S> { + pub(crate) fn new(mat: &'a mut Matrix) -> Self { + let range = 0..mat.ncols(); + ColumnIterMut { + mat, + range, + phantom: Default::default(), + } + } + + #[cfg(feature = "rayon")] + pub(crate) fn split_at(self, index: usize) -> (Self, Self) { + // SAFETY: this makes sure the generated ranges are valid. + let split_pos = (self.range.start + index).min(self.range.end); + + let left_iter = ColumnIterMut { + mat: self.mat, + range: self.range.start..split_pos, + phantom: Default::default(), + }; + + let right_iter = ColumnIterMut { + mat: self.mat, + range: split_pos..self.range.end, + phantom: Default::default(), + }; + + (left_iter, right_iter) + } + + fn ncols(&self) -> usize { + unsafe { (*self.mat).ncols() } + } +} + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Iterator + for ColumnIterMut<'a, T, R, C, S> +{ + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; + + #[inline] + fn next(&'_ mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if self.range.start < self.range.end { + let res = unsafe { (*self.mat).column_mut(self.range.start) }; + self.range.start += 1; + Some(res) + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let hint = self.range.len(); + (hint, Some(hint)) + } + + #[inline] + fn count(self) -> usize { + self.range.len() + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> ExactSizeIterator + for ColumnIterMut<'a, T, R, C, S> +{ + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> DoubleEndedIterator + for ColumnIterMut<'a, T, R, C, S> +{ + fn next_back(&mut self) -> Option { + debug_assert!(self.range.start <= self.range.end); + if !self.range.is_empty() { + self.range.end -= 1; + debug_assert!(self.range.end < self.ncols()); + debug_assert!(self.range.end >= self.range.start); + Some(unsafe { (*self.mat).column_mut(self.range.end) }) + } else { + None + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix.rs new file mode 100644 index 000000000..6f358a84a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix.rs @@ -0,0 +1,2362 @@ +use num::{One, Zero}; + +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use std::any::TypeId; +use std::cmp::Ordering; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use std::mem; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "rkyv-serialize-no-std")] +use super::rkyv_wrappers::CustomPhantom; +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{with::With, Archive, Archived}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, ClosedSubAssign, Field, SupersetOf}; +use simba::simd::SimdPartialOrd; + +use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; +use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{Dim, DimAdd, DimSum, IsNotStaticOne, U1, U2, U3}; +use crate::base::iter::{ + ColumnIter, ColumnIterMut, MatrixIter, MatrixIterMut, RowIter, RowIterMut, +}; +use crate::base::storage::{Owned, RawStorage, RawStorageMut, SameShapeStorage}; +use crate::base::{Const, DefaultAllocator, OMatrix, OVector, Scalar, Unit}; +use crate::{ArrayStorage, SMatrix, SimdComplexField, Storage, UninitMatrix}; + +use crate::storage::IsContiguous; +use crate::uninit::{Init, InitStatus, Uninit}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::{DMatrix, DVector, Dyn, RowDVector, VecStorage}; +use std::mem::MaybeUninit; + +/// A square matrix. +pub type SquareMatrix = Matrix; + +/// A matrix with one column and `D` rows. +pub type Vector = Matrix; + +/// A matrix with one row and `D` columns . +pub type RowVector = Matrix; + +/// The type of the result of a matrix sum. +pub type MatrixSum = + Matrix, SameShapeC, SameShapeStorage>; + +/// The type of the result of a matrix sum. +pub type VectorSum = + Matrix, U1, SameShapeStorage>; + +/// The type of the result of a matrix cross product. +pub type MatrixCross = + Matrix, SameShapeC, SameShapeStorage>; + +/// The most generic column-major matrix (and vector) type. +/// +/// # Methods summary +/// Because `Matrix` is the most generic types used as a common representation of all matrices and +/// vectors of **nalgebra** this documentation page contains every single matrix/vector-related +/// method. In order to make browsing this page simpler, the next subsections contain direct links +/// to groups of methods related to a specific topic. +/// +/// #### Vector and matrix construction +/// - [Constructors of statically-sized vectors or statically-sized matrices](#constructors-of-statically-sized-vectors-or-statically-sized-matrices) +/// (`Vector3`, `Matrix3x6`…) +/// - [Constructors of fully dynamic matrices](#constructors-of-fully-dynamic-matrices) (`DMatrix`) +/// - [Constructors of dynamic vectors and matrices with a dynamic number of rows](#constructors-of-dynamic-vectors-and-matrices-with-a-dynamic-number-of-rows) +/// (`DVector`, `MatrixXx3`…) +/// - [Constructors of matrices with a dynamic number of columns](#constructors-of-matrices-with-a-dynamic-number-of-columns) +/// (`Matrix2xX`…) +/// - [Generic constructors](#generic-constructors) +/// (For code generic wrt. the vectors or matrices dimensions.) +/// +/// #### Computer graphics utilities for transformations +/// - [2D transformations as a Matrix3 `new_rotation`…](#2d-transformations-as-a-matrix3) +/// - [3D transformations as a Matrix4 `new_rotation`, `new_perspective`, `look_at_rh`…](#3d-transformations-as-a-matrix4) +/// - [Translation and scaling in any dimension `new_scaling`, `new_translation`…](#translation-and-scaling-in-any-dimension) +/// - [Append/prepend translation and scaling `append_scaling`, `prepend_translation_mut`…](#appendprepend-translation-and-scaling) +/// - [Transformation of vectors and points `transform_vector`, `transform_point`…](#transformation-of-vectors-and-points) +/// +/// #### Common math operations +/// - [Componentwise operations `component_mul`, `component_div`, `inf`…](#componentwise-operations) +/// - [Special multiplications `tr_mul`, `ad_mul`, `kronecker`…](#special-multiplications) +/// - [Dot/scalar product `dot`, `dotc`, `tr_dot`…](#dotscalar-product) +/// - [Cross product `cross`, `perp`…](#cross-product) +/// - [Magnitude and norms `norm`, `normalize`, `metric_distance`…](#magnitude-and-norms) +/// - [In-place normalization `normalize_mut`, `try_normalize_mut`…](#in-place-normalization) +/// - [Interpolation `lerp`, `slerp`…](#interpolation) +/// - [BLAS functions `gemv`, `gemm`, `syger`…](#blas-functions) +/// - [Swizzling `xx`, `yxz`…](#swizzling) +/// - [Triangular matrix extraction `upper_triangle`, `lower_triangle`](#triangular-matrix-extraction) +/// +/// #### Statistics +/// - [Common operations `row_sum`, `column_mean`, `variance`…](#common-statistics-operations) +/// - [Find the min and max components `min`, `max`, `amin`, `amax`, `camin`, `cmax`…](#find-the-min-and-max-components) +/// - [Find the min and max components (vector-specific methods) `argmin`, `argmax`, `icamin`, `icamax`…](#find-the-min-and-max-components-vector-specific-methods) +/// +/// #### Iteration, map, and fold +/// - [Iteration on components, rows, and columns `iter`, `column_iter`…](#iteration-on-components-rows-and-columns) +/// - [Parallel iterators using rayon `par_column_iter`, `par_column_iter_mut`…](#parallel-iterators-using-rayon) +/// - [Elementwise mapping and folding `map`, `fold`, `zip_map`…](#elementwise-mapping-and-folding) +/// - [Folding or columns and rows `compress_rows`, `compress_columns`…](#folding-on-columns-and-rows) +/// +/// #### Vector and matrix views +/// - [Creating matrix views from `&[T]` `from_slice`, `from_slice_with_strides`…](#creating-matrix-views-from-t) +/// - [Creating mutable matrix views from `&mut [T]` `from_slice_mut`, `from_slice_with_strides_mut`…](#creating-mutable-matrix-views-from-mut-t) +/// - [Views based on index and length `row`, `columns`, `view`…](#views-based-on-index-and-length) +/// - [Mutable views based on index and length `row_mut`, `columns_mut`, `view_mut`…](#mutable-views-based-on-index-and-length) +/// - [Views based on ranges `rows_range`, `columns_range`…](#views-based-on-ranges) +/// - [Mutable views based on ranges `rows_range_mut`, `columns_range_mut`…](#mutable-views-based-on-ranges) +/// +/// #### In-place modification of a single matrix or vector +/// - [In-place filling `fill`, `fill_diagonal`, `fill_with_identity`…](#in-place-filling) +/// - [In-place swapping `swap`, `swap_columns`…](#in-place-swapping) +/// - [Set rows, columns, and diagonal `set_column`, `set_diagonal`…](#set-rows-columns-and-diagonal) +/// +/// #### Vector and matrix size modification +/// - [Rows and columns insertion `insert_row`, `insert_column`…](#rows-and-columns-insertion) +/// - [Rows and columns removal `remove_row`, `remove column`…](#rows-and-columns-removal) +/// - [Rows and columns extraction `select_rows`, `select_columns`…](#rows-and-columns-extraction) +/// - [Resizing and reshaping `resize`, `reshape_generic`…](#resizing-and-reshaping) +/// - [In-place resizing `resize_mut`, `resize_vertically_mut`…](#in-place-resizing) +/// +/// #### Matrix decomposition +/// - [Rectangular matrix decomposition `qr`, `lu`, `svd`…](#rectangular-matrix-decomposition) +/// - [Square matrix decomposition `cholesky`, `symmetric_eigen`…](#square-matrix-decomposition) +/// +/// #### Vector basis computation +/// - [Basis and orthogonalization `orthonormal_subspace_basis`, `orthonormalize`…](#basis-and-orthogonalization) +/// +/// # Type parameters +/// The generic `Matrix` type has four type parameters: +/// - `T`: for the matrix components scalar type. +/// - `R`: for the matrix number of rows. +/// - `C`: for the matrix number of columns. +/// - `S`: for the matrix data storage, i.e., the buffer that actually contains the matrix +/// components. +/// +/// The matrix dimensions parameters `R` and `C` can either be: +/// - type-level unsigned integer constants (e.g. `U1`, `U124`) from the `nalgebra::` root module. +/// All numbers from 0 to 127 are defined that way. +/// - type-level unsigned integer constants (e.g. `U1024`, `U10000`) from the `typenum::` crate. +/// Using those, you will not get error messages as nice as for numbers smaller than 128 defined on +/// the `nalgebra::` module. +/// - the special value `Dyn` from the `nalgebra::` root module. This indicates that the +/// specified dimension is not known at compile-time. Note that this will generally imply that the +/// matrix data storage `S` performs a dynamic allocation and contains extra metadata for the +/// matrix shape. +/// +/// Note that mixing `Dyn` with type-level unsigned integers is allowed. Actually, a +/// dynamically-sized column vector should be represented as a `Matrix` (given +/// some concrete types for `T` and a compatible data storage type `S`). +#[repr(C)] +#[derive(Clone, Copy)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Matrix", + bound(archive = " + T: Archive, + S: Archive, + With, CustomPhantom<(Archived, R, C)>>: Archive, R, C)>> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +pub struct Matrix { + /// The data storage that contains all the matrix components. Disappointed? + /// + /// Well, if you came here to see how you can access the matrix components, + /// you may be in luck: you can access the individual components of all vectors with compile-time + /// dimensions <= 6 using field notation like this: + /// `vec.x`, `vec.y`, `vec.z`, `vec.w`, `vec.a`, `vec.b`. Reference and assignation work too: + /// ``` + /// # use nalgebra::Vector3; + /// let mut vec = Vector3::new(1.0, 2.0, 3.0); + /// vec.x = 10.0; + /// vec.y += 30.0; + /// assert_eq!(vec.x, 10.0); + /// assert_eq!(vec.y + 100.0, 132.0); + /// ``` + /// Similarly, for matrices with compile-time dimensions <= 6, you can use field notation + /// like this: `mat.m11`, `mat.m42`, etc. The first digit identifies the row to address + /// and the second digit identifies the column to address. So `mat.m13` identifies the component + /// at the first row and third column (note that the count of rows and columns start at 1 instead + /// of 0 here. This is so we match the mathematical notation). + /// + /// For all matrices and vectors, independently from their size, individual components can + /// be accessed and modified using indexing: `vec[20]`, `mat[(20, 19)]`. Here the indexing + /// starts at 0 as you would expect. + pub data: S, + + // NOTE: the fact that this field is private is important because + // this prevents the user from constructing a matrix with + // dimensions R, C that don't match the dimension of the + // storage S. Instead they have to use the unsafe function + // from_data_statically_unchecked. + // Note that it would probably make sense to just have + // the type `Matrix`, and have `T, R, C` be associated-types + // of the `RawStorage` trait. However, because we don't have + // specialization, this is not possible because these `T, R, C` + // allows us to desambiguate a lot of configurations. + #[cfg_attr(feature = "rkyv-serialize-no-std", with(CustomPhantom<(T::Archived, R, C)>))] + _phantoms: PhantomData<(T, R, C)>, +} + +impl fmt::Debug for Matrix { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.data.fmt(formatter) + } +} + +impl Default for Matrix +where + T: Scalar, + R: Dim, + C: Dim, + S: Default, +{ + fn default() -> Self { + Matrix { + data: Default::default(), + _phantoms: PhantomData, + } + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Matrix +where + T: Scalar, + R: Dim, + C: Dim, + S: Serialize, +{ + fn serialize(&self, serializer: Ser) -> Result + where + Ser: Serializer, + { + self.data.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'de, T, R, C, S> Deserialize<'de> for Matrix +where + T: Scalar, + R: Dim, + C: Dim, + S: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + S::deserialize(deserializer).map(|x| Matrix { + data: x, + _phantoms: PhantomData, + }) + } +} + +#[cfg(feature = "compare")] +impl> matrixcompare_core::Matrix + for Matrix +{ + fn rows(&self) -> usize { + self.nrows() + } + + fn cols(&self) -> usize { + self.ncols() + } + + fn access(&self) -> matrixcompare_core::Access<'_, T> { + matrixcompare_core::Access::Dense(self) + } +} + +#[cfg(feature = "compare")] +impl> matrixcompare_core::DenseAccess + for Matrix +{ + fn fetch_single(&self, row: usize, col: usize) -> T { + self.index((row, col)).clone() + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl> bytemuck::Zeroable + for Matrix +where + S: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl> bytemuck::Pod for Matrix +where + S: bytemuck::Pod, + Self: Copy, +{ +} + +impl Matrix { + /// Creates a new matrix with the given data without statically checking that the matrix + /// dimension matches the storage dimension. + /// + /// # Safety + /// + /// The storage dimension must match the given dimensions. + #[inline(always)] + pub const unsafe fn from_data_statically_unchecked(data: S) -> Matrix { + Matrix { + data, + _phantoms: PhantomData, + } + } +} + +impl SMatrix { + /// Creates a new statically-allocated matrix from the given [`ArrayStorage`]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + #[inline(always)] + pub const fn from_array_storage(storage: ArrayStorage) -> Self { + // This is sound because the row and column types are exactly the same as that of the + // storage, so there can be no mismatch + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +// TODO: Consider removing/deprecating `from_vec_storage` once we are able to make +// `from_data` const fn compatible +#[cfg(any(feature = "std", feature = "alloc"))] +impl DMatrix { + /// Creates a new heap-allocated matrix from the given [`VecStorage`]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +// TODO: Consider removing/deprecating `from_vec_storage` once we are able to make +// `from_data` const fn compatible +#[cfg(any(feature = "std", feature = "alloc"))] +impl DVector { + /// Creates a new heap-allocated matrix from the given [`VecStorage`]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +// TODO: Consider removing/deprecating `from_vec_storage` once we are able to make +// `from_data` const fn compatible +#[cfg(any(feature = "std", feature = "alloc"))] +impl RowDVector { + /// Creates a new heap-allocated matrix from the given [`VecStorage`]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +impl UninitMatrix +where + DefaultAllocator: Allocator, +{ + /// Assumes a matrix's entries to be initialized. This operation should be near zero-cost. + /// + /// # Safety + /// The user must make sure that every single entry of the buffer has been initialized, + /// or Undefined Behavior will immediately occur. + #[inline(always)] + pub unsafe fn assume_init(self) -> OMatrix { + OMatrix::from_data(>::assume_init( + self.data, + )) + } +} + +impl> Matrix { + /// Creates a new matrix with the given data. + #[inline(always)] + pub fn from_data(data: S) -> Self { + unsafe { Self::from_data_statically_unchecked(data) } + } + + /// The shape of this matrix returned as the tuple (number of rows, number of columns). + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.shape(), (3, 4)); + /// ``` + #[inline] + #[must_use] + pub fn shape(&self) -> (usize, usize) { + let (nrows, ncols) = self.shape_generic(); + (nrows.value(), ncols.value()) + } + + /// The shape of this matrix wrapped into their representative types (`Const` or `Dyn`). + #[inline] + #[must_use] + pub fn shape_generic(&self) -> (R, C) { + self.data.shape() + } + + /// The number of rows of this matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.nrows(), 3); + /// ``` + #[inline] + #[must_use] + pub fn nrows(&self) -> usize { + self.shape().0 + } + + /// The number of columns of this matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.ncols(), 4); + /// ``` + #[inline] + #[must_use] + pub fn ncols(&self) -> usize { + self.shape().1 + } + + /// The strides (row stride, column stride) of this matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::DMatrix; + /// let mat = DMatrix::::zeros(10, 10); + /// let view = mat.view_with_steps((0, 0), (5, 3), (1, 2)); + /// // The column strides is the number of steps (here 2) multiplied by the corresponding dimension. + /// assert_eq!(mat.strides(), (1, 10)); + /// ``` + #[inline] + #[must_use] + pub fn strides(&self) -> (usize, usize) { + let (srows, scols) = self.data.strides(); + (srows.value(), scols.value()) + } + + /// Computes the row and column coordinates of the i-th element of this matrix seen as a + /// vector. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2; + /// let m = Matrix2::new(1, 2, + /// 3, 4); + /// let i = m.vector_to_matrix_index(3); + /// assert_eq!(i, (1, 1)); + /// assert_eq!(m[i], m[3]); + /// ``` + #[inline] + #[must_use] + pub fn vector_to_matrix_index(&self, i: usize) -> (usize, usize) { + let (nrows, ncols) = self.shape(); + + // Two most common uses that should be optimized by the compiler for statically-sized + // matrices. + if nrows == 1 { + (0, i) + } else if ncols == 1 { + (i, 0) + } else { + (i % nrows, i / nrows) + } + } + + /// Returns a pointer to the start of the matrix. + /// + /// If the matrix is not empty, this pointer is guaranteed to be aligned + /// and non-null. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2; + /// let m = Matrix2::new(1, 2, + /// 3, 4); + /// let ptr = m.as_ptr(); + /// assert_eq!(unsafe { *ptr }, m[0]); + /// ``` + #[inline] + #[must_use] + pub fn as_ptr(&self) -> *const T { + self.data.ptr() + } + + /// Tests whether `self` and `rhs` are equal up to a given epsilon. + /// + /// See `relative_eq` from the `RelativeEq` trait for more details. + #[inline] + #[must_use] + pub fn relative_eq( + &self, + other: &Matrix, + eps: T::Epsilon, + max_relative: T::Epsilon, + ) -> bool + where + T: RelativeEq + Scalar, + R2: Dim, + C2: Dim, + SB: Storage, + T::Epsilon: Clone, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + assert!(self.shape() == other.shape()); + self.iter() + .zip(other.iter()) + .all(|(a, b)| a.relative_eq(b, eps.clone(), max_relative.clone())) + } + + /// Tests whether `self` and `rhs` are exactly equal. + #[inline] + #[must_use] + #[allow(clippy::should_implement_trait)] + pub fn eq(&self, other: &Matrix) -> bool + where + T: PartialEq, + R2: Dim, + C2: Dim, + SB: RawStorage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + assert!(self.shape() == other.shape()); + self.iter().zip(other.iter()).all(|(a, b)| *a == *b) + } + + /// Moves this matrix into one that owns its data. + #[inline] + pub fn into_owned(self) -> OMatrix + where + T: Scalar, + S: Storage, + DefaultAllocator: Allocator, + { + Matrix::from_data(self.data.into_owned()) + } + + // TODO: this could probably benefit from specialization. + // XXX: bad name. + /// Moves this matrix into one that owns its data. The actual type of the result depends on + /// matrix storage combination rules for addition. + #[inline] + pub fn into_owned_sum(self) -> MatrixSum + where + T: Scalar, + S: Storage, + R2: Dim, + C2: Dim, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + if TypeId::of::>() == TypeId::of::>() { + // We can just return `self.into_owned()`. + + unsafe { + // TODO: check that those copies are optimized away by the compiler. + let owned = self.into_owned(); + let res = mem::transmute_copy(&owned); + mem::forget(owned); + res + } + } else { + self.clone_owned_sum() + } + } + + /// Clones this matrix to one that owns its data. + #[inline] + #[must_use] + pub fn clone_owned(&self) -> OMatrix + where + T: Scalar, + S: Storage, + DefaultAllocator: Allocator, + { + Matrix::from_data(self.data.clone_owned()) + } + + /// Clones this matrix into one that owns its data. The actual type of the result depends on + /// matrix storage combination rules for addition. + #[inline] + #[must_use] + pub fn clone_owned_sum(&self) -> MatrixSum + where + T: Scalar, + S: Storage, + R2: Dim, + C2: Dim, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + let nrows: SameShapeR = Dim::from_usize(nrows); + let ncols: SameShapeC = Dim::from_usize(ncols); + + let mut res = Matrix::uninit(nrows, ncols); + + unsafe { + // TODO: use copy_from? + for j in 0..res.ncols() { + for i in 0..res.nrows() { + *res.get_unchecked_mut((i, j)) = + MaybeUninit::new(self.get_unchecked((i, j)).clone()); + } + } + + // SAFETY: the output has been initialized above. + res.assume_init() + } + } + + /// Transposes `self` and store the result into `out`. + #[inline] + fn transpose_to_uninit( + &self, + _status: Status, + out: &mut Matrix, + ) where + Status: InitStatus, + T: Scalar, + R2: Dim, + C2: Dim, + SB: RawStorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + assert!( + (ncols, nrows) == out.shape(), + "Incompatible shape for transposition." + ); + + // TODO: optimize that. + for i in 0..nrows { + for j in 0..ncols { + // Safety: the indices are in range. + unsafe { + Status::init( + out.get_unchecked_mut((j, i)), + self.get_unchecked((i, j)).clone(), + ); + } + } + } + } + + /// Transposes `self` and store the result into `out`. + #[inline] + pub fn transpose_to(&self, out: &mut Matrix) + where + T: Scalar, + R2: Dim, + C2: Dim, + SB: RawStorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + self.transpose_to_uninit(Init, out) + } + + /// Transposes `self`. + #[inline] + #[must_use = "Did you mean to use transpose_mut()?"] + pub fn transpose(&self) -> OMatrix + where + T: Scalar, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + + let mut res = Matrix::uninit(ncols, nrows); + self.transpose_to_uninit(Uninit, &mut res); + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } +} + +/// # Elementwise mapping and folding +impl> Matrix { + /// Returns a matrix containing the result of `f` applied to each of its entries. + #[inline] + #[must_use] + pub fn map T2>(&self, mut f: F) -> OMatrix + where + T: Scalar, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + let mut res = Matrix::uninit(nrows, ncols); + + for j in 0..ncols.value() { + for i in 0..nrows.value() { + // Safety: all indices are in range. + unsafe { + let a = self.data.get_unchecked(i, j).clone(); + *res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(a)); + } + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let q = Vector3::new(1.0f64, 2.0, 3.0); + /// let q2 = q.cast::(); + /// assert_eq!(q2, Vector3::new(1.0f32, 2.0, 3.0)); + /// ``` + pub fn cast(self) -> OMatrix + where + T: Scalar, + OMatrix: SupersetOf, + DefaultAllocator: Allocator, + { + crate::convert(self) + } + + /// Attempts to cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let q = Vector3::new(1.0f64, 2.0, 3.0); + /// let q2 = q.try_cast::(); + /// assert_eq!(q2, Some(Vector3::new(1, 2, 3))); + /// ``` + pub fn try_cast(self) -> Option> + where + T: Scalar, + Self: SupersetOf>, + DefaultAllocator: Allocator, + { + crate::try_convert(self) + } + + /// Similar to `self.iter().fold(init, f)` except that `init` is replaced by a closure. + /// + /// The initialization closure is given the first component of this matrix: + /// - If the matrix has no component (0 rows or 0 columns) then `init_f` is called with `None` + /// and its return value is the value returned by this method. + /// - If the matrix has has least one component, then `init_f` is called with the first component + /// to compute the initial value. Folding then continues on all the remaining components of the matrix. + #[inline] + #[must_use] + pub fn fold_with( + &self, + init_f: impl FnOnce(Option<&T>) -> T2, + f: impl FnMut(T2, &T) -> T2, + ) -> T2 + where + T: Scalar, + { + let mut it = self.iter(); + let init = init_f(it.next()); + it.fold(init, f) + } + + /// Returns a matrix containing the result of `f` applied to each of its entries. Unlike `map`, + /// `f` also gets passed the row and column index, i.e. `f(row, col, value)`. + #[inline] + #[must_use] + pub fn map_with_location T2>( + &self, + mut f: F, + ) -> OMatrix + where + T: Scalar, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + let mut res = Matrix::uninit(nrows, ncols); + + for j in 0..ncols.value() { + for i in 0..nrows.value() { + // Safety: all indices are in range. + unsafe { + let a = self.data.get_unchecked(i, j).clone(); + *res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(i, j, a)); + } + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Returns a matrix containing the result of `f` applied to each entries of `self` and + /// `rhs`. + #[inline] + #[must_use] + pub fn zip_map(&self, rhs: &Matrix, mut f: F) -> OMatrix + where + T: Scalar, + T2: Scalar, + N3: Scalar, + S2: RawStorage, + F: FnMut(T, T2) -> N3, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + let mut res = Matrix::uninit(nrows, ncols); + + assert_eq!( + (nrows.value(), ncols.value()), + rhs.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + + for j in 0..ncols.value() { + for i in 0..nrows.value() { + // Safety: all indices are in range. + unsafe { + let a = self.data.get_unchecked(i, j).clone(); + let b = rhs.data.get_unchecked(i, j).clone(); + *res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(a, b)) + } + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Returns a matrix containing the result of `f` applied to each entries of `self` and + /// `b`, and `c`. + #[inline] + #[must_use] + pub fn zip_zip_map( + &self, + b: &Matrix, + c: &Matrix, + mut f: F, + ) -> OMatrix + where + T: Scalar, + T2: Scalar, + N3: Scalar, + N4: Scalar, + S2: RawStorage, + S3: RawStorage, + F: FnMut(T, T2, N3) -> N4, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + let mut res = Matrix::uninit(nrows, ncols); + + assert_eq!( + (nrows.value(), ncols.value()), + b.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + assert_eq!( + (nrows.value(), ncols.value()), + c.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + + for j in 0..ncols.value() { + for i in 0..nrows.value() { + // Safety: all indices are in range. + unsafe { + let a = self.data.get_unchecked(i, j).clone(); + let b = b.data.get_unchecked(i, j).clone(); + let c = c.data.get_unchecked(i, j).clone(); + *res.data.get_unchecked_mut(i, j) = MaybeUninit::new(f(a, b, c)) + } + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Folds a function `f` on each entry of `self`. + #[inline] + #[must_use] + pub fn fold(&self, init: Acc, mut f: impl FnMut(Acc, T) -> Acc) -> Acc + where + T: Scalar, + { + let (nrows, ncols) = self.shape_generic(); + + let mut res = init; + + for j in 0..ncols.value() { + for i in 0..nrows.value() { + // Safety: all indices are in range. + unsafe { + let a = self.data.get_unchecked(i, j).clone(); + res = f(res, a) + } + } + } + + res + } + + /// Folds a function `f` on each pairs of entries from `self` and `rhs`. + #[inline] + #[must_use] + pub fn zip_fold( + &self, + rhs: &Matrix, + init: Acc, + mut f: impl FnMut(Acc, T, T2) -> Acc, + ) -> Acc + where + T: Scalar, + T2: Scalar, + R2: Dim, + C2: Dim, + S2: RawStorage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape_generic(); + + let mut res = init; + + assert_eq!( + (nrows.value(), ncols.value()), + rhs.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + + for j in 0..ncols.value() { + for i in 0..nrows.value() { + unsafe { + let a = self.data.get_unchecked(i, j).clone(); + let b = rhs.data.get_unchecked(i, j).clone(); + res = f(res, a, b) + } + } + } + + res + } + + /// Applies a closure `f` to modify each component of `self`. + #[inline] + pub fn apply(&mut self, mut f: F) + where + S: RawStorageMut, + { + let (nrows, ncols) = self.shape(); + + for j in 0..ncols { + for i in 0..nrows { + unsafe { + let e = self.data.get_unchecked_mut(i, j); + f(e) + } + } + } + } + + /// Replaces each component of `self` by the result of a closure `f` applied on its components + /// joined with the components from `rhs`. + #[inline] + pub fn zip_apply( + &mut self, + rhs: &Matrix, + mut f: impl FnMut(&mut T, T2), + ) where + S: RawStorageMut, + T2: Scalar, + R2: Dim, + C2: Dim, + S2: RawStorage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + + assert_eq!( + (nrows, ncols), + rhs.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + + for j in 0..ncols { + for i in 0..nrows { + unsafe { + let e = self.data.get_unchecked_mut(i, j); + let rhs = rhs.get_unchecked((i, j)).clone(); + f(e, rhs) + } + } + } + } + + /// Replaces each component of `self` by the result of a closure `f` applied on its components + /// joined with the components from `b` and `c`. + #[inline] + pub fn zip_zip_apply( + &mut self, + b: &Matrix, + c: &Matrix, + mut f: impl FnMut(&mut T, T2, N3), + ) where + S: RawStorageMut, + T2: Scalar, + R2: Dim, + C2: Dim, + S2: RawStorage, + N3: Scalar, + R3: Dim, + C3: Dim, + S3: RawStorage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + + assert_eq!( + (nrows, ncols), + b.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + assert_eq!( + (nrows, ncols), + c.shape(), + "Matrix simultaneous traversal error: dimension mismatch." + ); + + for j in 0..ncols { + for i in 0..nrows { + unsafe { + let e = self.data.get_unchecked_mut(i, j); + let b = b.get_unchecked((i, j)).clone(); + let c = c.get_unchecked((i, j)).clone(); + f(e, b, c) + } + } + } + } +} + +/// # Iteration on components, rows, and columns +impl> Matrix { + /// Iterates through this matrix coordinates in column-major order. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mat = Matrix2x3::new(11, 12, 13, + /// 21, 22, 23); + /// let mut it = mat.iter(); + /// assert_eq!(*it.next().unwrap(), 11); + /// assert_eq!(*it.next().unwrap(), 21); + /// assert_eq!(*it.next().unwrap(), 12); + /// assert_eq!(*it.next().unwrap(), 22); + /// assert_eq!(*it.next().unwrap(), 13); + /// assert_eq!(*it.next().unwrap(), 23); + /// assert!(it.next().is_none()); + /// ``` + #[inline] + pub fn iter(&self) -> MatrixIter<'_, T, R, C, S> { + MatrixIter::new(&self.data) + } + + /// Iterate through the rows of this matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mut a = Matrix2x3::new(1, 2, 3, + /// 4, 5, 6); + /// for (i, row) in a.row_iter().enumerate() { + /// assert_eq!(row, a.row(i)) + /// } + /// ``` + #[inline] + pub fn row_iter(&self) -> RowIter<'_, T, R, C, S> { + RowIter::new(self) + } + + /// Iterate through the columns of this matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mut a = Matrix2x3::new(1, 2, 3, + /// 4, 5, 6); + /// for (i, column) in a.column_iter().enumerate() { + /// assert_eq!(column, a.column(i)) + /// } + /// ``` + #[inline] + pub fn column_iter(&self) -> ColumnIter<'_, T, R, C, S> { + ColumnIter::new(self) + } + + /// Mutably iterates through this matrix coordinates. + #[inline] + pub fn iter_mut(&mut self) -> MatrixIterMut<'_, T, R, C, S> + where + S: RawStorageMut, + { + MatrixIterMut::new(&mut self.data) + } + + /// Mutably iterates through this matrix rows. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mut a = Matrix2x3::new(1, 2, 3, + /// 4, 5, 6); + /// for (i, mut row) in a.row_iter_mut().enumerate() { + /// row *= (i + 1) * 10; + /// } + /// + /// let expected = Matrix2x3::new(10, 20, 30, + /// 80, 100, 120); + /// assert_eq!(a, expected); + /// ``` + #[inline] + pub fn row_iter_mut(&mut self) -> RowIterMut<'_, T, R, C, S> + where + S: RawStorageMut, + { + RowIterMut::new(self) + } + + /// Mutably iterates through this matrix columns. + /// + /// # Example + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mut a = Matrix2x3::new(1, 2, 3, + /// 4, 5, 6); + /// for (i, mut col) in a.column_iter_mut().enumerate() { + /// col *= (i + 1) * 10; + /// } + /// + /// let expected = Matrix2x3::new(10, 40, 90, + /// 40, 100, 180); + /// assert_eq!(a, expected); + /// ``` + #[inline] + pub fn column_iter_mut(&mut self) -> ColumnIterMut<'_, T, R, C, S> + where + S: RawStorageMut, + { + ColumnIterMut::new(self) + } +} + +impl> Matrix { + /// Returns a mutable pointer to the start of the matrix. + /// + /// If the matrix is not empty, this pointer is guaranteed to be aligned + /// and non-null. + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self.data.ptr_mut() + } + + /// Swaps two entries without bound-checking. + /// + /// # Safety + /// + /// Both `(r, c)` must have `r < nrows(), c < ncols()`. + #[inline] + pub unsafe fn swap_unchecked(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) { + debug_assert!(row_cols1.0 < self.nrows() && row_cols1.1 < self.ncols()); + debug_assert!(row_cols2.0 < self.nrows() && row_cols2.1 < self.ncols()); + self.data.swap_unchecked(row_cols1, row_cols2) + } + + /// Swaps two entries. + #[inline] + pub fn swap(&mut self, row_cols1: (usize, usize), row_cols2: (usize, usize)) { + let (nrows, ncols) = self.shape(); + assert!( + row_cols1.0 < nrows && row_cols1.1 < ncols, + "Matrix elements swap index out of bounds." + ); + assert!( + row_cols2.0 < nrows && row_cols2.1 < ncols, + "Matrix elements swap index out of bounds." + ); + unsafe { self.swap_unchecked(row_cols1, row_cols2) } + } + + /// Fills this matrix with the content of a slice. Both must hold the same number of elements. + /// + /// The components of the slice are assumed to be ordered in column-major order. + #[inline] + pub fn copy_from_slice(&mut self, slice: &[T]) + where + T: Scalar, + { + let (nrows, ncols) = self.shape(); + + assert!( + nrows * ncols == slice.len(), + "The slice must contain the same number of elements as the matrix." + ); + + for j in 0..ncols { + for i in 0..nrows { + unsafe { + *self.get_unchecked_mut((i, j)) = slice.get_unchecked(i + j * nrows).clone(); + } + } + } + } + + /// Fills this matrix with the content of another one. Both must have the same shape. + #[inline] + pub fn copy_from(&mut self, other: &Matrix) + where + T: Scalar, + R2: Dim, + C2: Dim, + SB: RawStorage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + assert!( + self.shape() == other.shape(), + "Unable to copy from a matrix with a different shape." + ); + + for j in 0..self.ncols() { + for i in 0..self.nrows() { + unsafe { + *self.get_unchecked_mut((i, j)) = other.get_unchecked((i, j)).clone(); + } + } + } + } + + /// Fills this matrix with the content of the transpose another one. + #[inline] + pub fn tr_copy_from(&mut self, other: &Matrix) + where + T: Scalar, + R2: Dim, + C2: Dim, + SB: RawStorage, + ShapeConstraint: DimEq + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + assert!( + (ncols, nrows) == other.shape(), + "Unable to copy from a matrix with incompatible shape." + ); + + for j in 0..ncols { + for i in 0..nrows { + unsafe { + *self.get_unchecked_mut((i, j)) = other.get_unchecked((j, i)).clone(); + } + } + } + } + + // TODO: rename `apply` to `apply_mut` and `apply_into` to `apply`? + /// Returns `self` with each of its components replaced by the result of a closure `f` applied on it. + #[inline] + pub fn apply_into(mut self, f: F) -> Self { + self.apply(f); + self + } +} + +impl> Vector { + /// Gets a reference to the i-th element of this column vector without bound checking. + /// # Safety + /// `i` must be less than `D`. + #[inline] + #[must_use] + pub unsafe fn vget_unchecked(&self, i: usize) -> &T { + debug_assert!(i < self.nrows(), "Vector index out of bounds."); + let i = i * self.strides().0; + self.data.get_unchecked_linear(i) + } +} + +impl> Vector { + /// Gets a mutable reference to the i-th element of this column vector without bound checking. + /// # Safety + /// `i` must be less than `D`. + #[inline] + #[must_use] + pub unsafe fn vget_unchecked_mut(&mut self, i: usize) -> &mut T { + debug_assert!(i < self.nrows(), "Vector index out of bounds."); + let i = i * self.strides().0; + self.data.get_unchecked_linear_mut(i) + } +} + +impl + IsContiguous> Matrix { + /// Extracts a slice containing the entire matrix entries ordered column-by-columns. + #[inline] + #[must_use] + pub fn as_slice(&self) -> &[T] { + // Safety: this is OK thanks to the IsContiguous trait. + unsafe { self.data.as_slice_unchecked() } + } +} + +impl + IsContiguous> Matrix { + /// Extracts a mutable slice containing the entire matrix entries ordered column-by-columns. + #[inline] + #[must_use] + pub fn as_mut_slice(&mut self) -> &mut [T] { + // Safety: this is OK thanks to the IsContiguous trait. + unsafe { self.data.as_mut_slice_unchecked() } + } +} + +impl> Matrix { + /// Transposes the square matrix `self` in-place. + pub fn transpose_mut(&mut self) { + assert!( + self.is_square(), + "Unable to transpose a non-square matrix in-place." + ); + + let dim = self.shape().0; + + for i in 1..dim { + for j in 0..i { + unsafe { self.swap_unchecked((i, j), (j, i)) } + } + } + } +} + +impl> Matrix { + /// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`. + #[inline] + fn adjoint_to_uninit( + &self, + _status: Status, + out: &mut Matrix, + ) where + Status: InitStatus, + R2: Dim, + C2: Dim, + SB: RawStorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let (nrows, ncols) = self.shape(); + assert!( + (ncols, nrows) == out.shape(), + "Incompatible shape for transpose-copy." + ); + + // TODO: optimize that. + for i in 0..nrows { + for j in 0..ncols { + // Safety: all indices are in range. + unsafe { + Status::init( + out.get_unchecked_mut((j, i)), + self.get_unchecked((i, j)).clone().simd_conjugate(), + ); + } + } + } + } + + /// Takes the adjoint (aka. conjugate-transpose) of `self` and store the result into `out`. + #[inline] + pub fn adjoint_to(&self, out: &mut Matrix) + where + R2: Dim, + C2: Dim, + SB: RawStorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + self.adjoint_to_uninit(Init, out) + } + + /// The adjoint (aka. conjugate-transpose) of `self`. + #[inline] + #[must_use = "Did you mean to use adjoint_mut()?"] + pub fn adjoint(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + + let mut res = Matrix::uninit(ncols, nrows); + self.adjoint_to_uninit(Uninit, &mut res); + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Takes the conjugate and transposes `self` and store the result into `out`. + #[deprecated(note = "Renamed `self.adjoint_to(out)`.")] + #[inline] + pub fn conjugate_transpose_to(&self, out: &mut Matrix) + where + R2: Dim, + C2: Dim, + SB: RawStorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + self.adjoint_to(out) + } + + /// The conjugate transposition of `self`. + #[deprecated(note = "Renamed `self.adjoint()`.")] + #[inline] + pub fn conjugate_transpose(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + self.adjoint() + } + + /// The conjugate of `self`. + #[inline] + #[must_use = "Did you mean to use conjugate_mut()?"] + pub fn conjugate(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + self.map(|e| e.simd_conjugate()) + } + + /// Divides each component of the complex matrix `self` by the given real. + #[inline] + #[must_use = "Did you mean to use unscale_mut()?"] + pub fn unscale(&self, real: T::SimdRealField) -> OMatrix + where + DefaultAllocator: Allocator, + { + self.map(|e| e.simd_unscale(real.clone())) + } + + /// Multiplies each component of the complex matrix `self` by the given real. + #[inline] + #[must_use = "Did you mean to use scale_mut()?"] + pub fn scale(&self, real: T::SimdRealField) -> OMatrix + where + DefaultAllocator: Allocator, + { + self.map(|e| e.simd_scale(real.clone())) + } +} + +impl> Matrix { + /// The conjugate of the complex matrix `self` computed in-place. + #[inline] + pub fn conjugate_mut(&mut self) { + self.apply(|e| *e = e.clone().simd_conjugate()) + } + + /// Divides each component of the complex matrix `self` by the given real. + #[inline] + pub fn unscale_mut(&mut self, real: T::SimdRealField) { + self.apply(|e| *e = e.clone().simd_unscale(real.clone())) + } + + /// Multiplies each component of the complex matrix `self` by the given real. + #[inline] + pub fn scale_mut(&mut self, real: T::SimdRealField) { + self.apply(|e| *e = e.clone().simd_scale(real.clone())) + } +} + +impl> Matrix { + /// Sets `self` to its adjoint. + #[deprecated(note = "Renamed to `self.adjoint_mut()`.")] + pub fn conjugate_transform_mut(&mut self) { + self.adjoint_mut() + } + + /// Sets `self` to its adjoint (aka. conjugate-transpose). + pub fn adjoint_mut(&mut self) { + assert!( + self.is_square(), + "Unable to transpose a non-square matrix in-place." + ); + + let dim = self.shape().0; + + for i in 0..dim { + for j in 0..i { + unsafe { + let ref_ij = self.get_unchecked((i, j)).clone(); + let ref_ji = self.get_unchecked((j, i)).clone(); + let conj_ij = ref_ij.simd_conjugate(); + let conj_ji = ref_ji.simd_conjugate(); + *self.get_unchecked_mut((i, j)) = conj_ji; + *self.get_unchecked_mut((j, i)) = conj_ij; + } + } + + { + let diag = unsafe { self.get_unchecked_mut((i, i)) }; + *diag = diag.clone().simd_conjugate(); + } + } + } +} + +impl> SquareMatrix { + /// The diagonal of this matrix. + #[inline] + #[must_use] + pub fn diagonal(&self) -> OVector + where + DefaultAllocator: Allocator, + { + self.map_diagonal(|e| e) + } + + /// Apply the given function to this matrix's diagonal and returns it. + /// + /// This is a more efficient version of `self.diagonal().map(f)` since this + /// allocates only once. + #[must_use] + pub fn map_diagonal(&self, mut f: impl FnMut(T) -> T2) -> OVector + where + DefaultAllocator: Allocator, + { + assert!( + self.is_square(), + "Unable to get the diagonal of a non-square matrix." + ); + + let dim = self.shape_generic().0; + let mut res = Matrix::uninit(dim, Const::<1>); + + for i in 0..dim.value() { + // Safety: all indices are in range. + unsafe { + *res.vget_unchecked_mut(i) = + MaybeUninit::new(f(self.get_unchecked((i, i)).clone())); + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Computes a trace of a square matrix, i.e., the sum of its diagonal elements. + #[inline] + #[must_use] + pub fn trace(&self) -> T + where + T: Scalar + Zero + ClosedAddAssign, + { + assert!( + self.is_square(), + "Cannot compute the trace of non-square matrix." + ); + + let dim = self.shape_generic().0; + let mut res = T::zero(); + + for i in 0..dim.value() { + res += unsafe { self.get_unchecked((i, i)).clone() }; + } + + res + } +} + +impl> SquareMatrix { + /// The symmetric part of `self`, i.e., `0.5 * (self + self.transpose())`. + #[inline] + #[must_use] + pub fn symmetric_part(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + assert!( + self.is_square(), + "Cannot compute the symmetric part of a non-square matrix." + ); + let mut tr = self.transpose(); + tr += self; + tr *= crate::convert::<_, T>(0.5); + tr + } + + /// The hermitian part of `self`, i.e., `0.5 * (self + self.adjoint())`. + #[inline] + #[must_use] + pub fn hermitian_part(&self) -> OMatrix + where + DefaultAllocator: Allocator, + { + assert!( + self.is_square(), + "Cannot compute the hermitian part of a non-square matrix." + ); + + let mut tr = self.adjoint(); + tr += self; + tr *= crate::convert::<_, T>(0.5); + tr + } +} + +impl + IsNotStaticOne, S: RawStorage> + Matrix +{ + /// Yields the homogeneous matrix for this matrix, i.e., appending an additional dimension and + /// and setting the diagonal element to `1`. + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, DimSum> + where + DefaultAllocator: Allocator, DimSum>, + { + assert!( + self.is_square(), + "Only square matrices can currently be transformed to homogeneous coordinates." + ); + let dim = DimSum::::from_usize(self.nrows() + 1); + let mut res = OMatrix::identity_generic(dim, dim); + res.generic_view_mut::((0, 0), self.shape_generic()) + .copy_from(self); + res + } +} + +impl, S: RawStorage> Vector { + /// Computes the coordinates in projective space of this vector, i.e., appends a `0` to its + /// coordinates. + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OVector> + where + DefaultAllocator: Allocator>, + { + self.push(T::zero()) + } + + /// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of + /// `self`. Returns `None` if this last component is not zero. + #[inline] + pub fn from_homogeneous(v: Vector, SB>) -> Option> + where + SB: RawStorage>, + DefaultAllocator: Allocator, + { + if v[v.len() - 1].is_zero() { + let nrows = D::from_usize(v.len() - 1); + Some(v.generic_view((0, 0), (nrows, Const::<1>)).into_owned()) + } else { + None + } + } +} + +impl, S: RawStorage> Vector { + /// Constructs a new vector of higher dimension by appending `element` to the end of `self`. + #[inline] + #[must_use] + pub fn push(&self, element: T) -> OVector> + where + DefaultAllocator: Allocator>, + { + let len = self.len(); + let hnrows = DimSum::::from_usize(len + 1); + let mut res = Matrix::uninit(hnrows, Const::<1>); + // This is basically a copy_from except that we warp the copied + // values into MaybeUninit. + res.generic_view_mut((0, 0), self.shape_generic()) + .zip_apply(self, |out, e| *out = MaybeUninit::new(e)); + res[(len, 0)] = MaybeUninit::new(element); + + // Safety: res has been fully initialized. + unsafe { res.assume_init() } + } +} + +impl AbsDiffEq for Matrix +where + T: Scalar + AbsDiffEq, + S: RawStorage, + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.iter() + .zip(other.iter()) + .all(|(a, b)| a.abs_diff_eq(b, epsilon.clone())) + } +} + +impl RelativeEq for Matrix +where + T: Scalar + RelativeEq, + S: Storage, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.relative_eq(other, epsilon, max_relative) + } +} + +impl UlpsEq for Matrix +where + T: Scalar + UlpsEq, + S: RawStorage, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + assert!(self.shape() == other.shape()); + self.iter() + .zip(other.iter()) + .all(|(a, b)| a.ulps_eq(b, epsilon.clone(), max_ulps)) + } +} + +impl PartialOrd for Matrix +where + T: Scalar + PartialOrd, + S: RawStorage, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + if self.shape() != other.shape() { + return None; + } + + if self.nrows() == 0 || self.ncols() == 0 { + return Some(Ordering::Equal); + } + + let mut first_ord = unsafe { + self.data + .get_unchecked_linear(0) + .partial_cmp(other.data.get_unchecked_linear(0)) + }; + + if let Some(first_ord) = first_ord.as_mut() { + let mut it = self.iter().zip(other.iter()); + let _ = it.next(); // Drop the first elements (we already tested it). + + for (left, right) in it { + if let Some(ord) = left.partial_cmp(right) { + match ord { + Ordering::Equal => { /* Does not change anything. */ } + Ordering::Less => { + if *first_ord == Ordering::Greater { + return None; + } + *first_ord = ord + } + Ordering::Greater => { + if *first_ord == Ordering::Less { + return None; + } + *first_ord = ord + } + } + } else { + return None; + } + } + } + + first_ord + } + + #[inline] + fn lt(&self, right: &Self) -> bool { + assert_eq!( + self.shape(), + right.shape(), + "Matrix comparison error: dimensions mismatch." + ); + self.iter().zip(right.iter()).all(|(a, b)| a.lt(b)) + } + + #[inline] + fn le(&self, right: &Self) -> bool { + assert_eq!( + self.shape(), + right.shape(), + "Matrix comparison error: dimensions mismatch." + ); + self.iter().zip(right.iter()).all(|(a, b)| a.le(b)) + } + + #[inline] + fn gt(&self, right: &Self) -> bool { + assert_eq!( + self.shape(), + right.shape(), + "Matrix comparison error: dimensions mismatch." + ); + self.iter().zip(right.iter()).all(|(a, b)| a.gt(b)) + } + + #[inline] + fn ge(&self, right: &Self) -> bool { + assert_eq!( + self.shape(), + right.shape(), + "Matrix comparison error: dimensions mismatch." + ); + self.iter().zip(right.iter()).all(|(a, b)| a.ge(b)) + } +} + +impl Eq for Matrix +where + T: Eq, + S: RawStorage, +{ +} + +impl PartialEq> for Matrix +where + T: PartialEq, + C: Dim, + C2: Dim, + R: Dim, + R2: Dim, + S: RawStorage, + S2: RawStorage, +{ + #[inline] + fn eq(&self, right: &Matrix) -> bool { + self.shape() == right.shape() && self.iter().zip(right.iter()).all(|(l, r)| l == r) + } +} + +macro_rules! impl_fmt { + ($trait: path, $fmt_str_without_precision: expr, $fmt_str_with_precision: expr) => { + impl $trait for Matrix + where + T: Scalar + $trait, + S: RawStorage, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + #[cfg(feature = "std")] + fn val_width(val: &T, f: &mut fmt::Formatter<'_>) -> usize { + match f.precision() { + Some(precision) => format!($fmt_str_with_precision, val, precision) + .chars() + .count(), + None => format!($fmt_str_without_precision, val).chars().count(), + } + } + + #[cfg(not(feature = "std"))] + fn val_width(_: &T, _: &mut fmt::Formatter<'_>) -> usize { + 4 + } + + let (nrows, ncols) = self.shape(); + + if nrows == 0 || ncols == 0 { + return write!(f, "[ ]"); + } + + let mut max_length = 0; + + for i in 0..nrows { + for j in 0..ncols { + max_length = crate::max(max_length, val_width(&self[(i, j)], f)); + } + } + + let max_length_with_space = max_length + 1; + + writeln!(f)?; + writeln!( + f, + " ┌ {:>width$} ┐", + "", + width = max_length_with_space * ncols - 1 + )?; + + for i in 0..nrows { + write!(f, " │")?; + for j in 0..ncols { + let number_length = val_width(&self[(i, j)], f) + 1; + let pad = max_length_with_space - number_length; + write!(f, " {:>thepad$}", "", thepad = pad)?; + match f.precision() { + Some(precision) => { + write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)? + } + None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?, + } + } + writeln!(f, " │")?; + } + + writeln!( + f, + " └ {:>width$} ┘", + "", + width = max_length_with_space * ncols - 1 + )?; + writeln!(f) + } + } + }; +} +impl_fmt!(fmt::Display, "{}", "{:.1$}"); +impl_fmt!(fmt::LowerExp, "{:e}", "{:.1$e}"); +impl_fmt!(fmt::UpperExp, "{:E}", "{:.1$E}"); +impl_fmt!(fmt::Octal, "{:o}", "{:1$o}"); +impl_fmt!(fmt::LowerHex, "{:x}", "{:1$x}"); +impl_fmt!(fmt::UpperHex, "{:X}", "{:1$X}"); +impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}"); +impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); + +#[cfg(test)] +mod tests { + #[test] + fn empty_display() { + let vec: Vec = Vec::new(); + let dvector = crate::DVector::from_vec(vec); + assert_eq!(format!("{}", dvector), "[ ]") + } + + #[test] + fn lower_exp() { + let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.); + assert_eq!( + format!("{:e}", test), + r" + ┌ ┐ + │ 1e6 2e5 │ + │ 2e-5 1e0 │ + └ ┘ + +" + ) + } +} + +/// # Cross product +impl< + T: Scalar + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign, + R: Dim, + C: Dim, + S: RawStorage, + > Matrix +{ + /// The perpendicular product between two 2D column vectors, i.e. `a.x * b.y - a.y * b.x`. + #[inline] + #[must_use] + pub fn perp(&self, b: &Matrix) -> T + where + R2: Dim, + C2: Dim, + SB: RawStorage, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + SameNumberOfRows + + SameNumberOfColumns, + { + let shape = self.shape(); + assert_eq!( + shape, + b.shape(), + "2D vector perpendicular product dimension mismatch." + ); + assert_eq!( + shape, + (2, 1), + "2D perpendicular product requires (2, 1) vectors {:?}", + shape + ); + + // SAFETY: assertion above ensures correct shape + let ax = unsafe { self.get_unchecked((0, 0)).clone() }; + let ay = unsafe { self.get_unchecked((1, 0)).clone() }; + let bx = unsafe { b.get_unchecked((0, 0)).clone() }; + let by = unsafe { b.get_unchecked((1, 0)).clone() }; + + ax * by - ay * bx + } + + // TODO: use specialization instead of an assertion. + /// The 3D cross product between two vectors. + /// + /// Panics if the shape is not 3D vector. In the future, this will be implemented only for + /// dynamically-sized matrices and statically-sized 3D matrices. + #[inline] + #[must_use] + pub fn cross(&self, b: &Matrix) -> MatrixCross + where + R2: Dim, + C2: Dim, + SB: RawStorage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + let shape = self.shape(); + assert_eq!(shape, b.shape(), "Vector cross product dimension mismatch."); + assert!( + shape == (3, 1) || shape == (1, 3), + "Vector cross product dimension mismatch: must be (3, 1) or (1, 3) but found {:?}.", + shape + ); + + if shape.0 == 3 { + unsafe { + let mut res = Matrix::uninit(Dim::from_usize(3), Dim::from_usize(1)); + + let ax = self.get_unchecked((0, 0)); + let ay = self.get_unchecked((1, 0)); + let az = self.get_unchecked((2, 0)); + + let bx = b.get_unchecked((0, 0)); + let by = b.get_unchecked((1, 0)); + let bz = b.get_unchecked((2, 0)); + + *res.get_unchecked_mut((0, 0)) = + MaybeUninit::new(ay.clone() * bz.clone() - az.clone() * by.clone()); + *res.get_unchecked_mut((1, 0)) = + MaybeUninit::new(az.clone() * bx.clone() - ax.clone() * bz.clone()); + *res.get_unchecked_mut((2, 0)) = + MaybeUninit::new(ax.clone() * by.clone() - ay.clone() * bx.clone()); + + // Safety: res is now fully initialized. + res.assume_init() + } + } else { + unsafe { + let mut res = Matrix::uninit(Dim::from_usize(1), Dim::from_usize(3)); + + let ax = self.get_unchecked((0, 0)); + let ay = self.get_unchecked((0, 1)); + let az = self.get_unchecked((0, 2)); + + let bx = b.get_unchecked((0, 0)); + let by = b.get_unchecked((0, 1)); + let bz = b.get_unchecked((0, 2)); + + *res.get_unchecked_mut((0, 0)) = + MaybeUninit::new(ay.clone() * bz.clone() - az.clone() * by.clone()); + *res.get_unchecked_mut((0, 1)) = + MaybeUninit::new(az.clone() * bx.clone() - ax.clone() * bz.clone()); + *res.get_unchecked_mut((0, 2)) = + MaybeUninit::new(ax.clone() * by.clone() - ay.clone() * bx.clone()); + + // Safety: res is now fully initialized. + res.assume_init() + } + } + } +} + +impl> Vector { + /// Computes the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`. + #[inline] + #[must_use] + pub fn cross_matrix(&self) -> OMatrix { + OMatrix::::new( + T::zero(), + -self[2].clone(), + self[1].clone(), + self[2].clone(), + T::zero(), + -self[0].clone(), + -self[1].clone(), + self[0].clone(), + T::zero(), + ) + } +} + +impl> Matrix { + /// The smallest angle between two vectors. + #[inline] + #[must_use] + pub fn angle(&self, other: &Matrix) -> T::SimdRealField + where + SB: Storage, + ShapeConstraint: DimEq + DimEq, + { + let prod = self.dotc(other); + let n1 = self.norm(); + let n2 = other.norm(); + + if n1.is_zero() || n2.is_zero() { + T::SimdRealField::zero() + } else { + let cang = prod.simd_real() / (n1 * n2); + cang.simd_clamp(-T::SimdRealField::one(), T::SimdRealField::one()) + .simd_acos() + } + } +} + +impl AbsDiffEq for Unit> +where + T: Scalar + AbsDiffEq, + S: RawStorage, + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.as_ref().abs_diff_eq(other.as_ref(), epsilon) + } +} + +impl RelativeEq for Unit> +where + T: Scalar + RelativeEq, + S: Storage, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.as_ref() + .relative_eq(other.as_ref(), epsilon, max_relative) + } +} + +impl UlpsEq for Unit> +where + T: Scalar + UlpsEq, + S: RawStorage, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) + } +} + +impl Hash for Matrix +where + T: Scalar + Hash, + R: Dim, + C: Dim, + S: RawStorage, +{ + fn hash(&self, state: &mut H) { + let (nrows, ncols) = self.shape(); + (nrows, ncols).hash(state); + + for j in 0..ncols { + for i in 0..nrows { + unsafe { + self.get_unchecked((i, j)).hash(state); + } + } + } + } +} + +impl Unit> +where + T: Scalar, + D: Dim, + S: RawStorage, +{ + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::::y_axis(); + /// let v2 = v.cast::(); + /// assert_eq!(v2, Vector3::::y_axis()); + /// ``` + pub fn cast(self) -> Unit> + where + T: Scalar, + OVector: SupersetOf>, + DefaultAllocator: Allocator, + { + Unit::new_unchecked(crate::convert_ref(self.as_ref())) + } +} + +impl Matrix +where + S: RawStorage, +{ + /// Returns a reference to the single element in this matrix. + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let inner_product: f32 = *(v.transpose() * v).as_scalar(); + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let inner_product = (v * v.transpose()).item(); // Typo, does not compile. + ///``` + pub fn as_scalar(&self) -> &T { + &self[(0, 0)] + } + /// Get a mutable reference to the single element in this matrix + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product = (v.transpose() * v); + /// *inner_product.as_scalar_mut() = 3.; + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product = (v * v.transpose()); + /// *inner_product.as_scalar_mut() = 3.; + ///``` + pub fn as_scalar_mut(&mut self) -> &mut T + where + S: RawStorageMut, + { + &mut self[(0, 0)] + } + /// Convert this 1x1 matrix by reference into a scalar. + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product: f32 = (v.transpose() * v).to_scalar(); + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product: f32 = (v * v.transpose()).to_scalar(); + ///``` + pub fn to_scalar(&self) -> T + where + T: Clone, + { + self.as_scalar().clone() + } +} + +impl super::alias::Matrix1 { + /// Convert this 1x1 matrix into a scalar. + /// + /// As opposed to indexing, using this provides type-safety + /// when flattening dimensions. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Matrix2, U1}; + /// let v = Vector3::new(0., 0., 1.); + /// let inner_product: f32 = (v.transpose() * v).into_scalar(); + /// assert_eq!(inner_product, 1.); + /// ``` + /// + ///```compile_fail + /// # use nalgebra::Vector3; + /// let v = Vector3::new(0., 0., 1.); + /// let mut inner_product: f32 = (v * v.transpose()).into_scalar(); + ///``` + pub fn into_scalar(self) -> T { + let [[scalar]] = self.data.0; + scalar + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_simba.rs new file mode 100644 index 000000000..25a6cd5e2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_simba.rs @@ -0,0 +1,56 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::Dim; +use crate::base::{DefaultAllocator, OMatrix, Scalar}; + +/* + * + * Simd structures. + * + */ +impl SimdValue for OMatrix +where + T: Scalar + SimdValue, + R: Dim, + C: Dim, + T::Element: Scalar, + DefaultAllocator: Allocator, +{ + const LANES: usize = T::LANES; + type Element = OMatrix; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + val.map(T::splat) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.map(|e| e.extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.map(|e| e.extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.zip_apply(&val, |a, b| { + a.replace(i, b); + }) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.zip_apply(&val, |a, b| { + a.replace_unchecked(i, b); + }) + } + + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.zip_map(&other, |a, b| a.select(cond, b)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_view.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_view.rs new file mode 100644 index 000000000..c2ed337d5 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/matrix_view.rs @@ -0,0 +1,1246 @@ +use std::marker::PhantomData; +use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; +use std::slice; + +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Const, Dim, DimName, Dyn, IsNotStaticOne, U1}; +use crate::base::iter::MatrixIter; +use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage}; +use crate::base::{Matrix, Scalar}; +use crate::constraint::{DimEq, ShapeConstraint}; +use crate::ReshapableStorage; + +macro_rules! view_storage_impl ( + ($doc: expr; $Storage: ident as $SRef: ty; $legacy_name:ident => $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => { + #[doc = $doc] + #[derive(Debug)] + pub struct $T<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> { + ptr: $Ptr, + shape: (R, C), + strides: (RStride, CStride), + _phantoms: PhantomData<$Ref>, + } + + #[doc = $doc] + /// + /// This type alias exists only for legacy purposes and is deprecated. It will be removed + /// in a future release. Please use + /// [` + #[doc = stringify!($T)] + /// `] instead. See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) + /// for the rationale. + #[deprecated = "Use ViewStorage(Mut) instead."] + pub type $legacy_name<'a, T, R, C, RStride, CStride> = $T<'a, T, R, C, RStride, CStride>; + + unsafe impl<'a, T: Send, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Send + for $T<'a, T, R, C, RStride, CStride> + {} + + unsafe impl<'a, T: Sync, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Sync + for $T<'a, T, R, C, RStride, CStride> + {} + + impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> $T<'a, T, R, C, RStride, CStride> { + /// Create a new matrix view without bounds checking and from a raw pointer. + /// + /// # Safety + /// + /// `*ptr` must point to memory that is valid `[T; R * C]`. + #[inline] + pub unsafe fn from_raw_parts(ptr: $Ptr, + shape: (R, C), + strides: (RStride, CStride)) + -> Self + where RStride: Dim, + CStride: Dim { + + $T { + ptr, + shape, + strides, + _phantoms: PhantomData + } + } + } + + // Dyn is arbitrary. It's just to be able to call the constructors with `Slice::` + impl<'a, T, R: Dim, C: Dim> $T<'a, T, R, C, Dyn, Dyn> { + /// Create a new matrix view without bounds checking. + /// + /// # Safety + /// + /// `storage` contains sufficient elements beyond `start + R * C` such that all + /// accesses are within bounds. + #[inline] + pub unsafe fn new_unchecked(storage: $SRef, start: (usize, usize), shape: (R, C)) + -> $T<'a, T, R, C, S::RStride, S::CStride> + where RStor: Dim, + CStor: Dim, + S: $Storage { + + let strides = storage.strides(); + $T::new_with_strides_unchecked(storage, start, shape, strides) + } + + /// Create a new matrix view without bounds checking. + /// + /// # Safety + /// + /// `strides` must be a valid stride indexing. + #[inline] + pub unsafe fn new_with_strides_unchecked(storage: $SRef, + start: (usize, usize), + shape: (R, C), + strides: (RStride, CStride)) + -> $T<'a, T, R, C, RStride, CStride> + where RStor: Dim, + CStor: Dim, + S: $Storage, + RStride: Dim, + CStride: Dim { + $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides) + } + } + + impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + $T<'a, T, R, C, RStride, CStride> + where + Self: RawStorage + IsContiguous + { + /// Extracts the original slice from this storage. + pub fn into_slice(self) -> &'a [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts(self.ptr, sz + 1) } + } else { + unsafe { slice::from_raw_parts(self.ptr, 0) } + } + } + } + } +); + +view_storage_impl!("A matrix data storage for a matrix view. Only contains an internal reference \ + to another matrix data storage."; + RawStorage as &'a S; SliceStorage => ViewStorage.get_address_unchecked(*const T as &'a T)); + +view_storage_impl!("A mutable matrix data storage for mutable matrix view. Only contains an \ + internal mutable reference to another matrix data storage."; + RawStorageMut as &'a mut S; SliceStorageMut => ViewStorageMut.get_address_unchecked_mut(*mut T as &'a mut T) +); + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy + for ViewStorage<'a, T, R, C, RStride, CStride> +{ +} + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone + for ViewStorage<'a, T, R, C, RStride, CStride> +{ + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + ViewStorageMut<'a, T, R, C, RStride, CStride> +where + Self: RawStorageMut + IsContiguous, +{ + /// Extracts the original slice from this storage + pub fn into_slice_mut(self) -> &'a mut [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) } + } else { + unsafe { slice::from_raw_parts_mut(self.ptr, 0) } + } + } +} + +macro_rules! storage_impl( + ($($T: ident),* $(,)*) => {$( + unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage + for $T<'a, T, R, C, RStride, CStride> { + + type RStride = RStride; + type CStride = CStride; + + #[inline] + fn ptr(&self) -> *const T { + self.ptr + } + + #[inline] + fn shape(&self) -> (R, C) { + self.shape + } + + #[inline] + fn strides(&self) -> (Self::RStride, Self::CStride) { + self.strides + } + + #[inline] + fn is_contiguous(&self) -> bool { + // Common cases that can be deduced at compile-time even if one of the dimensions + // is Dyn. + if (RStride::is::() && C::is::()) || // Column vector. + (CStride::is::() && R::is::()) { // Row vector. + true + } + else { + let (nrows, _) = self.shape(); + let (srows, scols) = self.strides(); + + srows.value() == 1 && scols.value() == nrows.value() + } + } + + #[inline] + unsafe fn as_slice_unchecked(&self) -> &[T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + slice::from_raw_parts(self.ptr, sz + 1) + } + else { + slice::from_raw_parts(self.ptr, 0) + } + } + } + + unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage + for $T<'a, T, R, C, RStride, CStride> { + #[inline] + fn into_owned(self) -> Owned + where DefaultAllocator: Allocator { + self.clone_owned() + } + + #[inline] + fn clone_owned(&self) -> Owned + where DefaultAllocator: Allocator { + let (nrows, ncols) = self.shape(); + let it = MatrixIter::new(self).cloned(); + DefaultAllocator::allocate_from_iterator(nrows, ncols, it) + } + + #[inline] + fn forget_elements(self) { + // No cleanup required. + } + } + )*} +); + +storage_impl!(ViewStorage, ViewStorageMut); + +unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut + for ViewStorageMut<'a, T, R, C, RStride, CStride> +{ + #[inline] + fn ptr_mut(&mut self) -> *mut T { + self.ptr + } + + #[inline] + unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + slice::from_raw_parts_mut(self.ptr, sz + 1) + } else { + slice::from_raw_parts_mut(self.ptr, 0) + } + } +} + +unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous for ViewStorage<'a, T, R, U1, U1, CStride> {} +unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous + for ViewStorageMut<'a, T, R, U1, U1, CStride> +{ +} + +unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous + for ViewStorage<'a, T, R, C, U1, R> +{ +} +unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous + for ViewStorageMut<'a, T, R, C, U1, R> +{ +} + +impl> Matrix { + #[inline] + fn assert_view_index( + &self, + start: (usize, usize), + shape: (usize, usize), + steps: (usize, usize), + ) { + let my_shape = self.shape(); + // NOTE: we don't do any subtraction to avoid underflow for zero-sized matrices. + // + // Terms that would have been negative are moved to the other side of the inequality + // instead. + assert!( + start.0 + (steps.0 + 1) * shape.0 <= my_shape.0 + steps.0, + "Matrix slicing out of bounds." + ); + assert!( + start.1 + (steps.1 + 1) * shape.1 <= my_shape.1 + steps.1, + "Matrix slicing out of bounds." + ); + } +} + +macro_rules! matrix_view_impl ( + ($me: ident: $Me: ty, $MatrixView: ident, $ViewStorage: ident, $Storage: ident.$get_addr: ident (), $data: expr; + $row: ident, + $row_part: ident, + $rows: ident, + $rows_with_step: ident, + $fixed_rows: ident, + $fixed_rows_with_step: ident, + $rows_generic: ident, + $rows_generic_with_step: ident, + $column: ident, + $column_part: ident, + $columns: ident, + $columns_with_step: ident, + $fixed_columns: ident, + $fixed_columns_with_step: ident, + $columns_generic: ident, + $columns_generic_with_step: ident, + $slice: ident => $view:ident, + $slice_with_steps: ident => $view_with_steps:ident, + $fixed_slice: ident => $fixed_view:ident, + $fixed_slice_with_steps: ident => $fixed_view_with_steps:ident, + $generic_slice: ident => $generic_view:ident, + $generic_slice_with_steps: ident => $generic_view_with_steps:ident, + $rows_range_pair: ident, + $columns_range_pair: ident) => { + /* + * + * Row slicing. + * + */ + /// Returns a view containing the i-th row of this matrix. + #[inline] + pub fn $row($me: $Me, i: usize) -> $MatrixView<'_, T, U1, C, S::RStride, S::CStride> { + $me.$fixed_rows::<1>(i) + } + + /// Returns a view containing the `n` first elements of the i-th row of this matrix. + #[inline] + pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixView<'_, T, U1, Dyn, S::RStride, S::CStride> { + $me.$generic_view((i, 0), (Const::<1>, Dyn(n))) + } + + /// Extracts from this matrix a set of consecutive rows. + #[inline] + pub fn $rows($me: $Me, first_row: usize, nrows: usize) + -> $MatrixView<'_, T, Dyn, C, S::RStride, S::CStride> { + + $me.$rows_generic(first_row, Dyn(nrows)) + } + + /// Extracts from this matrix a set of consecutive rows regularly skipping `step` rows. + #[inline] + pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize) + -> $MatrixView<'_, T, Dyn, C, Dyn, S::CStride> { + + $me.$rows_generic_with_step(first_row, Dyn(nrows), step) + } + + /// Extracts a compile-time number of consecutive rows from this matrix. + #[inline] + pub fn $fixed_rows($me: $Me, first_row: usize) + -> $MatrixView<'_, T, Const, C, S::RStride, S::CStride> { + + $me.$rows_generic(first_row, Const::) + } + + /// Extracts from this matrix a compile-time number of rows regularly skipping `step` + /// rows. + #[inline] + pub fn $fixed_rows_with_step($me: $Me, first_row: usize, step: usize) + -> $MatrixView<'_, T, Const, C, Dyn, S::CStride> { + + $me.$rows_generic_with_step(first_row, Const::, step) + } + + /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both + /// argument may or may not be values known at compile-time. + #[inline] + pub fn $rows_generic($me: $Me, row_start: usize, nrows: RView) + -> $MatrixView<'_, T, RView, C, S::RStride, S::CStride> { + + let my_shape = $me.shape_generic(); + $me.assert_view_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); + + let shape = (nrows, my_shape.1); + + unsafe { + let data = $ViewStorage::new_unchecked($data, (row_start, 0), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both + /// argument may or may not be values known at compile-time. + #[inline] + pub fn $rows_generic_with_step($me: $Me, row_start: usize, nrows: RView, step: usize) + -> $MatrixView<'_, T, RView, C, Dyn, S::CStride> + where RView: Dim { + + let my_shape = $me.shape_generic(); + let my_strides = $me.data.strides(); + $me.assert_view_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); + + let strides = (Dyn((step + 1) * my_strides.0.value()), my_strides.1); + let shape = (nrows, my_shape.1); + + unsafe { + let data = $ViewStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides); + Matrix::from_data_statically_unchecked(data) + } + } + + /* + * + * Column slicing. + * + */ + /// Returns a view containing the i-th column of this matrix. + #[inline] + pub fn $column($me: $Me, i: usize) -> $MatrixView<'_, T, R, U1, S::RStride, S::CStride> { + $me.$fixed_columns::<1>(i) + } + + /// Returns a view containing the `n` first elements of the i-th column of this matrix. + #[inline] + pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixView<'_, T, Dyn, U1, S::RStride, S::CStride> { + $me.$generic_view((0, i), (Dyn(n), Const::<1>)) + } + + /// Extracts from this matrix a set of consecutive columns. + #[inline] + pub fn $columns($me: $Me, first_col: usize, ncols: usize) + -> $MatrixView<'_, T, R, Dyn, S::RStride, S::CStride> { + + $me.$columns_generic(first_col, Dyn(ncols)) + } + + /// Extracts from this matrix a set of consecutive columns regularly skipping `step` + /// columns. + #[inline] + pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize) + -> $MatrixView<'_, T, R, Dyn, S::RStride, Dyn> { + + $me.$columns_generic_with_step(first_col, Dyn(ncols), step) + } + + /// Extracts a compile-time number of consecutive columns from this matrix. + #[inline] + pub fn $fixed_columns($me: $Me, first_col: usize) + -> $MatrixView<'_, T, R, Const, S::RStride, S::CStride> { + + $me.$columns_generic(first_col, Const::) + } + + /// Extracts from this matrix a compile-time number of columns regularly skipping + /// `step` columns. + #[inline] + pub fn $fixed_columns_with_step($me: $Me, first_col: usize, step: usize) + -> $MatrixView<'_, T, R, Const, S::RStride, Dyn> { + + $me.$columns_generic_with_step(first_col, Const::, step) + } + + /// Extracts from this matrix `ncols` columns. The number of columns may or may not be + /// known at compile-time. + #[inline] + pub fn $columns_generic($me: $Me, first_col: usize, ncols: CView) + -> $MatrixView<'_, T, R, CView, S::RStride, S::CStride> { + + let my_shape = $me.shape_generic(); + $me.assert_view_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $ViewStorage::new_unchecked($data, (0, first_col), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + + /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may + /// or may not be values known at compile-time. + #[inline] + pub fn $columns_generic_with_step($me: $Me, first_col: usize, ncols: CView, step: usize) + -> $MatrixView<'_, T, R, CView, S::RStride, Dyn> { + + let my_shape = $me.shape_generic(); + let my_strides = $me.data.strides(); + + $me.assert_view_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); + + let strides = (my_strides.0, Dyn((step + 1) * my_strides.1.value())); + let shape = (my_shape.0, ncols); + + unsafe { + let data = $ViewStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides); + Matrix::from_data_statically_unchecked(data) + } + } + + /* + * + * General slicing. + * + */ + /// Slices this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` + /// consecutive elements. + #[inline] + #[deprecated = slice_deprecation_note!($view)] + pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, S::RStride, S::CStride> { + $me.$view(start, shape) + } + + /// Return a view of this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)` + /// consecutive elements. + #[inline] + pub fn $view($me: $Me, start: (usize, usize), shape: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, S::RStride, S::CStride> { + + $me.assert_view_index(start, shape, (0, 0)); + let shape = (Dyn(shape.0), Dyn(shape.1)); + + unsafe { + let data = $ViewStorage::new_unchecked($data, start, shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Slices this matrix starting at its component `(start.0, start.1)` and with + /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is + /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the + /// original matrix. + #[inline] + #[deprecated = slice_deprecation_note!($view_with_steps)] + pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, Dyn, Dyn> { + $me.$view_with_steps(start, shape, steps) + } + + /// Return a view of this matrix starting at its component `(start.0, start.1)` and with + /// `(shape.0, shape.1)` components. Each row (resp. column) of the matrix view is + /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the + /// original matrix. + #[inline] + pub fn $view_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Dyn, Dyn, Dyn, Dyn> { + let shape = (Dyn(shape.0), Dyn(shape.1)); + $me.$generic_view_with_steps(start, shape, steps) + } + + /// Slices this matrix starting at its component `(irow, icol)` and with `(RVIEW, CVIEW)` + /// consecutive components. + #[inline] + #[deprecated = slice_deprecation_note!($fixed_view)] + pub fn $fixed_slice($me: $Me, irow: usize, icol: usize) + -> $MatrixView<'_, T, Const, Const, S::RStride, S::CStride> { + $me.$fixed_view(irow, icol) + } + + /// Return a view of this matrix starting at its component `(irow, icol)` and with + /// `(RVIEW, CVIEW)` consecutive components. + #[inline] + pub fn $fixed_view($me: $Me, irow: usize, icol: usize) + -> $MatrixView<'_, T, Const, Const, S::RStride, S::CStride> { + + $me.assert_view_index((irow, icol), (RVIEW, CVIEW), (0, 0)); + let shape = (Const::, Const::); + + unsafe { + let data = $ViewStorage::new_unchecked($data, (irow, icol), shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Slices this matrix starting at its component `(start.0, start.1)` and with + /// `(RVIEW, CVIEW)` components. Each row (resp. column) of the sliced + /// matrix is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of + /// the original matrix. + #[inline] + #[deprecated = slice_deprecation_note!($fixed_view_with_steps)] + pub fn $fixed_slice_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Const, Const, Dyn, Dyn> { + $me.$fixed_view_with_steps(start, steps) + } + + /// Returns a view of this matrix starting at its component `(start.0, start.1)` and with + /// `(RVIEW, CVIEW)` components. Each row (resp. column) of the matrix view + /// is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of + /// the original matrix. + #[inline] + pub fn $fixed_view_with_steps($me: $Me, start: (usize, usize), steps: (usize, usize)) + -> $MatrixView<'_, T, Const, Const, Dyn, Dyn> { + let shape = (Const::, Const::); + $me.$generic_view_with_steps(start, shape, steps) + } + + /// Creates a slice that may or may not have a fixed size and stride. + #[inline] + #[deprecated = slice_deprecation_note!($generic_view)] + pub fn $generic_slice($me: $Me, start: (usize, usize), shape: (RView, CView)) + -> $MatrixView<'_, T, RView, CView, S::RStride, S::CStride> + where RView: Dim, + CView: Dim { + $me.$generic_view(start, shape) + } + + /// Creates a matrix view that may or may not have a fixed size and stride. + #[inline] + pub fn $generic_view($me: $Me, start: (usize, usize), shape: (RView, CView)) + -> $MatrixView<'_, T, RView, CView, S::RStride, S::CStride> + where RView: Dim, + CView: Dim { + + $me.assert_view_index(start, (shape.0.value(), shape.1.value()), (0, 0)); + + unsafe { + let data = $ViewStorage::new_unchecked($data, start, shape); + Matrix::from_data_statically_unchecked(data) + } + } + + /// Creates a slice that may or may not have a fixed size and stride. + #[inline] + #[deprecated = slice_deprecation_note!($generic_view_with_steps)] + pub fn $generic_slice_with_steps($me: $Me, + start: (usize, usize), + shape: (RView, CView), + steps: (usize, usize)) + -> $MatrixView<'_, T, RView, CView, Dyn, Dyn> + where RView: Dim, + CView: Dim { + $me.$generic_view_with_steps(start, shape, steps) + } + + /// Creates a matrix view that may or may not have a fixed size and stride. + #[inline] + pub fn $generic_view_with_steps($me: $Me, + start: (usize, usize), + shape: (RView, CView), + steps: (usize, usize)) + -> $MatrixView<'_, T, RView, CView, Dyn, Dyn> + where RView: Dim, + CView: Dim { + + $me.assert_view_index(start, (shape.0.value(), shape.1.value()), steps); + + let my_strides = $me.data.strides(); + let strides = (Dyn((steps.0 + 1) * my_strides.0.value()), + Dyn((steps.1 + 1) * my_strides.1.value())); + + unsafe { + let data = $ViewStorage::new_with_strides_unchecked($data, start, shape, strides); + Matrix::from_data_statically_unchecked(data) + } + } + + /* + * + * Splitting. + * + */ + /// Splits this `NxM` matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $rows_range_pair, Range2: DimRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixView<'_, T, Range1::Size, C, S::RStride, S::CStride>, + $MatrixView<'_, T, Range2::Size, C, S::RStride, S::CStride>) { + + let (nrows, ncols) = $me.shape_generic(); + let strides = $me.data.strides(); + + let start1 = r1.begin(nrows); + let start2 = r2.begin(nrows); + + let end1 = r1.end(nrows); + let end2 = r2.end(nrows); + + let nrows1 = r1.size(nrows); + let nrows2 = r2.size(nrows); + + assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the ranges must not overlap."); + assert!(end2 <= nrows.value(), "Rows range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(start1, 0); + let ptr2 = $data.$get_addr(start2, 0); + + let data1 = $ViewStorage::from_raw_parts(ptr1, (nrows1, ncols), strides); + let data2 = $ViewStorage::from_raw_parts(ptr2, (nrows2, ncols), strides); + let view1 = Matrix::from_data_statically_unchecked(data1); + let view2 = Matrix::from_data_statically_unchecked(data2); + + (view1, view2) + } + } + + /// Splits this `NxM` matrix into two parts delimited by two ranges. + /// + /// Panics if the ranges overlap or if the first range is empty. + #[inline] + pub fn $columns_range_pair, Range2: DimRange>($me: $Me, r1: Range1, r2: Range2) + -> ($MatrixView<'_, T, R, Range1::Size, S::RStride, S::CStride>, + $MatrixView<'_, T, R, Range2::Size, S::RStride, S::CStride>) { + + let (nrows, ncols) = $me.shape_generic(); + let strides = $me.data.strides(); + + let start1 = r1.begin(ncols); + let start2 = r2.begin(ncols); + + let end1 = r1.end(ncols); + let end2 = r2.end(ncols); + + let ncols1 = r1.size(ncols); + let ncols2 = r2.size(ncols); + + assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the ranges must not overlap."); + assert!(end2 <= ncols.value(), "Columns range pair: index out of range."); + + unsafe { + let ptr1 = $data.$get_addr(0, start1); + let ptr2 = $data.$get_addr(0, start2); + + let data1 = $ViewStorage::from_raw_parts(ptr1, (nrows, ncols1), strides); + let data2 = $ViewStorage::from_raw_parts(ptr2, (nrows, ncols2), strides); + let view1 = Matrix::from_data_statically_unchecked(data1); + let view2 = Matrix::from_data_statically_unchecked(data2); + + (view1, view2) + } + } + } +); + +/// A matrix slice. +/// +/// This type alias exists only for legacy purposes and is deprecated. It will be removed +/// in a future release. Please use [`MatrixView`] instead. +/// See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) +/// for the rationale. +#[deprecated = "Use MatrixView instead."] +pub type MatrixSlice<'a, T, R, C, RStride = U1, CStride = R> = + MatrixView<'a, T, R, C, RStride, CStride>; + +/// A matrix view. +pub type MatrixView<'a, T, R, C, RStride = U1, CStride = R> = + Matrix>; + +/// A mutable matrix slice. +/// +/// This type alias exists only for legacy purposes and is deprecated. It will be removed +/// in a future release. Please use [`MatrixViewMut`] instead. +/// See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) +/// for the rationale. +#[deprecated = "Use MatrixViewMut instead."] +pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> = + MatrixViewMut<'a, T, R, C, RStride, CStride>; + +/// A mutable matrix view. +pub type MatrixViewMut<'a, T, R, C, RStride = U1, CStride = R> = + Matrix>; + +/// # Views based on index and length +impl> Matrix { + matrix_view_impl!( + self: &Self, MatrixView, ViewStorage, RawStorage.get_address_unchecked(), &self.data; + row, + row_part, + rows, + rows_with_step, + fixed_rows, + fixed_rows_with_step, + rows_generic, + rows_generic_with_step, + column, + column_part, + columns, + columns_with_step, + fixed_columns, + fixed_columns_with_step, + columns_generic, + columns_generic_with_step, + slice => view, + slice_with_steps => view_with_steps, + fixed_slice => fixed_view, + fixed_slice_with_steps => fixed_view_with_steps, + generic_slice => generic_view, + generic_slice_with_steps => generic_view_with_steps, + rows_range_pair, + columns_range_pair); +} + +/// # Mutable views based on index and length +impl> Matrix { + matrix_view_impl!( + self: &mut Self, MatrixViewMut, ViewStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data; + row_mut, + row_part_mut, + rows_mut, + rows_with_step_mut, + fixed_rows_mut, + fixed_rows_with_step_mut, + rows_generic_mut, + rows_generic_with_step_mut, + column_mut, + column_part_mut, + columns_mut, + columns_with_step_mut, + fixed_columns_mut, + fixed_columns_with_step_mut, + columns_generic_mut, + columns_generic_with_step_mut, + slice_mut => view_mut, + slice_with_steps_mut => view_with_steps_mut, + fixed_slice_mut => fixed_view_mut, + fixed_slice_with_steps_mut => fixed_view_with_steps_mut, + generic_slice_mut => generic_view_mut, + generic_slice_with_steps_mut => generic_view_with_steps_mut, + rows_range_pair_mut, + columns_range_pair_mut); +} + +/// A range with a size that may be known at compile-time. +/// +/// This may be: +/// * A single `usize` index, e.g., `4` +/// * A left-open range `std::ops::RangeTo`, e.g., `.. 4` +/// * A right-open range `std::ops::RangeFrom`, e.g., `4 ..` +/// * A full range `std::ops::RangeFull`, e.g., `..` +pub trait DimRange { + /// Type of the range size. May be a type-level integer. + type Size: Dim; + + /// The start index of the range. + fn begin(&self, shape: D) -> usize; + // NOTE: this is the index immediately after the last index. + /// The index immediately after the last index inside of the range. + fn end(&self, shape: D) -> usize; + /// The number of elements of the range, i.e., `self.end - self.begin`. + fn size(&self, shape: D) -> Self::Size; +} + +/// A range with a size that may be known at compile-time. +/// +/// This is merely a legacy trait alias to minimize breakage. Use the [`DimRange`] trait instead. +#[deprecated = slice_deprecation_note!(DimRange)] +pub trait SliceRange: DimRange {} + +#[allow(deprecated)] +impl, D: Dim> SliceRange for R {} + +impl DimRange for usize { + type Size = U1; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + *self + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + *self + 1 + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Const::<1> + } +} + +impl DimRange for Range { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + self.end + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dyn(self.end - self.start) + } +} + +impl DimRange for RangeFrom { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + self.start + } + + #[inline(always)] + fn end(&self, dim: D) -> usize { + dim.value() + } + + #[inline(always)] + fn size(&self, dim: D) -> Self::Size { + Dyn(dim.value() - self.start) + } +} + +impl DimRange for RangeTo { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + self.end + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dyn(self.end) + } +} + +impl DimRange for RangeFull { + type Size = D; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + 0 + } + + #[inline(always)] + fn end(&self, dim: D) -> usize { + dim.value() + } + + #[inline(always)] + fn size(&self, dim: D) -> Self::Size { + dim + } +} + +impl DimRange for RangeInclusive { + type Size = Dyn; + + #[inline(always)] + fn begin(&self, _: D) -> usize { + *self.start() + } + + #[inline(always)] + fn end(&self, _: D) -> usize { + *self.end() + 1 + } + + #[inline(always)] + fn size(&self, _: D) -> Self::Size { + Dyn(*self.end() + 1 - *self.start()) + } +} + +// TODO: see how much of this overlaps with the general indexing +// methods from indexing.rs. +impl> Matrix { + /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed + /// by the range `cols`. + #[inline] + #[must_use] + #[deprecated = slice_deprecation_note!(view_range)] + pub fn slice_range( + &self, + rows: RowRange, + cols: ColRange, + ) -> MatrixView<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + let (nrows, ncols) = self.shape_generic(); + self.generic_view( + (rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols)), + ) + } + + /// Returns a view containing the rows indexed by the range `rows` and the columns indexed + /// by the range `cols`. + #[inline] + #[must_use] + pub fn view_range( + &self, + rows: RowRange, + cols: ColRange, + ) -> MatrixView<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + let (nrows, ncols) = self.shape_generic(); + self.generic_view( + (rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols)), + ) + } + + /// View containing all the rows indexed by the range `rows`. + #[inline] + #[must_use] + pub fn rows_range>( + &self, + rows: RowRange, + ) -> MatrixView<'_, T, RowRange::Size, C, S::RStride, S::CStride> { + self.view_range(rows, ..) + } + + /// View containing all the columns indexed by the range `rows`. + #[inline] + #[must_use] + pub fn columns_range>( + &self, + cols: ColRange, + ) -> MatrixView<'_, T, R, ColRange::Size, S::RStride, S::CStride> { + self.view_range(.., cols) + } +} + +// TODO: see how much of this overlaps with the general indexing +// methods from indexing.rs. +impl> Matrix { + /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns + /// indexed by the range `cols`. + #[deprecated = slice_deprecation_note!(view_range_mut)] + pub fn slice_range_mut( + &mut self, + rows: RowRange, + cols: ColRange, + ) -> MatrixViewMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + self.view_range_mut(rows, cols) + } + + /// Return a mutable view containing the rows indexed by the range `rows` and the columns + /// indexed by the range `cols`. + pub fn view_range_mut( + &mut self, + rows: RowRange, + cols: ColRange, + ) -> MatrixViewMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride> + where + RowRange: DimRange, + ColRange: DimRange, + { + let (nrows, ncols) = self.shape_generic(); + self.generic_view_mut( + (rows.begin(nrows), cols.begin(ncols)), + (rows.size(nrows), cols.size(ncols)), + ) + } + + /// Mutable view containing all the rows indexed by the range `rows`. + #[inline] + pub fn rows_range_mut>( + &mut self, + rows: RowRange, + ) -> MatrixViewMut<'_, T, RowRange::Size, C, S::RStride, S::CStride> { + self.view_range_mut(rows, ..) + } + + /// Mutable view containing all the columns indexed by the range `cols`. + #[inline] + pub fn columns_range_mut>( + &mut self, + cols: ColRange, + ) -> MatrixViewMut<'_, T, R, ColRange::Size, S::RStride, S::CStride> { + self.view_range_mut(.., cols) + } +} + +impl<'a, T, R, C, RStride, CStride> From> + for MatrixView<'a, T, R, C, RStride, CStride> +where + R: Dim, + C: Dim, + RStride: Dim, + CStride: Dim, +{ + fn from(view_mut: MatrixViewMut<'a, T, R, C, RStride, CStride>) -> Self { + let data = ViewStorage { + ptr: view_mut.data.ptr, + shape: view_mut.data.shape, + strides: view_mut.data.strides, + _phantoms: PhantomData, + }; + + unsafe { Matrix::from_data_statically_unchecked(data) } + } +} + +impl Matrix +where + R: Dim, + C: Dim, + S: RawStorage, +{ + /// Returns this matrix as a view. + /// + /// The returned view type is generally ambiguous unless specified. + /// This is particularly useful when working with functions or methods that take + /// matrix views as input. + /// + /// # Panics + /// Panics if the dimensions of the view and the matrix are not compatible and this cannot + /// be proven at compile-time. This might happen, for example, when constructing a static + /// view of size 3x3 from a dynamically sized matrix of dimension 5x5. + /// + /// # Examples + /// ``` + /// use nalgebra::{DMatrixSlice, SMatrixView}; + /// + /// fn consume_view(_: DMatrixSlice) {} + /// + /// let matrix = nalgebra::Matrix3::zeros(); + /// consume_view(matrix.as_view()); + /// + /// let dynamic_view: DMatrixSlice = matrix.as_view(); + /// let static_view_from_dyn: SMatrixView = dynamic_view.as_view(); + /// ``` + pub fn as_view( + &self, + ) -> MatrixView<'_, T, RView, CView, RViewStride, CViewStride> + where + RView: Dim, + CView: Dim, + RViewStride: Dim, + CViewStride: Dim, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, + { + // Defer to (&matrix).into() + self.into() + } +} + +impl Matrix +where + R: Dim, + C: Dim, + S: RawStorageMut, +{ + /// Returns this matrix as a mutable view. + /// + /// The returned view type is generally ambiguous unless specified. + /// This is particularly useful when working with functions or methods that take + /// matrix views as input. + /// + /// # Panics + /// Panics if the dimensions of the view and the matrix are not compatible and this cannot + /// be proven at compile-time. This might happen, for example, when constructing a static + /// view of size 3x3 from a dynamically sized matrix of dimension 5x5. + /// + /// # Examples + /// ``` + /// use nalgebra::{DMatrixViewMut, SMatrixViewMut}; + /// + /// fn consume_view(_: DMatrixViewMut) {} + /// + /// let mut matrix = nalgebra::Matrix3::zeros(); + /// consume_view(matrix.as_view_mut()); + /// + /// let mut dynamic_view: DMatrixViewMut = matrix.as_view_mut(); + /// let static_view_from_dyn: SMatrixViewMut = dynamic_view.as_view_mut(); + /// ``` + pub fn as_view_mut( + &mut self, + ) -> MatrixViewMut<'_, T, RView, CView, RViewStride, CViewStride> + where + RView: Dim, + CView: Dim, + RViewStride: Dim, + CViewStride: Dim, + ShapeConstraint: DimEq + + DimEq + + DimEq + + DimEq, + { + // Defer to (&mut matrix).into() + self.into() + } +} + +// TODO: Arbitrary strides? +impl<'a, T, R1, C1, R2, C2> ReshapableStorage + for ViewStorage<'a, T, R1, C1, U1, R1> +where + T: Scalar, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, +{ + type Output = ViewStorage<'a, T, R2, C2, U1, R2>; + + fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output { + let (r1, c1) = self.shape(); + assert_eq!(nrows.value() * ncols.value(), r1.value() * c1.value()); + let ptr = self.ptr(); + let new_shape = (nrows, ncols); + let strides = (U1::name(), nrows); + unsafe { ViewStorage::from_raw_parts(ptr, new_shape, strides) } + } +} + +// TODO: Arbitrary strides? +impl<'a, T, R1, C1, R2, C2> ReshapableStorage + for ViewStorageMut<'a, T, R1, C1, U1, R1> +where + T: Scalar, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, +{ + type Output = ViewStorageMut<'a, T, R2, C2, U1, R2>; + + fn reshape_generic(mut self, nrows: R2, ncols: C2) -> Self::Output { + let (r1, c1) = self.shape(); + assert_eq!(nrows.value() * ncols.value(), r1.value() * c1.value()); + let ptr = self.ptr_mut(); + let new_shape = (nrows, ncols); + let strides = (U1::name(), nrows); + unsafe { ViewStorageMut::from_raw_parts(ptr, new_shape, strides) } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/min_max.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/min_max.rs new file mode 100644 index 000000000..68c1cedd0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/min_max.rs @@ -0,0 +1,405 @@ +use crate::storage::RawStorage; +use crate::{ComplexField, Dim, Matrix, Scalar, SimdComplexField, SimdPartialOrd, Vector}; +use num::{Signed, Zero}; +use simba::simd::SimdSigned; + +/// # Find the min and max components +impl> Matrix { + /// Returns the absolute value of the component with the largest absolute value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).amax(), 3.0); + /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0); + /// ``` + #[inline] + #[must_use] + pub fn amax(&self) -> T + where + T: Zero + SimdSigned + SimdPartialOrd, + { + self.fold_with( + |e| e.unwrap_or(&T::zero()).simd_abs(), + |a, b| a.simd_max(b.simd_abs()), + ) + } + + /// Returns the the 1-norm of the complex component with the largest 1-norm. + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Complex}; + /// assert_eq!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, 2.0), + /// Complex::new(1.0, 3.0)).camax(), 5.0); + /// ``` + #[inline] + #[must_use] + pub fn camax(&self) -> T::SimdRealField + where + T: SimdComplexField, + { + self.fold_with( + |e| e.unwrap_or(&T::zero()).clone().simd_norm1(), + |a, b| a.simd_max(b.clone().simd_norm1()), + ) + } + + /// Returns the component with the largest value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).max(), 3.0); + /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).max(), -1.0); + /// assert_eq!(Vector3::new(5u32, 2, 3).max(), 5); + /// ``` + #[inline] + #[must_use] + pub fn max(&self) -> T + where + T: SimdPartialOrd + Zero, + { + self.fold_with( + |e| e.cloned().unwrap_or_else(T::zero), + |a, b| a.simd_max(b.clone()), + ) + } + + /// Returns the absolute value of the component with the smallest absolute value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, -3.0).amin(), 1.0); + /// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0); + /// ``` + #[inline] + #[must_use] + pub fn amin(&self) -> T + where + T: Zero + SimdPartialOrd + SimdSigned, + { + self.fold_with( + |e| e.map(|e| e.simd_abs()).unwrap_or_else(T::zero), + |a, b| a.simd_min(b.simd_abs()), + ) + } + + /// Returns the the 1-norm of the complex component with the smallest 1-norm. + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Complex}; + /// assert_eq!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, 2.0), + /// Complex::new(1.0, 3.0)).camin(), 3.0); + /// ``` + #[inline] + #[must_use] + pub fn camin(&self) -> T::SimdRealField + where + T: SimdComplexField, + { + self.fold_with( + |e| { + e.map(|e| e.clone().simd_norm1()) + .unwrap_or_else(T::SimdRealField::zero) + }, + |a, b| a.simd_min(b.clone().simd_norm1()), + ) + } + + /// Returns the component with the smallest value. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).min(), -1.0); + /// assert_eq!(Vector3::new(1.0, 2.0, 3.0).min(), 1.0); + /// assert_eq!(Vector3::new(5u32, 2, 3).min(), 2); + /// ``` + #[inline] + #[must_use] + pub fn min(&self) -> T + where + T: SimdPartialOrd + Zero, + { + self.fold_with( + |e| e.cloned().unwrap_or_else(T::zero), + |a, b| a.simd_min(b.clone()), + ) + } + + /// Computes the index of the matrix component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # extern crate num_complex; + /// # extern crate nalgebra; + /// # use num_complex::Complex; + /// # use nalgebra::Matrix2x3; + /// let mat = Matrix2x3::new(Complex::new(11.0, 1.0), Complex::new(-12.0, 2.0), Complex::new(13.0, 3.0), + /// Complex::new(21.0, 43.0), Complex::new(22.0, 5.0), Complex::new(-23.0, 0.0)); + /// assert_eq!(mat.icamax_full(), (1, 0)); + /// ``` + #[inline] + #[must_use] + pub fn icamax_full(&self) -> (usize, usize) + where + T: ComplexField, + { + assert!(!self.is_empty(), "The input matrix must not be empty."); + + let mut the_max = unsafe { self.get_unchecked((0, 0)).clone().norm1() }; + let mut the_ij = (0, 0); + + for j in 0..self.ncols() { + for i in 0..self.nrows() { + let val = unsafe { self.get_unchecked((i, j)).clone().norm1() }; + + if val > the_max { + the_max = val; + the_ij = (i, j); + } + } + } + + the_ij + } +} + +impl> Matrix { + /// Computes the index of the matrix component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix2x3; + /// let mat = Matrix2x3::new(11, -12, 13, + /// 21, 22, -23); + /// assert_eq!(mat.iamax_full(), (1, 2)); + /// ``` + #[inline] + #[must_use] + pub fn iamax_full(&self) -> (usize, usize) { + assert!(!self.is_empty(), "The input matrix must not be empty."); + + let mut the_max = unsafe { self.get_unchecked((0, 0)).abs() }; + let mut the_ij = (0, 0); + + for j in 0..self.ncols() { + for i in 0..self.nrows() { + let val = unsafe { self.get_unchecked((i, j)).abs() }; + + if val > the_max { + the_max = val; + the_ij = (i, j); + } + } + } + + the_ij + } +} + +// TODO: find a way to avoid code duplication just for complex number support. +/// # Find the min and max components (vector-specific methods) +impl> Vector { + /// Computes the index of the vector component with the largest complex or real absolute value. + /// + /// # Examples: + /// + /// ``` + /// # extern crate num_complex; + /// # extern crate nalgebra; + /// # use num_complex::Complex; + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(Complex::new(11.0, 3.0), Complex::new(-15.0, 0.0), Complex::new(13.0, 5.0)); + /// assert_eq!(vec.icamax(), 2); + /// ``` + #[inline] + #[must_use] + pub fn icamax(&self) -> usize + where + T: ComplexField, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0).clone().norm1() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).clone().norm1() }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + the_i + } + + /// Computes the index and value of the vector component with the largest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.argmax(), (2, 13)); + /// ``` + #[inline] + #[must_use] + pub fn argmax(&self) -> (usize, T) + where + T: PartialOrd, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0) }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i) }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + (the_i, the_max.clone()) + } + + /// Computes the index of the vector component with the largest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.imax(), 2); + /// ``` + #[inline] + #[must_use] + pub fn imax(&self) -> usize + where + T: PartialOrd, + { + self.argmax().0 + } + + /// Computes the index of the vector component with the largest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.iamax(), 1); + /// ``` + #[inline] + #[must_use] + pub fn iamax(&self) -> usize + where + T: PartialOrd + Signed, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_max = unsafe { self.vget_unchecked(0).abs() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).abs() }; + + if val > the_max { + the_max = val; + the_i = i; + } + } + + the_i + } + + /// Computes the index and value of the vector component with the smallest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.argmin(), (1, -15)); + /// ``` + #[inline] + #[must_use] + pub fn argmin(&self) -> (usize, T) + where + T: PartialOrd, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_min = unsafe { self.vget_unchecked(0) }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i) }; + + if val < the_min { + the_min = val; + the_i = i; + } + } + + (the_i, the_min.clone()) + } + + /// Computes the index of the vector component with the smallest value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.imin(), 1); + /// ``` + #[inline] + #[must_use] + pub fn imin(&self) -> usize + where + T: PartialOrd, + { + self.argmin().0 + } + + /// Computes the index of the vector component with the smallest absolute value. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Vector3; + /// let vec = Vector3::new(11, -15, 13); + /// assert_eq!(vec.iamin(), 0); + /// ``` + #[inline] + #[must_use] + pub fn iamin(&self) -> usize + where + T: PartialOrd + Signed, + { + assert!(!self.is_empty(), "The input vector must not be empty."); + + let mut the_min = unsafe { self.vget_unchecked(0).abs() }; + let mut the_i = 0; + + for i in 1..self.nrows() { + let val = unsafe { self.vget_unchecked(i).abs() }; + + if val < the_min { + the_min = val; + the_i = i; + } + } + + the_i + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/mod.rs new file mode 100644 index 000000000..eb66d8578 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/mod.rs @@ -0,0 +1,66 @@ +//! [Reexported at the root of this crate.] Data structures for vector and matrix computations. + +pub mod allocator; +mod blas; +pub mod constraint; +pub mod coordinates; +pub mod default_allocator; +pub mod dimension; +pub mod iter; +mod ops; +pub mod storage; + +mod alias; +mod alias_slice; +mod alias_view; +mod array_storage; +mod cg; +mod componentwise; +#[macro_use] +mod construction; +mod construction_view; +mod conversion; +mod edition; +pub mod indexing; +mod matrix; +mod matrix_simba; +mod matrix_view; +mod norm; +mod properties; +mod scalar; +mod statistics; +mod swizzle; +mod unit; +#[cfg(any(feature = "std", feature = "alloc"))] +mod vec_storage; + +mod blas_uninit; +#[doc(hidden)] +pub mod helper; +mod interpolation; +mod min_max; +/// Mechanisms for working with values that may not be initialized. +pub mod uninit; + +#[cfg(feature = "rayon")] +pub mod par_iter; + +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_wrappers; + +pub use self::matrix::*; +pub use self::norm::*; +pub use self::scalar::*; +pub use self::unit::*; + +pub use self::default_allocator::*; +pub use self::dimension::*; + +pub use self::alias::*; +pub use self::alias_slice::*; +pub use self::alias_view::*; +pub use self::array_storage::*; +pub use self::matrix_view::*; +pub use self::storage::*; +#[cfg(any(feature = "std", feature = "alloc"))] +pub use self::vec_storage::*; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/norm.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/norm.rs new file mode 100644 index 000000000..670a059c9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/norm.rs @@ -0,0 +1,640 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + +use num::Zero; +use std::ops::Neg; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Dim, DimName, Matrix, Normed, OMatrix, OVector}; +use crate::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::storage::{Storage, StorageMut}; +use crate::{ComplexField, Scalar, SimdComplexField, Unit}; +use simba::scalar::ClosedNeg; +use simba::simd::{SimdOption, SimdPartialOrd, SimdValue}; + +// TODO: this should be be a trait on alga? +/// A trait for abstract matrix norms. +/// +/// This may be moved to the alga crate in the future. +pub trait Norm { + /// Apply this norm to the given matrix. + fn norm(&self, m: &Matrix) -> T::SimdRealField + where + R: Dim, + C: Dim, + S: Storage; + /// Use the metric induced by this norm to compute the metric distance between the two given matrices. + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> T::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns; +} + +/// Euclidean norm. +#[derive(Copy, Clone, Debug)] +pub struct EuclideanNorm; +/// Lp norm. +#[derive(Copy, Clone, Debug)] +pub struct LpNorm(pub i32); +/// L-infinite norm aka. Chebytchev norm aka. uniform norm aka. suppremum norm. +#[derive(Copy, Clone, Debug)] +pub struct UniformNorm; + +impl Norm for EuclideanNorm { + #[inline] + fn norm(&self, m: &Matrix) -> T::SimdRealField + where + R: Dim, + C: Dim, + S: Storage, + { + m.norm_squared().simd_sqrt() + } + + #[inline] + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> T::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + m1.zip_fold(m2, T::SimdRealField::zero(), |acc, a, b| { + let diff = a - b; + acc + diff.simd_modulus_squared() + }) + .simd_sqrt() + } +} + +impl Norm for LpNorm { + #[inline] + fn norm(&self, m: &Matrix) -> T::SimdRealField + where + R: Dim, + C: Dim, + S: Storage, + { + m.fold(T::SimdRealField::zero(), |a, b| { + a + b.simd_modulus().simd_powi(self.0) + }) + .simd_powf(crate::convert(1.0 / (self.0 as f64))) + } + + #[inline] + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> T::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + m1.zip_fold(m2, T::SimdRealField::zero(), |acc, a, b| { + let diff = a - b; + acc + diff.simd_modulus().simd_powi(self.0) + }) + .simd_powf(crate::convert(1.0 / (self.0 as f64))) + } +} + +impl Norm for UniformNorm { + #[inline] + fn norm(&self, m: &Matrix) -> T::SimdRealField + where + R: Dim, + C: Dim, + S: Storage, + { + // NOTE: we don't use `m.amax()` here because for the complex + // numbers this will return the max norm1 instead of the modulus. + m.fold(T::SimdRealField::zero(), |acc, a| { + acc.simd_max(a.simd_modulus()) + }) + } + + #[inline] + fn metric_distance( + &self, + m1: &Matrix, + m2: &Matrix, + ) -> T::SimdRealField + where + R1: Dim, + C1: Dim, + S1: Storage, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + m1.zip_fold(m2, T::SimdRealField::zero(), |acc, a, b| { + let val = (a - b).simd_modulus(); + acc.simd_max(val) + }) + } +} + +/// # Magnitude and norms +impl> Matrix { + /// The squared L2 norm of this vector. + #[inline] + #[must_use] + pub fn norm_squared(&self) -> T::SimdRealField + where + T: SimdComplexField, + { + let mut res = T::SimdRealField::zero(); + + for i in 0..self.ncols() { + let col = self.column(i); + res += col.dotc(&col).simd_real() + } + + res + } + + /// The L2 norm of this matrix. + /// + /// Use `.apply_norm` to apply a custom norm. + #[inline] + #[must_use] + pub fn norm(&self) -> T::SimdRealField + where + T: SimdComplexField, + { + self.norm_squared().simd_sqrt() + } + + /// Compute the distance between `self` and `rhs` using the metric induced by the euclidean norm. + /// + /// Use `.apply_metric_distance` to apply a custom norm. + #[inline] + #[must_use] + pub fn metric_distance(&self, rhs: &Matrix) -> T::SimdRealField + where + T: SimdComplexField, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + self.apply_metric_distance(rhs, &EuclideanNorm) + } + + /// Uses the given `norm` to compute the norm of `self`. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Vector3, UniformNorm, LpNorm, EuclideanNorm}; + /// + /// let v = Vector3::new(1.0, 2.0, 3.0); + /// assert_eq!(v.apply_norm(&UniformNorm), 3.0); + /// assert_eq!(v.apply_norm(&LpNorm(1)), 6.0); + /// assert_eq!(v.apply_norm(&EuclideanNorm), v.norm()); + /// ``` + #[inline] + #[must_use] + pub fn apply_norm(&self, norm: &impl Norm) -> T::SimdRealField + where + T: SimdComplexField, + { + norm.norm(self) + } + + /// Uses the metric induced by the given `norm` to compute the metric distance between `self` and `rhs`. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Vector3, UniformNorm, LpNorm, EuclideanNorm}; + /// + /// let v1 = Vector3::new(1.0, 2.0, 3.0); + /// let v2 = Vector3::new(10.0, 20.0, 30.0); + /// + /// assert_eq!(v1.apply_metric_distance(&v2, &UniformNorm), 27.0); + /// assert_eq!(v1.apply_metric_distance(&v2, &LpNorm(1)), 27.0 + 18.0 + 9.0); + /// assert_eq!(v1.apply_metric_distance(&v2, &EuclideanNorm), (v1 - v2).norm()); + /// ``` + #[inline] + #[must_use] + pub fn apply_metric_distance( + &self, + rhs: &Matrix, + norm: &impl Norm, + ) -> T::SimdRealField + where + T: SimdComplexField, + R2: Dim, + C2: Dim, + S2: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, + { + norm.metric_distance(self, rhs) + } + + /// A synonym for the norm of this matrix. + /// + /// Aka the length. + /// + /// This function is simply implemented as a call to `norm()` + #[inline] + #[must_use] + pub fn magnitude(&self) -> T::SimdRealField + where + T: SimdComplexField, + { + self.norm() + } + + /// A synonym for the squared norm of this matrix. + /// + /// Aka the squared length. + /// + /// This function is simply implemented as a call to `norm_squared()` + #[inline] + #[must_use] + pub fn magnitude_squared(&self) -> T::SimdRealField + where + T: SimdComplexField, + { + self.norm_squared() + } + + /// Sets the magnitude of this vector. + #[inline] + pub fn set_magnitude(&mut self, magnitude: T::SimdRealField) + where + T: SimdComplexField, + S: StorageMut, + { + let n = self.norm(); + self.scale_mut(magnitude / n) + } + + /// Returns a normalized version of this matrix. + #[inline] + #[must_use = "Did you mean to use normalize_mut()?"] + pub fn normalize(&self) -> OMatrix + where + T: SimdComplexField, + DefaultAllocator: Allocator, + { + self.unscale(self.norm()) + } + + /// The Lp norm of this matrix. + #[inline] + #[must_use] + pub fn lp_norm(&self, p: i32) -> T::SimdRealField + where + T: SimdComplexField, + { + self.apply_norm(&LpNorm(p)) + } + + /// Attempts to normalize `self`. + /// + /// The components of this matrix can be SIMD types. + #[inline] + #[must_use = "Did you mean to use simd_try_normalize_mut()?"] + pub fn simd_try_normalize(&self, min_norm: T::SimdRealField) -> SimdOption> + where + T: SimdComplexField, + T::Element: Scalar, + DefaultAllocator: Allocator, + { + let n = self.norm(); + let le = n.clone().simd_le(min_norm); + let val = self.unscale(n); + SimdOption::new(val, le) + } + + /// Sets the magnitude of this vector unless it is smaller than `min_magnitude`. + /// + /// If `self.magnitude()` is smaller than `min_magnitude`, it will be left unchanged. + /// Otherwise this is equivalent to: `*self = self.normalize() * magnitude`. + #[inline] + pub fn try_set_magnitude(&mut self, magnitude: T::RealField, min_magnitude: T::RealField) + where + T: ComplexField, + S: StorageMut, + { + let n = self.norm(); + + if n > min_magnitude { + self.scale_mut(magnitude / n) + } + } + + /// Returns a new vector with the same magnitude as `self` clamped between `0.0` and `max`. + #[inline] + #[must_use] + pub fn cap_magnitude(&self, max: T::RealField) -> OMatrix + where + T: ComplexField, + DefaultAllocator: Allocator, + { + let n = self.norm(); + + if n > max { + self.scale(max / n) + } else { + self.clone_owned() + } + } + + /// Returns a new vector with the same magnitude as `self` clamped between `0.0` and `max`. + #[inline] + #[must_use] + pub fn simd_cap_magnitude(&self, max: T::SimdRealField) -> OMatrix + where + T: SimdComplexField, + T::Element: Scalar, + DefaultAllocator: Allocator, + { + let n = self.norm(); + let scaled = self.scale(max.clone() / n.clone()); + let use_scaled = n.simd_gt(max); + scaled.select(use_scaled, self.clone_owned()) + } + + /// Returns a normalized version of this matrix unless its norm as smaller or equal to `eps`. + /// + /// The components of this matrix cannot be SIMD types (see `simd_try_normalize`) instead. + #[inline] + #[must_use = "Did you mean to use try_normalize_mut()?"] + pub fn try_normalize(&self, min_norm: T::RealField) -> Option> + where + T: ComplexField, + DefaultAllocator: Allocator, + { + let n = self.norm(); + + if n <= min_norm { + None + } else { + Some(self.unscale(n)) + } + } +} + +/// # In-place normalization +impl> Matrix { + /// Normalizes this matrix in-place and returns its norm. + /// + /// The components of the matrix cannot be SIMD types (see `simd_try_normalize_mut` instead). + #[inline] + pub fn normalize_mut(&mut self) -> T::SimdRealField + where + T: SimdComplexField, + { + let n = self.norm(); + self.unscale_mut(n.clone()); + + n + } + + /// Normalizes this matrix in-place and return its norm. + /// + /// The components of the matrix can be SIMD types. + #[inline] + #[must_use = "Did you mean to use simd_try_normalize_mut()?"] + pub fn simd_try_normalize_mut( + &mut self, + min_norm: T::SimdRealField, + ) -> SimdOption + where + T: SimdComplexField, + T::Element: Scalar, + DefaultAllocator: Allocator, + { + let n = self.norm(); + let le = n.clone().simd_le(min_norm); + self.apply(|e| *e = e.clone().simd_unscale(n.clone()).select(le, e.clone())); + SimdOption::new(n, le) + } + + /// Normalizes this matrix in-place or does nothing if its norm is smaller or equal to `eps`. + /// + /// If the normalization succeeded, returns the old norm of this matrix. + #[inline] + pub fn try_normalize_mut(&mut self, min_norm: T::RealField) -> Option + where + T: ComplexField, + { + let n = self.norm(); + + if n <= min_norm { + None + } else { + self.unscale_mut(n.clone()); + Some(n) + } + } +} + +impl Normed for OMatrix +where + DefaultAllocator: Allocator, +{ + type Norm = T::SimdRealField; + + #[inline] + fn norm(&self) -> T::SimdRealField { + self.norm() + } + + #[inline] + fn norm_squared(&self) -> T::SimdRealField { + self.norm_squared() + } + + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.scale_mut(n) + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.unscale_mut(n) + } +} + +impl Neg for Unit> +where + DefaultAllocator: Allocator, +{ + type Output = Unit>; + + #[inline] + fn neg(self) -> Self::Output { + Unit::new_unchecked(-self.value) + } +} + +// TODO: specialization will greatly simplify this implementation in the future. +// In particular: +// − use `x()` instead of `::canonical_basis_element` +// − use `::new(x, y, z)` instead of `::from_slice` +/// # Basis and orthogonalization +impl OVector +where + DefaultAllocator: Allocator, +{ + /// The i-the canonical basis element. + #[inline] + fn canonical_basis_element(i: usize) -> Self { + let mut res = Self::zero(); + res[i] = T::one(); + res + } + + /// Orthonormalizes the given family of vectors. The largest free family of vectors is moved at + /// the beginning of the array and its size is returned. Vectors at an indices larger or equal to + /// this length can be modified to an arbitrary value. + #[inline] + pub fn orthonormalize(vs: &mut [Self]) -> usize { + let mut nbasis_elements = 0; + + for i in 0..vs.len() { + { + let (elt, basis) = vs[..i + 1].split_last_mut().unwrap(); + + for basis_element in &basis[..nbasis_elements] { + *elt -= basis_element * elt.dot(basis_element) + } + } + + if vs[i].try_normalize_mut(T::RealField::zero()).is_some() { + // TODO: this will be efficient on dynamically-allocated vectors but for + // statically-allocated ones, `.clone_from` would be better. + vs.swap(nbasis_elements, i); + nbasis_elements += 1; + + // All the other vectors will be dependent. + if nbasis_elements == D::dim() { + break; + } + } + } + + nbasis_elements + } + + /// Applies the given closure to each element of the orthonormal basis of the subspace + /// orthogonal to free family of vectors `vs`. If `vs` is not a free family, the result is + /// unspecified. + // TODO: return an iterator instead when `-> impl Iterator` will be supported by Rust. + #[inline] + pub fn orthonormal_subspace_basis(vs: &[Self], mut f: F) + where + F: FnMut(&Self) -> bool, + { + // TODO: is this necessary? + assert!( + vs.len() <= D::dim(), + "The given set of vectors has no chance of being a free family." + ); + + match D::dim() { + 1 => { + if vs.is_empty() { + let _ = f(&Self::canonical_basis_element(0)); + } + } + 2 => { + if vs.is_empty() { + let _ = f(&Self::canonical_basis_element(0)) + && f(&Self::canonical_basis_element(1)); + } else if vs.len() == 1 { + let v = &vs[0]; + let res = Self::from_column_slice(&[-v[1].clone(), v[0].clone()]); + + let _ = f(&res.normalize()); + } + + // Otherwise, nothing. + } + 3 => { + if vs.is_empty() { + let _ = f(&Self::canonical_basis_element(0)) + && f(&Self::canonical_basis_element(1)) + && f(&Self::canonical_basis_element(2)); + } else if vs.len() == 1 { + let v = &vs[0]; + let mut a; + + if v[0].clone().norm1() > v[1].clone().norm1() { + a = Self::from_column_slice(&[v[2].clone(), T::zero(), -v[0].clone()]); + } else { + a = Self::from_column_slice(&[T::zero(), -v[2].clone(), v[1].clone()]); + }; + + let _ = a.normalize_mut(); + + if f(&a.cross(v)) { + let _ = f(&a); + } + } else if vs.len() == 2 { + let _ = f(&vs[0].cross(&vs[1]).normalize()); + } + } + _ => { + #[cfg(any(feature = "std", feature = "alloc"))] + { + // XXX: use a GenericArray instead. + let mut known_basis = Vec::new(); + + for v in vs.iter() { + known_basis.push(v.normalize()) + } + + for i in 0..D::dim() - vs.len() { + let mut elt = Self::canonical_basis_element(i); + + for v in &known_basis { + elt -= v * elt.dot(v) + } + + if let Some(subsp_elt) = elt.try_normalize(T::RealField::zero()) { + if !f(&subsp_elt) { + return; + }; + + known_basis.push(subsp_elt); + } + } + } + #[cfg(all(not(feature = "std"), not(feature = "alloc")))] + { + panic!("Cannot compute the orthogonal subspace basis of a vector with a dimension greater than 3 \ + if #![no_std] is enabled and the 'alloc' feature is not enabled.") + } + } + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/ops.rs new file mode 100644 index 000000000..e492da98b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/ops.rs @@ -0,0 +1,856 @@ +use num::{One, Zero}; +use std::iter; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, +}; + +use simba::scalar::{ + ClosedAddAssign, ClosedDivAssign, ClosedMulAssign, ClosedNeg, ClosedSubAssign, +}; + +use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR}; +use crate::base::blas_uninit::gemm_uninit; +use crate::base::constraint::{ + AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, +}; +use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dyn}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::uninit::Uninit; +use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorView}; +use crate::storage::IsContiguous; +use crate::uninit::{Init, InitStatus}; +use crate::{RawStorage, RawStorageMut, SimdComplexField}; +use std::mem::MaybeUninit; + +/* + * + * Indexing. + * + */ +impl> Index for Matrix { + type Output = T; + + #[inline] + fn index(&self, i: usize) -> &Self::Output { + let ij = self.vector_to_matrix_index(i); + &self[ij] + } +} + +impl> Index<(usize, usize)> for Matrix { + type Output = T; + + #[inline] + fn index(&self, ij: (usize, usize)) -> &Self::Output { + let shape = self.shape(); + assert!( + ij.0 < shape.0 && ij.1 < shape.1, + "Matrix index out of bounds." + ); + + unsafe { self.get_unchecked((ij.0, ij.1)) } + } +} + +// Mutable versions. +impl> IndexMut for Matrix { + #[inline] + fn index_mut(&mut self, i: usize) -> &mut T { + let ij = self.vector_to_matrix_index(i); + &mut self[ij] + } +} + +impl> IndexMut<(usize, usize)> for Matrix { + #[inline] + fn index_mut(&mut self, ij: (usize, usize)) -> &mut T { + let shape = self.shape(); + assert!( + ij.0 < shape.0 && ij.1 < shape.1, + "Matrix index out of bounds." + ); + + unsafe { self.get_unchecked_mut((ij.0, ij.1)) } + } +} + +/* + * + * Neg + * + */ +impl Neg for Matrix +where + T: Scalar + ClosedNeg, + S: Storage, + DefaultAllocator: Allocator, +{ + type Output = OMatrix; + + #[inline] + fn neg(self) -> Self::Output { + let mut res = self.into_owned(); + res.neg_mut(); + res + } +} + +impl<'a, T, R: Dim, C: Dim, S> Neg for &'a Matrix +where + T: Scalar + ClosedNeg, + S: Storage, + DefaultAllocator: Allocator, +{ + type Output = OMatrix; + + #[inline] + fn neg(self) -> Self::Output { + -self.clone_owned() + } +} + +impl Matrix +where + T: Scalar + ClosedNeg, + S: StorageMut, +{ + /// Negates `self` in-place. + #[inline] + pub fn neg_mut(&mut self) { + for e in self.iter_mut() { + *e = -e.clone() + } + } +} + +/* + * + * Addition & Subtraction + * + */ + +macro_rules! componentwise_binop_impl( + ($Trait: ident, $method: ident, $bound: ident; + $TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident, + $method_assign_statically_unchecked_rhs: ident; + $method_to: ident, $method_to_statically_unchecked_uninit: ident) => { + + impl> Matrix + where T: Scalar + $bound { + + /* + * + * Methods without dimension checking at compile-time. + * This is useful for code reuse because the sum representative system does not plays + * easily with static checks. + * + */ + #[inline] + fn $method_to_statically_unchecked_uninit(&self, + _status: Status, + rhs: &Matrix, + out: &mut Matrix) + where Status: InitStatus, + SB: RawStorage, + SC: RawStorageMut { + assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch."); + + // This is the most common case and should be deduced at compile-time. + // TODO: use specialization instead? + unsafe { + if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() { + let arr1 = self.data.as_slice_unchecked(); + let arr2 = rhs.data.as_slice_unchecked(); + let out = out.data.as_mut_slice_unchecked(); + for i in 0 .. arr1.len() { + Status::init(out.get_unchecked_mut(i), arr1.get_unchecked(i).clone().$method(arr2.get_unchecked(i).clone())); + } + } else { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + let val = self.get_unchecked((i, j)).clone().$method(rhs.get_unchecked((i, j)).clone()); + Status::init(out.get_unchecked_mut((i, j)), val); + } + } + } + } + } + + + #[inline] + fn $method_assign_statically_unchecked(&mut self, rhs: &Matrix) + where R2: Dim, + C2: Dim, + SA: StorageMut, + SB: Storage { + assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + + // This is the most common case and should be deduced at compile-time. + // TODO: use specialization instead? + unsafe { + if self.data.is_contiguous() && rhs.data.is_contiguous() { + let arr1 = self.data.as_mut_slice_unchecked(); + let arr2 = rhs.data.as_slice_unchecked(); + + for i in 0 .. arr2.len() { + arr1.get_unchecked_mut(i).$method_assign(arr2.get_unchecked(i).clone()); + } + } else { + for j in 0 .. rhs.ncols() { + for i in 0 .. rhs.nrows() { + self.get_unchecked_mut((i, j)).$method_assign(rhs.get_unchecked((i, j)).clone()) + } + } + } + } + } + + + #[inline] + fn $method_assign_statically_unchecked_rhs(&self, rhs: &mut Matrix) + where R2: Dim, + C2: Dim, + SB: StorageMut { + assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + + // This is the most common case and should be deduced at compile-time. + // TODO: use specialization instead? + unsafe { + if self.data.is_contiguous() && rhs.data.is_contiguous() { + let arr1 = self.data.as_slice_unchecked(); + let arr2 = rhs.data.as_mut_slice_unchecked(); + + for i in 0 .. arr1.len() { + let res = arr1.get_unchecked(i).clone().$method(arr2.get_unchecked(i).clone()); + *arr2.get_unchecked_mut(i) = res; + } + } else { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + let r = rhs.get_unchecked_mut((i, j)); + *r = self.get_unchecked((i, j)).clone().$method(r.clone()) + } + } + } + } + } + + + /* + * + * Methods without dimension checking at compile-time. + * This is useful for code reuse because the sum representative system does not plays + * easily with static checks. + * + */ + /// Equivalent to `self + rhs` but stores the result into `out` to avoid allocations. + #[inline] + pub fn $method_to(&self, + rhs: &Matrix, + out: &mut Matrix) + where SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns + + SameNumberOfRows + SameNumberOfColumns { + self.$method_to_statically_unchecked_uninit(Init, rhs, out) + } + } + + impl<'b, T, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix> for Matrix + where R1: Dim, C1: Dim, R2: Dim, C2: Dim, + T: Scalar + $bound, + SA: Storage, + SB: Storage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; + + #[inline] + fn $method(self, rhs: &'b Matrix) -> Self::Output { + assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + let mut res = self.into_owned_sum::(); + res.$method_assign_statically_unchecked(rhs); + res + } + } + + impl<'a, T, R1, C1, R2, C2, SA, SB> $Trait> for &'a Matrix + where R1: Dim, C1: Dim, R2: Dim, C2: Dim, + T: Scalar + $bound, + SA: Storage, + SB: Storage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; + + #[inline] + fn $method(self, rhs: Matrix) -> Self::Output { + let mut rhs = rhs.into_owned_sum::(); + assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch."); + self.$method_assign_statically_unchecked_rhs(&mut rhs); + rhs + } + } + + impl $Trait> for Matrix + where R1: Dim, C1: Dim, R2: Dim, C2: Dim, + T: Scalar + $bound, + SA: Storage, + SB: Storage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; + + #[inline] + fn $method(self, rhs: Matrix) -> Self::Output { + self.$method(&rhs) + } + } + + impl<'a, 'b, T, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix> for &'a Matrix + where R1: Dim, C1: Dim, R2: Dim, C2: Dim, + T: Scalar + $bound, + SA: Storage, + SB: Storage, + DefaultAllocator: SameShapeAllocator, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + type Output = MatrixSum; + + #[inline] + fn $method(self, rhs: &'b Matrix) -> Self::Output { + let (nrows, ncols) = self.shape(); + let nrows: SameShapeR = Dim::from_usize(nrows); + let ncols: SameShapeC = Dim::from_usize(ncols); + let mut res = Matrix::uninit(nrows, ncols); + self.$method_to_statically_unchecked_uninit(Uninit, rhs, &mut res); + // SAFETY: the output has been initialized above. + unsafe { res.assume_init() } + } + } + + impl<'b, T, R1, C1, R2, C2, SA, SB> $TraitAssign<&'b Matrix> for Matrix + where R1: Dim, C1: Dim, R2: Dim, C2: Dim, + T: Scalar + $bound, + SA: StorageMut, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + #[inline] + fn $method_assign(&mut self, rhs: &'b Matrix) { + self.$method_assign_statically_unchecked(rhs) + } + } + + impl $TraitAssign> for Matrix + where R1: Dim, C1: Dim, R2: Dim, C2: Dim, + T: Scalar + $bound, + SA: StorageMut, + SB: Storage, + ShapeConstraint: SameNumberOfRows + SameNumberOfColumns { + + #[inline] + fn $method_assign(&mut self, rhs: Matrix) { + self.$method_assign(&rhs) + } + } + } +); + +componentwise_binop_impl!(Add, add, ClosedAddAssign; + AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut; + add_to, add_to_statically_unchecked_uninit); +componentwise_binop_impl!(Sub, sub, ClosedSubAssign; + SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut; + sub_to, sub_to_statically_unchecked_uninit); + +impl iter::Sum for OMatrix +where + T: Scalar + ClosedAddAssign + Zero, + DefaultAllocator: Allocator, +{ + fn sum>>(iter: I) -> OMatrix { + iter.fold(Matrix::zero(), |acc, x| acc + x) + } +} + +impl iter::Sum for OMatrix +where + T: Scalar + ClosedAddAssign + Zero, + DefaultAllocator: Allocator, +{ + /// # Example + /// ``` + /// # use nalgebra::DVector; + /// assert_eq!(vec![DVector::repeat(3, 1.0f64), + /// DVector::repeat(3, 1.0f64), + /// DVector::repeat(3, 1.0f64)].into_iter().sum::>(), + /// DVector::repeat(3, 1.0f64) + DVector::repeat(3, 1.0f64) + DVector::repeat(3, 1.0f64)); + /// ``` + /// + /// # Panics + /// Panics if the iterator is empty: + /// ```should_panic + /// # use std::iter; + /// # use nalgebra::DMatrix; + /// iter::empty::>().sum::>(); // panics! + /// ``` + fn sum>>(mut iter: I) -> OMatrix { + if let Some(first) = iter.next() { + iter.fold(first, |acc, x| acc + x) + } else { + panic!("Cannot compute `sum` of empty iterator.") + } + } +} + +impl<'a, T, R: DimName, C: DimName> iter::Sum<&'a OMatrix> for OMatrix +where + T: Scalar + ClosedAddAssign + Zero, + DefaultAllocator: Allocator, +{ + fn sum>>(iter: I) -> OMatrix { + iter.fold(Matrix::zero(), |acc, x| acc + x) + } +} + +impl<'a, T, C: Dim> iter::Sum<&'a OMatrix> for OMatrix +where + T: Scalar + ClosedAddAssign + Zero, + DefaultAllocator: Allocator, +{ + /// # Example + /// ``` + /// # use nalgebra::DVector; + /// let v = &DVector::repeat(3, 1.0f64); + /// + /// assert_eq!(vec![v, v, v].into_iter().sum::>(), + /// v + v + v); + /// ``` + /// + /// # Panics + /// Panics if the iterator is empty: + /// ```should_panic + /// # use std::iter; + /// # use nalgebra::DMatrix; + /// iter::empty::<&DMatrix>().sum::>(); // panics! + /// ``` + fn sum>>(mut iter: I) -> OMatrix { + if let Some(first) = iter.next() { + iter.fold(first.clone(), |acc, x| acc + x) + } else { + panic!("Cannot compute `sum` of empty iterator.") + } + } +} + +/* + * + * Multiplication + * + */ + +// Matrix × Scalar +// Matrix / Scalar +macro_rules! componentwise_scalarop_impl( + ($Trait: ident, $method: ident, $bound: ident; + $TraitAssign: ident, $method_assign: ident) => { + impl $Trait for Matrix + where T: Scalar + $bound, + S: Storage, + DefaultAllocator: Allocator { + type Output = OMatrix; + + #[inline] + fn $method(self, rhs: T) -> Self::Output { + let mut res = self.into_owned(); + + // XXX: optimize our iterator! + // + // Using our own iterator prevents loop unrolling, which breaks some optimization + // (like SIMD). On the other hand, using the slice iterator is 4x faster. + + // for left in res.iter_mut() { + for left in res.as_mut_slice().iter_mut() { + *left = left.clone().$method(rhs.clone()) + } + + res + } + } + + impl<'a, T, R: Dim, C: Dim, S> $Trait for &'a Matrix + where T: Scalar + $bound, + S: Storage, + DefaultAllocator: Allocator { + type Output = OMatrix; + + #[inline] + fn $method(self, rhs: T) -> Self::Output { + self.clone_owned().$method(rhs) + } + } + + impl $TraitAssign for Matrix + where T: Scalar + $bound, + S: StorageMut { + #[inline] + fn $method_assign(&mut self, rhs: T) { + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs.clone()) }; + } + } + } + } + } +); + +componentwise_scalarop_impl!(Mul, mul, ClosedMulAssign; MulAssign, mul_assign); +componentwise_scalarop_impl!(Div, div, ClosedDivAssign; DivAssign, div_assign); + +macro_rules! left_scalar_mul_impl( + ($($T: ty),* $(,)*) => {$( + impl> Mul> for $T + where DefaultAllocator: Allocator { + type Output = OMatrix<$T, R, C>; + + #[inline] + fn mul(self, rhs: Matrix<$T, R, C, S>) -> Self::Output { + let mut res = rhs.into_owned(); + + // XXX: optimize our iterator! + // + // Using our own iterator prevents loop unrolling, which breaks some optimization + // (like SIMD). On the other hand, using the slice iterator is 4x faster. + + // for rhs in res.iter_mut() { + for rhs in res.as_mut_slice().iter_mut() { + *rhs *= self + } + + res + } + } + + impl<'b, R: Dim, C: Dim, S: Storage<$T, R, C>> Mul<&'b Matrix<$T, R, C, S>> for $T + where DefaultAllocator: Allocator { + type Output = OMatrix<$T, R, C>; + + #[inline] + fn mul(self, rhs: &'b Matrix<$T, R, C, S>) -> Self::Output { + self * rhs.clone_owned() + } + } + )*} +); + +left_scalar_mul_impl!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64); + +// Matrix × Matrix +impl<'a, 'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix> + for &'a Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SA: Storage, + SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable, +{ + type Output = OMatrix; + + #[inline] + fn mul(self, rhs: &'b Matrix) -> Self::Output { + let mut res = Matrix::uninit(self.shape_generic().0, rhs.shape_generic().1); + unsafe { + // SAFETY: this is OK because status = Uninit && bevy == 0 + gemm_uninit(Uninit, &mut res, T::one(), self, rhs, T::zero()); + res.assume_init() + } + } +} + +impl<'a, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul> + for &'a Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SB: Storage, + SA: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable, +{ + type Output = OMatrix; + + #[inline] + fn mul(self, rhs: Matrix) -> Self::Output { + self * &rhs + } +} + +impl<'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix> + for Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SB: Storage, + SA: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable, +{ + type Output = OMatrix; + + #[inline] + fn mul(self, rhs: &'b Matrix) -> Self::Output { + &self * rhs + } +} + +impl Mul> + for Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SB: Storage, + SA: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: AreMultipliable, +{ + type Output = OMatrix; + + #[inline] + fn mul(self, rhs: Matrix) -> Self::Output { + &self * &rhs + } +} + +// TODO: this is too restrictive: +// − we can't use `a *= b` when `a` is a mutable slice. +// − we can't use `a *= b` when C2 is not equal to C1. +impl MulAssign> for Matrix +where + R1: Dim, + C1: Dim, + R2: Dim, + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SB: Storage, + SA: StorageMut + IsContiguous + Clone, // TODO: get rid of the IsContiguous + ShapeConstraint: AreMultipliable, + DefaultAllocator: Allocator = SA>, +{ + #[inline] + fn mul_assign(&mut self, rhs: Matrix) { + *self = &*self * rhs + } +} + +impl<'b, T, R1, C1, R2, SA, SB> MulAssign<&'b Matrix> for Matrix +where + R1: Dim, + C1: Dim, + R2: Dim, + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SB: Storage, + SA: StorageMut + IsContiguous + Clone, // TODO: get rid of the IsContiguous + ShapeConstraint: AreMultipliable, + // TODO: this is too restrictive. See comments for the non-ref version. + DefaultAllocator: Allocator = SA>, +{ + #[inline] + fn mul_assign(&mut self, rhs: &'b Matrix) { + *self = &*self * rhs + } +} + +/// # Special multiplications. +impl Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + SA: Storage, +{ + /// Equivalent to `self.transpose() * rhs`. + #[inline] + #[must_use] + pub fn tr_mul(&self, rhs: &Matrix) -> OMatrix + where + SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1); + self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dot(b)); + // SAFETY: this is OK because the result is now initialized. + unsafe { res.assume_init() } + } + + /// Equivalent to `self.adjoint() * rhs`. + #[inline] + #[must_use] + pub fn ad_mul(&self, rhs: &Matrix) -> OMatrix + where + T: SimdComplexField, + SB: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1); + self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dotc(b)); + // SAFETY: this is OK because the result is now initialized. + unsafe { res.assume_init() } + } + + #[inline(always)] + fn xx_mul_to_uninit( + &self, + _status: Status, + rhs: &Matrix, + out: &mut Matrix, + dot: impl Fn( + &VectorView<'_, T, R1, SA::RStride, SA::CStride>, + &VectorView<'_, T, R2, SB::RStride, SB::CStride>, + ) -> T, + ) where + Status: InitStatus, + SB: RawStorage, + SC: RawStorageMut, + ShapeConstraint: SameNumberOfRows + DimEq + DimEq, + { + let (nrows1, ncols1) = self.shape(); + let (nrows2, ncols2) = rhs.shape(); + let (nrows3, ncols3) = out.shape(); + + assert!( + nrows1 == nrows2, + "Matrix multiplication dimensions mismatch {:?} and {:?}: left rows != right rows.", + self.shape(), + rhs.shape() + ); + assert!( + ncols1 == nrows3, + "Matrix multiplication output dimensions mismatch {:?} and {:?}: left cols != right rows.", + self.shape(), + out.shape() + ); + assert!( + ncols2 == ncols3, + "Matrix multiplication output dimensions mismatch {:?} and {:?}: left cols != right cols", + rhs.shape(), + out.shape() + ); + + for i in 0..ncols1 { + for j in 0..ncols2 { + let dot = dot(&self.column(i), &rhs.column(j)); + let elt = unsafe { out.get_unchecked_mut((i, j)) }; + Status::init(elt, dot); + } + } + } + + /// Equivalent to `self.transpose() * rhs` but stores the result into `out` to avoid + /// allocations. + #[inline] + pub fn tr_mul_to( + &self, + rhs: &Matrix, + out: &mut Matrix, + ) where + SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + DimEq + DimEq, + { + self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dot(b)) + } + + /// Equivalent to `self.adjoint() * rhs` but stores the result into `out` to avoid + /// allocations. + #[inline] + pub fn ad_mul_to( + &self, + rhs: &Matrix, + out: &mut Matrix, + ) where + T: SimdComplexField, + SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + DimEq + DimEq, + { + self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dotc(b)) + } + + /// Equivalent to `self * rhs` but stores the result into `out` to avoid allocations. + #[inline] + pub fn mul_to( + &self, + rhs: &Matrix, + out: &mut Matrix, + ) where + SB: Storage, + SC: StorageMut, + ShapeConstraint: SameNumberOfRows + + SameNumberOfColumns + + AreMultipliable, + { + out.gemm(T::one(), self, rhs, T::zero()); + } + + /// The kronecker product of two matrices (aka. tensor product of the corresponding linear + /// maps). + #[must_use] + pub fn kronecker( + &self, + rhs: &Matrix, + ) -> OMatrix, DimProd> + where + T: ClosedMulAssign, + R1: DimMul, + C1: DimMul, + SB: Storage, + DefaultAllocator: Allocator, DimProd>, + { + let (nrows1, ncols1) = self.shape_generic(); + let (nrows2, ncols2) = rhs.shape_generic(); + + let mut res = Matrix::uninit(nrows1.mul(nrows2), ncols1.mul(ncols2)); + let mut data_res = res.data.ptr_mut(); + + unsafe { + for j1 in 0..ncols1.value() { + for j2 in 0..ncols2.value() { + for i1 in 0..nrows1.value() { + let coeff = self.get_unchecked((i1, j1)).clone(); + + for i2 in 0..nrows2.value() { + *data_res = MaybeUninit::new( + coeff.clone() * rhs.get_unchecked((i2, j2)).clone(), + ); + data_res = data_res.offset(1); + } + } + } + } + + // SAFETY: the result matrix has been initialized by the loop above. + res.assume_init() + } + } +} + +impl iter::Product for OMatrix +where + T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign, + DefaultAllocator: Allocator, +{ + fn product>>(iter: I) -> OMatrix { + iter.fold(Matrix::one(), |acc, x| acc * x) + } +} + +impl<'a, T, D: DimName> iter::Product<&'a OMatrix> for OMatrix +where + T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign, + DefaultAllocator: Allocator, +{ + fn product>>(iter: I) -> OMatrix { + iter.fold(Matrix::one(), |acc, x| acc * x) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/par_iter.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/par_iter.rs new file mode 100644 index 000000000..7c8ebd3d9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/par_iter.rs @@ -0,0 +1,285 @@ +//! Parallel iterators for matrices compatible with rayon. + +// only enables the `doc_cfg` feature when +// the `docsrs` configuration attribute is defined +#![cfg_attr(docsrs, feature(doc_cfg))] + +use crate::{ + iter::{ColumnIter, ColumnIterMut}, + Dim, Matrix, MatrixView, MatrixViewMut, RawStorage, RawStorageMut, Scalar, U1, +}; +use rayon::iter::plumbing::Producer; +use rayon::{iter::plumbing::bridge, prelude::*}; + +/// A rayon parallel iterator over the columns of a matrix. It is created +/// using the [`par_column_iter`] method of [`Matrix`]. +/// +/// *Only available if compiled with the feature `rayon`.* +/// [`par_column_iter`]: crate::Matrix::par_column_iter +/// [`Matrix`]: crate::Matrix +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +pub struct ParColumnIter<'a, T, R: Dim, Cols: Dim, S: RawStorage> { + mat: &'a Matrix, +} + +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParColumnIter<'a, T, R, Cols, S> { + /// Create a new parallel iterator for the given matrix. + fn new(matrix: &'a Matrix) -> Self { + Self { mat: matrix } + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> ParallelIterator + for ParColumnIter<'a, T, R, Cols, S> +where + T: Sync + Send + Scalar, + S: Sync, +{ + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; + + fn drive_unindexed(self, consumer: Consumer) -> Consumer::Result + where + Consumer: rayon::iter::plumbing::UnindexedConsumer, + { + bridge(self, consumer) + } + + fn opt_len(&self) -> Option { + Some(self.mat.ncols()) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`.* +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> IndexedParallelIterator + for ParColumnIter<'a, T, R, Cols, S> +where + T: Send + Sync + Scalar, + S: Sync, +{ + fn len(&self) -> usize { + self.mat.ncols() + } + + fn drive>(self, consumer: C) -> C::Result { + bridge(self, consumer) + } + + fn with_producer>( + self, + callback: CB, + ) -> CB::Output { + let producer = ColumnProducer(ColumnIter::new(self.mat)); + callback.callback(producer) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// A rayon parallel iterator through the mutable columns of a matrix. +/// *Only available if compiled with the feature `rayon`.* +pub struct ParColumnIterMut< + 'a, + T, + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, +> { + mat: &'a mut Matrix, +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *only available if compiled with the feature `rayon`* +impl<'a, T, R, Cols, S> ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, +{ + /// create a new parallel iterator for the given matrix. + fn new(mat: &'a mut Matrix) -> Self { + Self { mat } + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`* +impl<'a, T, R, Cols, S> ParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, + T: Send + Sync + Scalar, + S: Send + Sync, +{ + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: rayon::iter::plumbing::UnindexedConsumer, + { + bridge(self, consumer) + } + + fn opt_len(&self) -> Option { + Some(self.mat.ncols()) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *Only available if compiled with the feature `rayon`* +impl<'a, T, R, Cols, S> IndexedParallelIterator for ParColumnIterMut<'a, T, R, Cols, S> +where + R: Dim, + Cols: Dim, + S: RawStorage + RawStorageMut, + T: Send + Sync + Scalar, + S: Send + Sync, +{ + fn drive>(self, consumer: C) -> C::Result { + bridge(self, consumer) + } + + fn len(&self) -> usize { + self.mat.ncols() + } + + fn with_producer>( + self, + callback: CB, + ) -> CB::Output { + let producer = ColumnProducerMut(ColumnIterMut::new(self.mat)); + callback.callback(producer) + } +} + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// # Parallel iterators using `rayon` +/// *Only available if compiled with the feature `rayon`* +impl> Matrix +where + T: Send + Sync + Scalar, + S: Sync, +{ + /// Iterate through the columns of the matrix in parallel using rayon. + /// This iterates over *immutable* references to the columns of the matrix, + /// if *mutable* access to the columns is required, use [`par_column_iter_mut`] + /// instead. + /// + /// # Example + /// Using parallel column iterators to calculate the sum of the maximum + /// elements in each column: + /// ``` + /// use nalgebra::{dmatrix, DMatrix}; + /// use rayon::prelude::*; + /// + /// let matrix : DMatrix = dmatrix![1.0, 0.0, 5.0; + /// 2.0, 4.0, 1.0; + /// 3.0, 2.0, 2.0; + /// ]; + /// let sum_of_max :f64 = matrix + /// .par_column_iter() + /// .map(|col| col.max()) + /// .sum(); + /// + /// assert_eq!(sum_of_max,3.0 + 4.0 + 5.0); + /// + /// ``` + /// + /// [`par_column_iter_mut`]: crate::Matrix::par_column_iter_mut + pub fn par_column_iter(&self) -> ParColumnIter<'_, T, R, Cols, S> { + ParColumnIter::new(self) + } + + /// Mutably iterate through the columns of this matrix in parallel using rayon. + /// Allows mutable access to the columns in parallel using mutable references. + /// If mutable access to the columns is not required rather use [`par_column_iter`] + /// instead. + /// + /// # Example + /// Normalize each column of a matrix with respect to its own maximum value. + /// + /// ``` + /// use nalgebra::{dmatrix, DMatrix}; + /// use rayon::prelude::*; + /// + /// let mut matrix : DMatrix = dmatrix![ + /// 2.0, 4.0, 6.0; + /// 1.0, 2.0, 3.0; + /// ]; + /// matrix.par_column_iter_mut().for_each(|mut col| col /= col.max()); + /// + /// assert_eq!(matrix, dmatrix![1.0, 1.0, 1.0; 0.5, 0.5, 0.5]); + /// ``` + /// + /// [`par_column_iter`]: crate::Matrix::par_column_iter + pub fn par_column_iter_mut(&mut self) -> ParColumnIterMut<'_, T, R, Cols, S> + where + S: RawStorageMut, + { + ParColumnIterMut::new(self) + } +} + +/// A private helper newtype that wraps the `ColumnIter` and implements +/// the rayon `Producer` trait. It's just here so we don't have to make the +/// rayon trait part of the public interface of the `ColumnIter`. +struct ColumnProducer<'a, T, R: Dim, C: Dim, S: RawStorage>(ColumnIter<'a, T, R, C, S>); + +#[cfg_attr(doc_cfg, doc(cfg(feature = "rayon")))] +/// *only available if compiled with the feature `rayon`* +impl<'a, T, R: Dim, Cols: Dim, S: RawStorage> Producer + for ColumnProducer<'a, T, R, Cols, S> +where + T: Send + Sync + Scalar, + S: Sync, +{ + type Item = MatrixView<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIter<'a, T, R, Cols, S>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0 + } + + #[inline] + fn split_at(self, index: usize) -> (Self, Self) { + // The index is relative to the size of this current iterator. + // It will always start at zero so it serves as an offset. + let (left_iter, right_iter) = self.0.split_at(index); + (Self(left_iter), Self(right_iter)) + } +} + +/// See `ColumnProducer`. A private wrapper newtype that keeps the Producer +/// implementation private +struct ColumnProducerMut<'a, T, R: Dim, C: Dim, S: RawStorageMut>( + ColumnIterMut<'a, T, R, C, S>, +); + +impl<'a, T, R: Dim, C: Dim, S: 'a + RawStorageMut> Producer + for ColumnProducerMut<'a, T, R, C, S> +where + T: Send + Sync + Scalar, + S: Send + Sync, +{ + type Item = MatrixViewMut<'a, T, R, U1, S::RStride, S::CStride>; + type IntoIter = ColumnIterMut<'a, T, R, C, S>; + + fn into_iter(self) -> Self::IntoIter { + self.0 + } + + fn split_at(self, index: usize) -> (Self, Self) { + // The index is relative to the size of this current iterator + // it will always start at zero so it serves as an offset. + let (left_iter, right_iter) = self.0.split_at(index); + (Self(left_iter), Self(right_iter)) + } +} + +/// this implementation is safe because we are enforcing exclusive access +/// to the columns through the active range of the iterator +unsafe impl<'a, T: Scalar, R: Dim, C: Dim, S: 'a + RawStorageMut> Send + for ColumnIterMut<'a, T, R, C, S> +{ +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/properties.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/properties.rs new file mode 100644 index 000000000..eec132336 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/properties.rs @@ -0,0 +1,122 @@ +// Matrix properties checks. +use approx::RelativeEq; +use num::{One, Zero}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, ComplexField, RealField}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, DimMin}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, Matrix, SquareMatrix}; +use crate::RawStorage; + +impl> Matrix { + /// The total number of elements of this matrix. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert_eq!(mat.len(), 12); + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + let (nrows, ncols) = self.shape(); + nrows * ncols + } + + /// Returns true if the matrix contains no elements. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Matrix3x4; + /// let mat = Matrix3x4::::zeros(); + /// assert!(!mat.is_empty()); + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Indicates if this is a square matrix. + #[inline] + #[must_use] + pub fn is_square(&self) -> bool { + let (nrows, ncols) = self.shape(); + nrows == ncols + } + + // TODO: RelativeEq prevents us from using those methods on integer matrices… + /// Indicated if this is the identity matrix within a relative error of `eps`. + /// + /// If the matrix is diagonal, this checks that diagonal elements (i.e. at coordinates `(i, i)` + /// for i from `0` to `min(R, C)`) are equal one; and that all other elements are zero. + #[inline] + #[must_use] + pub fn is_identity(&self, eps: T::Epsilon) -> bool + where + T: Zero + One + RelativeEq, + T::Epsilon: Clone, + { + let (nrows, ncols) = self.shape(); + + for j in 0..ncols { + for i in 0..nrows { + let el = unsafe { self.get_unchecked((i, j)) }; + if (i == j && !relative_eq!(*el, T::one(), epsilon = eps.clone())) + || (i != j && !relative_eq!(*el, T::zero(), epsilon = eps.clone())) + { + return false; + } + } + } + + true + } +} + +impl> Matrix { + /// Checks that `Mᵀ × M = Id`. + /// + /// In this definition `Id` is approximately equal to the identity matrix with a relative error + /// equal to `eps`. + #[inline] + #[must_use] + pub fn is_orthogonal(&self, eps: T::Epsilon) -> bool + where + T: Zero + One + ClosedAddAssign + ClosedMulAssign + RelativeEq, + S: Storage, + T::Epsilon: Clone, + DefaultAllocator: Allocator + Allocator, + { + (self.ad_mul(self)).is_identity(eps) + } +} + +impl> SquareMatrix +where + DefaultAllocator: Allocator, +{ + /// Checks that this matrix is orthogonal and has a determinant equal to 1. + #[inline] + #[must_use] + pub fn is_special_orthogonal(&self, eps: T) -> bool + where + D: DimMin, + DefaultAllocator: Allocator, + { + self.is_square() && self.is_orthogonal(eps) && self.determinant() > T::zero() + } + + /// Returns `true` if this matrix is invertible. + #[inline] + #[must_use] + pub fn is_invertible(&self) -> bool { + // TODO: improve this? + self.clone_owned().try_inverse().is_some() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/rkyv_wrappers.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/rkyv_wrappers.rs new file mode 100644 index 000000000..27ec4d548 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/rkyv_wrappers.rs @@ -0,0 +1,46 @@ +//! Wrapper that allows changing the generic type of a PhantomData +//! +//! Copied from (MIT-Apache2 licences) which isn’t published yet. + +use rkyv::{ + with::{ArchiveWith, DeserializeWith, SerializeWith}, + Fallible, +}; +use std::marker::PhantomData; + +/// A wrapper that allows for changing the generic type of a `PhantomData`. +pub struct CustomPhantom { + _data: PhantomData<*const NT>, +} + +impl ArchiveWith> for CustomPhantom { + type Archived = PhantomData; + type Resolver = (); + + #[inline] + unsafe fn resolve_with( + _: &PhantomData, + _: usize, + _: Self::Resolver, + _: *mut Self::Archived, + ) { + } +} + +impl SerializeWith, S> + for CustomPhantom +{ + #[inline] + fn serialize_with(_: &PhantomData, _: &mut S) -> Result { + Ok(()) + } +} + +impl + DeserializeWith, PhantomData, D> for CustomPhantom +{ + #[inline] + fn deserialize_with(_: &PhantomData, _: &mut D) -> Result, D::Error> { + Ok(PhantomData) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/scalar.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/scalar.rs new file mode 100644 index 000000000..dfebe9bef --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/scalar.rs @@ -0,0 +1,8 @@ +use std::fmt::Debug; + +/// The basic scalar type for all structures of `nalgebra`. +/// +/// This does not make any assumption on the algebraic properties of `Self`. +pub trait Scalar: 'static + Clone + PartialEq + Debug {} + +impl Scalar for T {} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/statistics.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/statistics.rs new file mode 100644 index 000000000..46b980f8d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/statistics.rs @@ -0,0 +1,522 @@ +use crate::allocator::Allocator; +use crate::storage::RawStorage; +use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RowOVector, Scalar, VectorView, U1}; +use num::{One, Zero}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, Field, SupersetOf}; +use std::mem::MaybeUninit; + +/// # Folding on columns and rows +impl> Matrix { + /// Returns a row vector where each element is the result of the application of `f` on the + /// corresponding column of the original matrix. + #[inline] + #[must_use] + pub fn compress_rows( + &self, + f: impl Fn(VectorView<'_, T, R, S::RStride, S::CStride>) -> T, + ) -> RowOVector + where + DefaultAllocator: Allocator, + { + let ncols = self.shape_generic().1; + let mut res = Matrix::uninit(Const::<1>, ncols); + + for i in 0..ncols.value() { + // TODO: avoid bound checking of column. + // Safety: all indices are in range. + unsafe { + *res.get_unchecked_mut((0, i)) = MaybeUninit::new(f(self.column(i))); + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Returns a column vector where each element is the result of the application of `f` on the + /// corresponding column of the original matrix. + /// + /// This is the same as `self.compress_rows(f).transpose()`. + #[inline] + #[must_use] + pub fn compress_rows_tr( + &self, + f: impl Fn(VectorView<'_, T, R, S::RStride, S::CStride>) -> T, + ) -> OVector + where + DefaultAllocator: Allocator, + { + let ncols = self.shape_generic().1; + let mut res = Matrix::uninit(ncols, Const::<1>); + + for i in 0..ncols.value() { + // TODO: avoid bound checking of column. + // Safety: all indices are in range. + unsafe { + *res.vget_unchecked_mut(i) = MaybeUninit::new(f(self.column(i))); + } + } + + // Safety: res is now fully initialized. + unsafe { res.assume_init() } + } + + /// Returns a column vector resulting from the folding of `f` on each column of this matrix. + #[inline] + #[must_use] + pub fn compress_columns( + &self, + init: OVector, + f: impl Fn(&mut OVector, VectorView<'_, T, R, S::RStride, S::CStride>), + ) -> OVector + where + DefaultAllocator: Allocator, + { + let mut res = init; + + for i in 0..self.ncols() { + f(&mut res, self.column(i)) + } + + res + } +} + +/// # Common statistics operations +impl> Matrix { + /* + * + * Sum computation. + * + */ + /// The sum of all the elements of this matrix. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2x3; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.sum(), 21.0); + /// ``` + #[inline] + #[must_use] + pub fn sum(&self) -> T + where + T: ClosedAddAssign + Zero, + { + self.iter().cloned().fold(T::zero(), |a, b| a + b) + } + + /// The sum of all the rows of this matrix. + /// + /// Use `.row_sum_tr` if you need the result in a column vector instead. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Matrix3x2}; + /// # use nalgebra::{RowVector2, RowVector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_sum(), RowVector3::new(5.0, 7.0, 9.0)); + /// + /// let mint = Matrix3x2::new(1, 2, + /// 3, 4, + /// 5, 6); + /// assert_eq!(mint.row_sum(), RowVector2::new(9,12)); + /// ``` + #[inline] + #[must_use] + pub fn row_sum(&self) -> RowOVector + where + T: ClosedAddAssign + Zero, + DefaultAllocator: Allocator, + { + self.compress_rows(|col| col.sum()) + } + + /// The sum of all the rows of this matrix. The result is transposed and returned as a column vector. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Matrix3x2}; + /// # use nalgebra::{Vector2, Vector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_sum_tr(), Vector3::new(5.0, 7.0, 9.0)); + /// + /// let mint = Matrix3x2::new(1, 2, + /// 3, 4, + /// 5, 6); + /// assert_eq!(mint.row_sum_tr(), Vector2::new(9, 12)); + /// ``` + #[inline] + #[must_use] + pub fn row_sum_tr(&self) -> OVector + where + T: ClosedAddAssign + Zero, + DefaultAllocator: Allocator, + { + self.compress_rows_tr(|col| col.sum()) + } + + /// The sum of all the columns of this matrix. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Matrix3x2}; + /// # use nalgebra::{Vector2, Vector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.column_sum(), Vector2::new(6.0, 15.0)); + /// + /// let mint = Matrix3x2::new(1, 2, + /// 3, 4, + /// 5, 6); + /// assert_eq!(mint.column_sum(), Vector3::new(3, 7, 11)); + /// ``` + #[inline] + #[must_use] + pub fn column_sum(&self) -> OVector + where + T: ClosedAddAssign + Zero, + DefaultAllocator: Allocator, + { + let nrows = self.shape_generic().0; + self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| { + *out += col; + }) + } + + /* + * + * Product computation. + * + */ + /// The product of all the elements of this matrix. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2x3; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.product(), 720.0); + /// ``` + #[inline] + #[must_use] + pub fn product(&self) -> T + where + T: ClosedMulAssign + One, + { + self.iter().cloned().fold(T::one(), |a, b| a * b) + } + + /// The product of all the rows of this matrix. + /// + /// Use `.row_sum_tr` if you need the result in a column vector instead. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Matrix3x2}; + /// # use nalgebra::{RowVector2, RowVector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_product(), RowVector3::new(4.0, 10.0, 18.0)); + /// + /// let mint = Matrix3x2::new(1, 2, + /// 3, 4, + /// 5, 6); + /// assert_eq!(mint.row_product(), RowVector2::new(15, 48)); + /// ``` + #[inline] + #[must_use] + pub fn row_product(&self) -> RowOVector + where + T: ClosedMulAssign + One, + DefaultAllocator: Allocator, + { + self.compress_rows(|col| col.product()) + } + + /// The product of all the rows of this matrix. The result is transposed and returned as a column vector. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Matrix3x2}; + /// # use nalgebra::{Vector2, Vector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_product_tr(), Vector3::new(4.0, 10.0, 18.0)); + /// + /// let mint = Matrix3x2::new(1, 2, + /// 3, 4, + /// 5, 6); + /// assert_eq!(mint.row_product_tr(), Vector2::new(15, 48)); + /// ``` + #[inline] + #[must_use] + pub fn row_product_tr(&self) -> OVector + where + T: ClosedMulAssign + One, + DefaultAllocator: Allocator, + { + self.compress_rows_tr(|col| col.product()) + } + + /// The product of all the columns of this matrix. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Matrix3x2}; + /// # use nalgebra::{Vector2, Vector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.column_product(), Vector2::new(6.0, 120.0)); + /// + /// let mint = Matrix3x2::new(1, 2, + /// 3, 4, + /// 5, 6); + /// assert_eq!(mint.column_product(), Vector3::new(2, 12, 30)); + /// ``` + #[inline] + #[must_use] + pub fn column_product(&self) -> OVector + where + T: ClosedMulAssign + One, + DefaultAllocator: Allocator, + { + let nrows = self.shape_generic().0; + self.compress_columns( + OVector::repeat_generic(nrows, Const::<1>, T::one()), + |out, col| { + out.component_mul_assign(&col); + }, + ) + } + + /* + * + * Variance computation. + * + */ + /// The variance of all the elements of this matrix. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Matrix2x3; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_relative_eq!(m.variance(), 35.0 / 12.0, epsilon = 1.0e-8); + /// ``` + #[inline] + #[must_use] + pub fn variance(&self) -> T + where + T: Field + SupersetOf, + { + if self.is_empty() { + T::zero() + } else { + let n_elements: T = crate::convert(self.len() as f64); + let mean = self.mean(); + + self.iter().cloned().fold(T::zero(), |acc, x| { + acc + (x.clone() - mean.clone()) * (x - mean.clone()) + }) / n_elements + } + } + + /// The variance of all the rows of this matrix. + /// + /// Use `.row_variance_tr` if you need the result in a column vector instead. + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, RowVector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_variance(), RowVector3::new(2.25, 2.25, 2.25)); + /// ``` + #[inline] + #[must_use] + pub fn row_variance(&self) -> RowOVector + where + T: Field + SupersetOf, + DefaultAllocator: Allocator, + { + self.compress_rows(|col| col.variance()) + } + + /// The variance of all the rows of this matrix. The result is transposed and returned as a column vector. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_variance_tr(), Vector3::new(2.25, 2.25, 2.25)); + /// ``` + #[inline] + #[must_use] + pub fn row_variance_tr(&self) -> OVector + where + T: Field + SupersetOf, + DefaultAllocator: Allocator, + { + self.compress_rows_tr(|col| col.variance()) + } + + /// The variance of all the columns of this matrix. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix2x3, Vector2}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_relative_eq!(m.column_variance(), Vector2::new(2.0 / 3.0, 2.0 / 3.0), epsilon = 1.0e-8); + /// ``` + #[inline] + #[must_use] + pub fn column_variance(&self) -> OVector + where + T: Field + SupersetOf, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + + let mut mean = self.column_mean(); + mean.apply(|e| *e = -(e.clone() * e.clone())); + + let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64); + self.compress_columns(mean, |out, col| { + for i in 0..nrows.value() { + unsafe { + let val = col.vget_unchecked(i); + *out.vget_unchecked_mut(i) += denom.clone() * val.clone() * val.clone() + } + } + }) + } + + /* + * + * Mean computation. + * + */ + /// The mean of all the elements of this matrix. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2x3; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.mean(), 3.5); + /// ``` + #[inline] + #[must_use] + pub fn mean(&self) -> T + where + T: Field + SupersetOf, + { + if self.is_empty() { + T::zero() + } else { + self.sum() / crate::convert(self.len() as f64) + } + } + + /// The mean of all the rows of this matrix. + /// + /// Use `.row_mean_tr` if you need the result in a column vector instead. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, RowVector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_mean(), RowVector3::new(2.5, 3.5, 4.5)); + /// ``` + #[inline] + #[must_use] + pub fn row_mean(&self) -> RowOVector + where + T: Field + SupersetOf, + DefaultAllocator: Allocator, + { + self.compress_rows(|col| col.mean()) + } + + /// The mean of all the rows of this matrix. The result is transposed and returned as a column vector. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.row_mean_tr(), Vector3::new(2.5, 3.5, 4.5)); + /// ``` + #[inline] + #[must_use] + pub fn row_mean_tr(&self) -> OVector + where + T: Field + SupersetOf, + DefaultAllocator: Allocator, + { + self.compress_rows_tr(|col| col.mean()) + } + + /// The mean of all the columns of this matrix. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Matrix2x3, Vector2}; + /// + /// let m = Matrix2x3::new(1.0, 2.0, 3.0, + /// 4.0, 5.0, 6.0); + /// assert_eq!(m.column_mean(), Vector2::new(2.0, 5.0)); + /// ``` + #[inline] + #[must_use] + pub fn column_mean(&self) -> OVector + where + T: Field + SupersetOf, + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.shape_generic(); + let denom = T::one() / crate::convert::<_, T>(ncols.value() as f64); + self.compress_columns(OVector::zeros_generic(nrows, Const::<1>), |out, col| { + out.axpy(denom.clone(), &col, T::one()) + }) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/storage.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/storage.rs new file mode 100644 index 000000000..709deed05 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/storage.rs @@ -0,0 +1,302 @@ +//! Abstract definition of a matrix data storage. + +use std::ptr; + +use crate::base::allocator::{Allocator, SameShapeC, SameShapeR}; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Dim, U1}; +use crate::base::Scalar; + +/* + * Aliases for allocation results. + */ +/// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`. +pub type SameShapeStorage = + , SameShapeC>>::Buffer; + +// TODO: better name than Owned ? +/// The owned data storage that can be allocated from `S`. +pub type Owned = >::Buffer; + +/// The owned data storage that can be allocated from `S`. +pub type OwnedUninit = >::BufferUninit; + +/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`. +pub type RStride = + <>::Buffer as RawStorage>::RStride; + +/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`. +pub type CStride = + <>::Buffer as RawStorage>::CStride; + +/// The trait shared by all matrix data storage. +/// +/// TODO: doc +/// # Safety +/// +/// In generic code, it is recommended use the `Storage` trait bound instead. The `RawStorage` +/// trait bound is generally used by code that needs to work with storages that contains +/// `MaybeUninit` elements. +/// +/// Note that `Self` must always have a number of elements compatible with the matrix length (given +/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait +/// should **not** allow the user to modify the size of the underlying buffer with safe methods +/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the +/// vector's size so that it no longer contains enough elements: this will lead to UB. +pub unsafe trait RawStorage: Sized { + /// The static stride of this storage's rows. + type RStride: Dim; + + /// The static stride of this storage's columns. + type CStride: Dim; + + /// The matrix data pointer. + fn ptr(&self) -> *const T; + + /// The dimension of the matrix at run-time. Arr length of zero indicates the additive identity + /// element of any dimension. Must be equal to `Self::dimension()` if it is not `None`. + fn shape(&self) -> (R, C); + + /// The spacing between consecutive row elements and consecutive column elements. + /// + /// For example this returns `(1, 5)` for a column-major matrix with 5 columns. + fn strides(&self) -> (Self::RStride, Self::CStride); + + /// Compute the index corresponding to the irow-th row and icol-th column of this matrix. The + /// index must be such that the following holds: + /// + /// ```ignore + /// let lindex = self.linear_index(irow, icol); + /// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex)) + /// ``` + #[inline] + fn linear_index(&self, irow: usize, icol: usize) -> usize { + let (rstride, cstride) = self.strides(); + + irow * rstride.value() + icol * cstride.value() + } + + /// Gets the address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. + #[inline] + fn get_address_unchecked_linear(&self, i: usize) -> *const T { + self.ptr().wrapping_add(i) + } + + /// Gets the address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. + #[inline] + fn get_address_unchecked(&self, irow: usize, icol: usize) -> *const T { + self.get_address_unchecked_linear(self.linear_index(irow, icol)) + } + + /// Retrieves a reference to the i-th element without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. + #[inline] + unsafe fn get_unchecked_linear(&self, i: usize) -> &T { + &*self.get_address_unchecked_linear(i) + } + + /// Retrieves a reference to the i-th element without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. + #[inline] + unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &T { + self.get_unchecked_linear(self.linear_index(irow, icol)) + } + + /// Indicates whether this data buffer stores its elements contiguously. + /// + /// # Safety + /// This function must not return `true` if the underlying storage is not contiguous, + /// or undefined behaviour will occur. + fn is_contiguous(&self) -> bool; + + /// Retrieves the data buffer as a contiguous slice. + /// + /// # Safety + /// The matrix components may not be stored in a contiguous way, depending on the strides. + /// This method is unsafe because this can yield to invalid aliasing when called on some pairs + /// of matrix views originating from the same matrix with strides. + /// + /// Call the safe alternative `matrix.as_slice()` instead. + unsafe fn as_slice_unchecked(&self) -> &[T]; +} + +/// Trait shared by all matrix data storage that don’t contain any uninitialized elements. +/// +/// # Safety +/// +/// Note that `Self` must always have a number of elements compatible with the matrix length (given +/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait +/// should **not** allow the user to modify the size of the underlying buffer with safe methods +/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the +/// vector's size so that it no longer contains enough elements: this will lead to UB. +pub unsafe trait Storage: RawStorage { + /// Builds a matrix data storage that does not contain any reference. + fn into_owned(self) -> Owned + where + DefaultAllocator: Allocator; + + /// Clones this data storage to one that does not contain any reference. + fn clone_owned(&self) -> Owned + where + DefaultAllocator: Allocator; + + /// Drops the storage without calling the destructors on the contained elements. + fn forget_elements(self); +} + +/// Trait implemented by matrix data storage that can provide a mutable access to its elements. +/// +/// # Safety +/// +/// In generic code, it is recommended use the `StorageMut` trait bound instead. The +/// `RawStorageMut` trait bound is generally used by code that needs to work with storages that +/// contains `MaybeUninit` elements. +/// +/// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable +/// matrix view can provide mutable access to its elements even if it does not own its data (it +/// contains only an internal reference to them). +pub unsafe trait RawStorageMut: RawStorage { + /// The matrix mutable data pointer. + fn ptr_mut(&mut self) -> *mut T; + + /// Gets the mutable address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. + #[inline] + fn get_address_unchecked_linear_mut(&mut self, i: usize) -> *mut T { + self.ptr_mut().wrapping_add(i) + } + + /// Gets the mutable address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. + #[inline] + fn get_address_unchecked_mut(&mut self, irow: usize, icol: usize) -> *mut T { + let lid = self.linear_index(irow, icol); + self.get_address_unchecked_linear_mut(lid) + } + + /// Retrieves a mutable reference to the i-th element without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. + unsafe fn get_unchecked_linear_mut(&mut self, i: usize) -> &mut T { + &mut *self.get_address_unchecked_linear_mut(i) + } + + /// Retrieves a mutable reference to the element at `(irow, icol)` without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. + #[inline] + unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut T { + &mut *self.get_address_unchecked_mut(irow, icol) + } + + /// Swaps two elements using their linear index without bound-checking. + /// + /// # Safety + /// If the indices are out of bounds, the method will cause undefined behavior. + /// + /// # Validity + /// The default implementation of this trait function is only guaranteed to be + /// sound if invocations of `self.ptr_mut()` and `self.get_address_unchecked_linear_mut()` + /// result in stable references. If any of the data pointed to by these trait methods + /// moves as a consequence of invoking either of these methods then this default + /// trait implementation may be invalid or unsound and should be overridden. + #[inline] + unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) { + // we can't just use the pointers returned from `get_address_unchecked_linear_mut` because calling a + // method taking self mutably invalidates any existing (mutable) pointers. since `get_address_unchecked_linear_mut` can + // also be overriden by a custom implementation, we can't just use `wrapping_add` assuming that's what the method does. + // instead, we use `offset_from` to compute the re-calculate the pointers from the base pointer. + // this is sound as long as this trait matches the Validity preconditions + // (and it's the caller's responsibility to ensure the indices are in-bounds). + let base = self.ptr_mut(); + let offset1 = self.get_address_unchecked_linear_mut(i1).offset_from(base); + let offset2 = self.get_address_unchecked_linear_mut(i2).offset_from(base); + + let base = self.ptr_mut(); + let a = base.offset(offset1); + let b = base.offset(offset2); + + ptr::swap(a, b); + } + + /// Swaps two elements without bound-checking. + /// + /// # Safety + /// If the indices are out of bounds, the method will cause undefined behavior. + #[inline] + unsafe fn swap_unchecked(&mut self, row_col1: (usize, usize), row_col2: (usize, usize)) { + let lid1 = self.linear_index(row_col1.0, row_col1.1); + let lid2 = self.linear_index(row_col2.0, row_col2.1); + + self.swap_unchecked_linear(lid1, lid2) + } + + /// Retrieves the mutable data buffer as a contiguous slice. + /// + /// Matrix components may not be contiguous, depending on its strides. + /// + /// # Safety + /// The matrix components may not be stored in a contiguous way, depending on the strides. + /// This method is unsafe because this can yield to invalid aliasing when called on some pairs + /// of matrix slices originating from the same matrix with strides. + unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T]; +} + +/// Trait shared by all mutable matrix data storage that don’t contain any uninitialized elements. +/// +/// # Safety +/// +/// See safety note for `Storage`, `RawStorageMut`. +pub unsafe trait StorageMut: + Storage + RawStorageMut +{ +} + +unsafe impl StorageMut for S +where + R: Dim, + C: Dim, + S: Storage + RawStorageMut, +{ +} + +/// Marker trait indicating that a storage is stored contiguously in memory. +/// +/// # Safety +/// +/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value +/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because +/// failing to comply to this may cause Undefined Behaviors. +pub unsafe trait IsContiguous {} + +/// A matrix storage that can be reshaped in-place. +pub trait ReshapableStorage: RawStorage +where + T: Scalar, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, +{ + /// The reshaped storage type. + type Output: RawStorage; + + /// Reshapes the storage into the output storage type. + fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output; +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/swizzle.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/swizzle.rs new file mode 100644 index 000000000..95d739deb --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/swizzle.rs @@ -0,0 +1,66 @@ +use crate::base::{DimName, Scalar, ToTypenum, Vector, Vector2, Vector3}; +use crate::storage::RawStorage; +use typenum::{self, Cmp, Greater}; + +macro_rules! impl_swizzle { + ($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => { + $( + $( + /// Builds a new vector from components of `self`. + #[inline] + #[must_use] + pub fn $name(&self) -> $Result + where D::Typenum: Cmp { + $Result::new($(self[$i].clone()),*) + } + )* + )* + } +} + +/// # Swizzling +impl> Vector +where + D: DimName + ToTypenum, +{ + impl_swizzle!( + where U0: xx() -> Vector2[0, 0], + xxx() -> Vector3[0, 0, 0]; + + where U1: xy() -> Vector2[0, 1], + yx() -> Vector2[1, 0], + yy() -> Vector2[1, 1], + xxy() -> Vector3[0, 0, 1], + xyx() -> Vector3[0, 1, 0], + xyy() -> Vector3[0, 1, 1], + yxx() -> Vector3[1, 0, 0], + yxy() -> Vector3[1, 0, 1], + yyx() -> Vector3[1, 1, 0], + yyy() -> Vector3[1, 1, 1]; + + where U2: xz() -> Vector2[0, 2], + yz() -> Vector2[1, 2], + zx() -> Vector2[2, 0], + zy() -> Vector2[2, 1], + zz() -> Vector2[2, 2], + xxz() -> Vector3[0, 0, 2], + xyz() -> Vector3[0, 1, 2], + xzx() -> Vector3[0, 2, 0], + xzy() -> Vector3[0, 2, 1], + xzz() -> Vector3[0, 2, 2], + yxz() -> Vector3[1, 0, 2], + yyz() -> Vector3[1, 1, 2], + yzx() -> Vector3[1, 2, 0], + yzy() -> Vector3[1, 2, 1], + yzz() -> Vector3[1, 2, 2], + zxx() -> Vector3[2, 0, 0], + zxy() -> Vector3[2, 0, 1], + zxz() -> Vector3[2, 0, 2], + zyx() -> Vector3[2, 1, 0], + zyy() -> Vector3[2, 1, 1], + zyz() -> Vector3[2, 1, 2], + zzx() -> Vector3[2, 2, 0], + zzy() -> Vector3[2, 2, 1], + zzz() -> Vector3[2, 2, 2]; + ); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/uninit.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/uninit.rs new file mode 100644 index 000000000..795cd890f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/uninit.rs @@ -0,0 +1,76 @@ +use std::mem::MaybeUninit; + +/// This trait is used to write code that may work on matrices that may or may not +/// be initialized. +/// +/// This trait is used to describe how a value must be accessed to initialize it or +/// to retrieve a reference or mutable reference. Typically, a function accepting +/// both initialized and uninitialized inputs should have a `Status: InitStatus` +/// type parameter. Then the methods of the `Status` can be used to access the element. +/// +/// # Safety +/// This trait must not be implemented outside of this crate. +pub unsafe trait InitStatus: Copy { + /// The type of the values with the initialization status described by `Self`. + type Value; + + /// Initialize the given element. + fn init(out: &mut Self::Value, t: T); + + /// Retrieve a reference to the element, assuming that it is initialized. + /// + /// # Safety + /// This is unsound if the referenced value isn’t initialized. + unsafe fn assume_init_ref(t: &Self::Value) -> &T; + + /// Retrieve a mutable reference to the element, assuming that it is initialized. + /// + /// # Safety + /// This is unsound if the referenced value isn’t initialized. + unsafe fn assume_init_mut(t: &mut Self::Value) -> &mut T; +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// A type implementing `InitStatus` indicating that the value is completely initialized. +pub struct Init; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// A type implementing `InitStatus` indicating that the value is completely uninitialized. +pub struct Uninit; + +unsafe impl InitStatus for Init { + type Value = T; + + #[inline(always)] + fn init(out: &mut T, t: T) { + *out = t; + } + + #[inline(always)] + unsafe fn assume_init_ref(t: &T) -> &T { + t + } + + #[inline(always)] + unsafe fn assume_init_mut(t: &mut T) -> &mut T { + t + } +} + +unsafe impl InitStatus for Uninit { + type Value = MaybeUninit; + + #[inline(always)] + fn init(out: &mut MaybeUninit, t: T) { + *out = MaybeUninit::new(t); + } + + #[inline(always)] + unsafe fn assume_init_ref(t: &MaybeUninit) -> &T { + &*t.as_ptr() // TODO: use t.assume_init_ref() + } + + #[inline(always)] + unsafe fn assume_init_mut(t: &mut MaybeUninit) -> &mut T { + &mut *t.as_mut_ptr() // TODO: use t.assume_init_mut() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/unit.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/unit.rs new file mode 100644 index 000000000..97f94b71f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/unit.rs @@ -0,0 +1,385 @@ +use std::fmt; +use std::ops::Deref; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::allocator::Allocator; +use crate::base::DefaultAllocator; +use crate::storage::RawStorage; +use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealField}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A wrapper that ensures the underlying algebraic entity has a unit norm. +/// +/// **It is likely that the only piece of documentation that you need in this page are:** +/// - **[The construction with normalization](#construction-with-normalization)** +/// - **[Data extraction and construction without normalization](#data-extraction-and-construction-without-normalization)** +/// - **[Interpolation between two unit vectors](#interpolation-between-two-unit-vectors)** +/// +/// All the other impl blocks you will see in this page are about [`UnitComplex`](crate::UnitComplex) +/// and [`UnitQuaternion`](crate::UnitQuaternion); both built on top of `Unit`. If you are interested +/// in their documentation, read their dedicated pages directly. +#[repr(transparent)] +#[derive(Clone, Hash, Copy)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Unit", + bound(archive = " + T: rkyv::Archive, + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +pub struct Unit { + pub(crate) value: T, +} + +impl fmt::Debug for Unit { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.value.fmt(formatter) + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Unit where T: bytemuck::Zeroable {} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Unit where T: bytemuck::Pod {} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Unit { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.value.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'de, T: Deserialize<'de>> Deserialize<'de> for Unit { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(|x| Unit { value: x }) + } +} + +impl PartialEq for Unit> +where + T: Scalar + PartialEq, + R: Dim, + C: Dim, + S: RawStorage, +{ + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.value.eq(&rhs.value) + } +} + +impl Eq for Unit> +where + T: Scalar + Eq, + R: Dim, + C: Dim, + S: RawStorage, +{ +} + +/// Trait implemented by entities scan be be normalized and put in an `Unit` struct. +pub trait Normed { + /// The type of the norm. + type Norm: SimdRealField; + /// Computes the norm. + fn norm(&self) -> Self::Norm; + /// Computes the squared norm. + fn norm_squared(&self) -> Self::Norm; + /// Multiply `self` by n. + fn scale_mut(&mut self, n: Self::Norm); + /// Divides `self` by n. + fn unscale_mut(&mut self, n: Self::Norm); +} + +/// # Construction with normalization +impl Unit { + /// Normalize the given vector and return it wrapped on a `Unit` structure. + #[inline] + pub fn new_normalize(value: T) -> Self { + Self::new_and_get(value).0 + } + + /// Attempts to normalize the given vector and return it wrapped on a `Unit` structure. + /// + /// Returns `None` if the norm was smaller or equal to `min_norm`. + #[inline] + pub fn try_new(value: T, min_norm: T::Norm) -> Option + where + T::Norm: RealField, + { + Self::try_new_and_get(value, min_norm).map(|res| res.0) + } + + /// Normalize the given vector and return it wrapped on a `Unit` structure and its norm. + #[inline] + pub fn new_and_get(mut value: T) -> (Self, T::Norm) { + let n = value.norm(); + value.unscale_mut(n.clone()); + (Unit { value }, n) + } + + /// Normalize the given vector and return it wrapped on a `Unit` structure and its norm. + /// + /// Returns `None` if the norm was smaller or equal to `min_norm`. + #[inline] + pub fn try_new_and_get(mut value: T, min_norm: T::Norm) -> Option<(Self, T::Norm)> + where + T::Norm: RealField, + { + let sq_norm = value.norm_squared(); + + if sq_norm > min_norm.clone() * min_norm { + let n = sq_norm.simd_sqrt(); + value.unscale_mut(n.clone()); + Some((Unit { value }, n)) + } else { + None + } + } + + /// Normalizes this vector again. This is useful when repeated computations + /// might cause a drift in the norm because of float inaccuracies. + /// + /// Returns the norm before re-normalization. See `.renormalize_fast` for a faster alternative + /// that may be slightly less accurate if `self` drifted significantly from having a unit length. + #[inline] + pub fn renormalize(&mut self) -> T::Norm { + let n = self.norm(); + self.value.unscale_mut(n.clone()); + n + } + + /// Normalizes this vector again using a first-order Taylor approximation. + /// This is useful when repeated computations might cause a drift in the norm + /// because of float inaccuracies. + #[inline] + pub fn renormalize_fast(&mut self) { + let sq_norm = self.value.norm_squared(); + let three: T::Norm = crate::convert(3.0); + let half: T::Norm = crate::convert(0.5); + self.value.scale_mut(half * (three - sq_norm)); + } +} + +/// # Data extraction and construction without normalization +impl Unit { + /// Wraps the given value, assuming it is already normalized. + #[inline] + pub const fn new_unchecked(value: T) -> Self { + Unit { value } + } + + /// Wraps the given reference, assuming it is already normalized. + #[inline] + pub fn from_ref_unchecked(value: &T) -> &Self { + unsafe { &*(value as *const T as *const Self) } + } + + /// Retrieves the underlying value. + #[inline] + pub fn into_inner(self) -> T { + self.value + } + + /// Retrieves the underlying value. + /// Deprecated: use [`Unit::into_inner`] instead. + #[deprecated(note = "use `.into_inner()` instead")] + #[inline] + pub fn unwrap(self) -> T { + self.value + } + + /// Returns a mutable reference to the underlying value. This is `_unchecked` because modifying + /// the underlying value in such a way that it no longer has unit length may lead to unexpected + /// results. + #[inline] + pub fn as_mut_unchecked(&mut self) -> &mut T { + &mut self.value + } +} + +impl AsRef for Unit { + #[inline] + fn as_ref(&self) -> &T { + &self.value + } +} + +/* +/* + * + * Conversions. + * + */ +impl SubsetOf for Unit +where T::RealField: RelativeEq +{ + #[inline] + fn to_superset(&self) -> T { + self.clone().into_inner() + } + + #[inline] + fn is_in_subset(value: &T) -> bool { + relative_eq!(value.norm_squared(), crate::one()) + } + + #[inline] + fn from_superset_unchecked(value: &T) -> Self { + Unit::new_normalize(value.clone()) // We still need to re-normalize because the condition is inexact. + } +} + +// impl RelativeEq for Unit { +// type Epsilon = T::Epsilon; +// +// #[inline] +// fn default_epsilon() -> Self::Epsilon { +// T::default_epsilon() +// } +// +// #[inline] +// fn default_max_relative() -> Self::Epsilon { +// T::default_max_relative() +// } +// +// #[inline] +// fn default_max_ulps() -> u32 { +// T::default_max_ulps() +// } +// +// #[inline] +// fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool { +// self.value.relative_eq(&other.value, epsilon, max_relative) +// } +// +// #[inline] +// fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { +// self.value.ulps_eq(&other.value, epsilon, max_ulps) +// } +// } +*/ +// TODO:re-enable this impl when specialization is possible. +// Currently, it is disabled so that we can have a nice output for the `UnitQuaternion` display. +/* +impl fmt::Display for Unit { + // XXX: will not always work correctly due to rounding errors. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.value.fmt(f) + } +} +*/ + +impl Deref for Unit { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { &*(self as *const Self as *const T) } + } +} + +// NOTE: we can't use a generic implementation for `Unit` because +// num_complex::Complex does not implement `From[Complex<...>...]` (and can't +// because of the orphan rules). +impl + From<[Unit>; 2]> for Unit> +where + T: From<[::Element; 2]>, + T::Element: Scalar, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [Unit>; 2]) -> Self { + Self::new_unchecked(OMatrix::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + ])) + } +} + +impl + From<[Unit>; 4]> for Unit> +where + T: From<[::Element; 4]>, + T::Element: Scalar, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [Unit>; 4]) -> Self { + Self::new_unchecked(OMatrix::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + ])) + } +} + +impl + From<[Unit>; 8]> for Unit> +where + T: From<[::Element; 8]>, + T::Element: Scalar, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [Unit>; 8]) -> Self { + Self::new_unchecked(OMatrix::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + arr[4].clone().into_inner(), + arr[5].clone().into_inner(), + arr[6].clone().into_inner(), + arr[7].clone().into_inner(), + ])) + } +} + +impl + From<[Unit>; 16]> for Unit> +where + T: From<[::Element; 16]>, + T::Element: Scalar, + DefaultAllocator: Allocator, +{ + #[inline] + fn from(arr: [Unit>; 16]) -> Self { + Self::new_unchecked(OMatrix::from([ + arr[0].clone().into_inner(), + arr[1].clone().into_inner(), + arr[2].clone().into_inner(), + arr[3].clone().into_inner(), + arr[4].clone().into_inner(), + arr[5].clone().into_inner(), + arr[6].clone().into_inner(), + arr[7].clone().into_inner(), + arr[8].clone().into_inner(), + arr[9].clone().into_inner(), + arr[10].clone().into_inner(), + arr[11].clone().into_inner(), + arr[12].clone().into_inner(), + arr[13].clone().into_inner(), + arr[14].clone().into_inner(), + arr[15].clone().into_inner(), + ])) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/base/vec_storage.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/vec_storage.rs new file mode 100644 index 000000000..242d38c35 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/base/vec_storage.rs @@ -0,0 +1,526 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + +use crate::base::allocator::Allocator; +use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Dim, DimName, Dyn, U1}; +use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, ReshapableStorage}; +use crate::base::{Scalar, Vector}; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{ + de::{Deserialize, Deserializer, Error}, + ser::{Serialize, Serializer}, +}; + +use crate::Storage; +use std::mem::MaybeUninit; + +/* + * + * RawStorage. + * + */ +/// A Vec-based matrix data storage. It may be dynamically-sized. +#[repr(C)] +#[derive(Eq, Debug, Clone, PartialEq)] +pub struct VecStorage { + data: Vec, + nrows: R, + ncols: C, +} + +impl Default for VecStorage { + fn default() -> Self { + Self { + data: Vec::new(), + nrows: Dyn::from_usize(0), + ncols: Dyn::from_usize(0), + } + } +} + +impl Default for VecStorage { + fn default() -> Self { + Self { + data: Vec::new(), + nrows: R::name(), + ncols: Dyn::from_usize(0), + } + } +} + +impl Default for VecStorage { + fn default() -> Self { + Self { + data: Vec::new(), + nrows: Dyn::from_usize(0), + ncols: C::name(), + } + } +} + +impl Default for VecStorage { + fn default() -> Self { + let nrows = R::name(); + let ncols = C::name(); + let mut data = Vec::new(); + data.resize_with(nrows.value() * ncols.value(), Default::default); + Self { data, nrows, ncols } + } +} + +#[cfg(feature = "serde-serialize")] +impl Serialize for VecStorage +where + T: Serialize, + R: Serialize, + C: Serialize, +{ + fn serialize(&self, serializer: Ser) -> Result + where + Ser: Serializer, + { + (&self.data, &self.nrows, &self.ncols).serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize")] +impl<'a, T, R: Dim, C: Dim> Deserialize<'a> for VecStorage +where + T: Deserialize<'a>, + R: Deserialize<'a>, + C: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let (data, nrows, ncols): (Vec, R, C) = Deserialize::deserialize(deserializer)?; + + // SAFETY: make sure the data we deserialize have the + // correct number of elements. + if nrows.value() * ncols.value() != data.len() { + return Err(Des::Error::custom(format!( + "Expected {} components, found {}", + nrows.value() * ncols.value(), + data.len() + ))); + } + + Ok(Self { data, nrows, ncols }) + } +} + +#[deprecated(note = "renamed to `VecStorage`")] +/// Renamed to [`VecStorage`]. +pub type MatrixVec = VecStorage; + +impl VecStorage { + /// Creates a new dynamic matrix data storage from the given vector and shape. + #[inline] + pub fn new(nrows: R, ncols: C, data: Vec) -> Self { + assert!( + nrows.value() * ncols.value() == data.len(), + "Data storage buffer dimension mismatch." + ); + Self { data, nrows, ncols } + } + + /// The underlying data storage. + #[inline] + #[must_use] + pub fn as_vec(&self) -> &Vec { + &self.data + } + + /// The underlying mutable data storage. + /// + /// # Safety + /// This is unsafe because this may cause UB if the size of the vector is changed + /// by the user. + #[inline] + pub unsafe fn as_vec_mut(&mut self) -> &mut Vec { + &mut self.data + } + + /// Resizes the underlying mutable data storage and unwraps it. + /// + /// # Safety + /// - If `sz` is larger than the current size, additional elements are uninitialized. + /// - If `sz` is smaller than the current size, additional elements are truncated but **not** dropped. + /// It is the responsibility of the caller of this method to drop these elements. + #[inline] + pub unsafe fn resize(mut self, sz: usize) -> Vec> { + let len = self.len(); + + let new_data = if sz < len { + // Use `set_len` instead of `truncate` because we don’t want to + // drop the removed elements (it’s the caller’s responsibility). + self.data.set_len(sz); + self.data.shrink_to_fit(); + + // Safety: + // - MaybeUninit has the same alignment and layout as T. + // - The length and capacity come from a valid vector. + Vec::from_raw_parts( + self.data.as_mut_ptr() as *mut MaybeUninit, + self.data.len(), + self.data.capacity(), + ) + } else { + self.data.reserve_exact(sz - len); + + // Safety: + // - MaybeUninit has the same alignment and layout as T. + // - The length and capacity come from a valid vector. + let mut new_data = Vec::from_raw_parts( + self.data.as_mut_ptr() as *mut MaybeUninit, + self.data.len(), + self.data.capacity(), + ); + + // Safety: we can set the length here because MaybeUninit is always assumed + // to be initialized. + new_data.set_len(sz); + new_data + }; + + // Avoid double-free by forgetting `self` because its data buffer has + // been transferred to `new_data`. + std::mem::forget(self); + new_data + } + + /// The number of elements on the underlying vector. + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.data.len() + } + + /// Returns true if the underlying vector contains no elements. + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// A slice containing all the components stored in this storage in column-major order. + #[inline] + pub fn as_slice(&self) -> &[T] { + &self.data[..] + } + + /// A mutable slice containing all the components stored in this storage in column-major order. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + &mut self.data[..] + } +} + +impl From> for Vec { + fn from(vec: VecStorage) -> Self { + vec.data + } +} + +/* + * + * Dyn − Static + * Dyn − Dyn + * + */ +unsafe impl RawStorage for VecStorage { + type RStride = U1; + type CStride = Dyn; + + #[inline] + fn ptr(&self) -> *const T { + self.data.as_ptr() + } + + #[inline] + fn shape(&self) -> (Dyn, C) { + (self.nrows, self.ncols) + } + + #[inline] + fn strides(&self) -> (Self::RStride, Self::CStride) { + (Self::RStride::name(), self.nrows) + } + + #[inline] + fn is_contiguous(&self) -> bool { + true + } + + #[inline] + unsafe fn as_slice_unchecked(&self) -> &[T] { + &self.data + } +} + +unsafe impl Storage for VecStorage +where + DefaultAllocator: Allocator = Self>, +{ + #[inline] + fn into_owned(self) -> Owned + where + DefaultAllocator: Allocator, + { + self + } + + #[inline] + fn clone_owned(&self) -> Owned + where + DefaultAllocator: Allocator, + { + self.clone() + } + + #[inline] + fn forget_elements(mut self) { + // SAFETY: setting the length to zero is always sound, as it does not + // cause any memory to be deemed initialized. If the previous length was + // non-zero, it is equivalent to using mem::forget to leak each element. + // Then, when this function returns, self.data is dropped, freeing the + // allocated memory, but the elements are not dropped because they are + // now considered uninitialized. + unsafe { self.data.set_len(0) }; + } +} + +unsafe impl RawStorage for VecStorage { + type RStride = U1; + type CStride = R; + + #[inline] + fn ptr(&self) -> *const T { + self.data.as_ptr() + } + + #[inline] + fn shape(&self) -> (R, Dyn) { + (self.nrows, self.ncols) + } + + #[inline] + fn strides(&self) -> (Self::RStride, Self::CStride) { + (Self::RStride::name(), self.nrows) + } + + #[inline] + fn is_contiguous(&self) -> bool { + true + } + + #[inline] + unsafe fn as_slice_unchecked(&self) -> &[T] { + &self.data + } +} + +unsafe impl Storage for VecStorage +where + DefaultAllocator: Allocator = Self>, +{ + #[inline] + fn into_owned(self) -> Owned + where + DefaultAllocator: Allocator, + { + self + } + + #[inline] + fn clone_owned(&self) -> Owned + where + DefaultAllocator: Allocator, + { + self.clone() + } + + #[inline] + fn forget_elements(mut self) { + // SAFETY: setting the length to zero is always sound, as it does not + // cause any memory to be deemed initialized. If the previous length was + // non-zero, it is equivalent to using mem::forget to leak each element. + // Then, when this function returns, self.data is dropped, freeing the + // allocated memory, but the elements are not dropped because they are + // now considered uninitialized. + unsafe { self.data.set_len(0) }; + } +} + +/* + * + * RawStorageMut, ContiguousStorage. + * + */ +unsafe impl RawStorageMut for VecStorage { + #[inline] + fn ptr_mut(&mut self) -> *mut T { + self.data.as_mut_ptr() + } + + #[inline] + unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] { + &mut self.data[..] + } +} + +unsafe impl IsContiguous for VecStorage {} + +impl ReshapableStorage for VecStorage +where + T: Scalar, + C1: Dim, + C2: Dim, +{ + type Output = VecStorage; + + fn reshape_generic(self, nrows: Dyn, ncols: C2) -> Self::Output { + assert_eq!(nrows.value() * ncols.value(), self.data.len()); + VecStorage { + data: self.data, + nrows, + ncols, + } + } +} + +impl ReshapableStorage for VecStorage +where + T: Scalar, + C1: Dim, + R2: DimName, +{ + type Output = VecStorage; + + fn reshape_generic(self, nrows: R2, ncols: Dyn) -> Self::Output { + assert_eq!(nrows.value() * ncols.value(), self.data.len()); + VecStorage { + data: self.data, + nrows, + ncols, + } + } +} + +unsafe impl RawStorageMut for VecStorage { + #[inline] + fn ptr_mut(&mut self) -> *mut T { + self.data.as_mut_ptr() + } + + #[inline] + unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] { + &mut self.data[..] + } +} + +impl ReshapableStorage for VecStorage +where + T: Scalar, + R1: DimName, + C2: Dim, +{ + type Output = VecStorage; + + fn reshape_generic(self, nrows: Dyn, ncols: C2) -> Self::Output { + assert_eq!(nrows.value() * ncols.value(), self.data.len()); + VecStorage { + data: self.data, + nrows, + ncols, + } + } +} + +impl ReshapableStorage for VecStorage +where + T: Scalar, + R1: DimName, + R2: DimName, +{ + type Output = VecStorage; + + fn reshape_generic(self, nrows: R2, ncols: Dyn) -> Self::Output { + assert_eq!(nrows.value() * ncols.value(), self.data.len()); + VecStorage { + data: self.data, + nrows, + ncols, + } + } +} + +impl Extend for VecStorage { + /// Extends the number of columns of the `VecStorage` with elements + /// from the given iterator. + /// + /// # Panics + /// This function panics if the number of elements yielded by the + /// given iterator is not a multiple of the number of rows of the + /// `VecStorage`. + fn extend>(&mut self, iter: I) { + self.data.extend(iter); + self.ncols = Dyn(self.data.len() / self.nrows.value()); + assert!(self.data.len() % self.nrows.value() == 0, + "The number of elements produced by the given iterator was not a multiple of the number of rows."); + } +} + +impl<'a, T: 'a + Copy, R: Dim> Extend<&'a T> for VecStorage { + /// Extends the number of columns of the `VecStorage` with elements + /// from the given iterator. + /// + /// # Panics + /// This function panics if the number of elements yielded by the + /// given iterator is not a multiple of the number of rows of the + /// `VecStorage`. + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().copied()) + } +} + +impl Extend> for VecStorage +where + T: Scalar, + R: Dim, + RV: Dim, + SV: RawStorage, + ShapeConstraint: SameNumberOfRows, +{ + /// Extends the number of columns of the `VecStorage` with vectors + /// from the given iterator. + /// + /// # Panics + /// This function panics if the number of rows of each `Vector` + /// yielded by the iterator is not equal to the number of rows + /// of this `VecStorage`. + fn extend>>(&mut self, iter: I) { + let nrows = self.nrows.value(); + let iter = iter.into_iter(); + let (lower, _upper) = iter.size_hint(); + self.data.reserve(nrows * lower); + for vector in iter { + assert_eq!(nrows, vector.shape().0); + self.data.extend(vector.iter().cloned()); + } + self.ncols = Dyn(self.data.len() / nrows); + } +} + +impl Extend for VecStorage { + /// Extends the number of rows of the `VecStorage` with elements + /// from the given iterator. + fn extend>(&mut self, iter: I) { + self.data.extend(iter); + self.nrows = Dyn(self.data.len()); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/mod.rs new file mode 100644 index 000000000..1e3b5fd31 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/mod.rs @@ -0,0 +1,7 @@ +//! Various tools useful for testing/debugging/benchmarking. + +mod random_orthogonal; +mod random_sdp; + +pub use self::random_orthogonal::*; +pub use self::random_sdp::*; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_orthogonal.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_orthogonal.rs new file mode 100644 index 000000000..9fcfec752 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_orthogonal.rs @@ -0,0 +1,55 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, Dyn}; +use crate::base::Scalar; +use crate::base::{DefaultAllocator, OMatrix}; +use crate::linalg::givens::GivensRotation; +use simba::scalar::ComplexField; + +/// A random orthogonal matrix. +#[derive(Clone, Debug)] +pub struct RandomOrthogonal +where + DefaultAllocator: Allocator, +{ + m: OMatrix, +} + +impl RandomOrthogonal +where + DefaultAllocator: Allocator, +{ + /// Retrieve the generated matrix. + pub fn unwrap(self) -> OMatrix { + self.m + } + + /// Creates a new random orthogonal matrix from its dimension and a random reals generators. + pub fn new T>(dim: D, mut rand: Rand) -> Self { + let mut res = OMatrix::identity_generic(dim, dim); + + // Create an orthogonal matrix by composing random Givens rotations rotations. + for i in 0..dim.value() - 1 { + let rot = GivensRotation::new(rand(), rand()).0; + rot.rotate(&mut res.fixed_rows_mut::<2>(i)); + } + + RandomOrthogonal { m: res } + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for RandomOrthogonal +where + DefaultAllocator: Allocator, + Owned: Clone + Send, +{ + fn arbitrary(g: &mut Gen) -> Self { + let dim = D::try_to_usize().unwrap_or(1 + usize::arbitrary(g) % 50); + Self::new(D::from_usize(dim), || T::arbitrary(g)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_sdp.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_sdp.rs new file mode 100644 index 000000000..bca4153d0 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/debug/random_sdp.rs @@ -0,0 +1,58 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, Dyn}; +use crate::base::Scalar; +use crate::base::{DefaultAllocator, OMatrix}; +use simba::scalar::ComplexField; + +use crate::debug::RandomOrthogonal; + +/// A random, well-conditioned, symmetric definite-positive matrix. +#[derive(Clone, Debug)] +pub struct RandomSDP +where + DefaultAllocator: Allocator, +{ + m: OMatrix, +} + +impl RandomSDP +where + DefaultAllocator: Allocator, +{ + /// Retrieve the generated matrix. + pub fn unwrap(self) -> OMatrix { + self.m + } + + /// Creates a new well conditioned symmetric definite-positive matrix from its dimension and a + /// random reals generators. + pub fn new T>(dim: D, mut rand: Rand) -> Self { + let mut m = RandomOrthogonal::new(dim, || rand()).unwrap(); + let mt = m.adjoint(); + + for i in 0..dim.value() { + let mut col = m.column_mut(i); + let eigenval = T::one() + T::from_real(rand().modulus()); + col *= eigenval; + } + + RandomSDP { m: m * mt } + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for RandomSDP +where + DefaultAllocator: Allocator, + Owned: Clone + Send, +{ + fn arbitrary(g: &mut Gen) -> Self { + let dim = D::try_to_usize().unwrap_or(1 + usize::arbitrary(g) % 50); + Self::new(D::from_usize(dim), || T::arbitrary(g)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/abstract_rotation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/abstract_rotation.rs new file mode 100644 index 000000000..642661f40 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/abstract_rotation.rs @@ -0,0 +1,151 @@ +use crate::geometry::{Rotation, UnitComplex, UnitQuaternion}; +use crate::{Const, OVector, Point, SVector, Scalar, SimdRealField, Unit}; + +use simba::scalar::ClosedMulAssign; + +/// Trait implemented by rotations that can be used inside of an `Isometry` or `Similarity`. +pub trait AbstractRotation: PartialEq + ClosedMulAssign + Clone { + /// The rotation identity. + fn identity() -> Self; + /// The rotation inverse. + fn inverse(&self) -> Self; + /// Change `self` to its inverse. + fn inverse_mut(&mut self); + /// Apply the rotation to the given vector. + fn transform_vector(&self, v: &SVector) -> SVector; + /// Apply the rotation to the given point. + fn transform_point(&self, p: &Point) -> Point; + /// Apply the inverse rotation to the given vector. + fn inverse_transform_vector(&self, v: &OVector>) -> OVector>; + /// Apply the inverse rotation to the given unit vector. + fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + Unit::new_unchecked(self.inverse_transform_vector(&**v)) + } + /// Apply the inverse rotation to the given point. + fn inverse_transform_point(&self, p: &Point) -> Point; +} + +impl AbstractRotation for Rotation +where + T::Element: SimdRealField, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } + + #[inline] + fn inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn inverse_mut(&mut self) { + self.inverse_mut() + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } + + #[inline] + fn transform_point(&self, p: &Point) -> Point { + self * p + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } + + #[inline] + fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + self.inverse_transform_unit_vector(v) + } + + #[inline] + fn inverse_transform_point(&self, p: &Point) -> Point { + self.inverse_transform_point(p) + } +} + +impl AbstractRotation for UnitQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } + + #[inline] + fn inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn inverse_mut(&mut self) { + self.inverse_mut() + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } + + #[inline] + fn transform_point(&self, p: &Point) -> Point { + self * p + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } + + #[inline] + fn inverse_transform_point(&self, p: &Point) -> Point { + self.inverse_transform_point(p) + } +} + +impl AbstractRotation for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } + + #[inline] + fn inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn inverse_mut(&mut self) { + self.inverse_mut() + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } + + #[inline] + fn transform_point(&self, p: &Point) -> Point { + self * p + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } + + #[inline] + fn inverse_transform_point(&self, p: &Point) -> Point { + self.inverse_transform_point(p) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion.rs new file mode 100644 index 000000000..0f531c942 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion.rs @@ -0,0 +1,1028 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +use crate::{ + Isometry3, Matrix4, Normed, OVector, Point3, Quaternion, Scalar, SimdRealField, Translation3, + Unit, UnitQuaternion, Vector3, Zero, U8, +}; +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; + +use simba::scalar::{ClosedNeg, RealField}; + +/// A dual quaternion. +/// +/// # Indexing +/// +/// `DualQuaternions` are stored as \[..real, ..dual\]. +/// Both of the quaternion components are laid out in `i, j, k, w` order. +/// +/// # Example +/// ``` +/// # use nalgebra::{DualQuaternion, Quaternion}; +/// +/// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); +/// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); +/// +/// let dq = DualQuaternion::from_real_and_dual(real, dual); +/// assert_eq!(dq[0], 2.0); +/// assert_eq!(dq[1], 3.0); +/// +/// assert_eq!(dq[4], 6.0); +/// assert_eq!(dq[7], 5.0); +/// ``` +/// +/// NOTE: +/// As of December 2020, dual quaternion support is a work in progress. +/// If a feature that you need is missing, feel free to open an issue or a PR. +/// See +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "DualQuaternion", + bound(archive = " + T: rkyv::Archive, + Quaternion: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +pub struct DualQuaternion { + /// The real component of the quaternion + pub real: Quaternion, + /// The dual component of the quaternion + pub dual: Quaternion, +} + +impl Eq for DualQuaternion {} + +impl PartialEq for DualQuaternion { + #[inline] + fn eq(&self, right: &Self) -> bool { + self.real == right.real && self.dual == right.dual + } +} + +impl Default for DualQuaternion { + fn default() -> Self { + Self { + real: Quaternion::default(), + dual: Quaternion::default(), + } + } +} + +impl DualQuaternion +where + T::Element: SimdRealField, +{ + /// Normalizes this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let dq = DualQuaternion::from_real_and_dual(real, dual); + /// + /// let dq_normalized = dq.normalize(); + /// + /// assert_relative_eq!(dq_normalized.real.norm(), 1.0); + /// ``` + #[inline] + #[must_use = "Did you mean to use normalize_mut()?"] + pub fn normalize(&self) -> Self { + let real_norm = self.real.norm(); + + Self::from_real_and_dual( + self.real.clone() / real_norm.clone(), + self.dual.clone() / real_norm, + ) + } + + /// Normalizes this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let mut dq = DualQuaternion::from_real_and_dual(real, dual); + /// + /// dq.normalize_mut(); + /// + /// assert_relative_eq!(dq.real.norm(), 1.0); + /// ``` + #[inline] + pub fn normalize_mut(&mut self) -> T { + let real_norm = self.real.norm(); + self.real /= real_norm.clone(); + self.dual /= real_norm.clone(); + real_norm + } + + /// The conjugate of this dual quaternion, containing the conjugate of + /// the real and imaginary parts.. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let dq = DualQuaternion::from_real_and_dual(real, dual); + /// + /// let conj = dq.conjugate(); + /// assert!(conj.real.i == -2.0 && conj.real.j == -3.0 && conj.real.k == -4.0); + /// assert!(conj.real.w == 1.0); + /// assert!(conj.dual.i == -6.0 && conj.dual.j == -7.0 && conj.dual.k == -8.0); + /// assert!(conj.dual.w == 5.0); + /// ``` + #[inline] + #[must_use = "Did you mean to use conjugate_mut()?"] + pub fn conjugate(&self) -> Self { + Self::from_real_and_dual(self.real.conjugate(), self.dual.conjugate()) + } + + /// Replaces this quaternion by its conjugate. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let mut dq = DualQuaternion::from_real_and_dual(real, dual); + /// + /// dq.conjugate_mut(); + /// assert!(dq.real.i == -2.0 && dq.real.j == -3.0 && dq.real.k == -4.0); + /// assert!(dq.real.w == 1.0); + /// assert!(dq.dual.i == -6.0 && dq.dual.j == -7.0 && dq.dual.k == -8.0); + /// assert!(dq.dual.w == 5.0); + /// ``` + #[inline] + pub fn conjugate_mut(&mut self) { + self.real.conjugate_mut(); + self.dual.conjugate_mut(); + } + + /// Inverts this dual quaternion if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let dq = DualQuaternion::from_real_and_dual(real, dual); + /// let inverse = dq.try_inverse(); + /// + /// assert!(inverse.is_some()); + /// assert_relative_eq!(inverse.unwrap() * dq, DualQuaternion::identity()); + /// + /// //Non-invertible case + /// let zero = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// let dq = DualQuaternion::from_real_and_dual(zero, zero); + /// let inverse = dq.try_inverse(); + /// + /// assert!(inverse.is_none()); + /// ``` + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn try_inverse(&self) -> Option + where + T: RealField, + { + let mut res = self.clone(); + if res.try_inverse_mut() { + Some(res) + } else { + None + } + } + + /// Inverts this dual quaternion in-place if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let real = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let dual = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let dq = DualQuaternion::from_real_and_dual(real, dual); + /// let mut dq_inverse = dq; + /// dq_inverse.try_inverse_mut(); + /// + /// assert_relative_eq!(dq_inverse * dq, DualQuaternion::identity()); + /// + /// //Non-invertible case + /// let zero = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// let mut dq = DualQuaternion::from_real_and_dual(zero, zero); + /// assert!(!dq.try_inverse_mut()); + /// ``` + #[inline] + pub fn try_inverse_mut(&mut self) -> bool + where + T: RealField, + { + let inverted = self.real.try_inverse_mut(); + if inverted { + self.dual = -self.real.clone() * self.dual.clone() * self.real.clone(); + true + } else { + false + } + } + + /// Linear interpolation between two dual quaternions. + /// + /// Computes `self * (1 - t) + other * t`. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let dq1 = DualQuaternion::from_real_and_dual( + /// Quaternion::new(1.0, 0.0, 0.0, 4.0), + /// Quaternion::new(0.0, 2.0, 0.0, 0.0) + /// ); + /// let dq2 = DualQuaternion::from_real_and_dual( + /// Quaternion::new(2.0, 0.0, 1.0, 0.0), + /// Quaternion::new(0.0, 2.0, 0.0, 0.0) + /// ); + /// assert_eq!(dq1.lerp(&dq2, 0.25), DualQuaternion::from_real_and_dual( + /// Quaternion::new(1.25, 0.0, 0.25, 3.0), + /// Quaternion::new(0.0, 2.0, 0.0, 0.0) + /// )); + /// ``` + #[inline] + #[must_use] + pub fn lerp(&self, other: &Self, t: T) -> Self { + self * (T::one() - t.clone()) + other * t + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for DualQuaternion +where + T: Scalar + bytemuck::Zeroable, + Quaternion: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for DualQuaternion +where + T: Scalar + bytemuck::Pod, + Quaternion: bytemuck::Pod, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for DualQuaternion +where + T: Serialize, +{ + fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> + where + S: Serializer, + { + self.as_ref().serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: SimdRealField> Deserialize<'a> for DualQuaternion +where + T: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + type Dq = [T; 8]; + + let dq: Dq = Dq::::deserialize(deserializer)?; + + Ok(Self { + real: Quaternion::new(dq[3].clone(), dq[0].clone(), dq[1].clone(), dq[2].clone()), + dual: Quaternion::new(dq[7].clone(), dq[4].clone(), dq[5].clone(), dq[6].clone()), + }) + } +} + +impl DualQuaternion { + #[allow(clippy::wrong_self_convention)] + fn to_vector(&self) -> OVector { + self.as_ref().clone().into() + } +} + +impl> AbsDiffEq for DualQuaternion { + type Epsilon = T; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.to_vector().abs_diff_eq(&other.to_vector(), epsilon.clone()) || + // Account for the double-covering of S², i.e. q = -q + self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-b.clone(), epsilon.clone())) + } +} + +impl> RelativeEq for DualQuaternion { + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.to_vector().relative_eq(&other.to_vector(), epsilon.clone(), max_relative.clone()) || + // Account for the double-covering of S², i.e. q = -q + self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.relative_eq(&-b.clone(), epsilon.clone(), max_relative.clone())) + } +} + +impl> UlpsEq for DualQuaternion { + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.to_vector().ulps_eq(&other.to_vector(), epsilon.clone(), max_ulps) || + // Account for the double-covering of S², i.e. q = -q. + self.to_vector().iter().zip(other.to_vector().iter()).all(|(a, b)| a.ulps_eq(&-b.clone(), epsilon.clone(), max_ulps)) + } +} + +/// A unit dual quaternion. May be used to represent a rotation followed by a +/// translation. +pub type UnitDualQuaternion = Unit>; + +impl PartialEq for UnitDualQuaternion { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.as_ref().eq(rhs.as_ref()) + } +} + +impl Eq for UnitDualQuaternion {} + +impl Normed for DualQuaternion { + type Norm = T::SimdRealField; + + #[inline] + fn norm(&self) -> T::SimdRealField { + self.real.norm() + } + + #[inline] + fn norm_squared(&self) -> T::SimdRealField { + self.real.norm_squared() + } + + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.real.scale_mut(n.clone()); + self.dual.scale_mut(n); + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.real.unscale_mut(n.clone()); + self.dual.unscale_mut(n); + } +} + +impl UnitDualQuaternion +where + T::Element: SimdRealField, +{ + /// The underlying dual quaternion. + /// + /// Same as `self.as_ref()`. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, UnitDualQuaternion, Quaternion}; + /// let id = UnitDualQuaternion::identity(); + /// assert_eq!(*id.dual_quaternion(), DualQuaternion::from_real_and_dual( + /// Quaternion::new(1.0, 0.0, 0.0, 0.0), + /// Quaternion::new(0.0, 0.0, 0.0, 0.0) + /// )); + /// ``` + #[inline] + #[must_use] + pub fn dual_quaternion(&self) -> &DualQuaternion { + self.as_ref() + } + + /// Compute the conjugate of this unit quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion}; + /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let unit = UnitDualQuaternion::new_normalize( + /// DualQuaternion::from_real_and_dual(qr, qd) + /// ); + /// let conj = unit.conjugate(); + /// assert_eq!(conj.real, unit.real.conjugate()); + /// assert_eq!(conj.dual, unit.dual.conjugate()); + /// ``` + #[inline] + #[must_use = "Did you mean to use conjugate_mut()?"] + pub fn conjugate(&self) -> Self { + Self::new_unchecked(self.as_ref().conjugate()) + } + + /// Compute the conjugate of this unit quaternion in-place. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion}; + /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let unit = UnitDualQuaternion::new_normalize( + /// DualQuaternion::from_real_and_dual(qr, qd) + /// ); + /// let mut conj = unit.clone(); + /// conj.conjugate_mut(); + /// assert_eq!(conj.as_ref().real, unit.as_ref().real.conjugate()); + /// assert_eq!(conj.as_ref().dual, unit.as_ref().dual.conjugate()); + /// ``` + #[inline] + pub fn conjugate_mut(&mut self) { + self.as_mut_unchecked().conjugate_mut() + } + + /// Inverts this dual quaternion if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, Quaternion, DualQuaternion}; + /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let unit = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qr, qd)); + /// let inv = unit.inverse(); + /// assert_relative_eq!(unit * inv, UnitDualQuaternion::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * unit, UnitDualQuaternion::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Self { + let real = Unit::new_unchecked(self.as_ref().real.clone()) + .inverse() + .into_inner(); + let dual = -real.clone() * self.as_ref().dual.clone() * real.clone(); + UnitDualQuaternion::new_unchecked(DualQuaternion { real, dual }) + } + + /// Inverts this dual quaternion in place if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, Quaternion, DualQuaternion}; + /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let unit = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qr, qd)); + /// let mut inv = unit.clone(); + /// inv.inverse_mut(); + /// assert_relative_eq!(unit * inv, UnitDualQuaternion::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * unit, UnitDualQuaternion::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) { + let quat = self.as_mut_unchecked(); + quat.real = Unit::new_unchecked(quat.real.clone()) + .inverse() + .into_inner(); + quat.dual = -quat.real.clone() * quat.dual.clone() * quat.real.clone(); + } + + /// The unit dual quaternion needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.isometry_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion}; + /// let qr = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let qd = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// let dq1 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qr, qd)); + /// let dq2 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual(qd, qr)); + /// let dq_to = dq1.isometry_to(&dq2); + /// assert_relative_eq!(dq_to * dq1, dq2, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn isometry_to(&self, other: &Self) -> Self { + other / self + } + + /// Linear interpolation between two unit dual quaternions. + /// + /// The result is not normalized. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion}; + /// let dq1 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual( + /// Quaternion::new(0.5, 0.0, 0.5, 0.0), + /// Quaternion::new(0.0, 0.5, 0.0, 0.5) + /// )); + /// let dq2 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual( + /// Quaternion::new(0.5, 0.0, 0.0, 0.5), + /// Quaternion::new(0.5, 0.0, 0.5, 0.0) + /// )); + /// assert_relative_eq!( + /// UnitDualQuaternion::new_normalize(dq1.lerp(&dq2, 0.5)), + /// UnitDualQuaternion::new_normalize( + /// DualQuaternion::from_real_and_dual( + /// Quaternion::new(0.5, 0.0, 0.25, 0.25), + /// Quaternion::new(0.25, 0.25, 0.25, 0.25) + /// ) + /// ), + /// epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn lerp(&self, other: &Self, t: T) -> DualQuaternion { + self.as_ref().lerp(other.as_ref(), t) + } + + /// Normalized linear interpolation between two unit quaternions. + /// + /// This is the same as `self.lerp` except that the result is normalized. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, Quaternion}; + /// let dq1 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual( + /// Quaternion::new(0.5, 0.0, 0.5, 0.0), + /// Quaternion::new(0.0, 0.5, 0.0, 0.5) + /// )); + /// let dq2 = UnitDualQuaternion::new_normalize(DualQuaternion::from_real_and_dual( + /// Quaternion::new(0.5, 0.0, 0.0, 0.5), + /// Quaternion::new(0.5, 0.0, 0.5, 0.0) + /// )); + /// assert_relative_eq!(dq1.nlerp(&dq2, 0.2), UnitDualQuaternion::new_normalize( + /// DualQuaternion::from_real_and_dual( + /// Quaternion::new(0.5, 0.0, 0.4, 0.1), + /// Quaternion::new(0.1, 0.4, 0.1, 0.4) + /// ) + /// ), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn nlerp(&self, other: &Self, t: T) -> Self { + let mut res = self.lerp(other, t); + let _ = res.normalize_mut(); + + Self::new_unchecked(res) + } + + /// Screw linear interpolation between two unit quaternions. This creates a + /// smooth arc from one dual-quaternion to another. + /// + /// Panics if the angle between both quaternion is 180 degrees (in which + /// case the interpolation is not well-defined). Use `.try_sclerp` + /// instead to avoid the panic. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, DualQuaternion, UnitQuaternion, Vector3}; + /// + /// let dq1 = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0), + /// ); + /// + /// let dq2 = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 0.0, 3.0).into(), + /// UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0), + /// ); + /// + /// let dq = dq1.sclerp(&dq2, 1.0 / 3.0); + /// + /// assert_relative_eq!( + /// dq.rotation().euler_angles().0, std::f32::consts::FRAC_PI_2, epsilon = 1.0e-6 + /// ); + /// assert_relative_eq!(dq.translation().vector.y, 3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn sclerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + self.try_sclerp(other, t, T::default_epsilon()) + .expect("DualQuaternion sclerp: ambiguous configuration.") + } + + /// Computes the screw-linear interpolation between two unit quaternions or + /// returns `None` if both quaternions are approximately 180 degrees + /// apart (in which case the interpolation is not well-defined). + /// + /// # Arguments + /// * `self`: the first quaternion to interpolate from. + /// * `other`: the second quaternion to interpolate toward. + /// * `t`: the interpolation parameter. Should be between 0 and 1. + /// * `epsilon`: the value below which the sinus of the angle separating + /// both quaternion + /// must be to return `None`. + #[inline] + #[must_use] + pub fn try_sclerp(&self, other: &Self, t: T, epsilon: T) -> Option + where + T: RealField, + { + let two = T::one() + T::one(); + let half = T::one() / two.clone(); + + // Invert one of the quaternions if we've got a longest-path + // interpolation. + let other = { + let dot_product = self.as_ref().real.coords.dot(&other.as_ref().real.coords); + if relative_eq!(dot_product, T::zero(), epsilon = epsilon.clone()) { + return None; + } + + if dot_product < T::zero() { + -other.clone() + } else { + other.clone() + } + }; + + let difference = self.as_ref().conjugate() * other.as_ref(); + let norm_squared = difference.real.vector().norm_squared(); + if relative_eq!(norm_squared, T::zero(), epsilon = epsilon) { + return Some(Self::from_parts( + self.translation() + .vector + .lerp(&other.translation().vector, t) + .into(), + self.rotation(), + )); + } + + let scalar: T = difference.real.scalar(); + let mut angle = two.clone() * scalar.acos(); + + let inverse_norm_squared: T = T::one() / norm_squared; + let inverse_norm = inverse_norm_squared.sqrt(); + + let mut pitch = -two * difference.dual.scalar() * inverse_norm.clone(); + let direction = difference.real.vector() * inverse_norm.clone(); + let moment = (difference.dual.vector() + - direction.clone() * (pitch.clone() * difference.real.scalar() * half.clone())) + * inverse_norm; + + angle *= t.clone(); + pitch *= t; + + let sin = (half.clone() * angle.clone()).sin(); + let cos = (half.clone() * angle).cos(); + + let real = Quaternion::from_parts(cos.clone(), direction.clone() * sin.clone()); + let dual = Quaternion::from_parts( + -pitch.clone() * half.clone() * sin.clone(), + moment * sin + direction * (pitch * half * cos), + ); + + Some( + self * UnitDualQuaternion::new_unchecked(DualQuaternion::from_real_and_dual( + real, dual, + )), + ) + } + + /// Return the rotation part of this unit dual quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0) + /// ); + /// + /// assert_relative_eq!( + /// dq.rotation().angle(), std::f32::consts::FRAC_PI_4, epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn rotation(&self) -> UnitQuaternion { + Unit::new_unchecked(self.as_ref().real.clone()) + } + + /// Return the translation part of this unit dual quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0) + /// ); + /// + /// assert_relative_eq!( + /// dq.translation().vector, Vector3::new(0.0, 3.0, 0.0), epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn translation(&self) -> Translation3 { + let two = T::one() + T::one(); + Translation3::from( + ((self.as_ref().dual.clone() * self.as_ref().real.clone().conjugate()) * two) + .vector() + .into_owned(), + ) + } + + /// Builds an isometry from this unit dual quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3}; + /// let rotation = UnitQuaternion::from_euler_angles(std::f32::consts::PI, 0.0, 0.0); + /// let translation = Vector3::new(1.0, 3.0, 2.5); + /// let dq = UnitDualQuaternion::from_parts( + /// translation.into(), + /// rotation + /// ); + /// let iso = dq.to_isometry(); + /// + /// assert_relative_eq!(iso.rotation.angle(), std::f32::consts::PI, epsilon = 1.0e-6); + /// assert_relative_eq!(iso.translation.vector, translation, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn to_isometry(self) -> Isometry3 { + Isometry3::from_parts(self.translation(), self.rotation()) + } + + /// Rotate and translate a point by this unit dual quaternion interpreted + /// as an isometry. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let point = Point3::new(1.0, 2.0, 3.0); + /// + /// assert_relative_eq!( + /// dq.transform_point(&point), Point3::new(1.0, 0.0, 2.0), epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point3) -> Point3 { + self * pt + } + + /// Rotate a vector by this unit dual quaternion, ignoring the translational + /// component. + /// + /// This is the same as the multiplication `self * v`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let vector = Vector3::new(1.0, 2.0, 3.0); + /// + /// assert_relative_eq!( + /// dq.transform_vector(&vector), Vector3::new(1.0, -3.0, 2.0), epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &Vector3) -> Vector3 { + self * v + } + + /// Rotate and translate a point by the inverse of this unit quaternion. + /// + /// This may be cheaper than inverting the unit dual quaternion and + /// transforming the point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let point = Point3::new(1.0, 2.0, 3.0); + /// + /// assert_relative_eq!( + /// dq.inverse_transform_point(&point), Point3::new(1.0, 3.0, 1.0), epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point3) -> Point3 { + self.inverse() * pt + } + + /// Rotate a vector by the inverse of this unit quaternion, ignoring the + /// translational component. + /// + /// This may be cheaper than inverting the unit dual quaternion and + /// transforming the vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let vector = Vector3::new(1.0, 2.0, 3.0); + /// + /// assert_relative_eq!( + /// dq.inverse_transform_vector(&vector), Vector3::new(1.0, 3.0, -2.0), epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { + self.inverse() * v + } + + /// Rotate a unit vector by the inverse of this unit quaternion, ignoring + /// the translational component. This may be + /// cheaper than inverting the unit dual quaternion and transforming the + /// vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Unit, Vector3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let vector = Unit::new_unchecked(Vector3::new(0.0, 1.0, 0.0)); + /// + /// assert_relative_eq!( + /// dq.inverse_transform_unit_vector(&vector), + /// Unit::new_unchecked(Vector3::new(0.0, 0.0, -1.0)), + /// epsilon = 1.0e-6 + /// ); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + self.inverse() * v + } +} + +impl UnitDualQuaternion +where + T::Element: SimdRealField, +{ + /// Converts this unit dual quaternion interpreted as an isometry + /// into its equivalent homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix4, UnitDualQuaternion, UnitQuaternion, Vector3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(1.0, 3.0, 2.0).into(), + /// UnitQuaternion::from_axis_angle(&Vector3::z_axis(), std::f32::consts::FRAC_PI_6) + /// ); + /// let expected = Matrix4::new(0.8660254, -0.5, 0.0, 1.0, + /// 0.5, 0.8660254, 0.0, 3.0, + /// 0.0, 0.0, 1.0, 2.0, + /// 0.0, 0.0, 0.0, 1.0); + /// + /// assert_relative_eq!(dq.to_homogeneous(), expected, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(self) -> Matrix4 { + self.to_isometry().to_homogeneous() + } +} + +impl Default for UnitDualQuaternion { + fn default() -> Self { + Self::identity() + } +} + +impl fmt::Display for UnitDualQuaternion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(axis) = self.rotation().axis() { + let axis = axis.into_inner(); + write!( + f, + "UnitDualQuaternion translation: {} − angle: {} − axis: ({}, {}, {})", + self.translation().vector, + self.rotation().angle(), + axis[0], + axis[1], + axis[2] + ) + } else { + write!( + f, + "UnitDualQuaternion translation: {} − angle: {} − axis: (undefined)", + self.translation().vector, + self.rotation().angle() + ) + } + } +} + +impl> AbsDiffEq for UnitDualQuaternion { + type Epsilon = T; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.as_ref().abs_diff_eq(other.as_ref(), epsilon) + } +} + +impl> RelativeEq for UnitDualQuaternion { + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.as_ref() + .relative_eq(other.as_ref(), epsilon, max_relative) + } +} + +impl> UlpsEq for UnitDualQuaternion { + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_construction.rs new file mode 100644 index 000000000..2b16fdd62 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_construction.rs @@ -0,0 +1,259 @@ +use crate::{ + DualQuaternion, Isometry3, Quaternion, Scalar, SimdRealField, Translation3, UnitDualQuaternion, + UnitQuaternion, +}; +use num::{One, Zero}; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; +use simba::scalar::SupersetOf; + +impl DualQuaternion { + /// Creates a dual quaternion from its rotation and translation components. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let rot = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let trans = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// + /// let dq = DualQuaternion::from_real_and_dual(rot, trans); + /// assert_eq!(dq.real.w, 1.0); + /// ``` + #[inline] + pub fn from_real_and_dual(real: Quaternion, dual: Quaternion) -> Self { + Self { real, dual } + } + + /// The dual quaternion multiplicative identity. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// + /// let dq1 = DualQuaternion::identity(); + /// let dq2 = DualQuaternion::from_real_and_dual( + /// Quaternion::new(1.,2.,3.,4.), + /// Quaternion::new(5.,6.,7.,8.) + /// ); + /// + /// assert_eq!(dq1 * dq2, dq2); + /// assert_eq!(dq2 * dq1, dq2); + /// ``` + #[inline] + pub fn identity() -> Self + where + T: SimdRealField, + { + Self::from_real_and_dual( + Quaternion::from_real(T::one()), + Quaternion::from_real(T::zero()), + ) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, DualQuaternion}; + /// let q = DualQuaternion::from_real(Quaternion::new(1.0f64, 2.0, 3.0, 4.0)); + /// let q2 = q.cast::(); + /// assert_eq!(q2, DualQuaternion::from_real(Quaternion::new(1.0f32, 2.0, 3.0, 4.0))); + /// ``` + pub fn cast(self) -> DualQuaternion + where + DualQuaternion: SupersetOf, + { + crate::convert(self) + } +} + +impl DualQuaternion +where + T::Element: SimdRealField, +{ + /// Creates a dual quaternion from only its real part, with no translation + /// component. + /// + /// # Example + /// ``` + /// # use nalgebra::{DualQuaternion, Quaternion}; + /// let rot = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// + /// let dq = DualQuaternion::from_real(rot); + /// assert_eq!(dq.real.w, 1.0); + /// assert_eq!(dq.dual.w, 0.0); + /// ``` + #[inline] + pub fn from_real(real: Quaternion) -> Self { + Self { + real, + dual: Quaternion::zero(), + } + } +} + +impl One for DualQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} + +impl Zero for DualQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn zero() -> Self { + DualQuaternion::from_real_and_dual(Quaternion::zero(), Quaternion::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + self.real.is_zero() && self.dual.is_zero() + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for DualQuaternion +where + T: SimdRealField + Arbitrary + Send, + T::Element: SimdRealField, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + Self::from_real_and_dual(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng)) + } +} + +impl UnitDualQuaternion { + /// The unit dual quaternion multiplicative identity, which also represents + /// the identity transformation as an isometry. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3}; + /// let ident = UnitDualQuaternion::identity(); + /// let point = Point3::new(1.0, -4.3, 3.33); + /// + /// assert_eq!(ident * point, point); + /// assert_eq!(ident, ident.inverse()); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::new_unchecked(DualQuaternion::identity()) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitDualQuaternion; + /// let q = UnitDualQuaternion::::identity(); + /// let q2 = q.cast::(); + /// assert_eq!(q2, UnitDualQuaternion::::identity()); + /// ``` + pub fn cast(self) -> UnitDualQuaternion + where + UnitDualQuaternion: SupersetOf, + { + crate::convert(self) + } +} + +impl UnitDualQuaternion +where + T::Element: SimdRealField, +{ + /// Return a dual quaternion representing the translation and orientation + /// given by the provided rotation quaternion and translation vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitDualQuaternion, UnitQuaternion, Vector3, Point3}; + /// let dq = UnitDualQuaternion::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let point = Point3::new(1.0, 2.0, 3.0); + /// + /// assert_relative_eq!(dq * point, Point3::new(1.0, 0.0, 2.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn from_parts(translation: Translation3, rotation: UnitQuaternion) -> Self { + let half: T = crate::convert(0.5f64); + UnitDualQuaternion::new_unchecked(DualQuaternion { + real: rotation.clone().into_inner(), + dual: Quaternion::from_parts(T::zero(), translation.vector) + * rotation.into_inner() + * half, + }) + } + + /// Return a unit dual quaternion representing the translation and orientation + /// given by the provided isometry. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Isometry3, UnitDualQuaternion, UnitQuaternion, Vector3, Point3}; + /// let iso = Isometry3::from_parts( + /// Vector3::new(0.0, 3.0, 0.0).into(), + /// UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_2, 0.0, 0.0) + /// ); + /// let dq = UnitDualQuaternion::from_isometry(&iso); + /// let point = Point3::new(1.0, 2.0, 3.0); + /// + /// assert_relative_eq!(dq * point, iso * point, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn from_isometry(isometry: &Isometry3) -> Self { + // TODO: take the isometry by-move instead of cloning it. + let isometry = isometry.clone(); + UnitDualQuaternion::from_parts(isometry.translation, isometry.rotation) + } + + /// Creates a dual quaternion from a unit quaternion rotation. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitQuaternion, UnitDualQuaternion, Quaternion}; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let rot = UnitQuaternion::new_normalize(q); + /// + /// let dq = UnitDualQuaternion::from_rotation(rot); + /// assert_relative_eq!(dq.as_ref().real.norm(), 1.0, epsilon = 1.0e-6); + /// assert_eq!(dq.as_ref().dual.norm(), 0.0); + /// ``` + #[inline] + pub fn from_rotation(rotation: UnitQuaternion) -> Self { + Self::new_unchecked(DualQuaternion::from_real(rotation.into_inner())) + } +} + +impl One for UnitDualQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for UnitDualQuaternion +where + T: SimdRealField + Arbitrary + Send, + T::Element: SimdRealField, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + Self::new_normalize(Arbitrary::arbitrary(rng)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_conversion.rs new file mode 100644 index 000000000..cae86f302 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_conversion.rs @@ -0,0 +1,187 @@ +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::SimdRealField; + +use crate::base::{Matrix4, Vector4}; +use crate::geometry::{ + DualQuaternion, Isometry3, Similarity3, SuperTCategoryOf, TAffine, Transform, Translation3, + UnitDualQuaternion, UnitQuaternion, +}; + +/* + * This file provides the following conversions: + * ============================================= + * + * DualQuaternion -> DualQuaternion + * UnitDualQuaternion -> UnitDualQuaternion + * UnitDualQuaternion -> Isometry<3> + * UnitDualQuaternion -> Similarity<3> + * UnitDualQuaternion -> Transform<3> + * UnitDualQuaternion -> Matrix (homogeneous) + * + * NOTE: + * UnitDualQuaternion -> DualQuaternion is already provided by: Unit -> T + */ + +impl SubsetOf> for DualQuaternion +where + T1: SimdRealField, + T2: SimdRealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> DualQuaternion { + DualQuaternion::from_real_and_dual(self.real.to_superset(), self.dual.to_superset()) + } + + #[inline] + fn is_in_subset(dq: &DualQuaternion) -> bool { + crate::is_convertible::<_, Vector4>(&dq.real.coords) + && crate::is_convertible::<_, Vector4>(&dq.dual.coords) + } + + #[inline] + fn from_superset_unchecked(dq: &DualQuaternion) -> Self { + DualQuaternion::from_real_and_dual( + dq.real.to_subset_unchecked(), + dq.dual.to_subset_unchecked(), + ) + } +} + +impl SubsetOf> for UnitDualQuaternion +where + T1: SimdRealField, + T2: SimdRealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitDualQuaternion { + UnitDualQuaternion::new_unchecked(self.as_ref().to_superset()) + } + + #[inline] + fn is_in_subset(dq: &UnitDualQuaternion) -> bool { + crate::is_convertible::<_, DualQuaternion>(dq.as_ref()) + } + + #[inline] + fn from_superset_unchecked(dq: &UnitDualQuaternion) -> Self { + Self::new_unchecked(crate::convert_ref_unchecked(dq.as_ref())) + } +} + +impl SubsetOf> for UnitDualQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Isometry3 { + let dq: UnitDualQuaternion = self.to_superset(); + let iso = dq.to_isometry(); + crate::convert_unchecked(iso) + } + + #[inline] + fn is_in_subset(iso: &Isometry3) -> bool { + crate::is_convertible::<_, UnitQuaternion>(&iso.rotation) + && crate::is_convertible::<_, Translation3>(&iso.translation) + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry3) -> Self { + let dq = UnitDualQuaternion::::from_isometry(iso); + crate::convert_unchecked(dq) + } +} + +impl SubsetOf> for UnitDualQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Similarity3 { + Similarity3::from_isometry(crate::convert_ref(self), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity3) -> bool { + sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity3) -> Self { + crate::convert_ref_unchecked(&sim.isometry) + } +} + +impl SubsetOf> for UnitDualQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.clone().to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl> SubsetOf> + for UnitDualQuaternion +{ + #[inline] + fn to_superset(&self) -> Matrix4 { + self.clone().to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &Matrix4) -> bool { + crate::is_convertible::<_, Isometry3>(m) + } + + #[inline] + fn from_superset_unchecked(m: &Matrix4) -> Self { + let iso: Isometry3 = crate::convert_ref_unchecked(m); + Self::from_isometry(&iso) + } +} + +impl From> for Matrix4 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(dq: UnitDualQuaternion) -> Self { + dq.to_homogeneous() + } +} + +impl From> for Isometry3 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(dq: UnitDualQuaternion) -> Self { + dq.to_isometry() + } +} + +impl From> for UnitDualQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn from(iso: Isometry3) -> Self { + Self::from_isometry(&iso) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_ops.rs new file mode 100644 index 000000000..22e3a79b4 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/dual_quaternion_ops.rs @@ -0,0 +1,1256 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +/* + * This file provides: + * + * NOTE: Work in progress https://github.com/dimforge/nalgebra/issues/487 + * + * (Dual Quaternion) + * + * Index + * IndexMut + * + * (Assignment Operators) + * + * -DualQuaternion + * DualQuaternion × Scalar + * DualQuaternion × DualQuaternion + * DualQuaternion + DualQuaternion + * DualQuaternion - DualQuaternion + * DualQuaternion × UnitDualQuaternion + * DualQuaternion ÷ UnitDualQuaternion + * -UnitDualQuaternion + * UnitDualQuaternion × DualQuaternion + * UnitDualQuaternion × UnitDualQuaternion + * UnitDualQuaternion ÷ UnitDualQuaternion + * UnitDualQuaternion × Translation3 + * UnitDualQuaternion ÷ Translation3 + * UnitDualQuaternion × UnitQuaternion + * UnitDualQuaternion ÷ UnitQuaternion + * Translation3 × UnitDualQuaternion + * Translation3 ÷ UnitDualQuaternion + * UnitQuaternion × UnitDualQuaternion + * UnitQuaternion ÷ UnitDualQuaternion + * UnitDualQuaternion × Isometry3 + * UnitDualQuaternion ÷ Isometry3 + * Isometry3 × UnitDualQuaternion + * Isometry3 ÷ UnitDualQuaternion + * UnitDualQuaternion × Point + * UnitDualQuaternion × Vector + * UnitDualQuaternion × Unit + * + * --- + * + * References: + * Multiplication: + * - https://cs.gmu.edu/~jmlien/teaching/cs451/uploads/Main/dual-quaternion.pdf + */ + +use crate::base::storage::Storage; +use crate::{ + DualQuaternion, Isometry3, Point, Point3, Quaternion, SimdRealField, Translation3, Unit, + UnitDualQuaternion, UnitQuaternion, Vector, Vector3, U3, +}; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, +}; + +impl AsRef<[T; 8]> for DualQuaternion { + #[inline] + fn as_ref(&self) -> &[T; 8] { + unsafe { &*(self as *const Self as *const [T; 8]) } + } +} + +impl AsMut<[T; 8]> for DualQuaternion { + #[inline] + fn as_mut(&mut self) -> &mut [T; 8] { + unsafe { &mut *(self as *mut Self as *mut [T; 8]) } + } +} + +impl Index for DualQuaternion { + type Output = T; + + #[inline] + fn index(&self, i: usize) -> &Self::Output { + &self.as_ref()[i] + } +} + +impl IndexMut for DualQuaternion { + #[inline] + fn index_mut(&mut self, i: usize) -> &mut T { + &mut self.as_mut()[i] + } +} + +impl Neg for DualQuaternion +where + T::Element: SimdRealField, +{ + type Output = DualQuaternion; + + #[inline] + fn neg(self) -> Self::Output { + DualQuaternion::from_real_and_dual(-self.real, -self.dual) + } +} + +impl<'a, T: SimdRealField> Neg for &'a DualQuaternion +where + T::Element: SimdRealField, +{ + type Output = DualQuaternion; + + #[inline] + fn neg(self) -> Self::Output { + DualQuaternion::from_real_and_dual(-&self.real, -&self.dual) + } +} + +impl Neg for UnitDualQuaternion +where + T::Element: SimdRealField, +{ + type Output = UnitDualQuaternion; + + #[inline] + fn neg(self) -> Self::Output { + UnitDualQuaternion::new_unchecked(-self.into_inner()) + } +} + +impl<'a, T: SimdRealField> Neg for &'a UnitDualQuaternion +where + T::Element: SimdRealField, +{ + type Output = UnitDualQuaternion; + + #[inline] + fn neg(self) -> Self::Output { + UnitDualQuaternion::new_unchecked(-self.as_ref()) + } +} + +macro_rules! dual_quaternion_op_impl( + ($Op: ident, $op: ident; + ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident) + $(for $Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty $(=> $VDimA: ty, $VDimB: ty)*; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField, { + type Output = $Result; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +// DualQuaternion + DualQuaternion +dual_quaternion_op_impl!( + Add, add; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: &'b DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + &self.real + &rhs.real, + &self.dual + &rhs.dual, + ); + 'a, 'b); + +dual_quaternion_op_impl!( + Add, add; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + &self.real + rhs.real, + &self.dual + rhs.dual, + ); + 'a); + +dual_quaternion_op_impl!( + Add, add; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + self.real + &rhs.real, + self.dual + &rhs.dual, + ); + 'b); + +dual_quaternion_op_impl!( + Add, add; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + self.real + rhs.real, + self.dual + rhs.dual, + ); ); + +// DualQuaternion - DualQuaternion +dual_quaternion_op_impl!( + Sub, sub; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: &'b DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + &self.real - &rhs.real, + &self.dual - &rhs.dual, + ); + 'a, 'b); + +dual_quaternion_op_impl!( + Sub, sub; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + &self.real - rhs.real, + &self.dual - rhs.dual, + ); + 'a); + +dual_quaternion_op_impl!( + Sub, sub; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + self.real - &rhs.real, + self.dual - &rhs.dual, + ); + 'b); + +dual_quaternion_op_impl!( + Sub, sub; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + self.real - rhs.real, + self.dual - rhs.dual, + ); ); + +// DualQuaternion × DualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: &'b DualQuaternion, Output = DualQuaternion; + DualQuaternion::from_real_and_dual( + &self.real * &rhs.real, + &self.real * &rhs.dual + &self.dual * &rhs.real, + ); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: DualQuaternion, Output = DualQuaternion; + self * &rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b DualQuaternion, Output = DualQuaternion; + &self * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: DualQuaternion, Output = DualQuaternion; + &self * &rhs; ); + +// DualQuaternion × UnitDualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: &'b UnitDualQuaternion, Output = DualQuaternion; + self * rhs.dual_quaternion(); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: UnitDualQuaternion, Output = DualQuaternion; + self * rhs.dual_quaternion(); + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b UnitDualQuaternion, Output = DualQuaternion; + self * rhs.dual_quaternion(); + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: UnitDualQuaternion, Output = DualQuaternion; + self * rhs.dual_quaternion();); + +// DualQuaternion ÷ UnitDualQuaternion +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: &'b UnitDualQuaternion, Output = DualQuaternion; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * rhs.inverse().dual_quaternion() }; + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a DualQuaternion, rhs: UnitDualQuaternion, Output = DualQuaternion; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * rhs.inverse().dual_quaternion() }; + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b UnitDualQuaternion, Output = DualQuaternion; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * rhs.inverse().dual_quaternion() }; + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: UnitDualQuaternion, Output = DualQuaternion; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * rhs.inverse().dual_quaternion() };); + +// UnitDualQuaternion × UnitDualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: &'b UnitDualQuaternion, Output = UnitDualQuaternion; + UnitDualQuaternion::new_unchecked(self.as_ref() * rhs.as_ref()); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: UnitDualQuaternion, Output = UnitDualQuaternion; + self * &rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitDualQuaternion, Output = UnitDualQuaternion; + &self * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitDualQuaternion, Output = UnitDualQuaternion; + &self * &rhs; ); + +// UnitDualQuaternion ÷ UnitDualQuaternion +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: &'b UnitDualQuaternion, Output = UnitDualQuaternion; + #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: UnitDualQuaternion, Output = UnitDualQuaternion; + self / &rhs; + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitDualQuaternion, Output = UnitDualQuaternion; + &self / rhs; + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitDualQuaternion, Output = UnitDualQuaternion; + &self / &rhs; ); + +// UnitDualQuaternion × DualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: &'b DualQuaternion, + Output = DualQuaternion => U1, U4; + self.dual_quaternion() * rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: DualQuaternion, + Output = DualQuaternion => U3, U3; + self.dual_quaternion() * rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b DualQuaternion, + Output = DualQuaternion => U3, U3; + self.dual_quaternion() * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: DualQuaternion, + Output = DualQuaternion => U3, U3; + self.dual_quaternion() * rhs;); + +// UnitDualQuaternion × UnitQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: &'b UnitQuaternion, + Output = UnitDualQuaternion => U1, U4; + self * UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(rhs.clone().into_inner())); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: UnitQuaternion, + Output = UnitDualQuaternion => U3, U3; + self * UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(rhs.into_inner())); + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitQuaternion, + Output = UnitDualQuaternion => U3, U3; + self * UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(rhs.clone().into_inner())); + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitQuaternion, + Output = UnitDualQuaternion => U3, U3; + self * UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(rhs.into_inner()));); + +// UnitQuaternion × UnitDualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitQuaternion, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U1, U4; + UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(self.clone().into_inner())) * rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: &'a UnitQuaternion, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U3; + UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(self.clone().into_inner())) * rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitQuaternion, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U3; + UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(self.into_inner())) * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U4, U1); + self: UnitQuaternion, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U3; + UnitDualQuaternion::::new_unchecked(DualQuaternion::from_real(self.into_inner())) * rhs;); + +// UnitDualQuaternion ÷ UnitQuaternion +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: &'b UnitQuaternion, + Output = UnitDualQuaternion => U1, U4; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_rotation(rhs.inverse()) }; + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a UnitDualQuaternion, rhs: UnitQuaternion, + Output = UnitDualQuaternion => U3, U3; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_rotation(rhs.inverse()) }; + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitQuaternion, + Output = UnitDualQuaternion => U3, U3; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_rotation(rhs.inverse()) }; + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitQuaternion, + Output = UnitDualQuaternion => U3, U3; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_rotation(rhs.inverse()) };); + +// UnitQuaternion ÷ UnitDualQuaternion +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a UnitQuaternion, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U1, U4; + #[allow(clippy::suspicious_arithmetic_impl)] + { + UnitDualQuaternion::::new_unchecked( + DualQuaternion::from_real(self.clone().into_inner()) + ) * rhs.inverse() + }; 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: &'a UnitQuaternion, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U3; + #[allow(clippy::suspicious_arithmetic_impl)] + { + UnitDualQuaternion::::new_unchecked( + DualQuaternion::from_real(self.clone().into_inner()) + ) * rhs.inverse() + }; 'a); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: UnitQuaternion, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U3; + #[allow(clippy::suspicious_arithmetic_impl)] + { + UnitDualQuaternion::::new_unchecked( + DualQuaternion::from_real(self.into_inner()) + ) * rhs.inverse() + }; 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U4, U1); + self: UnitQuaternion, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U3; + #[allow(clippy::suspicious_arithmetic_impl)] + { + UnitDualQuaternion::::new_unchecked( + DualQuaternion::from_real(self.into_inner()) + ) * rhs.inverse() + };); + +// UnitDualQuaternion × Translation3 +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1); + self: &'a UnitDualQuaternion, rhs: &'b Translation3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_parts(rhs.clone(), UnitQuaternion::identity()); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U3); + self: &'a UnitDualQuaternion, rhs: Translation3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_parts(rhs, UnitQuaternion::identity()); + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: &'b Translation3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_parts(rhs.clone(), UnitQuaternion::identity()); + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: Translation3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_parts(rhs, UnitQuaternion::identity()); ); + +// UnitDualQuaternion ÷ Translation3 +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U1); + self: &'a UnitDualQuaternion, rhs: &'b Translation3, + Output = UnitDualQuaternion => U3, U1; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_parts(rhs.inverse(), UnitQuaternion::identity()) }; + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U3); + self: &'a UnitDualQuaternion, rhs: Translation3, + Output = UnitDualQuaternion => U3, U1; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_parts(rhs.inverse(), UnitQuaternion::identity()) }; + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: &'b Translation3, + Output = UnitDualQuaternion => U3, U1; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_parts(rhs.inverse(), UnitQuaternion::identity()) }; + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: Translation3, + Output = UnitDualQuaternion => U3, U1; + #[allow(clippy::suspicious_arithmetic_impl)] + { self * UnitDualQuaternion::::from_parts(rhs.inverse(), UnitQuaternion::identity()) };); + +// Translation3 × UnitDualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: &'b Translation3, rhs: &'a UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self.clone(), UnitQuaternion::identity()) * rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: &'a Translation3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self.clone(), UnitQuaternion::identity()) * rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: Translation3, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self, UnitQuaternion::identity()) * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: Translation3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self, UnitQuaternion::identity()) * rhs;); + +// Translation3 ÷ UnitDualQuaternion +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: &'b Translation3, rhs: &'a UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self.clone(), UnitQuaternion::identity()) / rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: &'a Translation3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self.clone(), UnitQuaternion::identity()) / rhs; + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: Translation3, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self, UnitQuaternion::identity()) / rhs; + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: Translation3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_parts(self, UnitQuaternion::identity()) / rhs;); + +// UnitDualQuaternion × Isometry3 +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1); + self: &'a UnitDualQuaternion, rhs: &'b Isometry3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_isometry(rhs); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U3); + self: &'a UnitDualQuaternion, rhs: Isometry3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_isometry(&rhs); + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: &'b Isometry3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_isometry(rhs); + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: Isometry3, + Output = UnitDualQuaternion => U3, U1; + self * UnitDualQuaternion::::from_isometry(&rhs); ); + +// UnitDualQuaternion ÷ Isometry3 +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U1); + self: &'a UnitDualQuaternion, rhs: &'b Isometry3, + Output = UnitDualQuaternion => U3, U1; + // TODO: can we avoid the conversion to a rotation matrix? + self / UnitDualQuaternion::::from_isometry(rhs); + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U3); + self: &'a UnitDualQuaternion, rhs: Isometry3, + Output = UnitDualQuaternion => U3, U1; + self / UnitDualQuaternion::::from_isometry(&rhs); + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: &'b Isometry3, + Output = UnitDualQuaternion => U3, U1; + self / UnitDualQuaternion::::from_isometry(rhs); + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U4, U1), (U3, U3); + self: UnitDualQuaternion, rhs: Isometry3, + Output = UnitDualQuaternion => U3, U1; + self / UnitDualQuaternion::::from_isometry(&rhs); ); + +// Isometry × UnitDualQuaternion +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: &'a Isometry3, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(self) * rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: &'a Isometry3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(self) * rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: Isometry3, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(&self) * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U3, U1), (U4, U1); + self: Isometry3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(&self) * rhs; ); + +// Isometry ÷ UnitDualQuaternion +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: &'a Isometry3, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + // TODO: can we avoid the conversion from a rotation matrix? + UnitDualQuaternion::::from_isometry(self) / rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: &'a Isometry3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(self) / rhs; + 'a); + +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: Isometry3, rhs: &'b UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(&self) / rhs; + 'b); + +dual_quaternion_op_impl!( + Div, div; + (U3, U1), (U4, U1); + self: Isometry3, rhs: UnitDualQuaternion, + Output = UnitDualQuaternion => U3, U1; + UnitDualQuaternion::::from_isometry(&self) / rhs; ); + +// UnitDualQuaternion × Vector +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitDualQuaternion, rhs: &'b Vector, + Output = Vector3 => U3, U1; + Unit::new_unchecked(self.as_ref().real.clone()) * rhs; + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitDualQuaternion, rhs: Vector, + Output = Vector3 => U3, U1; + self * &rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitDualQuaternion, rhs: &'b Vector, + Output = Vector3 => U3, U1; + &self * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitDualQuaternion, rhs: Vector, + Output = Vector3 => U3, U1; + &self * &rhs; ); + +// UnitDualQuaternion × Point +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1); + self: &'a UnitDualQuaternion, rhs: &'b Point3, + Output = Point3 => U3, U1; + { + let two: T = crate::convert(2.0f64); + let q_point = Quaternion::from_parts(T::zero(), rhs.coords.clone()); + Point::from( + ((self.as_ref().real.clone() * q_point + self.as_ref().dual.clone() * two) * self.as_ref().real.clone().conjugate()) + .vector() + .into_owned(), + ) + }; + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1); + self: &'a UnitDualQuaternion, rhs: Point3, + Output = Point3 => U3, U1; + self * &rhs; + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1); + self: UnitDualQuaternion, rhs: &'b Point3, + Output = Point3 => U3, U1; + &self * rhs; + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1); + self: UnitDualQuaternion, rhs: Point3, + Output = Point3 => U3, U1; + &self * &rhs; ); + +// UnitDualQuaternion × Unit +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitDualQuaternion, rhs: &'b Unit>, + Output = Unit> => U3, U4; + Unit::new_unchecked(self * rhs.as_ref()); + 'a, 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: &'a UnitDualQuaternion, rhs: Unit>, + Output = Unit> => U3, U4; + Unit::new_unchecked(self * rhs.into_inner()); + 'a); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitDualQuaternion, rhs: &'b Unit>, + Output = Unit> => U3, U4; + Unit::new_unchecked(self * rhs.as_ref()); + 'b); + +dual_quaternion_op_impl!( + Mul, mul; + (U4, U1), (U3, U1) for SB: Storage ; + self: UnitDualQuaternion, rhs: Unit>, + Output = Unit> => U3, U4; + Unit::new_unchecked(self * rhs.into_inner()); ); + +macro_rules! left_scalar_mul_impl( + ($($T: ty),* $(,)*) => {$( + impl Mul> for $T { + type Output = DualQuaternion<$T>; + + #[inline] + fn mul(self, right: DualQuaternion<$T>) -> Self::Output { + DualQuaternion::from_real_and_dual( + self * right.real, + self * right.dual + ) + } + } + + impl<'b> Mul<&'b DualQuaternion<$T>> for $T { + type Output = DualQuaternion<$T>; + + #[inline] + fn mul(self, right: &'b DualQuaternion<$T>) -> Self::Output { + DualQuaternion::from_real_and_dual( + self * &right.real, + self * &right.dual + ) + } + } + )*} +); + +left_scalar_mul_impl!(f32, f64); + +macro_rules! dual_quaternion_op_impl( + ($OpAssign: ident, $op_assign: ident; + ($LhsRDim: ident, $LhsCDim: ident), ($RhsRDim: ident, $RhsCDim: ident); + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField> $OpAssign<$Rhs> for $Lhs + where T::Element: SimdRealField { + + #[inline] + fn $op_assign(&mut $lhs, $rhs: $Rhs) { + $action + } + } + } +); + +// DualQuaternion += DualQuaternion +dual_quaternion_op_impl!( + AddAssign, add_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b DualQuaternion; + { + self.real += &rhs.real; + self.dual += &rhs.dual; + }; + 'b); + +dual_quaternion_op_impl!( + AddAssign, add_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: DualQuaternion; + { + self.real += rhs.real; + self.dual += rhs.dual; + };); + +// DualQuaternion -= DualQuaternion +dual_quaternion_op_impl!( + SubAssign, sub_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b DualQuaternion; + { + self.real -= &rhs.real; + self.dual -= &rhs.dual; + }; + 'b); + +dual_quaternion_op_impl!( + SubAssign, sub_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: DualQuaternion; + { + self.real -= rhs.real; + self.dual -= rhs.dual; + };); + +// DualQuaternion ×= DualQuaternion +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b DualQuaternion; + { + let res = &*self * rhs; + self.real.coords.copy_from(&res.real.coords); + self.dual.coords.copy_from(&res.dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: DualQuaternion; + *self *= &rhs;); + +// DualQuaternion ×= UnitDualQuaternion +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b UnitDualQuaternion; + { + let res = &*self * rhs; + self.real.coords.copy_from(&res.real.coords); + self.dual.coords.copy_from(&res.dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: UnitDualQuaternion; + *self *= &rhs; ); + +// DualQuaternion ÷= UnitDualQuaternion +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: &'b UnitDualQuaternion; + { + let res = &*self / rhs; + self.real.coords.copy_from(&res.real.coords); + self.dual.coords.copy_from(&res.dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: DualQuaternion, rhs: UnitDualQuaternion; + *self /= &rhs; ); + +// UnitDualQuaternion ×= UnitDualQuaternion +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitDualQuaternion; + { + let res = &*self * rhs; + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitDualQuaternion; + *self *= &rhs; ); + +// UnitDualQuaternion ÷= UnitDualQuaternion +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitDualQuaternion; + { + let res = &*self / rhs; + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitDualQuaternion; + *self /= &rhs; ); + +// UnitDualQuaternion ×= UnitQuaternion +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitQuaternion; + { + let res = &*self * UnitDualQuaternion::from_rotation(rhs); + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + };); + +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitQuaternion; + *self *= rhs.clone(); 'b); + +// UnitDualQuaternion ÷= UnitQuaternion +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b UnitQuaternion; + #[allow(clippy::suspicious_op_assign_impl)] + { + let res = &*self * UnitDualQuaternion::from_rotation(rhs.inverse()); + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: UnitQuaternion; + *self /= &rhs; ); + +// UnitDualQuaternion ×= Translation3 +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: Translation3; + { + let res = &*self * UnitDualQuaternion::from_parts(rhs, UnitQuaternion::identity()); + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + };); + +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b Translation3; + *self *= rhs.clone(); 'b); + +// UnitDualQuaternion ÷= Translation3 +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: &'b Translation3; + #[allow(clippy::suspicious_op_assign_impl)] + { + let res = &*self * UnitDualQuaternion::from_parts(rhs.inverse(), UnitQuaternion::identity()); + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U4, U1); + self: UnitDualQuaternion, rhs: Translation3; + *self /= &rhs; ); + +// UnitDualQuaternion ×= Isometry3 +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U3, U1); + self: UnitDualQuaternion, rhs: &'b Isometry3 => U3, U1; + { + let res = &*self * rhs; + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + MulAssign, mul_assign; + (U4, U1), (U3, U1); + self: UnitDualQuaternion, rhs: Isometry3 => U3, U1; + *self *= &rhs; ); + +// UnitDualQuaternion ÷= Isometry3 +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U3, U1); + self: UnitDualQuaternion, rhs: &'b Isometry3 => U3, U1; + { + let res = &*self / rhs; + self.as_mut_unchecked().real.coords.copy_from(&res.as_ref().real.coords); + self.as_mut_unchecked().dual.coords.copy_from(&res.as_ref().dual.coords); + }; + 'b); + +dual_quaternion_op_impl!( + DivAssign, div_assign; + (U4, U1), (U3, U1); + self: UnitDualQuaternion, rhs: Isometry3 => U3, U1; + *self /= &rhs; ); + +macro_rules! scalar_op_impl( + ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$( + impl $Op for DualQuaternion + where T::Element: SimdRealField { + type Output = DualQuaternion; + + #[inline] + fn $op(self, n: T) -> Self::Output { + DualQuaternion::from_real_and_dual( + self.real.clone().$op(n.clone()), + self.dual.clone().$op(n) + ) + } + } + + impl<'a, T: SimdRealField> $Op for &'a DualQuaternion + where T::Element: SimdRealField { + type Output = DualQuaternion; + + #[inline] + fn $op(self, n: T) -> Self::Output { + DualQuaternion::from_real_and_dual( + self.real.clone().$op(n.clone()), + self.dual.clone().$op(n) + ) + } + } + + impl $OpAssign for DualQuaternion + where T::Element: SimdRealField { + + #[inline] + fn $op_assign(&mut self, n: T) { + self.real.$op_assign(n.clone()); + self.dual.$op_assign(n); + } + } + )*} +); + +scalar_op_impl!( + Mul, mul, MulAssign, mul_assign; + Div, div, DivAssign, div_assign; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry.rs new file mode 100644 index 000000000..8fcb12180 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry.rs @@ -0,0 +1,569 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use std::fmt; +use std::hash; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use simba::scalar::{RealField, SubsetOf}; +use simba::simd::SimdRealField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar, Unit}; +use crate::geometry::{AbstractRotation, Point, Translation}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A direct isometry, i.e., a rotation followed by a translation (aka. a rigid-body motion). +/// +/// This is also known as an element of a Special Euclidean (SE) group. +/// The `Isometry` type can either represent a 2D or 3D isometry. +/// A 2D isometry is composed of: +/// - A translation part of type [`Translation2`](crate::Translation2) +/// - A rotation part which can either be a [`UnitComplex`](crate::UnitComplex) or a [`Rotation2`](crate::Rotation2). +/// +/// A 3D isometry is composed of: +/// - A translation part of type [`Translation3`](crate::Translation3) +/// - A rotation part which can either be a [`UnitQuaternion`](crate::UnitQuaternion) or a [`Rotation3`](crate::Rotation3). +/// +/// Note that instead of using the [`Isometry`](crate::Isometry) type in your code directly, you should use one +/// of its aliases: [`Isometry2`](crate::Isometry2), [`Isometry3`](crate::Isometry3), +/// [`IsometryMatrix2`](crate::IsometryMatrix2), [`IsometryMatrix3`](crate::IsometryMatrix3). Though +/// keep in mind that all the documentation of all the methods of these aliases will also appears on +/// this page. +/// +/// # Construction +/// * [From a 2D vector and/or an angle `new`, `translation`, `rotation`…](#construction-from-a-2d-vector-andor-a-rotation-angle) +/// * [From a 3D vector and/or an axis-angle `new`, `translation`, `rotation`…](#construction-from-a-3d-vector-andor-an-axis-angle) +/// * [From a 3D eye position and target point `look_at`, `look_at_lh`, `face_towards`…](#construction-from-a-3d-eye-position-and-target-point) +/// * [From the translation and rotation parts `from_parts`…](#from-the-translation-and-rotation-parts) +/// +/// # Transformation and composition +/// Note that transforming vectors and points can be done by multiplication, e.g., `isometry * point`. +/// Composing an isometry with another transformation can also be done by multiplication or division. +/// +/// * [Transformation of a vector or a point `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) +/// * [Inversion and in-place composition `inverse`, `append_rotation_wrt_point_mut`…](#inversion-and-in-place-composition) +/// * [Interpolation `lerp_slerp`…](#interpolation) +/// +/// # Conversion to a matrix +/// * [Conversion to a matrix `to_matrix`…](#conversion-to-a-matrix) +/// +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "R: Serialize, + DefaultAllocator: Allocator>, + Owned>: Serialize, + T: Scalar")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "R: Deserialize<'de>, + DefaultAllocator: Allocator>, + Owned>: Deserialize<'de>, + T: Scalar")) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Isometry", + bound(archive = " + T: rkyv::Archive, + R: rkyv::Archive, + Translation: rkyv::Archive> + ") + ) +)] +pub struct Isometry { + /// The pure rotational part of this isometry. + pub rotation: R, + /// The pure translational part of this isometry. + pub translation: Translation, +} + +impl hash::Hash for Isometry +where + Owned>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.translation.hash(state); + self.rotation.hash(state); + } +} + +/// # From the translation and rotation parts +impl, const D: usize> Isometry { + /// Creates a new isometry from its rotational and translational parts. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// assert_relative_eq!(iso * Point3::new(1.0, 2.0, 3.0), Point3::new(-1.0, 2.0, 0.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn from_parts(translation: Translation, rotation: R) -> Self { + Self { + rotation, + translation, + } + } +} + +/// # Inversion and in-place composition +impl, const D: usize> Isometry +where + T::Element: SimdRealField, +{ + /// Inverts `self`. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{Isometry2, Point2, Vector2}; + /// let iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// let inv = iso.inverse(); + /// let pt = Point2::new(1.0, 2.0); + /// + /// assert_eq!(inv * (iso * pt), pt); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Self { + let mut res = self.clone(); + res.inverse_mut(); + res + } + + /// Inverts `self` in-place. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{Isometry2, Point2, Vector2}; + /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// let pt = Point2::new(1.0, 2.0); + /// let transformed_pt = iso * pt; + /// iso.inverse_mut(); + /// + /// assert_eq!(iso * transformed_pt, pt); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) { + self.rotation.inverse_mut(); + self.translation.inverse_mut(); + self.translation.vector = self.rotation.transform_vector(&self.translation.vector); + } + + /// Computes `self.inverse() * rhs` in a more efficient way. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{Isometry2, Point2, Vector2}; + /// let mut iso1 = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// let mut iso2 = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_4); + /// + /// assert_eq!(iso1.inverse() * iso2, iso1.inv_mul(&iso2)); + /// ``` + #[inline] + #[must_use] + pub fn inv_mul(&self, rhs: &Isometry) -> Self { + let inv_rot1 = self.rotation.inverse(); + let tr_12 = &rhs.translation.vector - &self.translation.vector; + Isometry::from_parts( + inv_rot1.transform_vector(&tr_12).into(), + inv_rot1 * rhs.rotation.clone(), + ) + } + + /// Appends to `self` the given translation in-place. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{Isometry2, Translation2, Vector2}; + /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// let tra = Translation2::new(3.0, 4.0); + /// // Same as `iso = tra * iso`. + /// iso.append_translation_mut(&tra); + /// + /// assert_eq!(iso.translation, Translation2::new(4.0, 6.0)); + /// ``` + #[inline] + pub fn append_translation_mut(&mut self, t: &Translation) { + self.translation.vector += &t.vector + } + + /// Appends to `self` the given rotation in-place. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2}; + /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0); + /// let rot = UnitComplex::new(f32::consts::PI / 2.0); + /// // Same as `iso = rot * iso`. + /// iso.append_rotation_mut(&rot); + /// + /// assert_relative_eq!(iso, Isometry2::new(Vector2::new(-2.0, 1.0), f32::consts::PI * 2.0 / 3.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn append_rotation_mut(&mut self, r: &R) { + self.rotation = r.clone() * self.rotation.clone(); + self.translation.vector = r.transform_vector(&self.translation.vector); + } + + /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that + /// lets `p` invariant. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2}; + /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let pt = Point2::new(1.0, 0.0); + /// iso.append_rotation_wrt_point_mut(&rot, &pt); + /// + /// assert_relative_eq!(iso * pt, Point2::new(-2.0, 0.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point) { + self.translation.vector -= &p.coords; + self.append_rotation_mut(r); + self.translation.vector += &p.coords; + } + + /// Appends in-place to `self` a rotation centered at the point with coordinates + /// `self.translation`. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2}; + /// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// iso.append_rotation_wrt_center_mut(&rot); + /// + /// // The translation part should not have changed. + /// assert_eq!(iso.translation.vector, Vector2::new(1.0, 2.0)); + /// assert_eq!(iso.rotation, UnitComplex::new(f32::consts::PI)); + /// ``` + #[inline] + pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { + self.rotation = r.clone() * self.rotation.clone(); + } +} + +/// # Transformation of a vector or a point +impl, const D: usize> Isometry +where + T::Element: SimdRealField, +{ + /// Transform the given point by this isometry. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, 2.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Transform the given vector by this isometry, ignoring the translation + /// component of the isometry. + /// + /// This is the same as the multiplication `self * v`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } + + /// Transform the given point by the inverse of this isometry. This may be + /// less expensive than computing the entire isometry inverse and then + /// transforming the point. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Point3::new(0.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + self.rotation + .inverse_transform_point(&(pt - &self.translation.vector)) + } + + /// Transform the given vector by the inverse of this isometry, ignoring the + /// translation component of the isometry. This may be + /// less expensive than computing the entire isometry inverse and then + /// transforming the point. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.rotation.inverse_transform_vector(v) + } + + /// Transform the given unit vector by the inverse of this isometry, ignoring the + /// translation component of the isometry. This may be + /// less expensive than computing the entire isometry inverse and then + /// transforming the point. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::z() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.inverse_transform_unit_vector(&Vector3::x_axis()); + /// assert_relative_eq!(transformed_point, -Vector3::y_axis(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + self.rotation.inverse_transform_unit_vector(v) + } +} + +// NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation +// and makes it hard to use it, e.g., for Transform × Isometry implementation. +// This is OK since all constructors of the isometry enforce the Rotation bound already (and +// explicit struct construction is prevented by the dummy ZST field). +/// # Conversion to a matrix +impl Isometry { + /// Converts this isometry into its equivalent homogeneous transformation matrix. + /// + /// This is the same as `self.to_matrix()`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry2, Vector2, Matrix3}; + /// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6); + /// let expected = Matrix3::new(0.8660254, -0.5, 10.0, + /// 0.5, 0.8660254, 20.0, + /// 0.0, 0.0, 1.0); + /// + /// assert_relative_eq!(iso.to_homogeneous(), expected, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> + where + Const: DimNameAdd, + R: SubsetOf, U1>, DimNameSum, U1>>>, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + { + let mut res: OMatrix = crate::convert_ref(&self.rotation); + res.fixed_view_mut::(0, D) + .copy_from(&self.translation.vector); + + res + } + + /// Converts this isometry into its equivalent homogeneous transformation matrix. + /// + /// This is the same as `self.to_homogeneous()`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry2, Vector2, Matrix3}; + /// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6); + /// let expected = Matrix3::new(0.8660254, -0.5, 10.0, + /// 0.5, 0.8660254, 20.0, + /// 0.0, 0.0, 1.0); + /// + /// assert_relative_eq!(iso.to_matrix(), expected, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn to_matrix(&self) -> OMatrix, U1>, DimNameSum, U1>> + where + Const: DimNameAdd, + R: SubsetOf, U1>, DimNameSum, U1>>>, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + { + self.to_homogeneous() + } +} + +impl Eq for Isometry where + R: AbstractRotation + Eq +{ +} + +impl PartialEq for Isometry +where + R: AbstractRotation + PartialEq, +{ + #[inline] + fn eq(&self, right: &Self) -> bool { + self.translation == right.translation && self.rotation == right.rotation + } +} + +impl AbsDiffEq for Isometry +where + R: AbstractRotation + AbsDiffEq, + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.translation + .abs_diff_eq(&other.translation, epsilon.clone()) + && self.rotation.abs_diff_eq(&other.rotation, epsilon) + } +} + +impl RelativeEq for Isometry +where + R: AbstractRotation + RelativeEq, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.translation + .relative_eq(&other.translation, epsilon.clone(), max_relative.clone()) + && self + .rotation + .relative_eq(&other.rotation, epsilon, max_relative) + } +} + +impl UlpsEq for Isometry +where + R: AbstractRotation + UlpsEq, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.translation + .ulps_eq(&other.translation, epsilon.clone(), max_ulps) + && self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps) + } +} + +/* + * + * Display + * + */ +impl fmt::Display for Isometry +where + R: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let precision = f.precision().unwrap_or(3); + + writeln!(f, "Isometry {{")?; + write!(f, "{:.*}", precision, self.translation)?; + write!(f, "{:.*}", precision, self.rotation)?; + writeln!(f, "}}") + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_alias.rs new file mode 100644 index 000000000..7453c3e92 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_alias.rs @@ -0,0 +1,42 @@ +use crate::geometry::{Isometry, Rotation2, Rotation3, UnitComplex, UnitQuaternion}; + +/// A 2-dimensional direct isometry using a unit complex number for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a 2D rigid-body motion, or as an element of SE(2). + +pub type Isometry2 = Isometry, 2>; + +/// A 3-dimensional direct isometry using a unit quaternion for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a rigid-body motion, or as an element of SE(3). +pub type Isometry3 = Isometry, 3>; + +/// A 2-dimensional direct isometry using a rotation matrix for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a rigid-body motion, or as an element of SE(2). +pub type IsometryMatrix2 = Isometry, 2>; + +/// A 3-dimensional direct isometry using a rotation matrix for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a rigid-body motion, or as an element of SE(3). +pub type IsometryMatrix3 = Isometry, 3>; + +// This tests that the types correctly implement `Copy`, without having to run tests +// (when targeting no-std for example). +#[allow(dead_code)] +fn ensure_copy() { + fn is_copy() {} + + is_copy::>(); + is_copy::>(); + is_copy::>(); + is_copy::>(); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_construction.rs new file mode 100644 index 000000000..a061225bd --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_construction.rs @@ -0,0 +1,477 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::One; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use simba::scalar::SupersetOf; +use simba::simd::SimdRealField; + +use crate::base::{Vector2, Vector3}; + +use crate::{ + AbstractRotation, Isometry, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Point, + Point3, Rotation, Rotation3, Scalar, Translation, Translation2, Translation3, UnitComplex, + UnitQuaternion, +}; + +impl, const D: usize> Default for Isometry +where + T::Element: SimdRealField, +{ + fn default() -> Self { + Self::identity() + } +} + +impl, const D: usize> Isometry +where + T::Element: SimdRealField, +{ + /// Creates a new identity isometry. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Isometry2, Point2, Isometry3, Point3}; + /// + /// let iso = Isometry2::identity(); + /// let pt = Point2::new(1.0, 2.0); + /// assert_eq!(iso * pt, pt); + /// + /// let iso = Isometry3::identity(); + /// let pt = Point3::new(1.0, 2.0, 3.0); + /// assert_eq!(iso * pt, pt); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::from_parts(Translation::identity(), R::identity()) + } + + /// The isometry that applies the rotation `r` with its axis passing through the point `p`. + /// This effectively lets `p` invariant. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry2, Point2, UnitComplex}; + /// let rot = UnitComplex::new(f32::consts::PI); + /// let pt = Point2::new(1.0, 0.0); + /// let iso = Isometry2::rotation_wrt_point(rot, pt); + /// + /// assert_eq!(iso * pt, pt); // The rotation center is not affected. + /// assert_relative_eq!(iso * Point2::new(1.0, 2.0), Point2::new(1.0, -2.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn rotation_wrt_point(r: R, p: Point) -> Self { + let shift = r.transform_vector(&-&p.coords); + Self::from_parts(Translation::from(shift + p.coords), r) + } +} + +impl, const D: usize> One for Isometry +where + T::Element: SimdRealField, +{ + /// Creates a new identity isometry. + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + R: AbstractRotation, + Standard: Distribution + Distribution, +{ + #[inline] + fn sample(&self, rng: &mut G) -> Isometry { + Isometry::from_parts(rng.gen(), rng.gen()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Isometry +where + T: SimdRealField + Arbitrary + Send, + T::Element: SimdRealField, + R: AbstractRotation + Arbitrary + Send, + Owned>: Send, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng)) + } +} + +/* + * + * Constructors for various static dimensions. + * + */ + +/// # Construction from a 2D vector and/or a rotation angle +impl IsometryMatrix2 +where + T::Element: SimdRealField, +{ + /// Creates a new 2D isometry from a translation and a rotation angle. + /// + /// Its rotational part is represented as a 2x2 rotation matrix. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{Isometry2, Vector2, Point2}; + /// let iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// + /// assert_eq!(iso * Point2::new(3.0, 4.0), Point2::new(-3.0, 5.0)); + /// ``` + #[inline] + pub fn new(translation: Vector2, angle: T) -> Self { + Self::from_parts(Translation::from(translation), Rotation::::new(angle)) + } + + /// Creates a new isometry from the given translation coordinates. + #[inline] + pub fn translation(x: T, y: T) -> Self { + Self::new(Vector2::new(x, y), T::zero()) + } + + /// Creates a new isometry from the given rotation angle. + #[inline] + pub fn rotation(angle: T) -> Self { + Self::new(Vector2::zeros(), angle) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::IsometryMatrix2; + /// let iso = IsometryMatrix2::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, IsometryMatrix2::::identity()); + /// ``` + pub fn cast(self) -> IsometryMatrix2 + where + IsometryMatrix2: SupersetOf, + { + crate::convert(self) + } +} + +impl Isometry2 +where + T::Element: SimdRealField, +{ + /// Creates a new 2D isometry from a translation and a rotation angle. + /// + /// Its rotational part is represented as an unit complex number. + /// + /// # Example + /// + /// ``` + /// # use std::f32; + /// # use nalgebra::{IsometryMatrix2, Point2, Vector2}; + /// let iso = IsometryMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2); + /// + /// assert_eq!(iso * Point2::new(3.0, 4.0), Point2::new(-3.0, 5.0)); + /// ``` + #[inline] + pub fn new(translation: Vector2, angle: T) -> Self { + Self::from_parts( + Translation::from(translation), + UnitComplex::from_angle(angle), + ) + } + + /// Creates a new isometry from the given translation coordinates. + #[inline] + pub fn translation(x: T, y: T) -> Self { + Self::from_parts(Translation2::new(x, y), UnitComplex::identity()) + } + + /// Creates a new isometry from the given rotation angle. + #[inline] + pub fn rotation(angle: T) -> Self { + Self::new(Vector2::zeros(), angle) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Isometry2; + /// let iso = Isometry2::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, Isometry2::::identity()); + /// ``` + pub fn cast(self) -> Isometry2 + where + Isometry2: SupersetOf, + { + crate::convert(self) + } +} + +// 3D rotation. +macro_rules! basic_isometry_construction_impl( + ($RotId: ident < $($RotParams: ident),*>) => { + /// Creates a new isometry from a translation and a rotation axis-angle. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// + /// // Isometry with its rotation part represented as a UnitQuaternion + /// let iso = Isometry3::new(translation, axisangle); + /// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6); + /// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // Isometry with its rotation part represented as a Rotation3 (a 3x3 rotation matrix). + /// let iso = IsometryMatrix3::new(translation, axisangle); + /// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6); + /// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn new(translation: Vector3, axisangle: Vector3) -> Self { + Self::from_parts( + Translation::from(translation), + $RotId::<$($RotParams),*>::from_scaled_axis(axisangle)) + } + + /// Creates a new isometry from the given translation coordinates. + #[inline] + pub fn translation(x: T, y: T, z: T) -> Self { + Self::from_parts(Translation3::new(x, y, z), $RotId::identity()) + } + + /// Creates a new isometry from the given rotation angle. + #[inline] + pub fn rotation(axisangle: Vector3) -> Self { + Self::new(Vector3::zeros(), axisangle) + } + } +); + +macro_rules! look_at_isometry_construction_impl( + ($RotId: ident < $($RotParams: ident),*>) => { + /// Creates an isometry that corresponds to the local frame of an observer standing at the + /// point `eye` and looking toward `target`. + /// + /// It maps the `z` axis to the view direction `target - eye`and the origin to the `eye`. + /// + /// # Arguments + /// * eye - The observer position. + /// * target - The target position. + /// * up - Vertical direction. The only requirement of this parameter is to not be collinear + /// to `eye - at`. Non-collinearity is not checked. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; + /// let eye = Point3::new(1.0, 2.0, 3.0); + /// let target = Point3::new(2.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// // Isometry with its rotation part represented as a UnitQuaternion + /// let iso = Isometry3::face_towards(&eye, &target, &up); + /// assert_eq!(iso * Point3::origin(), eye); + /// assert_relative_eq!(iso * Vector3::z(), Vector3::x()); + /// + /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix). + /// let iso = IsometryMatrix3::face_towards(&eye, &target, &up); + /// assert_eq!(iso * Point3::origin(), eye); + /// assert_relative_eq!(iso * Vector3::z(), Vector3::x()); + /// ``` + #[inline] + pub fn face_towards(eye: &Point3, + target: &Point3, + up: &Vector3) + -> Self { + Self::from_parts( + Translation::from(eye.coords.clone()), + $RotId::face_towards(&(target - eye), up)) + } + + /// Deprecated: Use [`Isometry::face_towards`] instead. + #[deprecated(note="renamed to `face_towards`")] + pub fn new_observer_frame(eye: &Point3, + target: &Point3, + up: &Vector3) + -> Self { + Self::face_towards(eye, target, up) + } + + /// Builds a right-handed look-at view matrix. + /// + /// It maps the view direction `target - eye` to the **negative** `z` axis to and the `eye` to the origin. + /// This conforms to the common notion of right handed camera look-at **view matrix** from + /// the computer graphics community, i.e. the camera is assumed to look toward its local `-z` axis. + /// + /// # Arguments + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; + /// let eye = Point3::new(1.0, 2.0, 3.0); + /// let target = Point3::new(2.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// // Isometry with its rotation part represented as a UnitQuaternion + /// let iso = Isometry3::look_at_rh(&eye, &target, &up); + /// assert_eq!(iso * eye, Point3::origin()); + /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z()); + /// + /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix). + /// let iso = IsometryMatrix3::look_at_rh(&eye, &target, &up); + /// assert_eq!(iso * eye, Point3::origin()); + /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z()); + /// ``` + #[inline] + pub fn look_at_rh(eye: &Point3, + target: &Point3, + up: &Vector3) + -> Self { + let rotation = $RotId::look_at_rh(&(target - eye), up); + let trans = &rotation * (-eye); + + Self::from_parts(Translation::from(trans.coords), rotation) + } + + /// Builds a left-handed look-at view matrix. + /// + /// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin. + /// This conforms to the common notion of left handed camera look-at **view matrix** from + /// the computer graphics community, i.e. the camera is assumed to look toward its local `z` axis. + /// + /// # Arguments + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3}; + /// let eye = Point3::new(1.0, 2.0, 3.0); + /// let target = Point3::new(2.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// // Isometry with its rotation part represented as a UnitQuaternion + /// let iso = Isometry3::look_at_lh(&eye, &target, &up); + /// assert_eq!(iso * eye, Point3::origin()); + /// assert_relative_eq!(iso * Vector3::x(), Vector3::z()); + /// + /// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix). + /// let iso = IsometryMatrix3::look_at_lh(&eye, &target, &up); + /// assert_eq!(iso * eye, Point3::origin()); + /// assert_relative_eq!(iso * Vector3::x(), Vector3::z()); + /// ``` + #[inline] + pub fn look_at_lh(eye: &Point3, + target: &Point3, + up: &Vector3) + -> Self { + let rotation = $RotId::look_at_lh(&(target - eye), up); + let trans = &rotation * (-eye); + + Self::from_parts(Translation::from(trans.coords), rotation) + } + } +); + +/// # Construction from a 3D vector and/or an axis-angle +impl Isometry3 +where + T::Element: SimdRealField, +{ + basic_isometry_construction_impl!(UnitQuaternion); + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Isometry3; + /// let iso = Isometry3::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, Isometry3::::identity()); + /// ``` + pub fn cast(self) -> Isometry3 + where + Isometry3: SupersetOf, + { + crate::convert(self) + } +} + +impl IsometryMatrix3 +where + T::Element: SimdRealField, +{ + basic_isometry_construction_impl!(Rotation3); + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::IsometryMatrix3; + /// let iso = IsometryMatrix3::::identity(); + /// let iso2 = iso.cast::(); + /// assert_eq!(iso2, IsometryMatrix3::::identity()); + /// ``` + pub fn cast(self) -> IsometryMatrix3 + where + IsometryMatrix3: SupersetOf, + { + crate::convert(self) + } +} + +/// # Construction from a 3D eye position and target point +impl Isometry3 +where + T::Element: SimdRealField, +{ + look_at_isometry_construction_impl!(UnitQuaternion); +} + +impl IsometryMatrix3 +where + T::Element: SimdRealField, +{ + look_at_isometry_construction_impl!(Rotation3); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_conversion.rs new file mode 100644 index 000000000..266aa050d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_conversion.rs @@ -0,0 +1,356 @@ +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimMin, DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix, Scalar}; + +use crate::geometry::{ + AbstractRotation, Isometry, Isometry3, Similarity, SuperTCategoryOf, TAffine, Transform, + Translation, UnitDualQuaternion, UnitQuaternion, +}; +use crate::{ArrayStorage, Point, SVector}; + +/* + * This file provides the following conversions: + * ============================================= + * + * Isometry -> Isometry + * Isometry3 -> UnitDualQuaternion + * Isometry -> Similarity + * Isometry -> Transform + * Isometry -> Matrix (homogeneous) + */ + +impl SubsetOf> for Isometry +where + T1: RealField, + T2: RealField + SupersetOf, + R1: AbstractRotation + SubsetOf, + R2: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Isometry { + Isometry::from_parts(self.translation.to_superset(), self.rotation.to_superset()) + } + + #[inline] + fn is_in_subset(iso: &Isometry) -> bool { + crate::is_convertible::<_, Translation>(&iso.translation) + && crate::is_convertible::<_, R1>(&iso.rotation) + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry) -> Self { + Isometry::from_parts( + iso.translation.to_subset_unchecked(), + iso.rotation.to_subset_unchecked(), + ) + } +} + +impl SubsetOf> for Isometry3 +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitDualQuaternion { + let dq = UnitDualQuaternion::::from_isometry(self); + dq.to_superset() + } + + #[inline] + fn is_in_subset(dq: &UnitDualQuaternion) -> bool { + crate::is_convertible::<_, UnitQuaternion>(&dq.rotation()) + && crate::is_convertible::<_, Translation>(&dq.translation()) + } + + #[inline] + fn from_superset_unchecked(dq: &UnitDualQuaternion) -> Self { + let dq: UnitDualQuaternion = crate::convert_ref_unchecked(dq); + dq.to_isometry() + } +} + +impl SubsetOf> for Isometry +where + T1: RealField, + T2: RealField + SupersetOf, + R1: AbstractRotation + SubsetOf, + R2: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_isometry(self.to_superset(), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + crate::is_convertible::<_, Isometry>(&sim.isometry) && sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + crate::convert_ref_unchecked(&sim.isometry) + } +} + +impl SubsetOf> for Isometry +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, + R: AbstractRotation + + SubsetOf, U1>, DimNameSum, U1>>> + + SubsetOf, U1>, DimNameSum, U1>>>, + Const: DimNameAdd + DimMin, Output = Const>, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + // + Allocator + // + Allocator + // + Allocator + // + Allocator +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> for Isometry +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + + SubsetOf, U1>, DimNameSum, U1>>> + + SubsetOf, U1>, DimNameSum, U1>>>, + Const: DimNameAdd + DimMin, Output = Const>, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator, Const<1>, Buffer = ArrayStorage> + + Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + let rot = m.fixed_view::(0, 0); + let bottom = m.fixed_view::<1, D>(D, 0); + + // Scalar types agree. + m.iter().all(|e| SupersetOf::::is_in_subset(e)) && + // The block part is a rotation. + rot.is_special_orthogonal(T2::default_epsilon() * crate::convert(100.0)) && + // The bottom row is (0, 0, ..., 1) + bottom.iter().all(|e| e.is_zero()) && m[(D, D)] == T2::one() + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + let t = m.fixed_view::(0, D).into_owned(); + let t = Translation { + vector: crate::convert_unchecked(t), + }; + + Self::from_parts(t, crate::convert_unchecked(m.clone_owned())) + } +} + +impl, const D: usize> From> + for Isometry +{ + #[inline] + fn from(tra: Translation) -> Self { + Self::from_parts(tra, R::identity()) + } +} + +impl From> + for OMatrix, U1>, DimNameSum, U1>> +where + Const: DimNameAdd, + R: SubsetOf, U1>, DimNameSum, U1>>>, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, // + Allocator, +{ + #[inline] + fn from(iso: Isometry) -> Self { + iso.to_homogeneous() + } +} + +impl From<[T; D]> for Isometry +where + R: AbstractRotation, +{ + #[inline] + fn from(coords: [T; D]) -> Self { + Self::from_parts(coords.into(), R::identity()) + } +} + +impl From> for Isometry +where + R: AbstractRotation, +{ + #[inline] + fn from(coords: SVector) -> Self { + Self::from_parts(coords.into(), R::identity()) + } +} +impl From> for Isometry +where + R: AbstractRotation, +{ + #[inline] + fn from(coords: Point) -> Self { + Self::from_parts(coords.into(), R::identity()) + } +} + +impl + From<[Isometry; 2]> for Isometry +where + T: From<[::Element; 2]>, + R: SimdValue + AbstractRotation + From<[::Element; 2]>, + R::Element: AbstractRotation, + T::Element: Scalar + Copy, + R::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Isometry; 2]) -> Self { + let tra = Translation::from([arr[0].translation, arr[1].translation]); + let rot = R::from([arr[0].rotation, arr[0].rotation]); + + Self::from_parts(tra, rot) + } +} + +impl + From<[Isometry; 4]> for Isometry +where + T: From<[::Element; 4]>, + R: SimdValue + AbstractRotation + From<[::Element; 4]>, + R::Element: AbstractRotation, + T::Element: Scalar + Copy, + R::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Isometry; 4]) -> Self { + let tra = Translation::from([ + arr[0].translation, + arr[1].translation, + arr[2].translation, + arr[3].translation, + ]); + let rot = R::from([ + arr[0].rotation, + arr[1].rotation, + arr[2].rotation, + arr[3].rotation, + ]); + + Self::from_parts(tra, rot) + } +} + +impl + From<[Isometry; 8]> for Isometry +where + T: From<[::Element; 8]>, + R: SimdValue + AbstractRotation + From<[::Element; 8]>, + R::Element: AbstractRotation, + T::Element: Scalar + Copy, + R::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Isometry; 8]) -> Self { + let tra = Translation::from([ + arr[0].translation, + arr[1].translation, + arr[2].translation, + arr[3].translation, + arr[4].translation, + arr[5].translation, + arr[6].translation, + arr[7].translation, + ]); + let rot = R::from([ + arr[0].rotation, + arr[1].rotation, + arr[2].rotation, + arr[3].rotation, + arr[4].rotation, + arr[5].rotation, + arr[6].rotation, + arr[7].rotation, + ]); + + Self::from_parts(tra, rot) + } +} + +impl + From<[Isometry; 16]> for Isometry +where + T: From<[::Element; 16]>, + R: SimdValue + AbstractRotation + From<[::Element; 16]>, + R::Element: AbstractRotation, + T::Element: Scalar + Copy, + R::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Isometry; 16]) -> Self { + let tra = Translation::from([ + arr[0].translation, + arr[1].translation, + arr[2].translation, + arr[3].translation, + arr[4].translation, + arr[5].translation, + arr[6].translation, + arr[7].translation, + arr[8].translation, + arr[9].translation, + arr[10].translation, + arr[11].translation, + arr[12].translation, + arr[13].translation, + arr[14].translation, + arr[15].translation, + ]); + let rot = R::from([ + arr[0].rotation, + arr[1].rotation, + arr[2].rotation, + arr[3].rotation, + arr[4].rotation, + arr[5].rotation, + arr[6].rotation, + arr[7].rotation, + arr[8].rotation, + arr[9].rotation, + arr[10].rotation, + arr[11].rotation, + arr[12].rotation, + arr[13].rotation, + arr[14].rotation, + arr[15].rotation, + ]); + + Self::from_parts(tra, rot) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_interpolation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_interpolation.rs new file mode 100644 index 000000000..b0bf89df8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_interpolation.rs @@ -0,0 +1,234 @@ +use crate::{Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, RealField, SimdRealField}; + +/// # Interpolation +impl Isometry3 { + /// Interpolates between two isometries using a linear interpolation for the translation part, + /// and a spherical interpolation for the rotation part. + /// + /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion}; + /// + /// let t1 = Translation3::new(1.0, 2.0, 3.0); + /// let t2 = Translation3::new(4.0, 8.0, 12.0); + /// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0); + /// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0); + /// let iso1 = Isometry3::from_parts(t1, q1); + /// let iso2 = Isometry3::from_parts(t2, q2); + /// + /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0); + /// + /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0)); + /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn lerp_slerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + let tr = self + .translation + .vector + .lerp(&other.translation.vector, t.clone()); + let rot = self.rotation.slerp(&other.rotation, t); + Self::from_parts(tr.into(), rot) + } + + /// Attempts to interpolate between two isometries using a linear interpolation for the translation part, + /// and a spherical interpolation for the rotation part. + /// + /// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion}; + /// + /// let t1 = Translation3::new(1.0, 2.0, 3.0); + /// let t2 = Translation3::new(4.0, 8.0, 12.0); + /// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0); + /// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0); + /// let iso1 = Isometry3::from_parts(t1, q1); + /// let iso2 = Isometry3::from_parts(t2, q2); + /// + /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0); + /// + /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0)); + /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option + where + T: RealField, + { + let tr = self + .translation + .vector + .lerp(&other.translation.vector, t.clone()); + let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?; + Some(Self::from_parts(tr.into(), rot)) + } +} + +impl IsometryMatrix3 { + /// Interpolates between two isometries using a linear interpolation for the translation part, + /// and a spherical interpolation for the rotation part. + /// + /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3}; + /// + /// let t1 = Translation3::new(1.0, 2.0, 3.0); + /// let t2 = Translation3::new(4.0, 8.0, 12.0); + /// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0); + /// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0); + /// let iso1 = IsometryMatrix3::from_parts(t1, q1); + /// let iso2 = IsometryMatrix3::from_parts(t2, q2); + /// + /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0); + /// + /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0)); + /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn lerp_slerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + let tr = self + .translation + .vector + .lerp(&other.translation.vector, t.clone()); + let rot = self.rotation.slerp(&other.rotation, t); + Self::from_parts(tr.into(), rot) + } + + /// Attempts to interpolate between two isometries using a linear interpolation for the translation part, + /// and a spherical interpolation for the rotation part. + /// + /// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3}; + /// + /// let t1 = Translation3::new(1.0, 2.0, 3.0); + /// let t2 = Translation3::new(4.0, 8.0, 12.0); + /// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0); + /// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0); + /// let iso1 = IsometryMatrix3::from_parts(t1, q1); + /// let iso2 = IsometryMatrix3::from_parts(t2, q2); + /// + /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0); + /// + /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0)); + /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option + where + T: RealField, + { + let tr = self + .translation + .vector + .lerp(&other.translation.vector, t.clone()); + let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?; + Some(Self::from_parts(tr.into(), rot)) + } +} + +impl Isometry2 { + /// Interpolates between two isometries using a linear interpolation for the translation part, + /// and a spherical interpolation for the rotation part. + /// + /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector2, Translation2, UnitComplex, Isometry2}; + /// + /// let t1 = Translation2::new(1.0, 2.0); + /// let t2 = Translation2::new(4.0, 8.0); + /// let q1 = UnitComplex::new(std::f32::consts::FRAC_PI_4); + /// let q2 = UnitComplex::new(-std::f32::consts::PI); + /// let iso1 = Isometry2::from_parts(t1, q1); + /// let iso2 = Isometry2::from_parts(t2, q2); + /// + /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0); + /// + /// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0)); + /// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2); + /// ``` + #[inline] + #[must_use] + pub fn lerp_slerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + let tr = self + .translation + .vector + .lerp(&other.translation.vector, t.clone()); + let rot = self.rotation.slerp(&other.rotation, t); + Self::from_parts(tr.into(), rot) + } +} + +impl IsometryMatrix2 { + /// Interpolates between two isometries using a linear interpolation for the translation part, + /// and a spherical interpolation for the rotation part. + /// + /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector2, Translation2, Rotation2, IsometryMatrix2}; + /// + /// let t1 = Translation2::new(1.0, 2.0); + /// let t2 = Translation2::new(4.0, 8.0); + /// let q1 = Rotation2::new(std::f32::consts::FRAC_PI_4); + /// let q2 = Rotation2::new(-std::f32::consts::PI); + /// let iso1 = IsometryMatrix2::from_parts(t1, q1); + /// let iso2 = IsometryMatrix2::from_parts(t2, q2); + /// + /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0); + /// + /// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0)); + /// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2); + /// ``` + #[inline] + #[must_use] + pub fn lerp_slerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + let tr = self + .translation + .vector + .lerp(&other.translation.vector, t.clone()); + let rot = self.rotation.slerp(&other.rotation, t); + Self::from_parts(tr.into(), rot) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_ops.rs new file mode 100644 index 000000000..14319fd0b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_ops.rs @@ -0,0 +1,536 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +use num::{One, Zero}; +use std::ops::{Div, DivAssign, Mul, MulAssign}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; +use simba::simd::SimdRealField; + +use crate::base::{SVector, Unit}; +use crate::Scalar; + +use crate::geometry::{ + AbstractRotation, Isometry, Point, Rotation, Translation, UnitComplex, UnitQuaternion, +}; + +// TODO: there are several cloning of rotations that we could probably get rid of (but we didn't +// yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` +// which is quite ugly. + +/* + * + * In this file, we provide: + * ========================= + * + * + * (Operators) + * + * Isometry × Isometry + * Isometry × R + * + * + * Isometry ÷ Isometry + * Isometry ÷ R + * + * Isometry × Point + * Isometry × Vector + * Isometry × Unit + * + * + * Isometry × Translation + * Translation × Isometry + * Translation × R -> Isometry + * + * NOTE: The following are provided explicitly because we can't have R × Isometry. + * Rotation × Isometry + * UnitQuaternion × Isometry + * + * Rotation ÷ Isometry + * UnitQuaternion ÷ Isometry + * + * Rotation × Translation -> Isometry + * UnitQuaternion × Translation -> Isometry + * + * + * (Assignment Operators) + * + * Isometry ×= Translation + * + * Isometry ×= Isometry + * Isometry ×= R + * + * Isometry ÷= Isometry + * Isometry ÷= R + * + */ + +macro_rules! isometry_binop_impl( + ($Op: ident, $op: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField, R, const D: usize> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField, + R: AbstractRotation, { + type Output = $Output; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +macro_rules! isometry_binop_impl_all( + ($Op: ident, $op: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + [val val] => $action_val_val: expr; + [ref val] => $action_ref_val: expr; + [val ref] => $action_val_ref: expr; + [ref ref] => $action_ref_ref: expr;) => { + isometry_binop_impl!( + $Op, $op; + $lhs: $Lhs, $rhs: $Rhs, Output = $Output; + $action_val_val; ); + + isometry_binop_impl!( + $Op, $op; + $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Output; + $action_ref_val; 'a); + + isometry_binop_impl!( + $Op, $op; + $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_val_ref; 'b); + + isometry_binop_impl!( + $Op, $op; + $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_ref_ref; 'a, 'b); + } +); + +macro_rules! isometry_binop_assign_impl_all( + ($OpAssign: ident, $op_assign: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; + [val] => $action_val: expr; + [ref] => $action_ref: expr;) => { + impl $OpAssign<$Rhs> for $Lhs + where T::Element: SimdRealField, + R: AbstractRotation { + #[inline] + fn $op_assign(&mut $lhs, $rhs: $Rhs) { + $action_val + } + } + + impl<'b, T: SimdRealField, R, const D: usize> $OpAssign<&'b $Rhs> for $Lhs + where T::Element: SimdRealField, + R: AbstractRotation { + #[inline] + fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { + $action_ref + } + } + } +); + +// Isometry × Isometry +// Isometry ÷ Isometry +isometry_binop_impl_all!( + Mul, mul; + self: Isometry, rhs: Isometry, Output = Isometry; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let shift = self.rotation.transform_vector(&rhs.translation.vector); + + #[allow(clippy::suspicious_arithmetic_impl)] + Isometry::from_parts(Translation::from(&self.translation.vector + shift), + self.rotation.clone() * rhs.rotation.clone()) // TODO: too bad we have to clone. + }; +); + +isometry_binop_impl_all!( + Div, div; + self: Isometry, rhs: Isometry, Output = Isometry; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// Isometry ×= Translation +isometry_binop_assign_impl_all!( + MulAssign, mul_assign; + self: Isometry, rhs: Translation; + [val] => *self *= &rhs; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { + let shift = self.rotation.transform_vector(&rhs.vector); + self.translation.vector += shift; + }; +); + +// Isometry ×= Isometry +// Isometry ÷= Isometry +isometry_binop_assign_impl_all!( + MulAssign, mul_assign; + self: Isometry, rhs: Isometry; + [val] => *self *= &rhs; + [ref] => { + let shift = self.rotation.transform_vector(&rhs.translation.vector); + self.translation.vector += shift; + self.rotation *= rhs.rotation.clone(); + }; +); + +isometry_binop_assign_impl_all!( + DivAssign, div_assign; + self: Isometry, rhs: Isometry; + [val] => *self /= &rhs; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Isometry ×= R +// Isometry ÷= R +md_assign_impl_all!( + MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField; + (Const, U1), (Const, Const) + const D; for; where; + self: Isometry, D>, rhs: Rotation; + [val] => self.rotation *= rhs; + [ref] => self.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField; + (Const, U1), (Const, Const) + const D; for; where; + self: Isometry, D>, rhs: Rotation; + // TODO: don't invert explicitly? + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +md_assign_impl_all!( + MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField; + (U3, U3), (U3, U3) + const; for; where; + self: Isometry, 3>, rhs: UnitQuaternion; + [val] => self.rotation *= rhs; + [ref] => self.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField; + (U3, U3), (U3, U3) + const; for; where; + self: Isometry, 3>, rhs: UnitQuaternion; + // TODO: don't invert explicitly? + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +md_assign_impl_all!( + MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField; + (U2, U2), (U2, U2) + const; for; where; + self: Isometry, 2>, rhs: UnitComplex; + [val] => self.rotation *= rhs; + [ref] => self.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField; + (U2, U2), (U2, U2) + const; for; where; + self: Isometry, 2>, rhs: UnitComplex; + // TODO: don't invert explicitly? + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Isometry × Point +isometry_binop_impl_all!( + Mul, mul; + self: Isometry, right: Point, Output = Point; + [val val] => self.translation * self.rotation.transform_point(&right); + [ref val] => &self.translation * self.rotation.transform_point(&right); + [val ref] => self.translation * self.rotation.transform_point(right); + [ref ref] => &self.translation * self.rotation.transform_point(right); +); + +// Isometry × Vector +isometry_binop_impl_all!( + Mul, mul; + // TODO: because of `transform_vector`, we cant use a generic storage type for the rhs vector, + // i.e., right: Vector where S: Storage. + self: Isometry, right: SVector, Output = SVector; + [val val] => self.rotation.transform_vector(&right); + [ref val] => self.rotation.transform_vector(&right); + [val ref] => self.rotation.transform_vector(right); + [ref ref] => self.rotation.transform_vector(right); +); + +// Isometry × Unit +isometry_binop_impl_all!( + Mul, mul; + // TODO: because of `transform_vector`, we cant use a generic storage type for the rhs vector, + // i.e., right: Vector where S: Storage. + self: Isometry, right: Unit>, Output = Unit>; + [val val] => Unit::new_unchecked(self.rotation.transform_vector(right.as_ref())); + [ref val] => Unit::new_unchecked(self.rotation.transform_vector(right.as_ref())); + [val ref] => Unit::new_unchecked(self.rotation.transform_vector(right.as_ref())); + [ref ref] => Unit::new_unchecked(self.rotation.transform_vector(right.as_ref())); +); + +// Isometry × Translation +isometry_binop_impl_all!( + Mul, mul; + self: Isometry, right: Translation, Output = Isometry; + [val val] => &self * &right; + [ref val] => self * &right; + [val ref] => &self * right; + [ref ref] => { + #[allow(clippy::suspicious_arithmetic_impl)] + let new_tr = &self.translation.vector + self.rotation.transform_vector(&right.vector); + Isometry::from_parts(Translation::from(new_tr), self.rotation.clone()) + }; +); + +// Translation × Isometry +isometry_binop_impl_all!( + Mul, mul; + self: Translation, right: Isometry, Output = Isometry; + [val val] => Isometry::from_parts(self * right.translation, right.rotation); + [ref val] => Isometry::from_parts(self * &right.translation, right.rotation); + [val ref] => Isometry::from_parts(self * &right.translation, right.rotation.clone()); + [ref ref] => Isometry::from_parts(self * &right.translation, right.rotation.clone()); +); + +macro_rules! isometry_from_composition_impl( + ($Op: ident, $op: ident; + $($Dims: ident),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField $(, const $Dims: usize)*> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField { + type Output = $Output; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +macro_rules! isometry_from_composition_impl_all( + ($Op: ident, $op: ident; + $($Dims: ident),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + [val val] => $action_val_val: expr; + [ref val] => $action_ref_val: expr; + [val ref] => $action_val_ref: expr; + [ref ref] => $action_ref_ref: expr;) => { + + isometry_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: $Lhs, $rhs: $Rhs, Output = $Output; + $action_val_val; ); + + isometry_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Output; + $action_ref_val; 'a); + + isometry_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_val_ref; 'b); + + isometry_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_ref_ref; 'a, 'b); + } +); + +// Rotation × Translation +isometry_from_composition_impl_all!( + Mul, mul; + D; + self: Rotation, right: Translation, Output = Isometry, D>; + [val val] => Isometry::from_parts(Translation::from(&self * right.vector), self); + [ref val] => Isometry::from_parts(Translation::from(self * right.vector), self.clone()); + [val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self); + [ref ref] => Isometry::from_parts(Translation::from(self * &right.vector), self.clone()); +); + +// UnitQuaternion × Translation +isometry_from_composition_impl_all!( + Mul, mul; + ; + self: UnitQuaternion, right: Translation, + Output = Isometry, 3>; + [val val] => Isometry::from_parts(Translation::from(&self * right.vector), self); + [ref val] => Isometry::from_parts(Translation::from( self * right.vector), self.clone()); + [val ref] => Isometry::from_parts(Translation::from(&self * &right.vector), self); + [ref ref] => Isometry::from_parts(Translation::from( self * &right.vector), self.clone()); +); + +// Isometry × Rotation +isometry_from_composition_impl_all!( + Mul, mul; + D; + self: Isometry, D>, rhs: Rotation, + Output = Isometry, D>; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +); + +// Rotation × Isometry +isometry_from_composition_impl_all!( + Mul, mul; + D; + self: Rotation, right: Isometry, D>, + Output = Isometry, D>; + [val val] => &self * &right; + [ref val] => self * &right; + [val ref] => &self * right; + [ref ref] => { + let shift = self * &right.translation.vector; + Isometry::from_parts(Translation::from(shift), self * &right.rotation) + }; +); + +// Isometry ÷ Rotation +isometry_from_composition_impl_all!( + Div, div; + D; + self: Isometry, D>, rhs: Rotation, + Output = Isometry, D>; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +); + +// Rotation ÷ Isometry +isometry_from_composition_impl_all!( + Div, div; + D; + self: Rotation, right: Isometry, D>, + Output = Isometry, D>; + // TODO: don't call inverse explicitly? + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; +); + +// Isometry × UnitQuaternion +isometry_from_composition_impl_all!( + Mul, mul; + ; + self: Isometry, 3>, rhs: UnitQuaternion, + Output = Isometry, 3>; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +); + +// UnitQuaternion × Isometry +isometry_from_composition_impl_all!( + Mul, mul; + ; + self: UnitQuaternion, right: Isometry, 3>, + Output = Isometry, 3>; + [val val] => &self * &right; + [ref val] => self * &right; + [val ref] => &self * right; + [ref ref] => { + let shift = self * &right.translation.vector; + Isometry::from_parts(Translation::from(shift), self * &right.rotation) + }; +); + +// Isometry ÷ UnitQuaternion +isometry_from_composition_impl_all!( + Div, div; + ; + self: Isometry, 3>, rhs: UnitQuaternion, + Output = Isometry, 3>; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +); + +// UnitQuaternion ÷ Isometry +isometry_from_composition_impl_all!( + Div, div; + ; + self: UnitQuaternion, right: Isometry, 3>, + Output = Isometry, 3>; + // TODO: don't call inverse explicitly? + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; +); + +// Translation × Rotation +isometry_from_composition_impl_all!( + Mul, mul; + D; + self: Translation, right: Rotation, Output = Isometry, D>; + [val val] => Isometry::from_parts(self, right); + [ref val] => Isometry::from_parts(self.clone(), right); + [val ref] => Isometry::from_parts(self, right.clone()); + [ref ref] => Isometry::from_parts(self.clone(), right.clone()); +); + +// Translation × UnitQuaternion +isometry_from_composition_impl_all!( + Mul, mul; + ; + self: Translation, right: UnitQuaternion, Output = Isometry, 3>; + [val val] => Isometry::from_parts(self, right); + [ref val] => Isometry::from_parts(self.clone(), right); + [val ref] => Isometry::from_parts(self, right.clone()); + [ref ref] => Isometry::from_parts(self.clone(), right.clone()); +); + +// Isometry × UnitComplex +isometry_from_composition_impl_all!( + Mul, mul; + ; + self: Isometry, 2>, rhs: UnitComplex, + Output = Isometry, 2>; + [val val] => Isometry::from_parts(self.translation, self.rotation * rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation * rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() * rhs.clone()); +); + +// Isometry ÷ UnitComplex +isometry_from_composition_impl_all!( + Div, div; + ; + self: Isometry, 2>, rhs: UnitComplex, + Output = Isometry, 2>; + [val val] => Isometry::from_parts(self.translation, self.rotation / rhs); + [ref val] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs); + [val ref] => Isometry::from_parts(self.translation, self.rotation / rhs.clone()); + [ref ref] => Isometry::from_parts(self.translation.clone(), self.rotation.clone() / rhs.clone()); +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_simba.rs new file mode 100644 index 000000000..75ce7b768 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/isometry_simba.rs @@ -0,0 +1,54 @@ +use simba::simd::SimdValue; + +use crate::SimdRealField; + +use crate::geometry::{AbstractRotation, Isometry, Translation}; + +impl SimdValue for Isometry +where + T::Element: SimdRealField, + R: SimdValue + AbstractRotation, + R::Element: AbstractRotation, +{ + const LANES: usize = T::LANES; + type Element = Isometry; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + Isometry::from_parts(Translation::splat(val.translation), R::splat(val.rotation)) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Isometry::from_parts(self.translation.extract(i), self.rotation.extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Isometry::from_parts( + self.translation.extract_unchecked(i), + self.rotation.extract_unchecked(i), + ) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.translation.replace(i, val.translation); + self.rotation.replace(i, val.rotation); + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.translation.replace_unchecked(i, val.translation); + self.rotation.replace_unchecked(i, val.rotation); + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Isometry::from_parts( + self.translation.select(cond, other.translation), + self.rotation.select(cond, other.rotation), + ) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/mod.rs new file mode 100644 index 000000000..c3e53478c --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/mod.rs @@ -0,0 +1,122 @@ +//! [Reexported at the root of this crate.] Data structures for points and usual transformations +//! (rotations, isometries, etc.) + +mod op_macros; + +mod abstract_rotation; + +mod point; +mod point_alias; +mod point_construction; +mod point_conversion; +mod point_coordinates; +mod point_ops; +mod point_simba; + +mod rotation; +mod rotation_alias; +mod rotation_construction; +mod rotation_conversion; +mod rotation_interpolation; +mod rotation_ops; +mod rotation_simba; // TODO: implement Rotation methods. +mod rotation_specialization; + +mod quaternion; +mod quaternion_construction; +mod quaternion_conversion; +mod quaternion_coordinates; +mod quaternion_ops; +mod quaternion_simba; + +mod dual_quaternion; +mod dual_quaternion_construction; +mod dual_quaternion_conversion; +mod dual_quaternion_ops; + +mod unit_complex; +mod unit_complex_construction; +mod unit_complex_conversion; +mod unit_complex_ops; +mod unit_complex_simba; + +mod translation; +mod translation_alias; +mod translation_construction; +mod translation_conversion; +mod translation_coordinates; +mod translation_ops; +mod translation_simba; + +mod scale; +mod scale_alias; +mod scale_construction; +mod scale_conversion; +mod scale_coordinates; +mod scale_ops; +mod scale_simba; + +mod isometry; +mod isometry_alias; +mod isometry_construction; +mod isometry_conversion; +mod isometry_interpolation; +mod isometry_ops; +mod isometry_simba; + +mod similarity; +mod similarity_alias; +mod similarity_construction; +mod similarity_conversion; +mod similarity_ops; +mod similarity_simba; + +mod swizzle; + +mod transform; +mod transform_alias; +mod transform_construction; +mod transform_conversion; +mod transform_ops; +mod transform_simba; + +mod reflection; +mod reflection_alias; + +mod orthographic; +mod perspective; + +pub use self::abstract_rotation::AbstractRotation; + +pub use self::point::*; +pub use self::point_alias::*; + +pub use self::rotation::*; +pub use self::rotation_alias::*; + +pub use self::quaternion::*; + +pub use self::dual_quaternion::*; + +pub use self::unit_complex::*; + +pub use self::translation::*; +pub use self::translation_alias::*; + +pub use self::scale::*; +pub use self::scale_alias::*; + +pub use self::isometry::*; +pub use self::isometry_alias::*; + +pub use self::similarity::*; +pub use self::similarity_alias::*; + +pub use self::transform::*; +pub use self::transform_alias::*; + +pub use self::reflection::*; +pub use self::reflection_alias::*; + +pub use self::orthographic::Orthographic3; +pub use self::perspective::Perspective3; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/op_macros.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/op_macros.rs new file mode 100644 index 000000000..291cf1088 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/op_macros.rs @@ -0,0 +1,209 @@ +#![macro_use] + +// TODO: merge with `md_impl`. +/// Macro for the implementation of multiplication and division. +macro_rules! md_impl( + ( + // Operator, operator method, and scalar bounds. + $Op: ident, $op: ident $(where T: $($ScalarBounds: ident),*)*; + // Storage dimensions, and dimension bounds. + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) + // Const type declaration + const $($D: ident),*; + // Other generic type declarations. + for $($DimsDecl: ident),*; + // Where clause. + where $($ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)*),*; + // Argument identifiers and types + output. + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; + // Operator actual implementation. + $action: expr; + // Lifetime. + $($lives: tt),*) => { + impl<$($lives ,)* T $(, $DimsDecl)* $(, const $D: usize)*> $Op<$Rhs> for $Lhs + where T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign $($(+ $ScalarBounds)*)*, + $( $ConstraintType: $ConstraintBound$(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),* + { + type Output = $Result; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +/// Macro for the implementation of multiplication and division. +/// Implements all the argument reference combinations. +macro_rules! md_impl_all( + ( + // Operator, operator method, and scalar bounds. + $Op: ident, $op: ident $(where T: $($ScalarBounds: ident),*)*; + // Storage dimensions, and dimension bounds. + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) + // Const type declaration + const $($D: ident),*; + // Other generic type declarations. + for $($DimsDecl: ident),*; + // Where clause. + where $($ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)*),*; + // Argument identifiers and types + output. + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; + // Operators actual implementations. + [val val] => $action_val_val: expr; + [ref val] => $action_ref_val: expr; + [val ref] => $action_val_ref: expr; + [ref ref] => $action_ref_ref: expr;) => { + + md_impl!( + $Op, $op $(where T: $($ScalarBounds),*)*; + ($R1, $C1),($R2, $C2) + const $($D),*; + for $($DimsDecl),*; + where $($ConstraintType: $ConstraintBound$(<$($ConstraintBoundParams $( = $EqBound )*),*>)*),*; + $lhs: $Lhs, $rhs: $Rhs, Output = $Result; + $action_val_val; ); + + md_impl!( + $Op, $op $(where T: $($ScalarBounds),*)*; + ($R1, $C1),($R2, $C2) + const $($D),*; + for $($DimsDecl),*; + where $($ConstraintType: $ConstraintBound$(<$($ConstraintBoundParams $( = $EqBound )*),*>)*),*; + $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Result; + $action_ref_val; 'a); + + md_impl!( + $Op, $op $(where T: $($ScalarBounds),*)*; + ($R1, $C1),($R2, $C2) + const $($D),*; + for $($DimsDecl),*; + where $($ConstraintType: $ConstraintBound$(<$($ConstraintBoundParams $( = $EqBound )*),*>)*),*; + $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Result; + $action_val_ref; 'b); + + md_impl!( + $Op, $op $(where T: $($ScalarBounds),*)*; + ($R1, $C1),($R2, $C2) + const $($D),*; + for $($DimsDecl),*; + where $($ConstraintType: $ConstraintBound$(<$($ConstraintBoundParams $( = $EqBound )*),*>)*),*; + $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Result; + $action_ref_ref; 'a, 'b); + } +); + +/// Macro for the implementation of assignment-multiplication and assignment-division. +macro_rules! md_assign_impl( + ( + // Operator, operator method, and scalar bounds. + $Op: ident, $op: ident $(where T: $($ScalarBounds: ident),*)* $(for T::Element: $($ElementBounds: ident),*)*; + // Storage dimensions, and dimension bounds. + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) + // Const type declaration + const $($D: ident),*; + // Other generic type declarations. + for $($DimsDecl: ident),*; + // Where clause. + where $($ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)*),*; + // Argument identifiers and types. + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; + // Actual implementation and lifetimes. + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T $(, $DimsDecl)* $(, const $D: usize)*> $Op<$Rhs> for $Lhs + where T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign $($(+ $ScalarBounds)*)*, + $($(T::Element: $ElementBounds,)*)* + $( $ConstraintType: $ConstraintBound $(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),* + { + #[inline] + fn $op(&mut $lhs, $rhs: $Rhs) { + $action + } + } + } +); + +/// Macro for the implementation of assignment-multiplication and assignment-division with and +/// without reference to the right-hand-side. +macro_rules! md_assign_impl_all( + ( + // Operator, operator method, and scalar bounds. + $Op: ident, $op: ident $(where T: $($ScalarBounds: ident),*)* $(for T::Element: $($ElementBounds: ident),*)*; + // Storage dimensions, and dimension bounds. + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) + // Const type declaration + const $($D: ident),*; + // Other generic type declarations. + for $($DimsDecl: ident),*; + // Where clause. + where $($ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)*),*; + // Argument identifiers and types. + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; + // Actual implementation and lifetimes. + [val] => $action_val: expr; + [ref] => $action_ref: expr;) => { + md_assign_impl!( + $Op, $op $(where T: $($ScalarBounds),*)* $(for T::Element: $($ElementBounds),*)*; + ($R1, $C1),($R2, $C2) + const $($D),*; + for $($DimsDecl),*; + where $($ConstraintType: $ConstraintBound$(<$($ConstraintBoundParams $( = $EqBound )*),*>)*),*; + $lhs: $Lhs, $rhs: $Rhs; + $action_val; ); + + md_assign_impl!( + $Op, $op $(where T: $($ScalarBounds),*)* $(for T::Element: $($ElementBounds),*)*; + ($R1, $C1),($R2, $C2) + const $($D),*; + for $($DimsDecl),*; + where $($ConstraintType: $ConstraintBound$(<$($ConstraintBoundParams $( = $EqBound )*),*>)*),*; + $lhs: $Lhs, $rhs: &'b $Rhs; + $action_ref; 'b); + } +); + +// TODO: merge with `as_impl`. +/// Macro for the implementation of addition and subtraction. +macro_rules! add_sub_impl( + ($Op: ident, $op: ident, $bound: ident; + ($R1: ty, $C1: ty),($R2: ty, $C2: ty) $(-> ($RRes: ty, $CRes: ty))* + // Const type declaration + const $($D: ident),*; + // Other generic type declarations. + for $($DimsDecl: ident),*; + // Where clause. + where $($ConstraintType: ty: $ConstraintBound: ident$(<$($ConstraintBoundParams: ty $( = $EqBound: ty )*),*>)*),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T $(, $DimsDecl)* $(, const $D: usize)*> $Op<$Rhs> for $Lhs + where T: Scalar + $bound, + ShapeConstraint: SameNumberOfRows<$R1, $R2 $(, Representative = $RRes)*> + + SameNumberOfColumns<$C1, $C2 $(, Representative = $CRes)*>, + $( $ConstraintType: $ConstraintBound$(<$( $ConstraintBoundParams $( = $EqBound )*),*>)* ),* { + type Output = $Result; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +// TODO: merge with `md_assign_impl`. +/// Macro for the implementation of assignment-addition and assignment-subtraction. +macro_rules! add_sub_assign_impl( + ($Op: ident, $op: ident, $bound: ident; + $(const $D: ident),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T $(, const $D: usize),*> $Op<$Rhs> for $Lhs + where T: Scalar + $bound { + #[inline] + fn $op(&mut $lhs, $rhs: $Rhs) { + $action + } + } + } +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/orthographic.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/orthographic.rs new file mode 100644 index 000000000..367658789 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/orthographic.rs @@ -0,0 +1,785 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; + +use simba::scalar::RealField; + +use crate::base::dimension::U3; +use crate::base::storage::Storage; +use crate::base::{Matrix4, Vector, Vector3}; + +use crate::geometry::{Point3, Projective3}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A 3D orthographic projection stored as a homogeneous 4x4 matrix. +#[repr(C)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Orthographic3", + bound(archive = " + T: rkyv::Archive, + Matrix4: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[derive(Copy, Clone)] +pub struct Orthographic3 { + matrix: Matrix4, +} + +impl fmt::Debug for Orthographic3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.matrix.fmt(f) + } +} + +impl PartialEq for Orthographic3 { + #[inline] + fn eq(&self, right: &Self) -> bool { + self.matrix == right.matrix + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Orthographic3 +where + T: RealField + bytemuck::Zeroable, + Matrix4: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Orthographic3 +where + T: RealField + bytemuck::Pod, + Matrix4: bytemuck::Pod, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Orthographic3 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.matrix.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: RealField + Deserialize<'a>> Deserialize<'a> for Orthographic3 { + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = Matrix4::::deserialize(deserializer)?; + + Ok(Self::from_matrix_unchecked(matrix)) + } +} + +impl Orthographic3 { + /// Wraps the given matrix to interpret it as a 3D orthographic matrix. + /// + /// It is not checked whether or not the given matrix actually represents an orthographic + /// projection. + /// + /// # Example + /// ``` + /// # use nalgebra::{Orthographic3, Point3, Matrix4}; + /// let mat = Matrix4::new( + /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0, + /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0, + /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9, + /// 0.0, 0.0, 0.0, 1.0 + /// ); + /// let proj = Orthographic3::from_matrix_unchecked(mat); + /// assert_eq!(proj, Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0)); + /// ``` + #[inline] + pub const fn from_matrix_unchecked(matrix: Matrix4) -> Self { + Self { matrix } + } +} + +impl Orthographic3 { + /// Creates a new orthographic projection matrix. + /// + /// This follows the OpenGL convention, so this will flip the `z` axis. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Orthographic3, Point3}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// // Check this projection actually transforms the view cuboid into the double-unit cube. + /// // See https://www.nalgebra.org/docs/user_guide/projections#orthographic-projection for more details. + /// let p1 = Point3::new(1.0, 2.0, -0.1); + /// let p2 = Point3::new(1.0, 2.0, -1000.0); + /// let p3 = Point3::new(1.0, 20.0, -0.1); + /// let p4 = Point3::new(1.0, 20.0, -1000.0); + /// let p5 = Point3::new(10.0, 2.0, -0.1); + /// let p6 = Point3::new(10.0, 2.0, -1000.0); + /// let p7 = Point3::new(10.0, 20.0, -0.1); + /// let p8 = Point3::new(10.0, 20.0, -1000.0); + /// + /// assert_relative_eq!(proj.project_point(&p1), Point3::new(-1.0, -1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p2), Point3::new(-1.0, -1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p3), Point3::new(-1.0, 1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p4), Point3::new(-1.0, 1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p5), Point3::new( 1.0, -1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p6), Point3::new( 1.0, -1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p7), Point3::new( 1.0, 1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0)); + /// + /// // This also works with flipped axis. In other words, we allow that + /// // `left > right`, `bottom > top`, and/or `znear > zfar`. + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// + /// assert_relative_eq!(proj.project_point(&p1), Point3::new( 1.0, 1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p2), Point3::new( 1.0, 1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p3), Point3::new( 1.0, -1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p4), Point3::new( 1.0, -1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p5), Point3::new(-1.0, 1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p6), Point3::new(-1.0, 1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p7), Point3::new(-1.0, -1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p8), Point3::new(-1.0, -1.0, -1.0)); + /// ``` + #[inline] + pub fn new(left: T, right: T, bottom: T, top: T, znear: T, zfar: T) -> Self { + let matrix = Matrix4::::identity(); + let mut res = Self::from_matrix_unchecked(matrix); + + res.set_left_and_right(left, right); + res.set_bottom_and_top(bottom, top); + res.set_znear_and_zfar(znear, zfar); + + res + } + + /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view. + #[inline] + pub fn from_fov(aspect: T, vfov: T, znear: T, zfar: T) -> Self { + assert!( + znear != zfar, + "The far plane must not be equal to the near plane." + ); + assert!( + !relative_eq!(aspect, T::zero()), + "The aspect ratio must not be zero." + ); + + let half: T = crate::convert(0.5); + let width = zfar.clone() * (vfov * half.clone()).tan(); + let height = width.clone() / aspect; + + Self::new( + -width.clone() * half.clone(), + width * half.clone(), + -height.clone() * half.clone(), + height * half, + znear, + zfar, + ) + } + + /// Retrieves the inverse of the underlying homogeneous matrix. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Orthographic3, Point3, Matrix4}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// let inv = proj.inverse(); + /// + /// assert_relative_eq!(inv * proj.as_matrix(), Matrix4::identity()); + /// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity()); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// let inv = proj.inverse(); + /// assert_relative_eq!(inv * proj.as_matrix(), Matrix4::identity()); + /// assert_relative_eq!(proj.as_matrix() * inv, Matrix4::identity()); + /// ``` + #[inline] + #[must_use] + pub fn inverse(&self) -> Matrix4 { + let mut res = self.clone().to_homogeneous(); + + let inv_m11 = T::one() / self.matrix[(0, 0)].clone(); + let inv_m22 = T::one() / self.matrix[(1, 1)].clone(); + let inv_m33 = T::one() / self.matrix[(2, 2)].clone(); + + res[(0, 0)] = inv_m11.clone(); + res[(1, 1)] = inv_m22.clone(); + res[(2, 2)] = inv_m33.clone(); + + res[(0, 3)] = -self.matrix[(0, 3)].clone() * inv_m11; + res[(1, 3)] = -self.matrix[(1, 3)].clone() * inv_m22; + res[(2, 3)] = -self.matrix[(2, 3)].clone() * inv_m33; + + res + } + + /// Computes the corresponding homogeneous matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Orthographic3, Point3, Matrix4}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// let expected = Matrix4::new( + /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0, + /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0, + /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9, + /// 0.0, 0.0, 0.0, 1.0 + /// ); + /// assert_eq!(proj.to_homogeneous(), expected); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(self) -> Matrix4 { + self.matrix + } + + /// A reference to the underlying homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Orthographic3, Point3, Matrix4}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// let expected = Matrix4::new( + /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0, + /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0, + /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9, + /// 0.0, 0.0, 0.0, 1.0 + /// ); + /// assert_eq!(*proj.as_matrix(), expected); + /// ``` + #[inline] + #[must_use] + pub fn as_matrix(&self) -> &Matrix4 { + &self.matrix + } + + /// A reference to this transformation seen as a `Projective3`. + /// + /// # Example + /// ``` + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_eq!(proj.as_projective().to_homogeneous(), proj.to_homogeneous()); + /// ``` + #[inline] + #[must_use] + pub fn as_projective(&self) -> &Projective3 { + unsafe { &*(self as *const Orthographic3 as *const Projective3) } + } + + /// This transformation seen as a `Projective3`. + /// + /// # Example + /// ``` + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_eq!(proj.to_projective().to_homogeneous(), proj.to_homogeneous()); + /// ``` + #[inline] + #[must_use] + pub fn to_projective(self) -> Projective3 { + Projective3::from_matrix_unchecked(self.matrix) + } + + /// Retrieves the underlying homogeneous matrix. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Orthographic3, Point3, Matrix4}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// let expected = Matrix4::new( + /// 2.0 / 9.0, 0.0, 0.0, -11.0 / 9.0, + /// 0.0, 2.0 / 18.0, 0.0, -22.0 / 18.0, + /// 0.0, 0.0, -2.0 / 999.9, -1000.1 / 999.9, + /// 0.0, 0.0, 0.0, 1.0 + /// ); + /// assert_eq!(proj.into_inner(), expected); + /// ``` + #[inline] + pub fn into_inner(self) -> Matrix4 { + self.matrix + } + + /// Retrieves the underlying homogeneous matrix. + /// Deprecated: Use [`Orthographic3::into_inner`] instead. + #[deprecated(note = "use `.into_inner()` instead")] + #[inline] + pub fn unwrap(self) -> Matrix4 { + self.matrix + } + + /// The left offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_relative_eq!(proj.left(), 1.0, epsilon = 1.0e-6); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// assert_relative_eq!(proj.left(), 10.0, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn left(&self) -> T { + (-T::one() - self.matrix[(0, 3)].clone()) / self.matrix[(0, 0)].clone() + } + + /// The right offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_relative_eq!(proj.right(), 10.0, epsilon = 1.0e-6); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// assert_relative_eq!(proj.right(), 1.0, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn right(&self) -> T { + (T::one() - self.matrix[(0, 3)].clone()) / self.matrix[(0, 0)].clone() + } + + /// The bottom offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_relative_eq!(proj.bottom(), 2.0, epsilon = 1.0e-6); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// assert_relative_eq!(proj.bottom(), 20.0, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn bottom(&self) -> T { + (-T::one() - self.matrix[(1, 3)].clone()) / self.matrix[(1, 1)].clone() + } + + /// The top offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_relative_eq!(proj.top(), 20.0, epsilon = 1.0e-6); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// assert_relative_eq!(proj.top(), 2.0, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn top(&self) -> T { + (T::one() - self.matrix[(1, 3)].clone()) / self.matrix[(1, 1)].clone() + } + + /// The near plane offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_relative_eq!(proj.znear(), 0.1, epsilon = 1.0e-6); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// assert_relative_eq!(proj.znear(), 1000.0, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn znear(&self) -> T { + (T::one() + self.matrix[(2, 3)].clone()) / self.matrix[(2, 2)].clone() + } + + /// The far plane offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// assert_relative_eq!(proj.zfar(), 1000.0, epsilon = 1.0e-6); + /// + /// let proj = Orthographic3::new(10.0, 1.0, 20.0, 2.0, 1000.0, 0.1); + /// assert_relative_eq!(proj.zfar(), 0.1, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn zfar(&self) -> T { + (-T::one() + self.matrix[(2, 3)].clone()) / self.matrix[(2, 2)].clone() + } + + // TODO: when we get specialization, specialize the Mul impl instead. + /// Projects a point. Faster than matrix multiplication. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Orthographic3, Point3}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// + /// let p1 = Point3::new(1.0, 2.0, -0.1); + /// let p2 = Point3::new(1.0, 2.0, -1000.0); + /// let p3 = Point3::new(1.0, 20.0, -0.1); + /// let p4 = Point3::new(1.0, 20.0, -1000.0); + /// let p5 = Point3::new(10.0, 2.0, -0.1); + /// let p6 = Point3::new(10.0, 2.0, -1000.0); + /// let p7 = Point3::new(10.0, 20.0, -0.1); + /// let p8 = Point3::new(10.0, 20.0, -1000.0); + /// + /// assert_relative_eq!(proj.project_point(&p1), Point3::new(-1.0, -1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p2), Point3::new(-1.0, -1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p3), Point3::new(-1.0, 1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p4), Point3::new(-1.0, 1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p5), Point3::new( 1.0, -1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p6), Point3::new( 1.0, -1.0, 1.0)); + /// assert_relative_eq!(proj.project_point(&p7), Point3::new( 1.0, 1.0, -1.0)); + /// assert_relative_eq!(proj.project_point(&p8), Point3::new( 1.0, 1.0, 1.0)); + /// ``` + #[inline] + #[must_use] + pub fn project_point(&self, p: &Point3) -> Point3 { + Point3::new( + self.matrix[(0, 0)].clone() * p[0].clone() + self.matrix[(0, 3)].clone(), + self.matrix[(1, 1)].clone() * p[1].clone() + self.matrix[(1, 3)].clone(), + self.matrix[(2, 2)].clone() * p[2].clone() + self.matrix[(2, 3)].clone(), + ) + } + + /// Un-projects a point. Faster than multiplication by the underlying matrix inverse. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Orthographic3, Point3}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// + /// let p1 = Point3::new(-1.0, -1.0, -1.0); + /// let p2 = Point3::new(-1.0, -1.0, 1.0); + /// let p3 = Point3::new(-1.0, 1.0, -1.0); + /// let p4 = Point3::new(-1.0, 1.0, 1.0); + /// let p5 = Point3::new( 1.0, -1.0, -1.0); + /// let p6 = Point3::new( 1.0, -1.0, 1.0); + /// let p7 = Point3::new( 1.0, 1.0, -1.0); + /// let p8 = Point3::new( 1.0, 1.0, 1.0); + /// + /// assert_relative_eq!(proj.unproject_point(&p1), Point3::new(1.0, 2.0, -0.1), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p2), Point3::new(1.0, 2.0, -1000.0), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p3), Point3::new(1.0, 20.0, -0.1), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p4), Point3::new(1.0, 20.0, -1000.0), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p5), Point3::new(10.0, 2.0, -0.1), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p6), Point3::new(10.0, 2.0, -1000.0), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p7), Point3::new(10.0, 20.0, -0.1), epsilon = 1.0e-6); + /// assert_relative_eq!(proj.unproject_point(&p8), Point3::new(10.0, 20.0, -1000.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn unproject_point(&self, p: &Point3) -> Point3 { + Point3::new( + (p[0].clone() - self.matrix[(0, 3)].clone()) / self.matrix[(0, 0)].clone(), + (p[1].clone() - self.matrix[(1, 3)].clone()) / self.matrix[(1, 1)].clone(), + (p[2].clone() - self.matrix[(2, 3)].clone()) / self.matrix[(2, 2)].clone(), + ) + } + + // TODO: when we get specialization, specialize the Mul impl instead. + /// Projects a vector. Faster than matrix multiplication. + /// + /// Vectors are not affected by the translation part of the projection. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Orthographic3, Vector3}; + /// let proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// + /// let v1 = Vector3::x(); + /// let v2 = Vector3::y(); + /// let v3 = Vector3::z(); + /// + /// assert_relative_eq!(proj.project_vector(&v1), Vector3::x() * 2.0 / 9.0); + /// assert_relative_eq!(proj.project_vector(&v2), Vector3::y() * 2.0 / 18.0); + /// assert_relative_eq!(proj.project_vector(&v3), Vector3::z() * -2.0 / 999.9); + /// ``` + #[inline] + #[must_use] + pub fn project_vector(&self, p: &Vector) -> Vector3 + where + SB: Storage, + { + Vector3::new( + self.matrix[(0, 0)].clone() * p[0].clone(), + self.matrix[(1, 1)].clone() * p[1].clone(), + self.matrix[(2, 2)].clone() * p[2].clone(), + ) + } + + /// Sets the left offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_left(2.0); + /// assert_relative_eq!(proj.left(), 2.0, epsilon = 1.0e-6); + /// + /// // It is OK to set a left offset greater than the current right offset. + /// proj.set_left(20.0); + /// assert_relative_eq!(proj.left(), 20.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_left(&mut self, left: T) { + let right = self.right(); + self.set_left_and_right(left, right); + } + + /// Sets the right offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_right(15.0); + /// assert_relative_eq!(proj.right(), 15.0, epsilon = 1.0e-6); + /// + /// // It is OK to set a right offset smaller than the current left offset. + /// proj.set_right(-3.0); + /// assert_relative_eq!(proj.right(), -3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_right(&mut self, right: T) { + let left = self.left(); + self.set_left_and_right(left, right); + } + + /// Sets the bottom offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_bottom(8.0); + /// assert_relative_eq!(proj.bottom(), 8.0, epsilon = 1.0e-6); + /// + /// // It is OK to set a bottom offset greater than the current top offset. + /// proj.set_bottom(50.0); + /// assert_relative_eq!(proj.bottom(), 50.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_bottom(&mut self, bottom: T) { + let top = self.top(); + self.set_bottom_and_top(bottom, top); + } + + /// Sets the top offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_top(15.0); + /// assert_relative_eq!(proj.top(), 15.0, epsilon = 1.0e-6); + /// + /// // It is OK to set a top offset smaller than the current bottom offset. + /// proj.set_top(-3.0); + /// assert_relative_eq!(proj.top(), -3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_top(&mut self, top: T) { + let bottom = self.bottom(); + self.set_bottom_and_top(bottom, top); + } + + /// Sets the near plane offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_znear(8.0); + /// assert_relative_eq!(proj.znear(), 8.0, epsilon = 1.0e-6); + /// + /// // It is OK to set a znear greater than the current zfar. + /// proj.set_znear(5000.0); + /// assert_relative_eq!(proj.znear(), 5000.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_znear(&mut self, znear: T) { + let zfar = self.zfar(); + self.set_znear_and_zfar(znear, zfar); + } + + /// Sets the far plane offset of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_zfar(15.0); + /// assert_relative_eq!(proj.zfar(), 15.0, epsilon = 1.0e-6); + /// + /// // It is OK to set a zfar smaller than the current znear. + /// proj.set_zfar(-3.0); + /// assert_relative_eq!(proj.zfar(), -3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_zfar(&mut self, zfar: T) { + let znear = self.znear(); + self.set_znear_and_zfar(znear, zfar); + } + + /// Sets the view cuboid offsets along the `x` axis. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_left_and_right(7.0, 70.0); + /// assert_relative_eq!(proj.left(), 7.0, epsilon = 1.0e-6); + /// assert_relative_eq!(proj.right(), 70.0, epsilon = 1.0e-6); + /// + /// // It is also OK to have `left > right`. + /// proj.set_left_and_right(70.0, 7.0); + /// assert_relative_eq!(proj.left(), 70.0, epsilon = 1.0e-6); + /// assert_relative_eq!(proj.right(), 7.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_left_and_right(&mut self, left: T, right: T) { + assert!( + left != right, + "The left corner must not be equal to the right corner." + ); + self.matrix[(0, 0)] = crate::convert::<_, T>(2.0) / (right.clone() - left.clone()); + self.matrix[(0, 3)] = -(right.clone() + left.clone()) / (right - left); + } + + /// Sets the view cuboid offsets along the `y` axis. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_bottom_and_top(7.0, 70.0); + /// assert_relative_eq!(proj.bottom(), 7.0, epsilon = 1.0e-6); + /// assert_relative_eq!(proj.top(), 70.0, epsilon = 1.0e-6); + /// + /// // It is also OK to have `bottom > top`. + /// proj.set_bottom_and_top(70.0, 7.0); + /// assert_relative_eq!(proj.bottom(), 70.0, epsilon = 1.0e-6); + /// assert_relative_eq!(proj.top(), 7.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_bottom_and_top(&mut self, bottom: T, top: T) { + assert_ne!( + bottom, top, + "The top corner must not be equal to the bottom corner." + ); + self.matrix[(1, 1)] = crate::convert::<_, T>(2.0) / (top.clone() - bottom.clone()); + self.matrix[(1, 3)] = -(top.clone() + bottom.clone()) / (top - bottom); + } + + /// Sets the near and far plane offsets of the view cuboid. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Orthographic3; + /// let mut proj = Orthographic3::new(1.0, 10.0, 2.0, 20.0, 0.1, 1000.0); + /// proj.set_znear_and_zfar(50.0, 5000.0); + /// assert_relative_eq!(proj.znear(), 50.0, epsilon = 1.0e-6); + /// assert_relative_eq!(proj.zfar(), 5000.0, epsilon = 1.0e-6); + /// + /// // It is also OK to have `znear > zfar`. + /// proj.set_znear_and_zfar(5000.0, 0.5); + /// assert_relative_eq!(proj.znear(), 5000.0, epsilon = 1.0e-6); + /// assert_relative_eq!(proj.zfar(), 0.5, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn set_znear_and_zfar(&mut self, znear: T, zfar: T) { + assert!( + zfar != znear, + "The near-plane and far-plane must not be superimposed." + ); + self.matrix[(2, 2)] = -crate::convert::<_, T>(2.0) / (zfar.clone() - znear.clone()); + self.matrix[(2, 3)] = -(zfar.clone() + znear.clone()) / (zfar - znear); + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, +{ + /// Generate an arbitrary random variate for testing purposes. + fn sample(&self, r: &mut R) -> Orthographic3 { + use crate::base::helper; + let left = r.gen(); + let right = helper::reject_rand(r, |x: &T| *x > left); + let bottom = r.gen(); + let top = helper::reject_rand(r, |x: &T| *x > bottom); + let znear = r.gen(); + let zfar = helper::reject_rand(r, |x: &T| *x > znear); + + Orthographic3::new(left, right, bottom, top, znear, zfar) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Orthographic3 +where + Matrix4: Send, +{ + fn arbitrary(g: &mut Gen) -> Self { + use crate::base::helper; + let left = Arbitrary::arbitrary(g); + let right = helper::reject(g, |x: &T| *x > left); + let bottom = Arbitrary::arbitrary(g); + let top = helper::reject(g, |x: &T| *x > bottom); + let znear = Arbitrary::arbitrary(g); + let zfar = helper::reject(g, |x: &T| *x > znear); + + Self::new(left, right, bottom, top, znear, zfar) + } +} + +impl From> for Matrix4 { + #[inline] + fn from(orth: Orthographic3) -> Self { + orth.into_inner() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/perspective.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/perspective.rs new file mode 100644 index 000000000..646c4128a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/perspective.rs @@ -0,0 +1,348 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; + +use simba::scalar::RealField; + +use crate::base::dimension::U3; +use crate::base::storage::Storage; +use crate::base::{Matrix4, Vector, Vector3}; + +use crate::geometry::{Point3, Projective3}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A 3D perspective projection stored as a homogeneous 4x4 matrix. +#[repr(C)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Perspective3", + bound(archive = " + T: rkyv::Archive, + Matrix4: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[derive(Copy, Clone)] +pub struct Perspective3 { + matrix: Matrix4, +} + +impl fmt::Debug for Perspective3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.matrix.fmt(f) + } +} + +impl PartialEq for Perspective3 { + #[inline] + fn eq(&self, right: &Self) -> bool { + self.matrix == right.matrix + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Perspective3 +where + T: RealField + bytemuck::Zeroable, + Matrix4: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Perspective3 +where + T: RealField + bytemuck::Pod, + Matrix4: bytemuck::Pod, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Perspective3 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.matrix.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: RealField + Deserialize<'a>> Deserialize<'a> for Perspective3 { + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = Matrix4::::deserialize(deserializer)?; + + Ok(Self::from_matrix_unchecked(matrix)) + } +} + +impl Perspective3 { + /// Wraps the given matrix to interpret it as a 3D perspective matrix. + /// + /// It is not checked whether or not the given matrix actually represents a perspective + /// projection. + #[inline] + pub const fn from_matrix_unchecked(matrix: Matrix4) -> Self { + Self { matrix } + } +} + +impl Perspective3 { + /// Creates a new perspective matrix from the aspect ratio, y field of view, and near/far planes. + pub fn new(aspect: T, fovy: T, znear: T, zfar: T) -> Self { + assert!( + relative_ne!(zfar, znear), + "The near-plane and far-plane must not be superimposed." + ); + assert!( + !relative_eq!(aspect, T::zero()), + "The aspect ratio must not be zero." + ); + + let matrix = Matrix4::identity(); + let mut res = Self::from_matrix_unchecked(matrix); + + res.set_fovy(fovy); + res.set_aspect(aspect); + res.set_znear_and_zfar(znear, zfar); + + res.matrix[(3, 3)] = T::zero(); + res.matrix[(3, 2)] = -T::one(); + + res + } + + /// Retrieves the inverse of the underlying homogeneous matrix. + #[inline] + #[must_use] + pub fn inverse(&self) -> Matrix4 { + let mut res = self.clone().to_homogeneous(); + + res[(0, 0)] = T::one() / self.matrix[(0, 0)].clone(); + res[(1, 1)] = T::one() / self.matrix[(1, 1)].clone(); + res[(2, 2)] = T::zero(); + + let m23 = self.matrix[(2, 3)].clone(); + let m32 = self.matrix[(3, 2)].clone(); + + res[(2, 3)] = T::one() / m32.clone(); + res[(3, 2)] = T::one() / m23.clone(); + res[(3, 3)] = -self.matrix[(2, 2)].clone() / (m23 * m32); + + res + } + + /// Computes the corresponding homogeneous matrix. + #[inline] + #[must_use] + pub fn to_homogeneous(self) -> Matrix4 { + self.matrix.clone_owned() + } + + /// A reference to the underlying homogeneous transformation matrix. + #[inline] + #[must_use] + pub fn as_matrix(&self) -> &Matrix4 { + &self.matrix + } + + /// A reference to this transformation seen as a `Projective3`. + #[inline] + #[must_use] + pub fn as_projective(&self) -> &Projective3 { + unsafe { &*(self as *const Perspective3 as *const Projective3) } + } + + /// This transformation seen as a `Projective3`. + #[inline] + #[must_use] + pub fn to_projective(self) -> Projective3 { + Projective3::from_matrix_unchecked(self.matrix) + } + + /// Retrieves the underlying homogeneous matrix. + #[inline] + pub fn into_inner(self) -> Matrix4 { + self.matrix + } + + /// Retrieves the underlying homogeneous matrix. + /// Deprecated: Use [`Perspective3::into_inner`] instead. + #[deprecated(note = "use `.into_inner()` instead")] + #[inline] + pub fn unwrap(self) -> Matrix4 { + self.matrix + } + + /// Gets the `width / height` aspect ratio of the view frustum. + #[inline] + #[must_use] + pub fn aspect(&self) -> T { + self.matrix[(1, 1)].clone() / self.matrix[(0, 0)].clone() + } + + /// Gets the y field of view of the view frustum. + #[inline] + #[must_use] + pub fn fovy(&self) -> T { + (T::one() / self.matrix[(1, 1)].clone()).atan() * crate::convert(2.0) + } + + /// Gets the near plane offset of the view frustum. + #[inline] + #[must_use] + pub fn znear(&self) -> T { + let ratio = + (-self.matrix[(2, 2)].clone() + T::one()) / (-self.matrix[(2, 2)].clone() - T::one()); + + self.matrix[(2, 3)].clone() / (ratio * crate::convert(2.0)) + - self.matrix[(2, 3)].clone() / crate::convert(2.0) + } + + /// Gets the far plane offset of the view frustum. + #[inline] + #[must_use] + pub fn zfar(&self) -> T { + let ratio = + (-self.matrix[(2, 2)].clone() + T::one()) / (-self.matrix[(2, 2)].clone() - T::one()); + + (self.matrix[(2, 3)].clone() - ratio * self.matrix[(2, 3)].clone()) / crate::convert(2.0) + } + + // TODO: add a method to retrieve znear and zfar simultaneously? + + // TODO: when we get specialization, specialize the Mul impl instead. + /// Projects a point. Faster than matrix multiplication. + #[inline] + #[must_use] + pub fn project_point(&self, p: &Point3) -> Point3 { + let inverse_denom = -T::one() / p[2].clone(); + Point3::new( + self.matrix[(0, 0)].clone() * p[0].clone() * inverse_denom.clone(), + self.matrix[(1, 1)].clone() * p[1].clone() * inverse_denom.clone(), + (self.matrix[(2, 2)].clone() * p[2].clone() + self.matrix[(2, 3)].clone()) + * inverse_denom, + ) + } + + /// Un-projects a point. Faster than multiplication by the matrix inverse. + #[inline] + #[must_use] + pub fn unproject_point(&self, p: &Point3) -> Point3 { + let inverse_denom = + self.matrix[(2, 3)].clone() / (p[2].clone() + self.matrix[(2, 2)].clone()); + + Point3::new( + p[0].clone() * inverse_denom.clone() / self.matrix[(0, 0)].clone(), + p[1].clone() * inverse_denom.clone() / self.matrix[(1, 1)].clone(), + -inverse_denom, + ) + } + + // TODO: when we get specialization, specialize the Mul impl instead. + /// Projects a vector. Faster than matrix multiplication. + #[inline] + #[must_use] + pub fn project_vector(&self, p: &Vector) -> Vector3 + where + SB: Storage, + { + let inverse_denom = -T::one() / p[2].clone(); + Vector3::new( + self.matrix[(0, 0)].clone() * p[0].clone() * inverse_denom.clone(), + self.matrix[(1, 1)].clone() * p[1].clone() * inverse_denom, + self.matrix[(2, 2)].clone(), + ) + } + + /// Updates this perspective matrix with a new `width / height` aspect ratio of the view + /// frustum. + #[inline] + pub fn set_aspect(&mut self, aspect: T) { + assert!( + !relative_eq!(aspect, T::zero()), + "The aspect ratio must not be zero." + ); + self.matrix[(0, 0)] = self.matrix[(1, 1)].clone() / aspect; + } + + /// Updates this perspective with a new y field of view of the view frustum. + #[inline] + pub fn set_fovy(&mut self, fovy: T) { + let old_m22 = self.matrix[(1, 1)].clone(); + let new_m22 = T::one() / (fovy / crate::convert(2.0)).tan(); + self.matrix[(1, 1)] = new_m22.clone(); + self.matrix[(0, 0)] *= new_m22 / old_m22; + } + + /// Updates this perspective matrix with a new near plane offset of the view frustum. + #[inline] + pub fn set_znear(&mut self, znear: T) { + let zfar = self.zfar(); + self.set_znear_and_zfar(znear, zfar); + } + + /// Updates this perspective matrix with a new far plane offset of the view frustum. + #[inline] + pub fn set_zfar(&mut self, zfar: T) { + let znear = self.znear(); + self.set_znear_and_zfar(znear, zfar); + } + + /// Updates this perspective matrix with new near and far plane offsets of the view frustum. + #[inline] + pub fn set_znear_and_zfar(&mut self, znear: T, zfar: T) { + self.matrix[(2, 2)] = (zfar.clone() + znear.clone()) / (znear.clone() - zfar.clone()); + self.matrix[(2, 3)] = zfar.clone() * znear.clone() * crate::convert(2.0) / (znear - zfar); + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, +{ + /// Generate an arbitrary random variate for testing purposes. + fn sample(&self, r: &mut R) -> Perspective3 { + use crate::base::helper; + let znear = r.gen(); + let zfar = helper::reject_rand(r, |x: &T| !(x.clone() - znear.clone()).is_zero()); + let aspect = helper::reject_rand(r, |x: &T| !x.is_zero()); + + Perspective3::new(aspect, r.gen(), znear, zfar) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Perspective3 { + fn arbitrary(g: &mut Gen) -> Self { + use crate::base::helper; + let znear: T = Arbitrary::arbitrary(g); + let zfar = helper::reject(g, |x: &T| !(x.clone() - znear.clone()).is_zero()); + let aspect = helper::reject(g, |x: &T| !x.is_zero()); + + Self::new(aspect, Arbitrary::arbitrary(g), znear, zfar) + } +} + +impl From> for Matrix4 { + #[inline] + fn from(pers: Perspective3) -> Self { + pers.into_inner() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point.rs new file mode 100644 index 000000000..c8baf90a5 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point.rs @@ -0,0 +1,515 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::{One, Zero}; +use std::cmp::Ordering; +use std::fmt; +use std::hash; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use simba::simd::SimdPartialOrd; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; +use crate::base::iter::{MatrixIter, MatrixIterMut}; +use crate::base::{Const, DefaultAllocator, OVector, Scalar}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, ClosedSubAssign}; +use std::mem::MaybeUninit; + +/// A point in an euclidean space. +/// +/// The difference between a point and a vector is only semantic. See [the user guide](https://www.nalgebra.org/docs/user_guide/points_and_transformations) +/// for details on the distinction. The most notable difference that vectors ignore translations. +/// In particular, an [`Isometry2`](crate::Isometry2) or [`Isometry3`](crate::Isometry3) will +/// transform points by applying a rotation and a translation on them. However, these isometries +/// will only apply rotations to vectors (when doing `isometry * vector`, the translation part of +/// the isometry is ignored). +/// +/// # Construction +/// * [From individual components `new`…](#construction-from-individual-components) +/// * [Swizzling `xx`, `yxz`…](#swizzling) +/// * [Other construction methods `origin`, `from_slice`, `from_homogeneous`…](#other-construction-methods) +/// +/// # Transformation +/// Transforming a point by an [Isometry](crate::Isometry), [rotation](crate::Rotation), etc. can be +/// achieved by multiplication, e.g., `isometry * point` or `rotation * point`. Some of these transformation +/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation +/// of said transformations for details. +#[repr(C)] +#[derive(Clone)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "OPoint", + bound(archive = " + T: rkyv::Archive, + T::Archived: Scalar, + OVector: rkyv::Archive>, + DefaultAllocator: Allocator, + ") + ) +)] +pub struct OPoint +where + DefaultAllocator: Allocator, +{ + /// The coordinates of this point, i.e., the shift from the origin. + pub coords: OVector, +} + +impl fmt::Debug for OPoint +where + DefaultAllocator: Allocator, +{ + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.coords.as_slice().fmt(formatter) + } +} + +impl hash::Hash for OPoint +where + DefaultAllocator: Allocator, +{ + fn hash(&self, state: &mut H) { + self.coords.hash(state) + } +} + +impl Copy for OPoint +where + DefaultAllocator: Allocator, + OVector: Copy, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for OPoint +where + OVector: bytemuck::Zeroable, + DefaultAllocator: Allocator, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for OPoint +where + T: Copy, + OVector: bytemuck::Pod, + DefaultAllocator: Allocator, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for OPoint +where + DefaultAllocator: Allocator, + >::Buffer: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.coords.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: Scalar, D: DimName> Deserialize<'a> for OPoint +where + DefaultAllocator: Allocator, + >::Buffer: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let coords = OVector::::deserialize(deserializer)?; + + Ok(Self::from(coords)) + } +} + +impl OPoint +where + DefaultAllocator: Allocator, +{ + /// Returns a point containing the result of `f` applied to each of its entries. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// let p = Point2::new(1.0, 2.0); + /// assert_eq!(p.map(|e| e * 10.0), Point2::new(10.0, 20.0)); + /// + /// // This works in any dimension. + /// let p = Point3::new(1.1, 2.1, 3.1); + /// assert_eq!(p.map(|e| e as u32), Point3::new(1, 2, 3)); + /// ``` + #[inline] + #[must_use] + pub fn map T2>(&self, f: F) -> OPoint + where + DefaultAllocator: Allocator, + { + self.coords.map(f).into() + } + + /// Replaces each component of `self` by the result of a closure `f` applied on it. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// let mut p = Point2::new(1.0, 2.0); + /// p.apply(|e| *e = *e * 10.0); + /// assert_eq!(p, Point2::new(10.0, 20.0)); + /// + /// // This works in any dimension. + /// let mut p = Point3::new(1.0, 2.0, 3.0); + /// p.apply(|e| *e = *e * 10.0); + /// assert_eq!(p, Point3::new(10.0, 20.0, 30.0)); + /// ``` + #[inline] + pub fn apply(&mut self, f: F) { + self.coords.apply(f) + } + + /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the + /// end of it. + /// + /// This is the same as `.into()`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3, Vector3, Vector4}; + /// let p = Point2::new(10.0, 20.0); + /// assert_eq!(p.to_homogeneous(), Vector3::new(10.0, 20.0, 1.0)); + /// + /// // This works in any dimension. + /// let p = Point3::new(10.0, 20.0, 30.0); + /// assert_eq!(p.to_homogeneous(), Vector4::new(10.0, 20.0, 30.0, 1.0)); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OVector> + where + T: One, + D: DimNameAdd, + DefaultAllocator: Allocator>, + { + // TODO: this is mostly a copy-past from Vector::push. + // But we can’t use Vector::push because of the DimAdd bound + // (which we don’t use because we use DimNameAdd). + // We should find a way to re-use Vector::push. + let len = self.len(); + let mut res = crate::Matrix::uninit(DimNameSum::::name(), Const::<1>); + // This is basically a copy_from except that we warp the copied + // values into MaybeUninit. + res.generic_view_mut((0, 0), self.coords.shape_generic()) + .zip_apply(&self.coords, |out, e| *out = MaybeUninit::new(e)); + res[(len, 0)] = MaybeUninit::new(T::one()); + + // Safety: res has been fully initialized. + unsafe { res.assume_init() } + } + + /// Linear interpolation between two points. + /// + /// Returns `self * (1.0 - t) + rhs.coords * t`, i.e., the linear blend of the points + /// `self` and `rhs` using the scalar value `t`. + /// + /// The value for a is not restricted to the range `[0, 1]`. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::Point3; + /// let a = Point3::new(1.0, 2.0, 3.0); + /// let b = Point3::new(10.0, 20.0, 30.0); + /// assert_eq!(a.lerp(&b, 0.1), Point3::new(1.9, 3.8, 5.7)); + /// ``` + #[must_use] + pub fn lerp(&self, rhs: &OPoint, t: T) -> OPoint + where + T: Scalar + Zero + One + ClosedAddAssign + ClosedSubAssign + ClosedMulAssign, + { + OPoint { + coords: self.coords.lerp(&rhs.coords, t), + } + } + + /// Creates a new point with the given coordinates. + #[deprecated(note = "Use Point::from(vector) instead.")] + #[inline] + pub fn from_coordinates(coords: OVector) -> Self { + Self { coords } + } + + /// The dimension of this point. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// let p = Point2::new(1.0, 2.0); + /// assert_eq!(p.len(), 2); + /// + /// // This works in any dimension. + /// let p = Point3::new(10.0, 20.0, 30.0); + /// assert_eq!(p.len(), 3); + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.coords.len() + } + + /// Returns true if the point contains no elements. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// let p = Point2::new(1.0, 2.0); + /// assert!(!p.is_empty()); + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// The stride of this point. This is the number of buffer element separating each component of + /// this point. + #[inline] + #[deprecated(note = "This methods is no longer significant and will always return 1.")] + pub fn stride(&self) -> usize { + self.coords.strides().0 + } + + /// Iterates through this point coordinates. + /// + /// # Example + /// ``` + /// # use nalgebra::Point3; + /// let p = Point3::new(1.0, 2.0, 3.0); + /// let mut it = p.iter().cloned(); + /// + /// assert_eq!(it.next(), Some(1.0)); + /// assert_eq!(it.next(), Some(2.0)); + /// assert_eq!(it.next(), Some(3.0)); + /// assert_eq!(it.next(), None); + /// ``` + #[inline] + pub fn iter( + &self, + ) -> MatrixIter<'_, T, D, Const<1>, >::Buffer> { + self.coords.iter() + } + + /// Gets a reference to i-th element of this point without bound-checking. + /// + /// # Safety + /// + /// `i` must be less than `self.len()`. + #[inline] + #[must_use] + pub unsafe fn get_unchecked(&self, i: usize) -> &T { + self.coords.vget_unchecked(i) + } + + /// Mutably iterates through this point coordinates. + /// + /// # Example + /// ``` + /// # use nalgebra::Point3; + /// let mut p = Point3::new(1.0, 2.0, 3.0); + /// + /// for e in p.iter_mut() { + /// *e *= 10.0; + /// } + /// + /// assert_eq!(p, Point3::new(10.0, 20.0, 30.0)); + /// ``` + #[inline] + pub fn iter_mut( + &mut self, + ) -> MatrixIterMut<'_, T, D, Const<1>, >::Buffer> { + self.coords.iter_mut() + } + + /// Gets a mutable reference to i-th element of this point without bound-checking. + /// + /// # Safety + /// + /// `i` must be less than `self.len()`. + #[inline] + #[must_use] + pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut T { + self.coords.vget_unchecked_mut(i) + } + + /// Swaps two entries without bound-checking. + /// + /// # Safety + /// + /// `i1` and `i2` must be less than `self.len()`. + #[inline] + pub unsafe fn swap_unchecked(&mut self, i1: usize, i2: usize) { + self.coords.swap_unchecked((i1, 0), (i2, 0)) + } +} + +impl AbsDiffEq for OPoint +where + T::Epsilon: Clone, + DefaultAllocator: Allocator, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.coords.abs_diff_eq(&other.coords, epsilon) + } +} + +impl RelativeEq for OPoint +where + T::Epsilon: Clone, + DefaultAllocator: Allocator, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.coords + .relative_eq(&other.coords, epsilon, max_relative) + } +} + +impl UlpsEq for OPoint +where + T::Epsilon: Clone, + DefaultAllocator: Allocator, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.coords.ulps_eq(&other.coords, epsilon, max_ulps) + } +} + +impl Eq for OPoint where DefaultAllocator: Allocator {} + +impl PartialEq for OPoint +where + DefaultAllocator: Allocator, +{ + #[inline] + fn eq(&self, right: &Self) -> bool { + self.coords == right.coords + } +} + +impl PartialOrd for OPoint +where + DefaultAllocator: Allocator, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.coords.partial_cmp(&other.coords) + } + + #[inline] + fn lt(&self, right: &Self) -> bool { + self.coords.lt(&right.coords) + } + + #[inline] + fn le(&self, right: &Self) -> bool { + self.coords.le(&right.coords) + } + + #[inline] + fn gt(&self, right: &Self) -> bool { + self.coords.gt(&right.coords) + } + + #[inline] + fn ge(&self, right: &Self) -> bool { + self.coords.ge(&right.coords) + } +} + +/* + * inf/sup + */ +impl OPoint +where + DefaultAllocator: Allocator, +{ + /// Computes the infimum (aka. componentwise min) of two points. + #[inline] + #[must_use] + pub fn inf(&self, other: &Self) -> OPoint { + self.coords.inf(&other.coords).into() + } + + /// Computes the supremum (aka. componentwise max) of two points. + #[inline] + #[must_use] + pub fn sup(&self, other: &Self) -> OPoint { + self.coords.sup(&other.coords).into() + } + + /// Computes the (infimum, supremum) of two points. + #[inline] + #[must_use] + pub fn inf_sup(&self, other: &Self) -> (OPoint, OPoint) { + let (inf, sup) = self.coords.inf_sup(&other.coords); + (inf.into(), sup.into()) + } +} + +/* + * + * Display + * + */ +impl fmt::Display for OPoint +where + DefaultAllocator: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{{")?; + + let mut it = self.coords.iter(); + + ::fmt(it.next().unwrap(), f)?; + + for comp in it { + write!(f, ", ")?; + ::fmt(comp, f)?; + } + + write!(f, "}}") + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_alias.rs new file mode 100644 index 000000000..6aa945cdc --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_alias.rs @@ -0,0 +1,30 @@ +use crate::geometry::OPoint; +use crate::Const; + +/// A point with `D` elements. +pub type Point = OPoint>; + +/// A statically sized 1-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** +pub type Point1 = Point; +/// A statically sized 2-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** +pub type Point2 = Point; +/// A statically sized 3-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** +pub type Point3 = Point; +/// A statically sized 4-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** +pub type Point4 = Point; +/// A statically sized 5-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** +pub type Point5 = Point; +/// A statically sized 6-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** +pub type Point6 = Point; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_construction.rs new file mode 100644 index 000000000..fd114e916 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_construction.rs @@ -0,0 +1,237 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::{Bounded, One, Zero}; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{DefaultAllocator, Scalar}; +use crate::{ + Const, DimName, OPoint, OVector, Point1, Point2, Point3, Point4, Point5, Point6, Vector1, + Vector2, Vector3, Vector4, Vector5, Vector6, +}; +use simba::scalar::{ClosedDivAssign, SupersetOf}; + +use crate::geometry::Point; + +impl Default for OPoint +where + DefaultAllocator: Allocator, +{ + fn default() -> Self { + Self::origin() + } +} + +/// # Other construction methods +impl OPoint +where + DefaultAllocator: Allocator, +{ + /// Creates a new point with all coordinates equal to zero. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// // This works in any dimension. + /// // The explicit crate:: type annotation may not always be needed, + /// // depending on the context of type inference. + /// let pt = Point2::::origin(); + /// assert!(pt.x == 0.0 && pt.y == 0.0); + /// + /// let pt = Point3::::origin(); + /// assert!(pt.x == 0.0 && pt.y == 0.0 && pt.z == 0.0); + /// ``` + #[inline] + pub fn origin() -> Self + where + T: Zero, + { + Self::from(OVector::from_element(T::zero())) + } + + /// Creates a new point from a slice. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// let data = [ 1.0, 2.0, 3.0 ]; + /// + /// let pt = Point2::from_slice(&data[..2]); + /// assert_eq!(pt, Point2::new(1.0, 2.0)); + /// + /// let pt = Point3::from_slice(&data); + /// assert_eq!(pt, Point3::new(1.0, 2.0, 3.0)); + /// ``` + #[inline] + pub fn from_slice(components: &[T]) -> Self { + Self::from(OVector::from_row_slice(components)) + } + + /// Creates a new point from its homogeneous vector representation. + /// + /// In practice, this builds a D-dimensional points with the same first D component as `v` + /// divided by the last component of `v`. Returns `None` if this divisor is zero. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Point2, Point3, Vector3, Vector4}; + /// + /// let coords = Vector4::new(1.0, 2.0, 3.0, 1.0); + /// let pt = Point3::from_homogeneous(coords); + /// assert_eq!(pt, Some(Point3::new(1.0, 2.0, 3.0))); + /// + /// // All component of the result will be divided by the + /// // last component of the vector, here 2.0. + /// let coords = Vector4::new(1.0, 2.0, 3.0, 2.0); + /// let pt = Point3::from_homogeneous(coords); + /// assert_eq!(pt, Some(Point3::new(0.5, 1.0, 1.5))); + /// + /// // Fails because the last component is zero. + /// let coords = Vector4::new(1.0, 2.0, 3.0, 0.0); + /// let pt = Point3::from_homogeneous(coords); + /// assert!(pt.is_none()); + /// + /// // Works also in other dimensions. + /// let coords = Vector3::new(1.0, 2.0, 1.0); + /// let pt = Point2::from_homogeneous(coords); + /// assert_eq!(pt, Some(Point2::new(1.0, 2.0))); + /// ``` + #[inline] + pub fn from_homogeneous(v: OVector>) -> Option + where + T: Scalar + Zero + One + ClosedDivAssign, + D: DimNameAdd, + DefaultAllocator: Allocator>, + { + if !v[D::dim()].is_zero() { + let coords = v.generic_view((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); + Some(Self::from(coords)) + } else { + None + } + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Point2; + /// let pt = Point2::new(1.0f64, 2.0); + /// let pt2 = pt.cast::(); + /// assert_eq!(pt2, Point2::new(1.0f32, 2.0)); + /// ``` + pub fn cast(self) -> OPoint + where + OPoint: SupersetOf, + DefaultAllocator: Allocator, + { + crate::convert(self) + } +} + +/* + * + * Traits that build points. + * + */ +impl Bounded for OPoint +where + DefaultAllocator: Allocator, +{ + #[inline] + fn max_value() -> Self { + Self::from(OVector::max_value()) + } + + #[inline] + fn min_value() -> Self { + Self::from(OVector::min_value()) + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, + DefaultAllocator: Allocator, +{ + /// Generate a `Point` where each coordinate is an independent variate from `[0, 1)`. + #[inline] + fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> OPoint { + OPoint::from(rng.gen::>()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for OPoint +where + >::Buffer: Send, + DefaultAllocator: Allocator, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + Self::from(OVector::arbitrary(g)) + } +} + +/* + * + * Small points construction from components. + * + */ +// NOTE: the impl for Point1 is not with the others so that we +// can add a section with the impl block comment. +/// # Construction from individual components +impl Point1 { + /// Initializes this point from its components. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Point1; + /// let p = Point1::new(1.0); + /// assert_eq!(p.x, 1.0); + /// ``` + #[inline] + pub const fn new(x: T) -> Self { + Point { + coords: Vector1::new(x), + } + } +} +macro_rules! componentwise_constructors_impl( + ($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$( + impl $Point { + #[doc = "Initializes this point from its components."] + #[doc = "# Example\n```"] + #[doc = $doc] + #[doc = "```"] + #[inline] + pub const fn new($($args: T),*) -> Self { + Point { coords: $Vector::new($($args),*) } + } + } + )*} +); + +componentwise_constructors_impl!( + "# use nalgebra::Point2;\nlet p = Point2::new(1.0, 2.0);\nassert!(p.x == 1.0 && p.y == 2.0);"; + Point2, Vector2, x:0, y:1; + "# use nalgebra::Point3;\nlet p = Point3::new(1.0, 2.0, 3.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0);"; + Point3, Vector3, x:0, y:1, z:2; + "# use nalgebra::Point4;\nlet p = Point4::new(1.0, 2.0, 3.0, 4.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0);"; + Point4, Vector4, x:0, y:1, z:2, w:3; + "# use nalgebra::Point5;\nlet p = Point5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0);"; + Point5, Vector5, x:0, y:1, z:2, w:3, a:4; + "# use nalgebra::Point6;\nlet p = Point6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0 && p.b == 6.0);"; + Point6, Vector6, x:0, y:1, z:2, w:3, a:4, b:5; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_conversion.rs new file mode 100644 index 000000000..5ce18570b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_conversion.rs @@ -0,0 +1,191 @@ +use num::{One, Zero}; +use simba::scalar::{ClosedDivAssign, SubsetOf, SupersetOf}; +use simba::simd::PrimitiveSimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar}; + +use crate::geometry::Point; +use crate::{DimName, OPoint}; + +/* + * This file provides the following conversions: + * ============================================= + * + * Point -> Point + * Point -> Vector (homogeneous) + */ + +impl SubsetOf> for OPoint +where + T1: Scalar, + T2: Scalar + SupersetOf, + DefaultAllocator: Allocator, +{ + #[inline] + fn to_superset(&self) -> OPoint { + OPoint::from(self.coords.to_superset()) + } + + #[inline] + fn is_in_subset(m: &OPoint) -> bool { + // TODO: is there a way to reuse the `.is_in_subset` from the matrix implementation of + // SubsetOf? + m.iter().all(|e| e.is_in_subset()) + } + + #[inline] + fn from_superset_unchecked(m: &OPoint) -> Self { + Self::from(Matrix::from_superset_unchecked(&m.coords)) + } +} + +impl SubsetOf>> for OPoint +where + D: DimNameAdd, + T1: Scalar, + T2: Scalar + Zero + One + ClosedDivAssign + SupersetOf, + DefaultAllocator: Allocator + Allocator>, + // + Allocator + // + Allocator, +{ + #[inline] + fn to_superset(&self) -> OVector> { + let p: OPoint = self.to_superset(); + p.to_homogeneous() + } + + #[inline] + fn is_in_subset(v: &OVector>) -> bool { + crate::is_convertible::<_, OVector>>(v) && !v[D::dim()].is_zero() + } + + #[inline] + fn from_superset_unchecked(v: &OVector>) -> Self { + let coords = v.generic_view((0, 0), (D::name(), Const::<1>)) / v[D::dim()].clone(); + Self { + coords: crate::convert_unchecked(coords), + } + } +} + +impl From> for OVector> +where + D: DimNameAdd, + DefaultAllocator: Allocator> + Allocator, +{ + #[inline] + fn from(t: OPoint) -> Self { + t.to_homogeneous() + } +} + +impl From<[T; D]> for Point { + #[inline] + fn from(coords: [T; D]) -> Self { + Point { + coords: coords.into(), + } + } +} + +impl From> for [T; D] { + #[inline] + fn from(p: Point) -> Self { + p.coords.into() + } +} + +impl From> for OPoint +where + DefaultAllocator: Allocator, +{ + #[inline] + fn from(coords: OVector) -> Self { + OPoint { coords } + } +} + +impl From<[Point; 2]> + for Point +where + T: From<[::Element; 2]>, + T::Element: Scalar + Copy, + >>::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 2]) -> Self { + Self::from(OVector::from([arr[0].coords, arr[1].coords])) + } +} + +impl From<[Point; 4]> + for Point +where + T: From<[::Element; 4]>, + T::Element: Scalar + Copy, + >>::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 4]) -> Self { + Self::from(OVector::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + ])) + } +} + +impl From<[Point; 8]> + for Point +where + T: From<[::Element; 8]>, + T::Element: Scalar + Copy, + >>::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 8]) -> Self { + Self::from(OVector::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + ])) + } +} + +impl From<[Point; 16]> + for Point +where + T: From<[::Element; 16]>, + T::Element: Scalar + Copy, + >>::Buffer: Copy, +{ + #[inline] + fn from(arr: [Point; 16]) -> Self { + Self::from(OVector::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + arr[8].coords, + arr[9].coords, + arr[10].coords, + arr[11].coords, + arr[12].coords, + arr[13].coords, + arr[14].coords, + arr[15].coords, + ])) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_coordinates.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_coordinates.rs new file mode 100644 index 000000000..30ee4003f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_coordinates.rs @@ -0,0 +1,41 @@ +use std::ops::{Deref, DerefMut}; + +use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; +use crate::base::{Scalar, U1, U2, U3, U4, U5, U6}; + +use crate::geometry::OPoint; + +/* + * + * Give coordinates to Point{1 .. 6} + * + */ + +macro_rules! deref_impl( + ($D: ty, $Target: ident $(, $comps: ident)*) => { + impl Deref for OPoint + { + type Target = $Target; + + #[inline] + fn deref(&self) -> &Self::Target { + &*self.coords + } + } + + impl DerefMut for OPoint + { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.coords + } + } + } +); + +deref_impl!(U1, X, x); +deref_impl!(U2, XY, x, y); +deref_impl!(U3, XYZ, x, y, z); +deref_impl!(U4, XYZW, x, y, z, w); +deref_impl!(U5, XYZWA, x, y, z, w, a); +deref_impl!(U6, XYZWAB, x, y, z, w, a, b); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_ops.rs new file mode 100644 index 000000000..e0360eca6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_ops.rs @@ -0,0 +1,297 @@ +use num::{One, Zero}; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, +}; + +use simba::scalar::{ + ClosedAddAssign, ClosedDivAssign, ClosedMulAssign, ClosedNeg, ClosedSubAssign, +}; + +use crate::base::constraint::{ + AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, +}; +use crate::base::dimension::{Dim, DimName, U1}; +use crate::base::storage::Storage; +use crate::base::{Const, Matrix, OVector, Scalar, Vector}; + +use crate::allocator::Allocator; +use crate::geometry::{OPoint, Point}; +use crate::DefaultAllocator; + +/* + * + * Indexing. + * + */ +impl Index for OPoint +where + DefaultAllocator: Allocator, +{ + type Output = T; + + #[inline] + fn index(&self, i: usize) -> &Self::Output { + &self.coords[i] + } +} + +impl IndexMut for OPoint +where + DefaultAllocator: Allocator, +{ + #[inline] + fn index_mut(&mut self, i: usize) -> &mut Self::Output { + &mut self.coords[i] + } +} + +/* + * + * Neg. + * + */ +impl Neg for OPoint +where + DefaultAllocator: Allocator, +{ + type Output = Self; + + #[inline] + fn neg(self) -> Self::Output { + Self::Output::from(-self.coords) + } +} + +impl<'a, T: Scalar + ClosedNeg, D: DimName> Neg for &'a OPoint +where + DefaultAllocator: Allocator, +{ + type Output = OPoint; + + #[inline] + fn neg(self) -> Self::Output { + Self::Output::from(-&self.coords) + } +} + +/* + * + * Subtraction & Addition. + * + */ + +// Point - Point +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: &'a OPoint, right: &'b OPoint, Output = OVector; + &self.coords - &right.coords; 'a, 'b); + +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: &'a OPoint, right: OPoint, Output = OVector; + &self.coords - right.coords; 'a); + +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: OPoint, right: &'b OPoint, Output = OVector; + self.coords - &right.coords; 'b); + +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: OPoint, right: OPoint, Output = OVector; + self.coords - right.coords; ); + +// Point - Vector +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: &'b Vector, Output = OPoint; + Self::Output::from(&self.coords - right); 'a, 'b); + +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: Vector, Output = OPoint; + Self::Output::from(&self.coords - &right); 'a); // TODO: should not be a ref to `right`. + +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: &'b Vector, Output = OPoint; + Self::Output::from(self.coords - right); 'b); + +add_sub_impl!(Sub, sub, ClosedSubAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: Vector, Output = OPoint; + Self::Output::from(self.coords - right); ); + +// Point + Vector +add_sub_impl!(Add, add, ClosedAddAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: &'b Vector, Output = OPoint; + Self::Output::from(&self.coords + right); 'a, 'b); + +add_sub_impl!(Add, add, ClosedAddAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: Vector, Output = OPoint; + Self::Output::from(&self.coords + &right); 'a); // TODO: should not be a ref to `right`. + +add_sub_impl!(Add, add, ClosedAddAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: &'b Vector, Output = OPoint; + Self::Output::from(self.coords + right); 'b); + +add_sub_impl!(Add, add, ClosedAddAssign; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: Vector, Output = OPoint; + Self::Output::from(self.coords + right); ); + +// TODO: replace by the shared macro: add_sub_assign_impl? +macro_rules! op_assign_impl( + ($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$( + impl<'b, T, D1: DimName, D2: Dim, SB> $TraitAssign<&'b Vector> for OPoint + where T: Scalar + $bound, + SB: Storage, + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator { + + #[inline] + fn $method_assign(&mut self, right: &'b Vector) { + self.coords.$method_assign(right) + } + } + + impl $TraitAssign> for OPoint + where T: Scalar + $bound, + SB: Storage, + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator { + + #[inline] + fn $method_assign(&mut self, right: Vector) { + self.coords.$method_assign(right) + } + } + )*} +); + +op_assign_impl!( + AddAssign, add_assign, ClosedAddAssign; + SubAssign, sub_assign, ClosedSubAssign; +); + +/* + * + * Matrix × Point + * + */ +md_impl_all!( + Mul, mul; + (Const, Const), (Const, U1) + const D2, R1, C1; + for SA; + where SA: Storage, Const>, + ShapeConstraint: AreMultipliable, Const, Const, U1>; + self: Matrix, Const, SA>, right: Point, Output = Point; + [val val] => Point::from(self * right.coords); + [ref val] => Point::from(self * right.coords); + [val ref] => Point::from(self * &right.coords); + [ref ref] => Point::from(self * &right.coords); +); + +/* + * + * Point ×/÷ Scalar + * + */ +macro_rules! componentwise_scalarop_impl( + ($Trait: ident, $method: ident, $bound: ident; + $TraitAssign: ident, $method_assign: ident) => { + impl $Trait for OPoint + where DefaultAllocator: Allocator + { + type Output = OPoint; + + #[inline] + fn $method(self, right: T) -> Self::Output { + OPoint::from(self.coords.$method(right)) + } + } + + impl<'a, T: Scalar + $bound, D: DimName> $Trait for &'a OPoint + where DefaultAllocator: Allocator + { + type Output = OPoint; + + #[inline] + fn $method(self, right: T) -> Self::Output { + OPoint::from((&self.coords).$method(right)) + } + } + + impl $TraitAssign for OPoint + where DefaultAllocator: Allocator + { + #[inline] + fn $method_assign(&mut self, right: T) { + self.coords.$method_assign(right) + } + } + } +); + +componentwise_scalarop_impl!(Mul, mul, ClosedMulAssign; MulAssign, mul_assign); +componentwise_scalarop_impl!(Div, div, ClosedDivAssign; DivAssign, div_assign); + +macro_rules! left_scalar_mul_impl( + ($($T: ty),* $(,)*) => {$( + impl Mul> for $T + where DefaultAllocator: Allocator + { + type Output = OPoint<$T, D>; + + #[inline] + fn mul(self, right: OPoint<$T, D>) -> Self::Output { + OPoint::from(self * right.coords) + } + } + + impl<'b, D: DimName> Mul<&'b OPoint<$T, D>> for $T + where DefaultAllocator: Allocator + { + type Output = OPoint<$T, D>; + + #[inline] + fn mul(self, right: &'b OPoint<$T, D>) -> Self::Output { + OPoint::from(self * &right.coords) + } + } + )*} +); + +left_scalar_mul_impl!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_simba.rs new file mode 100644 index 000000000..351c1fa64 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/point_simba.rs @@ -0,0 +1,44 @@ +use simba::simd::SimdValue; + +use crate::base::{OVector, Scalar}; + +use crate::geometry::Point; + +impl SimdValue for Point +where + T::Element: Scalar, +{ + const LANES: usize = T::LANES; + type Element = Point; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + OVector::splat(val.coords).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.coords.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.coords.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.coords.replace(i, val.coords) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.coords.replace_unchecked(i, val.coords) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.coords.select(cond, other.coords).into() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion.rs new file mode 100644 index 000000000..d8e043005 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion.rs @@ -0,0 +1,1707 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::Zero; +use std::fmt; +use std::hash::{Hash, Hasher}; + +#[cfg(feature = "serde-serialize-no-std")] +use crate::base::storage::Owned; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use simba::scalar::{ClosedNeg, RealField}; +use simba::simd::{SimdBool, SimdOption, SimdRealField}; + +use crate::base::dimension::{U1, U3, U4}; +use crate::base::storage::{CStride, RStride}; +use crate::base::{ + Matrix3, Matrix4, MatrixView, MatrixViewMut, Normed, Scalar, Unit, Vector3, Vector4, +}; + +use crate::geometry::{Point3, Rotation}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A quaternion. See the type alias `UnitQuaternion = Unit` for a quaternion +/// that may be used as a rotation. +#[repr(C)] +#[derive(Copy, Clone)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Quaternion", + bound(archive = " + T: rkyv::Archive, + Vector4: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +pub struct Quaternion { + /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. + pub coords: Vector4, +} + +impl fmt::Debug for Quaternion { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.coords.as_slice().fmt(formatter) + } +} + +impl Hash for Quaternion { + fn hash(&self, state: &mut H) { + self.coords.hash(state) + } +} + +impl Eq for Quaternion {} + +impl PartialEq for Quaternion { + #[inline] + fn eq(&self, right: &Self) -> bool { + self.coords == right.coords + } +} + +impl Default for Quaternion { + fn default() -> Self { + Quaternion { + coords: Vector4::zeros(), + } + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Quaternion where Vector4: bytemuck::Zeroable {} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Quaternion +where + Vector4: bytemuck::Pod, + T: Copy, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Quaternion +where + Owned: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.coords.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: Scalar> Deserialize<'a> for Quaternion +where + Owned: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let coords = Vector4::::deserialize(deserializer)?; + + Ok(Self::from(coords)) + } +} + +impl Quaternion +where + T::Element: SimdRealField, +{ + /// Moves this unit quaternion into one that owns its data. + #[inline] + #[deprecated(note = "This method is a no-op and will be removed in a future release.")] + pub fn into_owned(self) -> Self { + self + } + + /// Clones this unit quaternion into one that owns its data. + #[inline] + #[deprecated(note = "This method is a no-op and will be removed in a future release.")] + pub fn clone_owned(&self) -> Self { + Self::from(self.coords.clone_owned()) + } + + /// Normalizes this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let q_normalized = q.normalize(); + /// assert_relative_eq!(q_normalized.norm(), 1.0); + /// ``` + #[inline] + #[must_use = "Did you mean to use normalize_mut()?"] + pub fn normalize(&self) -> Self { + Self::from(self.coords.normalize()) + } + + /// The imaginary part of this quaternion. + #[inline] + #[must_use] + pub fn imag(&self) -> Vector3 { + self.coords.xyz() + } + + /// The conjugate of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let conj = q.conjugate(); + /// assert!(conj.i == -2.0 && conj.j == -3.0 && conj.k == -4.0 && conj.w == 1.0); + /// ``` + #[inline] + #[must_use = "Did you mean to use conjugate_mut()?"] + pub fn conjugate(&self) -> Self { + Self::from_parts(self.w.clone(), -self.imag()) + } + + /// Linear interpolation between two quaternion. + /// + /// Computes `self * (1 - t) + other * t`. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let q2 = Quaternion::new(10.0, 20.0, 30.0, 40.0); + /// + /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6)); + /// ``` + #[inline] + #[must_use] + pub fn lerp(&self, other: &Self, t: T) -> Self { + self * (T::one() - t.clone()) + other * t + } + + /// The vector part `(i, j, k)` of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.vector()[0], 2.0); + /// assert_eq!(q.vector()[1], 3.0); + /// assert_eq!(q.vector()[2], 4.0); + /// ``` + #[inline] + #[must_use] + pub fn vector(&self) -> MatrixView<'_, T, U3, U1, RStride, CStride> { + self.coords.fixed_rows::<3>(0) + } + + /// The scalar part `w` of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.scalar(), 1.0); + /// ``` + #[inline] + #[must_use] + pub fn scalar(&self) -> T { + self.coords[3].clone() + } + + /// Reinterprets this quaternion as a 4D vector. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector4, Quaternion}; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// // Recall that the quaternion is stored internally as (i, j, k, w) + /// // while the crate::new constructor takes the arguments as (w, i, j, k). + /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); + /// ``` + #[inline] + #[must_use] + pub fn as_vector(&self) -> &Vector4 { + &self.coords + } + + /// The norm of this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn norm(&self) -> T { + self.coords.norm() + } + + /// A synonym for the norm of this quaternion. + /// + /// Aka the length. + /// This is the same as `.norm()` + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn magnitude(&self) -> T { + self.norm() + } + + /// The squared norm of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.norm_squared(), 30.0); + /// ``` + #[inline] + #[must_use] + pub fn norm_squared(&self) -> T { + self.coords.norm_squared() + } + + /// A synonym for the squared norm of this quaternion. + /// + /// Aka the squared length. + /// This is the same as `.norm_squared()` + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.magnitude_squared(), 30.0); + /// ``` + #[inline] + #[must_use] + pub fn magnitude_squared(&self) -> T { + self.norm_squared() + } + + /// The dot product of two quaternions. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let q2 = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// assert_eq!(q1.dot(&q2), 70.0); + /// ``` + #[inline] + #[must_use] + pub fn dot(&self, rhs: &Self) -> T { + self.coords.dot(&rhs.coords) + } +} + +impl Quaternion +where + T::Element: SimdRealField, +{ + /// Inverts this quaternion if it is not zero. + /// + /// This method also does not works with SIMD components (see `simd_try_inverse` instead). + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let inv_q = q.try_inverse(); + /// + /// assert!(inv_q.is_some()); + /// assert_relative_eq!(inv_q.unwrap() * q, Quaternion::identity()); + /// + /// //Non-invertible case + /// let q = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// let inv_q = q.try_inverse(); + /// + /// assert!(inv_q.is_none()); + /// ``` + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn try_inverse(&self) -> Option + where + T: RealField, + { + let mut res = self.clone(); + + if res.try_inverse_mut() { + Some(res) + } else { + None + } + } + + /// Attempt to inverse this quaternion. + /// + /// This method also works with SIMD components. + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn simd_try_inverse(&self) -> SimdOption { + let norm_squared = self.norm_squared(); + let ge = norm_squared.clone().simd_ge(T::simd_default_epsilon()); + SimdOption::new(self.conjugate() / norm_squared, ge) + } + + /// Calculates the inner product (also known as the dot product). + /// See "Foundations of Game Engine Development, Volume 1: Mathematics" by Lengyel + /// Formula 4.89. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let a = Quaternion::new(0.0, 2.0, 3.0, 4.0); + /// let b = Quaternion::new(0.0, 5.0, 2.0, 1.0); + /// let expected = Quaternion::new(-20.0, 0.0, 0.0, 0.0); + /// let result = a.inner(&b); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn inner(&self, other: &Self) -> Self { + (self * other + other * self).half() + } + + /// Calculates the outer product (also known as the wedge product). + /// See "Foundations of Game Engine Development, Volume 1: Mathematics" by Lengyel + /// Formula 4.89. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let a = Quaternion::new(0.0, 2.0, 3.0, 4.0); + /// let b = Quaternion::new(0.0, 5.0, 2.0, 1.0); + /// let expected = Quaternion::new(0.0, -5.0, 18.0, -11.0); + /// let result = a.outer(&b); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn outer(&self, other: &Self) -> Self { + #[allow(clippy::eq_op)] + (self * other - other * self).half() + } + + /// Calculates the projection of `self` onto `other` (also known as the parallel). + /// See "Foundations of Game Engine Development, Volume 1: Mathematics" by Lengyel + /// Formula 4.94. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let a = Quaternion::new(0.0, 2.0, 3.0, 4.0); + /// let b = Quaternion::new(0.0, 5.0, 2.0, 1.0); + /// let expected = Quaternion::new(0.0, 3.333333333333333, 1.3333333333333333, 0.6666666666666666); + /// let result = a.project(&b).unwrap(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn project(&self, other: &Self) -> Option + where + T: RealField, + { + self.inner(other).right_div(other) + } + + /// Calculates the rejection of `self` from `other` (also known as the perpendicular). + /// See "Foundations of Game Engine Development, Volume 1: Mathematics" by Lengyel + /// Formula 4.94. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let a = Quaternion::new(0.0, 2.0, 3.0, 4.0); + /// let b = Quaternion::new(0.0, 5.0, 2.0, 1.0); + /// let expected = Quaternion::new(0.0, -1.3333333333333333, 1.6666666666666665, 3.3333333333333335); + /// let result = a.reject(&b).unwrap(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn reject(&self, other: &Self) -> Option + where + T: RealField, + { + self.outer(other).right_div(other) + } + + /// The polar decomposition of this quaternion. + /// + /// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation + /// axis. If the rotation angle is zero, the rotation axis is set to `None`. + /// + /// # Example + /// ``` + /// # use std::f32; + /// # use nalgebra::{Vector3, Quaternion}; + /// let q = Quaternion::new(0.0, 5.0, 0.0, 0.0); + /// let (norm, half_ang, axis) = q.polar_decomposition(); + /// assert_eq!(norm, 5.0); + /// assert_eq!(half_ang, f32::consts::FRAC_PI_2); + /// assert_eq!(axis, Some(Vector3::x_axis())); + /// ``` + #[must_use] + pub fn polar_decomposition(&self) -> (T, T, Option>>) + where + T: RealField, + { + if let Some((q, n)) = Unit::try_new_and_get(self.clone(), T::zero()) { + if let Some(axis) = Unit::try_new(self.vector().clone_owned(), T::zero()) { + let angle = q.angle() / crate::convert(2.0f64); + + (n, angle, Some(axis)) + } else { + (n, T::zero(), None) + } + } else { + (T::zero(), T::zero(), None) + } + } + + /// Compute the natural logarithm of a quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0); + /// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6) + /// ``` + #[inline] + #[must_use] + pub fn ln(&self) -> Self { + let n = self.norm(); + let v = self.vector(); + let s = self.scalar(); + + Self::from_parts(n.clone().simd_ln(), v.normalize() * (s / n).simd_acos()) + } + + /// Compute the exponential of a quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); + /// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5) + /// ``` + #[inline] + #[must_use] + pub fn exp(&self) -> Self { + self.exp_eps(T::simd_default_epsilon()) + } + + /// Compute the exponential of a quaternion. Returns the identity if the vector part of this quaternion + /// has a norm smaller than `eps`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); + /// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5); + /// + /// // Singular case. + /// let q = Quaternion::new(0.0000001, 0.0, 0.0, 0.0); + /// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity()); + /// ``` + #[inline] + #[must_use] + pub fn exp_eps(&self, eps: T) -> Self { + let v = self.vector(); + let nn = v.norm_squared(); + let le = nn.clone().simd_le(eps.clone() * eps); + le.if_else(Self::identity, || { + let w_exp = self.scalar().simd_exp(); + let n = nn.simd_sqrt(); + let nv = v * (w_exp.clone() * n.clone().simd_sin() / n.clone()); + + Self::from_parts(w_exp * n.simd_cos(), nv) + }) + } + + /// Raise the quaternion to a given floating power. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn powf(&self, n: T) -> Self { + (self.ln() * n).exp() + } + + /// Transforms this quaternion into its 4D vector form (Vector part, Scalar part). + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, Vector4}; + /// let mut q = Quaternion::identity(); + /// *q.as_vector_mut() = Vector4::new(1.0, 2.0, 3.0, 4.0); + /// assert!(q.i == 1.0 && q.j == 2.0 && q.k == 3.0 && q.w == 4.0); + /// ``` + #[inline] + pub fn as_vector_mut(&mut self) -> &mut Vector4 { + &mut self.coords + } + + /// The mutable vector part `(i, j, k)` of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, Vector4}; + /// let mut q = Quaternion::identity(); + /// { + /// let mut v = q.vector_mut(); + /// v[0] = 2.0; + /// v[1] = 3.0; + /// v[2] = 4.0; + /// } + /// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0); + /// ``` + #[inline] + pub fn vector_mut( + &mut self, + ) -> MatrixViewMut<'_, T, U3, U1, RStride, CStride> { + self.coords.fixed_rows_mut::<3>(0) + } + + /// Replaces this quaternion by its conjugate. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// q.conjugate_mut(); + /// assert!(q.i == -2.0 && q.j == -3.0 && q.k == -4.0 && q.w == 1.0); + /// ``` + #[inline] + pub fn conjugate_mut(&mut self) { + self.coords[0] = -self.coords[0].clone(); + self.coords[1] = -self.coords[1].clone(); + self.coords[2] = -self.coords[2].clone(); + } + + /// Inverts this quaternion in-place if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let mut q = Quaternion::new(1.0f32, 2.0, 3.0, 4.0); + /// + /// assert!(q.try_inverse_mut()); + /// assert_relative_eq!(q * Quaternion::new(1.0, 2.0, 3.0, 4.0), Quaternion::identity()); + /// + /// //Non-invertible case + /// let mut q = Quaternion::new(0.0f32, 0.0, 0.0, 0.0); + /// assert!(!q.try_inverse_mut()); + /// ``` + #[inline] + pub fn try_inverse_mut(&mut self) -> T::SimdBool { + let norm_squared = self.norm_squared(); + let ge = norm_squared.clone().simd_ge(T::simd_default_epsilon()); + *self = ge.if_else(|| self.conjugate() / norm_squared, || self.clone()); + ge + } + + /// Normalizes this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// q.normalize_mut(); + /// assert_relative_eq!(q.norm(), 1.0); + /// ``` + #[inline] + pub fn normalize_mut(&mut self) -> T { + self.coords.normalize_mut() + } + + /// Calculates square of a quaternion. + #[inline] + #[must_use] + pub fn squared(&self) -> Self { + self * self + } + + /// Divides quaternion into two. + #[inline] + #[must_use] + pub fn half(&self) -> Self { + self / crate::convert(2.0f64) + } + + /// Calculates square root. + #[inline] + #[must_use] + pub fn sqrt(&self) -> Self { + self.powf(crate::convert(0.5)) + } + + /// Check if the quaternion is pure. + /// + /// A quaternion is pure if it has no real part (`self.w == 0.0`). + #[inline] + #[must_use] + pub fn is_pure(&self) -> bool { + self.w.is_zero() + } + + /// Convert quaternion to pure quaternion. + #[inline] + #[must_use] + pub fn pure(&self) -> Self { + Self::from_imag(self.imag()) + } + + /// Left quaternionic division. + /// + /// Calculates B-1 * A where A = self, B = other. + #[inline] + #[must_use] + pub fn left_div(&self, other: &Self) -> Option + where + T: RealField, + { + other.try_inverse().map(|inv| inv * self) + } + + /// Right quaternionic division. + /// + /// Calculates A * B-1 where A = self, B = other. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let a = Quaternion::new(0.0, 1.0, 2.0, 3.0); + /// let b = Quaternion::new(0.0, 5.0, 2.0, 1.0); + /// let result = a.right_div(&b).unwrap(); + /// let expected = Quaternion::new(0.4, 0.13333333333333336, -0.4666666666666667, 0.26666666666666666); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn right_div(&self, other: &Self) -> Option + where + T: RealField, + { + other.try_inverse().map(|inv| self * inv) + } + + /// Calculates the quaternionic cosinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(58.93364616794395, -34.086183690465596, -51.1292755356984, -68.17236738093119); + /// let result = input.cos(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn cos(&self) -> Self { + let z = self.imag().magnitude(); + let w = -self.w.clone().simd_sin() * z.clone().simd_sinhc(); + Self::from_parts(self.w.clone().simd_cos() * z.simd_cosh(), self.imag() * w) + } + + /// Calculates the quaternionic arccosinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let result = input.cos().acos(); + /// assert_relative_eq!(input, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn acos(&self) -> Self { + let u = Self::from_imag(self.imag().normalize()); + let identity = Self::identity(); + + let z = (self + (self.squared() - identity).sqrt()).ln(); + + -(u * z) + } + + /// Calculates the quaternionic sinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(91.78371578403467, 21.886486853029176, 32.82973027954377, 43.77297370605835); + /// let result = input.sin(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn sin(&self) -> Self { + let z = self.imag().magnitude(); + let w = self.w.clone().simd_cos() * z.clone().simd_sinhc(); + Self::from_parts(self.w.clone().simd_sin() * z.simd_cosh(), self.imag() * w) + } + + /// Calculates the quaternionic arcsinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let result = input.sin().asin(); + /// assert_relative_eq!(input, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn asin(&self) -> Self { + let u = Self::from_imag(self.imag().normalize()); + let identity = Self::identity(); + + let z = ((u.clone() * self) + (identity - self.squared()).sqrt()).ln(); + + -(u * z) + } + + /// Calculates the quaternionic tangent. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(0.00003821631725009489, 0.3713971716439371, 0.5570957574659058, 0.7427943432878743); + /// let result = input.tan(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn tan(&self) -> Self + where + T: RealField, + { + self.sin().right_div(&self.cos()).unwrap() + } + + /// Calculates the quaternionic arctangent. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let result = input.tan().atan(); + /// assert_relative_eq!(input, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn atan(&self) -> Self + where + T: RealField, + { + let u = Self::from_imag(self.imag().normalize()); + let num = u.clone() + self; + let den = u.clone() - self; + let fr = num.right_div(&den).unwrap(); + let ln = fr.ln(); + (u.half()) * ln + } + + /// Calculates the hyperbolic quaternionic sinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(0.7323376060463428, -0.4482074499805421, -0.6723111749708133, -0.8964148999610843); + /// let result = input.sinh(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn sinh(&self) -> Self { + (self.exp() - (-self).exp()).half() + } + + /// Calculates the hyperbolic quaternionic arcsinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(2.385889902585242, 0.514052600662788, 0.7710789009941821, 1.028105201325576); + /// let result = input.asinh(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn asinh(&self) -> Self { + let identity = Self::identity(); + (self + (identity + self.squared()).sqrt()).ln() + } + + /// Calculates the hyperbolic quaternionic cosinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(0.9615851176369566, -0.3413521745610167, -0.5120282618415251, -0.6827043491220334); + /// let result = input.cosh(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn cosh(&self) -> Self { + (self.exp() + (-self).exp()).half() + } + + /// Calculates the hyperbolic quaternionic arccosinus. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(2.4014472020074007, 0.5162761016176176, 0.7744141524264264, 1.0325522032352352); + /// let result = input.acosh(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn acosh(&self) -> Self { + let identity = Self::identity(); + (self + (self + identity.clone()).sqrt() * (self - identity).sqrt()).ln() + } + + /// Calculates the hyperbolic quaternionic tangent. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(1.0248695360556623, -0.10229568178876419, -0.1534435226831464, -0.20459136357752844); + /// let result = input.tanh(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn tanh(&self) -> Self + where + T: RealField, + { + self.sinh().right_div(&self.cosh()).unwrap() + } + + /// Calculates the hyperbolic quaternionic arctangent. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Quaternion; + /// let input = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let expected = Quaternion::new(0.03230293287000163, 0.5173453683196951, 0.7760180524795426, 1.0346907366393903); + /// let result = input.atanh(); + /// assert_relative_eq!(expected, result, epsilon = 1.0e-7); + /// ``` + #[inline] + #[must_use] + pub fn atanh(&self) -> Self { + let identity = Self::identity(); + ((identity.clone() + self).ln() - (identity - self).ln()).half() + } +} + +impl> AbsDiffEq for Quaternion { + type Epsilon = T; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.as_vector().abs_diff_eq(other.as_vector(), epsilon.clone()) || + // Account for the double-covering of S², i.e. q = -q + self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.abs_diff_eq(&-b.clone(), epsilon.clone())) + } +} + +impl> RelativeEq for Quaternion { + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.as_vector().relative_eq(other.as_vector(), epsilon.clone(), max_relative.clone()) || + // Account for the double-covering of S², i.e. q = -q + self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.relative_eq(&-b.clone(), epsilon.clone(), max_relative.clone())) + } +} + +impl> UlpsEq for Quaternion { + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.as_vector().ulps_eq(other.as_vector(), epsilon.clone(), max_ulps) || + // Account for the double-covering of S², i.e. q = -q. + self.as_vector().iter().zip(other.as_vector().iter()).all(|(a, b)| a.ulps_eq(&-b.clone(), epsilon.clone(), max_ulps)) + } +} + +impl fmt::Display for Quaternion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Quaternion {} − ({}, {}, {})", + self[3], self[0], self[1], self[2] + ) + } +} + +/// A unit quaternions. May be used to represent a rotation. +pub type UnitQuaternion = Unit>; + +impl PartialEq for UnitQuaternion { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + self.coords == rhs.coords || + // Account for the double-covering of S², i.e. q = -q + self.coords.iter().zip(rhs.coords.iter()).all(|(a, b)| *a == -b.clone()) + } +} + +impl Eq for UnitQuaternion {} + +impl Normed for Quaternion { + type Norm = T::SimdRealField; + + #[inline] + fn norm(&self) -> T::SimdRealField { + self.coords.norm() + } + + #[inline] + fn norm_squared(&self) -> T::SimdRealField { + self.coords.norm_squared() + } + + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.coords.scale_mut(n) + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.coords.unscale_mut(n) + } +} + +impl UnitQuaternion +where + T::Element: SimdRealField, +{ + /// The rotation angle in [0; pi] of this unit quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{Unit, UnitQuaternion, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78); + /// assert_eq!(rot.angle(), 1.78); + /// ``` + #[inline] + #[must_use] + pub fn angle(&self) -> T { + let w = self.quaternion().scalar().simd_abs(); + self.quaternion().imag().norm().simd_atan2(w) * crate::convert(2.0f64) + } + + /// The underlying quaternion. + /// + /// Same as `self.as_ref()`. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Quaternion}; + /// let axis = UnitQuaternion::identity(); + /// assert_eq!(*axis.quaternion(), Quaternion::new(1.0, 0.0, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn quaternion(&self) -> &Quaternion { + self.as_ref() + } + + /// Compute the conjugate of this unit quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{Unit, UnitQuaternion, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78); + /// let conj = rot.conjugate(); + /// assert_eq!(conj, UnitQuaternion::from_axis_angle(&-axis, 1.78)); + /// ``` + #[inline] + #[must_use = "Did you mean to use conjugate_mut()?"] + pub fn conjugate(&self) -> Self { + Self::new_unchecked(self.as_ref().conjugate()) + } + + /// Inverts this quaternion if it is not zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{Unit, UnitQuaternion, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78); + /// let inv = rot.inverse(); + /// assert_eq!(rot * inv, UnitQuaternion::identity()); + /// assert_eq!(inv * rot, UnitQuaternion::identity()); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Self { + self.conjugate() + } + + /// The rotation angle needed to make `self` and `other` coincide. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn angle_to(&self, other: &Self) -> T { + let delta = self.rotation_to(other); + delta.angle() + } + + /// The unit quaternion needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); + /// let rot_to = rot1.rotation_to(&rot2); + /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn rotation_to(&self, other: &Self) -> Self { + other / self + } + + /// Linear interpolation between two unit quaternions. + /// + /// The result is not normalized. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Quaternion}; + /// let q1 = UnitQuaternion::new_normalize(Quaternion::new(1.0, 0.0, 0.0, 0.0)); + /// let q2 = UnitQuaternion::new_normalize(Quaternion::new(0.0, 1.0, 0.0, 0.0)); + /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(0.9, 0.1, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn lerp(&self, other: &Self, t: T) -> Quaternion { + self.as_ref().lerp(other.as_ref(), t) + } + + /// Normalized linear interpolation between two unit quaternions. + /// + /// This is the same as `self.lerp` except that the result is normalized. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Quaternion}; + /// let q1 = UnitQuaternion::new_normalize(Quaternion::new(1.0, 0.0, 0.0, 0.0)); + /// let q2 = UnitQuaternion::new_normalize(Quaternion::new(0.0, 1.0, 0.0, 0.0)); + /// assert_eq!(q1.nlerp(&q2, 0.1), UnitQuaternion::new_normalize(Quaternion::new(0.9, 0.1, 0.0, 0.0))); + /// ``` + #[inline] + #[must_use] + pub fn nlerp(&self, other: &Self, t: T) -> Self { + let mut res = self.lerp(other, t); + let _ = res.normalize_mut(); + + Self::new_unchecked(res) + } + + /// Spherical linear interpolation between two unit quaternions. + /// + /// Panics if the angle between both quaternion is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_slerp` instead to avoid the panic. + /// + /// # Example + /// ``` + /// # use nalgebra::geometry::UnitQuaternion; + /// + /// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0); + /// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0); + /// + /// let q = q1.slerp(&q2, 1.0 / 3.0); + /// + /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn slerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + self.try_slerp(other, t, T::default_epsilon()) + .expect("Quaternion slerp: ambiguous configuration.") + } + + /// Computes the spherical linear interpolation between two unit quaternions or returns `None` + /// if both quaternions are approximately 180 degrees apart (in which case the interpolation is + /// not well-defined). + /// + /// # Arguments + /// * `self`: the first quaternion to interpolate from. + /// * `other`: the second quaternion to interpolate toward. + /// * `t`: the interpolation parameter. Should be between 0 and 1. + /// * `epsilon`: the value below which the sinus of the angle separating both quaternion + /// must be to return `None`. + #[inline] + #[must_use] + pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option + where + T: RealField, + { + let coords = if self.coords.dot(&other.coords) < T::zero() { + Unit::new_unchecked(self.coords.clone()).try_slerp( + &Unit::new_unchecked(-other.coords.clone()), + t, + epsilon, + ) + } else { + Unit::new_unchecked(self.coords.clone()).try_slerp( + &Unit::new_unchecked(other.coords.clone()), + t, + epsilon, + ) + }; + + coords.map(|q| Unit::new_unchecked(Quaternion::from(q.into_inner()))) + } + + /// Compute the conjugate of this unit quaternion in-place. + #[inline] + pub fn conjugate_mut(&mut self) { + self.as_mut_unchecked().conjugate_mut() + } + + /// Inverts this quaternion if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitQuaternion, Vector3, Unit}; + /// let axisangle = Vector3::new(0.1, 0.2, 0.3); + /// let mut rot = UnitQuaternion::new(axisangle); + /// rot.inverse_mut(); + /// assert_relative_eq!(rot * UnitQuaternion::new(axisangle), UnitQuaternion::identity()); + /// assert_relative_eq!(UnitQuaternion::new(axisangle) * rot, UnitQuaternion::identity()); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) { + self.as_mut_unchecked().conjugate_mut() + } + + /// The rotation axis of this unit quaternion or `None` if the rotation is zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = UnitQuaternion::from_axis_angle(&axis, angle); + /// assert_eq!(rot.axis(), Some(axis)); + /// + /// // Case with a zero angle. + /// let rot = UnitQuaternion::from_axis_angle(&axis, 0.0); + /// assert!(rot.axis().is_none()); + /// ``` + #[inline] + #[must_use] + pub fn axis(&self) -> Option>> + where + T: RealField, + { + let v = if self.quaternion().scalar() >= T::zero() { + self.as_ref().vector().clone_owned() + } else { + -self.as_ref().vector() + }; + + Unit::try_new(v, T::zero()) + } + + /// The rotation axis of this unit quaternion multiplied by the rotation angle. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitQuaternion, Vector3, Unit}; + /// let axisangle = Vector3::new(0.1, 0.2, 0.3); + /// let rot = UnitQuaternion::new(axisangle); + /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn scaled_axis(&self) -> Vector3 + where + T: RealField, + { + if let Some(axis) = self.axis() { + axis.into_inner() * self.angle() + } else { + Vector3::zero() + } + } + + /// The rotation axis and angle in (0, pi] of this unit quaternion. + /// + /// Returns `None` if the angle is zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = UnitQuaternion::from_axis_angle(&axis, angle); + /// assert_eq!(rot.axis_angle(), Some((axis, angle))); + /// + /// // Case with a zero angle. + /// let rot = UnitQuaternion::from_axis_angle(&axis, 0.0); + /// assert!(rot.axis_angle().is_none()); + /// ``` + #[inline] + #[must_use] + pub fn axis_angle(&self) -> Option<(Unit>, T)> + where + T: RealField, + { + self.axis().map(|axis| (axis, self.angle())) + } + + /// Compute the exponential of a quaternion. + /// + /// Note that this function yields a `Quaternion` because it loses the unit property. + #[inline] + #[must_use] + pub fn exp(&self) -> Quaternion { + self.as_ref().exp() + } + + /// Compute the natural logarithm of a quaternion. + /// + /// Note that this function yields a `Quaternion` because it loses the unit property. + /// The vector part of the return value corresponds to the axis-angle representation (divided + /// by 2.0) of this unit quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector3, UnitQuaternion}; + /// let axisangle = Vector3::new(0.1, 0.2, 0.3); + /// let q = UnitQuaternion::new(axisangle); + /// assert_relative_eq!(q.ln().vector().into_owned(), axisangle, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn ln(&self) -> Quaternion + where + T: RealField, + { + if let Some(v) = self.axis() { + Quaternion::from_imag(v.into_inner() * self.angle()) + } else { + Quaternion::zero() + } + } + + /// Raise the quaternion to a given floating power. + /// + /// This returns the unit quaternion that identifies a rotation with axis `self.axis()` and + /// angle `self.angle() × n`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitQuaternion, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = UnitQuaternion::from_axis_angle(&axis, angle); + /// let pow = rot.powf(2.0); + /// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6); + /// assert_eq!(pow.angle(), 2.4); + /// ``` + #[inline] + #[must_use] + pub fn powf(&self, n: T) -> Self + where + T: RealField, + { + if let Some(v) = self.axis() { + Self::from_axis_angle(&v, self.angle() * n) + } else { + Self::identity() + } + } + + /// Builds a rotation matrix from this unit quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3, Matrix3}; + /// let q = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); + /// let rot = q.to_rotation_matrix(); + /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// + /// assert_relative_eq!(*rot.matrix(), expected, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn to_rotation_matrix(self) -> Rotation { + let i = self.as_ref()[0].clone(); + let j = self.as_ref()[1].clone(); + let k = self.as_ref()[2].clone(); + let w = self.as_ref()[3].clone(); + + let ww = w.clone() * w.clone(); + let ii = i.clone() * i.clone(); + let jj = j.clone() * j.clone(); + let kk = k.clone() * k.clone(); + let ij = i.clone() * j.clone() * crate::convert(2.0f64); + let wk = w.clone() * k.clone() * crate::convert(2.0f64); + let wj = w.clone() * j.clone() * crate::convert(2.0f64); + let ik = i.clone() * k.clone() * crate::convert(2.0f64); + let jk = j * k * crate::convert(2.0f64); + let wi = w * i * crate::convert(2.0f64); + + Rotation::from_matrix_unchecked(Matrix3::new( + ww.clone() + ii.clone() - jj.clone() - kk.clone(), + ij.clone() - wk.clone(), + wj.clone() + ik.clone(), + wk + ij, + ww.clone() - ii.clone() + jj.clone() - kk.clone(), + jk.clone() - wi.clone(), + ik - wj, + wi + jk, + ww - ii - jj + kk, + )) + } + + /// Converts this unit quaternion into its equivalent Euler angles. + /// + /// The angles are produced in the form (roll, pitch, yaw). + #[inline] + #[deprecated(note = "This is renamed to use `.euler_angles()`.")] + pub fn to_euler_angles(self) -> (T, T, T) + where + T: RealField, + { + self.euler_angles() + } + + /// Retrieves the euler angles corresponding to this unit quaternion. + /// + /// The angles are produced in the form (roll, pitch, yaw). + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitQuaternion; + /// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3); + /// let euler = rot.euler_angles(); + /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn euler_angles(&self) -> (T, T, T) + where + T: RealField, + { + self.clone().to_rotation_matrix().euler_angles() + } + + /// Converts this unit quaternion into its equivalent homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3, Matrix4}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); + /// let expected = Matrix4::new(0.8660254, -0.5, 0.0, 0.0, + /// 0.5, 0.8660254, 0.0, 0.0, + /// 0.0, 0.0, 1.0, 0.0, + /// 0.0, 0.0, 0.0, 1.0); + /// + /// assert_relative_eq!(rot.to_homogeneous(), expected, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(self) -> Matrix4 { + self.to_rotation_matrix().to_homogeneous() + } + + /// Rotate a point by this unit quaternion. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3, Point3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_point = rot.transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point3) -> Point3 { + self * pt + } + + /// Rotate a vector by this unit quaternion. + /// + /// This is the same as the multiplication `self * v`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &Vector3) -> Vector3 { + self * v + } + + /// Rotate a point by the inverse of this unit quaternion. This may be + /// cheaper than inverting the unit quaternion and transforming the + /// point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3, Point3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_point = rot.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point3) -> Point3 { + // TODO: would it be useful performance-wise not to call inverse explicitly (i-e. implement + // the inverse transformation explicitly here) ? + self.inverse() * pt + } + + /// Rotate a vector by the inverse of this unit quaternion. This may be + /// cheaper than inverting the unit quaternion and transforming the + /// vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { + self.inverse() * v + } + + /// Rotate a vector by the inverse of this unit quaternion. This may be + /// cheaper than inverting the unit quaternion and transforming the + /// vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_unit_vector(&Vector3::x_axis()); + /// + /// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + self.inverse() * v + } + + /// Appends to `self` a rotation given in the axis-angle form, using a linearized formulation. + /// + /// This is faster, but approximate, way to compute `UnitQuaternion::new(axisangle) * self`. + #[inline] + #[must_use] + pub fn append_axisangle_linearized(&self, axisangle: &Vector3) -> Self { + let half: T = crate::convert(0.5); + let q1 = self.clone().into_inner(); + let q2 = Quaternion::from_imag(axisangle * half); + Unit::new_normalize(&q1 + q2 * &q1) + } +} + +impl Default for UnitQuaternion { + fn default() -> Self { + Self::identity() + } +} + +impl fmt::Display for UnitQuaternion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(axis) = self.axis() { + let axis = axis.into_inner(); + write!( + f, + "UnitQuaternion angle: {} − axis: ({}, {}, {})", + self.angle(), + axis[0], + axis[1], + axis[2] + ) + } else { + write!( + f, + "UnitQuaternion angle: {} − axis: (undefined)", + self.angle() + ) + } + } +} + +impl> AbsDiffEq for UnitQuaternion { + type Epsilon = T; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.as_ref().abs_diff_eq(other.as_ref(), epsilon) + } +} + +impl> RelativeEq for UnitQuaternion { + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.as_ref() + .relative_eq(other.as_ref(), epsilon, max_relative) + } +} + +impl> UlpsEq for UnitQuaternion { + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_construction.rs new file mode 100644 index 000000000..44308cccf --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_construction.rs @@ -0,0 +1,928 @@ +#[cfg(feature = "arbitrary")] +use crate::base::dimension::U4; +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{uniform::SampleUniform, Distribution, OpenClosed01, Standard, Uniform}, + Rng, +}; + +use num::{One, Zero}; + +use simba::scalar::{RealField, SupersetOf}; +use simba::simd::SimdBool; + +use crate::base::dimension::U3; +use crate::base::storage::Storage; +use crate::base::{Matrix3, Matrix4, Unit, Vector, Vector3, Vector4}; +use crate::{Scalar, SimdRealField}; + +use crate::geometry::{Quaternion, Rotation3, UnitQuaternion}; + +impl Quaternion { + /// Creates a quaternion from a 4D vector. The quaternion scalar part corresponds to the `w` + /// vector component. + #[inline] + // #[deprecated(note = "Use `::from` instead.")] // Don't deprecate because this one can be a const-fn. + pub const fn from_vector(vector: Vector4) -> Self { + Self { coords: vector } + } + + /// Creates a new quaternion from its individual components. Note that the arguments order does + /// **not** follow the storage order. + /// + /// The storage order is `[ i, j, k, w ]` while the arguments for this functions are in the + /// order `(w, i, j, k)`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, Vector4}; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0); + /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); + /// ``` + #[inline] + pub const fn new(w: T, i: T, j: T, k: T) -> Self { + Self::from_vector(Vector4::new(i, j, k, w)) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0f64, 2.0, 3.0, 4.0); + /// let q2 = q.cast::(); + /// assert_eq!(q2, Quaternion::new(1.0f32, 2.0, 3.0, 4.0)); + /// ``` + pub fn cast(self) -> Quaternion + where + T: Scalar, + To: SupersetOf, + { + crate::convert(self) + } +} + +impl Quaternion { + /// Constructs a pure quaternion. + #[inline] + pub fn from_imag(vector: Vector3) -> Self { + Self::from_parts(T::zero(), vector) + } + + /// Creates a new quaternion from its scalar and vector parts. Note that the arguments order does + /// **not** follow the storage order. + /// + /// The storage order is [ vector, scalar ]. + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, Vector3, Vector4}; + /// let w = 1.0; + /// let ijk = Vector3::new(2.0, 3.0, 4.0); + /// let q = Quaternion::from_parts(w, ijk); + /// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0); + /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); + /// ``` + #[inline] + // TODO: take a reference to `vector`? + pub fn from_parts(scalar: T, vector: Vector) -> Self + where + SB: Storage, + { + Self::new( + scalar, + vector[0].clone(), + vector[1].clone(), + vector[2].clone(), + ) + } + + /// Constructs a real quaternion. + #[inline] + pub fn from_real(r: T) -> Self { + Self::from_parts(r, Vector3::zero()) + } + + /// The quaternion multiplicative identity. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::identity(); + /// let q2 = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// + /// assert_eq!(q * q2, q2); + /// assert_eq!(q2 * q, q2); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::from_real(T::one()) + } +} + +// TODO: merge with the previous block. +impl Quaternion +where + T::Element: SimdRealField, +{ + /// Creates a new quaternion from its polar decomposition. + /// + /// Note that `axis` is assumed to be a unit vector. + // TODO: take a reference to `axis`? + pub fn from_polar_decomposition(scale: T, theta: T, axis: Unit>) -> Self + where + SB: Storage, + { + let rot = UnitQuaternion::::from_axis_angle(&axis, theta * crate::convert(2.0f64)); + + rot.into_inner() * scale + } +} + +impl One for Quaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} + +impl Zero for Quaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn zero() -> Self { + Self::from(Vector4::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + self.coords.is_zero() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, +{ + #[inline] + fn sample(&self, rng: &mut R) -> Quaternion { + Quaternion::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Quaternion +where + Owned: Send, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + Self::new( + T::arbitrary(g), + T::arbitrary(g), + T::arbitrary(g), + T::arbitrary(g), + ) + } +} + +impl UnitQuaternion +where + T::Element: SimdRealField, +{ + /// The rotation identity. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Vector3, Point3}; + /// let q = UnitQuaternion::identity(); + /// let q2 = UnitQuaternion::new(Vector3::new(1.0, 2.0, 3.0)); + /// let v = Vector3::new_random(); + /// let p = Point3::from(v); + /// + /// assert_eq!(q * q2, q2); + /// assert_eq!(q2 * q, q2); + /// assert_eq!(q * v, v); + /// assert_eq!(q * p, p); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::new_unchecked(Quaternion::identity()) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitQuaternion; + /// # use approx::assert_relative_eq; + /// let q = UnitQuaternion::from_euler_angles(1.0f64, 2.0, 3.0); + /// let q2 = q.cast::(); + /// assert_relative_eq!(q2, UnitQuaternion::from_euler_angles(1.0f32, 2.0, 3.0), epsilon = 1.0e-6); + /// ``` + pub fn cast(self) -> UnitQuaternion + where + To: SupersetOf, + { + crate::convert(self) + } + + /// Creates a new quaternion from a unit vector (the rotation axis) and an angle + /// (the rotation angle). + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Point3, Vector3}; + /// let axis = Vector3::y_axis(); + /// let angle = f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let q = UnitQuaternion::from_axis_angle(&axis, angle); + /// + /// assert_eq!(q.axis().unwrap(), axis); + /// assert_eq!(q.angle(), angle); + /// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // A zero vector yields an identity. + /// assert_eq!(UnitQuaternion::from_scaled_axis(Vector3::::zeros()), UnitQuaternion::identity()); + /// ``` + #[inline] + pub fn from_axis_angle(axis: &Unit>, angle: T) -> Self + where + SB: Storage, + { + let (sang, cang) = (angle / crate::convert(2.0f64)).simd_sin_cos(); + + let q = Quaternion::from_parts(cang, axis.as_ref() * sang); + Self::new_unchecked(q) + } + + /// Creates a new unit quaternion from a quaternion. + /// + /// The input quaternion will be normalized. + #[inline] + pub fn from_quaternion(q: Quaternion) -> Self { + Self::new_normalize(q) + } + + /// Creates a new unit quaternion from Euler angles. + /// + /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitQuaternion; + /// let rot = UnitQuaternion::from_euler_angles(0.1, 0.2, 0.3); + /// let euler = rot.euler_angles(); + /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn from_euler_angles(roll: T, pitch: T, yaw: T) -> Self { + let (sr, cr) = (roll * crate::convert(0.5f64)).simd_sin_cos(); + let (sp, cp) = (pitch * crate::convert(0.5f64)).simd_sin_cos(); + let (sy, cy) = (yaw * crate::convert(0.5f64)).simd_sin_cos(); + + let q = Quaternion::new( + cr.clone() * cp.clone() * cy.clone() + sr.clone() * sp.clone() * sy.clone(), + sr.clone() * cp.clone() * cy.clone() - cr.clone() * sp.clone() * sy.clone(), + cr.clone() * sp.clone() * cy.clone() + sr.clone() * cp.clone() * sy.clone(), + cr * cp * sy - sr * sp * cy, + ); + + Self::new_unchecked(q) + } + + /// Builds an unit quaternion from a basis assumed to be orthonormal. + /// + /// In order to get a valid unit-quaternion, the input must be an + /// orthonormal basis, i.e., all vectors are normalized, and the are + /// all orthogonal to each other. These invariants are not checked + /// by this method. + pub fn from_basis_unchecked(basis: &[Vector3; 3]) -> Self { + let rot = Rotation3::from_basis_unchecked(basis); + Self::from_rotation_matrix(&rot) + } + + /// Builds an unit quaternion from a rotation matrix. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, UnitQuaternion, Vector3}; + /// let axis = Vector3::y_axis(); + /// let angle = 0.1; + /// let rot = Rotation3::from_axis_angle(&axis, angle); + /// let q = UnitQuaternion::from_rotation_matrix(&rot); + /// assert_relative_eq!(q.to_rotation_matrix(), rot, epsilon = 1.0e-6); + /// assert_relative_eq!(q.axis().unwrap(), rot.axis().unwrap(), epsilon = 1.0e-6); + /// assert_relative_eq!(q.angle(), rot.angle(), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn from_rotation_matrix(rotmat: &Rotation3) -> Self { + // Robust matrix to quaternion transformation. + // See https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion + let tr = rotmat[(0, 0)].clone() + rotmat[(1, 1)].clone() + rotmat[(2, 2)].clone(); + let quarter: T = crate::convert(0.25); + + let res = tr.clone().simd_gt(T::zero()).if_else3( + || { + let denom = (tr.clone() + T::one()).simd_sqrt() * crate::convert(2.0); + Quaternion::new( + quarter.clone() * denom.clone(), + (rotmat[(2, 1)].clone() - rotmat[(1, 2)].clone()) / denom.clone(), + (rotmat[(0, 2)].clone() - rotmat[(2, 0)].clone()) / denom.clone(), + (rotmat[(1, 0)].clone() - rotmat[(0, 1)].clone()) / denom, + ) + }, + ( + || { + rotmat[(0, 0)].clone().simd_gt(rotmat[(1, 1)].clone()) + & rotmat[(0, 0)].clone().simd_gt(rotmat[(2, 2)].clone()) + }, + || { + let denom = (T::one() + rotmat[(0, 0)].clone() + - rotmat[(1, 1)].clone() + - rotmat[(2, 2)].clone()) + .simd_sqrt() + * crate::convert(2.0); + Quaternion::new( + (rotmat[(2, 1)].clone() - rotmat[(1, 2)].clone()) / denom.clone(), + quarter.clone() * denom.clone(), + (rotmat[(0, 1)].clone() + rotmat[(1, 0)].clone()) / denom.clone(), + (rotmat[(0, 2)].clone() + rotmat[(2, 0)].clone()) / denom, + ) + }, + ), + ( + || rotmat[(1, 1)].clone().simd_gt(rotmat[(2, 2)].clone()), + || { + let denom = (T::one() + rotmat[(1, 1)].clone() + - rotmat[(0, 0)].clone() + - rotmat[(2, 2)].clone()) + .simd_sqrt() + * crate::convert(2.0); + Quaternion::new( + (rotmat[(0, 2)].clone() - rotmat[(2, 0)].clone()) / denom.clone(), + (rotmat[(0, 1)].clone() + rotmat[(1, 0)].clone()) / denom.clone(), + quarter.clone() * denom.clone(), + (rotmat[(1, 2)].clone() + rotmat[(2, 1)].clone()) / denom, + ) + }, + ), + || { + let denom = (T::one() + rotmat[(2, 2)].clone() + - rotmat[(0, 0)].clone() + - rotmat[(1, 1)].clone()) + .simd_sqrt() + * crate::convert(2.0); + Quaternion::new( + (rotmat[(1, 0)].clone() - rotmat[(0, 1)].clone()) / denom.clone(), + (rotmat[(0, 2)].clone() + rotmat[(2, 0)].clone()) / denom.clone(), + (rotmat[(1, 2)].clone() + rotmat[(2, 1)].clone()) / denom.clone(), + quarter.clone() * denom, + ) + }, + ); + + Self::new_unchecked(res) + } + + /// Builds an unit quaternion by extracting the rotation part of the given transformation `m`. + /// + /// This is an iterative method. See `.from_matrix_eps` to provide mover + /// convergence parameters and starting solution. + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + pub fn from_matrix(m: &Matrix3) -> Self + where + T: RealField, + { + Rotation3::from_matrix(m).into() + } + + /// Builds an unit quaternion by extracting the rotation part of the given transformation `m`. + /// + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + /// + /// # Parameters + /// + /// * `m`: the matrix from which the rotational part is to be extracted. + /// * `eps`: the angular errors tolerated between the current rotation and the optimal one. + /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`. + /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close + /// to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other + /// guesses come to mind. + pub fn from_matrix_eps(m: &Matrix3, eps: T, max_iter: usize, guess: Self) -> Self + where + T: RealField, + { + let guess = Rotation3::from(guess); + Rotation3::from_matrix_eps(m, eps, max_iter, guess).into() + } + + /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same + /// direction. Returns `None` if both `a` and `b` are collinear and point to opposite directions, as then the + /// rotation desired is not unique. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector3, UnitQuaternion}; + /// let a = Vector3::new(1.0, 2.0, 3.0); + /// let b = Vector3::new(3.0, 1.0, 2.0); + /// let q = UnitQuaternion::rotation_between(&a, &b).unwrap(); + /// assert_relative_eq!(q * a, b); + /// assert_relative_eq!(q.inverse() * b, a); + /// ``` + #[inline] + pub fn rotation_between(a: &Vector, b: &Vector) -> Option + where + T: RealField, + SB: Storage, + SC: Storage, + { + Self::scaled_rotation_between(a, b, T::one()) + } + + /// The smallest rotation needed to make `a` and `b` collinear and point toward the same + /// direction, raised to the power `s`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector3, UnitQuaternion}; + /// let a = Vector3::new(1.0, 2.0, 3.0); + /// let b = Vector3::new(3.0, 1.0, 2.0); + /// let q2 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.2).unwrap(); + /// let q5 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.5).unwrap(); + /// assert_relative_eq!(q2 * q2 * q2 * q2 * q2 * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(q5 * q5 * a, b, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn scaled_rotation_between( + a: &Vector, + b: &Vector, + s: T, + ) -> Option + where + T: RealField, + SB: Storage, + SC: Storage, + { + // TODO: code duplication with Rotation. + if let (Some(na), Some(nb)) = ( + Unit::try_new(a.clone_owned(), T::zero()), + Unit::try_new(b.clone_owned(), T::zero()), + ) { + Self::scaled_rotation_between_axis(&na, &nb, s) + } else { + Some(Self::identity()) + } + } + + /// The unit quaternion needed to make `a` and `b` be collinear and point toward the same + /// direction. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Unit, Vector3, UnitQuaternion}; + /// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0)); + /// let q = UnitQuaternion::rotation_between(&a, &b).unwrap(); + /// assert_relative_eq!(q * a, b); + /// assert_relative_eq!(q.inverse() * b, a); + /// ``` + #[inline] + pub fn rotation_between_axis( + a: &Unit>, + b: &Unit>, + ) -> Option + where + T: RealField, + SB: Storage, + SC: Storage, + { + Self::scaled_rotation_between_axis(a, b, T::one()) + } + + /// The smallest rotation needed to make `a` and `b` collinear and point toward the same + /// direction, raised to the power `s`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Unit, Vector3, UnitQuaternion}; + /// let a = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let b = Unit::new_normalize(Vector3::new(3.0, 1.0, 2.0)); + /// let q2 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.2).unwrap(); + /// let q5 = UnitQuaternion::scaled_rotation_between(&a, &b, 0.5).unwrap(); + /// assert_relative_eq!(q2 * q2 * q2 * q2 * q2 * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(q5 * q5 * a, b, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn scaled_rotation_between_axis( + na: &Unit>, + nb: &Unit>, + s: T, + ) -> Option + where + T: RealField, + SB: Storage, + SC: Storage, + { + // TODO: code duplication with Rotation. + let c = na.cross(nb); + + if let Some(axis) = Unit::try_new(c, T::default_epsilon()) { + let cos = na.dot(nb); + + // The cosinus may be out of [-1, 1] because of inaccuracies. + if cos <= -T::one() { + None + } else if cos >= T::one() { + Some(Self::identity()) + } else { + Some(Self::from_axis_angle(&axis, cos.acos() * s)) + } + } else if na.dot(nb) < T::zero() { + // PI + // + // The rotation axis is undefined but the angle not zero. This is not a + // simple rotation. + None + } else { + // Zero + Some(Self::identity()) + } + } + + /// Creates an unit quaternion that corresponds to the local frame of an observer standing at the + /// origin and looking toward `dir`. + /// + /// It maps the `z` axis to the direction `dir`. + /// + /// # Arguments + /// * dir - The look direction. It does not need to be normalized. + /// * up - The vertical direction. It does not need to be normalized. + /// The only requirement of this parameter is to not be collinear to `dir`. Non-collinearity + /// is not checked. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let dir = Vector3::new(1.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// let q = UnitQuaternion::face_towards(&dir, &up); + /// assert_relative_eq!(q * Vector3::z(), dir.normalize()); + /// ``` + #[inline] + pub fn face_towards(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::from_rotation_matrix(&Rotation3::face_towards(dir, up)) + } + + /// Deprecated: Use [`UnitQuaternion::face_towards`] instead. + #[deprecated(note = "renamed to `face_towards`")] + pub fn new_observer_frames(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::face_towards(dir, up) + } + + /// Builds a right-handed look-at view matrix without translation. + /// + /// It maps the view direction `dir` to the **negative** `z` axis. + /// This conforms to the common notion of right handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * dir − The view direction. It does not need to be normalized. + /// * up - A vector approximately aligned with required the vertical axis. It does not need + /// to be normalized. The only requirement of this parameter is to not be collinear to `dir`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let dir = Vector3::new(1.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// let q = UnitQuaternion::look_at_rh(&dir, &up); + /// assert_relative_eq!(q * dir.normalize(), -Vector3::z()); + /// ``` + #[inline] + pub fn look_at_rh(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::face_towards(&-dir, up).inverse() + } + + /// Builds a left-handed look-at view matrix without translation. + /// + /// It maps the view direction `dir` to the **positive** `z` axis. + /// This conforms to the common notion of left handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * dir − The view direction. It does not need to be normalized. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `dir`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let dir = Vector3::new(1.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// let q = UnitQuaternion::look_at_lh(&dir, &up); + /// assert_relative_eq!(q * dir.normalize(), Vector3::z()); + /// ``` + #[inline] + pub fn look_at_lh(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::face_towards(dir, up).inverse() + } + + /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. + /// + /// If `axisangle` has a magnitude smaller than `T::default_epsilon()`, this returns the identity rotation. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let q = UnitQuaternion::new(axisangle); + /// + /// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // A zero vector yields an identity. + /// assert_eq!(UnitQuaternion::new(Vector3::::zeros()), UnitQuaternion::identity()); + /// ``` + #[inline] + pub fn new(axisangle: Vector) -> Self + where + SB: Storage, + { + let two: T = crate::convert(2.0f64); + let q = Quaternion::::from_imag(axisangle / two).exp(); + Self::new_unchecked(q) + } + + /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. + /// + /// If `axisangle` has a magnitude smaller than `eps`, this returns the identity rotation. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let q = UnitQuaternion::new_eps(axisangle, 1.0e-6); + /// + /// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // An almost zero vector yields an identity. + /// assert_eq!(UnitQuaternion::new_eps(Vector3::new(1.0e-8, 1.0e-9, 1.0e-7), 1.0e-6), UnitQuaternion::identity()); + /// ``` + #[inline] + pub fn new_eps(axisangle: Vector, eps: T) -> Self + where + SB: Storage, + { + let two: T = crate::convert(2.0f64); + let q = Quaternion::::from_imag(axisangle / two).exp_eps(eps); + Self::new_unchecked(q) + } + + /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. + /// + /// If `axisangle` has a magnitude smaller than `T::default_epsilon()`, this returns the identity rotation. + /// Same as `Self::new(axisangle)`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let q = UnitQuaternion::from_scaled_axis(axisangle); + /// + /// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // A zero vector yields an identity. + /// assert_eq!(UnitQuaternion::from_scaled_axis(Vector3::::zeros()), UnitQuaternion::identity()); + /// ``` + #[inline] + pub fn from_scaled_axis(axisangle: Vector) -> Self + where + SB: Storage, + { + Self::new(axisangle) + } + + /// Creates a new unit quaternion rotation from a rotation axis scaled by the rotation angle. + /// + /// If `axisangle` has a magnitude smaller than `eps`, this returns the identity rotation. + /// Same as `Self::new_eps(axisangle, eps)`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let q = UnitQuaternion::from_scaled_axis_eps(axisangle, 1.0e-6); + /// + /// assert_relative_eq!(q * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(q * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // An almost zero vector yields an identity. + /// assert_eq!(UnitQuaternion::from_scaled_axis_eps(Vector3::new(1.0e-8, 1.0e-9, 1.0e-7), 1.0e-6), UnitQuaternion::identity()); + /// ``` + #[inline] + pub fn from_scaled_axis_eps(axisangle: Vector, eps: T) -> Self + where + SB: Storage, + { + Self::new_eps(axisangle, eps) + } + + /// Create the mean unit quaternion from a data structure implementing `IntoIterator` + /// returning unit quaternions. + /// + /// The method will panic if the iterator does not return any quaternions. + /// + /// Algorithm from: Oshman, Yaakov, and Avishy Carmi. "Attitude estimation from vector + /// observations using a genetic-algorithm-embedded quaternion particle filter." Journal of + /// Guidance, Control, and Dynamics 29.4 (2006): 879-891. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion}; + /// let q1 = UnitQuaternion::from_euler_angles(0.0, 0.0, 0.0); + /// let q2 = UnitQuaternion::from_euler_angles(-0.1, 0.0, 0.0); + /// let q3 = UnitQuaternion::from_euler_angles(0.1, 0.0, 0.0); + /// + /// let quat_vec = vec![q1, q2, q3]; + /// let q_mean = UnitQuaternion::mean_of(quat_vec); + /// + /// let euler_angles_mean = q_mean.euler_angles(); + /// assert_relative_eq!(euler_angles_mean.0, 0.0, epsilon = 1.0e-7) + /// ``` + #[inline] + pub fn mean_of(unit_quaternions: impl IntoIterator) -> Self + where + T: RealField, + { + let quaternions_matrix: Matrix4 = unit_quaternions + .into_iter() + .map(|q| q.as_vector() * q.as_vector().transpose()) + .sum(); + + assert!(!quaternions_matrix.is_zero()); + + let eigen_matrix = quaternions_matrix + .try_symmetric_eigen(T::RealField::default_epsilon(), 10) + .expect("Quaternions matrix could not be diagonalized. This behavior should not be possible."); + + let max_eigenvalue_index = eigen_matrix + .eigenvalues + .iter() + .position(|v| *v == eigen_matrix.eigenvalues.max()) + .unwrap(); + + let max_eigenvector = eigen_matrix.eigenvectors.column(max_eigenvalue_index); + UnitQuaternion::from_quaternion(Quaternion::new( + max_eigenvector[0].clone(), + max_eigenvector[1].clone(), + max_eigenvector[2].clone(), + max_eigenvector[3].clone(), + )) + } +} + +impl One for UnitQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + T::Element: SimdRealField, + OpenClosed01: Distribution, + T: SampleUniform, +{ + /// Generate a uniformly distributed random rotation quaternion. + #[inline] + fn sample(&self, rng: &mut R) -> UnitQuaternion { + // Ken Shoemake's Subgroup Algorithm + // Uniform random rotations. + // In D. Kirk, editor, Graphics Gems III, pages 124-132. Academic, New York, 1992. + let x0 = rng.sample(OpenClosed01); + let twopi = Uniform::new(T::zero(), T::simd_two_pi()); + let theta1 = rng.sample(&twopi); + let theta2 = rng.sample(&twopi); + let s1 = theta1.clone().simd_sin(); + let c1 = theta1.simd_cos(); + let s2 = theta2.clone().simd_sin(); + let c2 = theta2.simd_cos(); + let r1 = (T::one() - x0.clone()).simd_sqrt(); + let r2 = x0.simd_sqrt(); + Unit::new_unchecked(Quaternion::new( + s1 * r1.clone(), + c1 * r1, + s2 * r2.clone(), + c2 * r2, + )) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for UnitQuaternion +where + Owned: Send, + Owned: Send, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + let axisangle = Vector3::arbitrary(g); + Self::from_scaled_axis(axisangle) + } +} + +#[cfg(test)] +#[cfg(feature = "rand")] +mod tests { + use super::*; + use rand::SeedableRng; + use rand_xorshift; + + #[test] + fn random_unit_quats_are_unit() { + let mut rng = rand_xorshift::XorShiftRng::from_seed([0xAB; 16]); + for _ in 0..1000 { + let x = rng.gen::>(); + assert!(relative_eq!(x.into_inner().norm(), 1.0)) + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_conversion.rs new file mode 100644 index 000000000..6678371d4 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_conversion.rs @@ -0,0 +1,410 @@ +use num::Zero; + +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; + +use crate::base::{Matrix3, Matrix4, Scalar, Vector4}; +use crate::geometry::{ + AbstractRotation, Isometry, Quaternion, Rotation, Rotation3, Similarity, SuperTCategoryOf, + TAffine, Transform, Translation, UnitDualQuaternion, UnitQuaternion, +}; + +/* + * This file provides the following conversions: + * ============================================= + * + * Quaternion -> Quaternion + * UnitQuaternion -> UnitQuaternion + * UnitQuaternion -> Rotation<3> + * UnitQuaternion -> Isometry<3> + * UnitQuaternion -> UnitDualQuaternion + * UnitQuaternion -> Similarity<3> + * UnitQuaternion -> Transform<3> + * UnitQuaternion -> Matrix (homogeneous) + * + * NOTE: + * UnitQuaternion -> Quaternion is already provided by: Unit -> T + */ + +impl SubsetOf> for Quaternion +where + T1: Scalar, + T2: Scalar + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Quaternion { + Quaternion::from(self.coords.to_superset()) + } + + #[inline] + fn is_in_subset(q: &Quaternion) -> bool { + crate::is_convertible::<_, Vector4>(&q.coords) + } + + #[inline] + fn from_superset_unchecked(q: &Quaternion) -> Self { + Self { + coords: q.coords.to_subset_unchecked(), + } + } +} + +impl SubsetOf> for UnitQuaternion +where + T1: Scalar, + T2: Scalar + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitQuaternion { + UnitQuaternion::new_unchecked(self.as_ref().to_superset()) + } + + #[inline] + fn is_in_subset(uq: &UnitQuaternion) -> bool { + crate::is_convertible::<_, Quaternion>(uq.as_ref()) + } + + #[inline] + fn from_superset_unchecked(uq: &UnitQuaternion) -> Self { + Self::new_unchecked(crate::convert_ref_unchecked(uq.as_ref())) + } +} + +impl SubsetOf> for UnitQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Rotation3 { + let q: UnitQuaternion = self.to_superset(); + q.to_rotation_matrix() + } + + #[inline] + fn is_in_subset(rot: &Rotation3) -> bool { + crate::is_convertible::<_, Rotation3>(rot) + } + + #[inline] + fn from_superset_unchecked(rot: &Rotation3) -> Self { + let q = UnitQuaternion::::from_rotation_matrix(rot); + crate::convert_unchecked(q) + } +} + +impl SubsetOf> for UnitQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Isometry { + Isometry::from_parts(Translation::identity(), crate::convert_ref(self)) + } + + #[inline] + fn is_in_subset(iso: &Isometry) -> bool { + iso.translation.vector.is_zero() + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry) -> Self { + crate::convert_ref_unchecked(&iso.rotation) + } +} + +impl SubsetOf> for UnitQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitDualQuaternion { + let q: UnitQuaternion = crate::convert_ref(self); + UnitDualQuaternion::from_rotation(q) + } + + #[inline] + fn is_in_subset(dq: &UnitDualQuaternion) -> bool { + dq.translation().vector.is_zero() + } + + #[inline] + fn from_superset_unchecked(dq: &UnitDualQuaternion) -> Self { + crate::convert_unchecked(dq.rotation()) + } +} + +impl SubsetOf> for UnitQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_isometry(crate::convert_ref(self), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + sim.isometry.translation.vector.is_zero() && sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + crate::convert_ref_unchecked(&sim.isometry) + } +} + +impl SubsetOf> for UnitQuaternion +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.clone().to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl> SubsetOf> for UnitQuaternion { + #[inline] + fn to_superset(&self) -> Matrix4 { + self.clone().to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &Matrix4) -> bool { + crate::is_convertible::<_, Rotation3>(m) + } + + #[inline] + fn from_superset_unchecked(m: &Matrix4) -> Self { + let rot: Rotation3 = crate::convert_ref_unchecked(m); + Self::from_rotation_matrix(&rot) + } +} + +impl From> for Matrix4 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: UnitQuaternion) -> Self { + q.to_homogeneous() + } +} + +impl From> for Rotation3 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: UnitQuaternion) -> Self { + q.to_rotation_matrix() + } +} + +impl From> for UnitQuaternion +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: Rotation3) -> Self { + Self::from_rotation_matrix(&q) + } +} + +impl From> for Matrix3 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: UnitQuaternion) -> Self { + q.to_rotation_matrix().into_inner() + } +} + +impl From> for Quaternion { + #[inline] + fn from(coords: Vector4) -> Self { + Self { coords } + } +} + +impl From<[T; 4]> for Quaternion { + #[inline] + fn from(coords: [T; 4]) -> Self { + Self { + coords: coords.into(), + } + } +} + +impl From<[Quaternion; 2]> for Quaternion +where + T: From<[::Element; 2]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 2]) -> Self { + Self::from(Vector4::from([arr[0].coords, arr[1].coords])) + } +} + +impl From<[Quaternion; 4]> for Quaternion +where + T: From<[::Element; 4]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 4]) -> Self { + Self::from(Vector4::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + ])) + } +} + +impl From<[Quaternion; 8]> for Quaternion +where + T: From<[::Element; 8]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 8]) -> Self { + Self::from(Vector4::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + ])) + } +} + +impl From<[Quaternion; 16]> for Quaternion +where + T: From<[::Element; 16]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Quaternion; 16]) -> Self { + Self::from(Vector4::from([ + arr[0].coords, + arr[1].coords, + arr[2].coords, + arr[3].coords, + arr[4].coords, + arr[5].coords, + arr[6].coords, + arr[7].coords, + arr[8].coords, + arr[9].coords, + arr[10].coords, + arr[11].coords, + arr[12].coords, + arr[13].coords, + arr[14].coords, + arr[15].coords, + ])) + } +} + +impl From<[UnitQuaternion; 2]> + for UnitQuaternion +where + T: From<[::Element; 2]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 2]) -> Self { + Self::new_unchecked(Quaternion::from([arr[0].into_inner(), arr[1].into_inner()])) + } +} + +impl From<[UnitQuaternion; 4]> + for UnitQuaternion +where + T: From<[::Element; 4]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 4]) -> Self { + Self::new_unchecked(Quaternion::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + ])) + } +} + +impl From<[UnitQuaternion; 8]> + for UnitQuaternion +where + T: From<[::Element; 8]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 8]) -> Self { + Self::new_unchecked(Quaternion::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + arr[4].into_inner(), + arr[5].into_inner(), + arr[6].into_inner(), + arr[7].into_inner(), + ])) + } +} + +impl From<[UnitQuaternion; 16]> + for UnitQuaternion +where + T: From<[::Element; 16]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitQuaternion; 16]) -> Self { + Self::new_unchecked(Quaternion::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + arr[4].into_inner(), + arr[5].into_inner(), + arr[6].into_inner(), + arr[7].into_inner(), + arr[8].into_inner(), + arr[9].into_inner(), + arr[10].into_inner(), + arr[11].into_inner(), + arr[12].into_inner(), + arr[13].into_inner(), + arr[14].into_inner(), + arr[15].into_inner(), + ])) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_coordinates.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_coordinates.rs new file mode 100644 index 000000000..81f91ed62 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_coordinates.rs @@ -0,0 +1,24 @@ +use std::ops::{Deref, DerefMut}; + +use simba::simd::SimdValue; + +use crate::base::coordinates::IJKW; +use crate::Scalar; + +use crate::geometry::Quaternion; + +impl Deref for Quaternion { + type Target = IJKW; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +impl DerefMut for Quaternion { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut Self::Target) } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_ops.rs new file mode 100644 index 000000000..25fe9f960 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_ops.rs @@ -0,0 +1,677 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +/* + * This file provides: + * =================== + * + * + * (Quaternion) + * + * Index + * IndexMut + * Quaternion × Quaternion + * Quaternion + Quaternion + * Quaternion - Quaternion + * -Quaternion + * Quaternion × Scalar + * Quaternion ÷ Scalar + * Scalar × Quaternion + * + * (Unit Quaternion) + * UnitQuaternion × UnitQuaternion + * UnitQuaternion × Rotation -> UnitQuaternion + * Rotation × UnitQuaternion -> UnitQuaternion + * + * UnitQuaternion ÷ UnitQuaternion + * UnitQuaternion ÷ Rotation -> UnitQuaternion + * Rotation ÷ UnitQuaternion -> UnitQuaternion + * + * + * UnitQuaternion × Point + * UnitQuaternion × Vector + * UnitQuaternion × Unit + * + * NOTE: -UnitQuaternion is already provided by `Unit`. + * + * + * (Assignment Operators) + * + * Quaternion ×= Scalar + * Quaternion ×= Quaternion + * Quaternion += Quaternion + * Quaternion -= Quaternion + * + * UnitQuaternion ×= UnitQuaternion + * UnitQuaternion ×= Rotation + * + * UnitQuaternion ÷= UnitQuaternion + * UnitQuaternion ÷= Rotation + * + * TODO: Rotation ×= UnitQuaternion + * TODO: Rotation ÷= UnitQuaternion + * + */ + +use std::ops::{ + Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, +}; + +use crate::base::dimension::U3; +use crate::base::storage::Storage; +use crate::base::{Const, Scalar, Unit, Vector, Vector3}; +use crate::SimdRealField; + +use crate::geometry::{Point3, Quaternion, Rotation, UnitQuaternion}; + +impl Index for Quaternion { + type Output = T; + + #[inline] + fn index(&self, i: usize) -> &Self::Output { + &self.coords[i] + } +} + +impl IndexMut for Quaternion { + #[inline] + fn index_mut(&mut self, i: usize) -> &mut T { + &mut self.coords[i] + } +} + +macro_rules! quaternion_op_impl( + ($Op: ident, $op: ident; + $($Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField { + type Output = $Result; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +// Quaternion + Quaternion +quaternion_op_impl!( + Add, add; + ; + self: &'a Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from(&self.coords + &rhs.coords); + 'a, 'b); + +quaternion_op_impl!( + Add, add; + ; + self: &'a Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from(&self.coords + rhs.coords); + 'a); + +quaternion_op_impl!( + Add, add; + ; + self: Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from(self.coords + &rhs.coords); + 'b); + +quaternion_op_impl!( + Add, add; + ; + self: Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from(self.coords + rhs.coords); ); + +// Quaternion - Quaternion +quaternion_op_impl!( + Sub, sub; + ; + self: &'a Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from(&self.coords - &rhs.coords); + 'a, 'b); + +quaternion_op_impl!( + Sub, sub; + ; + self: &'a Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from(&self.coords - rhs.coords); + 'a); + +quaternion_op_impl!( + Sub, sub; + ; + self: Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::from(self.coords - &rhs.coords); + 'b); + +quaternion_op_impl!( + Sub, sub; + ; + self: Quaternion, rhs: Quaternion, Output = Quaternion; + Quaternion::from(self.coords - rhs.coords); ); + +// Quaternion × Quaternion +quaternion_op_impl!( + Mul, mul; + ; + self: &'a Quaternion, rhs: &'b Quaternion, Output = Quaternion; + Quaternion::new( + self[3].clone() * rhs[3].clone() - self[0].clone() * rhs[0].clone() - self[1].clone() * rhs[1].clone() - self[2].clone() * rhs[2].clone(), + self[3].clone() * rhs[0].clone() + self[0].clone() * rhs[3].clone() + self[1].clone() * rhs[2].clone() - self[2].clone() * rhs[1].clone(), + self[3].clone() * rhs[1].clone() - self[0].clone() * rhs[2].clone() + self[1].clone() * rhs[3].clone() + self[2].clone() * rhs[0].clone(), + self[3].clone() * rhs[2].clone() + self[0].clone() * rhs[1].clone() - self[1].clone() * rhs[0].clone() + self[2].clone() * rhs[3].clone()); + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: &'a Quaternion, rhs: Quaternion, Output = Quaternion; + self * &rhs; + 'a); + +quaternion_op_impl!( + Mul, mul; + ; + self: Quaternion, rhs: &'b Quaternion, Output = Quaternion; + &self * rhs; + 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: Quaternion, rhs: Quaternion, Output = Quaternion; + &self * &rhs; ); + +// UnitQuaternion × UnitQuaternion +quaternion_op_impl!( + Mul, mul; + ; + self: &'a UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; + UnitQuaternion::new_unchecked(self.quaternion() * rhs.quaternion()); + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: &'a UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; + self * &rhs; + 'a); + +quaternion_op_impl!( + Mul, mul; + ; + self: UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; + &self * rhs; + 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; + &self * &rhs; ); + +// UnitQuaternion ÷ UnitQuaternion +quaternion_op_impl!( + Div, div; + ; + self: &'a UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; + #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + 'a, 'b); + +quaternion_op_impl!( + Div, div; + ; + self: &'a UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; + self / &rhs; + 'a); + +quaternion_op_impl!( + Div, div; + ; + self: UnitQuaternion, rhs: &'b UnitQuaternion, Output = UnitQuaternion; + &self / rhs; + 'b); + +quaternion_op_impl!( + Div, div; + ; + self: UnitQuaternion, rhs: UnitQuaternion, Output = UnitQuaternion; + &self / &rhs; ); + +// UnitQuaternion × Rotation +quaternion_op_impl!( + Mul, mul; + ; + self: &'a UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion; + // TODO: can we avoid the conversion from a rotation matrix? + self * UnitQuaternion::::from_rotation_matrix(rhs); + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: &'a UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion; + self * UnitQuaternion::::from_rotation_matrix(&rhs); + 'a); + +quaternion_op_impl!( + Mul, mul; + ; + self: UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion; + self * UnitQuaternion::::from_rotation_matrix(rhs); + 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion; + self * UnitQuaternion::::from_rotation_matrix(&rhs); ); + +// UnitQuaternion ÷ Rotation +quaternion_op_impl!( + Div, div; + ; + self: &'a UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion; + // TODO: can we avoid the conversion to a rotation matrix? + self / UnitQuaternion::::from_rotation_matrix(rhs); + 'a, 'b); + +quaternion_op_impl!( + Div, div; + ; + self: &'a UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion; + self / UnitQuaternion::::from_rotation_matrix(&rhs); + 'a); + +quaternion_op_impl!( + Div, div; + ; + self: UnitQuaternion, rhs: &'b Rotation, + Output = UnitQuaternion; + self / UnitQuaternion::::from_rotation_matrix(rhs); + 'b); + +quaternion_op_impl!( + Div, div; + ; + self: UnitQuaternion, rhs: Rotation, + Output = UnitQuaternion; + self / UnitQuaternion::::from_rotation_matrix(&rhs); ); + +// Rotation × UnitQuaternion +quaternion_op_impl!( + Mul, mul; + ; + self: &'a Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion; + // TODO: can we avoid the conversion from a rotation matrix? + UnitQuaternion::::from_rotation_matrix(self) * rhs; + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: &'a Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion; + UnitQuaternion::::from_rotation_matrix(self) * rhs; + 'a); + +quaternion_op_impl!( + Mul, mul; + ; + self: Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion; + UnitQuaternion::::from_rotation_matrix(&self) * rhs; + 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion; + UnitQuaternion::::from_rotation_matrix(&self) * rhs; ); + +// Rotation ÷ UnitQuaternion +quaternion_op_impl!( + Div, div; + ; + self: &'a Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion; + // TODO: can we avoid the conversion from a rotation matrix? + UnitQuaternion::::from_rotation_matrix(self) / rhs; + 'a, 'b); + +quaternion_op_impl!( + Div, div; + ; + self: &'a Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion; + UnitQuaternion::::from_rotation_matrix(self) / rhs; + 'a); + +quaternion_op_impl!( + Div, div; + ; + self: Rotation, rhs: &'b UnitQuaternion, + Output = UnitQuaternion; + UnitQuaternion::::from_rotation_matrix(&self) / rhs; + 'b); + +quaternion_op_impl!( + Div, div; + ; + self: Rotation, rhs: UnitQuaternion, + Output = UnitQuaternion; + UnitQuaternion::::from_rotation_matrix(&self) / rhs; ); + +// UnitQuaternion × Vector +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: &'a UnitQuaternion, rhs: &'b Vector, SB>, + Output = Vector3; + { + let two: T = crate::convert(2.0f64); + let t = self.as_ref().vector().cross(rhs) * two; + let cross = self.as_ref().vector().cross(&t); + + t * self.as_ref().scalar() + cross + rhs + }; + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: &'a UnitQuaternion, rhs: Vector, + Output = Vector3; + self * &rhs; + 'a); + +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: UnitQuaternion, rhs: &'b Vector, + Output = Vector3; + &self * rhs; + 'b); + +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: UnitQuaternion, rhs: Vector, + Output = Vector3; + &self * &rhs; ); + +// UnitQuaternion × Point +quaternion_op_impl!( + Mul, mul; + ; + self: &'a UnitQuaternion, rhs: &'b Point3, + Output = Point3; + Point3::from(self * &rhs.coords); + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: &'a UnitQuaternion, rhs: Point3, + Output = Point3; + Point3::from(self * rhs.coords); + 'a); + +quaternion_op_impl!( + Mul, mul; + ; + self: UnitQuaternion, rhs: &'b Point3, + Output = Point3; + Point3::from(self * &rhs.coords); + 'b); + +quaternion_op_impl!( + Mul, mul; + ; + self: UnitQuaternion, rhs: Point3, + Output = Point3; + Point3::from(self * rhs.coords); ); + +// UnitQuaternion × Unit +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: &'a UnitQuaternion, rhs: &'b Unit>, + Output = Unit>; + Unit::new_unchecked(self * rhs.as_ref()); + 'a, 'b); + +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: &'a UnitQuaternion, rhs: Unit>, + Output = Unit>; + Unit::new_unchecked(self * rhs.into_inner()); + 'a); + +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: UnitQuaternion, rhs: &'b Unit>, + Output = Unit>; + Unit::new_unchecked(self * rhs.as_ref()); + 'b); + +quaternion_op_impl!( + Mul, mul; + SB: Storage> ; + self: UnitQuaternion, rhs: Unit>, + Output = Unit>; + Unit::new_unchecked(self * rhs.into_inner()); ); + +macro_rules! scalar_op_impl( + ($($Op: ident, $op: ident, $OpAssign: ident, $op_assign: ident);* $(;)*) => {$( + impl $Op for Quaternion + where T::Element: SimdRealField { + type Output = Quaternion; + + #[inline] + fn $op(self, n: T) -> Self::Output { + Quaternion::from(self.coords.$op(n)) + } + } + + impl<'a, T: SimdRealField> $Op for &'a Quaternion + where T::Element: SimdRealField { + type Output = Quaternion; + + #[inline] + fn $op(self, n: T) -> Self::Output { + Quaternion::from((&self.coords).$op(n)) + } + } + + impl $OpAssign for Quaternion + where T::Element: SimdRealField { + + #[inline] + fn $op_assign(&mut self, n: T) { + self.coords.$op_assign(n) + } + } + )*} +); + +scalar_op_impl!( + Mul, mul, MulAssign, mul_assign; + Div, div, DivAssign, div_assign; +); + +macro_rules! left_scalar_mul_impl( + ($($T: ty),* $(,)*) => {$( + impl Mul> for $T { + type Output = Quaternion<$T>; + + #[inline] + fn mul(self, right: Quaternion<$T>) -> Self::Output { + Quaternion::from(self * right.coords) + } + } + + impl<'b> Mul<&'b Quaternion<$T>> for $T { + type Output = Quaternion<$T>; + + #[inline] + fn mul(self, right: &'b Quaternion<$T>) -> Self::Output { + Quaternion::from(self * &right.coords) + } + } + )*} +); + +left_scalar_mul_impl!(f32, f64); + +impl Neg for Quaternion +where + T::Element: SimdRealField, +{ + type Output = Quaternion; + + #[inline] + fn neg(self) -> Self::Output { + Self::Output::from(-self.coords) + } +} + +impl<'a, T: SimdRealField> Neg for &'a Quaternion +where + T::Element: SimdRealField, +{ + type Output = Quaternion; + + #[inline] + fn neg(self) -> Self::Output { + Self::Output::from(-&self.coords) + } +} + +macro_rules! quaternion_op_impl( + ($OpAssign: ident, $op_assign: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty $(=> $VDimA: ty, $VDimB: ty)*; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField> $OpAssign<$Rhs> for $Lhs + where T::Element: SimdRealField { + + #[inline] + fn $op_assign(&mut $lhs, $rhs: $Rhs) { + $action + } + } + } +); + +// Quaternion += Quaternion +quaternion_op_impl!( + AddAssign, add_assign; + self: Quaternion, rhs: &'b Quaternion; + self.coords += &rhs.coords; + 'b); + +quaternion_op_impl!( + AddAssign, add_assign; + self: Quaternion, rhs: Quaternion; + self.coords += rhs.coords; ); + +// Quaternion -= Quaternion +quaternion_op_impl!( + SubAssign, sub_assign; + self: Quaternion, rhs: &'b Quaternion; + self.coords -= &rhs.coords; + 'b); + +quaternion_op_impl!( + SubAssign, sub_assign; + self: Quaternion, rhs: Quaternion; + self.coords -= rhs.coords; ); + +// Quaternion ×= Quaternion +quaternion_op_impl!( + MulAssign, mul_assign; + self: Quaternion, rhs: &'b Quaternion; + { + let res = &*self * rhs; + // TODO: will this be optimized away? + self.coords.copy_from(&res.coords); + }; + 'b); + +quaternion_op_impl!( + MulAssign, mul_assign; + self: Quaternion, rhs: Quaternion; + *self *= &rhs; ); + +// UnitQuaternion ×= UnitQuaternion +quaternion_op_impl!( + MulAssign, mul_assign; + self: UnitQuaternion, rhs: &'b UnitQuaternion; + { + let res = &*self * rhs; + self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); + }; + 'b); + +quaternion_op_impl!( + MulAssign, mul_assign; + self: UnitQuaternion, rhs: UnitQuaternion; + *self *= &rhs; ); + +// UnitQuaternion ÷= UnitQuaternion +quaternion_op_impl!( + DivAssign, div_assign; + self: UnitQuaternion, rhs: &'b UnitQuaternion; + { + let res = &*self / rhs; + self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); + }; + 'b); + +quaternion_op_impl!( + DivAssign, div_assign; + self: UnitQuaternion, rhs: UnitQuaternion; + *self /= &rhs; ); + +// UnitQuaternion ×= Rotation +quaternion_op_impl!( + MulAssign, mul_assign; + self: UnitQuaternion, rhs: &'b Rotation; + { + let res = &*self * rhs; + self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); + }; + 'b); + +quaternion_op_impl!( + MulAssign, mul_assign; + self: UnitQuaternion, rhs: Rotation; + *self *= &rhs; ); + +// UnitQuaternion ÷= Rotation +quaternion_op_impl!( + DivAssign, div_assign; + self: UnitQuaternion, rhs: &'b Rotation; + { + let res = &*self / rhs; + self.as_mut_unchecked().coords.copy_from(&res.as_ref().coords); + }; + 'b); + +quaternion_op_impl!( + DivAssign, div_assign; + self: UnitQuaternion, rhs: Rotation; + *self /= &rhs; ); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_simba.rs new file mode 100644 index 000000000..733bbf8a2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/quaternion_simba.rs @@ -0,0 +1,84 @@ +use simba::simd::SimdValue; + +use crate::base::Vector4; +use crate::geometry::{Quaternion, UnitQuaternion}; +use crate::Scalar; + +impl SimdValue for Quaternion +where + T::Element: Scalar, +{ + const LANES: usize = T::LANES; + type Element = Quaternion; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + Vector4::splat(val.coords).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.coords.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.coords.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.coords.replace(i, val.coords) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.coords.replace_unchecked(i, val.coords) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.coords.select(cond, other.coords).into() + } +} + +impl SimdValue for UnitQuaternion +where + T::Element: Scalar, +{ + const LANES: usize = T::LANES; + type Element = UnitQuaternion; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + UnitQuaternion::new_unchecked(Quaternion::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + UnitQuaternion::new_unchecked(self.as_ref().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + UnitQuaternion::new_unchecked(self.as_ref().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + UnitQuaternion::new_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection.rs new file mode 100644 index 000000000..03b7ad2b9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection.rs @@ -0,0 +1,125 @@ +use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint}; +use crate::base::{Const, Matrix, Unit, Vector}; +use crate::dimension::{Dim, U1}; +use crate::storage::{Storage, StorageMut}; +use simba::scalar::ComplexField; + +use crate::geometry::Point; + +/// A reflection wrt. a plane. +pub struct Reflection { + axis: Vector, + bias: T, +} + +impl>, const D: usize> Reflection, S> { + /// Creates a new reflection wrt. the plane orthogonal to the given axis and that contains the + /// point `pt`. + pub fn new_containing_point(axis: Unit, S>>, pt: &Point) -> Self { + let bias = axis.dotc(&pt.coords); + Self::new(axis, bias) + } +} + +impl> Reflection { + /// Creates a new reflection wrt. the plane orthogonal to the given axis and bias. + /// + /// The bias is the position of the plane on the axis. In particular, a bias equal to zero + /// represents a plane that passes through the origin. + pub fn new(axis: Unit>, bias: T) -> Self { + Self { + axis: axis.into_inner(), + bias, + } + } + + /// The reflection axis. + #[must_use] + pub fn axis(&self) -> &Vector { + &self.axis + } + + /// The reflection bias. + /// + /// The bias is the position of the plane on the axis. In particular, a bias equal to zero + /// represents a plane that passes through the origin. + #[must_use] + pub fn bias(&self) -> T { + self.bias.clone() + } + + // TODO: naming convention: reflect_to, reflect_assign ? + /// Applies the reflection to the columns of `rhs`. + pub fn reflect(&self, rhs: &mut Matrix) + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..rhs.ncols() { + // NOTE: we borrow the column twice here. First it is borrowed immutably for the + // dot product, and then mutably. Somehow, this allows significantly + // better optimizations of the dot product from the compiler. + let m_two: T = crate::convert(-2.0f64); + let factor = (self.axis.dotc(&rhs.column(i)) - self.bias.clone()) * m_two; + rhs.column_mut(i).axpy(factor, &self.axis, T::one()); + } + } + + // TODO: naming convention: reflect_to, reflect_assign ? + /// Applies the reflection to the columns of `rhs`. + pub fn reflect_with_sign(&self, rhs: &mut Matrix, sign: T) + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..rhs.ncols() { + // NOTE: we borrow the column twice here. First it is borrowed immutably for the + // dot product, and then mutably. Somehow, this allows significantly + // better optimizations of the dot product from the compiler. + let m_two = sign.clone().scale(crate::convert(-2.0f64)); + let factor = (self.axis.dotc(&rhs.column(i)) - self.bias.clone()) * m_two; + rhs.column_mut(i).axpy(factor, &self.axis, sign.clone()); + } + } + + /// Applies the reflection to the rows of `lhs`. + pub fn reflect_rows( + &self, + lhs: &mut Matrix, + work: &mut Vector, + ) where + S2: StorageMut, + S3: StorageMut, + ShapeConstraint: DimEq + AreMultipliable, + { + lhs.mul_to(&self.axis, work); + + if !self.bias.is_zero() { + work.add_scalar_mut(-self.bias.clone()); + } + + let m_two: T = crate::convert(-2.0f64); + lhs.gerc(m_two, work, &self.axis, T::one()); + } + + /// Applies the reflection to the rows of `lhs`. + pub fn reflect_rows_with_sign( + &self, + lhs: &mut Matrix, + work: &mut Vector, + sign: T, + ) where + S2: StorageMut, + S3: StorageMut, + ShapeConstraint: DimEq + AreMultipliable, + { + lhs.mul_to(&self.axis, work); + + if !self.bias.is_zero() { + work.add_scalar_mut(-self.bias.clone()); + } + + let m_two = sign.clone().scale(crate::convert(-2.0f64)); + lhs.gerc(m_two, work, &self.axis, sign); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection_alias.rs new file mode 100644 index 000000000..8e9d86d41 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/reflection_alias.rs @@ -0,0 +1,21 @@ +use crate::base::ArrayStorage; +use crate::geometry::Reflection; +use crate::Const; + +/// A 1-dimensional reflection. +pub type Reflection1 = Reflection, ArrayStorage>; + +/// A 2-dimensional reflection. +pub type Reflection2 = Reflection, ArrayStorage>; + +/// A 3-dimensional reflection. +pub type Reflection3 = Reflection, ArrayStorage>; + +/// A 4-dimensional reflection. +pub type Reflection4 = Reflection, ArrayStorage>; + +/// A 5-dimensional reflection. +pub type Reflection5 = Reflection, ArrayStorage>; + +/// A 6-dimensional reflection. +pub type Reflection6 = Reflection, ArrayStorage>; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation.rs new file mode 100644 index 000000000..fd5dc47cc --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation.rs @@ -0,0 +1,586 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::{One, Zero}; +use std::fmt; +use std::hash; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "serde-serialize-no-std")] +use crate::base::storage::Owned; + +use simba::scalar::RealField; +use simba::simd::SimdRealField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix, SMatrix, SVector, Scalar, Unit}; +use crate::geometry::Point; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A rotation matrix. +/// +/// This is also known as an element of a Special Orthogonal (SO) group. +/// The `Rotation` type can either represent a 2D or 3D rotation, represented as a matrix. +/// For a rotation based on quaternions, see [`UnitQuaternion`](crate::UnitQuaternion) instead. +/// +/// Note that instead of using the [`Rotation`](crate::Rotation) type in your code directly, you should use one +/// of its aliases: [`Rotation2`](crate::Rotation2), or [`Rotation3`](crate::Rotation3). Though +/// keep in mind that all the documentation of all the methods of these aliases will also appears on +/// this page. +/// +/// # Construction +/// * [Identity `identity`](#identity) +/// * [From a 2D rotation angle `new`…](#construction-from-a-2d-rotation-angle) +/// * [From an existing 2D matrix or rotations `from_matrix`, `rotation_between`, `powf`…](#construction-from-an-existing-2d-matrix-or-rotations) +/// * [From a 3D axis and/or angles `new`, `from_euler_angles`, `from_axis_angle`…](#construction-from-a-3d-axis-andor-angles) +/// * [From a 3D eye position and target point `look_at`, `look_at_lh`, `rotation_between`…](#construction-from-a-3d-eye-position-and-target-point) +/// * [From an existing 3D matrix or rotations `from_matrix`, `rotation_between`, `powf`…](#construction-from-an-existing-3d-matrix-or-rotations) +/// +/// # Transformation and composition +/// Note that transforming vectors and points can be done by multiplication, e.g., `rotation * point`. +/// Composing an rotation with another transformation can also be done by multiplication or division. +/// * [3D axis and angle extraction `angle`, `euler_angles`, `scaled_axis`, `angle_to`…](#3d-axis-and-angle-extraction) +/// * [2D angle extraction `angle`, `angle_to`…](#2d-angle-extraction) +/// * [Transformation of a vector or a point `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) +/// * [Transposition and inversion `transpose`, `inverse`…](#transposition-and-inversion) +/// * [Interpolation `slerp`…](#interpolation) +/// +/// # Conversion +/// * [Conversion to a matrix `matrix`, `to_homogeneous`…](#conversion-to-a-matrix) +/// +#[repr(C)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Rotation", + bound(archive = " + T: rkyv::Archive, + SMatrix: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[derive(Copy, Clone)] +pub struct Rotation { + matrix: SMatrix, +} + +impl fmt::Debug for Rotation { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.matrix.fmt(formatter) + } +} + +impl hash::Hash for Rotation +where + , Const>>::Buffer: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.matrix.hash(state) + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Rotation +where + T: Scalar + bytemuck::Zeroable, + SMatrix: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Rotation +where + T: Scalar + bytemuck::Pod, + SMatrix: bytemuck::Pod, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Rotation +where + Owned, Const>: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.matrix.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Rotation +where + Owned, Const>: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = SMatrix::::deserialize(deserializer)?; + + Ok(Self::from_matrix_unchecked(matrix)) + } +} + +impl Rotation { + /// Creates a new rotation from the given square matrix. + /// + /// The matrix orthonormality is not checked. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, Rotation3, Matrix2, Matrix3}; + /// # use std::f32; + /// let mat = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// let rot = Rotation3::from_matrix_unchecked(mat); + /// + /// assert_eq!(*rot.matrix(), mat); + /// + /// + /// let mat = Matrix2::new(0.8660254, -0.5, + /// 0.5, 0.8660254); + /// let rot = Rotation2::from_matrix_unchecked(mat); + /// + /// assert_eq!(*rot.matrix(), mat); + /// ``` + #[inline] + pub const fn from_matrix_unchecked(matrix: SMatrix) -> Self { + Self { matrix } + } +} + +/// # Conversion to a matrix +impl Rotation { + /// A reference to the underlying matrix representation of this rotation. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3}; + /// # use std::f32; + /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); + /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(*rot.matrix(), expected); + /// + /// + /// let rot = Rotation2::new(f32::consts::FRAC_PI_6); + /// let expected = Matrix2::new(0.8660254, -0.5, + /// 0.5, 0.8660254); + /// assert_eq!(*rot.matrix(), expected); + /// ``` + #[inline] + #[must_use] + pub fn matrix(&self) -> &SMatrix { + &self.matrix + } + + /// A mutable reference to the underlying matrix representation of this rotation. + /// + /// # Safety + /// + /// Invariants of the rotation matrix should not be violated. + #[inline] + #[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")] + pub unsafe fn matrix_mut(&mut self) -> &mut SMatrix { + &mut self.matrix + } + + /// A mutable reference to the underlying matrix representation of this rotation. + /// + /// This is suffixed by "_unchecked" because this allows the user to replace the + /// matrix by another one that is non-inversible or non-orthonormal. If one of + /// those properties is broken, subsequent method calls may return bogus results. + #[inline] + pub fn matrix_mut_unchecked(&mut self) -> &mut SMatrix { + &mut self.matrix + } + + /// Unwraps the underlying matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3}; + /// # use std::f32; + /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); + /// let mat = rot.into_inner(); + /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(mat, expected); + /// + /// + /// let rot = Rotation2::new(f32::consts::FRAC_PI_6); + /// let mat = rot.into_inner(); + /// let expected = Matrix2::new(0.8660254, -0.5, + /// 0.5, 0.8660254); + /// assert_eq!(mat, expected); + /// ``` + #[inline] + pub fn into_inner(self) -> SMatrix { + self.matrix + } + + /// Unwraps the underlying matrix. + /// Deprecated: Use [`Rotation::into_inner`] instead. + #[deprecated(note = "use `.into_inner()` instead")] + #[inline] + pub fn unwrap(self) -> SMatrix { + self.matrix + } + + /// Converts this rotation into its equivalent homogeneous transformation matrix. + /// + /// This is the same as `self.into()`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix3, Matrix4}; + /// # use std::f32; + /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); + /// let expected = Matrix4::new(0.8660254, -0.5, 0.0, 0.0, + /// 0.5, 0.8660254, 0.0, 0.0, + /// 0.0, 0.0, 1.0, 0.0, + /// 0.0, 0.0, 0.0, 1.0); + /// assert_eq!(rot.to_homogeneous(), expected); + /// + /// + /// let rot = Rotation2::new(f32::consts::FRAC_PI_6); + /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(rot.to_homogeneous(), expected); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> + where + T: Zero + One, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + { + // We could use `SMatrix::to_homogeneous()` here, but that would imply + // adding the additional traits `DimAdd` and `IsNotStaticOne`. Maybe + // these things will get nicer once specialization lands in Rust. + let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); + res.fixed_view_mut::(0, 0).copy_from(&self.matrix); + + res + } +} + +/// # Transposition and inversion +impl Rotation { + /// Transposes `self`. + /// + /// Same as `.inverse()` because the inverse of a rotation matrix is its transpose. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation2, Rotation3, Vector3}; + /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); + /// let tr_rot = rot.transpose(); + /// assert_relative_eq!(rot * tr_rot, Rotation3::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(tr_rot * rot, Rotation3::identity(), epsilon = 1.0e-6); + /// + /// let rot = Rotation2::new(1.2); + /// let tr_rot = rot.transpose(); + /// assert_relative_eq!(rot * tr_rot, Rotation2::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use = "Did you mean to use transpose_mut()?"] + pub fn transpose(&self) -> Self { + Self::from_matrix_unchecked(self.matrix.transpose()) + } + + /// Inverts `self`. + /// + /// Same as `.transpose()` because the inverse of a rotation matrix is its transpose. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation2, Rotation3, Vector3}; + /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); + /// let inv = rot.inverse(); + /// assert_relative_eq!(rot * inv, Rotation3::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * rot, Rotation3::identity(), epsilon = 1.0e-6); + /// + /// let rot = Rotation2::new(1.2); + /// let inv = rot.inverse(); + /// assert_relative_eq!(rot * inv, Rotation2::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Self { + self.transpose() + } + + /// Transposes `self` in-place. + /// + /// Same as `.inverse_mut()` because the inverse of a rotation matrix is its transpose. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation2, Rotation3, Vector3}; + /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); + /// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); + /// tr_rot.transpose_mut(); + /// + /// assert_relative_eq!(rot * tr_rot, Rotation3::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(tr_rot * rot, Rotation3::identity(), epsilon = 1.0e-6); + /// + /// let rot = Rotation2::new(1.2); + /// let mut tr_rot = Rotation2::new(1.2); + /// tr_rot.transpose_mut(); + /// + /// assert_relative_eq!(rot * tr_rot, Rotation2::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transpose_mut(&mut self) { + self.matrix.transpose_mut() + } + + /// Inverts `self` in-place. + /// + /// Same as `.transpose_mut()` because the inverse of a rotation matrix is its transpose. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation2, Rotation3, Vector3}; + /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); + /// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); + /// inv.inverse_mut(); + /// + /// assert_relative_eq!(rot * inv, Rotation3::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * rot, Rotation3::identity(), epsilon = 1.0e-6); + /// + /// let rot = Rotation2::new(1.2); + /// let mut inv = Rotation2::new(1.2); + /// inv.inverse_mut(); + /// + /// assert_relative_eq!(rot * inv, Rotation2::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) { + self.transpose_mut() + } +} + +/// # Transformation of a vector or a point +impl Rotation +where + T::Element: SimdRealField, +{ + /// Rotate the given point. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_point = rot.transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Rotate the given vector. + /// + /// This is the same as the multiplication `self * v`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } + + /// Rotate the given point by the inverse of this rotation. This may be + /// cheaper than inverting the rotation and then transforming the given + /// point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_point = rot.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + Point::from(self.inverse_transform_vector(&pt.coords)) + } + + /// Rotate the given vector by the inverse of this rotation. This may be + /// cheaper than inverting the rotation and then transforming the given + /// vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.matrix().tr_mul(v) + } + + /// Rotate the given vector by the inverse of this rotation. This may be + /// cheaper than inverting the rotation and then transforming the given + /// vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::z() * f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_unit_vector(&Vector3::x_axis()); + /// + /// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + Unit::new_unchecked(self.inverse_transform_vector(&**v)) + } +} + +impl Eq for Rotation {} + +impl PartialEq for Rotation { + #[inline] + fn eq(&self, right: &Self) -> bool { + self.matrix == right.matrix + } +} + +impl AbsDiffEq for Rotation +where + T: Scalar + AbsDiffEq, + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.matrix.abs_diff_eq(&other.matrix, epsilon) + } +} + +impl RelativeEq for Rotation +where + T: Scalar + RelativeEq, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.matrix + .relative_eq(&other.matrix, epsilon, max_relative) + } +} + +impl UlpsEq for Rotation +where + T: Scalar + UlpsEq, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.matrix.ulps_eq(&other.matrix, epsilon, max_ulps) + } +} + +/* + * + * Display + * + */ +impl fmt::Display for Rotation +where + T: RealField + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let precision = f.precision().unwrap_or(3); + + writeln!(f, "Rotation matrix {{")?; + write!(f, "{:.*}", precision, self.matrix)?; + writeln!(f, "}}") + } +} + +// // /* +// // * +// // * Absolute +// // * +// // */ +// // impl Absolute for $t { +// // type AbsoluteValue = $submatrix; +// // +// // #[inline] +// // fn abs(m: &$t) -> $submatrix { +// // Absolute::abs(&m.submatrix) +// // } +// // } diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_alias.rs new file mode 100644 index 000000000..5c06cd032 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_alias.rs @@ -0,0 +1,11 @@ +use crate::geometry::Rotation; + +/// A 2-dimensional rotation matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Rotation`](crate::Rotation) type too.** +pub type Rotation2 = Rotation; + +/// A 3-dimensional rotation matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Rotation`](crate::Rotation) type too.** +pub type Rotation3 = Rotation; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_construction.rs new file mode 100644 index 000000000..3b488db85 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_construction.rs @@ -0,0 +1,73 @@ +use num::{One, Zero}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, SupersetOf}; + +use crate::base::{SMatrix, Scalar}; + +use crate::geometry::Rotation; + +impl Default for Rotation +where + T: Scalar + Zero + One, +{ + fn default() -> Self { + Self::identity() + } +} + +/// # Identity +impl Rotation +where + T: Scalar + Zero + One, +{ + /// Creates a new square identity rotation of the given `dimension`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, Rotation3}; + /// # use nalgebra::Vector3; + /// let rot1 = Rotation2::identity(); + /// let rot2 = Rotation2::new(std::f32::consts::FRAC_PI_2); + /// + /// assert_eq!(rot1 * rot2, rot2); + /// assert_eq!(rot2 * rot1, rot2); + /// + /// let rot1 = Rotation3::identity(); + /// let rot2 = Rotation3::from_axis_angle(&Vector3::z_axis(), std::f32::consts::FRAC_PI_2); + /// + /// assert_eq!(rot1 * rot2, rot2); + /// assert_eq!(rot2 * rot1, rot2); + /// ``` + #[inline] + pub fn identity() -> Rotation { + Self::from_matrix_unchecked(SMatrix::::identity()) + } +} + +impl Rotation { + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Rotation2; + /// let rot = Rotation2::::identity(); + /// let rot2 = rot.cast::(); + /// assert_eq!(rot2, Rotation2::::identity()); + /// ``` + pub fn cast(self) -> Rotation + where + Rotation: SupersetOf, + { + crate::convert(self) + } +} + +impl One for Rotation +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_conversion.rs new file mode 100644 index 000000000..8c390556f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_conversion.rs @@ -0,0 +1,337 @@ +use num::Zero; + +use crate::ArrayStorage; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdValue}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimMin, DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, Matrix2, Matrix3, Matrix4, OMatrix, SMatrix, Scalar}; + +use crate::geometry::{ + AbstractRotation, Isometry, Rotation, Rotation2, Rotation3, Similarity, SuperTCategoryOf, + TAffine, Transform, Translation, UnitComplex, UnitDualQuaternion, UnitQuaternion, +}; + +/* + * This file provides the following conversions: + * ============================================= + * + * Rotation -> Rotation + * Rotation3 -> UnitQuaternion + * Rotation3 -> UnitDualQuaternion + * Rotation2 -> UnitComplex + * Rotation -> Isometry + * Rotation -> Similarity + * Rotation -> Transform + * Rotation -> Matrix (homogeneous) + +*/ + +impl SubsetOf> for Rotation +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Rotation { + Rotation::from_matrix_unchecked(self.matrix().to_superset()) + } + + #[inline] + fn is_in_subset(rot: &Rotation) -> bool { + crate::is_convertible::<_, SMatrix>(rot.matrix()) + } + + #[inline] + fn from_superset_unchecked(rot: &Rotation) -> Self { + Rotation::from_matrix_unchecked(rot.matrix().to_subset_unchecked()) + } +} + +impl SubsetOf> for Rotation3 +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitQuaternion { + let q = UnitQuaternion::::from_rotation_matrix(self); + q.to_superset() + } + + #[inline] + fn is_in_subset(q: &UnitQuaternion) -> bool { + crate::is_convertible::<_, UnitQuaternion>(q) + } + + #[inline] + fn from_superset_unchecked(q: &UnitQuaternion) -> Self { + let q: UnitQuaternion = crate::convert_ref_unchecked(q); + q.to_rotation_matrix() + } +} + +impl SubsetOf> for Rotation3 +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitDualQuaternion { + let q = UnitQuaternion::::from_rotation_matrix(self); + let dq = UnitDualQuaternion::from_rotation(q); + dq.to_superset() + } + + #[inline] + fn is_in_subset(dq: &UnitDualQuaternion) -> bool { + crate::is_convertible::<_, UnitQuaternion>(&dq.rotation()) + && dq.translation().vector.is_zero() + } + + #[inline] + fn from_superset_unchecked(dq: &UnitDualQuaternion) -> Self { + let dq: UnitDualQuaternion = crate::convert_ref_unchecked(dq); + dq.rotation().to_rotation_matrix() + } +} + +impl SubsetOf> for Rotation2 +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitComplex { + let q = UnitComplex::::from_rotation_matrix(self); + q.to_superset() + } + + #[inline] + fn is_in_subset(q: &UnitComplex) -> bool { + crate::is_convertible::<_, UnitComplex>(q) + } + + #[inline] + fn from_superset_unchecked(q: &UnitComplex) -> Self { + let q: UnitComplex = crate::convert_ref_unchecked(q); + q.to_rotation_matrix() + } +} + +impl SubsetOf> for Rotation +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Isometry { + Isometry::from_parts(Translation::identity(), crate::convert_ref(self)) + } + + #[inline] + fn is_in_subset(iso: &Isometry) -> bool { + iso.translation.vector.is_zero() + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry) -> Self { + crate::convert_ref_unchecked(&iso.rotation) + } +} + +impl SubsetOf> for Rotation +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_parts(Translation::identity(), crate::convert_ref(self), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + sim.isometry.translation.vector.is_zero() && sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + crate::convert_ref_unchecked(&sim.isometry.rotation) + } +} + +impl SubsetOf> for Rotation +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, + Const: DimNameAdd + DimMin, Output = Const>, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + // + Allocator, + // + Allocator +{ + // needed by .is_special_orthogonal() + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> for Rotation +where + T1: RealField, + T2: RealField + SupersetOf, + Const: DimNameAdd + DimMin, Output = Const>, // needed by .is_special_orthogonal() + DefaultAllocator: Allocator, Const, Buffer = ArrayStorage> + + Allocator, U1>, DimNameSum, U1>>, // + Allocator, + // + Allocator +{ + // needed by .is_special_orthogonal() + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + let rot = m.fixed_view::(0, 0); + let bottom = m.fixed_view::<1, D>(D, 0); + + // Scalar types agree. + m.iter().all(|e| SupersetOf::::is_in_subset(e)) && + // The block part is a rotation. + rot.is_special_orthogonal(T2::default_epsilon() * crate::convert(100.0)) && + // The bottom row is (0, 0, ..., 1) + bottom.iter().all(|e| e.is_zero()) && m[(D, D)] == T2::one() + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + let r = m.fixed_view::(0, 0); + Self::from_matrix_unchecked(crate::convert_unchecked(r.into_owned())) + } +} + +impl From> for Matrix3 { + #[inline] + fn from(q: Rotation2) -> Self { + q.to_homogeneous() + } +} + +impl From> for Matrix2 { + #[inline] + fn from(q: Rotation2) -> Self { + q.into_inner() + } +} + +impl From> for Matrix4 { + #[inline] + fn from(q: Rotation3) -> Self { + q.to_homogeneous() + } +} + +impl From> for Matrix3 { + #[inline] + fn from(q: Rotation3) -> Self { + q.into_inner() + } +} + +impl From<[Rotation; 2]> + for Rotation +where + T: From<[::Element; 2]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Rotation; 2]) -> Self { + Self::from_matrix_unchecked(OMatrix::from([arr[0].into_inner(), arr[1].into_inner()])) + } +} + +impl From<[Rotation; 4]> + for Rotation +where + T: From<[::Element; 4]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Rotation; 4]) -> Self { + Self::from_matrix_unchecked(OMatrix::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + ])) + } +} + +impl From<[Rotation; 8]> + for Rotation +where + T: From<[::Element; 8]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Rotation; 8]) -> Self { + Self::from_matrix_unchecked(OMatrix::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + arr[4].into_inner(), + arr[5].into_inner(), + arr[6].into_inner(), + arr[7].into_inner(), + ])) + } +} + +impl From<[Rotation; 16]> + for Rotation +where + T: From<[::Element; 16]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [Rotation; 16]) -> Self { + Self::from_matrix_unchecked(OMatrix::from([ + arr[0].into_inner(), + arr[1].into_inner(), + arr[2].into_inner(), + arr[3].into_inner(), + arr[4].into_inner(), + arr[5].into_inner(), + arr[6].into_inner(), + arr[7].into_inner(), + arr[8].into_inner(), + arr[9].into_inner(), + arr[10].into_inner(), + arr[11].into_inner(), + arr[12].into_inner(), + arr[13].into_inner(), + arr[14].into_inner(), + arr[15].into_inner(), + ])) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_interpolation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_interpolation.rs new file mode 100644 index 000000000..d8ecd9610 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_interpolation.rs @@ -0,0 +1,81 @@ +use crate::{RealField, Rotation2, Rotation3, SimdRealField, UnitComplex, UnitQuaternion}; + +/// # Interpolation +impl Rotation2 { + /// Spherical linear interpolation between two rotation matrices. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::geometry::Rotation2; + /// + /// let rot1 = Rotation2::new(std::f32::consts::FRAC_PI_4); + /// let rot2 = Rotation2::new(-std::f32::consts::PI); + /// + /// let rot = rot1.slerp(&rot2, 1.0 / 3.0); + /// + /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); + /// ``` + #[inline] + #[must_use] + pub fn slerp(&self, other: &Self, t: T) -> Self + where + T::Element: SimdRealField, + { + let c1 = UnitComplex::from(self.clone()); + let c2 = UnitComplex::from(other.clone()); + c1.slerp(&c2, t).into() + } +} + +impl Rotation3 { + /// Spherical linear interpolation between two rotation matrices. + /// + /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_slerp` instead to avoid the panic. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::geometry::Rotation3; + /// + /// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0); + /// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0); + /// + /// let q = q1.slerp(&q2, 1.0 / 3.0); + /// + /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + #[must_use] + pub fn slerp(&self, other: &Self, t: T) -> Self + where + T: RealField, + { + let q1 = UnitQuaternion::from(self.clone()); + let q2 = UnitQuaternion::from(other.clone()); + q1.slerp(&q2, t).into() + } + + /// Computes the spherical linear interpolation between two rotation matrices or returns `None` + /// if both rotations are approximately 180 degrees apart (in which case the interpolation is + /// not well-defined). + /// + /// # Arguments + /// * `self`: the first rotation to interpolate from. + /// * `other`: the second rotation to interpolate toward. + /// * `t`: the interpolation parameter. Should be between 0 and 1. + /// * `epsilon`: the value below which the sinus of the angle separating both rotations + /// must be to return `None`. + #[inline] + #[must_use] + pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option + where + T: RealField, + { + let q1 = UnitQuaternion::from(self.clone()); + let q2 = UnitQuaternion::from(other.clone()); + q1.try_slerp(&q2, t, epsilon).map(|q| q.into()) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_ops.rs new file mode 100644 index 000000000..b5c512012 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_ops.rs @@ -0,0 +1,195 @@ +/* + * + * This provides the following operator overladings: + * + * Index<(usize, usize)> + * + * Rotation × Rotation + * Rotation ÷ Rotation + * Rotation × Matrix + * Matrix × Rotation + * Matrix ÷ Rotation + * Rotation × Point + * Rotation × Unit + * + * + * Rotation ×= Rotation + * Matrix ×= Rotation + */ + +use num::{One, Zero}; +use std::ops::{Div, DivAssign, Index, Mul, MulAssign}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; + +use crate::base::allocator::Allocator; +use crate::base::constraint::{AreMultipliable, ShapeConstraint}; +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::Storage; +use crate::base::{ + Const, DefaultAllocator, Matrix, OMatrix, SMatrix, SVector, Scalar, Unit, Vector, +}; + +use crate::geometry::{Point, Rotation}; + +impl Index<(usize, usize)> for Rotation { + type Output = T; + + #[inline] + fn index(&self, row_col: (usize, usize)) -> &T { + self.matrix().index(row_col) + } +} + +// Rotation × Rotation +md_impl_all!( + Mul, mul; + (Const, Const), (Const, Const) + const D; + for; + where; + self: Rotation, right: Rotation, Output = Rotation; + [val val] => Rotation::from_matrix_unchecked(self.into_inner() * right.into_inner()); + [ref val] => Rotation::from_matrix_unchecked(self.matrix() * right.into_inner()); + [val ref] => Rotation::from_matrix_unchecked(self.into_inner() * right.matrix()); + [ref ref] => Rotation::from_matrix_unchecked(self.matrix() * right.matrix()); +); + +// Rotation ÷ Rotation +// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? +md_impl_all!( + Div, div; + (Const, Const), (Const, Const) + const D; + for; + where; + self: Rotation, right: Rotation, Output = Rotation; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; +); + +// Rotation × Matrix +md_impl_all!( + Mul, mul; + (Const, Const), (R2, C2) + const D1; + for R2, C2, SB; + where R2: Dim, C2: Dim, SB: Storage, + DefaultAllocator: Allocator, C2>, + ShapeConstraint: AreMultipliable, Const, R2, C2>; + self: Rotation, right: Matrix, Output = OMatrix, C2>; + [val val] => self.into_inner() * right; + [ref val] => self.matrix() * right; + [val ref] => self.into_inner() * right; + [ref ref] => self.matrix() * right; +); + +// Matrix × Rotation +md_impl_all!( + Mul, mul; + (R1, C1), (Const, Const) + const D2; + for R1, C1, SA; + where R1: Dim, C1: Dim, SA: Storage, + DefaultAllocator: Allocator>, + ShapeConstraint: AreMultipliable, Const>; + self: Matrix, right: Rotation, Output = OMatrix>; + [val val] => self * right.into_inner(); + [ref val] => self * right.into_inner(); + [val ref] => self * right.matrix(); + [ref ref] => self * right.matrix(); +); + +// Matrix ÷ Rotation +md_impl_all!( + Div, div; + (R1, C1), (Const, Const) + const D2; + for R1, C1, SA; + where R1: Dim, C1: Dim, SA: Storage, + DefaultAllocator: Allocator>, + ShapeConstraint: AreMultipliable, Const>; + self: Matrix, right: Rotation, Output = OMatrix>; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; +); + +// Rotation × Point +// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended +// behavior? +md_impl_all!( + Mul, mul; + (Const, Const), (Const, U1) + const D; + for; + where ShapeConstraint: AreMultipliable, Const, Const, U1>; + self: Rotation, right: Point, Output = Point; + [val val] => self.into_inner() * right; + [ref val] => self.matrix() * right; + [val ref] => self.into_inner() * right; + [ref ref] => self.matrix() * right; +); + +// Rotation × Unit +md_impl_all!( + Mul, mul; + (Const, Const), (Const, U1) + const D; + for S; + where S: Storage>, + ShapeConstraint: AreMultipliable, Const, Const, U1>; + self: Rotation, right: Unit, S>>, Output = Unit>; + [val val] => Unit::new_unchecked(self.into_inner() * right.into_inner()); + [ref val] => Unit::new_unchecked(self.matrix() * right.into_inner()); + [val ref] => Unit::new_unchecked(self.into_inner() * right.as_ref()); + [ref ref] => Unit::new_unchecked(self.matrix() * right.as_ref()); +); + +// Rotation ×= Rotation +// TODO: try not to call `inverse()` explicitly. + +md_assign_impl_all!( + MulAssign, mul_assign; + (Const, Const), (Const, Const) + const D; for; where; + self: Rotation, right: Rotation; + [val] => self.matrix_mut_unchecked().mul_assign(right.into_inner()); + [ref] => self.matrix_mut_unchecked().mul_assign(right.matrix()); +); + +md_assign_impl_all!( + DivAssign, div_assign; + (Const, Const), (Const, Const) + const D; for; where; + self: Rotation, right: Rotation; + [val] => self.matrix_mut_unchecked().mul_assign(right.inverse().into_inner()); + [ref] => self.matrix_mut_unchecked().mul_assign(right.inverse().matrix()); +); + +// Matrix *= Rotation +// TODO: try not to call `inverse()` explicitly. +// TODO: this shares the same limitations as for the current impl. of MulAssign for matrices. +// (In particular the number of matrix column must be equal to the number of rotation columns, +// i.e., equal to the rotation dimension. + +md_assign_impl_all!( + MulAssign, mul_assign; + (Const, Const), (Const, Const) + const R1, C1; for; where; + self: SMatrix, right: Rotation; + [val] => self.mul_assign(right.into_inner()); + [ref] => self.mul_assign(right.matrix()); +); + +md_assign_impl_all!( + DivAssign, div_assign; + (Const, Const), (Const, Const) + const R1, C1; for; where; + self: SMatrix, right: Rotation; + [val] => self.mul_assign(right.inverse().into_inner()); + [ref] => self.mul_assign(right.inverse().matrix()); +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_simba.rs new file mode 100644 index 000000000..a0a14ada9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_simba.rs @@ -0,0 +1,46 @@ +use simba::simd::SimdValue; + +use crate::base::{OMatrix, Scalar}; + +use crate::geometry::Rotation; + +impl SimdValue for Rotation +where + T: Scalar + SimdValue, + T::Element: Scalar, +{ + const LANES: usize = T::LANES; + type Element = Rotation; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + Rotation::from_matrix_unchecked(OMatrix::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Rotation::from_matrix_unchecked(self.matrix().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Rotation::from_matrix_unchecked(self.matrix().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Rotation::from_matrix_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_specialization.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_specialization.rs new file mode 100644 index 000000000..8eb0b065a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/rotation_specialization.rs @@ -0,0 +1,1210 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::Zero; + +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{uniform::SampleUniform, Distribution, OpenClosed01, Standard, Uniform}, + Rng, +}; + +use simba::scalar::RealField; +use simba::simd::{SimdBool, SimdRealField}; +use std::ops::Neg; + +use crate::base::dimension::{U1, U2, U3}; +use crate::base::storage::Storage; +use crate::base::{ + Matrix2, Matrix3, SMatrix, SVector, Unit, UnitVector3, Vector, Vector1, Vector2, Vector3, +}; + +use crate::geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; + +/* + * + * 2D Rotation matrix. + * + */ +/// # Construction from a 2D rotation angle +impl Rotation2 { + /// Builds a 2 dimensional rotation matrix from an angle in radian. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation2, Point2}; + /// let rot = Rotation2::new(f32::consts::FRAC_PI_2); + /// + /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0)); + /// ``` + pub fn new(angle: T) -> Self { + let (sia, coa) = angle.simd_sin_cos(); + Self::from_matrix_unchecked(Matrix2::new(coa.clone(), -sia.clone(), sia, coa)) + } + + /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector. + /// + /// + /// This is generally used in the context of generic programming. Using + /// the `::new(angle)` method instead is more common. + #[inline] + pub fn from_scaled_axis>(axisangle: Vector) -> Self { + Self::new(axisangle[0].clone()) + } +} + +/// # Construction from an existing 2D matrix or rotations +impl Rotation2 { + /// Builds a rotation from a basis assumed to be orthonormal. + /// + /// In order to get a valid rotation matrix, the input must be an + /// orthonormal basis, i.e., all vectors are normalized, and the are + /// all orthogonal to each other. These invariants are not checked + /// by this method. + pub fn from_basis_unchecked(basis: &[Vector2; 2]) -> Self { + let mat = Matrix2::from_columns(&basis[..]); + Self::from_matrix_unchecked(mat) + } + + /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. + /// + /// This is an iterative method. See `.from_matrix_eps` to provide mover + /// convergence parameters and starting solution. + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + pub fn from_matrix(m: &Matrix2) -> Self + where + T: RealField, + { + Self::from_matrix_eps(m, T::default_epsilon(), 0, Self::identity()) + } + + /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. + /// + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + /// + /// # Parameters + /// + /// * `m`: the matrix from which the rotational part is to be extracted. + /// * `eps`: the angular errors tolerated between the current rotation and the optimal one. + /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`. + /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close + /// to the actual solution is provided. Can be set to `Rotation2::identity()` if no other + /// guesses come to mind. + pub fn from_matrix_eps(m: &Matrix2, eps: T, mut max_iter: usize, guess: Self) -> Self + where + T: RealField, + { + if max_iter == 0 { + max_iter = usize::max_value(); + } + + let mut rot = guess.into_inner(); + + for _ in 0..max_iter { + let axis = rot.column(0).perp(&m.column(0)) + rot.column(1).perp(&m.column(1)); + let denom = rot.column(0).dot(&m.column(0)) + rot.column(1).dot(&m.column(1)); + + let angle = axis / (denom.abs() + T::default_epsilon()); + if angle.clone().abs() > eps { + rot = Self::new(angle) * rot; + } else { + break; + } + } + + Self::from_matrix_unchecked(rot) + } + + /// The rotation matrix required to align `a` and `b` but with its angle. + /// + /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector2, Rotation2}; + /// let a = Vector2::new(1.0, 2.0); + /// let b = Vector2::new(2.0, 1.0); + /// let rot = Rotation2::rotation_between(&a, &b); + /// assert_relative_eq!(rot * a, b); + /// assert_relative_eq!(rot.inverse() * b, a); + /// ``` + #[inline] + pub fn rotation_between(a: &Vector, b: &Vector) -> Self + where + T: RealField, + SB: Storage, + SC: Storage, + { + crate::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix()) + } + + /// The smallest rotation needed to make `a` and `b` collinear and point toward the same + /// direction, raised to the power `s`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector2, Rotation2}; + /// let a = Vector2::new(1.0, 2.0); + /// let b = Vector2::new(2.0, 1.0); + /// let rot2 = Rotation2::scaled_rotation_between(&a, &b, 0.2); + /// let rot5 = Rotation2::scaled_rotation_between(&a, &b, 0.5); + /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn scaled_rotation_between( + a: &Vector, + b: &Vector, + s: T, + ) -> Self + where + T: RealField, + SB: Storage, + SC: Storage, + { + crate::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) + } + + /// The rotation matrix needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation2; + /// let rot1 = Rotation2::new(0.1); + /// let rot2 = Rotation2::new(1.7); + /// let rot_to = rot1.rotation_to(&rot2); + /// + /// assert_relative_eq!(rot_to * rot1, rot2); + /// assert_relative_eq!(rot_to.inverse() * rot2, rot1); + /// ``` + #[inline] + #[must_use] + pub fn rotation_to(&self, other: &Self) -> Self { + other * self.inverse() + } + + /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated + /// computations might cause the matrix from progressively not being orthonormal anymore. + #[inline] + pub fn renormalize(&mut self) + where + T: RealField, + { + let mut c = UnitComplex::from(self.clone()); + let _ = c.renormalize(); + + *self = Self::from_matrix_eps(self.matrix(), T::default_epsilon(), 0, c.into()) + } + + /// Raise the rotation to a given floating power, i.e., returns the rotation with the angle + /// of `self` multiplied by `n`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation2; + /// let rot = Rotation2::new(0.78); + /// let pow = rot.powf(2.0); + /// assert_relative_eq!(pow.angle(), 2.0 * 0.78); + /// ``` + #[inline] + #[must_use] + pub fn powf(&self, n: T) -> Self { + Self::new(self.angle() * n) + } +} + +/// # 2D angle extraction +impl Rotation2 { + /// The rotation angle. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation2; + /// let rot = Rotation2::new(1.78); + /// assert_relative_eq!(rot.angle(), 1.78); + /// ``` + #[inline] + #[must_use] + pub fn angle(&self) -> T { + self.matrix()[(1, 0)] + .clone() + .simd_atan2(self.matrix()[(0, 0)].clone()) + } + + /// The rotation angle needed to make `self` and `other` coincide. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation2; + /// let rot1 = Rotation2::new(0.1); + /// let rot2 = Rotation2::new(1.7); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); + /// ``` + #[inline] + #[must_use] + pub fn angle_to(&self, other: &Self) -> T { + self.rotation_to(other).angle() + } + + /// The rotation angle returned as a 1-dimensional vector. + /// + /// This is generally used in the context of generic programming. Using + /// the `.angle()` method instead is more common. + #[inline] + #[must_use] + pub fn scaled_axis(&self) -> SVector { + Vector1::new(self.angle()) + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + T::Element: SimdRealField, + T: SampleUniform, +{ + /// Generate a uniformly distributed random rotation. + #[inline] + fn sample(&self, rng: &mut R) -> Rotation2 { + let twopi = Uniform::new(T::zero(), T::simd_two_pi()); + Rotation2::new(rng.sample(twopi)) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Rotation2 +where + T::Element: SimdRealField, + Owned: Send, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + Self::new(T::arbitrary(g)) + } +} + +/* + * + * 3D Rotation matrix. + * + */ +/// # Construction from a 3D axis and/or angles +impl Rotation3 +where + T::Element: SimdRealField, +{ + /// Builds a 3 dimensional rotation matrix from an axis and an angle. + /// + /// # Arguments + /// * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation + /// in radian. Its direction is the axis of rotation. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation3, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let rot = Rotation3::new(axisangle); + /// + /// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // A zero vector yields an identity. + /// assert_eq!(Rotation3::new(Vector3::::zeros()), Rotation3::identity()); + /// ``` + pub fn new>(axisangle: Vector) -> Self { + let axisangle = axisangle.into_owned(); + let (axis, angle) = Unit::new_and_get(axisangle); + Self::from_axis_angle(&axis, angle) + } + + /// Builds a 3D rotation matrix from an axis scaled by the rotation angle. + /// + /// This is the same as `Self::new(axisangle)`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation3, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let rot = Rotation3::new(axisangle); + /// + /// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // A zero vector yields an identity. + /// assert_eq!(Rotation3::from_scaled_axis(Vector3::::zeros()), Rotation3::identity()); + /// ``` + pub fn from_scaled_axis>(axisangle: Vector) -> Self { + Self::new(axisangle) + } + + /// Builds a 3D rotation matrix from an axis and a rotation angle. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation3, Point3, Vector3}; + /// let axis = Vector3::y_axis(); + /// let angle = f32::consts::FRAC_PI_2; + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// let rot = Rotation3::from_axis_angle(&axis, angle); + /// + /// assert_eq!(rot.axis().unwrap(), axis); + /// assert_eq!(rot.angle(), angle); + /// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6); + /// + /// // A zero vector yields an identity. + /// assert_eq!(Rotation3::from_scaled_axis(Vector3::::zeros()), Rotation3::identity()); + /// ``` + pub fn from_axis_angle(axis: &Unit>, angle: T) -> Self + where + SB: Storage, + { + angle.clone().simd_ne(T::zero()).if_else( + || { + let ux = axis.as_ref()[0].clone(); + let uy = axis.as_ref()[1].clone(); + let uz = axis.as_ref()[2].clone(); + let sqx = ux.clone() * ux.clone(); + let sqy = uy.clone() * uy.clone(); + let sqz = uz.clone() * uz.clone(); + let (sin, cos) = angle.simd_sin_cos(); + let one_m_cos = T::one() - cos.clone(); + + Self::from_matrix_unchecked(SMatrix::::new( + sqx.clone() + (T::one() - sqx) * cos.clone(), + ux.clone() * uy.clone() * one_m_cos.clone() - uz.clone() * sin.clone(), + ux.clone() * uz.clone() * one_m_cos.clone() + uy.clone() * sin.clone(), + ux.clone() * uy.clone() * one_m_cos.clone() + uz.clone() * sin.clone(), + sqy.clone() + (T::one() - sqy) * cos.clone(), + uy.clone() * uz.clone() * one_m_cos.clone() - ux.clone() * sin.clone(), + ux.clone() * uz.clone() * one_m_cos.clone() - uy.clone() * sin.clone(), + uy * uz * one_m_cos + ux * sin, + sqz.clone() + (T::one() - sqz) * cos, + )) + }, + Self::identity, + ) + } + + /// Creates a new rotation from Euler angles. + /// + /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation3; + /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); + /// let euler = rot.euler_angles(); + /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); + /// ``` + pub fn from_euler_angles(roll: T, pitch: T, yaw: T) -> Self { + let (sr, cr) = roll.simd_sin_cos(); + let (sp, cp) = pitch.simd_sin_cos(); + let (sy, cy) = yaw.simd_sin_cos(); + + Self::from_matrix_unchecked(SMatrix::::new( + cy.clone() * cp.clone(), + cy.clone() * sp.clone() * sr.clone() - sy.clone() * cr.clone(), + cy.clone() * sp.clone() * cr.clone() + sy.clone() * sr.clone(), + sy.clone() * cp.clone(), + sy.clone() * sp.clone() * sr.clone() + cy.clone() * cr.clone(), + sy * sp.clone() * cr.clone() - cy * sr.clone(), + -sp, + cp.clone() * sr, + cp * cr, + )) + } +} + +/// # Construction from a 3D eye position and target point +impl Rotation3 +where + T::Element: SimdRealField, +{ + /// Creates a rotation that corresponds to the local frame of an observer standing at the + /// origin and looking toward `dir`. + /// + /// It maps the `z` axis to the direction `dir`. + /// + /// # Arguments + /// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with. + /// * up - The vertical direction. The only requirement of this parameter is to not be + /// collinear to `dir`. Non-collinearity is not checked. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation3, Vector3}; + /// let dir = Vector3::new(1.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// let rot = Rotation3::face_towards(&dir, &up); + /// assert_relative_eq!(rot * Vector3::z(), dir.normalize()); + /// ``` + #[inline] + pub fn face_towards(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + // Gram–Schmidt process + let zaxis = dir.normalize(); + let xaxis = up.cross(&zaxis).normalize(); + let yaxis = zaxis.cross(&xaxis); + + Self::from_matrix_unchecked(SMatrix::::new( + xaxis.x.clone(), + yaxis.x.clone(), + zaxis.x.clone(), + xaxis.y.clone(), + yaxis.y.clone(), + zaxis.y.clone(), + xaxis.z.clone(), + yaxis.z.clone(), + zaxis.z.clone(), + )) + } + + /// Deprecated: Use [`Rotation3::face_towards`] instead. + #[deprecated(note = "renamed to `face_towards`")] + pub fn new_observer_frames(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::face_towards(dir, up) + } + + /// Builds a right-handed look-at view matrix without translation. + /// + /// It maps the view direction `dir` to the **negative** `z` axis. + /// This conforms to the common notion of right handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * dir - The direction toward which the camera looks. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `dir`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation3, Vector3}; + /// let dir = Vector3::new(1.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// let rot = Rotation3::look_at_rh(&dir, &up); + /// assert_relative_eq!(rot * dir.normalize(), -Vector3::z()); + /// ``` + #[inline] + pub fn look_at_rh(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::face_towards(&dir.neg(), up).inverse() + } + + /// Builds a left-handed look-at view matrix without translation. + /// + /// It maps the view direction `dir` to the **positive** `z` axis. + /// This conforms to the common notion of left handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * dir - The direction toward which the camera looks. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `dir`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation3, Vector3}; + /// let dir = Vector3::new(1.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// let rot = Rotation3::look_at_lh(&dir, &up); + /// assert_relative_eq!(rot * dir.normalize(), Vector3::z()); + /// ``` + #[inline] + pub fn look_at_lh(dir: &Vector, up: &Vector) -> Self + where + SB: Storage, + SC: Storage, + { + Self::face_towards(dir, up).inverse() + } +} + +/// # Construction from an existing 3D matrix or rotations +impl Rotation3 +where + T::Element: SimdRealField, +{ + /// The rotation matrix required to align `a` and `b` but with its angle. + /// + /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector3, Rotation3}; + /// let a = Vector3::new(1.0, 2.0, 3.0); + /// let b = Vector3::new(3.0, 1.0, 2.0); + /// let rot = Rotation3::rotation_between(&a, &b).unwrap(); + /// assert_relative_eq!(rot * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(rot.inverse() * b, a, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn rotation_between(a: &Vector, b: &Vector) -> Option + where + T: RealField, + SB: Storage, + SC: Storage, + { + Self::scaled_rotation_between(a, b, T::one()) + } + + /// The smallest rotation needed to make `a` and `b` collinear and point toward the same + /// direction, raised to the power `s`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector3, Rotation3}; + /// let a = Vector3::new(1.0, 2.0, 3.0); + /// let b = Vector3::new(3.0, 1.0, 2.0); + /// let rot2 = Rotation3::scaled_rotation_between(&a, &b, 0.2).unwrap(); + /// let rot5 = Rotation3::scaled_rotation_between(&a, &b, 0.5).unwrap(); + /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn scaled_rotation_between( + a: &Vector, + b: &Vector, + n: T, + ) -> Option + where + T: RealField, + SB: Storage, + SC: Storage, + { + // TODO: code duplication with Rotation. + if let (Some(na), Some(nb)) = (a.try_normalize(T::zero()), b.try_normalize(T::zero())) { + let c = na.cross(&nb); + + if let Some(axis) = Unit::try_new(c, T::default_epsilon()) { + return Some(Self::from_axis_angle(&axis, na.dot(&nb).acos() * n)); + } + + // Zero or PI. + if na.dot(&nb) < T::zero() { + // PI + // + // The rotation axis is undefined but the angle not zero. This is not a + // simple rotation. + return None; + } + } + + Some(Self::identity()) + } + + /// The rotation matrix needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3}; + /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); + /// let rot_to = rot1.rotation_to(&rot2); + /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn rotation_to(&self, other: &Self) -> Self { + other * self.inverse() + } + + /// Raise the rotation to a given floating power, i.e., returns the rotation with the same + /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = Rotation3::from_axis_angle(&axis, angle); + /// let pow = rot.powf(2.0); + /// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6); + /// assert_eq!(pow.angle(), 2.4); + /// ``` + #[inline] + #[must_use] + pub fn powf(&self, n: T) -> Self + where + T: RealField, + { + if let Some(axis) = self.axis() { + Self::from_axis_angle(&axis, self.angle() * n) + } else if self.matrix()[(0, 0)] < T::zero() { + let minus_id = SMatrix::::from_diagonal_element(-T::one()); + Self::from_matrix_unchecked(minus_id) + } else { + Self::identity() + } + } + + /// Builds a rotation from a basis assumed to be orthonormal. + /// + /// In order to get a valid rotation matrix, the input must be an + /// orthonormal basis, i.e., all vectors are normalized, and the are + /// all orthogonal to each other. These invariants are not checked + /// by this method. + pub fn from_basis_unchecked(basis: &[Vector3; 3]) -> Self { + let mat = Matrix3::from_columns(&basis[..]); + Self::from_matrix_unchecked(mat) + } + + /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. + /// + /// This is an iterative method. See `.from_matrix_eps` to provide mover + /// convergence parameters and starting solution. + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + pub fn from_matrix(m: &Matrix3) -> Self + where + T: RealField, + { + Self::from_matrix_eps(m, T::default_epsilon(), 0, Self::identity()) + } + + /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. + /// + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + /// + /// # Parameters + /// + /// * `m`: the matrix from which the rotational part is to be extracted. + /// * `eps`: the angular errors tolerated between the current rotation and the optimal one. + /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`. + /// * `guess`: a guess of the solution. Convergence will be significantly faster if an initial solution close + /// to the actual solution is provided. Can be set to `Rotation3::identity()` if no other + /// guesses come to mind. + pub fn from_matrix_eps(m: &Matrix3, eps: T, mut max_iter: usize, guess: Self) -> Self + where + T: RealField, + { + if max_iter == 0 { + max_iter = usize::MAX; + } + + // Using sqrt(eps) ensures we perturb with something larger than eps; clamp to eps to handle the case of eps > 1.0 + let eps_disturbance = eps.clone().sqrt().max(eps.clone() * eps.clone()); + let mut perturbation_axes = Vector3::x_axis(); + let mut rot = guess.into_inner(); + + for _ in 0..max_iter { + let axis = rot.column(0).cross(&m.column(0)) + + rot.column(1).cross(&m.column(1)) + + rot.column(2).cross(&m.column(2)); + let denom = rot.column(0).dot(&m.column(0)) + + rot.column(1).dot(&m.column(1)) + + rot.column(2).dot(&m.column(2)); + + let axisangle = axis / (denom.abs() + T::default_epsilon()); + + if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, eps.clone()) { + rot = Rotation3::from_axis_angle(&axis, angle) * rot; + } else { + // Check if stuck in a maximum w.r.t. the norm (m - rot).norm() + let mut perturbed = rot.clone(); + let norm_squared = (m - &rot).norm_squared(); + let mut new_norm_squared: T; + + // Perturb until the new norm is significantly different + loop { + perturbed *= + Rotation3::from_axis_angle(&perturbation_axes, eps_disturbance.clone()); + new_norm_squared = (m - &perturbed).norm_squared(); + if abs_diff_ne!( + norm_squared, + new_norm_squared, + epsilon = T::default_epsilon() + ) { + break; + } + } + + // If new norm is larger, it's a minimum + if norm_squared < new_norm_squared { + break; + } + + // If not, continue from perturbed rotation, but use a different axes for the next perturbation + perturbation_axes = UnitVector3::new_unchecked(perturbation_axes.yzx()); + rot = perturbed; + } + } + + Self::from_matrix_unchecked(rot) + } + + /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated + /// computations might cause the matrix from progressively not being orthonormal anymore. + #[inline] + pub fn renormalize(&mut self) + where + T: RealField, + { + let mut c = UnitQuaternion::from(self.clone()); + let _ = c.renormalize(); + + *self = Self::from_matrix_eps(self.matrix(), T::default_epsilon(), 0, c.into()) + } +} + +/// # 3D axis and angle extraction +impl Rotation3 { + /// The rotation angle in [0; pi]. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Unit, Rotation3, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = Rotation3::from_axis_angle(&axis, 1.78); + /// assert_relative_eq!(rot.angle(), 1.78); + /// ``` + #[inline] + #[must_use] + pub fn angle(&self) -> T { + ((self.matrix()[(0, 0)].clone() + + self.matrix()[(1, 1)].clone() + + self.matrix()[(2, 2)].clone() + - T::one()) + / crate::convert(2.0)) + .simd_acos() + } + + /// The rotation axis. Returns `None` if the rotation angle is zero or PI. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = Rotation3::from_axis_angle(&axis, angle); + /// assert_relative_eq!(rot.axis().unwrap(), axis); + /// + /// // Case with a zero angle. + /// let rot = Rotation3::from_axis_angle(&axis, 0.0); + /// assert!(rot.axis().is_none()); + /// ``` + #[inline] + #[must_use] + pub fn axis(&self) -> Option>> + where + T: RealField, + { + let rotmat = self.matrix(); + let axis = SVector::::new( + rotmat[(2, 1)].clone() - rotmat[(1, 2)].clone(), + rotmat[(0, 2)].clone() - rotmat[(2, 0)].clone(), + rotmat[(1, 0)].clone() - rotmat[(0, 1)].clone(), + ); + + Unit::try_new(axis, T::default_epsilon()) + } + + /// The rotation axis multiplied by the rotation angle. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3, Unit}; + /// let axisangle = Vector3::new(0.1, 0.2, 0.3); + /// let rot = Rotation3::new(axisangle); + /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn scaled_axis(&self) -> Vector3 + where + T: RealField, + { + if let Some(axis) = self.axis() { + axis.into_inner() * self.angle() + } else { + Vector::zero() + } + } + + /// The rotation axis and angle in (0, pi] of this rotation matrix. + /// + /// Returns `None` if the angle is zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = Rotation3::from_axis_angle(&axis, angle); + /// let axis_angle = rot.axis_angle().unwrap(); + /// assert_relative_eq!(axis_angle.0, axis); + /// assert_relative_eq!(axis_angle.1, angle); + /// + /// // Case with a zero angle. + /// let rot = Rotation3::from_axis_angle(&axis, 0.0); + /// assert!(rot.axis_angle().is_none()); + /// ``` + #[inline] + #[must_use] + pub fn axis_angle(&self) -> Option<(Unit>, T)> + where + T: RealField, + { + self.axis().map(|axis| (axis, self.angle())) + } + + /// The rotation angle needed to make `self` and `other` coincide. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3}; + /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn angle_to(&self, other: &Self) -> T + where + T::Element: SimdRealField, + { + self.rotation_to(other).angle() + } + + /// Creates Euler angles from a rotation. + /// + /// The angles are produced in the form (roll, pitch, yaw). + #[deprecated(note = "This is renamed to use `.euler_angles()`.")] + pub fn to_euler_angles(self) -> (T, T, T) + where + T: RealField, + { + self.euler_angles() + } + + /// Euler angles corresponding to this rotation from a rotation. + /// + /// The angles are produced in the form (roll, pitch, yaw). + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation3; + /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); + /// let euler = rot.euler_angles(); + /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); + /// ``` + #[must_use] + pub fn euler_angles(&self) -> (T, T, T) + where + T: RealField, + { + // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh + // https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 + // where roll, pitch, yaw angles are referred to as ψ, θ, ϕ, + if self[(2, 0)].clone().abs() < T::one() { + let pitch = -self[(2, 0)].clone().asin(); + let theta_cos = pitch.clone().cos(); + let roll = (self[(2, 1)].clone() / theta_cos.clone()) + .atan2(self[(2, 2)].clone() / theta_cos.clone()); + let yaw = + (self[(1, 0)].clone() / theta_cos.clone()).atan2(self[(0, 0)].clone() / theta_cos); + (roll, pitch, yaw) + } else if self[(2, 0)].clone() <= -T::one() { + ( + self[(0, 1)].clone().atan2(self[(0, 2)].clone()), + T::frac_pi_2(), + T::zero(), + ) + } else { + ( + -self[(0, 1)].clone().atan2(-self[(0, 2)].clone()), + -T::frac_pi_2(), + T::zero(), + ) + } + } + + /// Represent this rotation as Euler angles. + /// + /// Returns the angles produced in the order provided by seq parameter, along with the + /// observability flag. The Euler axes passed to seq must form an orthonormal basis. If the + /// rotation is gimbal locked, then the observability flag is false. + /// + /// # Panics + /// + /// Panics if the Euler axes in `seq` are not orthonormal. + /// + /// # Example 1: + /// ``` + /// use std::f64::consts::PI; + /// use approx::assert_relative_eq; + /// use nalgebra::{Matrix3, Rotation3, Unit, Vector3}; + /// + /// // 3-1-2 + /// let n = [ + /// Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)), + /// Unit::new_unchecked(Vector3::new(1.0, 0.0, 0.0)), + /// Unit::new_unchecked(Vector3::new(0.0, 1.0, 0.0)), + /// ]; + /// + /// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0); + /// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0); + /// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0); + /// + /// let d = r3 * r2 * r1; + /// + /// let (angles, observable) = d.euler_angles_ordered(n, false); + /// assert!(observable); + /// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12); + /// ``` + /// + /// # Example 2: + /// ``` + /// use std::f64::consts::PI; + /// use approx::assert_relative_eq; + /// use nalgebra::{Matrix3, Rotation3, Unit, Vector3}; + /// + /// let sqrt_2 = 2.0_f64.sqrt(); + /// let n = [ + /// Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, 1.0 / sqrt_2, 0.0)), + /// Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, -1.0 / sqrt_2, 0.0)), + /// Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)), + /// ]; + /// + /// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0); + /// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0); + /// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0); + /// + /// let d = r3 * r2 * r1; + /// + /// let (angles, observable) = d.euler_angles_ordered(n, false); + /// assert!(observable); + /// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12); + /// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12); + /// ``` + /// + /// Algorithm based on: + /// Malcolm D. Shuster, F. Landis Markley, “General formula for extraction the Euler + /// angles”, Journal of guidance, control, and dynamics, vol. 29.1, pp. 215-221. 2006, + /// and modified to be able to produce extrinsic rotations. + #[must_use] + pub fn euler_angles_ordered( + &self, + mut seq: [Unit>; 3], + extrinsic: bool, + ) -> ([T; 3], bool) + where + T: RealField + Copy, + { + let mut angles = [T::zero(); 3]; + let eps = T::from_subset(&1e-7); + let two = T::from_subset(&2.0); + + if extrinsic { + seq.reverse(); + } + + let [n1, n2, n3] = &seq; + assert_relative_eq!(n1.dot(n2), T::zero(), epsilon = eps); + assert_relative_eq!(n3.dot(n1), T::zero(), epsilon = eps); + + let n1_c_n2 = n1.cross(n2); + let s1 = n1_c_n2.dot(n3); + let c1 = n1.dot(n3); + let lambda = s1.atan2(c1); + + let mut c = Matrix3::zeros(); + c.column_mut(0).copy_from(n2); + c.column_mut(1).copy_from(&n1_c_n2); + c.column_mut(2).copy_from(n1); + c.transpose_mut(); + + let r1l = Matrix3::new( + T::one(), + T::zero(), + T::zero(), + T::zero(), + c1, + s1, + T::zero(), + -s1, + c1, + ); + let o_t = c * self.matrix() * (c.transpose() * r1l); + angles[1] = o_t.m33.acos(); + + let safe1 = angles[1].abs() >= eps; + let safe2 = (angles[1] - T::pi()).abs() >= eps; + let observable = safe1 && safe2; + angles[1] += lambda; + + if observable { + angles[0] = o_t.m13.atan2(-o_t.m23); + angles[2] = o_t.m31.atan2(o_t.m32); + } else { + // gimbal lock detected + if extrinsic { + // angle1 is initialized to zero + if !safe1 { + angles[2] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22); + } else { + angles[2] = -(o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22); + }; + } else { + // angle3 is initialized to zero + if !safe1 { + angles[0] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22); + } else { + angles[0] = (o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22); + }; + }; + }; + + let adjust = if seq[0] == seq[2] { + // lambda = 0, so ensure angle2 -> [0, pi] + angles[1] < T::zero() || angles[1] > T::pi() + } else { + // lamda = + or - pi/2, so ensure angle2 -> [-pi/2, pi/2] + angles[1] < -T::frac_pi_2() || angles[1] > T::frac_pi_2() + }; + + // dont adjust gimbal locked rotation + if adjust && observable { + angles[0] += T::pi(); + angles[1] = two * lambda - angles[1]; + angles[2] -= T::pi(); + } + + // ensure all angles are within [-pi, pi] + for angle in angles.as_mut_slice().iter_mut() { + if *angle < -T::pi() { + *angle += T::two_pi(); + } else if *angle > T::pi() { + *angle -= T::two_pi(); + } + } + + if extrinsic { + angles.reverse(); + } + + (angles, observable) + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + T::Element: SimdRealField, + OpenClosed01: Distribution, + T: SampleUniform, +{ + /// Generate a uniformly distributed random rotation. + #[inline] + fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation3 { + // James Arvo. + // Fast random rotation matrices. + // In D. Kirk, editor, Graphics Gems III, pages 117-120. Academic, New York, 1992. + + // Compute a random rotation around Z + let twopi = Uniform::new(T::zero(), T::simd_two_pi()); + let theta = rng.sample(&twopi); + let (ts, tc) = theta.simd_sin_cos(); + let a = SMatrix::::new( + tc.clone(), + ts.clone(), + T::zero(), + -ts, + tc, + T::zero(), + T::zero(), + T::zero(), + T::one(), + ); + + // Compute a random rotation *of* Z + let phi = rng.sample(&twopi); + let z = rng.sample(OpenClosed01); + let (ps, pc) = phi.simd_sin_cos(); + let sqrt_z = z.clone().simd_sqrt(); + let v = Vector3::new(pc * sqrt_z.clone(), ps * sqrt_z, (T::one() - z).simd_sqrt()); + let mut b = v.clone() * v.transpose(); + b += b.clone(); + b -= SMatrix::::identity(); + + Rotation3::from_matrix_unchecked(b * a) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Rotation3 +where + T::Element: SimdRealField, + Owned: Send, + Owned: Send, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + Self::new(SVector::arbitrary(g)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale.rs new file mode 100644 index 000000000..1573d8e06 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale.rs @@ -0,0 +1,390 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::{One, Zero}; +use std::fmt; +use std::hash; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{Const, DefaultAllocator, OMatrix, OVector, SVector, Scalar}; +use crate::ClosedDivAssign; +use crate::ClosedMulAssign; + +use crate::geometry::Point; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A scale which supports non-uniform scaling. +#[repr(C)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Scale", + bound(archive = " + T: rkyv::Archive, + SVector: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[derive(Copy, Clone)] +pub struct Scale { + /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is + /// scaled. + pub vector: SVector, +} + +impl fmt::Debug for Scale { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.vector.as_slice().fmt(formatter) + } +} + +impl hash::Hash for Scale +where + Owned>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.vector.hash(state) + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Scale +where + T: Scalar + bytemuck::Zeroable, + SVector: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Scale +where + T: Scalar + bytemuck::Pod, + SVector: bytemuck::Pod, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Scale +where + Owned>: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.vector.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Scale +where + Owned>: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = SVector::::deserialize(deserializer)?; + + Ok(Scale::from(matrix)) + } +} + +impl Scale { + /// Inverts `self`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale2, Scale3}; + /// let t = Scale3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * t.try_inverse().unwrap(), Scale3::identity()); + /// assert_eq!(t.try_inverse().unwrap() * t, Scale3::identity()); + /// + /// // Work in all dimensions. + /// let t = Scale2::new(1.0, 2.0); + /// assert_eq!(t * t.try_inverse().unwrap(), Scale2::identity()); + /// assert_eq!(t.try_inverse().unwrap() * t, Scale2::identity()); + /// + /// // Returns None if any coordinate is 0. + /// let t = Scale2::new(0.0, 2.0); + /// assert_eq!(t.try_inverse(), None); + /// ``` + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn try_inverse(&self) -> Option> + where + T: ClosedDivAssign + One + Zero, + { + for i in 0..D { + if self.vector[i] == T::zero() { + return None; + } + } + Some(self.vector.map(|e| T::one() / e).into()) + } + + /// Inverts `self`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale2, Scale3}; + /// + /// unsafe { + /// let t = Scale3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * t.inverse_unchecked(), Scale3::identity()); + /// assert_eq!(t.inverse_unchecked() * t, Scale3::identity()); + /// + /// // Work in all dimensions. + /// let t = Scale2::new(1.0, 2.0); + /// assert_eq!(t * t.inverse_unchecked(), Scale2::identity()); + /// assert_eq!(t.inverse_unchecked() * t, Scale2::identity()); + /// } + /// ``` + /// + /// # Safety + /// + /// Should only be used if all scaling is known to be non-zero. + #[inline] + #[must_use] + pub unsafe fn inverse_unchecked(&self) -> Scale + where + T: ClosedDivAssign + One, + { + self.vector.map(|e| T::one() / e).into() + } + + /// Inverts `self`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale2, Scale3}; + /// let t = Scale3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * t.pseudo_inverse(), Scale3::identity()); + /// assert_eq!(t.pseudo_inverse() * t, Scale3::identity()); + /// + /// // Work in all dimensions. + /// let t = Scale2::new(1.0, 2.0); + /// assert_eq!(t * t.pseudo_inverse(), Scale2::identity()); + /// assert_eq!(t.pseudo_inverse() * t, Scale2::identity()); + /// + /// // Inverts only non-zero coordinates. + /// let t = Scale2::new(0.0, 2.0); + /// assert_eq!(t * t.pseudo_inverse(), Scale2::new(0.0, 1.0)); + /// assert_eq!(t.pseudo_inverse() * t, Scale2::new(0.0, 1.0)); + /// ``` + #[inline] + #[must_use] + pub fn pseudo_inverse(&self) -> Scale + where + T: ClosedDivAssign + One + Zero, + { + self.vector + .map(|e| { + if e != T::zero() { + T::one() / e + } else { + T::zero() + } + }) + .into() + } + + /// Converts this Scale into its equivalent homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale2, Scale3, Matrix3, Matrix4}; + /// let t = Scale3::new(10.0, 20.0, 30.0); + /// let expected = Matrix4::new(10.0, 0.0, 0.0, 0.0, + /// 0.0, 20.0, 0.0, 0.0, + /// 0.0, 0.0, 30.0, 0.0, + /// 0.0, 0.0, 0.0, 1.0); + /// assert_eq!(t.to_homogeneous(), expected); + /// + /// let t = Scale2::new(10.0, 20.0); + /// let expected = Matrix3::new(10.0, 0.0, 0.0, + /// 0.0, 20.0, 0.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(t.to_homogeneous(), expected); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> + where + T: Zero + One + Clone, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>, U1>, + { + // TODO: use self.vector.push() instead. We can’t right now because + // that would require the DimAdd bound (but here we use DimNameAdd). + // This should be fixable once Rust gets a more complete support of + // const-generics. + let mut v = OVector::from_element(T::one()); + for i in 0..D { + v[i] = self.vector[i].clone(); + } + OMatrix::from_diagonal(&v) + } + + /// Inverts `self` in-place. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale2, Scale3}; + /// let t = Scale3::new(1.0, 2.0, 3.0); + /// let mut inv_t = Scale3::new(1.0, 2.0, 3.0); + /// assert!(inv_t.try_inverse_mut()); + /// assert_eq!(t * inv_t, Scale3::identity()); + /// assert_eq!(inv_t * t, Scale3::identity()); + /// + /// // Work in all dimensions. + /// let t = Scale2::new(1.0, 2.0); + /// let mut inv_t = Scale2::new(1.0, 2.0); + /// assert!(inv_t.try_inverse_mut()); + /// assert_eq!(t * inv_t, Scale2::identity()); + /// assert_eq!(inv_t * t, Scale2::identity()); + /// + /// // Does not perform any operation if a coordinate is 0. + /// let mut t = Scale2::new(0.0, 2.0); + /// assert!(!t.try_inverse_mut()); + /// ``` + #[inline] + pub fn try_inverse_mut(&mut self) -> bool + where + T: ClosedDivAssign + One + Zero, + { + if let Some(v) = self.try_inverse() { + self.vector = v.vector; + true + } else { + false + } + } +} + +impl Scale { + /// Translate the given point. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale3, Point3}; + /// let t = Scale3::new(1.0, 2.0, 3.0); + /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_eq!(transformed_point, Point3::new(4.0, 10.0, 18.0)); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } +} + +impl Scale { + /// Translate the given point by the inverse of this Scale. + /// + /// # Example + /// ``` + /// # use nalgebra::{Scale3, Point3}; + /// let t = Scale3::new(1.0, 2.0, 3.0); + /// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)).unwrap(); + /// assert_eq!(transformed_point, Point3::new(4.0, 3.0, 2.0)); + /// + /// // Returns None if the inverse doesn't exist. + /// let t = Scale3::new(1.0, 0.0, 3.0); + /// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)); + /// assert_eq!(transformed_point, None); + /// ``` + #[inline] + #[must_use] + pub fn try_inverse_transform_point(&self, pt: &Point) -> Option> { + self.try_inverse().map(|s| s * pt) + } +} + +impl Eq for Scale {} + +impl PartialEq for Scale { + #[inline] + fn eq(&self, right: &Scale) -> bool { + self.vector == right.vector + } +} + +impl AbsDiffEq for Scale +where + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.vector.abs_diff_eq(&other.vector, epsilon) + } +} + +impl RelativeEq for Scale +where + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.vector + .relative_eq(&other.vector, epsilon, max_relative) + } +} + +impl UlpsEq for Scale +where + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.vector.ulps_eq(&other.vector, epsilon, max_ulps) + } +} + +/* + * + * Display + * + */ +impl fmt::Display for Scale { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let precision = f.precision().unwrap_or(3); + + writeln!(f, "Scale {{")?; + write!(f, "{:.*}", precision, self.vector)?; + writeln!(f, "}}") + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_alias.rs new file mode 100644 index 000000000..f01dbbf4a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_alias.rs @@ -0,0 +1,19 @@ +use crate::geometry::Scale; + +/// A 1-dimensional scale. +pub type Scale1 = Scale; + +/// A 2-dimensional scale. +pub type Scale2 = Scale; + +/// A 3-dimensional scale. +pub type Scale3 = Scale; + +/// A 4-dimensional scale. +pub type Scale4 = Scale; + +/// A 5-dimensional scale. +pub type Scale5 = Scale; + +/// A 6-dimensional scale. +pub type Scale6 = Scale; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_construction.rs new file mode 100644 index 000000000..9ef4c7017 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_construction.rs @@ -0,0 +1,123 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::One; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use simba::scalar::{ClosedMulAssign, SupersetOf}; + +use crate::base::{SVector, Scalar}; +use crate::geometry::Scale; + +impl Scale { + /// Creates a new identity scale. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3, Scale2, Scale3}; + /// let t = Scale2::identity(); + /// let p = Point2::new(1.0, 2.0); + /// assert_eq!(t * p, p); + /// + /// // Works in all dimensions. + /// let t = Scale3::identity(); + /// let p = Point3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * p, p); + /// ``` + #[inline] + pub fn identity() -> Scale + where + T: One, + { + Scale::from(SVector::from_element(T::one())) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Scale2; + /// let tra = Scale2::new(1.0f64, 2.0); + /// let tra2 = tra.cast::(); + /// assert_eq!(tra2, Scale2::new(1.0f32, 2.0)); + /// ``` + pub fn cast(self) -> Scale + where + Scale: SupersetOf, + { + crate::convert(self) + } +} + +impl One for Scale { + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, +{ + /// Generate an arbitrary random variate for testing purposes. + #[inline] + fn sample(&self, rng: &mut G) -> Scale { + Scale::from(rng.gen::>()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Scale +where + Owned>: Send, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + let v: SVector = Arbitrary::arbitrary(rng); + Self::from(v) + } +} + +/* + * + * Small Scale construction from components. + * + */ +macro_rules! componentwise_constructors_impl( + ($($doc: expr; $D: expr, $($args: ident:$irow: expr),*);* $(;)*) => {$( + impl Scale + { + #[doc = "Initializes this Scale from its components."] + #[doc = "# Example\n```"] + #[doc = $doc] + #[doc = "```"] + #[inline] + pub const fn new($($args: T),*) -> Self { + Self { vector: SVector::::new($($args),*) } + } + } + )*} +); + +componentwise_constructors_impl!( + "# use nalgebra::Scale1;\nlet t = Scale1::new(1.0);\nassert!(t.vector.x == 1.0);"; + 1, x:0; + "# use nalgebra::Scale2;\nlet t = Scale2::new(1.0, 2.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0);"; + 2, x:0, y:1; + "# use nalgebra::Scale3;\nlet t = Scale3::new(1.0, 2.0, 3.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0);"; + 3, x:0, y:1, z:2; + "# use nalgebra::Scale4;\nlet t = Scale4::new(1.0, 2.0, 3.0, 4.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0);"; + 4, x:0, y:1, z:2, w:3; + "# use nalgebra::Scale5;\nlet t = Scale5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0);"; + 5, x:0, y:1, z:2, w:3, a:4; + "# use nalgebra::Scale6;\nlet t = Scale6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0 && t.vector.b == 6.0);"; + 6, x:0, y:1, z:2, w:3, a:4, b:5; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_conversion.rs new file mode 100644 index 000000000..2055abd24 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_conversion.rs @@ -0,0 +1,231 @@ +use num::{One, Zero}; + +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::PrimitiveSimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix, OVector, SVector, Scalar}; + +use crate::geometry::{Scale, SuperTCategoryOf, TAffine, Transform}; +use crate::Point; + +/* + * This file provides the following conversions: + * ============================================= + * + * Scale -> Scale + * Scale -> Transform + * Scale -> Matrix (homogeneous) + */ + +impl SubsetOf> for Scale +where + T1: Scalar, + T2: Scalar + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Scale { + Scale::from(self.vector.to_superset()) + } + + #[inline] + fn is_in_subset(rot: &Scale) -> bool { + crate::is_convertible::<_, SVector>(&rot.vector) + } + + #[inline] + fn from_superset_unchecked(rot: &Scale) -> Self { + Scale { + vector: rot.vector.to_subset_unchecked(), + } + } +} + +impl SubsetOf> for Scale +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>, U1>, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> for Scale +where + T1: RealField, + T2: RealField + SupersetOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>, U1>, +{ + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + if m[(D, D)] != T2::one() { + return false; + } + for i in 0..D + 1 { + for j in 0..D + 1 { + if i != j && m[(i, j)] != T2::zero() { + return false; + } + } + } + true + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + let v = m.fixed_view::(0, 0).diagonal(); + Self { + vector: crate::convert_unchecked(v), + } + } +} + +impl From> + for OMatrix, U1>, DimNameSum, U1>> +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>, U1> + + Allocator>, +{ + #[inline] + fn from(t: Scale) -> Self { + t.to_homogeneous() + } +} + +impl From>> for Scale { + #[inline] + fn from(vector: OVector>) -> Self { + Scale { vector } + } +} + +impl From<[T; D]> for Scale { + #[inline] + fn from(coords: [T; D]) -> Self { + Scale { + vector: coords.into(), + } + } +} + +impl From> for Scale { + #[inline] + fn from(pt: Point) -> Self { + Scale { vector: pt.coords } + } +} + +impl From> for [T; D] { + #[inline] + fn from(t: Scale) -> Self { + t.vector.into() + } +} + +impl From<[Scale; 2]> for Scale +where + T: From<[::Element; 2]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Scale; 2]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + ])) + } +} + +impl From<[Scale; 4]> for Scale +where + T: From<[::Element; 4]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Scale; 4]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + ])) + } +} + +impl From<[Scale; 8]> for Scale +where + T: From<[::Element; 8]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Scale; 8]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + ])) + } +} + +impl From<[Scale; 16]> + for Scale +where + T: From<[::Element; 16]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Scale; 16]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + arr[8].vector.clone(), + arr[9].vector.clone(), + arr[10].vector.clone(), + arr[11].vector.clone(), + arr[12].vector.clone(), + arr[13].vector.clone(), + arr[14].vector.clone(), + arr[15].vector.clone(), + ])) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_coordinates.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_coordinates.rs new file mode 100644 index 000000000..441fed952 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_coordinates.rs @@ -0,0 +1,39 @@ +use std::ops::{Deref, DerefMut}; + +use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; +use crate::base::Scalar; + +use crate::geometry::Scale; + +/* + * + * Give coordinates to Scale{1 .. 6} + * + */ + +macro_rules! deref_impl( + ($D: expr, $Target: ident $(, $comps: ident)*) => { + impl Deref for Scale { + type Target = $Target; + + #[inline] + fn deref(&self) -> &Self::Target { + self.vector.deref() + } + } + + impl DerefMut for Scale { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + self.vector.deref_mut() + } + } + } +); + +deref_impl!(1, X, x); +deref_impl!(2, XY, x, y); +deref_impl!(3, XYZ, x, y, z); +deref_impl!(4, XYZW, x, y, z, w); +deref_impl!(5, XYZWA, x, y, z, w, a); +deref_impl!(6, XYZWAB, x, y, z, w, a, b); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_ops.rs new file mode 100644 index 000000000..0455094ed --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_ops.rs @@ -0,0 +1,125 @@ +use std::ops::{Mul, MulAssign}; + +use simba::scalar::ClosedMulAssign; + +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::U1; +use crate::base::{Const, SVector, Scalar}; + +use crate::geometry::{Point, Scale}; + +// Scale × Scale +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: &'b Scale, Output = Scale; + Scale::from(self.vector.component_mul(&right.vector)); + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: Scale, Output = Scale; + Scale::from(self.vector.component_mul(&right.vector)); + 'a); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: &'b Scale, Output = Scale; + Scale::from(self.vector.component_mul(&right.vector)); + 'b); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: Scale, Output = Scale; + Scale::from(self.vector.component_mul(&right.vector)); ); + +// Scale × scalar +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: T, Output = Scale; + Scale::from(&self.vector * right); + 'a); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: T, Output = Scale; + Scale::from(self.vector * right); ); + +// Scale × Point +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: &'b Point, Output = Point; + Point::from(self.vector.component_mul(&right.coords)); + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: Point, Output = Point; + Point::from(self.vector.component_mul(&right.coords)); + 'a); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: &'b Point, Output = Point; + Point::from(self.vector.component_mul(&right.coords)); + 'b); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: Point, Output = Point; + Point::from(self.vector.component_mul(&right.coords)); ); + +// Scale * Vector +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: &'b SVector, Output = SVector; + self.vector.component_mul(right); + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Scale, right: SVector, Output = SVector; + self.vector.component_mul(&right); + 'a); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: &'b SVector, Output = SVector; + self.vector.component_mul(right); + 'b); + +add_sub_impl!(Mul, mul, ClosedMulAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Scale, right: SVector, Output = SVector; + self.vector.component_mul(&right); ); + +// Scale *= Scale +add_sub_assign_impl!(MulAssign, mul_assign, ClosedMulAssign; + const D; + self: Scale, right: &'b Scale; + self.vector.component_mul_assign(&right.vector); + 'b); + +add_sub_assign_impl!(MulAssign, mul_assign, ClosedMulAssign; + const D; + self: Scale, right: Scale; + self.vector.component_mul_assign(&right.vector); ); + +// Scale ×= scalar +add_sub_assign_impl!(MulAssign, mul_assign, ClosedMulAssign; + const D; + self: Scale, right: T; + self.vector *= right; ); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_simba.rs new file mode 100644 index 000000000..60eeb5eae --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/scale_simba.rs @@ -0,0 +1,45 @@ +use simba::simd::SimdValue; + +use crate::base::OVector; +use crate::Scalar; + +use crate::geometry::Scale; + +impl SimdValue for Scale +where + T::Element: Scalar, +{ + const LANES: usize = T::LANES; + type Element = Scale; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + OVector::splat(val.vector).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.vector.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.vector.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.vector.replace(i, val.vector) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.vector.replace_unchecked(i, val.vector) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.vector.select(cond, other.vector).into() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity.rs new file mode 100644 index 000000000..f5608ddc8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity.rs @@ -0,0 +1,417 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::Zero; +use std::fmt; +use std::hash; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use simba::scalar::{RealField, SubsetOf}; +use simba::simd::SimdRealField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; +use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "T: Scalar + Serialize, + R: Serialize, + DefaultAllocator: Allocator>, + Owned>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "T: Scalar + Deserialize<'de>, + R: Deserialize<'de>, + DefaultAllocator: Allocator>, + Owned>: Deserialize<'de>")) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Similarity", + bound(archive = " + T: rkyv::Archive, + R: rkyv::Archive, + Isometry: rkyv::Archive> + ") + ) +)] +pub struct Similarity { + /// The part of this similarity that does not include the scaling factor. + pub isometry: Isometry, + scaling: T, +} + +impl hash::Hash for Similarity +where + Owned>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.isometry.hash(state); + self.scaling.hash(state); + } +} + +impl Similarity +where + R: AbstractRotation, +{ + /// Creates a new similarity from its rotational and translational parts. + #[inline] + pub fn from_parts(translation: Translation, rotation: R, scaling: T) -> Self { + Self::from_isometry(Isometry::from_parts(translation, rotation), scaling) + } + + /// Creates a new similarity from its rotational and translational parts. + #[inline] + pub fn from_isometry(isometry: Isometry, scaling: T) -> Self { + assert!(!scaling.is_zero(), "The scaling factor must not be zero."); + + Self { isometry, scaling } + } + + /// The scaling factor of this similarity transformation. + #[inline] + pub fn set_scaling(&mut self, scaling: T) { + assert!( + !scaling.is_zero(), + "The similarity scaling factor must not be zero." + ); + + self.scaling = scaling; + } +} + +impl Similarity { + /// The scaling factor of this similarity transformation. + #[inline] + #[must_use] + pub fn scaling(&self) -> T { + self.scaling.clone() + } +} + +impl Similarity +where + T::Element: SimdRealField, + R: AbstractRotation, +{ + /// Creates a new similarity that applies only a scaling factor. + #[inline] + pub fn from_scaling(scaling: T) -> Self { + Self::from_isometry(Isometry::identity(), scaling) + } + + /// Inverts `self`. + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Self { + let mut res = self.clone(); + res.inverse_mut(); + res + } + + /// Inverts `self` in-place. + #[inline] + pub fn inverse_mut(&mut self) { + self.scaling = T::one() / self.scaling.clone(); + self.isometry.inverse_mut(); + self.isometry.translation.vector *= self.scaling.clone(); + } + + /// The similarity transformation that applies a scaling factor `scaling` before `self`. + #[inline] + #[must_use = "Did you mean to use prepend_scaling_mut()?"] + pub fn prepend_scaling(&self, scaling: T) -> Self { + assert!( + !scaling.is_zero(), + "The similarity scaling factor must not be zero." + ); + + Self::from_isometry(self.isometry.clone(), self.scaling.clone() * scaling) + } + + /// The similarity transformation that applies a scaling factor `scaling` after `self`. + #[inline] + #[must_use = "Did you mean to use append_scaling_mut()?"] + pub fn append_scaling(&self, scaling: T) -> Self { + assert!( + !scaling.is_zero(), + "The similarity scaling factor must not be zero." + ); + + Self::from_parts( + Translation::from(&self.isometry.translation.vector * scaling.clone()), + self.isometry.rotation.clone(), + self.scaling.clone() * scaling, + ) + } + + /// Sets `self` to the similarity transformation that applies a scaling factor `scaling` before `self`. + #[inline] + pub fn prepend_scaling_mut(&mut self, scaling: T) { + assert!( + !scaling.is_zero(), + "The similarity scaling factor must not be zero." + ); + + self.scaling *= scaling + } + + /// Sets `self` to the similarity transformation that applies a scaling factor `scaling` after `self`. + #[inline] + pub fn append_scaling_mut(&mut self, scaling: T) { + assert!( + !scaling.is_zero(), + "The similarity scaling factor must not be zero." + ); + + self.isometry.translation.vector *= scaling.clone(); + self.scaling *= scaling; + } + + /// Appends to `self` the given translation in-place. + #[inline] + pub fn append_translation_mut(&mut self, t: &Translation) { + self.isometry.append_translation_mut(t) + } + + /// Appends to `self` the given rotation in-place. + #[inline] + pub fn append_rotation_mut(&mut self, r: &R) { + self.isometry.append_rotation_mut(r) + } + + /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that + /// lets `p` invariant. + #[inline] + pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &Point) { + self.isometry.append_rotation_wrt_point_mut(r, p) + } + + /// Appends in-place to `self` a rotation centered at the point with coordinates + /// `self.translation`. + #[inline] + pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { + self.isometry.append_rotation_wrt_center_mut(r) + } + + /// Transform the given point by this similarity. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 3.0); + /// let transformed_point = sim.transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_point, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Transform the given vector by this similarity, ignoring the translational + /// component. + /// + /// This is the same as the multiplication `self * t`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 3.0); + /// let transformed_vector = sim.transform_vector(&Vector3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_vector, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } + + /// Transform the given point by the inverse of this similarity. This may + /// be cheaper than inverting the similarity and then transforming the + /// given point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 2.0); + /// let transformed_point = sim.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_point, Point3::new(-1.5, 1.5, 1.5), epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + self.isometry.inverse_transform_point(pt) / self.scaling() + } + + /// Transform the given vector by the inverse of this similarity, + /// ignoring the translational component. This may be cheaper than + /// inverting the similarity and then transforming the given vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 2.0); + /// let transformed_vector = sim.inverse_transform_vector(&Vector3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.5, 2.0), epsilon = 1.0e-5); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.isometry.inverse_transform_vector(v) / self.scaling() + } +} + +// NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation +// and makes it harder to use it, e.g., for Transform × Isometry implementation. +// This is OK since all constructors of the isometry enforce the Rotation bound already (and +// explicit struct construction is prevented by the private scaling factor). +impl Similarity { + /// Converts this similarity into its equivalent homogeneous transformation matrix. + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> + where + Const: DimNameAdd, + R: SubsetOf, U1>, DimNameSum, U1>>>, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + { + let mut res = self.isometry.to_homogeneous(); + + for e in res.fixed_view_mut::(0, 0).iter_mut() { + *e *= self.scaling.clone() + } + + res + } +} + +impl Eq for Similarity where + R: AbstractRotation + Eq +{ +} + +impl PartialEq for Similarity +where + R: AbstractRotation + PartialEq, +{ + #[inline] + fn eq(&self, right: &Self) -> bool { + self.isometry == right.isometry && self.scaling == right.scaling + } +} + +impl AbsDiffEq for Similarity +where + R: AbstractRotation + AbsDiffEq, + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.isometry.abs_diff_eq(&other.isometry, epsilon.clone()) + && self.scaling.abs_diff_eq(&other.scaling, epsilon) + } +} + +impl RelativeEq for Similarity +where + R: AbstractRotation + RelativeEq, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.isometry + .relative_eq(&other.isometry, epsilon.clone(), max_relative.clone()) + && self + .scaling + .relative_eq(&other.scaling, epsilon, max_relative) + } +} + +impl UlpsEq for Similarity +where + R: AbstractRotation + UlpsEq, + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.isometry + .ulps_eq(&other.isometry, epsilon.clone(), max_ulps) + && self.scaling.ulps_eq(&other.scaling, epsilon, max_ulps) + } +} + +/* + * + * Display + * + */ +impl fmt::Display for Similarity +where + T: RealField + fmt::Display, + R: AbstractRotation + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let precision = f.precision().unwrap_or(3); + + writeln!(f, "Similarity {{")?; + write!(f, "{:.*}", precision, self.isometry)?; + write!(f, "Scaling: {:.*}", precision, self.scaling)?; + writeln!(f, "}}") + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_alias.rs new file mode 100644 index 000000000..0d406f567 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_alias.rs @@ -0,0 +1,13 @@ +use crate::geometry::{Rotation2, Rotation3, Similarity, UnitComplex, UnitQuaternion}; + +/// A 2-dimensional similarity. +pub type Similarity2 = Similarity, 2>; + +/// A 3-dimensional similarity. +pub type Similarity3 = Similarity, 3>; + +/// A 2-dimensional similarity using a rotation matrix for its rotation part. +pub type SimilarityMatrix2 = Similarity, 2>; + +/// A 3-dimensional similarity using a rotation matrix for its rotation part. +pub type SimilarityMatrix3 = Similarity, 3>; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_construction.rs new file mode 100644 index 000000000..ca1f373d1 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_construction.rs @@ -0,0 +1,401 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::One; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use simba::scalar::SupersetOf; +use simba::simd::SimdRealField; + +use crate::base::{Vector2, Vector3}; + +use crate::{ + AbstractRotation, Isometry, Point, Point3, Rotation2, Rotation3, Scalar, Similarity, + Translation, UnitComplex, UnitQuaternion, +}; + +impl Default for Similarity +where + T::Element: SimdRealField, + R: AbstractRotation, +{ + fn default() -> Self { + Self::identity() + } +} + +impl Similarity +where + T::Element: SimdRealField, + R: AbstractRotation, +{ + /// Creates a new identity similarity. + /// + /// # Example + /// ``` + /// # use nalgebra::{Similarity2, Point2, Similarity3, Point3}; + /// + /// let sim = Similarity2::identity(); + /// let pt = Point2::new(1.0, 2.0); + /// assert_eq!(sim * pt, pt); + /// + /// let sim = Similarity3::identity(); + /// let pt = Point3::new(1.0, 2.0, 3.0); + /// assert_eq!(sim * pt, pt); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::from_isometry(Isometry::identity(), T::one()) + } +} + +impl One for Similarity +where + T::Element: SimdRealField, + R: AbstractRotation, +{ + /// Creates a new identity similarity. + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + R: AbstractRotation, + Standard: Distribution + Distribution, +{ + /// Generate an arbitrary random variate for testing purposes. + #[inline] + fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Similarity { + let mut s = rng.gen(); + while relative_eq!(s, T::zero()) { + s = rng.gen() + } + + Similarity::from_isometry(rng.gen(), s) + } +} + +impl Similarity +where + T::Element: SimdRealField, + R: AbstractRotation, +{ + /// The similarity that applies the scaling factor `scaling`, followed by the rotation `r` with + /// its axis passing through the point `p`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity2, Point2, UnitComplex}; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let pt = Point2::new(3.0, 2.0); + /// let sim = Similarity2::rotation_wrt_point(rot, pt, 4.0); + /// + /// assert_relative_eq!(sim * Point2::new(1.0, 2.0), Point2::new(-3.0, 3.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn rotation_wrt_point(r: R, p: Point, scaling: T) -> Self { + let shift = r.transform_vector(&-&p.coords); + Self::from_parts(Translation::from(shift + p.coords), r, scaling) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Similarity +where + T: crate::RealField + Arbitrary + Send, + T::Element: crate::RealField, + R: AbstractRotation + Arbitrary + Send, + Owned>: Send, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + let mut s: T = Arbitrary::arbitrary(rng); + while s.is_zero() { + s = Arbitrary::arbitrary(rng) + } + + Self::from_isometry(Arbitrary::arbitrary(rng), s) + } +} + +/* + * + * Constructors for various static dimensions. + * + */ + +// 2D similarity. +impl Similarity, 2> +where + T::Element: SimdRealField, +{ + /// Creates a new similarity from a translation, a rotation, and an uniform scaling factor. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{SimilarityMatrix2, Vector2, Point2}; + /// let sim = SimilarityMatrix2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0); + /// + /// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn new(translation: Vector2, angle: T, scaling: T) -> Self { + Self::from_parts( + Translation::from(translation), + Rotation2::new(angle), + scaling, + ) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::SimilarityMatrix2; + /// let sim = SimilarityMatrix2::::identity(); + /// let sim2 = sim.cast::(); + /// assert_eq!(sim2, SimilarityMatrix2::::identity()); + /// ``` + pub fn cast(self) -> Similarity, 2> + where + Similarity, 2>: SupersetOf, + { + crate::convert(self) + } +} + +impl Similarity, 2> +where + T::Element: SimdRealField, +{ + /// Creates a new similarity from a translation and a rotation angle. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity2, Vector2, Point2}; + /// let sim = Similarity2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2, 3.0); + /// + /// assert_relative_eq!(sim * Point2::new(2.0, 4.0), Point2::new(-11.0, 8.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn new(translation: Vector2, angle: T, scaling: T) -> Self { + Self::from_parts( + Translation::from(translation), + UnitComplex::new(angle), + scaling, + ) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Similarity2; + /// let sim = Similarity2::::identity(); + /// let sim2 = sim.cast::(); + /// assert_eq!(sim2, Similarity2::::identity()); + /// ``` + pub fn cast(self) -> Similarity, 2> + where + Similarity, 2>: SupersetOf, + { + crate::convert(self) + } +} + +// 3D rotation. +macro_rules! similarity_construction_impl( + ($Rot: ident) => { + impl Similarity, 3> + where T::Element: SimdRealField { + /// Creates a new similarity from a translation, rotation axis-angle, and scaling + /// factor. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// // Point and vector being transformed in the tests. + /// let pt = Point3::new(4.0, 5.0, 6.0); + /// let vec = Vector3::new(4.0, 5.0, 6.0); + /// + /// // Similarity with its rotation part represented as a UnitQuaternion + /// let sim = Similarity3::new(translation, axisangle, 3.0); + /// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5); + /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5); + /// + /// // Similarity with its rotation part represented as a Rotation3 (a 3x3 rotation matrix). + /// let sim = SimilarityMatrix3::new(translation, axisangle, 3.0); + /// assert_relative_eq!(sim * pt, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5); + /// assert_relative_eq!(sim * vec, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5); + /// ``` + #[inline] + pub fn new(translation: Vector3, axisangle: Vector3, scaling: T) -> Self + { + Self::from_isometry(Isometry::<_, $Rot, 3>::new(translation, axisangle), scaling) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Similarity3; + /// let sim = Similarity3::::identity(); + /// let sim2 = sim.cast::(); + /// assert_eq!(sim2, Similarity3::::identity()); + /// ``` + pub fn cast(self) -> Similarity, 3> + where + Similarity, 3>: SupersetOf, + { + crate::convert(self) + } + + /// Creates an similarity that corresponds to a scaling factor and a local frame of + /// an observer standing at the point `eye` and looking toward `target`. + /// + /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the + /// `eye`. + /// + /// # Arguments + /// * eye - The observer position. + /// * target - The target position. + /// * up - Vertical direction. The only requirement of this parameter is to not be collinear + /// to `eye - at`. Non-collinearity is not checked. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; + /// let eye = Point3::new(1.0, 2.0, 3.0); + /// let target = Point3::new(2.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// // Similarity with its rotation part represented as a UnitQuaternion + /// let sim = Similarity3::face_towards(&eye, &target, &up, 3.0); + /// assert_eq!(sim * Point3::origin(), eye); + /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6); + /// + /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix). + /// let sim = SimilarityMatrix3::face_towards(&eye, &target, &up, 3.0); + /// assert_eq!(sim * Point3::origin(), eye); + /// assert_relative_eq!(sim * Vector3::z(), Vector3::x() * 3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn face_towards(eye: &Point3, + target: &Point3, + up: &Vector3, + scaling: T) + -> Self { + Self::from_isometry(Isometry::<_, $Rot, 3>::face_towards(eye, target, up), scaling) + } + + /// Deprecated: Use [`SimilarityMatrix3::face_towards`](Self::face_towards) instead. + #[deprecated(note="renamed to `face_towards`")] + pub fn new_observer_frames(eye: &Point3, + target: &Point3, + up: &Vector3, + scaling: T) + -> Self { + Self::face_towards(eye, target, up, scaling) + } + + /// Builds a right-handed look-at view matrix including scaling factor. + /// + /// This conforms to the common notion of right handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; + /// let eye = Point3::new(1.0, 2.0, 3.0); + /// let target = Point3::new(2.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// // Similarity with its rotation part represented as a UnitQuaternion + /// let iso = Similarity3::look_at_rh(&eye, &target, &up, 3.0); + /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6); + /// + /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix). + /// let iso = SimilarityMatrix3::look_at_rh(&eye, &target, &up, 3.0); + /// assert_relative_eq!(iso * Vector3::x(), -Vector3::z() * 3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn look_at_rh(eye: &Point3, + target: &Point3, + up: &Vector3, + scaling: T) + -> Self { + Self::from_isometry(Isometry::<_, $Rot, 3>::look_at_rh(eye, target, up), scaling) + } + + /// Builds a left-handed look-at view matrix including a scaling factor. + /// + /// This conforms to the common notion of left handed look-at matrix from the computer + /// graphics community. + /// + /// # Arguments + /// * eye - The eye position. + /// * target - The target position. + /// * up - A vector approximately aligned with required the vertical axis. The only + /// requirement of this parameter is to not be collinear to `target - eye`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, SimilarityMatrix3, Point3, Vector3}; + /// let eye = Point3::new(1.0, 2.0, 3.0); + /// let target = Point3::new(2.0, 2.0, 3.0); + /// let up = Vector3::y(); + /// + /// // Similarity with its rotation part represented as a UnitQuaternion + /// let sim = Similarity3::look_at_lh(&eye, &target, &up, 3.0); + /// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6); + /// + /// // Similarity with its rotation part represented as Rotation3 (a 3x3 rotation matrix). + /// let sim = SimilarityMatrix3::look_at_lh(&eye, &target, &up, 3.0); + /// assert_relative_eq!(sim * Vector3::x(), Vector3::z() * 3.0, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn look_at_lh(eye: &Point3, + target: &Point3, + up: &Vector3, + scaling: T) + -> Self { + Self::from_isometry(Isometry::<_, $Rot, 3>::look_at_lh(eye, target, up), scaling) + } + } + } +); + +similarity_construction_impl!(Rotation3); +similarity_construction_impl!(UnitQuaternion); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_conversion.rs new file mode 100644 index 000000000..137a890f9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_conversion.rs @@ -0,0 +1,315 @@ +use num::Zero; + +use crate::ArrayStorage; +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField, SimdValue}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimMin, DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix, Scalar}; + +use crate::geometry::{ + AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, +}; + +/* + * This file provides the following conversions: + * ============================================= + * + * Similarity -> Similarity + * Similarity -> Transform + * Similarity -> Matrix (homogeneous) + */ + +impl SubsetOf> for Similarity +where + T1: RealField + SubsetOf, + T2: RealField + SupersetOf, + R1: AbstractRotation + SubsetOf, + R2: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_isometry(self.isometry.to_superset(), self.scaling().to_superset()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + crate::is_convertible::<_, Isometry>(&sim.isometry) + && crate::is_convertible::<_, T1>(&sim.scaling()) + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + Similarity::from_isometry( + sim.isometry.to_subset_unchecked(), + sim.scaling().to_subset_unchecked(), + ) + } +} + +impl SubsetOf> for Similarity +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, + R: AbstractRotation + + SubsetOf, U1>, DimNameSum, U1>>> + + SubsetOf, U1>, DimNameSum, U1>>>, + Const: DimNameAdd + DimMin, Output = Const>, // needed by .determinant() + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + // + Allocator + // + Allocator + // + Allocator + // + Allocator + // + Allocator, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> + for Similarity +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + + SubsetOf, U1>, DimNameSum, U1>>> + + SubsetOf, U1>, DimNameSum, U1>>>, + Const: DimNameAdd + DimMin, Output = Const>, // needed by .determinant() + DefaultAllocator: Allocator, Const<1>, Buffer = ArrayStorage> + + Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + let mut rot = m.fixed_view::(0, 0).clone_owned(); + if rot + .fixed_columns_mut::<1>(0) + .try_normalize_mut(T2::zero()) + .is_some() + && rot + .fixed_columns_mut::<1>(1) + .try_normalize_mut(T2::zero()) + .is_some() + && rot + .fixed_columns_mut::<1>(2) + .try_normalize_mut(T2::zero()) + .is_some() + { + // TODO: could we avoid explicit the computation of the determinant? + // (its sign is needed to see if the scaling factor is negative). + if rot.determinant() < T2::zero() { + rot.fixed_columns_mut::<1>(0).neg_mut(); + rot.fixed_columns_mut::<1>(1).neg_mut(); + rot.fixed_columns_mut::<1>(2).neg_mut(); + } + + let bottom = m.fixed_view::<1, D>(D, 0); + // Scalar types agree. + m.iter().all(|e| SupersetOf::::is_in_subset(e)) && + // The normalized block part is a rotation. + // rot.is_special_orthogonal(T2::default_epsilon().sqrt()) && + // The bottom row is (0, 0, ..., 1) + bottom.iter().all(|e| e.is_zero()) && m[(D, D)] == T2::one() + } else { + false + } + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + let mut mm = m.clone_owned(); + let na = mm.fixed_view_mut::(0, 0).normalize_mut(); + let nb = mm.fixed_view_mut::(0, 1).normalize_mut(); + let nc = mm.fixed_view_mut::(0, 2).normalize_mut(); + + let mut scale = (na + nb + nc) / crate::convert(3.0); // We take the mean, for robustness. + + // TODO: could we avoid the explicit computation of the determinant? + // (its sign is needed to see if the scaling factor is negative). + if mm.fixed_view::(0, 0).determinant() < T2::zero() { + mm.fixed_view_mut::(0, 0).neg_mut(); + mm.fixed_view_mut::(0, 1).neg_mut(); + mm.fixed_view_mut::(0, 2).neg_mut(); + scale = -scale; + } + + let t = m.fixed_view::(0, D).into_owned(); + let t = Translation { + vector: crate::convert_unchecked(t), + }; + + Self::from_parts( + t, + crate::convert_unchecked(mm), + crate::convert_unchecked(scale), + ) + } +} + +impl From> + for OMatrix, U1>, DimNameSum, U1>> +where + Const: DimNameAdd, + R: SubsetOf, U1>, DimNameSum, U1>>>, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, // + Allocator +{ + #[inline] + fn from(sim: Similarity) -> Self { + sim.to_homogeneous() + } +} + +impl + From<[Similarity; 2]> for Similarity +where + T: From<[::Element; 2]>, + R: SimdValue + AbstractRotation + From<[::Element; 2]>, + R::Element: AbstractRotation, + T::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, +{ + #[inline] + fn from(arr: [Similarity; 2]) -> Self { + let iso = Isometry::from([arr[0].isometry, arr[1].isometry]); + let scale = T::from([arr[0].scaling(), arr[1].scaling()]); + + Self::from_isometry(iso, scale) + } +} + +impl + From<[Similarity; 4]> for Similarity +where + T: From<[::Element; 4]>, + R: SimdValue + AbstractRotation + From<[::Element; 4]>, + R::Element: AbstractRotation, + T::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, +{ + #[inline] + fn from(arr: [Similarity; 4]) -> Self { + let iso = Isometry::from([ + arr[0].isometry, + arr[1].isometry, + arr[2].isometry, + arr[3].isometry, + ]); + let scale = T::from([ + arr[0].scaling(), + arr[1].scaling(), + arr[2].scaling(), + arr[3].scaling(), + ]); + + Self::from_isometry(iso, scale) + } +} + +impl + From<[Similarity; 8]> for Similarity +where + T: From<[::Element; 8]>, + R: SimdValue + AbstractRotation + From<[::Element; 8]>, + R::Element: AbstractRotation, + T::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, +{ + #[inline] + fn from(arr: [Similarity; 8]) -> Self { + let iso = Isometry::from([ + arr[0].isometry, + arr[1].isometry, + arr[2].isometry, + arr[3].isometry, + arr[4].isometry, + arr[5].isometry, + arr[6].isometry, + arr[7].isometry, + ]); + let scale = T::from([ + arr[0].scaling(), + arr[1].scaling(), + arr[2].scaling(), + arr[3].scaling(), + arr[4].scaling(), + arr[5].scaling(), + arr[6].scaling(), + arr[7].scaling(), + ]); + + Self::from_isometry(iso, scale) + } +} + +impl + From<[Similarity; 16]> for Similarity +where + T: From<[::Element; 16]>, + R: SimdValue + AbstractRotation + From<[::Element; 16]>, + R::Element: AbstractRotation, + T::Element: Scalar + Zero + Copy, + R::Element: Scalar + Zero + Copy, +{ + #[inline] + fn from(arr: [Similarity; 16]) -> Self { + let iso = Isometry::from([ + arr[0].isometry, + arr[1].isometry, + arr[2].isometry, + arr[3].isometry, + arr[4].isometry, + arr[5].isometry, + arr[6].isometry, + arr[7].isometry, + arr[8].isometry, + arr[9].isometry, + arr[10].isometry, + arr[11].isometry, + arr[12].isometry, + arr[13].isometry, + arr[14].isometry, + arr[15].isometry, + ]); + let scale = T::from([ + arr[0].scaling(), + arr[1].scaling(), + arr[2].scaling(), + arr[3].scaling(), + arr[4].scaling(), + arr[5].scaling(), + arr[6].scaling(), + arr[7].scaling(), + arr[8].scaling(), + arr[9].scaling(), + arr[10].scaling(), + arr[11].scaling(), + arr[12].scaling(), + arr[13].scaling(), + arr[14].scaling(), + arr[15].scaling(), + ]); + + Self::from_isometry(iso, scale) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_ops.rs new file mode 100644 index 000000000..d2926a758 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_ops.rs @@ -0,0 +1,602 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +use num::{One, Zero}; +use std::ops::{Div, DivAssign, Mul, MulAssign}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; +use simba::simd::SimdRealField; + +use crate::base::{SVector, Scalar}; + +use crate::geometry::{ + AbstractRotation, Isometry, Point, Rotation, Similarity, Translation, UnitComplex, + UnitQuaternion, +}; + +// TODO: there are several cloning of rotations that we could probably get rid of (but we didn't +// yet because that would require to add a bound like `where for<'a, 'b> &'a R: Mul<&'b R, Output = R>` +// which is quite ugly. + +/* + * + * In this file, we provide: + * ========================= + * + * + * (Operators) + * + * Similarity × Similarity + * Similarity × R + * Similarity × Isometry + * + * Isometry × Similarity + * Isometry ÷ Similarity + * + * + * Similarity ÷ Similarity + * Similarity ÷ R + * Similarity ÷ Isometry + * + * Similarity × Point + * Similarity × Vector + * + * + * Similarity × Translation + * Translation × Similarity + * + * NOTE: The following are provided explicitly because we can't have R × Similarity. + * Rotation × Similarity + * UnitQuaternion × Similarity + * + * Rotation ÷ Similarity + * UnitQuaternion ÷ Similarity + * + * (Assignment Operators) + * + * Similarity ×= Translation + * + * Similarity ×= Similarity + * Similarity ×= Isometry + * Similarity ×= R + * + * Similarity ÷= Similarity + * Similarity ÷= Isometry + * Similarity ÷= R + * + */ + +// XXX: code duplication: those macros are the same as for the isometry. +macro_rules! similarity_binop_impl( + ($Op: ident, $op: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField, R, const D: usize> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField, + R: AbstractRotation { + type Output = $Output; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +macro_rules! similarity_binop_impl_all( + ($Op: ident, $op: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + [val val] => $action_val_val: expr; + [ref val] => $action_ref_val: expr; + [val ref] => $action_val_ref: expr; + [ref ref] => $action_ref_ref: expr;) => { + similarity_binop_impl!( + $Op, $op; + $lhs: $Lhs, $rhs: $Rhs, Output = $Output; + $action_val_val; ); + + similarity_binop_impl!( + $Op, $op; + $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Output; + $action_ref_val; 'a); + + similarity_binop_impl!( + $Op, $op; + $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_val_ref; 'b); + + similarity_binop_impl!( + $Op, $op; + $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_ref_ref; 'a, 'b); + } +); + +macro_rules! similarity_binop_assign_impl_all( + ($OpAssign: ident, $op_assign: ident; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty; + [val] => $action_val: expr; + [ref] => $action_ref: expr;) => { + impl $OpAssign<$Rhs> for $Lhs + where T::Element: SimdRealField, + R: AbstractRotation{ + #[inline] + fn $op_assign(&mut $lhs, $rhs: $Rhs) { + $action_val + } + } + + impl<'b, T: SimdRealField, R, const D: usize> $OpAssign<&'b $Rhs> for $Lhs + where T::Element: SimdRealField, + R: AbstractRotation { + #[inline] + fn $op_assign(&mut $lhs, $rhs: &'b $Rhs) { + $action_ref + } + } + } +); + +// Similarity × Similarity +// Similarity ÷ Similarity +similarity_binop_impl_all!( + Mul, mul; + self: Similarity, rhs: Similarity, Output = Similarity; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let mut res = self * &rhs.isometry; + res.prepend_scaling_mut(rhs.scaling()); + res + }; +); + +similarity_binop_impl_all!( + Div, div; + self: Similarity, rhs: Similarity, Output = Similarity; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// Similarity ×= Translation +similarity_binop_assign_impl_all!( + MulAssign, mul_assign; + self: Similarity, rhs: Translation; + [val] => *self *= &rhs; + [ref] => { + let shift = self.isometry.rotation.transform_vector(&rhs.vector) * self.scaling(); + self.isometry.translation.vector += shift; + }; +); + +// Similarity ×= Similarity +// Similarity ÷= Similarity +similarity_binop_assign_impl_all!( + MulAssign, mul_assign; + self: Similarity, rhs: Similarity; + [val] => *self *= &rhs; + [ref] => { + *self *= &rhs.isometry; + self.prepend_scaling_mut(rhs.scaling()); + }; +); + +similarity_binop_assign_impl_all!( + DivAssign, div_assign; + self: Similarity, rhs: Similarity; + [val] => *self /= &rhs; + // TODO: don't invert explicitly. + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Similarity ×= Isometry +// Similarity ÷= Isometry +similarity_binop_assign_impl_all!( + MulAssign, mul_assign; + self: Similarity, rhs: Isometry; + [val] => *self *= &rhs; + [ref] => { + let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); + self.isometry.translation.vector += shift; + self.isometry.rotation *= rhs.rotation.clone(); + }; +); + +similarity_binop_assign_impl_all!( + DivAssign, div_assign; + self: Similarity, rhs: Isometry; + [val] => *self /= &rhs; + // TODO: don't invert explicitly. + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Similarity ×= R +// Similarity ÷= R +md_assign_impl_all!( + MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField; + (Const, U1), (Const, Const) + const D; for; where; + self: Similarity, D>, rhs: Rotation; + [val] => self.isometry.rotation *= rhs; + [ref] => self.isometry.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField; + (Const, U1), (Const, Const) + const D; for; where; + self: Similarity, D>, rhs: Rotation; + // TODO: don't invert explicitly? + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +md_assign_impl_all!( + MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField; + (U3, U3), (U3, U3) + const; for; where; + self: Similarity, 3>, rhs: UnitQuaternion; + [val] => self.isometry.rotation *= rhs; + [ref] => self.isometry.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField; + (U3, U3), (U3, U3) + const; for; where; + self: Similarity, 3>, rhs: UnitQuaternion; + // TODO: don't invert explicitly? + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +md_assign_impl_all!( + MulAssign, mul_assign where T: SimdRealField for T::Element: SimdRealField; + (U2, U2), (U2, U2) + const; for; where; + self: Similarity, 2>, rhs: UnitComplex; + [val] => self.isometry.rotation *= rhs; + [ref] => self.isometry.rotation *= rhs.clone(); +); + +md_assign_impl_all!( + DivAssign, div_assign where T: SimdRealField for T::Element: SimdRealField; + (U2, U2), (U2, U2) + const; for; where; + self: Similarity, 2>, rhs: UnitComplex; + // TODO: don't invert explicitly? + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Similarity × Isometry +// Similarity ÷ Isometry +similarity_binop_impl_all!( + Mul, mul; + self: Similarity, rhs: Isometry, Output = Similarity; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let shift = self.isometry.rotation.transform_vector(&rhs.translation.vector) * self.scaling(); + Similarity::from_parts( + #[allow(clippy::suspicious_arithmetic_impl)] + Translation::from(&self.isometry.translation.vector + shift), + self.isometry.rotation.clone() * rhs.rotation.clone(), + self.scaling()) + }; +); + +similarity_binop_impl_all!( + Div, div; + self: Similarity, rhs: Isometry, Output = Similarity; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// Isometry × Similarity +// Isometry ÷ Similarity +similarity_binop_impl_all!( + Mul, mul; + self: Isometry, rhs: Similarity, Output = Similarity; + [val val] => { + let scaling = rhs.scaling(); + Similarity::from_isometry(self * rhs.isometry, scaling) + }; + [ref val] => { + let scaling = rhs.scaling(); + Similarity::from_isometry(self * rhs.isometry, scaling) + }; + [val ref] => { + let scaling = rhs.scaling(); + Similarity::from_isometry(self * &rhs.isometry, scaling) + }; + [ref ref] => { + let scaling = rhs.scaling(); + Similarity::from_isometry(self * &rhs.isometry, scaling) + }; +); + +similarity_binop_impl_all!( + Div, div; + self: Isometry, rhs: Similarity, Output = Similarity; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// Similarity × Point +similarity_binop_impl_all!( + Mul, mul; + self: Similarity, right: Point, Output = Point; + [val val] => { + let scaling = self.scaling(); + self.isometry.translation * (self.isometry.rotation.transform_point(&right) * scaling) + }; + [ref val] => &self.isometry.translation * (self.isometry.rotation.transform_point(&right) * self.scaling()); + [val ref] => { + let scaling = self.scaling(); + self.isometry.translation * (self.isometry.rotation.transform_point(right) * scaling) + }; + [ref ref] => &self.isometry.translation * (self.isometry.rotation.transform_point(right) * self.scaling()); +); + +// Similarity × Vector +similarity_binop_impl_all!( + Mul, mul; + self: Similarity, right: SVector, Output = SVector; + [val val] => self.isometry.rotation.transform_vector(&right) * self.scaling(); + [ref val] => self.isometry.rotation.transform_vector(&right) * self.scaling(); + [val ref] => self.isometry.rotation.transform_vector(right) * self.scaling(); + [ref ref] => self.isometry.rotation.transform_vector(right) * self.scaling(); +); + +// Similarity × Translation +similarity_binop_impl_all!( + Mul, mul; + self: Similarity, right: Translation, Output = Similarity; + [val val] => &self * &right; + [ref val] => self * &right; + [val ref] => &self * right; + [ref ref] => { + let shift = self.isometry.rotation.transform_vector(&right.vector) * self.scaling(); + Similarity::from_parts( + #[allow(clippy::suspicious_arithmetic_impl)] + Translation::from(&self.isometry.translation.vector + shift), + self.isometry.rotation.clone(), + self.scaling()) + }; +); + +// Translation × Similarity +similarity_binop_impl_all!( + Mul, mul; + self: Translation, right: Similarity, Output = Similarity; + [val val] => { + let scaling = right.scaling(); + Similarity::from_isometry(self * right.isometry, scaling) + }; + [ref val] => { + let scaling = right.scaling(); + Similarity::from_isometry(self * right.isometry, scaling) + }; + [val ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); + [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); +); + +macro_rules! similarity_from_composition_impl( + ($Op: ident, $op: ident; + $($Dims: ident),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField $(, const $Dims: usize)*> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField { + type Output = $Output; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +macro_rules! similarity_from_composition_impl_all( + ($Op: ident, $op: ident; + $($Dims: ident),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Output: ty; + [val val] => $action_val_val: expr; + [ref val] => $action_ref_val: expr; + [val ref] => $action_val_ref: expr; + [ref ref] => $action_ref_ref: expr;) => { + + similarity_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: $Lhs, $rhs: $Rhs, Output = $Output; + $action_val_val; ); + + similarity_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Output; + $action_ref_val; 'a); + + similarity_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_val_ref; 'b); + + similarity_from_composition_impl!( + $Op, $op; + $($Dims),*; + $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Output; + $action_ref_ref; 'a, 'b); + } +); + +// Similarity × Rotation +similarity_from_composition_impl_all!( + Mul, mul; + D; + self: Similarity, D>, rhs: Rotation, + Output = Similarity, D>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +); + +// Rotation × Similarity +similarity_from_composition_impl_all!( + Mul, mul; + D; + self: Rotation, right: Similarity, D>, + Output = Similarity, D>; + [val val] => &self * &right; + [ref val] => self * &right; + [val ref] => &self * right; + [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); +); + +// Similarity ÷ Rotation +similarity_from_composition_impl_all!( + Div, div; + D; + self: Similarity, D>, rhs: Rotation, + Output = Similarity, D>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +); + +// Rotation ÷ Similarity +similarity_from_composition_impl_all!( + Div, div; + D; + self: Rotation, right: Similarity, D>, + Output = Similarity, D>; + // TODO: don't call inverse explicitly? + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; +); + +// Similarity × UnitQuaternion +similarity_from_composition_impl_all!( + Mul, mul; + ; + self: Similarity, 3>, rhs: UnitQuaternion, + Output = Similarity, 3>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +); + +// UnitQuaternion × Similarity +similarity_from_composition_impl_all!( + Mul, mul; + ; + self: UnitQuaternion, right: Similarity, 3>, + Output = Similarity, 3>; + [val val] => &self * &right; + [ref val] => self * &right; + [val ref] => &self * right; + [ref ref] => Similarity::from_isometry(self * &right.isometry, right.scaling()); +); + +// Similarity ÷ UnitQuaternion +similarity_from_composition_impl_all!( + Div, div; + ; + self: Similarity, 3>, rhs: UnitQuaternion, + Output = Similarity, 3>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +); + +// UnitQuaternion ÷ Similarity +similarity_from_composition_impl_all!( + Div, div; + ; + self: UnitQuaternion, right: Similarity, 3>, + Output = Similarity, 3>; + // TODO: don't call inverse explicitly? + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * right.inverse() }; +); + +// Similarity × UnitComplex +similarity_from_composition_impl_all!( + Mul, mul; + ; + self: Similarity, 2>, rhs: UnitComplex, + Output = Similarity, 2>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry * rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry * rhs, self.scaling()); +); + +// Similarity ÷ UnitComplex +similarity_from_composition_impl_all!( + Div, div; + ; + self: Similarity, 2>, rhs: UnitComplex, + Output = Similarity, 2>; + [val val] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref val] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); + [val ref] => { + let scaling = self.scaling(); + Similarity::from_isometry(self.isometry / rhs, scaling) + }; + [ref ref] => Similarity::from_isometry(&self.isometry / rhs, self.scaling()); +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_simba.rs new file mode 100644 index 000000000..a7d7fef43 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/similarity_simba.rs @@ -0,0 +1,55 @@ +use simba::simd::{SimdRealField, SimdValue}; + +use crate::geometry::{AbstractRotation, Isometry, Similarity}; + +impl SimdValue for Similarity +where + T::Element: SimdRealField, + R: SimdValue + AbstractRotation, + R::Element: AbstractRotation, +{ + const LANES: usize = T::LANES; + type Element = Similarity; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + let scaling = T::splat(val.scaling()); + Similarity::from_isometry(Isometry::splat(val.isometry), scaling) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Similarity::from_isometry(self.isometry.extract(i), self.scaling().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Similarity::from_isometry( + self.isometry.extract_unchecked(i), + self.scaling().extract_unchecked(i), + ) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + let mut s = self.scaling(); + s.replace(i, val.scaling()); + self.set_scaling(s); + self.isometry.replace(i, val.isometry); + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + let mut s = self.scaling(); + s.replace_unchecked(i, val.scaling()); + self.set_scaling(s); + self.isometry.replace_unchecked(i, val.isometry); + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + let scaling = self.scaling().select(cond, other.scaling()); + Similarity::from_isometry(self.isometry.select(cond, other.isometry), scaling) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/swizzle.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/swizzle.rs new file mode 100644 index 000000000..eececaa82 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/swizzle.rs @@ -0,0 +1,66 @@ +use crate::base::{Const, Scalar, ToTypenum}; +use crate::geometry::{Point, Point2, Point3}; +use typenum::{self, Cmp, Greater}; + +macro_rules! impl_swizzle { + ($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => { + $( + $( + /// Builds a new point from components of `self`. + #[inline] + #[must_use] + pub fn $name(&self) -> $Result + where as ToTypenum>::Typenum: Cmp { + $Result::new($(self[$i].clone()),*) + } + )* + )* + } +} + +/// # Swizzling +impl Point +where + Const: ToTypenum, +{ + impl_swizzle!( + where U0: xx() -> Point2[0, 0], + xxx() -> Point3[0, 0, 0]; + + where U1: xy() -> Point2[0, 1], + yx() -> Point2[1, 0], + yy() -> Point2[1, 1], + xxy() -> Point3[0, 0, 1], + xyx() -> Point3[0, 1, 0], + xyy() -> Point3[0, 1, 1], + yxx() -> Point3[1, 0, 0], + yxy() -> Point3[1, 0, 1], + yyx() -> Point3[1, 1, 0], + yyy() -> Point3[1, 1, 1]; + + where U2: xz() -> Point2[0, 2], + yz() -> Point2[1, 2], + zx() -> Point2[2, 0], + zy() -> Point2[2, 1], + zz() -> Point2[2, 2], + xxz() -> Point3[0, 0, 2], + xyz() -> Point3[0, 1, 2], + xzx() -> Point3[0, 2, 0], + xzy() -> Point3[0, 2, 1], + xzz() -> Point3[0, 2, 2], + yxz() -> Point3[1, 0, 2], + yyz() -> Point3[1, 1, 2], + yzx() -> Point3[1, 2, 0], + yzy() -> Point3[1, 2, 1], + yzz() -> Point3[1, 2, 2], + zxx() -> Point3[2, 0, 0], + zxy() -> Point3[2, 0, 1], + zxz() -> Point3[2, 0, 2], + zyx() -> Point3[2, 1, 0], + zyy() -> Point3[2, 1, 1], + zyz() -> Point3[2, 1, 2], + zzx() -> Point3[2, 2, 0], + zzy() -> Point3[2, 2, 1], + zzz() -> Point3[2, 2, 2]; + ); +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform.rs new file mode 100644 index 000000000..ea1ff751d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform.rs @@ -0,0 +1,662 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use std::any::Any; +use std::fmt::{self, Debug}; +use std::hash; +use std::marker::PhantomData; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use simba::scalar::RealField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{Const, DefaultAllocator, DimName, OMatrix, SVector}; + +use crate::geometry::Point; + +/// Trait implemented by phantom types identifying the projective transformation type. +/// +/// NOTE: this trait is not intended to be implemented outside of the `nalgebra` crate. +pub trait TCategory: Any + Debug + Copy + PartialEq + Send { + /// Indicates whether a `Transform` with the category `Self` has a bottom-row different from + /// `0 0 .. 1`. + #[inline] + fn has_normalizer() -> bool { + true + } + + /// Checks that the given matrix is a valid homogeneous representation of an element of the + /// category `Self`. + fn check_homogeneous_invariants(mat: &OMatrix) -> bool + where + T::Epsilon: Clone, + DefaultAllocator: Allocator; +} + +/// Traits that gives the `Transform` category that is compatible with the result of the +/// multiplication of transformations with categories `Self` and `Other`. +pub trait TCategoryMul: TCategory { + /// The transform category that results from the multiplication of a `Transform` to a + /// `Transform`. This is usually equal to `Self` or `Other`, whichever is the most + /// general category. + type Representative: TCategory; +} + +/// Indicates that `Self` is a more general `Transform` category than `Other`. +pub trait SuperTCategoryOf: TCategory {} + +/// Indicates that `Self` is a more specific `Transform` category than `Other`. +/// +/// Automatically implemented based on `SuperTCategoryOf`. +pub trait SubTCategoryOf: TCategory {} +impl SubTCategoryOf for T1 +where + T1: TCategory, + T2: SuperTCategoryOf, +{ +} + +/// Tag representing the most general (not necessarily inversible) `Transform` type. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum TGeneral {} + +/// Tag representing the most general inversible `Transform` type. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum TProjective {} + +/// Tag representing an affine `Transform`. Its bottom-row is equal to `(0, 0 ... 0, 1)`. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum TAffine {} + +impl TCategory for TGeneral { + #[inline] + fn check_homogeneous_invariants(_: &OMatrix) -> bool + where + T::Epsilon: Clone, + DefaultAllocator: Allocator, + { + true + } +} + +impl TCategory for TProjective { + #[inline] + fn check_homogeneous_invariants(mat: &OMatrix) -> bool + where + T::Epsilon: Clone, + DefaultAllocator: Allocator, + { + mat.is_invertible() + } +} + +impl TCategory for TAffine { + #[inline] + fn has_normalizer() -> bool { + false + } + + #[inline] + fn check_homogeneous_invariants(mat: &OMatrix) -> bool + where + T::Epsilon: Clone, + DefaultAllocator: Allocator, + { + let last = D::dim() - 1; + mat.is_invertible() + && mat[(last, last)] == T::one() + && (0..last).all(|i| mat[(last, i)].is_zero()) + } +} + +macro_rules! category_mul_impl( + ($($a: ident * $b: ident => $c: ty);* $(;)*) => {$( + impl TCategoryMul<$a> for $b { + type Representative = $c; + } + )*} +); + +// We require stability upon multiplication. +impl TCategoryMul for T { + type Representative = T; +} + +category_mul_impl!( +// TGeneral * TGeneral => TGeneral; + TGeneral * TProjective => TGeneral; + TGeneral * TAffine => TGeneral; + + TProjective * TGeneral => TGeneral; +// TProjective * TProjective => TProjective; + TProjective * TAffine => TProjective; + + TAffine * TGeneral => TGeneral; + TAffine * TProjective => TProjective; +// TAffine * TAffine => TAffine; +); + +macro_rules! super_tcategory_impl( + ($($a: ident >= $b: ident);* $(;)*) => {$( + impl SuperTCategoryOf<$b> for $a { } + )*} +); + +impl SuperTCategoryOf for T {} + +super_tcategory_impl!( + TGeneral >= TProjective; + TGeneral >= TAffine; + TProjective >= TAffine; +); + +/// A transformation matrix in homogeneous coordinates. +/// +/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a +/// 3D transformation. +#[repr(C)] +pub struct Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + matrix: OMatrix, U1>, DimNameSum, U1>>, + _phantom: PhantomData, +} + +impl Debug for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.matrix.fmt(formatter) + } +} + +impl hash::Hash for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + Owned, U1>, DimNameSum, U1>>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.matrix.hash(state); + } +} + +impl Copy for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + Owned, U1>, DimNameSum, U1>>: Copy, +{ +} + +impl Clone for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn clone(&self) -> Self { + Transform::from_matrix_unchecked(self.matrix.clone()) + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Transform +where + T: RealField + bytemuck::Zeroable, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + OMatrix, U1>, DimNameSum, U1>>: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Transform +where + T: RealField + bytemuck::Pod, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + OMatrix, U1>, DimNameSum, U1>>: bytemuck::Pod, + Owned, U1>, DimNameSum, U1>>: Copy, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + Owned, U1>, DimNameSum, U1>>: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.matrix.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: RealField, C: TCategory, const D: usize> Deserialize<'a> for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + Owned, U1>, DimNameSum, U1>>: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = OMatrix::, U1>, DimNameSum, U1>>::deserialize( + deserializer, + )?; + + Ok(Transform::from_matrix_unchecked(matrix)) + } +} + +impl Eq for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ +} + +impl PartialEq for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn eq(&self, right: &Self) -> bool { + self.matrix == right.matrix + } +} + +impl Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + /// Creates a new transformation from the given homogeneous matrix. The transformation category + /// of `Self` is not checked to be verified by the given matrix. + #[inline] + pub fn from_matrix_unchecked( + matrix: OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + Transform { + matrix, + _phantom: PhantomData, + } + } + + /// Retrieves the underlying matrix. + /// + /// # Examples + /// ``` + /// # use nalgebra::{Matrix3, Transform2}; + /// + /// let m = Matrix3::new(1.0, 2.0, 0.0, + /// 3.0, 4.0, 0.0, + /// 0.0, 0.0, 1.0); + /// let t = Transform2::from_matrix_unchecked(m); + /// assert_eq!(t.into_inner(), m); + /// ``` + #[inline] + pub fn into_inner(self) -> OMatrix, U1>, DimNameSum, U1>> { + self.matrix + } + + /// Retrieves the underlying matrix. + /// Deprecated: Use [`Transform::into_inner`] instead. + #[deprecated(note = "use `.into_inner()` instead")] + #[inline] + pub fn unwrap(self) -> OMatrix, U1>, DimNameSum, U1>> { + self.matrix + } + + /// A reference to the underlying matrix. + /// + /// # Examples + /// ``` + /// # use nalgebra::{Matrix3, Transform2}; + /// + /// let m = Matrix3::new(1.0, 2.0, 0.0, + /// 3.0, 4.0, 0.0, + /// 0.0, 0.0, 1.0); + /// let t = Transform2::from_matrix_unchecked(m); + /// assert_eq!(*t.matrix(), m); + /// ``` + #[inline] + #[must_use] + pub fn matrix(&self) -> &OMatrix, U1>, DimNameSum, U1>> { + &self.matrix + } + + /// A mutable reference to the underlying matrix. + /// + /// It is `_unchecked` because direct modifications of this matrix may break invariants + /// identified by this transformation category. + /// + /// # Examples + /// ``` + /// # use nalgebra::{Matrix3, Transform2}; + /// + /// let m = Matrix3::new(1.0, 2.0, 0.0, + /// 3.0, 4.0, 0.0, + /// 0.0, 0.0, 1.0); + /// let mut t = Transform2::from_matrix_unchecked(m); + /// t.matrix_mut_unchecked().m12 = 42.0; + /// t.matrix_mut_unchecked().m23 = 90.0; + /// + /// + /// let expected = Matrix3::new(1.0, 42.0, 0.0, + /// 3.0, 4.0, 90.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(*t.matrix(), expected); + /// ``` + #[inline] + pub fn matrix_mut_unchecked( + &mut self, + ) -> &mut OMatrix, U1>, DimNameSum, U1>> { + &mut self.matrix + } + + /// Sets the category of this transform. + /// + /// This can be done only if the new category is more general than the current one, e.g., a + /// transform with category `TProjective` cannot be converted to a transform with category + /// `TAffine` because not all projective transformations are affine (the other way-round is + /// valid though). + #[inline] + pub fn set_category>(self) -> Transform { + Transform::from_matrix_unchecked(self.matrix) + } + + /// Clones this transform into one that owns its data. + #[inline] + #[deprecated( + note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release." + )] + pub fn clone_owned(&self) -> Transform { + Transform::from_matrix_unchecked(self.matrix.clone_owned()) + } + + /// Converts this transform into its equivalent homogeneous transformation matrix. + /// + /// # Examples + /// ``` + /// # use nalgebra::{Matrix3, Transform2}; + /// + /// let m = Matrix3::new(1.0, 2.0, 0.0, + /// 3.0, 4.0, 0.0, + /// 0.0, 0.0, 1.0); + /// let t = Transform2::from_matrix_unchecked(m); + /// assert_eq!(t.to_homogeneous(), m); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.matrix().clone_owned() + } + + /// Attempts to invert this transformation. You may use `.inverse` instead of this + /// transformation has a subcategory of `TProjective` (i.e. if it is a `Projective{2,3}` or `Affine{2,3}`). + /// + /// # Examples + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3, Transform2}; + /// + /// let m = Matrix3::new(2.0, 2.0, -0.3, + /// 3.0, 4.0, 0.1, + /// 0.0, 0.0, 1.0); + /// let t = Transform2::from_matrix_unchecked(m); + /// let inv_t = t.try_inverse().unwrap(); + /// assert_relative_eq!(t * inv_t, Transform2::identity()); + /// assert_relative_eq!(inv_t * t, Transform2::identity()); + /// + /// // Non-invertible case. + /// let m = Matrix3::new(0.0, 2.0, 1.0, + /// 3.0, 0.0, 5.0, + /// 0.0, 0.0, 0.0); + /// let t = Transform2::from_matrix_unchecked(m); + /// assert!(t.try_inverse().is_none()); + /// ``` + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn try_inverse(self) -> Option> { + self.matrix + .try_inverse() + .map(Transform::from_matrix_unchecked) + } + + /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral` + /// category (i.e., a `Transform{2,3}` may not be invertible). + /// + /// # Examples + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3, Projective2}; + /// + /// let m = Matrix3::new(2.0, 2.0, -0.3, + /// 3.0, 4.0, 0.1, + /// 0.0, 0.0, 1.0); + /// let proj = Projective2::from_matrix_unchecked(m); + /// let inv_t = proj.inverse(); + /// assert_relative_eq!(proj * inv_t, Projective2::identity()); + /// assert_relative_eq!(inv_t * proj, Projective2::identity()); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(self) -> Transform + where + C: SubTCategoryOf, + { + // TODO: specialize for TAffine? + Transform::from_matrix_unchecked(self.matrix.try_inverse().unwrap()) + } + + /// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this + /// transformation has a subcategory of `TProjective`. + /// + /// # Examples + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3, Transform2}; + /// + /// let m = Matrix3::new(2.0, 2.0, -0.3, + /// 3.0, 4.0, 0.1, + /// 0.0, 0.0, 1.0); + /// let t = Transform2::from_matrix_unchecked(m); + /// let mut inv_t = t; + /// assert!(inv_t.try_inverse_mut()); + /// assert_relative_eq!(t * inv_t, Transform2::identity()); + /// assert_relative_eq!(inv_t * t, Transform2::identity()); + /// + /// // Non-invertible case. + /// let m = Matrix3::new(0.0, 2.0, 1.0, + /// 3.0, 0.0, 5.0, + /// 0.0, 0.0, 0.0); + /// let mut t = Transform2::from_matrix_unchecked(m); + /// assert!(!t.try_inverse_mut()); + /// ``` + #[inline] + pub fn try_inverse_mut(&mut self) -> bool { + self.matrix.try_inverse_mut() + } + + /// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the + /// `TGeneral` category (it may not be invertible). + /// + /// # Examples + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Matrix3, Projective2}; + /// + /// let m = Matrix3::new(2.0, 2.0, -0.3, + /// 3.0, 4.0, 0.1, + /// 0.0, 0.0, 1.0); + /// let proj = Projective2::from_matrix_unchecked(m); + /// let mut inv_t = proj; + /// inv_t.inverse_mut(); + /// assert_relative_eq!(proj * inv_t, Projective2::identity()); + /// assert_relative_eq!(inv_t * proj, Projective2::identity()); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) + where + C: SubTCategoryOf, + { + let _ = self.matrix.try_inverse_mut(); + } +} + +impl Transform +where + T: RealField, + C: TCategory, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>>, // + Allocator + // + Allocator +{ + /// Transform the given point by this transformation. + /// + /// This is the same as the multiplication `self * pt`. + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Transform the given vector by this transformation, ignoring the + /// translational component of the transformation. + /// + /// This is the same as the multiplication `self * v`. + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &SVector) -> SVector { + self * v + } +} + +impl Transform +where + Const: DimNameAdd, + C: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>>, // + Allocator + // + Allocator +{ + /// Transform the given point by the inverse of this transformation. + /// This may be cheaper than inverting the transformation and transforming + /// the point. + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + self.clone().inverse() * pt + } + + /// Transform the given vector by the inverse of this transformation. + /// This may be cheaper than inverting the transformation and transforming + /// the vector. + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.clone().inverse() * v + } +} + +impl Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this + /// transformation category is not `TGeneral`. + #[inline] + pub fn matrix_mut( + &mut self, + ) -> &mut OMatrix, U1>, DimNameSum, U1>> { + self.matrix_mut_unchecked() + } +} + +impl AbsDiffEq for Transform +where + Const: DimNameAdd, + T::Epsilon: Clone, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.matrix.abs_diff_eq(&other.matrix, epsilon) + } +} + +impl RelativeEq for Transform +where + Const: DimNameAdd, + T::Epsilon: Clone, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.matrix + .relative_eq(&other.matrix, epsilon, max_relative) + } +} + +impl UlpsEq for Transform +where + Const: DimNameAdd, + T::Epsilon: Clone, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.matrix.ulps_eq(&other.matrix, epsilon, max_ulps) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::base::Matrix4; + + #[test] + fn checks_homogeneous_invariants_of_square_identity_matrix() { + assert!(TAffine::check_homogeneous_invariants( + &Matrix4::::identity() + )); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_alias.rs new file mode 100644 index 000000000..1fc6bd63f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_alias.rs @@ -0,0 +1,15 @@ +use crate::geometry::{TAffine, TGeneral, TProjective, Transform}; + +/// A 2D general transformation that may not be invertible. Stored as a homogeneous 3x3 matrix. +pub type Transform2 = Transform; +/// An invertible 2D general transformation. Stored as a homogeneous 3x3 matrix. +pub type Projective2 = Transform; +/// A 2D affine transformation. Stored as a homogeneous 3x3 matrix. +pub type Affine2 = Transform; + +/// A 3D general transformation that may not be inversible. Stored as a homogeneous 4x4 matrix. +pub type Transform3 = Transform; +/// An invertible 3D general transformation. Stored as a homogeneous 4x4 matrix. +pub type Projective3 = Transform; +/// A 3D affine transformation. Stored as a homogeneous 4x4 matrix. +pub type Affine3 = Transform; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_construction.rs new file mode 100644 index 000000000..b52100c7d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_construction.rs @@ -0,0 +1,74 @@ +use num::One; + +use simba::scalar::RealField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix}; + +use crate::geometry::{TCategory, Transform}; + +impl Default for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + fn default() -> Self { + Self::identity() + } +} + +impl Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + /// Creates a new identity transform. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::{Transform2, Projective2, Affine2, Transform3, Projective3, Affine3, Point2, Point3}; + /// + /// let pt = Point2::new(1.0, 2.0); + /// let t = Projective2::identity(); + /// assert_eq!(t * pt, pt); + /// + /// let aff = Affine2::identity(); + /// assert_eq!(aff * pt, pt); + /// + /// let aff = Transform2::identity(); + /// assert_eq!(aff * pt, pt); + /// + /// // Also works in 3D. + /// let pt = Point3::new(1.0, 2.0, 3.0); + /// let t = Projective3::identity(); + /// assert_eq!(t * pt, pt); + /// + /// let aff = Affine3::identity(); + /// assert_eq!(aff * pt, pt); + /// + /// let aff = Transform3::identity(); + /// assert_eq!(aff * pt, pt); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::from_matrix_unchecked(OMatrix::< + _, + DimNameSum, U1>, + DimNameSum, U1>, + >::identity()) + } +} + +impl One for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + /// Creates a new identity transform. + #[inline] + fn one() -> Self { + Self::identity() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_conversion.rs new file mode 100644 index 000000000..d46a6c7c2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_conversion.rs @@ -0,0 +1,77 @@ +use simba::scalar::{RealField, SubsetOf}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix}; + +use crate::geometry::{SuperTCategoryOf, TCategory, Transform}; + +impl SubsetOf> for Transform +where + T1: RealField + SubsetOf, + T2: RealField, + C1: TCategory, + C2: SuperTCategoryOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + T1::Epsilon: Copy, + T2::Epsilon: Copy, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> + for Transform +where + T1: RealField + SubsetOf, + T2: RealField, + C: TCategory, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + T1::Epsilon: Copy, + T2::Epsilon: Copy, +{ + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.matrix().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + C::check_homogeneous_invariants(m) + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + Self::from_matrix_unchecked(crate::convert_ref_unchecked(m)) + } +} + +impl From> + for OMatrix, U1>, DimNameSum, U1>> +where + Const: DimNameAdd, + C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn from(t: Transform) -> Self { + t.to_homogeneous() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_ops.rs new file mode 100644 index 000000000..665032bba --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_ops.rs @@ -0,0 +1,704 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +use num::{One, Zero}; +use std::ops::{Div, DivAssign, Index, IndexMut, Mul, MulAssign}; + +use simba::scalar::{ClosedAddAssign, ClosedMulAssign, RealField, SubsetOf}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; + +use crate::geometry::{ + Isometry, Point, Rotation, Similarity, SubTCategoryOf, SuperTCategoryOf, TAffine, TCategory, + TCategoryMul, TGeneral, TProjective, Transform, Translation, UnitComplex, UnitQuaternion, +}; + +/* + * + * In the following, we provide: + * ========================= + * + * Index<(usize, usize)> + * IndexMut<(usize, usize)> (where TCategory == TGeneral) + * + * (Operators) + * + * Transform × Isometry + * Transform × Rotation + * Transform × Similarity + * Transform × Transform + * Transform × UnitQuaternion + * Transform × UnitComplex + * Transform × Translation + * Transform × Vector + * Transform × Point + * + * Isometry × Transform + * Rotation × Transform + * Similarity × Transform + * Translation × Transform + * UnitQuaternion × Transform + * UnitComplex × Transform + * + * TODO: Transform ÷ Isometry + * Transform ÷ Rotation + * TODO: Transform ÷ Similarity + * Transform ÷ Transform + * Transform ÷ UnitQuaternion + * Transform ÷ Translation + * + * TODO: Isometry ÷ Transform + * Rotation ÷ Transform + * TODO: Similarity ÷ Transform + * Translation ÷ Transform + * UnitQuaternion ÷ Transform + * TODO: UnitComplex ÷ Transform + * + * + * (Assignment Operators) + * + * + * Transform ×= Transform + * Transform ×= Similarity + * Transform ×= Isometry + * Transform ×= Rotation + * Transform ×= UnitQuaternion + * Transform ×= UnitComplex + * Transform ×= Translation + * + * Transform ÷= Transform + * TODO: Transform ÷= Similarity + * TODO: Transform ÷= Isometry + * Transform ÷= Rotation + * Transform ÷= UnitQuaternion + * Transform ÷= UnitComplex + * + */ + +/* + * + * Indexing. + * + */ +impl Index<(usize, usize)> for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + type Output = T; + + #[inline] + fn index(&self, ij: (usize, usize)) -> &T { + self.matrix().index(ij) + } +} + +// Only general transformations are mutably indexable. +impl IndexMut<(usize, usize)> for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn index_mut(&mut self, ij: (usize, usize)) -> &mut T { + self.matrix_mut().index_mut(ij) + } +} + +// Transform × Vector +md_impl_all!( + Mul, mul where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C; + where Const: DimNameAdd, C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: SVector, Output = SVector; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let transform = self.matrix().fixed_view::(0, 0); + + if C::has_normalizer() { + let normalizer = self.matrix().fixed_view::<1, D>(D, 0); + let n = normalizer.tr_dot(rhs); + + if !n.is_zero() { + return transform * (rhs / n); + } + } + + transform * rhs + }; +); + +// Transform × Point +md_impl_all!( + Mul, mul where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C; + where Const: DimNameAdd, C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Point, Output = Point; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let transform = self.matrix().fixed_view::(0, 0); + let translation = self.matrix().fixed_view::(0, D); + + if C::has_normalizer() { + let normalizer = self.matrix().fixed_view::<1, D>(D, 0); + #[allow(clippy::suspicious_arithmetic_impl)] + let n = normalizer.tr_dot(&rhs.coords) + unsafe { self.matrix().get_unchecked((D, D)).clone() }; + + if !n.is_zero() { + return (transform * rhs + translation) / n; + } + } + + transform * rhs + translation + }; +); + +// Transform × Transform +md_impl_all!( + Mul, mul where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for CA, CB; + where Const: DimNameAdd, CA: TCategoryMul, CB: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.matrix()); +); + +// Transform × Rotation +md_impl_all!( + Mul, mul + where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, Const) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Rotation, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); +); + +// Rotation × Transform +md_impl_all!( + Mul, mul where T: RealField; + (Const, Const), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Rotation, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +); + +// Transform × UnitQuaternion +md_impl_all!( + Mul, mul where T: RealField; + (U4, U4), (U4, U1) + const; + for C; + where C: TCategoryMul; + self: Transform, rhs: UnitQuaternion, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.clone().to_homogeneous()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.clone().to_homogeneous()); +); + +// Transform × UnitComplex +md_impl_all!( + Mul, mul where T: RealField; + (U3, U3), (U2, U1) + const; + for C; + where C: TCategoryMul; + self: Transform, rhs: UnitComplex, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.clone().to_homogeneous()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.clone().to_homogeneous()); +); + +// UnitQuaternion × Transform +md_impl_all!( + Mul, mul where T: RealField; + (U4, U1), (U4, U4) + const; + for C; + where C: TCategoryMul; + self: UnitQuaternion, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.matrix()); +); + +// UnitComplex × Transform +md_impl_all!( + Mul, mul where T: RealField; + (U2, U1), (U3, U3) + const; + for C; + where C: TCategoryMul; + self: UnitComplex, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.clone().to_homogeneous() * rhs.matrix()); +); + +// Transform × Isometry +md_impl_all!( + Mul, mul where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C, R; + where Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> >, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Isometry, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); +); + +// Isometry × Transform +md_impl_all!( + Mul, mul where T: RealField; + (Const, U1), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for C, R; + where Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> >, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Isometry, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +); + +// Transform × Similarity +md_impl_all!( + Mul, mul where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C, R; + where Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> >, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Similarity, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); +); + +// Similarity × Transform +md_impl_all!( + Mul, mul where T: RealField; + (Const, U1), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for C, R; + where Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> >, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Similarity, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +); + +/* + * + * TODO: don't explicitly build the homogeneous translation matrix. + * Directly apply the translation, just as in `Matrix::{append,prepend}_translation`. This has not + * been done yet because of the `DimNameDiff` requirement (which is not automatically deduced from + * `DimNameAdd` requirement). + * + */ +// Transform × Translation +md_impl_all!( + Mul, mul where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Translation, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); + [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); + [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); +); + +// Translation × Transform +md_impl_all!( + Mul, mul where T: RealField; + (Const, U1), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Translation, rhs: Transform, Output = Transform; + [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); + [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); + [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +); + +// Transform ÷ Transform +md_impl_all!( + Div, div where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for CA, CB; + where Const: DimNameAdd, CA: TCategoryMul, CB: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Transform, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.clone().inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.clone().inverse() }; +); + +// Transform ÷ Rotation +md_impl_all!( + Div, div where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, Const) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Rotation, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// Rotation ÷ Transform +md_impl_all!( + Div, div where T: RealField; + (Const, Const), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Rotation, rhs: Transform, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; +); + +// Transform ÷ UnitQuaternion +md_impl_all!( + Div, div where T: RealField; + (U4, U4), (U4, U1) + const; + for C; + where C: TCategoryMul; + self: Transform, rhs: UnitQuaternion, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// UnitQuaternion ÷ Transform +md_impl_all!( + Div, div where T: RealField; + (U4, U1), (U4, U4) + const; + for C; + where C: TCategoryMul; + self: UnitQuaternion, rhs: Transform, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; +); + +// // Transform ÷ Isometry +// md_impl_all!( +// Div, div where T: RealField; +// (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) +// for Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> > +// where SB::Alloc: Allocator, U1>, DimNameSum, U1> >; +// self: Transform, rhs: Isometry, Output = Transform; +// [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.inverse().to_homogeneous()); +// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous()); +// [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.inverse().to_homogeneous()); +// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.inverse().to_homogeneous()); +// ); + +// // Isometry ÷ Transform +// md_impl_all!( +// Div, div where T: RealField; +// (Const, U1), (DimNameSum, U1>, DimNameSum, U1>) +// for Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> > +// where SA::Alloc: Allocator, U1>, DimNameSum, U1> >; +// self: Isometry, rhs: Transform, Output = Transform; +// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); +// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); +// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +// ); + +// // Transform ÷ Similarity +// md_impl_all!( +// Div, div where T: RealField; +// (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) +// for Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> > +// where SB::Alloc: Allocator +// where SB::Alloc: Allocator, U1>, DimNameSum, U1> >; +// self: Transform, rhs: Similarity, Output = Transform; +// [val val] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); +// [ref val] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); +// [val ref] => Self::Output::from_matrix_unchecked(self.into_inner() * rhs.to_homogeneous()); +// [ref ref] => Self::Output::from_matrix_unchecked(self.matrix() * rhs.to_homogeneous()); +// ); + +// // Similarity ÷ Transform +// md_impl_all!( +// Div, div where T: RealField; +// (Const, U1), (DimNameSum, U1>, DimNameSum, U1>) +// for Const: DimNameAdd, C: TCategoryMul, R: SubsetOf, U1>, DimNameSum, U1>> > +// where SA::Alloc: Allocator +// where SA::Alloc: Allocator, U1>, DimNameSum, U1> >; +// self: Similarity, rhs: Transform, Output = Transform; +// [val val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); +// [ref val] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.into_inner()); +// [val ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +// [ref ref] => Self::Output::from_matrix_unchecked(self.to_homogeneous() * rhs.matrix()); +// ); + +// Transform ÷ Translation +md_impl_all!( + Div, div where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Translation, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * rhs.inverse() }; +); + +// Translation ÷ Transform +md_impl_all!( + Div, div where T: RealField; + (Const, U1), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for C; + where Const: DimNameAdd, C: TCategoryMul, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Translation, rhs: Transform, Output = Transform; + [val val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [ref val] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [val ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self.inverse() * rhs }; +); + +// Transform ×= Transform +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for CA, CB; + where Const: DimNameAdd, CA: TCategory, CB: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Transform; + [val] => *self.matrix_mut_unchecked() *= rhs.into_inner(); + [ref] => *self.matrix_mut_unchecked() *= rhs.matrix(); +); + +// Transform ×= Similarity +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C, R; + where Const: DimNameAdd, C: TCategory, R: SubsetOf, U1>, DimNameSum, U1>> >, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Similarity; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); +); + +// Transform ×= Isometry +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C, R; + where Const: DimNameAdd, C: TCategory, R: SubsetOf, U1>, DimNameSum, U1>> >, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Isometry; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); +); + +/* + * + * TODO: don't explicitly build the homogeneous translation matrix. + * Directly apply the translation, just as in `Matrix::{append,prepend}_translation`. This has not + * been done yet because of the `DimNameDiff` requirement (which is not automatically deduced from + * `DimNameAdd` requirement). + * + */ +// Transform ×= Translation +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C; + where Const: DimNameAdd, C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Translation; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); +); + +// Transform ×= Rotation +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, Const) + const D; + for C; + where Const: DimNameAdd, C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Rotation; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); +); + +// Transform ×= UnitQuaternion +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (U4, U4), (U4, U1) + const; + for C; + where C: TCategory; + self: Transform, rhs: UnitQuaternion; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.clone().to_homogeneous(); +); + +// Transform ×= UnitComplex +md_assign_impl_all!( + MulAssign, mul_assign where T: RealField; + (U3, U3), (U2, U1) + const; + for C; + where C: TCategory; + self: Transform, rhs: UnitComplex; + [val] => *self.matrix_mut_unchecked() *= rhs.to_homogeneous(); + [ref] => *self.matrix_mut_unchecked() *= rhs.clone().to_homogeneous(); +); + +// Transform ÷= Transform +md_assign_impl_all!( + DivAssign, div_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (DimNameSum, U1>, DimNameSum, U1>) + const D; + for CA, CB; + where Const: DimNameAdd, CA: SuperTCategoryOf, CB: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Transform; + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.clone().inverse() }; +); + +// // Transform ÷= Similarity +// md_assign_impl_all!( +// DivAssign, div_assign; +// (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) +// for Const: DimNameAdd, C: TCategory, R: SubsetOf, U1>, DimNameSum, U1>> >; +// self: Transform, rhs: Similarity; +// [val] => *self *= rhs.inverse(); +// [ref] => *self *= rhs.inverse(); +// ); +// +// +// // Transform ÷= Isometry +// md_assign_impl_all!( +// DivAssign, div_assign; +// (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) +// for Const: DimNameAdd, C: TCategory, R: SubsetOf, U1>, DimNameSum, U1>> >; +// self: Transform, rhs: Isometry; +// [val] => *self *= rhs.inverse(); +// [ref] => *self *= rhs.inverse(); +// ); + +// Transform ÷= Translation +md_assign_impl_all!( + DivAssign, div_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, U1) + const D; + for C; + where Const: DimNameAdd, C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Translation; + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Transform ÷= Rotation +md_assign_impl_all!( + DivAssign, div_assign where T: RealField; + (DimNameSum, U1>, DimNameSum, U1>), (Const, Const) + const D; + for C; + where Const: DimNameAdd, C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>; + self: Transform, rhs: Rotation; + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Transform ÷= UnitQuaternion +md_assign_impl_all!( + DivAssign, div_assign where T: RealField; + (U4, U4), (U4, U1) + const; + for C; + where C: TCategory; + self: Transform, rhs: UnitQuaternion; + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); + +// Transform ÷= UnitComplex +md_assign_impl_all!( + DivAssign, div_assign where T: RealField; + (U3, U3), (U2, U1) + const; + for C; + where C: TCategory; + self: Transform, rhs: UnitComplex; + [val] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; + [ref] => #[allow(clippy::suspicious_op_assign_impl)] { *self *= rhs.inverse() }; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_simba.rs new file mode 100644 index 000000000..7d919dc97 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/transform_simba.rs @@ -0,0 +1,51 @@ +use simba::simd::SimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, OMatrix, Scalar}; +use crate::RealField; + +use crate::geometry::{TCategory, Transform}; + +impl SimdValue for Transform +where + T::Element: Scalar, + C: TCategory, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + const LANES: usize = T::LANES; + type Element = Transform; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + Transform::from_matrix_unchecked(OMatrix::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Transform::from_matrix_unchecked(self.matrix().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Transform::from_matrix_unchecked(self.matrix().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.matrix_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Transform::from_matrix_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation.rs new file mode 100644 index 000000000..1886b82a6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation.rs @@ -0,0 +1,302 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num::{One, Zero}; +use std::fmt; +use std::hash; + +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use simba::scalar::{ClosedAddAssign, ClosedNeg, ClosedSubAssign}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; + +use crate::geometry::Point; + +#[cfg(feature = "rkyv-serialize")] +use rkyv::bytecheck; + +/// A translation. +#[repr(C)] +#[cfg_attr( + feature = "rkyv-serialize-no-std", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Translation", + bound(archive = " + T: rkyv::Archive, + SVector: rkyv::Archive> + ") + ) +)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] +#[derive(Copy, Clone)] +pub struct Translation { + /// The translation coordinates, i.e., how much is added to a point's coordinates when it is + /// translated. + pub vector: SVector, +} + +impl fmt::Debug for Translation { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.vector.as_slice().fmt(formatter) + } +} + +impl hash::Hash for Translation +where + Owned>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.vector.hash(state) + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Translation +where + T: Scalar + bytemuck::Zeroable, + SVector: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Translation +where + T: Scalar + bytemuck::Pod, + SVector: bytemuck::Pod, +{ +} + +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Translation +where + Owned>: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.vector.serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Translation +where + Owned>: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = SVector::::deserialize(deserializer)?; + + Ok(Translation::from(matrix)) + } +} + +impl Translation { + /// Creates a new translation from the given vector. + #[inline] + #[deprecated(note = "Use `::from` instead.")] + pub fn from_vector(vector: SVector) -> Translation { + Translation { vector } + } + + /// Inverts `self`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation2, Translation3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * t.inverse(), Translation3::identity()); + /// assert_eq!(t.inverse() * t, Translation3::identity()); + /// + /// // Work in all dimensions. + /// let t = Translation2::new(1.0, 2.0); + /// assert_eq!(t * t.inverse(), Translation2::identity()); + /// assert_eq!(t.inverse() * t, Translation2::identity()); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Translation + where + T: ClosedNeg, + { + Translation::from(-&self.vector) + } + + /// Converts this translation into its equivalent homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation2, Translation3, Matrix3, Matrix4}; + /// let t = Translation3::new(10.0, 20.0, 30.0); + /// let expected = Matrix4::new(1.0, 0.0, 0.0, 10.0, + /// 0.0, 1.0, 0.0, 20.0, + /// 0.0, 0.0, 1.0, 30.0, + /// 0.0, 0.0, 0.0, 1.0); + /// assert_eq!(t.to_homogeneous(), expected); + /// + /// let t = Translation2::new(10.0, 20.0); + /// let expected = Matrix3::new(1.0, 0.0, 10.0, + /// 0.0, 1.0, 20.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(t.to_homogeneous(), expected); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> + where + T: Zero + One, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + { + let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); + res.fixed_view_mut::(0, D).copy_from(&self.vector); + + res + } + + /// Inverts `self` in-place. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation2, Translation3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// let mut inv_t = Translation3::new(1.0, 2.0, 3.0); + /// inv_t.inverse_mut(); + /// assert_eq!(t * inv_t, Translation3::identity()); + /// assert_eq!(inv_t * t, Translation3::identity()); + /// + /// // Work in all dimensions. + /// let t = Translation2::new(1.0, 2.0); + /// let mut inv_t = Translation2::new(1.0, 2.0); + /// inv_t.inverse_mut(); + /// assert_eq!(t * inv_t, Translation2::identity()); + /// assert_eq!(inv_t * t, Translation2::identity()); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) + where + T: ClosedNeg, + { + self.vector.neg_mut() + } +} + +impl Translation { + /// Translate the given point. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation3, Point3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_eq!(transformed_point, Point3::new(5.0, 7.0, 9.0)); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + pt + &self.vector + } +} + +impl Translation { + /// Translate the given point by the inverse of this translation. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation3, Point3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// let transformed_point = t.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_eq!(transformed_point, Point3::new(3.0, 3.0, 3.0)); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + pt - &self.vector + } +} + +impl Eq for Translation {} + +impl PartialEq for Translation { + #[inline] + fn eq(&self, right: &Translation) -> bool { + self.vector == right.vector + } +} + +impl AbsDiffEq for Translation +where + T::Epsilon: Clone, +{ + type Epsilon = T::Epsilon; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.vector.abs_diff_eq(&other.vector, epsilon) + } +} + +impl RelativeEq for Translation +where + T::Epsilon: Clone, +{ + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.vector + .relative_eq(&other.vector, epsilon, max_relative) + } +} + +impl UlpsEq for Translation +where + T::Epsilon: Clone, +{ + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.vector.ulps_eq(&other.vector, epsilon, max_ulps) + } +} + +/* + * + * Display + * + */ +impl fmt::Display for Translation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let precision = f.precision().unwrap_or(3); + + writeln!(f, "Translation {{")?; + write!(f, "{:.*}", precision, self.vector)?; + writeln!(f, "}}") + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_alias.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_alias.rs new file mode 100644 index 000000000..f1fe8f146 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_alias.rs @@ -0,0 +1,19 @@ +use crate::geometry::Translation; + +/// A 1-dimensional translation. +pub type Translation1 = Translation; + +/// A 2-dimensional translation. +pub type Translation2 = Translation; + +/// A 3-dimensional translation. +pub type Translation3 = Translation; + +/// A 4-dimensional translation. +pub type Translation4 = Translation; + +/// A 5-dimensional translation. +pub type Translation5 = Translation; + +/// A 6-dimensional translation. +pub type Translation6 = Translation; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_construction.rs new file mode 100644 index 000000000..405ddba0e --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_construction.rs @@ -0,0 +1,129 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::{One, Zero}; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use simba::scalar::{ClosedAddAssign, SupersetOf}; + +use crate::base::{SVector, Scalar}; +use crate::geometry::Translation; + +impl Default for Translation { + fn default() -> Self { + Self::identity() + } +} + +impl Translation { + /// Creates a new identity translation. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3, Translation2, Translation3}; + /// let t = Translation2::identity(); + /// let p = Point2::new(1.0, 2.0); + /// assert_eq!(t * p, p); + /// + /// // Works in all dimensions. + /// let t = Translation3::identity(); + /// let p = Point3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * p, p); + /// ``` + #[inline] + pub fn identity() -> Translation + where + T: Zero, + { + Self::from(SVector::::from_element(T::zero())) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Translation2; + /// let tra = Translation2::new(1.0f64, 2.0); + /// let tra2 = tra.cast::(); + /// assert_eq!(tra2, Translation2::new(1.0f32, 2.0)); + /// ``` + pub fn cast(self) -> Translation + where + Translation: SupersetOf, + { + crate::convert(self) + } +} + +impl One for Translation { + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, +{ + /// Generate an arbitrary random variate for testing purposes. + #[inline] + fn sample(&self, rng: &mut G) -> Translation { + Translation::from(rng.gen::>()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Translation +where + Owned>: Send, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + let v: SVector = Arbitrary::arbitrary(rng); + Self::from(v) + } +} + +/* + * + * Small translation construction from components. + * + */ +macro_rules! componentwise_constructors_impl( + ($($doc: expr; $D: expr, $($args: ident:$irow: expr),*);* $(;)*) => {$( + impl Translation + { + #[doc = "Initializes this translation from its components."] + #[doc = "# Example\n```"] + #[doc = $doc] + #[doc = "```"] + #[inline] + pub const fn new($($args: T),*) -> Self { + Self { vector: SVector::::new($($args),*) } + } + } + )*} +); + +componentwise_constructors_impl!( + "# use nalgebra::Translation1;\nlet t = Translation1::new(1.0);\nassert!(t.vector.x == 1.0);"; + 1, x:0; + "# use nalgebra::Translation2;\nlet t = Translation2::new(1.0, 2.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0);"; + 2, x:0, y:1; + "# use nalgebra::Translation3;\nlet t = Translation3::new(1.0, 2.0, 3.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0);"; + 3, x:0, y:1, z:2; + "# use nalgebra::Translation4;\nlet t = Translation4::new(1.0, 2.0, 3.0, 4.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0);"; + 4, x:0, y:1, z:2, w:3; + "# use nalgebra::Translation5;\nlet t = Translation5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0);"; + 5, x:0, y:1, z:2, w:3, a:4; + "# use nalgebra::Translation6;\nlet t = Translation6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0 && t.vector.b == 6.0);"; + 6, x:0, y:1, z:2, w:3, a:4, b:5; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_conversion.rs new file mode 100644 index 000000000..c678e85c2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_conversion.rs @@ -0,0 +1,303 @@ +use num::{One, Zero}; + +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::PrimitiveSimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, DimName, OMatrix, OVector, SVector, Scalar}; + +use crate::geometry::{ + AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, + Translation3, UnitDualQuaternion, UnitQuaternion, +}; +use crate::{ArrayStorage, Point}; + +/* + * This file provides the following conversions: + * ============================================= + * + * Translation -> Translation + * Translation -> Isometry + * Translation3 -> UnitDualQuaternion + * Translation -> Similarity + * Translation -> Transform + * Translation -> Matrix (homogeneous) + */ + +impl SubsetOf> for Translation +where + T1: Scalar, + T2: Scalar + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Translation { + Translation::from(self.vector.to_superset()) + } + + #[inline] + fn is_in_subset(rot: &Translation) -> bool { + crate::is_convertible::<_, SVector>(&rot.vector) + } + + #[inline] + fn from_superset_unchecked(rot: &Translation) -> Self { + Translation { + vector: rot.vector.to_subset_unchecked(), + } + } +} + +impl SubsetOf> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Isometry { + Isometry::from_parts(self.to_superset(), R::identity()) + } + + #[inline] + fn is_in_subset(iso: &Isometry) -> bool { + iso.rotation == R::identity() + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry) -> Self { + Self::from_superset_unchecked(&iso.translation) + } +} + +impl SubsetOf> for Translation3 +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitDualQuaternion { + let dq = UnitDualQuaternion::::from_parts(self.clone(), UnitQuaternion::identity()); + dq.to_superset() + } + + #[inline] + fn is_in_subset(dq: &UnitDualQuaternion) -> bool { + crate::is_convertible::<_, Translation>(&dq.translation()) + && dq.rotation() == UnitQuaternion::identity() + } + + #[inline] + fn from_superset_unchecked(dq: &UnitDualQuaternion) -> Self { + let dq: UnitDualQuaternion = crate::convert_ref_unchecked(dq); + dq.translation() + } +} + +impl SubsetOf> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_parts(self.to_superset(), R::identity(), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + sim.isometry.rotation == R::identity() && sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + Self::from_superset_unchecked(&sim.isometry.translation) + } +} + +impl SubsetOf> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, Buffer = ArrayStorage> + + Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + let id = m.generic_view((0, 0), (DimNameSum::, U1>::name(), Const::)); + + // Scalar types agree. + m.iter().all(|e| SupersetOf::::is_in_subset(e)) && + // The block part does nothing. + id.is_identity(T2::zero()) && + // The normalization factor is one. + m[(D, D)] == T2::one() + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + let t: OVector> = m.fixed_view::(0, D).into_owned(); + Self { + vector: crate::convert_unchecked(t), + } + } +} + +impl From> + for OMatrix, U1>, DimNameSum, U1>> +where + Const: DimNameAdd, + DefaultAllocator: + Allocator, U1>, DimNameSum, U1>> + Allocator>, +{ + #[inline] + fn from(t: Translation) -> Self { + t.to_homogeneous() + } +} + +impl From>> for Translation { + #[inline] + fn from(vector: OVector>) -> Self { + Translation { vector } + } +} + +impl From<[T; D]> for Translation { + #[inline] + fn from(coords: [T; D]) -> Self { + Translation { + vector: coords.into(), + } + } +} + +impl From> for Translation { + #[inline] + fn from(pt: Point) -> Self { + Translation { vector: pt.coords } + } +} + +impl From> for [T; D] { + #[inline] + fn from(t: Translation) -> Self { + t.vector.into() + } +} + +impl From<[Translation; 2]> + for Translation +where + T: From<[::Element; 2]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 2]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + ])) + } +} + +impl From<[Translation; 4]> + for Translation +where + T: From<[::Element; 4]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 4]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + ])) + } +} + +impl From<[Translation; 8]> + for Translation +where + T: From<[::Element; 8]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 8]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + ])) + } +} + +impl From<[Translation; 16]> + for Translation +where + T: From<[::Element; 16]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 16]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + arr[8].vector.clone(), + arr[9].vector.clone(), + arr[10].vector.clone(), + arr[11].vector.clone(), + arr[12].vector.clone(), + arr[13].vector.clone(), + arr[14].vector.clone(), + arr[15].vector.clone(), + ])) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_coordinates.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_coordinates.rs new file mode 100644 index 000000000..bba8fd5d2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_coordinates.rs @@ -0,0 +1,39 @@ +use std::ops::{Deref, DerefMut}; + +use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; +use crate::base::Scalar; + +use crate::geometry::Translation; + +/* + * + * Give coordinates to Translation{1 .. 6} + * + */ + +macro_rules! deref_impl( + ($D: expr, $Target: ident $(, $comps: ident)*) => { + impl Deref for Translation { + type Target = $Target; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Translation as *const Self::Target) } + } + } + + impl DerefMut for Translation { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Translation as *mut Self::Target) } + } + } + } +); + +deref_impl!(1, X, x); +deref_impl!(2, XY, x, y); +deref_impl!(3, XYZ, x, y, z); +deref_impl!(4, XYZW, x, y, z, w); +deref_impl!(5, XYZWA, x, y, z, w, a); +deref_impl!(6, XYZWAB, x, y, z, w, a, b); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_ops.rs new file mode 100644 index 000000000..bba85be63 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_ops.rs @@ -0,0 +1,119 @@ +use std::ops::{Div, DivAssign, Mul, MulAssign}; + +use simba::scalar::{ClosedAddAssign, ClosedSubAssign}; + +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::U1; +use crate::base::{Const, Scalar}; + +use crate::geometry::{Point, Translation}; + +// Translation × Translation +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector + &right.vector) }; + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector + right.vector) }; + 'a); + +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + &right.vector) }; + 'b); + +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + right.vector) }; ); + +// Translation ÷ Translation +// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? +add_sub_impl!(Div, div, ClosedSubAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector - &right.vector) }; + 'a, 'b); + +add_sub_impl!(Div, div, ClosedSubAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector - right.vector) }; + 'a); + +add_sub_impl!(Div, div, ClosedSubAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - &right.vector) }; + 'b); + +add_sub_impl!(Div, div, ClosedSubAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - right.vector) }; ); + +// Translation × Point +// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended +// behavior? +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: &'b Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + &self.vector }; + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + &self.vector }; + 'a); + +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: &'b Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + self.vector }; + 'b); + +add_sub_impl!(Mul, mul, ClosedAddAssign; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + self.vector }; ); + +// Translation *= Translation +add_sub_assign_impl!(MulAssign, mul_assign, ClosedAddAssign; + const D; + self: Translation, right: &'b Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector += &right.vector }; + 'b); + +add_sub_assign_impl!(MulAssign, mul_assign, ClosedAddAssign; + const D; + self: Translation, right: Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector += right.vector }; ); + +add_sub_assign_impl!(DivAssign, div_assign, ClosedSubAssign; + const D; + self: Translation, right: &'b Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector -= &right.vector }; + 'b); + +add_sub_assign_impl!(DivAssign, div_assign, ClosedSubAssign; + const D; + self: Translation, right: Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector -= right.vector }; ); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_simba.rs new file mode 100644 index 000000000..10218228d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/translation_simba.rs @@ -0,0 +1,45 @@ +use simba::simd::SimdValue; + +use crate::base::OVector; +use crate::Scalar; + +use crate::geometry::Translation; + +impl SimdValue for Translation +where + T::Element: Scalar, +{ + const LANES: usize = T::LANES; + type Element = Translation; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + OVector::splat(val.vector).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.vector.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.vector.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.vector.replace(i, val.vector) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.vector.replace_unchecked(i, val.vector) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.vector.select(cond, other.vector).into() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex.rs new file mode 100644 index 000000000..a972846cf --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex.rs @@ -0,0 +1,465 @@ +use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +use num_complex::Complex; +use std::fmt; + +use crate::base::{Matrix2, Matrix3, Normed, Unit, Vector1, Vector2}; +use crate::geometry::{Point2, Rotation2}; +use crate::Scalar; +use simba::scalar::RealField; +use simba::simd::SimdRealField; +use std::cmp::{Eq, PartialEq}; + +/// A 2D rotation represented as a complex number with magnitude 1. +/// +/// All the methods specific [`UnitComplex`](crate::UnitComplex) are listed here. You may also +/// read the documentation of the [`Complex`](crate::Complex) type which +/// is used internally and accessible with `unit_complex.complex()`. +/// +/// # Construction +/// * [Identity `identity`](#identity) +/// * [From a 2D rotation angle `new`, `from_cos_sin_unchecked`…](#construction-from-a-2d-rotation-angle) +/// * [From an existing 2D matrix or complex number `from_matrix`, `rotation_to`, `powf`…](#construction-from-an-existing-2d-matrix-or-complex-number) +/// * [From two vectors `rotation_between`, `scaled_rotation_between_axis`…](#construction-from-two-vectors) +/// +/// # Transformation and composition +/// * [Angle extraction `angle`, `angle_to`…](#angle-extraction) +/// * [Transformation of a vector or a point `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) +/// * [Conjugation and inversion `conjugate`, `inverse_mut`…](#conjugation-and-inversion) +/// * [Interpolation `slerp`…](#interpolation) +/// +/// # Conversion +/// * [Conversion to a matrix `to_rotation_matrix`, `to_homogeneous`…](#conversion-to-a-matrix) +pub type UnitComplex = Unit>; + +impl PartialEq for UnitComplex { + #[inline] + fn eq(&self, rhs: &Self) -> bool { + (**self).eq(&**rhs) + } +} + +impl Eq for UnitComplex {} + +impl Normed for Complex { + type Norm = T::SimdRealField; + + #[inline] + fn norm(&self) -> T::SimdRealField { + // We don't use `.norm_sqr()` because it requires + // some very strong Num trait requirements. + (self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone()).simd_sqrt() + } + + #[inline] + fn norm_squared(&self) -> T::SimdRealField { + // We don't use `.norm_sqr()` because it requires + // some very strong Num trait requirements. + self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone() + } + + #[inline] + fn scale_mut(&mut self, n: Self::Norm) { + self.re *= n.clone(); + self.im *= n; + } + + #[inline] + fn unscale_mut(&mut self, n: Self::Norm) { + self.re /= n.clone(); + self.im /= n; + } +} + +/// # Angle extraction +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// The rotation angle in `]-pi; pi]` of this unit complex number. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitComplex; + /// let rot = UnitComplex::new(1.78); + /// assert_eq!(rot.angle(), 1.78); + /// ``` + #[inline] + #[must_use] + pub fn angle(&self) -> T { + self.im.clone().simd_atan2(self.re.clone()) + } + + /// The sine of the rotation angle. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitComplex; + /// let angle = 1.78f32; + /// let rot = UnitComplex::new(angle); + /// assert_eq!(rot.sin_angle(), angle.sin()); + /// ``` + #[inline] + #[must_use] + pub fn sin_angle(&self) -> T { + self.im.clone() + } + + /// The cosine of the rotation angle. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitComplex; + /// let angle = 1.78f32; + /// let rot = UnitComplex::new(angle); + /// assert_eq!(rot.cos_angle(),angle.cos()); + /// ``` + #[inline] + #[must_use] + pub fn cos_angle(&self) -> T { + self.re.clone() + } + + /// The rotation angle returned as a 1-dimensional vector. + /// + /// This is generally used in the context of generic programming. Using + /// the `.angle()` method instead is more common. + #[inline] + #[must_use] + pub fn scaled_axis(&self) -> Vector1 { + Vector1::new(self.angle()) + } + + /// The rotation axis and angle in (0, pi] of this complex number. + /// + /// This is generally used in the context of generic programming. Using + /// the `.angle()` method instead is more common. + /// Returns `None` if the angle is zero. + #[inline] + #[must_use] + pub fn axis_angle(&self) -> Option<(Unit>, T)> + where + T: RealField, + { + let ang = self.angle(); + + if ang.is_zero() { + None + } else if ang.is_sign_positive() { + Some((Unit::new_unchecked(Vector1::x()), ang)) + } else { + Some((Unit::new_unchecked(-Vector1::::x()), -ang)) + } + } + + /// The rotation angle needed to make `self` and `other` coincide. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let rot1 = UnitComplex::new(0.1); + /// let rot2 = UnitComplex::new(1.7); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); + /// ``` + #[inline] + #[must_use] + pub fn angle_to(&self, other: &Self) -> T { + let delta = self.rotation_to(other); + delta.angle() + } +} + +/// # Conjugation and inversion +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// Compute the conjugate of this unit complex number. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitComplex; + /// let rot = UnitComplex::new(1.78); + /// let conj = rot.conjugate(); + /// assert_eq!(rot.complex().im, -conj.complex().im); + /// assert_eq!(rot.complex().re, conj.complex().re); + /// ``` + #[inline] + #[must_use = "Did you mean to use conjugate_mut()?"] + pub fn conjugate(&self) -> Self { + Self::new_unchecked(self.conj()) + } + + /// Inverts this complex number if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let rot = UnitComplex::new(1.2); + /// let inv = rot.inverse(); + /// assert_relative_eq!(rot * inv, UnitComplex::identity(), epsilon = 1.0e-6); + /// assert_relative_eq!(inv * rot, UnitComplex::identity(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Self { + self.conjugate() + } + + /// Compute in-place the conjugate of this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let angle = 1.7; + /// let rot = UnitComplex::new(angle); + /// let mut conj = UnitComplex::new(angle); + /// conj.conjugate_mut(); + /// assert_eq!(rot.complex().im, -conj.complex().im); + /// assert_eq!(rot.complex().re, conj.complex().re); + /// ``` + #[inline] + pub fn conjugate_mut(&mut self) { + let me = self.as_mut_unchecked(); + me.im = -me.im.clone(); + } + + /// Inverts in-place this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let angle = 1.7; + /// let mut rot = UnitComplex::new(angle); + /// rot.inverse_mut(); + /// assert_relative_eq!(rot * UnitComplex::new(angle), UnitComplex::identity()); + /// assert_relative_eq!(UnitComplex::new(angle) * rot, UnitComplex::identity()); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) { + self.conjugate_mut() + } +} + +/// # Conversion to a matrix +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// Builds the rotation matrix corresponding to this unit complex number. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitComplex, Rotation2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_6); + /// let expected = Rotation2::new(f32::consts::FRAC_PI_6); + /// assert_eq!(rot.to_rotation_matrix(), expected); + /// ``` + #[inline] + #[must_use] + pub fn to_rotation_matrix(self) -> Rotation2 { + let r = self.re.clone(); + let i = self.im.clone(); + + Rotation2::from_matrix_unchecked(Matrix2::new(r.clone(), -i.clone(), i, r)) + } + + /// Converts this unit complex number into its equivalent homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitComplex, Matrix3}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_6); + /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// assert_eq!(rot.to_homogeneous(), expected); + /// ``` + #[inline] + #[must_use] + pub fn to_homogeneous(self) -> Matrix3 { + self.to_rotation_matrix().to_homogeneous() + } +} + +/// # Transformation of a vector or a point +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// Rotate the given point by this unit complex number. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Point2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_point = rot.transform_point(&Point2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_point, Point2::new(-2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point2) -> Point2 { + self * pt + } + + /// Rotate the given vector by this unit complex number. + /// + /// This is the same as the multiplication `self * v`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Vector2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.transform_vector(&Vector2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_vector, Vector2::new(-2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn transform_vector(&self, v: &Vector2) -> Vector2 { + self * v + } + + /// Rotate the given point by the inverse of this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Point2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_point = rot.inverse_transform_point(&Point2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_point, Point2::new(2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point2) -> Point2 { + // TODO: would it be useful performance-wise not to call inverse explicitly (i-e. implement + // the inverse transformation explicitly here) ? + self.inverse() * pt + } + + /// Rotate the given vector by the inverse of this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Vector2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_vector(&Vector2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_vector, Vector2::new(2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_vector(&self, v: &Vector2) -> Vector2 { + self.inverse() * v + } + + /// Rotate the given vector by the inverse of this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Vector2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_unit_vector(&Vector2::x_axis()); + /// assert_relative_eq!(transformed_vector, -Vector2::y_axis(), epsilon = 1.0e-6); + /// ``` + #[inline] + #[must_use] + pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { + self.inverse() * v + } +} + +/// # Interpolation +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// Spherical linear interpolation between two rotations represented as unit complex numbers. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::geometry::UnitComplex; + /// + /// let rot1 = UnitComplex::new(std::f32::consts::FRAC_PI_4); + /// let rot2 = UnitComplex::new(-std::f32::consts::PI); + /// + /// let rot = rot1.slerp(&rot2, 1.0 / 3.0); + /// + /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); + /// ``` + #[inline] + #[must_use] + pub fn slerp(&self, other: &Self, t: T) -> Self { + let delta = other / self; + self * Self::new(delta.angle() * t) + } +} + +impl fmt::Display for UnitComplex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "UnitComplex angle: {}", self.angle()) + } +} + +impl AbsDiffEq for UnitComplex { + type Epsilon = T; + + #[inline] + fn default_epsilon() -> Self::Epsilon { + T::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.re.abs_diff_eq(&other.re, epsilon.clone()) && self.im.abs_diff_eq(&other.im, epsilon) + } +} + +impl RelativeEq for UnitComplex { + #[inline] + fn default_max_relative() -> Self::Epsilon { + T::default_max_relative() + } + + #[inline] + fn relative_eq( + &self, + other: &Self, + epsilon: Self::Epsilon, + max_relative: Self::Epsilon, + ) -> bool { + self.re + .relative_eq(&other.re, epsilon.clone(), max_relative.clone()) + && self.im.relative_eq(&other.im, epsilon, max_relative) + } +} + +impl UlpsEq for UnitComplex { + #[inline] + fn default_max_ulps() -> u32 { + T::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { + self.re.ulps_eq(&other.re, epsilon.clone(), max_ulps) + && self.im.ulps_eq(&other.im, epsilon, max_ulps) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_construction.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_construction.rs new file mode 100644 index 000000000..2455d0232 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_construction.rs @@ -0,0 +1,436 @@ +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use num::One; +use num_complex::Complex; + +use crate::base::dimension::{U1, U2}; +use crate::base::storage::Storage; +use crate::base::{Matrix2, Scalar, Unit, Vector, Vector2}; +use crate::geometry::{Rotation2, UnitComplex}; +use simba::scalar::{RealField, SupersetOf}; +use simba::simd::SimdRealField; + +impl Default for UnitComplex +where + T::Element: SimdRealField, +{ + fn default() -> Self { + Self::identity() + } +} + +/// # Identity +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// The unit complex number multiplicative identity. + /// + /// # Example + /// ``` + /// # use nalgebra::UnitComplex; + /// let rot1 = UnitComplex::identity(); + /// let rot2 = UnitComplex::new(1.7); + /// + /// assert_eq!(rot1 * rot2, rot2); + /// assert_eq!(rot2 * rot1, rot2); + /// ``` + #[inline] + pub fn identity() -> Self { + Self::new_unchecked(Complex::new(T::one(), T::zero())) + } +} + +/// # Construction from a 2D rotation angle +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// Builds the unit complex number corresponding to the rotation with the given angle. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitComplex, Point2}; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// + /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0)); + /// ``` + #[inline] + pub fn new(angle: T) -> Self { + let (sin, cos) = angle.simd_sin_cos(); + Self::from_cos_sin_unchecked(cos, sin) + } + + /// Builds the unit complex number corresponding to the rotation with the angle. + /// + /// Same as `Self::new(angle)`. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitComplex, Point2}; + /// let rot = UnitComplex::from_angle(f32::consts::FRAC_PI_2); + /// + /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0)); + /// ``` + // TODO: deprecate this. + #[inline] + pub fn from_angle(angle: T) -> Self { + Self::new(angle) + } + + /// Builds the unit complex number from the sinus and cosinus of the rotation angle. + /// + /// The input values are not checked to actually be cosines and sine of the same value. + /// Is is generally preferable to use the `::new(angle)` constructor instead. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitComplex, Vector2, Point2}; + /// let angle = f32::consts::FRAC_PI_2; + /// let rot = UnitComplex::from_cos_sin_unchecked(angle.cos(), angle.sin()); + /// + /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0)); + /// ``` + #[inline] + pub fn from_cos_sin_unchecked(cos: T, sin: T) -> Self { + Self::new_unchecked(Complex::new(cos, sin)) + } + + /// Builds a unit complex rotation from an angle in radian wrapped in a 1-dimensional vector. + /// + /// This is generally used in the context of generic programming. Using + /// the `::new(angle)` method instead is more common. + #[inline] + pub fn from_scaled_axis>(axisangle: Vector) -> Self { + Self::from_angle(axisangle[0].clone()) + } +} + +/// # Construction from an existing 2D matrix or complex number +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let c = UnitComplex::new(1.0f64); + /// let c2 = c.cast::(); + /// assert_relative_eq!(c2, UnitComplex::new(1.0f32)); + /// ``` + pub fn cast(self) -> UnitComplex + where + UnitComplex: SupersetOf, + { + crate::convert(self) + } + + /// The underlying complex number. + /// + /// Same as `self.as_ref()`. + /// + /// # Example + /// ``` + /// # extern crate num_complex; + /// # use num_complex::Complex; + /// # use nalgebra::UnitComplex; + /// let angle = 1.78f32; + /// let rot = UnitComplex::new(angle); + /// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin())); + /// ``` + #[inline] + #[must_use] + pub fn complex(&self) -> &Complex { + self.as_ref() + } + + /// Creates a new unit complex number from a complex number. + /// + /// The input complex number will be normalized. + #[inline] + pub fn from_complex(q: Complex) -> Self { + Self::from_complex_and_get(q).0 + } + + /// Creates a new unit complex number from a complex number. + /// + /// The input complex number will be normalized. Returns the norm of the complex number as well. + #[inline] + pub fn from_complex_and_get(q: Complex) -> (Self, T) { + let norm = (q.im.clone() * q.im.clone() + q.re.clone() * q.re.clone()).simd_sqrt(); + (Self::new_unchecked(q / norm.clone()), norm) + } + + /// Builds the unit complex number from the corresponding 2D rotation matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, UnitComplex}; + /// let rot = Rotation2::new(1.7); + /// let complex = UnitComplex::from_rotation_matrix(&rot); + /// assert_eq!(complex, UnitComplex::new(1.7)); + /// ``` + // TODO: add UnitComplex::from(...) instead? + #[inline] + pub fn from_rotation_matrix(rotmat: &Rotation2) -> Self { + Self::new_unchecked(Complex::new(rotmat[(0, 0)].clone(), rotmat[(1, 0)].clone())) + } + + /// Builds a rotation from a basis assumed to be orthonormal. + /// + /// In order to get a valid unit-quaternion, the input must be an + /// orthonormal basis, i.e., all vectors are normalized, and the are + /// all orthogonal to each other. These invariants are not checked + /// by this method. + pub fn from_basis_unchecked(basis: &[Vector2; 2]) -> Self { + let mat = Matrix2::from_columns(&basis[..]); + let rot = Rotation2::from_matrix_unchecked(mat); + Self::from_rotation_matrix(&rot) + } + + /// Builds an unit complex by extracting the rotation part of the given transformation `m`. + /// + /// This is an iterative method. See `.from_matrix_eps` to provide mover + /// convergence parameters and starting solution. + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + pub fn from_matrix(m: &Matrix2) -> Self + where + T: RealField, + { + Rotation2::from_matrix(m).into() + } + + /// Builds an unit complex by extracting the rotation part of the given transformation `m`. + /// + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + /// + /// # Parameters + /// + /// * `m`: the matrix from which the rotational part is to be extracted. + /// * `eps`: the angular errors tolerated between the current rotation and the optimal one. + /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`. + /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close + /// to the actual solution is provided. Can be set to `UnitQuaternion::identity()` if no other + /// guesses come to mind. + pub fn from_matrix_eps(m: &Matrix2, eps: T, max_iter: usize, guess: Self) -> Self + where + T: RealField, + { + let guess = Rotation2::from(guess); + Rotation2::from_matrix_eps(m, eps, max_iter, guess).into() + } + + /// The unit complex number needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let rot1 = UnitComplex::new(0.1); + /// let rot2 = UnitComplex::new(1.7); + /// let rot_to = rot1.rotation_to(&rot2); + /// + /// assert_relative_eq!(rot_to * rot1, rot2); + /// assert_relative_eq!(rot_to.inverse() * rot2, rot1); + /// ``` + #[inline] + #[must_use] + pub fn rotation_to(&self, other: &Self) -> Self { + other / self + } + + /// Raise this unit complex number to a given floating power. + /// + /// This returns the unit complex number that identifies a rotation angle equal to + /// `self.angle() × n`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let rot = UnitComplex::new(0.78); + /// let pow = rot.powf(2.0); + /// assert_relative_eq!(pow.angle(), 2.0 * 0.78); + /// ``` + #[inline] + #[must_use] + pub fn powf(&self, n: T) -> Self { + Self::from_angle(self.angle() * n) + } +} + +/// # Construction from two vectors +impl UnitComplex +where + T::Element: SimdRealField, +{ + /// The unit complex needed to make `a` and `b` be collinear and point toward the same + /// direction. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector2, UnitComplex}; + /// let a = Vector2::new(1.0, 2.0); + /// let b = Vector2::new(2.0, 1.0); + /// let rot = UnitComplex::rotation_between(&a, &b); + /// assert_relative_eq!(rot * a, b); + /// assert_relative_eq!(rot.inverse() * b, a); + /// ``` + #[inline] + pub fn rotation_between(a: &Vector, b: &Vector) -> Self + where + T: RealField, + SB: Storage, + SC: Storage, + { + Self::scaled_rotation_between(a, b, T::one()) + } + + /// The smallest rotation needed to make `a` and `b` collinear and point toward the same + /// direction, raised to the power `s`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Vector2, UnitComplex}; + /// let a = Vector2::new(1.0, 2.0); + /// let b = Vector2::new(2.0, 1.0); + /// let rot2 = UnitComplex::scaled_rotation_between(&a, &b, 0.2); + /// let rot5 = UnitComplex::scaled_rotation_between(&a, &b, 0.5); + /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn scaled_rotation_between( + a: &Vector, + b: &Vector, + s: T, + ) -> Self + where + T: RealField, + SB: Storage, + SC: Storage, + { + // TODO: code duplication with Rotation. + if let (Some(na), Some(nb)) = ( + Unit::try_new(a.clone_owned(), T::zero()), + Unit::try_new(b.clone_owned(), T::zero()), + ) { + Self::scaled_rotation_between_axis(&na, &nb, s) + } else { + Self::identity() + } + } + + /// The unit complex needed to make `a` and `b` be collinear and point toward the same + /// direction. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Unit, Vector2, UnitComplex}; + /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0)); + /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0)); + /// let rot = UnitComplex::rotation_between_axis(&a, &b); + /// assert_relative_eq!(rot * a, b); + /// assert_relative_eq!(rot.inverse() * b, a); + /// ``` + #[inline] + pub fn rotation_between_axis( + a: &Unit>, + b: &Unit>, + ) -> Self + where + SB: Storage, + SC: Storage, + { + Self::scaled_rotation_between_axis(a, b, T::one()) + } + + /// The smallest rotation needed to make `a` and `b` collinear and point toward the same + /// direction, raised to the power `s`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Unit, Vector2, UnitComplex}; + /// let a = Unit::new_normalize(Vector2::new(1.0, 2.0)); + /// let b = Unit::new_normalize(Vector2::new(2.0, 1.0)); + /// let rot2 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.2); + /// let rot5 = UnitComplex::scaled_rotation_between_axis(&a, &b, 0.5); + /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6); + /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn scaled_rotation_between_axis( + na: &Unit>, + nb: &Unit>, + s: T, + ) -> Self + where + SB: Storage, + SC: Storage, + { + let sang = na.perp(nb); + let cang = na.dot(nb); + + Self::from_angle(sang.simd_atan2(cang) * s) + } +} + +impl One for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand")] +impl Distribution> for Standard +where + T::Element: SimdRealField, + rand_distr::UnitCircle: Distribution<[T; 2]>, +{ + /// Generate a uniformly distributed random `UnitComplex`. + #[inline] + fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex { + let x = rng.sample(rand_distr::UnitCircle); + UnitComplex::new_unchecked(Complex::new(x[0].clone(), x[1].clone())) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn arbitrary(g: &mut Gen) -> Self { + UnitComplex::from_angle(T::arbitrary(g)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_conversion.rs new file mode 100644 index 000000000..e02052605 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_conversion.rs @@ -0,0 +1,264 @@ +use num::Zero; +use num_complex::Complex; + +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::{PrimitiveSimdValue, SimdRealField}; + +use crate::base::{Matrix2, Matrix3, Scalar}; +use crate::geometry::{ + AbstractRotation, Isometry, Rotation2, Similarity, SuperTCategoryOf, TAffine, Transform, + Translation, UnitComplex, +}; + +/* + * This file provides the following conversions: + * ============================================= + * + * UnitComplex -> UnitComplex + * UnitComplex -> Rotation + * UnitComplex -> Isometry<2> + * UnitComplex -> Similarity<2> + * UnitComplex -> Transform<2> + * UnitComplex -> Matrix (homogeneous) + * + * NOTE: + * UnitComplex -> Complex is already provided by: Unit -> T + */ + +impl SubsetOf> for UnitComplex +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitComplex { + UnitComplex::new_unchecked(self.as_ref().to_superset()) + } + + #[inline] + fn is_in_subset(uq: &UnitComplex) -> bool { + crate::is_convertible::<_, Complex>(uq.as_ref()) + } + + #[inline] + fn from_superset_unchecked(uq: &UnitComplex) -> Self { + Self::new_unchecked(crate::convert_ref_unchecked(uq.as_ref())) + } +} + +impl SubsetOf> for UnitComplex +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Rotation2 { + let q: UnitComplex = self.to_superset(); + q.to_rotation_matrix().to_superset() + } + + #[inline] + fn is_in_subset(rot: &Rotation2) -> bool { + crate::is_convertible::<_, Rotation2>(rot) + } + + #[inline] + fn from_superset_unchecked(rot: &Rotation2) -> Self { + let q = UnitComplex::::from_rotation_matrix(rot); + crate::convert_unchecked(q) + } +} + +impl SubsetOf> for UnitComplex +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Isometry { + Isometry::from_parts(Translation::identity(), crate::convert_ref(self)) + } + + #[inline] + fn is_in_subset(iso: &Isometry) -> bool { + iso.translation.vector.is_zero() + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry) -> Self { + crate::convert_ref_unchecked(&iso.rotation) + } +} + +impl SubsetOf> for UnitComplex +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_isometry(crate::convert_ref(self), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + sim.isometry.translation.vector.is_zero() && sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + crate::convert_ref_unchecked(&sim.isometry) + } +} + +impl SubsetOf> for UnitComplex +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.clone().to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl> SubsetOf> for UnitComplex { + #[inline] + fn to_superset(&self) -> Matrix3 { + self.clone().to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &Matrix3) -> bool { + crate::is_convertible::<_, Rotation2>(m) + } + + #[inline] + fn from_superset_unchecked(m: &Matrix3) -> Self { + let rot: Rotation2 = crate::convert_ref_unchecked(m); + Self::from_rotation_matrix(&rot) + } +} + +impl From> for Rotation2 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: UnitComplex) -> Self { + q.to_rotation_matrix() + } +} + +impl From> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: Rotation2) -> Self { + Self::from_rotation_matrix(&q) + } +} + +impl From> for Matrix3 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: UnitComplex) -> Matrix3 { + q.to_homogeneous() + } +} + +impl From> for Matrix2 +where + T::Element: SimdRealField, +{ + #[inline] + fn from(q: UnitComplex) -> Self { + q.to_rotation_matrix().into_inner() + } +} + +impl From<[UnitComplex; 2]> for UnitComplex +where + T: From<[::Element; 2]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 2]) -> Self { + Self::new_unchecked(Complex { + re: T::from([arr[0].re, arr[1].re]), + im: T::from([arr[0].im, arr[1].im]), + }) + } +} + +impl From<[UnitComplex; 4]> for UnitComplex +where + T: From<[::Element; 4]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 4]) -> Self { + Self::new_unchecked(Complex { + re: T::from([arr[0].re, arr[1].re, arr[2].re, arr[3].re]), + im: T::from([arr[0].im, arr[1].im, arr[2].im, arr[3].im]), + }) + } +} + +impl From<[UnitComplex; 8]> for UnitComplex +where + T: From<[::Element; 8]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 8]) -> Self { + Self::new_unchecked(Complex { + re: T::from([ + arr[0].re, arr[1].re, arr[2].re, arr[3].re, arr[4].re, arr[5].re, arr[6].re, + arr[7].re, + ]), + im: T::from([ + arr[0].im, arr[1].im, arr[2].im, arr[3].im, arr[4].im, arr[5].im, arr[6].im, + arr[7].im, + ]), + }) + } +} + +impl From<[UnitComplex; 16]> for UnitComplex +where + T: From<[::Element; 16]>, + T::Element: Scalar + Copy, +{ + #[inline] + fn from(arr: [UnitComplex; 16]) -> Self { + Self::new_unchecked(Complex { + re: T::from([ + arr[0].re, arr[1].re, arr[2].re, arr[3].re, arr[4].re, arr[5].re, arr[6].re, + arr[7].re, arr[8].re, arr[9].re, arr[10].re, arr[11].re, arr[12].re, arr[13].re, + arr[14].re, arr[15].re, + ]), + im: T::from([ + arr[0].im, arr[1].im, arr[2].im, arr[3].im, arr[4].im, arr[5].im, arr[6].im, + arr[7].im, arr[8].im, arr[9].im, arr[10].im, arr[11].im, arr[12].im, arr[13].im, + arr[14].im, arr[15].im, + ]), + }) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_ops.rs new file mode 100644 index 000000000..c1ecb1e1c --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_ops.rs @@ -0,0 +1,450 @@ +// The macros break if the references are taken out, for some reason. +#![allow(clippy::op_ref)] + +use std::ops::{Div, DivAssign, Mul, MulAssign}; + +use crate::base::storage::Storage; +use crate::base::{Const, Unit, Vector, Vector2}; +use crate::geometry::{Isometry, Point2, Rotation, Similarity, Translation, UnitComplex}; +use simba::simd::SimdRealField; + +/* + * This file provides: + * =================== + * + * UnitComplex × UnitComplex + * UnitComplex × Rotation -> UnitComplex + * Rotation × UnitComplex -> UnitComplex + * + * UnitComplex ÷ UnitComplex + * UnitComplex ÷ Rotation -> UnitComplex + * Rotation ÷ UnitComplex -> UnitComplex + * + * + * UnitComplex × Point + * UnitComplex × Vector + * UnitComplex × Unit + * + * UnitComplex × Isometry + * UnitComplex × Similarity + * UnitComplex × Translation -> Isometry + * + * (Assignment Operators) + * + * UnitComplex ×= UnitComplex + * UnitComplex ×= Rotation + * + * UnitComplex ÷= UnitComplex + * UnitComplex ÷= Rotation + * + * Rotation ×= UnitComplex + * Rotation ÷= UnitComplex + * + */ + +// UnitComplex × UnitComplex +impl Mul for UnitComplex { + type Output = Self; + + #[inline] + fn mul(self, rhs: Self) -> Self { + Unit::new_unchecked(self.into_inner() * rhs.into_inner()) + } +} + +impl<'a, T: SimdRealField> Mul> for &'a UnitComplex +where + T::Element: SimdRealField, +{ + type Output = UnitComplex; + + #[inline] + fn mul(self, rhs: UnitComplex) -> Self::Output { + Unit::new_unchecked(self.complex() * rhs.into_inner()) + } +} + +impl<'b, T: SimdRealField> Mul<&'b UnitComplex> for UnitComplex +where + T::Element: SimdRealField, +{ + type Output = Self; + + #[inline] + fn mul(self, rhs: &'b UnitComplex) -> Self::Output { + Unit::new_unchecked(self.into_inner() * rhs.as_ref()) + } +} + +impl<'a, 'b, T: SimdRealField> Mul<&'b UnitComplex> for &'a UnitComplex +where + T::Element: SimdRealField, +{ + type Output = UnitComplex; + + #[inline] + fn mul(self, rhs: &'b UnitComplex) -> Self::Output { + Unit::new_unchecked(self.complex() * rhs.as_ref()) + } +} + +// UnitComplex ÷ UnitComplex +impl Div for UnitComplex +where + T::Element: SimdRealField, +{ + type Output = Self; + + #[inline] + fn div(self, rhs: Self) -> Self::Output { + #[allow(clippy::suspicious_arithmetic_impl)] + Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner()) + } +} + +impl<'a, T: SimdRealField> Div> for &'a UnitComplex +where + T::Element: SimdRealField, +{ + type Output = UnitComplex; + + #[inline] + fn div(self, rhs: UnitComplex) -> Self::Output { + #[allow(clippy::suspicious_arithmetic_impl)] + Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner()) + } +} + +impl<'b, T: SimdRealField> Div<&'b UnitComplex> for UnitComplex +where + T::Element: SimdRealField, +{ + type Output = Self; + + #[inline] + fn div(self, rhs: &'b UnitComplex) -> Self::Output { + #[allow(clippy::suspicious_arithmetic_impl)] + Unit::new_unchecked(self.into_inner() * rhs.conjugate().into_inner()) + } +} + +impl<'a, 'b, T: SimdRealField> Div<&'b UnitComplex> for &'a UnitComplex +where + T::Element: SimdRealField, +{ + type Output = UnitComplex; + + #[inline] + fn div(self, rhs: &'b UnitComplex) -> Self::Output { + #[allow(clippy::suspicious_arithmetic_impl)] + Unit::new_unchecked(self.complex() * rhs.conjugate().into_inner()) + } +} + +macro_rules! complex_op_impl( + ($Op: ident, $op: ident; + $($Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; + $action: expr; $($lives: tt),*) => { + impl<$($lives ,)* T: SimdRealField $(, $Storage: $StoragesBound $(<$($BoundParam),*>)*)*> $Op<$Rhs> for $Lhs + where T::Element: SimdRealField { + type Output = $Result; + + #[inline] + fn $op($lhs, $rhs: $Rhs) -> Self::Output { + $action + } + } + } +); + +macro_rules! complex_op_impl_all( + ($Op: ident, $op: ident; + $($Storage: ident: $StoragesBound: ident $(<$($BoundParam: ty),*>)*),*; + $lhs: ident: $Lhs: ty, $rhs: ident: $Rhs: ty, Output = $Result: ty; + [val val] => $action_val_val: expr; + [ref val] => $action_ref_val: expr; + [val ref] => $action_val_ref: expr; + [ref ref] => $action_ref_ref: expr;) => { + + complex_op_impl!($Op, $op; + $($Storage: $StoragesBound $(<$($BoundParam),*>)*),*; + $lhs: $Lhs, $rhs: $Rhs, Output = $Result; + $action_val_val; ); + + complex_op_impl!($Op, $op; + $($Storage: $StoragesBound $(<$($BoundParam),*>)*),*; + $lhs: &'a $Lhs, $rhs: $Rhs, Output = $Result; + $action_ref_val; 'a); + + complex_op_impl!($Op, $op; + $($Storage: $StoragesBound $(<$($BoundParam),*>)*),*; + $lhs: $Lhs, $rhs: &'b $Rhs, Output = $Result; + $action_val_ref; 'b); + + complex_op_impl!($Op, $op; + $($Storage: $StoragesBound $(<$($BoundParam),*>)*),*; + $lhs: &'a $Lhs, $rhs: &'b $Rhs, Output = $Result; + $action_ref_ref; 'a, 'b); + + + } +); + +// UnitComplex × Rotation +complex_op_impl_all!( + Mul, mul; + ; + self: UnitComplex, rhs: Rotation, Output = UnitComplex; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => self * UnitComplex::from_rotation_matrix(rhs); +); + +// UnitComplex ÷ Rotation +complex_op_impl_all!( + Div, div; + ; + self: UnitComplex, rhs: Rotation, Output = UnitComplex; + [val val] => &self / &rhs; + [ref val] => self / &rhs; + [val ref] => &self / rhs; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { self * UnitComplex::from_rotation_matrix(rhs).inverse() }; +); + +// Rotation × UnitComplex +complex_op_impl_all!( + Mul, mul; + ; + self: Rotation, rhs: UnitComplex, Output = UnitComplex; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => UnitComplex::from_rotation_matrix(self) * rhs; +); + +// Rotation ÷ UnitComplex +complex_op_impl_all!( + Div, div; + ; + self: Rotation, rhs: UnitComplex, Output = UnitComplex; + [val val] => &self / &rhs; + [ref val] => self / &rhs; + [val ref] => &self / rhs; + [ref ref] => #[allow(clippy::suspicious_arithmetic_impl)] { UnitComplex::from_rotation_matrix(self) * rhs.inverse() }; +); + +// UnitComplex × Point +complex_op_impl_all!( + Mul, mul; + ; + self: UnitComplex, rhs: Point2, Output = Point2; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => Point2::from(self * &rhs.coords); +); + +// UnitComplex × Vector +complex_op_impl_all!( + Mul, mul; + S: Storage>; + self: UnitComplex, rhs: Vector, S>, Output = Vector2; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let i = self.as_ref().im.clone(); + let r = self.as_ref().re.clone(); + Vector2::new(r.clone() * rhs[0].clone() - i.clone() * rhs[1].clone(), i * rhs[0].clone() + r * rhs[1].clone()) + }; +); + +// UnitComplex × Unit +complex_op_impl_all!( + Mul, mul; + S: Storage>; + self: UnitComplex, rhs: Unit, S>>, Output = Unit>; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => Unit::new_unchecked(self * rhs.as_ref()); +); + +// UnitComplex × Isometry +complex_op_impl_all!( + Mul, mul; + ; + self: UnitComplex, rhs: Isometry, 2>, + Output = Isometry, 2>; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => { + let shift = self * &rhs.translation.vector; + Isometry::from_parts(Translation::from(shift), self * &rhs.rotation) + }; +); + +// UnitComplex × Similarity +complex_op_impl_all!( + Mul, mul; + ; + self: UnitComplex, rhs: Similarity, 2>, + Output = Similarity, 2>; + [val val] => &self * &rhs; + [ref val] => self * &rhs; + [val ref] => &self * rhs; + [ref ref] => Similarity::from_isometry(self * &rhs.isometry, rhs.scaling()); +); + +// UnitComplex × Translation +complex_op_impl_all!( + Mul, mul; + ; + self: UnitComplex, rhs: Translation, + Output = Isometry, 2>; + [val val] => Isometry::from_parts(Translation::from(&self * rhs.vector), self); + [ref val] => Isometry::from_parts(Translation::from( self * rhs.vector), self.clone()); + [val ref] => Isometry::from_parts(Translation::from(&self * &rhs.vector), self); + [ref ref] => Isometry::from_parts(Translation::from( self * &rhs.vector), self.clone()); +); + +// Translation × UnitComplex +complex_op_impl_all!( + Mul, mul; + ; + self: Translation, right: UnitComplex, + Output = Isometry, 2>; + [val val] => Isometry::from_parts(self, right); + [ref val] => Isometry::from_parts(self.clone(), right); + [val ref] => Isometry::from_parts(self, right.clone()); + [ref ref] => Isometry::from_parts(self.clone(), right.clone()); +); + +// UnitComplex ×= UnitComplex +impl MulAssign> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn mul_assign(&mut self, rhs: UnitComplex) { + *self = self.clone() * rhs + } +} + +impl<'b, T: SimdRealField> MulAssign<&'b UnitComplex> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn mul_assign(&mut self, rhs: &'b UnitComplex) { + *self = self.clone() * rhs + } +} + +// UnitComplex /= UnitComplex +impl DivAssign> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn div_assign(&mut self, rhs: UnitComplex) { + *self = self.clone() / rhs + } +} + +impl<'b, T: SimdRealField> DivAssign<&'b UnitComplex> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn div_assign(&mut self, rhs: &'b UnitComplex) { + *self = self.clone() / rhs + } +} + +// UnitComplex ×= Rotation +impl MulAssign> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn mul_assign(&mut self, rhs: Rotation) { + *self = self.clone() * rhs + } +} + +impl<'b, T: SimdRealField> MulAssign<&'b Rotation> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn mul_assign(&mut self, rhs: &'b Rotation) { + *self = self.clone() * rhs + } +} + +// UnitComplex ÷= Rotation +impl DivAssign> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn div_assign(&mut self, rhs: Rotation) { + *self = self.clone() / rhs + } +} + +impl<'b, T: SimdRealField> DivAssign<&'b Rotation> for UnitComplex +where + T::Element: SimdRealField, +{ + #[inline] + fn div_assign(&mut self, rhs: &'b Rotation) { + *self = self.clone() / rhs + } +} + +// Rotation ×= UnitComplex +impl MulAssign> for Rotation +where + T::Element: SimdRealField, +{ + #[inline] + fn mul_assign(&mut self, rhs: UnitComplex) { + self.mul_assign(rhs.to_rotation_matrix()) + } +} + +impl<'b, T: SimdRealField> MulAssign<&'b UnitComplex> for Rotation +where + T::Element: SimdRealField, +{ + #[inline] + fn mul_assign(&mut self, rhs: &'b UnitComplex) { + self.mul_assign(rhs.clone().to_rotation_matrix()) + } +} + +// Rotation ÷= UnitComplex +impl DivAssign> for Rotation +where + T::Element: SimdRealField, +{ + #[inline] + fn div_assign(&mut self, rhs: UnitComplex) { + self.div_assign(rhs.to_rotation_matrix()) + } +} + +impl<'b, T: SimdRealField> DivAssign<&'b UnitComplex> for Rotation +where + T::Element: SimdRealField, +{ + #[inline] + fn div_assign(&mut self, rhs: &'b UnitComplex) { + self.div_assign(rhs.clone().to_rotation_matrix()) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_simba.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_simba.rs new file mode 100644 index 000000000..6b92f43fa --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/geometry/unit_complex_simba.rs @@ -0,0 +1,47 @@ +use num_complex::Complex; +use simba::simd::SimdValue; +use std::ops::Deref; + +use crate::base::Unit; +use crate::geometry::UnitComplex; +use crate::SimdRealField; + +impl SimdValue for UnitComplex +where + T::Element: SimdRealField, +{ + const LANES: usize = T::LANES; + type Element = UnitComplex; + type SimdBool = T::SimdBool; + + #[inline] + fn splat(val: Self::Element) -> Self { + Unit::new_unchecked(Complex::splat(val.into_inner())) + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + Unit::new_unchecked(self.deref().extract(i)) + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + Unit::new_unchecked(self.deref().extract_unchecked(i)) + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked().replace(i, val.into_inner()) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.as_mut_unchecked() + .replace_unchecked(i, val.into_inner()) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + Unit::new_unchecked(self.into_inner().select(cond, other.into_inner())) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.pest b/collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.pest new file mode 100644 index 000000000..f62a47368 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.pest @@ -0,0 +1,16 @@ +WHITESPACE = _{ " " } + +Comments = _{ "%" ~ (!NEWLINE ~ ANY)* } +Header = { "%%" ~ (!NEWLINE ~ ANY)* } +Shape = { Dimension ~ Dimension ~ Dimension } +Document = { + SOI ~ + NEWLINE* ~ + Header ~ + (NEWLINE ~ Comments)* ~ + (NEWLINE ~ Shape) ~ + (NEWLINE ~ Entry?)* +} +Dimension = @{ ASCII_DIGIT+ } +Value = @{ ("+" | "-")? ~ NUMBER+ ~ ("." ~ NUMBER+)? ~ ("e" ~ ("+" | "-")? ~ NUMBER+)? } +Entry = { Dimension ~ Dimension ~ Value } \ No newline at end of file diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.rs new file mode 100644 index 000000000..2c6a7d458 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/io/matrix_market.rs @@ -0,0 +1,53 @@ +use std::fs; +use std::path::Path; + +use crate::sparse::CsMatrix; +use crate::RealField; +use pest::Parser; + +#[derive(Parser)] +#[grammar = "io/matrix_market.pest"] +struct MatrixMarketParser; + +// TODO: return an Error instead of an Option. +/// Parses a Matrix Market file at the given path, and returns the corresponding sparse matrix. +pub fn cs_matrix_from_matrix_market>(path: P) -> Option> { + let file = fs::read_to_string(path).ok()?; + cs_matrix_from_matrix_market_str(&file) +} + +// TODO: return an Error instead of an Option. +/// Parses a Matrix Market file described by the given string, and returns the corresponding sparse matrix. +pub fn cs_matrix_from_matrix_market_str(data: &str) -> Option> { + let file = MatrixMarketParser::parse(Rule::Document, data) + .unwrap() + .next()?; + let mut shape = (0, 0, 0); + let mut rows: Vec = Vec::new(); + let mut cols: Vec = Vec::new(); + let mut data: Vec = Vec::new(); + + for line in file.into_inner() { + match line.as_rule() { + Rule::Header => {} + Rule::Shape => { + let mut inner = line.into_inner(); + shape.0 = inner.next()?.as_str().parse::().ok()?; + shape.1 = inner.next()?.as_str().parse::().ok()?; + shape.2 = inner.next()?.as_str().parse::().ok()?; + } + Rule::Entry => { + let mut inner = line.into_inner(); + // NOTE: indices are 1-based. + rows.push(inner.next()?.as_str().parse::().ok()? - 1); + cols.push(inner.next()?.as_str().parse::().ok()? - 1); + data.push(crate::convert(inner.next()?.as_str().parse::().ok()?)); + } + _ => return None, // TODO: return an Err instead. + } + } + + Some(CsMatrix::from_triplet( + shape.0, shape.1, &rows, &cols, &data, + )) +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/io/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/io/mod.rs new file mode 100644 index 000000000..528cee19d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/io/mod.rs @@ -0,0 +1,5 @@ +//! Parsers for various matrix formats. + +pub use self::matrix_market::{cs_matrix_from_matrix_market, cs_matrix_from_matrix_market_str}; + +mod matrix_market; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/lib.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/lib.rs new file mode 100644 index 000000000..2fef3caf8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/lib.rs @@ -0,0 +1,549 @@ +/*! +# nalgebra + +**nalgebra** is a linear algebra library written for Rust targeting: + +* General-purpose linear algebra (still lacks a lot of features…) +* Real-time computer graphics. +* Real-time computer physics. + +## Using **nalgebra** +You will need the last stable build of the [rust compiler](https://www.rust-lang.org) +and the official package manager: [cargo](https://github.com/rust-lang/cargo). + +Simply add the following to your `Cargo.toml` file: + +```ignore +[dependencies] +// TODO: replace the * by the latest version. +nalgebra = "*" +``` + + +Most useful functionalities of **nalgebra** are grouped in the root module `nalgebra::`. + +However, the recommended way to use **nalgebra** is to import types and traits +explicitly, and call free-functions using the `na::` prefix: + +``` +#[macro_use] +extern crate approx; // For the macro assert_relative_eq! +extern crate nalgebra as na; +use na::{Vector3, Rotation3}; + +fn main() { + let axis = Vector3::x_axis(); + let angle = 1.57; + let b = Rotation3::from_axis_angle(&axis, angle); + + assert_relative_eq!(b.axis().unwrap(), axis); + assert_relative_eq!(b.angle(), angle); +} +``` + + +## Features +**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with +an optimized set of tools for computer graphics and physics. Those features include: + +* A single parametrizable type [`Matrix`](Matrix) for vectors, (square or rectangular) matrices, and + slices with dimensions known either at compile-time (using type-level integers) or at runtime. +* Matrices and vectors with compile-time sizes are statically allocated while dynamic ones are + allocated on the heap. +* Convenient aliases for low-dimensional matrices and vectors: [`Vector1`](Vector1) to + [`Vector6`](Vector6) and [`Matrix1x1`](Matrix1) to [`Matrix6x6`](Matrix6), including rectangular + matrices like [`Matrix2x5`](Matrix2x5). +* Points sizes known at compile time, and convenience aliases: [`Point1`](Point1) to + [`Point6`](Point6). +* Translation (seen as a transformation that composes by multiplication): + [`Translation2`](Translation2), [`Translation3`](Translation3). +* Rotation matrices: [`Rotation2`](Rotation2), [`Rotation3`](Rotation3). +* Quaternions: [`Quaternion`](Quaternion), [`UnitQuaternion`](UnitQuaternion) (for 3D rotation). +* Unit complex numbers can be used for 2D rotation: [`UnitComplex`](UnitComplex). +* Algebraic entities with a norm equal to one: [`Unit`](Unit), e.g., `Unit>`. +* Isometries (translation ⨯ rotation): [`Isometry2`](Isometry2), [`Isometry3`](Isometry3) +* Similarity transformations (translation ⨯ rotation ⨯ uniform scale): + [`Similarity2`](Similarity2), [`Similarity3`](Similarity3). +* Affine transformations stored as a homogeneous matrix: + [`Affine2`](Affine2), [`Affine3`](Affine3). +* Projective (i.e. invertible) transformations stored as a homogeneous matrix: + [`Projective2`](Projective2), [`Projective3`](Projective3). +* General transformations that does not have to be invertible, stored as a homogeneous matrix: + [`Transform2`](Transform2), [`Transform3`](Transform3). +* 3D projections for computer graphics: [`Perspective3`](Perspective3), + [`Orthographic3`](Orthographic3). +* Matrix factorizations: [`Cholesky`](Cholesky), [`QR`](QR), [`LU`](LU), [`FullPivLU`](FullPivLU), + [`SVD`](SVD), [`Schur`](Schur), [`Hessenberg`](Hessenberg), [`SymmetricEigen`](SymmetricEigen). +* Insertion and removal of rows of columns of a matrix. +*/ + +#![deny( + missing_docs, + nonstandard_style, + unused_variables, + unused_mut, + unused_parens, + rust_2018_idioms, + rust_2018_compatibility, + future_incompatible, + missing_copy_implementations +)] +#![cfg_attr(not(feature = "rkyv-serialize-no-std"), deny(unused_results))] // TODO: deny this globally once bytecheck stops generating unused results. +#![doc( + html_favicon_url = "https://nalgebra.org/img/favicon.ico", + html_root_url = "https://docs.rs/nalgebra/0.25.0" +)] +#![cfg_attr(not(feature = "std"), no_std)] + +/// Generates an appropriate deprecation note with a suggestion for replacement. +/// +/// Used for deprecating slice types in various locations throughout the library. +/// See #1076 for more information. +macro_rules! slice_deprecation_note { + ($replacement:ident) => { + concat!("Use ", stringify!($replacement), + r###" instead. See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) for more information."###) + } +} + +pub(crate) use slice_deprecation_note; + +#[cfg(feature = "rand-no-std")] +extern crate rand_package as rand; + +#[cfg(feature = "serde-serialize-no-std")] +#[macro_use] +extern crate serde; + +#[macro_use] +extern crate approx; +extern crate num_traits as num; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[cfg_attr(test, macro_use)] +extern crate alloc; + +#[cfg(not(feature = "std"))] +extern crate core as std; + +#[macro_use] +#[cfg(feature = "io")] +extern crate pest_derive; + +pub mod base; +#[cfg(feature = "debug")] +pub mod debug; +pub mod geometry; +#[cfg(feature = "io")] +pub mod io; +pub mod linalg; +#[cfg(feature = "proptest-support")] +pub mod proptest; +#[cfg(feature = "sparse")] +pub mod sparse; +mod third_party; + +pub use crate::base::*; +pub use crate::geometry::*; +pub use crate::linalg::*; +#[cfg(feature = "sparse")] +pub use crate::sparse::*; +#[cfg(feature = "std")] +#[deprecated( + note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate." +)] +pub use base as core; + +#[cfg(feature = "macros")] +pub use nalgebra_macros::{dmatrix, dvector, matrix, point, stack, vector}; + +use simba::scalar::SupersetOf; +use std::cmp::{self, Ordering, PartialOrd}; + +use num::{One, Signed, Zero}; + +use base::allocator::Allocator; +pub use num_complex::Complex; +pub use simba::scalar::{ + ClosedAddAssign, ClosedDivAssign, ClosedMulAssign, ClosedSubAssign, ComplexField, Field, + RealField, +}; +pub use simba::simd::{SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField, SimdValue}; + +/// Gets the multiplicative identity element. +/// +/// # See also: +/// +/// * [`origin()`](crate::OPoint::origin) +/// * [`zero()`] +#[inline] +pub fn one() -> T { + T::one() +} + +/// Gets the additive identity element. +/// +/// # See also: +/// +/// * [`one()`] +/// * [`origin()`](crate::OPoint::origin) +#[inline] +pub fn zero() -> T { + T::zero() +} + +/* + * + * Ordering + * + */ +// XXX: this is very naive and could probably be optimized for specific types. +// XXX: also, we might just want to use divisions, but assuming `val` is usually not far from `min` +// or `max`, would it still be more efficient? +/// Wraps `val` into the range `[min, max]` using modular arithmetics. +/// +/// The range must not be empty. +#[must_use] +#[inline] +pub fn wrap(mut val: T, min: T, max: T) -> T +where + T: Copy + PartialOrd + ClosedAddAssign + ClosedSubAssign, +{ + assert!(min < max, "Invalid wrapping bounds."); + let width = max - min; + + if val < min { + val += width; + + while val < min { + val += width + } + } else if val > max { + val -= width; + + while val > max { + val -= width + } + } + + val +} + +/// Returns a reference to the input value clamped to the interval `[min, max]`. +/// +/// In particular: +/// * If `min < val < max`, this returns `val`. +/// * If `val <= min`, this returns `min`. +/// * If `val >= max`, this returns `max`. +#[must_use] +#[inline] +pub fn clamp(val: T, min: T, max: T) -> T { + if val > min { + if val < max { + val + } else { + max + } + } else { + min + } +} + +/// Same as `cmp::max`. +#[inline] +pub fn max(a: T, b: T) -> T { + cmp::max(a, b) +} + +/// Same as `cmp::min`. +#[inline] +pub fn min(a: T, b: T) -> T { + cmp::min(a, b) +} + +/// The absolute value of `a`. +/// +/// Deprecated: Use [`Matrix::abs()`] or [`ComplexField::abs()`] instead. +#[deprecated(note = "use the inherent method `Matrix::abs` or `ComplexField::abs` instead")] +#[inline] +pub fn abs(a: &T) -> T { + a.abs() +} + +/// Returns the infimum of `a` and `b`. +#[deprecated(note = "use the inherent method `Matrix::inf` instead")] +#[inline] +pub fn inf(a: &OMatrix, b: &OMatrix) -> OMatrix +where + T: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + a.inf(b) +} + +/// Returns the supremum of `a` and `b`. +#[deprecated(note = "use the inherent method `Matrix::sup` instead")] +#[inline] +pub fn sup(a: &OMatrix, b: &OMatrix) -> OMatrix +where + T: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + a.sup(b) +} + +/// Returns simultaneously the infimum and supremum of `a` and `b`. +#[deprecated(note = "use the inherent method `Matrix::inf_sup` instead")] +#[inline] +pub fn inf_sup( + a: &OMatrix, + b: &OMatrix, +) -> (OMatrix, OMatrix) +where + T: Scalar + SimdPartialOrd, + DefaultAllocator: Allocator, +{ + a.inf_sup(b) +} + +/// Compare `a` and `b` using a partial ordering relation. +#[inline] +pub fn partial_cmp(a: &T, b: &T) -> Option { + a.partial_cmp(b) +} + +/// Returns `true` iff `a` and `b` are comparable and `a < b`. +#[inline] +pub fn partial_lt(a: &T, b: &T) -> bool { + a.lt(b) +} + +/// Returns `true` iff `a` and `b` are comparable and `a <= b`. +#[inline] +pub fn partial_le(a: &T, b: &T) -> bool { + a.le(b) +} + +/// Returns `true` iff `a` and `b` are comparable and `a > b`. +#[inline] +pub fn partial_gt(a: &T, b: &T) -> bool { + a.gt(b) +} + +/// Returns `true` iff `a` and `b` are comparable and `a >= b`. +#[inline] +pub fn partial_ge(a: &T, b: &T) -> bool { + a.ge(b) +} + +/// Return the minimum of `a` and `b` if they are comparable. +#[inline] +pub fn partial_min<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> { + if let Some(ord) = a.partial_cmp(b) { + match ord { + Ordering::Greater => Some(b), + _ => Some(a), + } + } else { + None + } +} + +/// Return the maximum of `a` and `b` if they are comparable. +#[inline] +pub fn partial_max<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> { + if let Some(ord) = a.partial_cmp(b) { + match ord { + Ordering::Less => Some(b), + _ => Some(a), + } + } else { + None + } +} + +/// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to +/// `min` or `max`. +#[inline] +pub fn partial_clamp<'a, T: PartialOrd>(value: &'a T, min: &'a T, max: &'a T) -> Option<&'a T> { + if let (Some(cmp_min), Some(cmp_max)) = (value.partial_cmp(min), value.partial_cmp(max)) { + if cmp_min == Ordering::Less { + Some(min) + } else if cmp_max == Ordering::Greater { + Some(max) + } else { + Some(value) + } + } else { + None + } +} + +/// Sorts two values in increasing order using a partial ordering. +#[inline] +pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &'a T)> { + if let Some(ord) = a.partial_cmp(b) { + match ord { + Ordering::Less => Some((a, b)), + _ => Some((b, a)), + } + } else { + None + } +} + +/* + * + * Point operations. + * + */ +/// The center of two points. +/// +/// # See also: +/// +/// * [`distance()`] +/// * [`distance_squared()`] +#[inline] +pub fn center( + p1: &Point, + p2: &Point, +) -> Point { + ((&p1.coords + &p2.coords) * convert::<_, T>(0.5)).into() +} + +/// The distance between two points. +/// +/// # See also: +/// +/// * [`center()`] +/// * [`distance_squared()`] +#[inline] +pub fn distance( + p1: &Point, + p2: &Point, +) -> T::SimdRealField { + (&p2.coords - &p1.coords).norm() +} + +/// The squared distance between two points. +/// +/// # See also: +/// +/// * [`center()`] +/// * [`distance()`] +#[inline] +pub fn distance_squared( + p1: &Point, + p2: &Point, +) -> T::SimdRealField { + (&p2.coords - &p1.coords).norm_squared() +} + +/* + * Cast + */ +/// Converts an object from one type to an equivalent or more general one. +/// +/// See also [`try_convert()`] for conversion to more specific types. +/// +/// # See also: +/// +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] +#[inline] +pub fn convert>(t: From) -> To { + To::from_subset(&t) +} + +/// Attempts to convert an object to a more specific one. +/// +/// See also [`convert()`] for conversion to more general types. +/// +/// # See also: +/// +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert_ref()`] +#[inline] +pub fn try_convert, To>(t: From) -> Option { + t.to_subset() +} + +/// Indicates if [`try_convert()`] will succeed without +/// actually performing the conversion. +/// +/// # See also: +/// +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] +#[inline] +pub fn is_convertible, To>(t: &From) -> bool { + t.is_in_subset() +} + +/// Use with care! Same as [`try_convert()`] but +/// without any property checks. +/// +/// # See also: +/// +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] +#[inline] +pub fn convert_unchecked, To>(t: From) -> To { + t.to_subset_unchecked() +} + +/// Converts an object from one type to an equivalent or more general one. +/// +/// # See also: +/// +/// * [`convert()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] +#[inline] +pub fn convert_ref>(t: &From) -> To { + To::from_subset(t) +} + +/// Attempts to convert an object to a more specific one. +/// +/// # See also: +/// +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`convert_ref_unchecked()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +#[inline] +pub fn try_convert_ref, To>(t: &From) -> Option { + t.to_subset() +} + +/// Use with care! Same as [`try_convert()`] but +/// without any property checks. +/// +/// # See also: +/// +/// * [`convert()`] +/// * [`convert_ref()`] +/// * [`is_convertible()`] +/// * [`try_convert()`] +/// * [`try_convert_ref()`] +#[inline] +pub fn convert_ref_unchecked, To>(t: &From) -> To { + t.to_subset_unchecked() +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/balancing.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/balancing.rs new file mode 100644 index 000000000..268902033 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/balancing.rs @@ -0,0 +1,84 @@ +//! Functions for balancing a matrix. + +use simba::scalar::RealField; +use std::ops::{DivAssign, MulAssign}; + +use crate::allocator::Allocator; +use crate::base::dimension::Dim; +use crate::base::{Const, DefaultAllocator, OMatrix, OVector}; + +/// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix and returns +/// the corresponding diagonal transformation. +/// +/// See +pub fn balance_parlett_reinsch(matrix: &mut OMatrix) -> OVector +where + DefaultAllocator: Allocator + Allocator, +{ + assert!(matrix.is_square(), "Unable to balance a non-square matrix."); + + let dim = matrix.shape_generic().0; + let radix: T = crate::convert(2.0f64); + let mut d = OVector::from_element_generic(dim, Const::<1>, T::one()); + + let mut converged = false; + + while !converged { + converged = true; + + for i in 0..dim.value() { + let mut n_col = matrix.column(i).norm_squared(); + let mut n_row = matrix.row(i).norm_squared(); + let mut f = T::one(); + + let s = n_col.clone() + n_row.clone(); + n_col = n_col.sqrt(); + n_row = n_row.sqrt(); + + if n_col.clone().is_zero() || n_row.clone().is_zero() { + continue; + } + + while n_col.clone() < n_row.clone() / radix.clone() { + n_col *= radix.clone(); + n_row /= radix.clone(); + f *= radix.clone(); + } + + while n_col.clone() >= n_row.clone() * radix.clone() { + n_col /= radix.clone(); + n_row *= radix.clone(); + f /= radix.clone(); + } + + let eps: T = crate::convert(0.95); + #[allow(clippy::suspicious_operation_groupings)] + if n_col.clone() * n_col + n_row.clone() * n_row < eps * s { + converged = false; + d[i] *= f.clone(); + matrix.column_mut(i).mul_assign(f.clone()); + matrix.row_mut(i).div_assign(f.clone()); + } + } + } + + d +} + +/// Computes in-place `D * m * D.inverse()`, where `D` is the matrix with diagonal `d`. +pub fn unbalance(m: &mut OMatrix, d: &OVector) +where + DefaultAllocator: Allocator + Allocator, +{ + assert!(m.is_square(), "Unable to unbalance a non-square matrix."); + assert_eq!(m.nrows(), d.len(), "Unbalancing: mismatched dimensions."); + + for j in 0..d.len() { + let mut col = m.column_mut(j); + let denom = T::one() / d[j].clone(); + + for i in 0..d.len() { + col[i] *= d[i].clone() * denom.clone(); + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/bidiagonal.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/bidiagonal.rs new file mode 100644 index 000000000..708646d3d --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/bidiagonal.rs @@ -0,0 +1,384 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit}; +use crate::dimension::{Const, Dim, DimDiff, DimMin, DimMinimum, DimSub, U1}; +use simba::scalar::ComplexField; + +use crate::geometry::Reflection; +use crate::linalg::householder; +use crate::num::Zero; +use std::mem::MaybeUninit; + +/// The bidiagonalization of a general matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DimMinimum: DimSub, + DefaultAllocator: Allocator + + Allocator> + + Allocator, U1>>, + OMatrix: Serialize, + OVector>: Serialize, + OVector, U1>>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DimMinimum: DimSub, + DefaultAllocator: Allocator + + Allocator> + + Allocator, U1>>, + OMatrix: Deserialize<'de>, + OVector>: Deserialize<'de>, + OVector, U1>>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct Bidiagonal, C: Dim> +where + DimMinimum: DimSub, + DefaultAllocator: + Allocator + Allocator> + Allocator, U1>>, +{ + // TODO: perhaps we should pack the axes into different vectors so that axes for `v_t` are + // contiguous. This prevents some useless copies. + uv: OMatrix, + /// The diagonal elements of the decomposed matrix. + diagonal: OVector>, + /// The off-diagonal elements of the decomposed matrix. + off_diagonal: OVector, U1>>, + upper_diagonal: bool, +} + +impl, C: Dim> Copy for Bidiagonal +where + DimMinimum: DimSub, + DefaultAllocator: + Allocator + Allocator> + Allocator, U1>>, + OMatrix: Copy, + OVector>: Copy, + OVector, U1>>: Copy, +{ +} + +impl, C: Dim> Bidiagonal +where + DimMinimum: DimSub, + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator> + + Allocator, U1>>, +{ + /// Computes the Bidiagonal decomposition using householder reflections. + pub fn new(mut matrix: OMatrix) -> Self { + let (nrows, ncols) = matrix.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + let dim = min_nrows_ncols.value(); + assert!( + dim != 0, + "Cannot compute the bidiagonalization of an empty matrix." + ); + + let mut diagonal = Matrix::uninit(min_nrows_ncols, Const::<1>); + let mut off_diagonal = Matrix::uninit(min_nrows_ncols.sub(Const::<1>), Const::<1>); + let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>); + let mut work = Matrix::zeros_generic(nrows, Const::<1>); + + let upper_diagonal = nrows.value() >= ncols.value(); + if upper_diagonal { + for ite in 0..dim - 1 { + diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked( + &mut matrix, + ite, + 0, + None, + )); + off_diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked( + &mut matrix, + &mut axis_packed, + &mut work, + ite, + 1, + )); + } + + diagonal[dim - 1] = MaybeUninit::new(householder::clear_column_unchecked( + &mut matrix, + dim - 1, + 0, + None, + )); + } else { + for ite in 0..dim - 1 { + diagonal[ite] = MaybeUninit::new(householder::clear_row_unchecked( + &mut matrix, + &mut axis_packed, + &mut work, + ite, + 0, + )); + off_diagonal[ite] = MaybeUninit::new(householder::clear_column_unchecked( + &mut matrix, + ite, + 1, + None, + )); + } + + diagonal[dim - 1] = MaybeUninit::new(householder::clear_row_unchecked( + &mut matrix, + &mut axis_packed, + &mut work, + dim - 1, + 0, + )); + } + + // Safety: diagonal and off_diagonal have been fully initialized. + let (diagonal, off_diagonal) = + unsafe { (diagonal.assume_init(), off_diagonal.assume_init()) }; + + Bidiagonal { + uv: matrix, + diagonal, + off_diagonal, + upper_diagonal, + } + } + + /// Indicates whether this decomposition contains an upper-diagonal matrix. + #[inline] + #[must_use] + pub fn is_upper_diagonal(&self) -> bool { + self.upper_diagonal + } + + #[inline] + fn axis_shift(&self) -> (usize, usize) { + if self.upper_diagonal { + (0, 1) + } else { + (1, 0) + } + } + + /// Unpacks this decomposition into its three matrix factors `(U, D, V^t)`. + /// + /// The decomposed matrix `M` is equal to `U * D * V^t`. + #[inline] + pub fn unpack( + self, + ) -> ( + OMatrix>, + OMatrix, DimMinimum>, + OMatrix, C>, + ) + where + DefaultAllocator: Allocator, DimMinimum> + + Allocator> + + Allocator, C>, + { + // TODO: optimize by calling a reallocator. + (self.u(), self.d(), self.v_t()) + } + + /// Retrieves the upper trapezoidal submatrix `R` of this decomposition. + #[inline] + #[must_use] + pub fn d(&self) -> OMatrix, DimMinimum> + where + DefaultAllocator: Allocator, DimMinimum>, + { + let (nrows, ncols) = self.uv.shape_generic(); + + let d = nrows.min(ncols); + let mut res = OMatrix::identity_generic(d, d); + res.set_partial_diagonal( + self.diagonal + .iter() + .map(|e| T::from_real(e.clone().modulus())), + ); + + let start = self.axis_shift(); + res.view_mut(start, (d.value() - 1, d.value() - 1)) + .set_partial_diagonal( + self.off_diagonal + .iter() + .map(|e| T::from_real(e.clone().modulus())), + ); + res + } + + /// Computes the orthogonal matrix `U` of this `U * D * V` decomposition. + // TODO: code duplication with householder::assemble_q. + // Except that we are returning a rectangular matrix here. + #[must_use] + pub fn u(&self) -> OMatrix> + where + DefaultAllocator: Allocator>, + { + let (nrows, ncols) = self.uv.shape_generic(); + + let mut res = Matrix::identity_generic(nrows, nrows.min(ncols)); + let dim = self.diagonal.len(); + let shift = self.axis_shift().0; + + for i in (0..dim - shift).rev() { + let axis = self.uv.view_range(i + shift.., i); + + // Sometimes, the axis might have a zero magnitude. + if axis.norm_squared().is_zero() { + continue; + } + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + let mut res_rows = res.view_range_mut(i + shift.., i..); + + let sign = if self.upper_diagonal { + self.diagonal[i].clone().signum() + } else { + self.off_diagonal[i].clone().signum() + }; + + refl.reflect_with_sign(&mut res_rows, sign); + } + + res + } + + /// Computes the orthogonal matrix `V_t` of this `U * D * V_t` decomposition. + #[must_use] + pub fn v_t(&self) -> OMatrix, C> + where + DefaultAllocator: Allocator, C>, + { + let (nrows, ncols) = self.uv.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + + let mut res = Matrix::identity_generic(min_nrows_ncols, ncols); + let mut work = Matrix::zeros_generic(min_nrows_ncols, Const::<1>); + let mut axis_packed = Matrix::zeros_generic(ncols, Const::<1>); + + let shift = self.axis_shift().1; + + for i in (0..min_nrows_ncols.value() - shift).rev() { + let axis = self.uv.view_range(i, i + shift..); + let mut axis_packed = axis_packed.rows_range_mut(i + shift..); + axis_packed.tr_copy_from(&axis); + + // Sometimes, the axis might have a zero magnitude. + if axis_packed.norm_squared().is_zero() { + continue; + } + let refl = Reflection::new(Unit::new_unchecked(axis_packed), T::zero()); + + let mut res_rows = res.view_range_mut(i.., i + shift..); + + let sign = if self.upper_diagonal { + self.off_diagonal[i].clone().signum() + } else { + self.diagonal[i].clone().signum() + }; + + refl.reflect_rows_with_sign(&mut res_rows, &mut work.rows_range_mut(i..), sign); + } + + res + } + + /// The diagonal part of this decomposed matrix. + #[must_use] + pub fn diagonal(&self) -> OVector> + where + DefaultAllocator: Allocator>, + { + self.diagonal.map(|e| e.modulus()) + } + + /// The off-diagonal part of this decomposed matrix. + #[must_use] + pub fn off_diagonal(&self) -> OVector, U1>> + where + DefaultAllocator: Allocator, U1>>, + { + self.off_diagonal.map(|e| e.modulus()) + } + + #[doc(hidden)] + pub fn uv_internal(&self) -> &OMatrix { + &self.uv + } +} + +// impl + DimSub> Bidiagonal +// where DefaultAllocator: Allocator + +// Allocator { +// /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. +// pub fn solve(&self, b: &Matrix) -> OMatrix +// where S2: StorageMut, +// ShapeConstraint: SameNumberOfRows { +// let mut res = b.clone_owned(); +// self.solve_mut(&mut res); +// res +// } +// +// /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. +// pub fn solve_mut(&self, b: &mut Matrix) +// where S2: StorageMut, +// ShapeConstraint: SameNumberOfRows { +// +// assert_eq!(self.uv.nrows(), b.nrows(), "Bidiagonal solve matrix dimension mismatch."); +// assert!(self.uv.is_square(), "Bidiagonal solve: unable to solve a non-square system."); +// +// self.q_tr_mul(b); +// self.solve_upper_triangular_mut(b); +// } +// +// // TODO: duplicate code from the `solve` module. +// fn solve_upper_triangular_mut(&self, b: &mut Matrix) +// where S2: StorageMut, +// ShapeConstraint: SameNumberOfRows { +// +// let dim = self.uv.nrows(); +// +// for k in 0 .. b.ncols() { +// let mut b = b.column_mut(k); +// for i in (0 .. dim).rev() { +// let coeff; +// +// unsafe { +// let diag = *self.diag.vget_unchecked(i); +// coeff = *b.vget_unchecked(i) / diag; +// *b.vget_unchecked_mut(i) = coeff; +// } +// +// b.rows_range_mut(.. i).axpy(-coeff, &self.uv.view_range(.. i, i), T::one()); +// } +// } +// } +// +// /// Computes the inverse of the decomposed matrix. +// pub fn inverse(&self) -> OMatrix { +// assert!(self.uv.is_square(), "Bidiagonal inverse: unable to compute the inverse of a non-square matrix."); +// +// // TODO: is there a less naive method ? +// let (nrows, ncols) = self.uv.shape_generic(); +// let mut res = OMatrix::identity_generic(nrows, ncols); +// self.solve_mut(&mut res); +// res +// } +// +// // /// Computes the determinant of the decomposed matrix. +// // pub fn determinant(&self) -> T { +// // let dim = self.uv.nrows(); +// // assert!(self.uv.is_square(), "Bidiagonal determinant: unable to compute the determinant of a non-square matrix."); +// +// // let mut res = T::one(); +// // for i in 0 .. dim { +// // res *= unsafe { *self.diag.vget_unchecked(i) }; +// // } +// +// // res self.q_determinant() +// // } +// } diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/cholesky.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/cholesky.rs new file mode 100644 index 000000000..7801fb4e7 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/cholesky.rs @@ -0,0 +1,441 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use num::{One, Zero}; +use simba::scalar::ComplexField; +use simba::simd::SimdComplexField; + +use crate::allocator::Allocator; +use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, Vector}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum, U1}; +use crate::storage::{Storage, StorageMut}; + +/// The Cholesky decomposition of a symmetric-definite-positive matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator, + OMatrix: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator, + OMatrix: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct Cholesky +where + DefaultAllocator: Allocator, +{ + chol: OMatrix, +} + +impl Copy for Cholesky +where + DefaultAllocator: Allocator, + OMatrix: Copy, +{ +} + +impl Cholesky +where + DefaultAllocator: Allocator, +{ + /// Computes the Cholesky decomposition of `matrix` without checking that the matrix is definite-positive. + /// + /// If the input matrix is not definite-positive, the decomposition may contain trash values (Inf, NaN, etc.) + pub fn new_unchecked(mut matrix: OMatrix) -> Self { + assert!(matrix.is_square(), "The input matrix must be square."); + + let n = matrix.nrows(); + + for j in 0..n { + for k in 0..j { + let factor = unsafe { -matrix.get_unchecked((j, k)).clone() }; + + let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k); + let mut col_j = col_j.rows_range_mut(j..); + let col_k = col_k.rows_range(j..); + col_j.axpy(factor.simd_conjugate(), &col_k, T::one()); + } + + let diag = unsafe { matrix.get_unchecked((j, j)).clone() }; + let denom = diag.simd_sqrt(); + + unsafe { + *matrix.get_unchecked_mut((j, j)) = denom.clone(); + } + + let mut col = matrix.view_range_mut(j + 1.., j); + col /= denom; + } + + Cholesky { chol: matrix } + } + + /// Uses the given matrix as-is without any checks or modifications as the + /// Cholesky decomposition. + /// + /// It is up to the user to ensure all invariants hold. + pub fn pack_dirty(matrix: OMatrix) -> Self { + Cholesky { chol: matrix } + } + + /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly + /// upper-triangular part filled with zeros. + pub fn unpack(mut self) -> OMatrix { + self.chol.fill_upper_triangle(T::zero(), 1); + self.chol + } + + /// Retrieves the lower-triangular factor of the Cholesky decomposition, without zeroing-out + /// its strict upper-triangular part. + /// + /// The values of the strict upper-triangular part are garbage and should be ignored by further + /// computations. + pub fn unpack_dirty(self) -> OMatrix { + self.chol + } + + /// Retrieves the lower-triangular factor of the Cholesky decomposition with its strictly + /// uppen-triangular part filled with zeros. + #[must_use] + pub fn l(&self) -> OMatrix { + self.chol.lower_triangle() + } + + /// Retrieves the lower-triangular factor of the Cholesky decomposition, without zeroing-out + /// its strict upper-triangular part. + /// + /// This is an allocation-less version of `self.l()`. The values of the strict upper-triangular + /// part are garbage and should be ignored by further computations. + #[must_use] + pub fn l_dirty(&self) -> &OMatrix { + &self.chol + } + + /// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown. + /// + /// The result is stored on `b`. + pub fn solve_mut(&self, b: &mut Matrix) + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + self.chol.solve_lower_triangular_unchecked_mut(b); + self.chol.ad_solve_lower_triangular_unchecked_mut(b); + } + + /// Returns the solution of the system `self * x = b` where `self` is the decomposed matrix and + /// `x` the unknown. + #[must_use = "Did you mean to use solve_mut()?"] + pub fn solve(&self, b: &Matrix) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.solve_mut(&mut res); + res + } + + /// Computes the inverse of the decomposed matrix. + #[must_use] + pub fn inverse(&self) -> OMatrix { + let shape = self.chol.shape_generic(); + let mut res = OMatrix::identity_generic(shape.0, shape.1); + + self.solve_mut(&mut res); + res + } + + /// Computes the determinant of the decomposed matrix. + #[must_use] + pub fn determinant(&self) -> T::SimdRealField { + let dim = self.chol.nrows(); + let mut prod_diag = T::one(); + for i in 0..dim { + prod_diag *= unsafe { self.chol.get_unchecked((i, i)).clone() }; + } + prod_diag.simd_modulus_squared() + } + + /// Computes the natural logarithm of determinant of the decomposed matrix. + /// + /// This method is more robust than `.determinant()` to very small or very + /// large determinants since it returns the natural logarithm of the + /// determinant rather than the determinant itself. + #[must_use] + pub fn ln_determinant(&self) -> T::SimdRealField { + let dim = self.chol.nrows(); + let mut sum_diag = T::SimdRealField::zero(); + for i in 0..dim { + sum_diag += unsafe { + self.chol + .get_unchecked((i, i)) + .clone() + .simd_modulus_squared() + .simd_ln() + }; + } + sum_diag + } +} + +impl Cholesky +where + DefaultAllocator: Allocator, +{ + /// Attempts to compute the Cholesky decomposition of `matrix`. + /// + /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed + /// to be symmetric and only the lower-triangular part is read. + pub fn new(matrix: OMatrix) -> Option { + Self::new_internal(matrix, None) + } + + /// Attempts to approximate the Cholesky decomposition of `matrix` by + /// replacing non-positive values on the diagonals during the decomposition + /// with the given `substitute`. + /// + /// [`try_sqrt`](ComplexField::try_sqrt) will be applied to the `substitute` + /// when it has to be used. + /// + /// If your input matrix results only in positive values on the diagonals + /// during the decomposition, `substitute` is unused and the result is just + /// the same as if you used [`new`](Cholesky::new). + /// + /// This method allows to compensate for matrices with very small or even + /// negative values due to numerical errors but necessarily results in only + /// an approximation: it is basically a hack. If you don't specifically need + /// Cholesky, it may be better to consider alternatives like the + /// [`LU`](crate::linalg::LU) decomposition/factorization. + pub fn new_with_substitute(matrix: OMatrix, substitute: T) -> Option { + Self::new_internal(matrix, Some(substitute)) + } + + /// Common implementation for `new` and `new_with_substitute`. + fn new_internal(mut matrix: OMatrix, substitute: Option) -> Option { + assert!(matrix.is_square(), "The input matrix must be square."); + + let n = matrix.nrows(); + + for j in 0..n { + for k in 0..j { + let factor = unsafe { -matrix.get_unchecked((j, k)).clone() }; + + let (mut col_j, col_k) = matrix.columns_range_pair_mut(j, k); + let mut col_j = col_j.rows_range_mut(j..); + let col_k = col_k.rows_range(j..); + + col_j.axpy(factor.conjugate(), &col_k, T::one()); + } + + let sqrt_denom = |v: T| { + if v.is_zero() { + return None; + } + v.try_sqrt() + }; + + let diag = unsafe { matrix.get_unchecked((j, j)).clone() }; + + if let Some(denom) = + sqrt_denom(diag).or_else(|| substitute.clone().and_then(sqrt_denom)) + { + unsafe { + *matrix.get_unchecked_mut((j, j)) = denom.clone(); + } + + let mut col = matrix.view_range_mut(j + 1.., j); + col /= denom; + continue; + } + + // The diagonal element is either zero or its square root could not + // be taken (e.g. for negative real numbers). + return None; + } + + Some(Cholesky { chol: matrix }) + } + + /// Given the Cholesky decomposition of a matrix `M`, a scalar `sigma` and a vector `v`, + /// performs a rank one update such that we end up with the decomposition of `M + sigma * (v * v.adjoint())`. + #[inline] + pub fn rank_one_update(&mut self, x: &Vector, sigma: T::RealField) + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + Self::xx_rank_one_update(&mut self.chol, &mut x.clone_owned(), sigma) + } + + /// Updates the decomposition such that we get the decomposition of a matrix with the given column `col` in the `j`th position. + /// Since the matrix is square, an identical row will be added in the `j`th row. + pub fn insert_column( + &self, + j: usize, + col: Vector, + ) -> Cholesky> + where + D: DimAdd, + R2: Dim, + S2: Storage, + DefaultAllocator: Allocator, DimSum> + Allocator, + ShapeConstraint: SameNumberOfRows>, + { + let mut col = col.into_owned(); + // for an explanation of the formulas, see https://en.wikipedia.org/wiki/Cholesky_decomposition#Updating_the_decomposition + let n = col.nrows(); + assert_eq!( + n, + self.chol.nrows() + 1, + "The new column must have the size of the factored matrix plus one." + ); + assert!(j < n, "j needs to be within the bound of the new matrix."); + + // loads the data into a new matrix with an additional jth row/column + // TODO: would it be worth it to avoid the zero-initialization? + let mut chol = Matrix::zeros_generic( + self.chol.shape_generic().0.add(Const::<1>), + self.chol.shape_generic().1.add(Const::<1>), + ); + chol.view_range_mut(..j, ..j) + .copy_from(&self.chol.view_range(..j, ..j)); + chol.view_range_mut(..j, j + 1..) + .copy_from(&self.chol.view_range(..j, j..)); + chol.view_range_mut(j + 1.., ..j) + .copy_from(&self.chol.view_range(j.., ..j)); + chol.view_range_mut(j + 1.., j + 1..) + .copy_from(&self.chol.view_range(j.., j..)); + + // update the jth row + let top_left_corner = self.chol.view_range(..j, ..j); + + let col_j = col[j].clone(); + let (mut new_rowj_adjoint, mut new_colj) = col.rows_range_pair_mut(..j, j + 1..); + assert!( + top_left_corner.solve_lower_triangular_mut(&mut new_rowj_adjoint), + "Cholesky::insert_column : Unable to solve lower triangular system!" + ); + + new_rowj_adjoint.adjoint_to(&mut chol.view_range_mut(j, ..j)); + + // update the center element + let center_element = T::sqrt(col_j - T::from_real(new_rowj_adjoint.norm_squared())); + chol[(j, j)] = center_element.clone(); + + // update the jth column + let bottom_left_corner = self.chol.view_range(j.., ..j); + // new_colj = (col_jplus - bottom_left_corner * new_rowj.adjoint()) / center_element; + new_colj.gemm( + -T::one() / center_element.clone(), + &bottom_left_corner, + &new_rowj_adjoint, + T::one() / center_element, + ); + chol.view_range_mut(j + 1.., j).copy_from(&new_colj); + + // update the bottom right corner + let mut bottom_right_corner = chol.view_range_mut(j + 1.., j + 1..); + Self::xx_rank_one_update( + &mut bottom_right_corner, + &mut new_colj, + -T::RealField::one(), + ); + + Cholesky { chol } + } + + /// Updates the decomposition such that we get the decomposition of the factored matrix with its `j`th column removed. + /// Since the matrix is square, the `j`th row will also be removed. + #[must_use] + pub fn remove_column(&self, j: usize) -> Cholesky> + where + D: DimSub, + DefaultAllocator: Allocator, DimDiff> + Allocator, + { + let n = self.chol.nrows(); + assert!(n > 0, "The matrix needs at least one column."); + assert!(j < n, "j needs to be within the bound of the matrix."); + + // loads the data into a new matrix except for the jth row/column + // TODO: would it be worth it to avoid this zero initialization? + let mut chol = Matrix::zeros_generic( + self.chol.shape_generic().0.sub(Const::<1>), + self.chol.shape_generic().1.sub(Const::<1>), + ); + chol.view_range_mut(..j, ..j) + .copy_from(&self.chol.view_range(..j, ..j)); + chol.view_range_mut(..j, j..) + .copy_from(&self.chol.view_range(..j, j + 1..)); + chol.view_range_mut(j.., ..j) + .copy_from(&self.chol.view_range(j + 1.., ..j)); + chol.view_range_mut(j.., j..) + .copy_from(&self.chol.view_range(j + 1.., j + 1..)); + + // updates the bottom right corner + let mut bottom_right_corner = chol.view_range_mut(j.., j..); + let mut workspace = self.chol.column(j).clone_owned(); + let mut old_colj = workspace.rows_range_mut(j + 1..); + Self::xx_rank_one_update(&mut bottom_right_corner, &mut old_colj, T::RealField::one()); + + Cholesky { chol } + } + + /// Given the Cholesky decomposition of a matrix `M`, a scalar `sigma` and a vector `x`, + /// performs a rank one update such that we end up with the decomposition of `M + sigma * (x * x.adjoint())`. + /// + /// This helper method is called by `rank_one_update` but also `insert_column` and `remove_column` + /// where it is used on a square view of the decomposition + fn xx_rank_one_update( + chol: &mut Matrix, + x: &mut Vector, + sigma: T::RealField, + ) where + //T: ComplexField, + Dm: Dim, + Rx: Dim, + Sm: StorageMut, + Sx: StorageMut, + { + // heavily inspired by Eigen's `llt_rank_update_lower` implementation https://eigen.tuxfamily.org/dox/LLT_8h_source.html + let n = x.nrows(); + assert_eq!( + n, + chol.nrows(), + "The input vector must be of the same size as the factorized matrix." + ); + + let mut beta = crate::one::(); + + for j in 0..n { + // updates the diagonal + let diag = T::real(unsafe { chol.get_unchecked((j, j)).clone() }); + let diag2 = diag.clone() * diag.clone(); + let xj = unsafe { x.get_unchecked(j).clone() }; + let sigma_xj2 = sigma.clone() * T::modulus_squared(xj.clone()); + let gamma = diag2.clone() * beta.clone() + sigma_xj2.clone(); + let new_diag = (diag2.clone() + sigma_xj2.clone() / beta.clone()).sqrt(); + unsafe { *chol.get_unchecked_mut((j, j)) = T::from_real(new_diag.clone()) }; + beta += sigma_xj2 / diag2; + // updates the terms of L + let mut xjplus = x.rows_range_mut(j + 1..); + let mut col_j = chol.view_range_mut(j + 1.., j); + // temp_jplus -= (wj / T::from_real(diag)) * col_j; + xjplus.axpy(-xj.clone() / T::from_real(diag.clone()), &col_j, T::one()); + if gamma != crate::zero::() { + // col_j = T::from_real(nljj / diag) * col_j + (T::from_real(nljj * sigma / gamma) * T::conjugate(wj)) * temp_jplus; + col_j.axpy( + T::from_real(new_diag.clone() * sigma.clone() / gamma) * T::conjugate(xj), + &xjplus, + T::from_real(new_diag / diag), + ); + } + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/col_piv_qr.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/col_piv_qr.rs new file mode 100644 index 000000000..1e48a98dd --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/col_piv_qr.rs @@ -0,0 +1,337 @@ +use num::Zero; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::{Allocator, Reallocator}; +use crate::base::{Const, DefaultAllocator, Matrix, OMatrix, OVector, Unit}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Dim, DimMin, DimMinimum}; +use crate::storage::StorageMut; +use crate::ComplexField; + +use crate::geometry::Reflection; +use crate::linalg::{householder, PermutationSequence}; +use std::mem::MaybeUninit; + +/// The QR decomposition (with column pivoting) of a general matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Serialize, + PermutationSequence>: Serialize, + OVector>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Deserialize<'de>, + PermutationSequence>: Deserialize<'de>, + OVector>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct ColPivQR, C: Dim> +where + DefaultAllocator: Allocator + Allocator>, +{ + col_piv_qr: OMatrix, + p: PermutationSequence>, + diag: OVector>, +} + +impl, C: Dim> Copy for ColPivQR +where + DefaultAllocator: Allocator + Allocator>, + OMatrix: Copy, + PermutationSequence>: Copy, + OVector>: Copy, +{ +} + +impl, C: Dim> ColPivQR +where + DefaultAllocator: Allocator + Allocator + Allocator>, +{ + /// Computes the `ColPivQR` decomposition using householder reflections. + pub fn new(mut matrix: OMatrix) -> Self { + let (nrows, ncols) = matrix.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + let mut p = PermutationSequence::identity_generic(min_nrows_ncols); + + if min_nrows_ncols.value() == 0 { + return ColPivQR { + col_piv_qr: matrix, + p, + diag: Matrix::zeros_generic(min_nrows_ncols, Const::<1>), + }; + } + + let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>); + + for i in 0..min_nrows_ncols.value() { + let piv = matrix.view_range(i.., i..).icamax_full(); + let col_piv = piv.1 + i; + matrix.swap_columns(i, col_piv); + p.append_permutation(i, col_piv); + + diag[i] = + MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None)); + } + + // Safety: diag is now fully initialized. + let diag = unsafe { diag.assume_init() }; + + ColPivQR { + col_piv_qr: matrix, + p, + diag, + } + } + + /// Retrieves the upper trapezoidal submatrix `R` of this decomposition. + #[inline] + #[must_use] + pub fn r(&self) -> OMatrix, C> + where + DefaultAllocator: Allocator, C>, + { + let (nrows, ncols) = self.col_piv_qr.shape_generic(); + let mut res = self + .col_piv_qr + .rows_generic(0, nrows.min(ncols)) + .upper_triangle(); + res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.clone().modulus()))); + res + } + + /// Retrieves the upper trapezoidal submatrix `R` of this decomposition. + /// + /// This is usually faster than `r` but consumes `self`. + #[inline] + pub fn unpack_r(self) -> OMatrix, C> + where + DefaultAllocator: Reallocator, C>, + { + let (nrows, ncols) = self.col_piv_qr.shape_generic(); + let mut res = self + .col_piv_qr + .resize_generic(nrows.min(ncols), ncols, T::zero()); + res.fill_lower_triangle(T::zero(), 1); + res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.clone().modulus()))); + res + } + + /// Computes the orthogonal matrix `Q` of this decomposition. + #[must_use] + pub fn q(&self) -> OMatrix> + where + DefaultAllocator: Allocator>, + { + let (nrows, ncols) = self.col_piv_qr.shape_generic(); + + // NOTE: we could build the identity matrix and call q_mul on it. + // Instead we don't so that we take in account the matrix sparseness. + let mut res = Matrix::identity_generic(nrows, nrows.min(ncols)); + let dim = self.diag.len(); + + for i in (0..dim).rev() { + let axis = self.col_piv_qr.view_range(i.., i); + // TODO: sometimes, the axis might have a zero magnitude. + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + let mut res_rows = res.view_range_mut(i.., i..); + refl.reflect_with_sign(&mut res_rows, self.diag[i].clone().signum()); + } + + res + } + /// Retrieves the column permutation of this decomposition. + #[inline] + #[must_use] + pub fn p(&self) -> &PermutationSequence> { + &self.p + } + + /// Unpacks this decomposition into its two matrix factors. + pub fn unpack( + self, + ) -> ( + OMatrix>, + OMatrix, C>, + PermutationSequence>, + ) + where + DimMinimum: DimMin>, + DefaultAllocator: Allocator> + + Reallocator, C> + + Allocator>, + { + (self.q(), self.r(), self.p) + } + + #[doc(hidden)] + pub fn col_piv_qr_internal(&self) -> &OMatrix { + &self.col_piv_qr + } + + /// Multiplies the provided matrix by the transpose of the `Q` matrix of this decomposition. + pub fn q_tr_mul(&self, rhs: &mut Matrix) + where + S2: StorageMut, + { + let dim = self.diag.len(); + + for i in 0..dim { + let axis = self.col_piv_qr.view_range(i.., i); + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + let mut rhs_rows = rhs.rows_range_mut(i..); + refl.reflect_with_sign(&mut rhs_rows, self.diag[i].clone().signum().conjugate()); + } + } +} + +impl> ColPivQR +where + DefaultAllocator: Allocator + Allocator + Allocator>, +{ + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// Returns `None` if `self` is not invertible. + #[must_use = "Did you mean to use solve_mut()?"] + pub fn solve( + &self, + b: &Matrix, + ) -> Option> + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator, + { + let mut res = b.clone_owned(); + + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// If the decomposed matrix is not invertible, this returns `false` and its input `b` is + /// overwritten with garbage. + pub fn solve_mut(&self, b: &mut Matrix) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + assert_eq!( + self.col_piv_qr.nrows(), + b.nrows(), + "ColPivQR solve matrix dimension mismatch." + ); + assert!( + self.col_piv_qr.is_square(), + "ColPivQR solve: unable to solve a non-square system." + ); + + self.q_tr_mul(b); + let solved = self.solve_upper_triangular_mut(b); + self.p.inv_permute_rows(b); + + solved + } + + // TODO: duplicate code from the `solve` module. + fn solve_upper_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.col_piv_qr.nrows(); + + for k in 0..b.ncols() { + let mut b = b.column_mut(k); + for i in (0..dim).rev() { + let coeff; + + unsafe { + let diag = self.diag.vget_unchecked(i).clone().modulus(); + + if diag.is_zero() { + return false; + } + + coeff = b.vget_unchecked(i).clone().unscale(diag); + *b.vget_unchecked_mut(i) = coeff.clone(); + } + + b.rows_range_mut(..i) + .axpy(-coeff, &self.col_piv_qr.view_range(..i, i), T::one()); + } + } + + true + } + + /// Computes the inverse of the decomposed matrix. + /// + /// Returns `None` if the decomposed matrix is not invertible. + #[must_use] + pub fn try_inverse(&self) -> Option> { + assert!( + self.col_piv_qr.is_square(), + "ColPivQR inverse: unable to compute the inverse of a non-square matrix." + ); + + // TODO: is there a less naive method ? + let (nrows, ncols) = self.col_piv_qr.shape_generic(); + let mut res = OMatrix::identity_generic(nrows, ncols); + + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Indicates if the decomposed matrix is invertible. + #[must_use] + pub fn is_invertible(&self) -> bool { + assert!( + self.col_piv_qr.is_square(), + "ColPivQR: unable to test the invertibility of a non-square matrix." + ); + + for i in 0..self.diag.len() { + if self.diag[i].is_zero() { + return false; + } + } + + true + } + + /// Computes the determinant of the decomposed matrix. + #[must_use] + pub fn determinant(&self) -> T { + let dim = self.col_piv_qr.nrows(); + assert!( + self.col_piv_qr.is_square(), + "ColPivQR determinant: unable to compute the determinant of a non-square matrix." + ); + + let mut res = T::one(); + for i in 0..dim { + res *= unsafe { self.diag.vget_unchecked(i).clone() }; + } + + res * self.p.determinant() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/convolution.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/convolution.rs new file mode 100644 index 000000000..717b058de --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/convolution.rs @@ -0,0 +1,144 @@ +use std::cmp; + +use crate::base::allocator::Allocator; +use crate::base::default_allocator::DefaultAllocator; +use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimSub, DimSum}; +use crate::storage::Storage; +use crate::{zero, OVector, RealField, Vector, U1}; + +impl> Vector { + /// Returns the convolution of the target vector and a kernel. + /// + /// # Arguments + /// + /// * `kernel` - A Vector with size > 0 + /// + /// # Errors + /// Inputs must satisfy `vector.len() >= kernel.len() > 0`. + /// + pub fn convolve_full( + &self, + kernel: Vector, + ) -> OVector, U1>> + where + D1: DimAdd, + D2: DimAdd>, + DimSum: DimSub, + S2: Storage, + DefaultAllocator: Allocator, U1>>, + { + let vec = self.len(); + let ker = kernel.len(); + + if ker == 0 || ker > vec { + panic!("convolve_full expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.", vec, ker); + } + + let result_len = self + .data + .shape() + .0 + .add(kernel.shape_generic().0) + .sub(Const::<1>); + let mut conv = OVector::zeros_generic(result_len, Const::<1>); + + for i in 0..(vec + ker - 1) { + let u_i = if i > vec { i - ker } else { 0 }; + let u_f = cmp::min(i, vec - 1); + + if u_i == u_f { + conv[i] += self[u_i].clone() * kernel[i - u_i].clone(); + } else { + for u in u_i..(u_f + 1) { + if i - u < ker { + conv[i] += self[u].clone() * kernel[i - u].clone(); + } + } + } + } + conv + } + /// Returns the convolution of the target vector and a kernel. + /// + /// The output convolution consists only of those elements that do not rely on the zero-padding. + /// # Arguments + /// + /// * `kernel` - A Vector with size > 0 + /// + /// + /// # Errors + /// Inputs must satisfy `self.len() >= kernel.len() > 0`. + /// + pub fn convolve_valid( + &self, + kernel: Vector, + ) -> OVector, D2>> + where + D1: DimAdd, + D2: Dim, + DimSum: DimSub, + S2: Storage, + DefaultAllocator: Allocator, D2>>, + { + let vec = self.len(); + let ker = kernel.len(); + + if ker == 0 || ker > vec { + panic!("convolve_valid expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); + } + + let result_len = self + .data + .shape() + .0 + .add(Const::<1>) + .sub(kernel.shape_generic().0); + let mut conv = OVector::zeros_generic(result_len, Const::<1>); + + for i in 0..(vec - ker + 1) { + for j in 0..ker { + conv[i] += self[i + j].clone() * kernel[ker - j - 1].clone(); + } + } + conv + } + + /// Returns the convolution of the target vector and a kernel. + /// + /// The output convolution is the same size as vector, centered with respect to the ‘full’ output. + /// # Arguments + /// + /// * `kernel` - A Vector with size > 0 + /// + /// # Errors + /// Inputs must satisfy `self.len() >= kernel.len() > 0`. + #[must_use] + pub fn convolve_same(&self, kernel: Vector) -> OVector + where + D2: Dim, + S2: Storage, + DefaultAllocator: Allocator, + { + let vec = self.len(); + let ker = kernel.len(); + + if ker == 0 || ker > vec { + panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); + } + + let mut conv = OVector::zeros_generic(self.shape_generic().0, Const::<1>); + + for i in 0..vec { + for j in 0..ker { + let val = if i + j < 1 || i + j >= vec + 1 { + zero::() + } else { + self[i + j - 1].clone() + }; + conv[i] += val * kernel[ker - j - 1].clone(); + } + } + + conv + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/decomposition.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/decomposition.rs new file mode 100644 index 000000000..674a5b8d5 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/decomposition.rs @@ -0,0 +1,364 @@ +use crate::storage::Storage; +use crate::{ + Allocator, Bidiagonal, Cholesky, ColPivQR, ComplexField, DefaultAllocator, Dim, DimDiff, + DimMin, DimMinimum, DimSub, FullPivLU, Hessenberg, Matrix, OMatrix, RealField, Schur, + SymmetricEigen, SymmetricTridiagonal, LU, QR, SVD, U1, UDU, +}; + +/// # Rectangular matrix decomposition +/// +/// This section contains the methods for computing some common decompositions of rectangular +/// matrices with real or complex components. The following are currently supported: +/// +/// | Decomposition | Factors | Details | +/// | -------------------------|---------------------|--------------| +/// | QR | `Q * R` | `Q` is an unitary matrix, and `R` is upper-triangular. | +/// | QR with column pivoting | `Q * R * P⁻¹` | `Q` is an unitary matrix, and `R` is upper-triangular. `P` is a permutation matrix. | +/// | LU with partial pivoting | `P⁻¹ * L * U` | `L` is lower-triangular with a diagonal filled with `1` and `U` is upper-triangular. `P` is a permutation matrix. | +/// | LU with full pivoting | `P⁻¹ * L * U * Q⁻¹` | `L` is lower-triangular with a diagonal filled with `1` and `U` is upper-triangular. `P` and `Q` are permutation matrices. | +/// | SVD | `U * Σ * Vᵀ` | `U` and `V` are two orthogonal matrices and `Σ` is a diagonal matrix containing the singular values. | +/// | Polar (Left Polar) | `P' * U` | `U` is semi-unitary/unitary and `P'` is a positive semi-definite Hermitian Matrix +impl> Matrix { + /// Computes the bidiagonalization using householder reflections. + pub fn bidiagonalize(self) -> Bidiagonal + where + R: DimMin, + DimMinimum: DimSub, + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator> + + Allocator, U1>>, + { + Bidiagonal::new(self.into_owned()) + } + + /// Computes the LU decomposition with full pivoting of `matrix`. + /// + /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`. + pub fn full_piv_lu(self) -> FullPivLU + where + R: DimMin, + DefaultAllocator: Allocator + Allocator>, + { + FullPivLU::new(self.into_owned()) + } + + /// Computes the LU decomposition with partial (row) pivoting of `matrix`. + pub fn lu(self) -> LU + where + R: DimMin, + DefaultAllocator: Allocator + Allocator>, + { + LU::new(self.into_owned()) + } + + /// Computes the QR decomposition of this matrix. + pub fn qr(self) -> QR + where + R: DimMin, + DefaultAllocator: Allocator + Allocator + Allocator>, + { + QR::new(self.into_owned()) + } + + /// Computes the QR decomposition (with column pivoting) of this matrix. + pub fn col_piv_qr(self) -> ColPivQR + where + R: DimMin, + DefaultAllocator: Allocator + + Allocator + + Allocator> + + Allocator>, + { + ColPivQR::new(self.into_owned()) + } + + /// Computes the Singular Value Decomposition using implicit shift. + /// The singular values are guaranteed to be sorted in descending order. + /// If this order is not required consider using `svd_unordered`. + pub fn svd(self, compute_u: bool, compute_v: bool) -> SVD + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator>, + { + SVD::new(self.into_owned(), compute_u, compute_v) + } + + /// Computes the Singular Value Decomposition using implicit shift. + /// The singular values are not guaranteed to be sorted in any particular order. + /// If a descending order is required, consider using `svd` instead. + pub fn svd_unordered(self, compute_u: bool, compute_v: bool) -> SVD + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator>, + { + SVD::new_unordered(self.into_owned(), compute_u, compute_v) + } + + /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. + /// The singular values are guaranteed to be sorted in descending order. + /// If this order is not required consider using `try_svd_unordered`. + /// + /// # Arguments + /// + /// * `compute_u` − set this to `true` to enable the computation of left-singular vectors. + /// * `compute_v` − set this to `true` to enable the computation of right-singular vectors. + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_svd( + self, + compute_u: bool, + compute_v: bool, + eps: T::RealField, + max_niter: usize, + ) -> Option> + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator>, + { + SVD::try_new(self.into_owned(), compute_u, compute_v, eps, max_niter) + } + + /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. + /// The singular values are not guaranteed to be sorted in any particular order. + /// If a descending order is required, consider using `try_svd` instead. + /// + /// # Arguments + /// + /// * `compute_u` − set this to `true` to enable the computation of left-singular vectors. + /// * `compute_v` − set this to `true` to enable the computation of right-singular vectors. + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_svd_unordered( + self, + compute_u: bool, + compute_v: bool, + eps: T::RealField, + max_niter: usize, + ) -> Option> + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, + { + SVD::try_new_unordered(self.into_owned(), compute_u, compute_v, eps, max_niter) + } + + /// Computes the Polar Decomposition of a `matrix` (indirectly uses SVD). + pub fn polar(self) -> (OMatrix, OMatrix) + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator, R> + + Allocator> + + Allocator + + Allocator, DimMinimum> + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, + { + SVD::new_unordered(self.into_owned(), true, true) + .to_polar() + .unwrap() + } + + /// Attempts to compute the Polar Decomposition of a `matrix` (indirectly uses SVD). + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0 when computing the SVD. + /// * `max_niter` − maximum total number of iterations performed by the SVD computation algorithm. + pub fn try_polar( + self, + eps: T::RealField, + max_niter: usize, + ) -> Option<(OMatrix, OMatrix)> + where + R: DimMin, + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator, R> + + Allocator> + + Allocator + + Allocator, DimMinimum> + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, + { + SVD::try_new_unordered(self.into_owned(), true, true, eps, max_niter) + .and_then(|svd| svd.to_polar()) + } +} + +/// # Square matrix decomposition +/// +/// This section contains the methods for computing some common decompositions of square +/// matrices with real or complex components. The following are currently supported: +/// +/// | Decomposition | Factors | Details | +/// | -------------------------|---------------------------|--------------| +/// | Hessenberg | `Q * H * Qᵀ` | `Q` is a unitary matrix and `H` an upper-Hessenberg matrix. | +/// | Cholesky | `L * Lᵀ` | `L` is a lower-triangular matrix. | +/// | UDU | `U * D * Uᵀ` | `U` is a upper-triangular matrix, and `D` a diagonal matrix. | +/// | Schur decomposition | `Q * T * Qᵀ` | `Q` is an unitary matrix and `T` a quasi-upper-triangular matrix. | +/// | Symmetric eigendecomposition | `Q ~ Λ ~ Qᵀ` | `Q` is an unitary matrix, and `Λ` is a real diagonal matrix. | +/// | Symmetric tridiagonalization | `Q ~ T ~ Qᵀ` | `Q` is an unitary matrix, and `T` is a tridiagonal matrix. | +impl> Matrix { + /// Attempts to compute the Cholesky decomposition of this matrix. + /// + /// Returns `None` if the input matrix is not definite-positive. The input matrix is assumed + /// to be symmetric and only the lower-triangular part is read. + pub fn cholesky(self) -> Option> + where + DefaultAllocator: Allocator, + { + Cholesky::new(self.into_owned()) + } + + /// Attempts to compute the UDU decomposition of this matrix. + /// + /// The input matrix `self` is assumed to be symmetric and this decomposition will only read + /// the upper-triangular part of `self`. + pub fn udu(self) -> Option> + where + T: RealField, + DefaultAllocator: Allocator + Allocator, + { + UDU::new(self.into_owned()) + } + + /// Computes the Hessenberg decomposition of this matrix using householder reflections. + pub fn hessenberg(self) -> Hessenberg + where + D: DimSub, + DefaultAllocator: Allocator + Allocator + Allocator>, + { + Hessenberg::new(self.into_owned()) + } + + /// Computes the Schur decomposition of a square matrix. + pub fn schur(self) -> Schur + where + D: DimSub, // For Hessenberg. + DefaultAllocator: Allocator> + + Allocator> + + Allocator + + Allocator, + { + Schur::new(self.into_owned()) + } + + /// Attempts to compute the Schur decomposition of a square matrix. + /// + /// If only eigenvalues are needed, it is more efficient to call the matrix method + /// `.eigenvalues()` instead. + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_schur(self, eps: T::RealField, max_niter: usize) -> Option> + where + D: DimSub, // For Hessenberg. + DefaultAllocator: Allocator> + + Allocator> + + Allocator + + Allocator, + { + Schur::try_new(self.into_owned(), eps, max_niter) + } + + /// Computes the eigendecomposition of this symmetric matrix. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + pub fn symmetric_eigen(self) -> SymmetricEigen + where + D: DimSub, + DefaultAllocator: + Allocator + Allocator> + Allocator + Allocator>, + { + SymmetricEigen::new(self.into_owned()) + } + + /// Computes the eigendecomposition of the given symmetric matrix with user-specified + /// convergence parameters. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_symmetric_eigen( + self, + eps: T::RealField, + max_niter: usize, + ) -> Option> + where + D: DimSub, + DefaultAllocator: + Allocator + Allocator> + Allocator + Allocator>, + { + SymmetricEigen::try_new(self.into_owned(), eps, max_niter) + } + + /// Computes the tridiagonalization of this symmetric matrix. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + pub fn symmetric_tridiagonalize(self) -> SymmetricTridiagonal + where + D: DimSub, + DefaultAllocator: Allocator + Allocator>, + { + SymmetricTridiagonal::new(self.into_owned()) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/determinant.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/determinant.rs new file mode 100644 index 000000000..c982f7a48 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/determinant.rs @@ -0,0 +1,61 @@ +use simba::scalar::ComplexField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::DimMin; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, SquareMatrix}; + +use crate::linalg::LU; + +impl, S: Storage> SquareMatrix { + /// Computes the matrix determinant. + /// + /// If the matrix has a dimension larger than 3, an LU decomposition is used. + #[inline] + #[must_use] + pub fn determinant(&self) -> T + where + DefaultAllocator: Allocator + Allocator, + { + assert!( + self.is_square(), + "Unable to compute the determinant of a non-square matrix." + ); + let dim = self.shape().0; + + unsafe { + match dim { + 0 => T::one(), + 1 => self.get_unchecked((0, 0)).clone(), + 2 => { + let m11 = self.get_unchecked((0, 0)).clone(); + let m12 = self.get_unchecked((0, 1)).clone(); + let m21 = self.get_unchecked((1, 0)).clone(); + let m22 = self.get_unchecked((1, 1)).clone(); + + m11 * m22 - m21 * m12 + } + 3 => { + let m11 = self.get_unchecked((0, 0)).clone(); + let m12 = self.get_unchecked((0, 1)).clone(); + let m13 = self.get_unchecked((0, 2)).clone(); + + let m21 = self.get_unchecked((1, 0)).clone(); + let m22 = self.get_unchecked((1, 1)).clone(); + let m23 = self.get_unchecked((1, 2)).clone(); + + let m31 = self.get_unchecked((2, 0)).clone(); + let m32 = self.get_unchecked((2, 1)).clone(); + let m33 = self.get_unchecked((2, 2)).clone(); + + let minor_m12_m23 = m22.clone() * m33.clone() - m32.clone() * m23.clone(); + let minor_m11_m23 = m21.clone() * m33 - m31.clone() * m23; + let minor_m11_m22 = m21 * m32 - m31 * m22; + + m11 * minor_m12_m23 - m12 * minor_m11_m23 + m13 * minor_m11_m22 + } + _ => LU::new(self.clone_owned()).determinant(), + } + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/eigen.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/eigen.rs new file mode 100644 index 000000000..c48c511e3 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/eigen.rs @@ -0,0 +1,112 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use num_complex::Complex; +use simba::scalar::ComplexField; +use std::cmp; +use std::fmt::Display; +use std::ops::MulAssign; + +use crate::allocator::Allocator; +use crate::base::dimension::{Dim, DimDiff, DimSub, Dyn, U1, U2, U3}; +use crate::base::storage::Storage; +use crate::base::{ + DefaultAllocator, Hessenberg, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3, +}; +use crate::constraint::{DimEq, ShapeConstraint}; + +use crate::geometry::{Reflection, UnitComplex}; +use crate::linalg::householder; +use crate::linalg::Schur; + +/// Eigendecomposition of a real matrix with real eigenvalues (or complex eigen values for complex matrices). +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator, + OVector: Serialize, + OMatrix: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator, + OVector: Serialize, + OMatrix: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct Eigen +where + DefaultAllocator: Allocator + Allocator, +{ + pub eigenvectors: OMatrix, + pub eigenvalues: OVector, +} + +impl Copy for Eigen +where + DefaultAllocator: Allocator + Allocator, + OMatrix: Copy, + OVector: Copy, +{ +} + +impl Eigen +where + D: DimSub, // For Hessenberg. + ShapeConstraint: DimEq>, // For Hessenberg. + DefaultAllocator: + Allocator> + Allocator> + Allocator + Allocator, + // XXX: for debug + DefaultAllocator: Allocator, + OMatrix: Display, +{ + /// Computes the eigendecomposition of a diagonalizable matrix with Complex eigenvalues. + pub fn new(m: OMatrix) -> Option> { + assert!( + m.is_square(), + "Unable to compute the eigendecomposition of a non-square matrix." + ); + + let dim = m.nrows(); + let (mut eigenvectors, mut eigenvalues) = Schur::new(m, 0).unwrap().unpack(); + + println!("Schur eigenvalues: {}", eigenvalues); + + // Check that the eigenvalues are all Complex. + for i in 0..dim - 1 { + if !eigenvalues[(i + 1, i)].is_zero() { + return None; + } + } + + for j in 1..dim { + for i in 0..j { + let diff = eigenvalues[(i, i)] - eigenvalues[(j, j)]; + + if diff.is_zero() && !eigenvalues[(i, j)].is_zero() { + return None; + } + + let z = -eigenvalues[(i, j)] / diff; + + for k in j + 1..dim { + eigenvalues[(i, k)] -= z * eigenvalues[(j, k)]; + } + + for k in 0..dim { + eigenvectors[(k, j)] += z * eigenvectors[(k, i)]; + } + } + } + + // Normalize the eigenvector basis. + for i in 0..dim { + let _ = eigenvectors.column_mut(i).normalize_mut(); + } + + Some(Eigen { + eigenvectors, + eigenvalues: eigenvalues.diagonal(), + }) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/exp.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/exp.rs new file mode 100644 index 000000000..e5233f0e7 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/exp.rs @@ -0,0 +1,560 @@ +//! This module provides the matrix exponent (exp) function to square matrices. +//! +use crate::{ + base::{ + allocator::Allocator, + dimension::{Const, Dim, DimMin, DimMinimum}, + DefaultAllocator, + }, + convert, try_convert, ComplexField, OMatrix, RealField, +}; + +use crate::num::Zero; + +/// Precomputed factorials for integers in range `0..=34`. +/// Note: `35!` does not fit into 128 bits. +// TODO: find a better place for this array? +const FACTORIAL: [u128; 35] = [ + 1, + 1, + 2, + 6, + 24, + 120, + 720, + 5040, + 40320, + 362880, + 3628800, + 39916800, + 479001600, + 6227020800, + 87178291200, + 1307674368000, + 20922789888000, + 355687428096000, + 6402373705728000, + 121645100408832000, + 2432902008176640000, + 51090942171709440000, + 1124000727777607680000, + 25852016738884976640000, + 620448401733239439360000, + 15511210043330985984000000, + 403291461126605635584000000, + 10888869450418352160768000000, + 304888344611713860501504000000, + 8841761993739701954543616000000, + 265252859812191058636308480000000, + 8222838654177922817725562880000000, + 263130836933693530167218012160000000, + 8683317618811886495518194401280000000, + 295232799039604140847618609643520000000, +]; + +// https://github.com/scipy/scipy/blob/c1372d8aa90a73d8a52f135529293ff4edb98fc8/scipy/sparse/linalg/matfuncs.py +struct ExpmPadeHelper +where + T: ComplexField, + D: DimMin, + DefaultAllocator: Allocator + Allocator>, +{ + use_exact_norm: bool, + ident: OMatrix, + + a: OMatrix, + a2: Option>, + a4: Option>, + a6: Option>, + a8: Option>, + a10: Option>, + + d4_exact: Option, + d6_exact: Option, + d8_exact: Option, + d10_exact: Option, + + d4_approx: Option, + d6_approx: Option, + d8_approx: Option, + d10_approx: Option, +} + +impl ExpmPadeHelper +where + T: ComplexField, + D: DimMin, + DefaultAllocator: Allocator + Allocator>, +{ + fn new(a: OMatrix, use_exact_norm: bool) -> Self { + let (nrows, ncols) = a.shape_generic(); + ExpmPadeHelper { + use_exact_norm, + ident: OMatrix::::identity_generic(nrows, ncols), + a, + a2: None, + a4: None, + a6: None, + a8: None, + a10: None, + d4_exact: None, + d6_exact: None, + d8_exact: None, + d10_exact: None, + d4_approx: None, + d6_approx: None, + d8_approx: None, + d10_approx: None, + } + } + + fn calc_a2(&mut self) { + if self.a2.is_none() { + self.a2 = Some(&self.a * &self.a); + } + } + + fn calc_a4(&mut self) { + if self.a4.is_none() { + self.calc_a2(); + let a2 = self.a2.as_ref().unwrap(); + self.a4 = Some(a2 * a2); + } + } + + fn calc_a6(&mut self) { + if self.a6.is_none() { + self.calc_a2(); + self.calc_a4(); + let a2 = self.a2.as_ref().unwrap(); + let a4 = self.a4.as_ref().unwrap(); + self.a6 = Some(a4 * a2); + } + } + + fn calc_a8(&mut self) { + if self.a8.is_none() { + self.calc_a2(); + self.calc_a6(); + let a2 = self.a2.as_ref().unwrap(); + let a6 = self.a6.as_ref().unwrap(); + self.a8 = Some(a6 * a2); + } + } + + fn calc_a10(&mut self) { + if self.a10.is_none() { + self.calc_a4(); + self.calc_a6(); + let a4 = self.a4.as_ref().unwrap(); + let a6 = self.a6.as_ref().unwrap(); + self.a10 = Some(a6 * a4); + } + } + + fn d4_tight(&mut self) -> T::RealField { + if self.d4_exact.is_none() { + self.calc_a4(); + self.d4_exact = Some(one_norm(self.a4.as_ref().unwrap()).powf(convert(0.25))); + } + self.d4_exact.clone().unwrap() + } + + fn d6_tight(&mut self) -> T::RealField { + if self.d6_exact.is_none() { + self.calc_a6(); + self.d6_exact = Some(one_norm(self.a6.as_ref().unwrap()).powf(convert(1.0 / 6.0))); + } + self.d6_exact.clone().unwrap() + } + + fn d8_tight(&mut self) -> T::RealField { + if self.d8_exact.is_none() { + self.calc_a8(); + self.d8_exact = Some(one_norm(self.a8.as_ref().unwrap()).powf(convert(1.0 / 8.0))); + } + self.d8_exact.clone().unwrap() + } + + fn d10_tight(&mut self) -> T::RealField { + if self.d10_exact.is_none() { + self.calc_a10(); + self.d10_exact = Some(one_norm(self.a10.as_ref().unwrap()).powf(convert(1.0 / 10.0))); + } + self.d10_exact.clone().unwrap() + } + + fn d4_loose(&mut self) -> T::RealField { + if self.use_exact_norm { + return self.d4_tight(); + } + + if self.d4_exact.is_some() { + return self.d4_exact.clone().unwrap(); + } + + if self.d4_approx.is_none() { + self.calc_a4(); + self.d4_approx = Some(one_norm(self.a4.as_ref().unwrap()).powf(convert(0.25))); + } + + self.d4_approx.clone().unwrap() + } + + fn d6_loose(&mut self) -> T::RealField { + if self.use_exact_norm { + return self.d6_tight(); + } + + if self.d6_exact.is_some() { + return self.d6_exact.clone().unwrap(); + } + + if self.d6_approx.is_none() { + self.calc_a6(); + self.d6_approx = Some(one_norm(self.a6.as_ref().unwrap()).powf(convert(1.0 / 6.0))); + } + + self.d6_approx.clone().unwrap() + } + + fn d8_loose(&mut self) -> T::RealField { + if self.use_exact_norm { + return self.d8_tight(); + } + + if self.d8_exact.is_some() { + return self.d8_exact.clone().unwrap(); + } + + if self.d8_approx.is_none() { + self.calc_a8(); + self.d8_approx = Some(one_norm(self.a8.as_ref().unwrap()).powf(convert(1.0 / 8.0))); + } + + self.d8_approx.clone().unwrap() + } + + fn d10_loose(&mut self) -> T::RealField { + if self.use_exact_norm { + return self.d10_tight(); + } + + if self.d10_exact.is_some() { + return self.d10_exact.clone().unwrap(); + } + + if self.d10_approx.is_none() { + self.calc_a10(); + self.d10_approx = Some(one_norm(self.a10.as_ref().unwrap()).powf(convert(1.0 / 10.0))); + } + + self.d10_approx.clone().unwrap() + } + + fn pade3(&mut self) -> (OMatrix, OMatrix) { + let b: [T; 4] = [convert(120.0), convert(60.0), convert(12.0), convert(1.0)]; + self.calc_a2(); + let a2 = self.a2.as_ref().unwrap(); + let u = &self.a * (a2 * b[3].clone() + &self.ident * b[1].clone()); + let v = a2 * b[2].clone() + &self.ident * b[0].clone(); + (u, v) + } + + fn pade5(&mut self) -> (OMatrix, OMatrix) { + let b: [T; 6] = [ + convert(30240.0), + convert(15120.0), + convert(3360.0), + convert(420.0), + convert(30.0), + convert(1.0), + ]; + self.calc_a2(); + self.calc_a6(); + let u = &self.a + * (self.a4.as_ref().unwrap() * b[5].clone() + + self.a2.as_ref().unwrap() * b[3].clone() + + &self.ident * b[1].clone()); + let v = self.a4.as_ref().unwrap() * b[4].clone() + + self.a2.as_ref().unwrap() * b[2].clone() + + &self.ident * b[0].clone(); + (u, v) + } + + fn pade7(&mut self) -> (OMatrix, OMatrix) { + let b: [T; 8] = [ + convert(17_297_280.0), + convert(8_648_640.0), + convert(1_995_840.0), + convert(277_200.0), + convert(25_200.0), + convert(1_512.0), + convert(56.0), + convert(1.0), + ]; + self.calc_a2(); + self.calc_a4(); + self.calc_a6(); + let u = &self.a + * (self.a6.as_ref().unwrap() * b[7].clone() + + self.a4.as_ref().unwrap() * b[5].clone() + + self.a2.as_ref().unwrap() * b[3].clone() + + &self.ident * b[1].clone()); + let v = self.a6.as_ref().unwrap() * b[6].clone() + + self.a4.as_ref().unwrap() * b[4].clone() + + self.a2.as_ref().unwrap() * b[2].clone() + + &self.ident * b[0].clone(); + (u, v) + } + + fn pade9(&mut self) -> (OMatrix, OMatrix) { + let b: [T; 10] = [ + convert(17_643_225_600.0), + convert(8_821_612_800.0), + convert(2_075_673_600.0), + convert(302_702_400.0), + convert(30_270_240.0), + convert(2_162_160.0), + convert(110_880.0), + convert(3_960.0), + convert(90.0), + convert(1.0), + ]; + self.calc_a2(); + self.calc_a4(); + self.calc_a6(); + self.calc_a8(); + let u = &self.a + * (self.a8.as_ref().unwrap() * b[9].clone() + + self.a6.as_ref().unwrap() * b[7].clone() + + self.a4.as_ref().unwrap() * b[5].clone() + + self.a2.as_ref().unwrap() * b[3].clone() + + &self.ident * b[1].clone()); + let v = self.a8.as_ref().unwrap() * b[8].clone() + + self.a6.as_ref().unwrap() * b[6].clone() + + self.a4.as_ref().unwrap() * b[4].clone() + + self.a2.as_ref().unwrap() * b[2].clone() + + &self.ident * b[0].clone(); + (u, v) + } + + fn pade13_scaled(&mut self, s: u64) -> (OMatrix, OMatrix) { + let b: [T; 14] = [ + convert(64_764_752_532_480_000.0), + convert(32_382_376_266_240_000.0), + convert(7_771_770_303_897_600.0), + convert(1_187_353_796_428_800.0), + convert(129_060_195_264_000.0), + convert(10_559_470_521_600.0), + convert(670_442_572_800.0), + convert(33_522_128_640.0), + convert(1_323_241_920.0), + convert(40_840_800.0), + convert(960_960.0), + convert(16_380.0), + convert(182.0), + convert(1.0), + ]; + let s = s as f64; + + let mb = &self.a * convert::(2.0_f64.powf(-s)); + self.calc_a2(); + self.calc_a4(); + self.calc_a6(); + let mb2 = self.a2.as_ref().unwrap() * convert::(2.0_f64.powf(-2.0 * s)); + let mb4 = self.a4.as_ref().unwrap() * convert::(2.0.powf(-4.0 * s)); + let mb6 = self.a6.as_ref().unwrap() * convert::(2.0.powf(-6.0 * s)); + + let u2 = &mb6 * (&mb6 * b[13].clone() + &mb4 * b[11].clone() + &mb2 * b[9].clone()); + let u = &mb + * (&u2 + + &mb6 * b[7].clone() + + &mb4 * b[5].clone() + + &mb2 * b[3].clone() + + &self.ident * b[1].clone()); + let v2 = &mb6 * (&mb6 * b[12].clone() + &mb4 * b[10].clone() + &mb2 * b[8].clone()); + let v = v2 + + &mb6 * b[6].clone() + + &mb4 * b[4].clone() + + &mb2 * b[2].clone() + + &self.ident * b[0].clone(); + (u, v) + } +} + +/// Compute `n!` +#[inline(always)] +fn factorial(n: usize) -> u128 { + match FACTORIAL.get(n) { + Some(f) => *f, + None => panic!("{}! is greater than u128::MAX", n), + } +} + +/// Compute the 1-norm of a non-negative integer power of a non-negative matrix. +fn onenorm_matrix_power_nonm(a: &OMatrix, p: usize) -> T +where + T: RealField, + D: Dim, + DefaultAllocator: Allocator + Allocator, +{ + let nrows = a.shape_generic().0; + let mut v = crate::OVector::::repeat_generic(nrows, Const::<1>, convert(1.0)); + let m = a.transpose(); + + for _ in 0..p { + v = &m * v; + } + + v.max() +} + +fn ell(a: &OMatrix, m: usize) -> u64 +where + T: ComplexField, + D: Dim, + DefaultAllocator: Allocator + Allocator + Allocator + Allocator, +{ + let a_abs = a.map(|x| x.abs()); + + let a_abs_onenorm = onenorm_matrix_power_nonm(&a_abs, 2 * m + 1); + + if a_abs_onenorm == ::RealField::zero() { + return 0; + } + + // 2m choose m = (2m)!/(m! * (2m-m)!) = (2m)!/((m!)^2) + let m_factorial = factorial(m); + let choose_2m_m = factorial(2 * m) / (m_factorial * m_factorial); + + let abs_c_recip = choose_2m_m * factorial(2 * m + 1); + let alpha = a_abs_onenorm / one_norm(a); + let alpha: f64 = try_convert::<_, f64>(alpha).unwrap() / abs_c_recip as f64; + + let u = 2_f64.powf(-53.0); + let log2_alpha_div_u = (alpha / u).log2(); + let value = (log2_alpha_div_u / (2.0 * m as f64)).ceil(); + if value > 0.0 { + value as u64 + } else { + 0 + } +} + +fn solve_p_q(u: OMatrix, v: OMatrix) -> OMatrix +where + T: ComplexField, + D: DimMin, + DefaultAllocator: Allocator + Allocator>, +{ + let p = &u + &v; + let q = &v - &u; + + q.lu().solve(&p).unwrap() +} + +fn one_norm(m: &OMatrix) -> T::RealField +where + T: ComplexField, + D: Dim, + DefaultAllocator: Allocator, +{ + let mut max = ::RealField::zero(); + + for i in 0..m.ncols() { + let col = m.column(i); + max = max.max( + col.iter() + .fold(::RealField::zero(), |a, b| { + a + b.clone().abs() + }), + ); + } + + max +} + +impl OMatrix +where + D: DimMin, + DefaultAllocator: Allocator + + Allocator> + + Allocator + + Allocator + + Allocator, +{ + /// Computes exponential of this matrix + #[must_use] + pub fn exp(&self) -> Self { + // Simple case + if self.nrows() == 1 { + return self.map(|v| v.exp()); + } + + let mut helper = ExpmPadeHelper::new(self.clone(), true); + + let eta_1 = T::RealField::max(helper.d4_loose(), helper.d6_loose()); + if eta_1 < convert(1.495_585_217_958_292e-2) && ell(&helper.a, 3) == 0 { + let (u, v) = helper.pade3(); + return solve_p_q(u, v); + } + + let eta_2 = T::RealField::max(helper.d4_tight(), helper.d6_loose()); + if eta_2 < convert(2.539_398_330_063_23e-1) && ell(&helper.a, 5) == 0 { + let (u, v) = helper.pade5(); + return solve_p_q(u, v); + } + + let eta_3 = T::RealField::max(helper.d6_tight(), helper.d8_loose()); + if eta_3 < convert(9.504_178_996_162_932e-1) && ell(&helper.a, 7) == 0 { + let (u, v) = helper.pade7(); + return solve_p_q(u, v); + } + if eta_3 < convert(2.097_847_961_257_068e0) && ell(&helper.a, 9) == 0 { + let (u, v) = helper.pade9(); + return solve_p_q(u, v); + } + + let eta_4 = T::RealField::max(helper.d8_loose(), helper.d10_loose()); + let eta_5 = T::RealField::min(eta_3, eta_4); + let theta_13 = convert(4.25); + + let mut s = if eta_5 == T::RealField::zero() { + 0 + } else { + let l2 = try_convert::<_, f64>((eta_5 / theta_13).log2().ceil()).unwrap(); + + if l2 < 0.0 { + 0 + } else { + l2 as u64 + } + }; + + s += ell( + &(&helper.a * convert::(2.0_f64.powf(-(s as f64)))), + 13, + ); + + let (u, v) = helper.pade13_scaled(s); + let mut x = solve_p_q(u, v); + + for _ in 0..s { + x = &x * &x; + } + x + } +} + +#[cfg(test)] +mod tests { + #[test] + #[allow(clippy::float_cmp)] + fn one_norm() { + use crate::Matrix3; + let m = Matrix3::new(-3.0, 5.0, 7.0, 2.0, 6.0, 4.0, 0.0, 2.0, 8.0); + + assert_eq!(super::one_norm(&m), 19.0); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/full_piv_lu.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/full_piv_lu.rs new file mode 100644 index 000000000..c73a9b7de --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/full_piv_lu.rs @@ -0,0 +1,267 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix, OMatrix}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Dim, DimMin, DimMinimum}; +use crate::storage::{Storage, StorageMut}; +use simba::scalar::ComplexField; + +use crate::linalg::lu; +use crate::linalg::PermutationSequence; + +/// LU decomposition with full row and column pivoting. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Serialize, + PermutationSequence>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Deserialize<'de>, + PermutationSequence>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct FullPivLU, C: Dim> +where + DefaultAllocator: Allocator + Allocator>, +{ + lu: OMatrix, + p: PermutationSequence>, + q: PermutationSequence>, +} + +impl, C: Dim> Copy for FullPivLU +where + DefaultAllocator: Allocator + Allocator>, + OMatrix: Copy, + PermutationSequence>: Copy, +{ +} + +impl, C: Dim> FullPivLU +where + DefaultAllocator: Allocator + Allocator>, +{ + /// Computes the LU decomposition with full pivoting of `matrix`. + /// + /// This effectively computes `P, L, U, Q` such that `P * matrix * Q = LU`. + pub fn new(mut matrix: OMatrix) -> Self { + let (nrows, ncols) = matrix.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + + let mut p = PermutationSequence::identity_generic(min_nrows_ncols); + let mut q = PermutationSequence::identity_generic(min_nrows_ncols); + + if min_nrows_ncols.value() == 0 { + return Self { lu: matrix, p, q }; + } + + for i in 0..min_nrows_ncols.value() { + let piv = matrix.view_range(i.., i..).icamax_full(); + let row_piv = piv.0 + i; + let col_piv = piv.1 + i; + let diag = matrix[(row_piv, col_piv)].clone(); + + if diag.is_zero() { + // The remaining of the matrix is zero. + break; + } + + matrix.swap_columns(i, col_piv); + q.append_permutation(i, col_piv); + + if row_piv != i { + p.append_permutation(i, row_piv); + matrix.columns_range_mut(..i).swap_rows(i, row_piv); + lu::gauss_step_swap(&mut matrix, diag, i, row_piv); + } else { + lu::gauss_step(&mut matrix, diag, i); + } + } + + Self { lu: matrix, p, q } + } + + #[doc(hidden)] + pub fn lu_internal(&self) -> &OMatrix { + &self.lu + } + + /// The lower triangular matrix of this decomposition. + #[inline] + #[must_use] + pub fn l(&self) -> OMatrix> + where + DefaultAllocator: Allocator>, + { + let (nrows, ncols) = self.lu.shape_generic(); + let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); + m.fill_upper_triangle(T::zero(), 1); + m.fill_diagonal(T::one()); + m + } + + /// The upper triangular matrix of this decomposition. + #[inline] + #[must_use] + pub fn u(&self) -> OMatrix, C> + where + DefaultAllocator: Allocator, C>, + { + let (nrows, ncols) = self.lu.shape_generic(); + self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle() + } + + /// The row permutations of this decomposition. + #[inline] + #[must_use] + pub fn p(&self) -> &PermutationSequence> { + &self.p + } + + /// The column permutations of this decomposition. + #[inline] + #[must_use] + pub fn q(&self) -> &PermutationSequence> { + &self.q + } + + /// The two matrices of this decomposition and the row and column permutations: `(P, L, U, Q)`. + #[inline] + pub fn unpack( + self, + ) -> ( + PermutationSequence>, + OMatrix>, + OMatrix, C>, + PermutationSequence>, + ) + where + DefaultAllocator: Allocator> + Allocator, C>, + { + // Use reallocation for either l or u. + let l = self.l(); + let u = self.u(); + let p = self.p; + let q = self.q; + + (p, l, u, q) + } +} + +impl> FullPivLU +where + DefaultAllocator: Allocator + Allocator, +{ + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// Returns `None` if the decomposed matrix is not invertible. + #[must_use = "Did you mean to use solve_mut()?"] + pub fn solve( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator, + { + let mut res = b.clone_owned(); + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// If the decomposed matrix is not invertible, this returns `false` and its input `b` may + /// be overwritten with garbage. + pub fn solve_mut(&self, b: &mut Matrix) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + assert_eq!( + self.lu.nrows(), + b.nrows(), + "FullPivLU solve matrix dimension mismatch." + ); + assert!( + self.lu.is_square(), + "FullPivLU solve: unable to solve a non-square system." + ); + + if self.is_invertible() { + self.p.permute_rows(b); + let _ = self.lu.solve_lower_triangular_with_diag_mut(b, T::one()); + let _ = self.lu.solve_upper_triangular_mut(b); + self.q.inv_permute_rows(b); + + true + } else { + false + } + } + + /// Computes the inverse of the decomposed matrix. + /// + /// Returns `None` if the decomposed matrix is not invertible. + #[must_use] + pub fn try_inverse(&self) -> Option> { + assert!( + self.lu.is_square(), + "FullPivLU inverse: unable to compute the inverse of a non-square matrix." + ); + + let (nrows, ncols) = self.lu.shape_generic(); + + let mut res = OMatrix::identity_generic(nrows, ncols); + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Indicates if the decomposed matrix is invertible. + #[must_use] + pub fn is_invertible(&self) -> bool { + assert!( + self.lu.is_square(), + "FullPivLU: unable to test the invertibility of a non-square matrix." + ); + + let dim = self.lu.nrows(); + !self.lu[(dim - 1, dim - 1)].is_zero() + } + + /// Computes the determinant of the decomposed matrix. + #[must_use] + pub fn determinant(&self) -> T { + assert!( + self.lu.is_square(), + "FullPivLU determinant: unable to compute the determinant of a non-square matrix." + ); + + let dim = self.lu.nrows(); + let mut res = self.lu[(dim - 1, dim - 1)].clone(); + if !res.is_zero() { + for i in 0..dim - 1 { + res *= unsafe { self.lu.get_unchecked((i, i)).clone() }; + } + + res * self.p.determinant() * self.q.determinant() + } else { + T::zero() + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/givens.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/givens.rs new file mode 100644 index 000000000..573ac80c6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/givens.rs @@ -0,0 +1,165 @@ +//! Construction of givens rotations. + +use num::{One, Zero}; +use simba::scalar::ComplexField; + +use crate::base::constraint::{DimEq, ShapeConstraint}; +use crate::base::dimension::{Dim, U2}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{Matrix, Vector}; + +/// A Givens rotation. +#[derive(Debug, Clone, Copy)] +pub struct GivensRotation { + c: T::RealField, + s: T, +} + +// Matrix = UnitComplex * Matrix +impl GivensRotation { + /// The Givens rotation that does nothing. + pub fn identity() -> Self { + Self { + c: T::RealField::one(), + s: T::zero(), + } + } + + /// Initializes a Givens rotation from its components. + /// + /// The components are copies as-is. It is not checked whether they describe + /// an actually valid Givens rotation. + pub fn new_unchecked(c: T::RealField, s: T) -> Self { + Self { c, s } + } + + /// Initializes a Givens rotation from its non-normalized cosine an sine components. + pub fn new(c: T, s: T) -> (Self, T) { + Self::try_new(c, s, T::RealField::zero()) + .unwrap_or_else(|| (GivensRotation::identity(), T::zero())) + } + + /// Initializes a Givens rotation form its non-normalized cosine an sine components. + pub fn try_new(c: T, s: T, eps: T::RealField) -> Option<(Self, T)> { + let (mod0, sign0) = c.to_exp(); + let denom = (mod0.clone() * mod0.clone() + s.clone().modulus_squared()).sqrt(); + + if denom > eps { + let norm = sign0.scale(denom.clone()); + let c = mod0 / denom; + let s = s / norm.clone(); + Some((Self { c, s }, norm)) + } else { + None + } + } + + /// Computes the rotation `R` required such that the `y` component of `R * v` is zero. + /// + /// Returns `None` if no rotation is needed (i.e. if `v.y == 0`). Otherwise, this returns the norm + /// of `v` and the rotation `r` such that `R * v = [ |v|, 0.0 ]^t` where `|v|` is the norm of `v`. + pub fn cancel_y>(v: &Vector) -> Option<(Self, T)> { + if !v[1].is_zero() { + let (mod0, sign0) = v[0].clone().to_exp(); + let denom = (mod0.clone() * mod0.clone() + v[1].clone().modulus_squared()).sqrt(); + let c = mod0 / denom.clone(); + let s = -v[1].clone() / sign0.clone().scale(denom.clone()); + let r = sign0.scale(denom); + Some((Self { c, s }, r)) + } else { + None + } + } + + /// Computes the rotation `R` required such that the `x` component of `R * v` is zero. + /// + /// Returns `None` if no rotation is needed (i.e. if `v.x == 0`). Otherwise, this returns the norm + /// of `v` and the rotation `r` such that `R * v = [ 0.0, |v| ]^t` where `|v|` is the norm of `v`. + pub fn cancel_x>(v: &Vector) -> Option<(Self, T)> { + if !v[0].is_zero() { + let (mod1, sign1) = v[1].clone().to_exp(); + let denom = (mod1.clone() * mod1.clone() + v[0].clone().modulus_squared()).sqrt(); + let c = mod1 / denom.clone(); + let s = (v[0].clone().conjugate() * sign1.clone()).unscale(denom.clone()); + let r = sign1.scale(denom); + Some((Self { c, s }, r)) + } else { + None + } + } + + /// The cos part of this rotation. + #[must_use] + pub fn c(&self) -> T::RealField { + self.c.clone() + } + + /// The sin part of this rotation. + #[must_use] + pub fn s(&self) -> T { + self.s.clone() + } + + /// The inverse of this givens rotation. + #[must_use = "This function does not mutate self."] + pub fn inverse(&self) -> Self { + Self { + c: self.c.clone(), + s: -self.s.clone(), + } + } + + /// Performs the multiplication `rhs = self * rhs` in-place. + pub fn rotate>( + &self, + rhs: &mut Matrix, + ) where + ShapeConstraint: DimEq, + { + assert_eq!( + rhs.nrows(), + 2, + "Unit complex rotation: the input matrix must have exactly two rows." + ); + let s = self.s.clone(); + let c = self.c.clone(); + + for j in 0..rhs.ncols() { + unsafe { + let a = rhs.get_unchecked((0, j)).clone(); + let b = rhs.get_unchecked((1, j)).clone(); + + *rhs.get_unchecked_mut((0, j)) = + a.clone().scale(c.clone()) - s.clone().conjugate() * b.clone(); + *rhs.get_unchecked_mut((1, j)) = s.clone() * a + b.scale(c.clone()); + } + } + } + + /// Performs the multiplication `lhs = lhs * self` in-place. + pub fn rotate_rows>( + &self, + lhs: &mut Matrix, + ) where + ShapeConstraint: DimEq, + { + assert_eq!( + lhs.ncols(), + 2, + "Unit complex rotation: the input matrix must have exactly two columns." + ); + let s = self.s.clone(); + let c = self.c.clone(); + + // TODO: can we optimize that to iterate on one column at a time ? + for j in 0..lhs.nrows() { + unsafe { + let a = lhs.get_unchecked((j, 0)).clone(); + let b = lhs.get_unchecked((j, 1)).clone(); + + *lhs.get_unchecked_mut((j, 0)) = a.clone().scale(c.clone()) + s.clone() * b.clone(); + *lhs.get_unchecked_mut((j, 1)) = -s.clone().conjugate() * a + b.scale(c.clone()); + } + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/hessenberg.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/hessenberg.rs new file mode 100644 index 000000000..f2285ff07 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/hessenberg.rs @@ -0,0 +1,154 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, OMatrix, OVector}; +use crate::dimension::{Const, DimDiff, DimSub, U1}; +use simba::scalar::ComplexField; + +use crate::linalg::householder; +use crate::Matrix; +use std::mem::MaybeUninit; + +/// Hessenberg decomposition of a general matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Serialize, + OVector>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Deserialize<'de>, + OVector>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct Hessenberg> +where + DefaultAllocator: Allocator + Allocator>, +{ + hess: OMatrix, + subdiag: OVector>, +} + +impl> Copy for Hessenberg +where + DefaultAllocator: Allocator + Allocator>, + OMatrix: Copy, + OVector>: Copy, +{ +} + +impl> Hessenberg +where + DefaultAllocator: Allocator + Allocator + Allocator>, +{ + /// Computes the Hessenberg decomposition using householder reflections. + pub fn new(hess: OMatrix) -> Self { + let mut work = Matrix::zeros_generic(hess.shape_generic().0, Const::<1>); + Self::new_with_workspace(hess, &mut work) + } + + /// Computes the Hessenberg decomposition using householder reflections. + /// + /// The workspace containing `D` elements must be provided but its content does not have to be + /// initialized. + pub fn new_with_workspace(mut hess: OMatrix, work: &mut OVector) -> Self { + assert!( + hess.is_square(), + "Cannot compute the hessenberg decomposition of a non-square matrix." + ); + + let dim = hess.shape_generic().0; + + assert!( + dim.value() != 0, + "Cannot compute the hessenberg decomposition of an empty matrix." + ); + assert_eq!( + dim.value(), + work.len(), + "Hessenberg: invalid workspace size." + ); + + if dim.value() == 0 { + return Hessenberg { + hess, + subdiag: Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>), + }; + } + + let mut subdiag = Matrix::uninit(dim.sub(Const::<1>), Const::<1>); + + for ite in 0..dim.value() - 1 { + subdiag[ite] = MaybeUninit::new(householder::clear_column_unchecked( + &mut hess, + ite, + 1, + Some(work), + )); + } + + // Safety: subdiag is now fully initialized. + let subdiag = unsafe { subdiag.assume_init() }; + Hessenberg { hess, subdiag } + } + + /// Retrieves `(q, h)` with `q` the orthogonal matrix of this decomposition and `h` the + /// hessenberg matrix. + #[inline] + pub fn unpack(self) -> (OMatrix, OMatrix) { + let q = self.q(); + + (q, self.unpack_h()) + } + + /// Retrieves the upper trapezoidal submatrix `H` of this decomposition. + #[inline] + pub fn unpack_h(mut self) -> OMatrix { + let dim = self.hess.nrows(); + self.hess.fill_lower_triangle(T::zero(), 2); + self.hess + .view_mut((1, 0), (dim - 1, dim - 1)) + .set_partial_diagonal( + self.subdiag + .iter() + .map(|e| T::from_real(e.clone().modulus())), + ); + self.hess + } + + // TODO: add a h that moves out of self. + /// Retrieves the upper trapezoidal submatrix `H` of this decomposition. + /// + /// This is less efficient than `.unpack_h()` as it allocates a new matrix. + #[inline] + #[must_use] + pub fn h(&self) -> OMatrix { + let dim = self.hess.nrows(); + let mut res = self.hess.clone(); + res.fill_lower_triangle(T::zero(), 2); + res.view_mut((1, 0), (dim - 1, dim - 1)) + .set_partial_diagonal( + self.subdiag + .iter() + .map(|e| T::from_real(e.clone().modulus())), + ); + res + } + + /// Computes the orthogonal matrix `Q` of this decomposition. + #[must_use] + pub fn q(&self) -> OMatrix { + householder::assemble_q(&self.hess, self.subdiag.as_slice()) + } + + #[doc(hidden)] + pub fn hess_internal(&self) -> &OMatrix { + &self.hess + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/householder.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/householder.rs new file mode 100644 index 000000000..a3b7acc42 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/householder.rs @@ -0,0 +1,150 @@ +//! Construction of householder elementary reflections. + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, OMatrix, OVector, Unit, Vector}; +use crate::dimension::Dim; +use crate::storage::StorageMut; +use num::Zero; +use simba::scalar::ComplexField; + +use crate::geometry::Reflection; + +/// Replaces `column` by the axis of the householder reflection that transforms `column` into +/// `(+/-|column|, 0, ..., 0)`. +/// +/// The unit-length axis is output to `column`. Returns what would be the first component of +/// `column` after reflection and `false` if no reflection was necessary. +#[doc(hidden)] +#[inline(always)] +pub fn reflection_axis_mut>( + column: &mut Vector, +) -> (T, bool) { + let reflection_sq_norm = column.norm_squared(); + let reflection_norm = reflection_sq_norm.clone().sqrt(); + + let factor; + let signed_norm; + + unsafe { + let (modulus, sign) = column.vget_unchecked(0).clone().to_exp(); + signed_norm = sign.scale(reflection_norm.clone()); + factor = (reflection_sq_norm + modulus * reflection_norm) * crate::convert(2.0); + *column.vget_unchecked_mut(0) += signed_norm.clone(); + }; + + if !factor.is_zero() { + column.unscale_mut(factor.sqrt()); + + // Normalize again, making sure the vector is unit-sized. + // If `factor` had a very small value, the first normalization + // (dividing by `factor.sqrt()`) might end up with a slightly + // non-unit vector (especially when using 32-bits float). + // Decompositions strongly rely on that unit-vector property, + // so we run a second normalization (that is much more numerically + // stable since the norm is close to 1) to ensure it has a unit + // size. + let _ = column.normalize_mut(); + + (-signed_norm, true) + } else { + // TODO: not sure why we don't have a - sign here. + (signed_norm, false) + } +} + +/// Uses an householder reflection to zero out the `icol`-th column, starting with the `shift + 1`-th +/// subdiagonal element. +/// +/// Returns the signed norm of the column. +#[doc(hidden)] +#[must_use] +pub fn clear_column_unchecked( + matrix: &mut OMatrix, + icol: usize, + shift: usize, + bilateral: Option<&mut OVector>, +) -> T +where + DefaultAllocator: Allocator + Allocator, +{ + let (mut left, mut right) = matrix.columns_range_pair_mut(icol, icol + 1..); + let mut axis = left.rows_range_mut(icol + shift..); + + let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis); + + if not_zero { + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + let sign = reflection_norm.clone().signum(); + if let Some(work) = bilateral { + refl.reflect_rows_with_sign(&mut right, work, sign.clone()); + } + refl.reflect_with_sign(&mut right.rows_range_mut(icol + shift..), sign.conjugate()); + } + + reflection_norm +} + +/// Uses an householder reflection to zero out the `irow`-th row, ending before the `shift + 1`-th +/// superdiagonal element. +/// +/// Returns the signed norm of the column. +#[doc(hidden)] +#[must_use] +pub fn clear_row_unchecked( + matrix: &mut OMatrix, + axis_packed: &mut OVector, + work: &mut OVector, + irow: usize, + shift: usize, +) -> T +where + DefaultAllocator: Allocator + Allocator + Allocator, +{ + let (mut top, mut bottom) = matrix.rows_range_pair_mut(irow, irow + 1..); + let mut axis = axis_packed.rows_range_mut(irow + shift..); + axis.tr_copy_from(&top.columns_range(irow + shift..)); + + let (reflection_norm, not_zero) = reflection_axis_mut(&mut axis); + axis.conjugate_mut(); // So that reflect_rows actually cancels the first row. + + if not_zero { + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + refl.reflect_rows_with_sign( + &mut bottom.columns_range_mut(irow + shift..), + &mut work.rows_range_mut(irow + 1..), + reflection_norm.clone().signum().conjugate(), + ); + top.columns_range_mut(irow + shift..) + .tr_copy_from(refl.axis()); + } else { + top.columns_range_mut(irow + shift..).tr_copy_from(&axis); + } + + reflection_norm +} + +/// Computes the orthogonal transformation described by the elementary reflector axii stored on +/// the lower-diagonal element of the given matrix. +/// matrices. +#[doc(hidden)] +pub fn assemble_q(m: &OMatrix, signs: &[T]) -> OMatrix +where + DefaultAllocator: Allocator, +{ + assert!(m.is_square()); + let dim = m.shape_generic().0; + + // NOTE: we could build the identity matrix and call p_mult on it. + // Instead we don't so that we take in account the matrix sparseness. + let mut res = OMatrix::identity_generic(dim, dim); + + for i in (0..dim.value() - 1).rev() { + let axis = m.view_range(i + 1.., i); + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + let mut res_rows = res.view_range_mut(i + 1.., i..); + refl.reflect_with_sign(&mut res_rows, signs[i].clone().signum()); + } + + res +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/inverse.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/inverse.rs new file mode 100644 index 000000000..e22d32a78 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/inverse.rs @@ -0,0 +1,284 @@ +use simba::scalar::ComplexField; + +use crate::base::allocator::Allocator; +use crate::base::dimension::Dim; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{DefaultAllocator, OMatrix, SquareMatrix}; + +use crate::linalg::lu; + +impl> SquareMatrix { + /// Attempts to invert this square matrix. + /// + /// # Panics + /// + /// Panics if `self` isn’t a square matrix. + #[inline] + #[must_use = "Did you mean to use try_inverse_mut()?"] + pub fn try_inverse(self) -> Option> + where + DefaultAllocator: Allocator, + { + let mut me = self.into_owned(); + if me.try_inverse_mut() { + Some(me) + } else { + None + } + } +} + +impl> SquareMatrix { + /// Attempts to invert this square matrix in-place. Returns `false` and leaves `self` untouched if + /// inversion fails. + /// + /// # Panics + /// + /// Panics if `self` isn’t a square matrix. + #[inline] + pub fn try_inverse_mut(&mut self) -> bool + where + DefaultAllocator: Allocator, + { + assert!(self.is_square(), "Unable to invert a non-square matrix."); + + let dim = self.shape().0; + + unsafe { + match dim { + 0 => true, + 1 => { + let determinant = self.get_unchecked((0, 0)).clone(); + if determinant.is_zero() { + false + } else { + *self.get_unchecked_mut((0, 0)) = T::one() / determinant; + true + } + } + 2 => { + let m11 = self.get_unchecked((0, 0)).clone(); + let m12 = self.get_unchecked((0, 1)).clone(); + let m21 = self.get_unchecked((1, 0)).clone(); + let m22 = self.get_unchecked((1, 1)).clone(); + + let determinant = m11.clone() * m22.clone() - m21.clone() * m12.clone(); + + if determinant.is_zero() { + false + } else { + *self.get_unchecked_mut((0, 0)) = m22 / determinant.clone(); + *self.get_unchecked_mut((0, 1)) = -m12 / determinant.clone(); + + *self.get_unchecked_mut((1, 0)) = -m21 / determinant.clone(); + *self.get_unchecked_mut((1, 1)) = m11 / determinant; + + true + } + } + 3 => { + let m11 = self.get_unchecked((0, 0)).clone(); + let m12 = self.get_unchecked((0, 1)).clone(); + let m13 = self.get_unchecked((0, 2)).clone(); + + let m21 = self.get_unchecked((1, 0)).clone(); + let m22 = self.get_unchecked((1, 1)).clone(); + let m23 = self.get_unchecked((1, 2)).clone(); + + let m31 = self.get_unchecked((2, 0)).clone(); + let m32 = self.get_unchecked((2, 1)).clone(); + let m33 = self.get_unchecked((2, 2)).clone(); + + let minor_m12_m23 = m22.clone() * m33.clone() - m32.clone() * m23.clone(); + let minor_m11_m23 = m21.clone() * m33.clone() - m31.clone() * m23.clone(); + let minor_m11_m22 = m21.clone() * m32.clone() - m31.clone() * m22.clone(); + + let determinant = m11.clone() * minor_m12_m23.clone() + - m12.clone() * minor_m11_m23.clone() + + m13.clone() * minor_m11_m22.clone(); + + if determinant.is_zero() { + false + } else { + *self.get_unchecked_mut((0, 0)) = minor_m12_m23 / determinant.clone(); + *self.get_unchecked_mut((0, 1)) = (m13.clone() * m32.clone() + - m33.clone() * m12.clone()) + / determinant.clone(); + *self.get_unchecked_mut((0, 2)) = (m12.clone() * m23.clone() + - m22.clone() * m13.clone()) + / determinant.clone(); + + *self.get_unchecked_mut((1, 0)) = -minor_m11_m23 / determinant.clone(); + *self.get_unchecked_mut((1, 1)) = + (m11.clone() * m33 - m31.clone() * m13.clone()) / determinant.clone(); + *self.get_unchecked_mut((1, 2)) = + (m13 * m21.clone() - m23 * m11.clone()) / determinant.clone(); + + *self.get_unchecked_mut((2, 0)) = minor_m11_m22 / determinant.clone(); + *self.get_unchecked_mut((2, 1)) = + (m12.clone() * m31 - m32 * m11.clone()) / determinant.clone(); + *self.get_unchecked_mut((2, 2)) = (m11 * m22 - m21 * m12) / determinant; + + true + } + } + 4 => { + let oself = self.clone_owned(); + do_inverse4(&oself, self) + } + _ => { + let oself = self.clone_owned(); + lu::try_invert_to(oself, self) + } + } + } + } +} + +// NOTE: this is an extremely efficient, loop-unrolled matrix inverse from MESA (MIT licensed). +fn do_inverse4>( + m: &OMatrix, + out: &mut SquareMatrix, +) -> bool +where + DefaultAllocator: Allocator, +{ + let m = m.as_slice(); + + let cofactor00 = m[5].clone() * m[10].clone() * m[15].clone() + - m[5].clone() * m[11].clone() * m[14].clone() + - m[9].clone() * m[6].clone() * m[15].clone() + + m[9].clone() * m[7].clone() * m[14].clone() + + m[13].clone() * m[6].clone() * m[11].clone() + - m[13].clone() * m[7].clone() * m[10].clone(); + + let cofactor01 = -m[4].clone() * m[10].clone() * m[15].clone() + + m[4].clone() * m[11].clone() * m[14].clone() + + m[8].clone() * m[6].clone() * m[15].clone() + - m[8].clone() * m[7].clone() * m[14].clone() + - m[12].clone() * m[6].clone() * m[11].clone() + + m[12].clone() * m[7].clone() * m[10].clone(); + + let cofactor02 = m[4].clone() * m[9].clone() * m[15].clone() + - m[4].clone() * m[11].clone() * m[13].clone() + - m[8].clone() * m[5].clone() * m[15].clone() + + m[8].clone() * m[7].clone() * m[13].clone() + + m[12].clone() * m[5].clone() * m[11].clone() + - m[12].clone() * m[7].clone() * m[9].clone(); + + let cofactor03 = -m[4].clone() * m[9].clone() * m[14].clone() + + m[4].clone() * m[10].clone() * m[13].clone() + + m[8].clone() * m[5].clone() * m[14].clone() + - m[8].clone() * m[6].clone() * m[13].clone() + - m[12].clone() * m[5].clone() * m[10].clone() + + m[12].clone() * m[6].clone() * m[9].clone(); + + let det = m[0].clone() * cofactor00.clone() + + m[1].clone() * cofactor01.clone() + + m[2].clone() * cofactor02.clone() + + m[3].clone() * cofactor03.clone(); + + if det.is_zero() { + return false; + } + out[(0, 0)] = cofactor00; + + out[(1, 0)] = -m[1].clone() * m[10].clone() * m[15].clone() + + m[1].clone() * m[11].clone() * m[14].clone() + + m[9].clone() * m[2].clone() * m[15].clone() + - m[9].clone() * m[3].clone() * m[14].clone() + - m[13].clone() * m[2].clone() * m[11].clone() + + m[13].clone() * m[3].clone() * m[10].clone(); + + out[(2, 0)] = m[1].clone() * m[6].clone() * m[15].clone() + - m[1].clone() * m[7].clone() * m[14].clone() + - m[5].clone() * m[2].clone() * m[15].clone() + + m[5].clone() * m[3].clone() * m[14].clone() + + m[13].clone() * m[2].clone() * m[7].clone() + - m[13].clone() * m[3].clone() * m[6].clone(); + + out[(3, 0)] = -m[1].clone() * m[6].clone() * m[11].clone() + + m[1].clone() * m[7].clone() * m[10].clone() + + m[5].clone() * m[2].clone() * m[11].clone() + - m[5].clone() * m[3].clone() * m[10].clone() + - m[9].clone() * m[2].clone() * m[7].clone() + + m[9].clone() * m[3].clone() * m[6].clone(); + + out[(0, 1)] = cofactor01; + + out[(1, 1)] = m[0].clone() * m[10].clone() * m[15].clone() + - m[0].clone() * m[11].clone() * m[14].clone() + - m[8].clone() * m[2].clone() * m[15].clone() + + m[8].clone() * m[3].clone() * m[14].clone() + + m[12].clone() * m[2].clone() * m[11].clone() + - m[12].clone() * m[3].clone() * m[10].clone(); + + out[(2, 1)] = -m[0].clone() * m[6].clone() * m[15].clone() + + m[0].clone() * m[7].clone() * m[14].clone() + + m[4].clone() * m[2].clone() * m[15].clone() + - m[4].clone() * m[3].clone() * m[14].clone() + - m[12].clone() * m[2].clone() * m[7].clone() + + m[12].clone() * m[3].clone() * m[6].clone(); + + out[(3, 1)] = m[0].clone() * m[6].clone() * m[11].clone() + - m[0].clone() * m[7].clone() * m[10].clone() + - m[4].clone() * m[2].clone() * m[11].clone() + + m[4].clone() * m[3].clone() * m[10].clone() + + m[8].clone() * m[2].clone() * m[7].clone() + - m[8].clone() * m[3].clone() * m[6].clone(); + + out[(0, 2)] = cofactor02; + + out[(1, 2)] = -m[0].clone() * m[9].clone() * m[15].clone() + + m[0].clone() * m[11].clone() * m[13].clone() + + m[8].clone() * m[1].clone() * m[15].clone() + - m[8].clone() * m[3].clone() * m[13].clone() + - m[12].clone() * m[1].clone() * m[11].clone() + + m[12].clone() * m[3].clone() * m[9].clone(); + + out[(2, 2)] = m[0].clone() * m[5].clone() * m[15].clone() + - m[0].clone() * m[7].clone() * m[13].clone() + - m[4].clone() * m[1].clone() * m[15].clone() + + m[4].clone() * m[3].clone() * m[13].clone() + + m[12].clone() * m[1].clone() * m[7].clone() + - m[12].clone() * m[3].clone() * m[5].clone(); + + out[(0, 3)] = cofactor03; + + out[(3, 2)] = -m[0].clone() * m[5].clone() * m[11].clone() + + m[0].clone() * m[7].clone() * m[9].clone() + + m[4].clone() * m[1].clone() * m[11].clone() + - m[4].clone() * m[3].clone() * m[9].clone() + - m[8].clone() * m[1].clone() * m[7].clone() + + m[8].clone() * m[3].clone() * m[5].clone(); + + out[(1, 3)] = m[0].clone() * m[9].clone() * m[14].clone() + - m[0].clone() * m[10].clone() * m[13].clone() + - m[8].clone() * m[1].clone() * m[14].clone() + + m[8].clone() * m[2].clone() * m[13].clone() + + m[12].clone() * m[1].clone() * m[10].clone() + - m[12].clone() * m[2].clone() * m[9].clone(); + + out[(2, 3)] = -m[0].clone() * m[5].clone() * m[14].clone() + + m[0].clone() * m[6].clone() * m[13].clone() + + m[4].clone() * m[1].clone() * m[14].clone() + - m[4].clone() * m[2].clone() * m[13].clone() + - m[12].clone() * m[1].clone() * m[6].clone() + + m[12].clone() * m[2].clone() * m[5].clone(); + + out[(3, 3)] = m[0].clone() * m[5].clone() * m[10].clone() + - m[0].clone() * m[6].clone() * m[9].clone() + - m[4].clone() * m[1].clone() * m[10].clone() + + m[4].clone() * m[2].clone() * m[9].clone() + + m[8].clone() * m[1].clone() * m[6].clone() + - m[8].clone() * m[2].clone() * m[5].clone(); + + let inv_det = T::one() / det; + + for j in 0..4 { + for i in 0..4 { + out[(i, j)] *= inv_det.clone(); + } + } + true +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/lu.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/lu.rs new file mode 100644 index 000000000..d3d6d2247 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/lu.rs @@ -0,0 +1,388 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::{Allocator, Reallocator}; +use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Dim, DimMin, DimMinimum}; +use crate::storage::{Storage, StorageMut}; +use simba::scalar::{ComplexField, Field}; +use std::mem; + +use crate::linalg::PermutationSequence; + +/// LU decomposition with partial (row) pivoting. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Serialize, + PermutationSequence>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Deserialize<'de>, + PermutationSequence>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct LU, C: Dim> +where + DefaultAllocator: Allocator + Allocator>, +{ + lu: OMatrix, + p: PermutationSequence>, +} + +impl, C: Dim> Copy for LU +where + DefaultAllocator: Allocator + Allocator>, + OMatrix: Copy, + PermutationSequence>: Copy, +{ +} + +/// Performs a LU decomposition to overwrite `out` with the inverse of `matrix`. +/// +/// If `matrix` is not invertible, `false` is returned and `out` may contain invalid data. +pub fn try_invert_to( + mut matrix: OMatrix, + out: &mut Matrix, +) -> bool +where + S: StorageMut, + DefaultAllocator: Allocator, +{ + assert!( + matrix.is_square(), + "LU inversion: unable to invert a rectangular matrix." + ); + let dim = matrix.nrows(); + + out.fill_with_identity(); + + for i in 0..dim { + let piv = matrix.view_range(i.., i).icamax() + i; + let diag = matrix[(piv, i)].clone(); + + if diag.is_zero() { + return false; + } + + if piv != i { + out.swap_rows(i, piv); + matrix.columns_range_mut(..i).swap_rows(i, piv); + gauss_step_swap(&mut matrix, diag, i, piv); + } else { + gauss_step(&mut matrix, diag, i); + } + } + + let _ = matrix.solve_lower_triangular_with_diag_mut(out, T::one()); + matrix.solve_upper_triangular_mut(out) +} + +impl, C: Dim> LU +where + DefaultAllocator: Allocator + Allocator>, +{ + /// Computes the LU decomposition with partial (row) pivoting of `matrix`. + pub fn new(mut matrix: OMatrix) -> Self { + let (nrows, ncols) = matrix.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + + let mut p = PermutationSequence::identity_generic(min_nrows_ncols); + + if min_nrows_ncols.value() == 0 { + return LU { lu: matrix, p }; + } + + for i in 0..min_nrows_ncols.value() { + let piv = matrix.view_range(i.., i).icamax() + i; + let diag = matrix[(piv, i)].clone(); + + if diag.is_zero() { + // No non-zero entries on this column. + continue; + } + + if piv != i { + p.append_permutation(i, piv); + matrix.columns_range_mut(..i).swap_rows(i, piv); + gauss_step_swap(&mut matrix, diag, i, piv); + } else { + gauss_step(&mut matrix, diag, i); + } + } + + LU { lu: matrix, p } + } + + #[doc(hidden)] + pub fn lu_internal(&self) -> &OMatrix { + &self.lu + } + + /// The lower triangular matrix of this decomposition. + #[inline] + #[must_use] + pub fn l(&self) -> OMatrix> + where + DefaultAllocator: Allocator>, + { + let (nrows, ncols) = self.lu.shape_generic(); + let mut m = self.lu.columns_generic(0, nrows.min(ncols)).into_owned(); + m.fill_upper_triangle(T::zero(), 1); + m.fill_diagonal(T::one()); + m + } + + /// The lower triangular matrix of this decomposition. + fn l_unpack_with_p( + self, + ) -> ( + OMatrix>, + PermutationSequence>, + ) + where + DefaultAllocator: Reallocator>, + { + let (nrows, ncols) = self.lu.shape_generic(); + let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero()); + m.fill_upper_triangle(T::zero(), 1); + m.fill_diagonal(T::one()); + (m, self.p) + } + + /// The lower triangular matrix of this decomposition. + #[inline] + pub fn l_unpack(self) -> OMatrix> + where + DefaultAllocator: Reallocator>, + { + let (nrows, ncols) = self.lu.shape_generic(); + let mut m = self.lu.resize_generic(nrows, nrows.min(ncols), T::zero()); + m.fill_upper_triangle(T::zero(), 1); + m.fill_diagonal(T::one()); + m + } + + /// The upper triangular matrix of this decomposition. + #[inline] + #[must_use] + pub fn u(&self) -> OMatrix, C> + where + DefaultAllocator: Allocator, C>, + { + let (nrows, ncols) = self.lu.shape_generic(); + self.lu.rows_generic(0, nrows.min(ncols)).upper_triangle() + } + + /// The row permutations of this decomposition. + #[inline] + #[must_use] + pub fn p(&self) -> &PermutationSequence> { + &self.p + } + + /// The row permutations and two triangular matrices of this decomposition: `(P, L, U)`. + #[inline] + pub fn unpack( + self, + ) -> ( + PermutationSequence>, + OMatrix>, + OMatrix, C>, + ) + where + DefaultAllocator: Allocator> + + Allocator, C> + + Reallocator>, + { + // Use reallocation for either l or u. + let u = self.u(); + let (l, p) = self.l_unpack_with_p(); + + (p, l, u) + } +} + +impl> LU +where + DefaultAllocator: Allocator + Allocator, +{ + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// Returns `None` if `self` is not invertible. + #[must_use = "Did you mean to use solve_mut()?"] + pub fn solve( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator, + { + let mut res = b.clone_owned(); + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// If the decomposed matrix is not invertible, this returns `false` and its input `b` may + /// be overwritten with garbage. + pub fn solve_mut(&self, b: &mut Matrix) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + assert_eq!( + self.lu.nrows(), + b.nrows(), + "LU solve matrix dimension mismatch." + ); + assert!( + self.lu.is_square(), + "LU solve: unable to solve a non-square system." + ); + + self.p.permute_rows(b); + let _ = self.lu.solve_lower_triangular_with_diag_mut(b, T::one()); + self.lu.solve_upper_triangular_mut(b) + } + + /// Computes the inverse of the decomposed matrix. + /// + /// Returns `None` if the matrix is not invertible. + #[must_use] + pub fn try_inverse(&self) -> Option> { + assert!( + self.lu.is_square(), + "LU inverse: unable to compute the inverse of a non-square matrix." + ); + + let (nrows, ncols) = self.lu.shape_generic(); + let mut res = OMatrix::identity_generic(nrows, ncols); + if self.try_inverse_to(&mut res) { + Some(res) + } else { + None + } + } + + /// Computes the inverse of the decomposed matrix and outputs the result to `out`. + /// + /// If the decomposed matrix is not invertible, this returns `false` and `out` may be + /// overwritten with garbage. + pub fn try_inverse_to>(&self, out: &mut Matrix) -> bool { + assert!( + self.lu.is_square(), + "LU inverse: unable to compute the inverse of a non-square matrix." + ); + assert!( + self.lu.shape() == out.shape(), + "LU inverse: mismatched output shape." + ); + + out.fill_with_identity(); + self.solve_mut(out) + } + + /// Computes the determinant of the decomposed matrix. + #[must_use] + pub fn determinant(&self) -> T { + let dim = self.lu.nrows(); + assert!( + self.lu.is_square(), + "LU determinant: unable to compute the determinant of a non-square matrix." + ); + + let mut res = T::one(); + for i in 0..dim { + res *= unsafe { self.lu.get_unchecked((i, i)).clone() }; + } + + res * self.p.determinant() + } + + /// Indicates if the decomposed matrix is invertible. + #[must_use] + pub fn is_invertible(&self) -> bool { + assert!( + self.lu.is_square(), + "LU: unable to test the invertibility of a non-square matrix." + ); + + for i in 0..self.lu.nrows() { + if self.lu[(i, i)].is_zero() { + return false; + } + } + + true + } +} + +#[doc(hidden)] +/// Executes one step of gaussian elimination on the i-th row and column of `matrix`. The diagonal +/// element `matrix[(i, i)]` is provided as argument. +pub fn gauss_step(matrix: &mut Matrix, diag: T, i: usize) +where + T: Scalar + Field, + S: StorageMut, +{ + let mut submat = matrix.view_range_mut(i.., i..); + + let inv_diag = T::one() / diag; + + let (mut coeffs, mut submat) = submat.columns_range_pair_mut(0, 1..); + + let mut coeffs = coeffs.rows_range_mut(1..); + coeffs *= inv_diag; + + let (pivot_row, mut down) = submat.rows_range_pair_mut(0, 1..); + + for k in 0..pivot_row.ncols() { + down.column_mut(k) + .axpy(-pivot_row[k].clone(), &coeffs, T::one()); + } +} + +#[doc(hidden)] +/// Swaps the rows `i` with the row `piv` and executes one step of gaussian elimination on the i-th +/// row and column of `matrix`. The diagonal element `matrix[(i, i)]` is provided as argument. +pub fn gauss_step_swap( + matrix: &mut Matrix, + diag: T, + i: usize, + piv: usize, +) where + T: Scalar + Field, + S: StorageMut, +{ + let piv = piv - i; + let mut submat = matrix.view_range_mut(i.., i..); + + let inv_diag = T::one() / diag; + + let (mut coeffs, mut submat) = submat.columns_range_pair_mut(0, 1..); + + coeffs.swap((0, 0), (piv, 0)); + let mut coeffs = coeffs.rows_range_mut(1..); + coeffs *= inv_diag; + + let (mut pivot_row, mut down) = submat.rows_range_pair_mut(0, 1..); + + for k in 0..pivot_row.ncols() { + mem::swap(&mut pivot_row[k], &mut down[(piv - 1, k)]); + down.column_mut(k) + .axpy(-pivot_row[k].clone(), &coeffs, T::one()); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/mod.rs new file mode 100644 index 000000000..3a1763a98 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/mod.rs @@ -0,0 +1,49 @@ +//! [Reexported at the root of this crate.] Factorization of real matrices. + +pub mod balancing; +mod bidiagonal; +mod cholesky; +mod convolution; +mod determinant; +// TODO: this should not be needed. However, the exp uses +// explicit float operations on `f32` and `f64`. We need to +// get rid of these to allow exp to be used on a no-std context. +mod col_piv_qr; +mod decomposition; +#[cfg(feature = "std")] +mod exp; +mod full_piv_lu; +pub mod givens; +mod hessenberg; +pub mod householder; +mod inverse; +mod lu; +mod permutation_sequence; +mod pow; +mod qr; +mod schur; +mod solve; +mod svd; +mod svd2; +mod svd3; +mod symmetric_eigen; +mod symmetric_tridiagonal; +mod udu; + +//// TODO: Not complete enough for publishing. +//// This handles only cases where each eigenvalue has multiplicity one. +// mod eigen; + +pub use self::bidiagonal::*; +pub use self::cholesky::*; +pub use self::col_piv_qr::*; +pub use self::full_piv_lu::*; +pub use self::hessenberg::*; +pub use self::lu::*; +pub use self::permutation_sequence::*; +pub use self::qr::*; +pub use self::schur::*; +pub use self::svd::*; +pub use self::symmetric_eigen::*; +pub use self::symmetric_tridiagonal::*; +pub use self::udu::*; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/permutation_sequence.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/permutation_sequence.rs new file mode 100644 index 000000000..644561e07 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/permutation_sequence.rs @@ -0,0 +1,164 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use num::One; +use simba::scalar::ClosedNeg; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix, OVector, Scalar}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::dimension::Dyn; +use crate::dimension::{Const, Dim, DimName}; +use crate::storage::StorageMut; + +/// A sequence of row or column permutations. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator, + OVector<(usize, usize), D>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator, + OVector<(usize, usize), D>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct PermutationSequence +where + DefaultAllocator: Allocator, +{ + len: usize, + ipiv: OVector<(usize, usize), D>, +} + +impl Copy for PermutationSequence +where + DefaultAllocator: Allocator, + OVector<(usize, usize), D>: Copy, +{ +} + +impl PermutationSequence +where + DefaultAllocator: Allocator, +{ + /// Creates a new statically-allocated sequence of `D` identity permutations. + #[inline] + pub fn identity() -> Self { + Self::identity_generic(D::name()) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl PermutationSequence +where + DefaultAllocator: Allocator, +{ + /// Creates a new dynamically-allocated sequence of `n` identity permutations. + #[inline] + pub fn identity(n: usize) -> Self { + Self::identity_generic(Dyn(n)) + } +} + +impl PermutationSequence +where + DefaultAllocator: Allocator, +{ + /// Creates a new sequence of D identity permutations. + #[inline] + pub fn identity_generic(dim: D) -> Self { + Self { + len: 0, + // TODO: using a uninitialized matrix would save some computation, but + // that loos difficult to setup with MaybeUninit. + ipiv: Matrix::repeat_generic(dim, Const::<1>, (0, 0)), + } + } + + /// Adds the interchange of the row (or column) `i` with the row (or column) `i2` to this + /// sequence of permutations. + #[inline] + pub fn append_permutation(&mut self, i: usize, i2: usize) { + if i != i2 { + assert!( + self.len < self.ipiv.len(), + "Maximum number of permutations exceeded." + ); + self.ipiv[self.len] = (i, i2); + self.len += 1; + } + } + + /// Applies this sequence of permutations to the rows of `rhs`. + #[inline] + pub fn permute_rows(&self, rhs: &mut Matrix) + where + S2: StorageMut, + { + for i in self.ipiv.rows_range(..self.len).iter() { + rhs.swap_rows(i.0, i.1) + } + } + + /// Applies this sequence of permutations in reverse to the rows of `rhs`. + #[inline] + pub fn inv_permute_rows(&self, rhs: &mut Matrix) + where + S2: StorageMut, + { + for i in 0..self.len { + let (i1, i2) = self.ipiv[self.len - i - 1]; + rhs.swap_rows(i1, i2) + } + } + + /// Applies this sequence of permutations to the columns of `rhs`. + #[inline] + pub fn permute_columns(&self, rhs: &mut Matrix) + where + S2: StorageMut, + { + for i in self.ipiv.rows_range(..self.len).iter() { + rhs.swap_columns(i.0, i.1) + } + } + + /// Applies this sequence of permutations in reverse to the columns of `rhs`. + #[inline] + pub fn inv_permute_columns( + &self, + rhs: &mut Matrix, + ) where + S2: StorageMut, + { + for i in 0..self.len { + let (i1, i2) = self.ipiv[self.len - i - 1]; + rhs.swap_columns(i1, i2) + } + } + + /// The number of non-identity permutations applied by this sequence. + #[must_use] + pub fn len(&self) -> usize { + self.len + } + + /// Returns true if the permutation sequence contains no elements. + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// The determinant of the matrix corresponding to this permutation. + #[inline] + #[must_use] + pub fn determinant(&self) -> T { + if self.len % 2 == 0 { + T::one() + } else { + -T::one() + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/pow.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/pow.rs new file mode 100644 index 000000000..657b60cdf --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/pow.rs @@ -0,0 +1,71 @@ +//! This module provides the matrix exponential (pow) function to square matrices. + +use crate::{ + allocator::Allocator, + storage::{Storage, StorageMut}, + DefaultAllocator, DimMin, Matrix, OMatrix, Scalar, +}; +use num::{One, Zero}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; + +impl Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + D: DimMin, + S: StorageMut, + DefaultAllocator: Allocator + Allocator, +{ + /// Raises this matrix to an integral power `exp` in-place. + pub fn pow_mut(&mut self, mut exp: u32) { + // A matrix raised to the zeroth power is just the identity. + if exp == 0 { + self.fill_with_identity(); + } else if exp > 1 { + // We use the buffer to hold the result of multiplier^2, thus avoiding + // extra allocations. + let mut x = self.clone_owned(); + let mut workspace = self.clone_owned(); + + if exp % 2 == 0 { + self.fill_with_identity(); + } else { + // Avoid an useless multiplication by the identity + // if the exponent is odd. + exp -= 1; + } + + // Exponentiation by squares. + loop { + if exp % 2 == 1 { + self.mul_to(&x, &mut workspace); + self.copy_from(&workspace); + } + + exp /= 2; + + if exp == 0 { + break; + } + + x.mul_to(&x, &mut workspace); + x.copy_from(&workspace); + } + } + } +} + +impl> Matrix +where + T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign, + D: DimMin, + S: StorageMut, + DefaultAllocator: Allocator + Allocator, +{ + /// Raise this matrix to an integral power `exp`. + #[must_use] + pub fn pow(&self, exp: u32) -> OMatrix { + let mut result = self.clone_owned(); + result.pow_mut(exp); + result + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/qr.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/qr.rs new file mode 100644 index 000000000..4ce10d8cc --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/qr.rs @@ -0,0 +1,307 @@ +use num::Zero; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::{Allocator, Reallocator}; +use crate::base::{DefaultAllocator, Matrix, OMatrix, OVector, Unit}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Const, Dim, DimMin, DimMinimum}; +use crate::storage::{Storage, StorageMut}; +use simba::scalar::ComplexField; + +use crate::geometry::Reflection; +use crate::linalg::householder; +use std::mem::MaybeUninit; + +/// The QR decomposition of a general matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Serialize, + OVector>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Deserialize<'de>, + OVector>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct QR, C: Dim> +where + DefaultAllocator: Allocator + Allocator>, +{ + qr: OMatrix, + diag: OVector>, +} + +impl, C: Dim> Copy for QR +where + DefaultAllocator: Allocator + Allocator>, + OMatrix: Copy, + OVector>: Copy, +{ +} + +impl, C: Dim> QR +where + DefaultAllocator: Allocator + Allocator + Allocator>, +{ + /// Computes the QR decomposition using householder reflections. + pub fn new(mut matrix: OMatrix) -> Self { + let (nrows, ncols) = matrix.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + + if min_nrows_ncols.value() == 0 { + return QR { + qr: matrix, + diag: Matrix::zeros_generic(min_nrows_ncols, Const::<1>), + }; + } + + let mut diag = Matrix::uninit(min_nrows_ncols, Const::<1>); + + for i in 0..min_nrows_ncols.value() { + diag[i] = + MaybeUninit::new(householder::clear_column_unchecked(&mut matrix, i, 0, None)); + } + + // Safety: diag is now fully initialized. + let diag = unsafe { diag.assume_init() }; + QR { qr: matrix, diag } + } + + /// Retrieves the upper trapezoidal submatrix `R` of this decomposition. + #[inline] + #[must_use] + pub fn r(&self) -> OMatrix, C> + where + DefaultAllocator: Allocator, C>, + { + let (nrows, ncols) = self.qr.shape_generic(); + let mut res = self.qr.rows_generic(0, nrows.min(ncols)).upper_triangle(); + res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.clone().modulus()))); + res + } + + /// Retrieves the upper trapezoidal submatrix `R` of this decomposition. + /// + /// This is usually faster than `r` but consumes `self`. + #[inline] + pub fn unpack_r(self) -> OMatrix, C> + where + DefaultAllocator: Reallocator, C>, + { + let (nrows, ncols) = self.qr.shape_generic(); + let mut res = self.qr.resize_generic(nrows.min(ncols), ncols, T::zero()); + res.fill_lower_triangle(T::zero(), 1); + res.set_partial_diagonal(self.diag.iter().map(|e| T::from_real(e.clone().modulus()))); + res + } + + /// Computes the orthogonal matrix `Q` of this decomposition. + #[must_use] + pub fn q(&self) -> OMatrix> + where + DefaultAllocator: Allocator>, + { + let (nrows, ncols) = self.qr.shape_generic(); + + // NOTE: we could build the identity matrix and call q_mul on it. + // Instead we don't so that we take in account the matrix sparseness. + let mut res = Matrix::identity_generic(nrows, nrows.min(ncols)); + let dim = self.diag.len(); + + for i in (0..dim).rev() { + let axis = self.qr.view_range(i.., i); + // TODO: sometimes, the axis might have a zero magnitude. + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + let mut res_rows = res.view_range_mut(i.., i..); + refl.reflect_with_sign(&mut res_rows, self.diag[i].clone().signum()); + } + + res + } + + /// Unpacks this decomposition into its two matrix factors. + pub fn unpack( + self, + ) -> ( + OMatrix>, + OMatrix, C>, + ) + where + DimMinimum: DimMin>, + DefaultAllocator: + Allocator> + Reallocator, C>, + { + (self.q(), self.unpack_r()) + } + + #[doc(hidden)] + pub fn qr_internal(&self) -> &OMatrix { + &self.qr + } + + #[must_use] + pub(crate) fn diag_internal(&self) -> &OVector> { + &self.diag + } + + /// Multiplies the provided matrix by the transpose of the `Q` matrix of this decomposition. + pub fn q_tr_mul(&self, rhs: &mut Matrix) + // TODO: do we need a static constraint on the number of rows of rhs? + where + S2: StorageMut, + { + let dim = self.diag.len(); + + for i in 0..dim { + let axis = self.qr.view_range(i.., i); + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + let mut rhs_rows = rhs.rows_range_mut(i..); + refl.reflect_with_sign(&mut rhs_rows, self.diag[i].clone().signum().conjugate()); + } + } +} + +impl> QR +where + DefaultAllocator: Allocator + Allocator, +{ + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// Returns `None` if `self` is not invertible. + #[must_use = "Did you mean to use solve_mut()?"] + pub fn solve( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator, + { + let mut res = b.clone_owned(); + + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self * x = b`, where `x` is the unknown to be determined. + /// + /// If the decomposed matrix is not invertible, this returns `false` and its input `b` is + /// overwritten with garbage. + pub fn solve_mut(&self, b: &mut Matrix) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + assert_eq!( + self.qr.nrows(), + b.nrows(), + "QR solve matrix dimension mismatch." + ); + assert!( + self.qr.is_square(), + "QR solve: unable to solve a non-square system." + ); + + self.q_tr_mul(b); + self.solve_upper_triangular_mut(b) + } + + // TODO: duplicate code from the `solve` module. + fn solve_upper_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.qr.nrows(); + + for k in 0..b.ncols() { + let mut b = b.column_mut(k); + for i in (0..dim).rev() { + let coeff; + + unsafe { + let diag = self.diag.vget_unchecked(i).clone().modulus(); + + if diag.is_zero() { + return false; + } + + coeff = b.vget_unchecked(i).clone().unscale(diag); + *b.vget_unchecked_mut(i) = coeff.clone(); + } + + b.rows_range_mut(..i) + .axpy(-coeff, &self.qr.view_range(..i, i), T::one()); + } + } + + true + } + + /// Computes the inverse of the decomposed matrix. + /// + /// Returns `None` if the decomposed matrix is not invertible. + #[must_use] + pub fn try_inverse(&self) -> Option> { + assert!( + self.qr.is_square(), + "QR inverse: unable to compute the inverse of a non-square matrix." + ); + + // TODO: is there a less naive method ? + let (nrows, ncols) = self.qr.shape_generic(); + let mut res = OMatrix::identity_generic(nrows, ncols); + + if self.solve_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Indicates if the decomposed matrix is invertible. + #[must_use] + pub fn is_invertible(&self) -> bool { + assert!( + self.qr.is_square(), + "QR: unable to test the invertibility of a non-square matrix." + ); + + for i in 0..self.diag.len() { + if self.diag[i].is_zero() { + return false; + } + } + + true + } + + // /// Computes the determinant of the decomposed matrix. + // pub fn determinant(&self) -> T { + // let dim = self.qr.nrows(); + // assert!(self.qr.is_square(), "QR determinant: unable to compute the determinant of a non-square matrix."); + + // let mut res = T::one(); + // for i in 0 .. dim { + // res *= unsafe { *self.diag.vget_unchecked(i) }; + // } + + // res self.q_determinant() + // } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/schur.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/schur.rs new file mode 100644 index 000000000..06fc3ccf1 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/schur.rs @@ -0,0 +1,578 @@ +#![allow(clippy::suspicious_operation_groupings)] +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use approx::AbsDiffEq; +use num_complex::Complex as NumComplex; +use simba::scalar::{ComplexField, RealField}; +use std::cmp; + +use crate::allocator::Allocator; +use crate::base::dimension::{Const, Dim, DimDiff, DimSub, Dyn, U1, U2}; +use crate::base::storage::Storage; +use crate::base::{DefaultAllocator, OMatrix, OVector, SquareMatrix, Unit, Vector2, Vector3}; + +use crate::geometry::Reflection; +use crate::linalg::givens::GivensRotation; +use crate::linalg::householder; +use crate::linalg::Hessenberg; +use crate::{Matrix, UninitVector}; +use std::mem::MaybeUninit; + +/// Schur decomposition of a square matrix. +/// +/// If this is a real matrix, this will be a `RealField` Schur decomposition. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator, + OMatrix: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator, + OMatrix: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct Schur +where + DefaultAllocator: Allocator, +{ + q: OMatrix, + t: OMatrix, +} + +impl Copy for Schur +where + DefaultAllocator: Allocator, + OMatrix: Copy, +{ +} + +impl Schur +where + D: DimSub, // For Hessenberg. + DefaultAllocator: + Allocator> + Allocator> + Allocator + Allocator, +{ + /// Computes the Schur decomposition of a square matrix. + pub fn new(m: OMatrix) -> Self { + Self::try_new(m, T::RealField::default_epsilon(), 0).unwrap() + } + + /// Attempts to compute the Schur decomposition of a square matrix. + /// + /// If only eigenvalues are needed, it is more efficient to call the matrix method + /// `.eigenvalues()` instead. + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_new(m: OMatrix, eps: T::RealField, max_niter: usize) -> Option { + let mut work = Matrix::zeros_generic(m.shape_generic().0, Const::<1>); + + Self::do_decompose(m, &mut work, eps, max_niter, true) + .map(|(q, t)| Schur { q: q.unwrap(), t }) + } + + fn do_decompose( + mut m: OMatrix, + work: &mut OVector, + eps: T::RealField, + max_niter: usize, + compute_q: bool, + ) -> Option<(Option>, OMatrix)> { + assert!( + m.is_square(), + "Unable to compute the eigenvectors and eigenvalues of a non-square matrix." + ); + + let dim = m.shape_generic().0; + + // Specialization would make this easier. + if dim.value() == 0 { + let vecs = Some(OMatrix::from_element_generic(dim, dim, T::zero())); + let vals = OMatrix::from_element_generic(dim, dim, T::zero()); + return Some((vecs, vals)); + } else if dim.value() == 1 { + if compute_q { + let q = OMatrix::from_element_generic(dim, dim, T::one()); + return Some((Some(q), m)); + } else { + return Some((None, m)); + } + } else if dim.value() == 2 { + return decompose_2x2(m, compute_q); + } + + let amax_m = m.camax(); + m.unscale_mut(amax_m.clone()); + + let hess = Hessenberg::new_with_workspace(m, work); + let mut q; + let mut t; + + if compute_q { + // TODO: could we work without unpacking? Using only the internal representation of + // hessenberg decomposition. + let (vecs, vals) = hess.unpack(); + q = Some(vecs); + t = vals; + } else { + q = None; + t = hess.unpack_h() + } + + // Implicit double-shift QR method. + let mut niter = 0; + let (mut start, mut end) = Self::delimit_subproblem(&mut t, eps.clone(), dim.value() - 1); + + while end != start { + let subdim = end - start + 1; + + if subdim > 2 { + let m = end - 1; + let n = end; + + let h11 = t[(start, start)].clone(); + let h12 = t[(start, start + 1)].clone(); + let h21 = t[(start + 1, start)].clone(); + let h22 = t[(start + 1, start + 1)].clone(); + let h32 = t[(start + 2, start + 1)].clone(); + + let hnn = t[(n, n)].clone(); + let hmm = t[(m, m)].clone(); + let hnm = t[(n, m)].clone(); + let hmn = t[(m, n)].clone(); + + let tra = hnn.clone() + hmm.clone(); + let det = hnn * hmm - hnm * hmn; + + let mut axis = Vector3::new( + h11.clone() * h11.clone() + h12 * h21.clone() - tra.clone() * h11.clone() + det, + h21.clone() * (h11 + h22 - tra), + h21 * h32, + ); + + for k in start..n - 1 { + let (norm, not_zero) = householder::reflection_axis_mut(&mut axis); + + if not_zero { + if k > start { + t[(k, k - 1)] = norm; + t[(k + 1, k - 1)] = T::zero(); + t[(k + 2, k - 1)] = T::zero(); + } + + let refl = Reflection::new(Unit::new_unchecked(axis.clone()), T::zero()); + + { + let krows = cmp::min(k + 4, end + 1); + let mut work = work.rows_mut(0, krows); + refl.reflect( + &mut t.generic_view_mut((k, k), (Const::<3>, Dyn(dim.value() - k))), + ); + refl.reflect_rows( + &mut t.generic_view_mut((0, k), (Dyn(krows), Const::<3>)), + &mut work, + ); + } + + if let Some(ref mut q) = q { + refl.reflect_rows( + &mut q.generic_view_mut((0, k), (dim, Const::<3>)), + work, + ); + } + } + + axis.x = t[(k + 1, k)].clone(); + axis.y = t[(k + 2, k)].clone(); + + if k < n - 2 { + axis.z = t[(k + 3, k)].clone(); + } + } + + let mut axis = Vector2::new(axis.x.clone(), axis.y.clone()); + let (norm, not_zero) = householder::reflection_axis_mut(&mut axis); + + if not_zero { + let refl = Reflection::new(Unit::new_unchecked(axis), T::zero()); + + t[(m, m - 1)] = norm; + t[(n, m - 1)] = T::zero(); + + { + let mut work = work.rows_mut(0, end + 1); + refl.reflect( + &mut t.generic_view_mut((m, m), (Const::<2>, Dyn(dim.value() - m))), + ); + refl.reflect_rows( + &mut t.generic_view_mut((0, m), (Dyn(end + 1), Const::<2>)), + &mut work, + ); + } + + if let Some(ref mut q) = q { + refl.reflect_rows(&mut q.generic_view_mut((0, m), (dim, Const::<2>)), work); + } + } + } else { + // Decouple the 2x2 block if it has real eigenvalues. + if let Some(rot) = compute_2x2_basis(&t.fixed_view::<2, 2>(start, start)) { + let inv_rot = rot.inverse(); + inv_rot.rotate( + &mut t.generic_view_mut( + (start, start), + (Const::<2>, Dyn(dim.value() - start)), + ), + ); + rot.rotate_rows( + &mut t.generic_view_mut((0, start), (Dyn(end + 1), Const::<2>)), + ); + t[(end, start)] = T::zero(); + + if let Some(ref mut q) = q { + rot.rotate_rows(&mut q.generic_view_mut((0, start), (dim, Const::<2>))); + } + } + + // Check if we reached the beginning of the matrix. + if end > 2 { + end -= 2; + } else { + break; + } + } + + let sub = Self::delimit_subproblem(&mut t, eps.clone(), end); + + start = sub.0; + end = sub.1; + + niter += 1; + if niter == max_niter { + return None; + } + } + + t.scale_mut(amax_m); + + Some((q, t)) + } + + /// Computes the eigenvalues of the decomposed matrix. + fn do_eigenvalues(t: &OMatrix, out: &mut OVector) -> bool { + let dim = t.nrows(); + let mut m = 0; + + while m < dim - 1 { + let n = m + 1; + + if t[(n, m)].is_zero() { + out[m] = t[(m, m)].clone(); + m += 1; + } else { + // Complex eigenvalue. + return false; + } + } + + if m == dim - 1 { + out[m] = t[(m, m)].clone(); + } + + true + } + + /// Computes the complex eigenvalues of the decomposed matrix. + fn do_complex_eigenvalues(t: &OMatrix, out: &mut UninitVector, D>) + where + T: RealField, + DefaultAllocator: Allocator, + { + let dim = t.nrows(); + let mut m = 0; + + while m < dim - 1 { + let n = m + 1; + + if t[(n, m)].is_zero() { + out[m] = MaybeUninit::new(NumComplex::new(t[(m, m)].clone(), T::zero())); + m += 1; + } else { + // Solve the 2x2 eigenvalue subproblem. + let hmm = t[(m, m)].clone(); + let hnm = t[(n, m)].clone(); + let hmn = t[(m, n)].clone(); + let hnn = t[(n, n)].clone(); + + // NOTE: use the same algorithm as in compute_2x2_eigvals. + let val = (hmm.clone() - hnn.clone()) * crate::convert(0.5); + let discr = hnm * hmn + val.clone() * val; + + // All 2x2 blocks have negative discriminant because we already decoupled those + // with positive eigenvalues. + let sqrt_discr = NumComplex::new(T::zero(), (-discr).sqrt()); + + let half_tra = (hnn + hmm) * crate::convert(0.5); + out[m] = MaybeUninit::new( + NumComplex::new(half_tra.clone(), T::zero()) + sqrt_discr.clone(), + ); + out[m + 1] = + MaybeUninit::new(NumComplex::new(half_tra, T::zero()) - sqrt_discr.clone()); + + m += 2; + } + } + + if m == dim - 1 { + out[m] = MaybeUninit::new(NumComplex::new(t[(m, m)].clone(), T::zero())); + } + } + + fn delimit_subproblem(t: &mut OMatrix, eps: T::RealField, end: usize) -> (usize, usize) + where + D: DimSub, + DefaultAllocator: Allocator>, + { + let mut n = end; + + while n > 0 { + let m = n - 1; + + if t[(n, m)].clone().norm1() + <= eps.clone() * (t[(n, n)].clone().norm1() + t[(m, m)].clone().norm1()) + { + t[(n, m)] = T::zero(); + } else { + break; + } + + n -= 1; + } + + if n == 0 { + return (0, 0); + } + + let mut new_start = n - 1; + while new_start > 0 { + let m = new_start - 1; + + let off_diag = t[(new_start, m)].clone(); + if off_diag.is_zero() + || off_diag.norm1() + <= eps.clone() + * (t[(new_start, new_start)].clone().norm1() + t[(m, m)].clone().norm1()) + { + t[(new_start, m)] = T::zero(); + break; + } + + new_start -= 1; + } + + (new_start, n) + } + + /// Retrieves the unitary matrix `Q` and the upper-quasitriangular matrix `T` such that the + /// decomposed matrix equals `Q * T * Q.transpose()`. + pub fn unpack(self) -> (OMatrix, OMatrix) { + (self.q, self.t) + } + + /// Computes the real eigenvalues of the decomposed matrix. + /// + /// Return `None` if some eigenvalues are complex. + #[must_use] + pub fn eigenvalues(&self) -> Option> { + let mut out = Matrix::zeros_generic(self.t.shape_generic().0, Const::<1>); + if Self::do_eigenvalues(&self.t, &mut out) { + Some(out) + } else { + None + } + } + + /// Computes the complex eigenvalues of the decomposed matrix. + #[must_use] + pub fn complex_eigenvalues(&self) -> OVector, D> + where + T: RealField, + DefaultAllocator: Allocator, + { + let mut out = Matrix::uninit(self.t.shape_generic().0, Const::<1>); + Self::do_complex_eigenvalues(&self.t, &mut out); + // Safety: out has been fully initialized by do_complex_eigenvalues. + unsafe { out.assume_init() } + } +} + +fn decompose_2x2( + mut m: OMatrix, + compute_q: bool, +) -> Option<(Option>, OMatrix)> +where + DefaultAllocator: Allocator, +{ + let dim = m.shape_generic().0; + let mut q = None; + match compute_2x2_basis(&m.fixed_view::<2, 2>(0, 0)) { + Some(rot) => { + let mut m = m.fixed_view_mut::<2, 2>(0, 0); + let inv_rot = rot.inverse(); + inv_rot.rotate(&mut m); + rot.rotate_rows(&mut m); + m[(1, 0)] = T::zero(); + + if compute_q { + // XXX: we have to build the matrix manually because + // rot.to_rotation_matrix().unwrap() causes an ICE. + let c = T::from_real(rot.c()); + q = Some(OMatrix::from_column_slice_generic( + dim, + dim, + &[c.clone(), rot.s(), -rot.s().conjugate(), c], + )); + } + } + None => { + if compute_q { + q = Some(OMatrix::identity_generic(dim, dim)); + } + } + }; + + Some((q, m)) +} + +fn compute_2x2_eigvals>( + m: &SquareMatrix, +) -> Option<(T, T)> { + // Solve the 2x2 eigenvalue subproblem. + let h00 = m[(0, 0)].clone(); + let h10 = m[(1, 0)].clone(); + let h01 = m[(0, 1)].clone(); + let h11 = m[(1, 1)].clone(); + + // NOTE: this discriminant computation is more stable than the + // one based on the trace and determinant: 0.25 * tra * tra - det + // because it ensures positiveness for symmetric matrices. + let val = (h00.clone() - h11.clone()) * crate::convert(0.5); + let discr = h10 * h01 + val.clone() * val; + + discr.try_sqrt().map(|sqrt_discr| { + let half_tra = (h00 + h11) * crate::convert(0.5); + (half_tra.clone() + sqrt_discr.clone(), half_tra - sqrt_discr) + }) +} + +// Computes the 2x2 transformation that upper-triangulates a 2x2 matrix with real eigenvalues. +/// Computes the singular vectors for a 2x2 matrix. +/// +/// Returns `None` if the matrix has complex eigenvalues, or is upper-triangular. In both case, +/// the basis is the identity. +fn compute_2x2_basis>( + m: &SquareMatrix, +) -> Option> { + let h10 = m[(1, 0)].clone(); + + if h10.is_zero() { + return None; + } + + if let Some((eigval1, eigval2)) = compute_2x2_eigvals(m) { + let x1 = eigval1 - m[(1, 1)].clone(); + let x2 = eigval2 - m[(1, 1)].clone(); + + // NOTE: Choose the one that yields a larger x component. + // This is necessary for numerical stability of the normalization of the complex + // number. + if x1.clone().norm1() > x2.clone().norm1() { + Some(GivensRotation::new(x1, h10).0) + } else { + Some(GivensRotation::new(x2, h10).0) + } + } else { + None + } +} + +impl> SquareMatrix +where + D: DimSub, // For Hessenberg. + DefaultAllocator: + Allocator> + Allocator> + Allocator + Allocator, +{ + /// Computes the eigenvalues of this matrix. + #[must_use] + pub fn eigenvalues(&self) -> Option> { + assert!( + self.is_square(), + "Unable to compute eigenvalues of a non-square matrix." + ); + + let mut work = Matrix::zeros_generic(self.shape_generic().0, Const::<1>); + + // Special case for 2x2 matrices. + if self.nrows() == 2 { + // TODO: can we avoid this slicing + // (which is needed here just to transform D to U2)? + let me = self.fixed_view::<2, 2>(0, 0); + return match compute_2x2_eigvals(&me) { + Some((a, b)) => { + work[0] = a; + work[1] = b; + Some(work) + } + None => None, + }; + } + + // TODO: add balancing? + let schur = Schur::do_decompose( + self.clone_owned(), + &mut work, + T::RealField::default_epsilon(), + 0, + false, + ) + .unwrap(); + + if Schur::do_eigenvalues(&schur.1, &mut work) { + Some(work) + } else { + None + } + } + + /// Computes the eigenvalues of this matrix. + #[must_use] + pub fn complex_eigenvalues(&self) -> OVector, D> + // TODO: add balancing? + where + T: RealField, + DefaultAllocator: Allocator, + { + let dim = self.shape_generic().0; + let mut work = Matrix::zeros_generic(dim, Const::<1>); + + let schur = Schur::do_decompose( + self.clone_owned(), + &mut work, + T::default_epsilon(), + 0, + false, + ) + .unwrap(); + let mut eig = Matrix::uninit(dim, Const::<1>); + Schur::do_complex_eigenvalues(&schur.1, &mut eig); + // Safety: eig has been fully initialized by do_complex_eigenvalues. + unsafe { eig.assume_init() } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/solve.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/solve.rs new file mode 100644 index 000000000..7d92720a7 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/solve.rs @@ -0,0 +1,780 @@ +use simba::scalar::ComplexField; +use simba::simd::SimdComplexField; + +use crate::base::allocator::Allocator; +use crate::base::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::{Dim, U1}; +use crate::base::storage::{Storage, StorageMut}; +use crate::base::{DVectorView, DefaultAllocator, Matrix, OMatrix, SquareMatrix, Vector}; + +impl> SquareMatrix { + /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use solve_lower_triangular_mut()?"] + #[inline] + pub fn solve_lower_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.solve_lower_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use solve_upper_triangular_mut()?"] + #[inline] + pub fn solve_upper_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.solve_upper_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn solve_lower_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let cols = b.ncols(); + + for i in 0..cols { + if !self.solve_lower_triangular_vector_mut(&mut b.column_mut(i)) { + return false; + } + } + + true + } + + fn solve_lower_triangular_vector_mut(&self, b: &mut Vector) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in 0..dim { + let coeff; + + unsafe { + let diag = self.get_unchecked((i, i)).clone(); + + if diag.is_zero() { + return false; + } + + coeff = b.vget_unchecked(i).clone() / diag; + *b.vget_unchecked_mut(i) = coeff.clone(); + } + + b.rows_range_mut(i + 1..) + .axpy(-coeff, &self.view_range(i + 1.., i), T::one()); + } + + true + } + + // TODO: add the same but for solving upper-triangular. + /// Solves the linear system `self . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` is considered not-zero. The diagonal is never read as it is + /// assumed to be equal to `diag`. Returns `false` and does not modify its inputs if `diag` is zero. + pub fn solve_lower_triangular_with_diag_mut( + &self, + b: &mut Matrix, + diag: T, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + if diag.is_zero() { + return false; + } + + let dim = self.nrows(); + let cols = b.ncols(); + + for k in 0..cols { + let mut bcol = b.column_mut(k); + + for i in 0..dim - 1 { + let coeff = unsafe { bcol.vget_unchecked(i).clone() } / diag.clone(); + bcol.rows_range_mut(i + 1..) + .axpy(-coeff, &self.view_range(i + 1.., i), T::one()); + } + } + + true + } + + /// Solves the linear system `self . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn solve_upper_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let cols = b.ncols(); + + for i in 0..cols { + if !self.solve_upper_triangular_vector_mut(&mut b.column_mut(i)) { + return false; + } + } + + true + } + + fn solve_upper_triangular_vector_mut(&self, b: &mut Vector) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in (0..dim).rev() { + let coeff; + + unsafe { + let diag = self.get_unchecked((i, i)).clone(); + + if diag.is_zero() { + return false; + } + + coeff = b.vget_unchecked(i).clone() / diag; + *b.vget_unchecked_mut(i) = coeff.clone(); + } + + b.rows_range_mut(..i) + .axpy(-coeff, &self.view_range(..i, i), T::one()); + } + + true + } + + /* + * + * Transpose and adjoint versions + * + */ + /// Computes the solution of the linear system `self.transpose() . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use tr_solve_lower_triangular_mut()?"] + #[inline] + pub fn tr_solve_lower_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.tr_solve_lower_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Computes the solution of the linear system `self.transpose() . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use tr_solve_upper_triangular_mut()?"] + #[inline] + pub fn tr_solve_upper_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.tr_solve_upper_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self.transpose() . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn tr_solve_lower_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let cols = b.ncols(); + + for i in 0..cols { + if !self.xx_solve_lower_triangular_vector_mut( + &mut b.column_mut(i), + |e| e, + |a, b| a.dot(b), + ) { + return false; + } + } + + true + } + + /// Solves the linear system `self.transpose() . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn tr_solve_upper_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let cols = b.ncols(); + + for i in 0..cols { + if !self.xx_solve_upper_triangular_vector_mut( + &mut b.column_mut(i), + |e| e, + |a, b| a.dot(b), + ) { + return false; + } + } + + true + } + + /// Computes the solution of the linear system `self.adjoint() . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use ad_solve_lower_triangular_mut()?"] + #[inline] + pub fn ad_solve_lower_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.ad_solve_lower_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Computes the solution of the linear system `self.adjoint() . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use ad_solve_upper_triangular_mut()?"] + #[inline] + pub fn ad_solve_upper_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + if self.ad_solve_upper_triangular_mut(&mut res) { + Some(res) + } else { + None + } + } + + /// Solves the linear system `self.adjoint() . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn ad_solve_lower_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let cols = b.ncols(); + + for i in 0..cols { + if !self.xx_solve_lower_triangular_vector_mut( + &mut b.column_mut(i), + |e| e.conjugate(), + |a, b| a.dotc(b), + ) { + return false; + } + } + + true + } + + /// Solves the linear system `self.adjoint() . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn ad_solve_upper_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let cols = b.ncols(); + + for i in 0..cols { + if !self.xx_solve_upper_triangular_vector_mut( + &mut b.column_mut(i), + |e| e.conjugate(), + |a, b| a.dotc(b), + ) { + return false; + } + } + + true + } + + #[inline(always)] + fn xx_solve_lower_triangular_vector_mut( + &self, + b: &mut Vector, + conjugate: impl Fn(T) -> T, + dot: impl Fn( + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, + ) -> T, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in (0..dim).rev() { + let dot = dot(&self.view_range(i + 1.., i), &b.view_range(i + 1.., 0)); + + unsafe { + let b_i = b.vget_unchecked_mut(i); + + let diag = conjugate(self.get_unchecked((i, i)).clone()); + + if diag.is_zero() { + return false; + } + + *b_i = (b_i.clone() - dot) / diag; + } + } + + true + } + + #[inline(always)] + fn xx_solve_upper_triangular_vector_mut( + &self, + b: &mut Vector, + conjugate: impl Fn(T) -> T, + dot: impl Fn( + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, + ) -> T, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in 0..dim { + let dot = dot(&self.view_range(..i, i), &b.view_range(..i, 0)); + + unsafe { + let b_i = b.vget_unchecked_mut(i); + let diag = conjugate(self.get_unchecked((i, i)).clone()); + + if diag.is_zero() { + return false; + } + + *b_i = (b_i.clone() - dot) / diag; + } + } + + true + } +} + +/* + * + * SIMD-compatible unchecked versions. + * + */ + +impl> SquareMatrix { + /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use solve_lower_triangular_unchecked_mut()?"] + #[inline] + pub fn solve_lower_triangular_unchecked( + &self, + b: &Matrix, + ) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.solve_lower_triangular_unchecked_mut(&mut res); + res + } + + /// Computes the solution of the linear system `self . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use solve_upper_triangular_unchecked_mut()?"] + #[inline] + pub fn solve_upper_triangular_unchecked( + &self, + b: &Matrix, + ) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.solve_upper_triangular_unchecked_mut(&mut res); + res + } + + /// Solves the linear system `self . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn solve_lower_triangular_unchecked_mut( + &self, + b: &mut Matrix, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..b.ncols() { + self.solve_lower_triangular_vector_unchecked_mut(&mut b.column_mut(i)); + } + } + + fn solve_lower_triangular_vector_unchecked_mut(&self, b: &mut Vector) + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in 0..dim { + let coeff; + + unsafe { + let diag = self.get_unchecked((i, i)).clone(); + coeff = b.vget_unchecked(i).clone() / diag; + *b.vget_unchecked_mut(i) = coeff.clone(); + } + + b.rows_range_mut(i + 1..) + .axpy(-coeff.clone(), &self.view_range(i + 1.., i), T::one()); + } + } + + // TODO: add the same but for solving upper-triangular. + /// Solves the linear system `self . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` is considered not-zero. The diagonal is never read as it is + /// assumed to be equal to `diag`. Returns `false` and does not modify its inputs if `diag` is zero. + pub fn solve_lower_triangular_with_diag_unchecked_mut( + &self, + b: &mut Matrix, + diag: T, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + let cols = b.ncols(); + + for k in 0..cols { + let mut bcol = b.column_mut(k); + + for i in 0..dim - 1 { + let coeff = unsafe { bcol.vget_unchecked(i).clone() } / diag.clone(); + bcol.rows_range_mut(i + 1..) + .axpy(-coeff, &self.view_range(i + 1.., i), T::one()); + } + } + } + + /// Solves the linear system `self . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn solve_upper_triangular_unchecked_mut( + &self, + b: &mut Matrix, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..b.ncols() { + self.solve_upper_triangular_vector_unchecked_mut(&mut b.column_mut(i)) + } + } + + fn solve_upper_triangular_vector_unchecked_mut(&self, b: &mut Vector) + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in (0..dim).rev() { + let coeff; + + unsafe { + let diag = self.get_unchecked((i, i)).clone(); + coeff = b.vget_unchecked(i).clone() / diag; + *b.vget_unchecked_mut(i) = coeff.clone(); + } + + b.rows_range_mut(..i) + .axpy(-coeff, &self.view_range(..i, i), T::one()); + } + } + + /* + * + * Transpose and adjoint versions + * + */ + /// Computes the solution of the linear system `self.transpose() . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use tr_solve_lower_triangular_unchecked_mut()?"] + #[inline] + pub fn tr_solve_lower_triangular_unchecked( + &self, + b: &Matrix, + ) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.tr_solve_lower_triangular_unchecked_mut(&mut res); + res + } + + /// Computes the solution of the linear system `self.transpose() . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use tr_solve_upper_triangular_unchecked_mut()?"] + #[inline] + pub fn tr_solve_upper_triangular_unchecked( + &self, + b: &Matrix, + ) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.tr_solve_upper_triangular_unchecked_mut(&mut res); + res + } + + /// Solves the linear system `self.transpose() . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn tr_solve_lower_triangular_unchecked_mut( + &self, + b: &mut Matrix, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..b.ncols() { + self.xx_solve_lower_triangular_vector_unchecked_mut( + &mut b.column_mut(i), + |e| e, + |a, b| a.dot(b), + ) + } + } + + /// Solves the linear system `self.transpose() . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn tr_solve_upper_triangular_unchecked_mut( + &self, + b: &mut Matrix, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..b.ncols() { + self.xx_solve_upper_triangular_vector_unchecked_mut( + &mut b.column_mut(i), + |e| e, + |a, b| a.dot(b), + ) + } + } + + /// Computes the solution of the linear system `self.adjoint() . x = b` where `x` is the unknown and only + /// the lower-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use ad_solve_lower_triangular_unchecked_mut()?"] + #[inline] + pub fn ad_solve_lower_triangular_unchecked( + &self, + b: &Matrix, + ) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.ad_solve_lower_triangular_unchecked_mut(&mut res); + res + } + + /// Computes the solution of the linear system `self.adjoint() . x = b` where `x` is the unknown and only + /// the upper-triangular part of `self` (including the diagonal) is considered not-zero. + #[must_use = "Did you mean to use ad_solve_upper_triangular_unchecked_mut()?"] + #[inline] + pub fn ad_solve_upper_triangular_unchecked( + &self, + b: &Matrix, + ) -> OMatrix + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut res = b.clone_owned(); + self.ad_solve_upper_triangular_unchecked_mut(&mut res); + res + } + + /// Solves the linear system `self.adjoint() . x = b` where `x` is the unknown and only the + /// lower-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn ad_solve_lower_triangular_unchecked_mut( + &self, + b: &mut Matrix, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..b.ncols() { + self.xx_solve_lower_triangular_vector_unchecked_mut( + &mut b.column_mut(i), + |e| e.simd_conjugate(), + |a, b| a.dotc(b), + ) + } + } + + /// Solves the linear system `self.adjoint() . x = b` where `x` is the unknown and only the + /// upper-triangular part of `self` (including the diagonal) is considered not-zero. + pub fn ad_solve_upper_triangular_unchecked_mut( + &self, + b: &mut Matrix, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..b.ncols() { + self.xx_solve_upper_triangular_vector_unchecked_mut( + &mut b.column_mut(i), + |e| e.simd_conjugate(), + |a, b| a.dotc(b), + ) + } + } + + #[inline(always)] + fn xx_solve_lower_triangular_vector_unchecked_mut( + &self, + b: &mut Vector, + conjugate: impl Fn(T) -> T, + dot: impl Fn( + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, + ) -> T, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let dim = self.nrows(); + + for i in (0..dim).rev() { + let dot = dot(&self.view_range(i + 1.., i), &b.view_range(i + 1.., 0)); + + unsafe { + let b_i = b.vget_unchecked_mut(i); + let diag = conjugate(self.get_unchecked((i, i)).clone()); + *b_i = (b_i.clone() - dot) / diag; + } + } + } + + #[inline(always)] + fn xx_solve_upper_triangular_vector_unchecked_mut( + &self, + b: &mut Vector, + conjugate: impl Fn(T) -> T, + dot: impl Fn( + &DVectorView<'_, T, S::RStride, S::CStride>, + &DVectorView<'_, T, S2::RStride, S2::CStride>, + ) -> T, + ) where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + for i in 0..self.nrows() { + let dot = dot(&self.view_range(..i, i), &b.view_range(..i, 0)); + + unsafe { + let b_i = b.vget_unchecked_mut(i); + let diag = conjugate(self.get_unchecked((i, i)).clone()); + *b_i = (b_i.clone() - dot) / diag; + } + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd.rs new file mode 100644 index 000000000..fb9d707ca --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd.rs @@ -0,0 +1,891 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; +use std::any::TypeId; + +use approx::AbsDiffEq; +use num::{One, Zero}; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2}; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1}; +use crate::storage::Storage; +use crate::{Matrix2, Matrix3, RawStorage, U2, U3}; +use simba::scalar::{ComplexField, RealField}; + +use crate::linalg::givens::GivensRotation; +use crate::linalg::symmetric_eigen; +use crate::linalg::Bidiagonal; + +/// Singular Value Decomposition of a general matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator> + + Allocator, C> + + Allocator>, + OMatrix>: Serialize, + OMatrix, C>: Serialize, + OVector>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator> + + Allocator, C> + + Allocator>, + OMatrix>: Deserialize<'de>, + OMatrix, C>: Deserialize<'de>, + OVector>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct SVD, C: Dim> +where + DefaultAllocator: Allocator, C> + + Allocator> + + Allocator>, +{ + /// The left-singular vectors `U` of this SVD. + pub u: Option>>, + /// The right-singular vectors `V^t` of this SVD. + pub v_t: Option, C>>, + /// The singular values of this SVD. + pub singular_values: OVector>, +} + +impl, C: Dim> Copy for SVD +where + DefaultAllocator: Allocator, C> + + Allocator> + + Allocator>, + OMatrix>: Copy, + OMatrix, C>: Copy, + OVector>: Copy, +{ +} + +impl, C: Dim> SVD +where + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, +{ + fn use_special_always_ordered_svd2() -> bool { + TypeId::of::>() == TypeId::of::>() + && TypeId::of::() == TypeId::of::>() + } + + fn use_special_always_ordered_svd3() -> bool { + TypeId::of::>() == TypeId::of::>() + && TypeId::of::() == TypeId::of::>() + } + + /// Computes the Singular Value Decomposition of `matrix` using implicit shift. + /// The singular values are not guaranteed to be sorted in any particular order. + /// If a descending order is required, consider using `new` instead. + pub fn new_unordered(matrix: OMatrix, compute_u: bool, compute_v: bool) -> Self { + Self::try_new_unordered( + matrix, + compute_u, + compute_v, + T::RealField::default_epsilon() * crate::convert(5.0), + 0, + ) + .unwrap() + } + + /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. + /// The singular values are not guaranteed to be sorted in any particular order. + /// If a descending order is required, consider using `try_new` instead. + /// + /// # Arguments + /// + /// * `compute_u` − set this to `true` to enable the computation of left-singular vectors. + /// * `compute_v` − set this to `true` to enable the computation of right-singular vectors. + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_new_unordered( + mut matrix: OMatrix, + compute_u: bool, + compute_v: bool, + eps: T::RealField, + max_niter: usize, + ) -> Option { + assert!( + !matrix.is_empty(), + "Cannot compute the SVD of an empty matrix." + ); + let (nrows, ncols) = matrix.shape_generic(); + let min_nrows_ncols = nrows.min(ncols); + + if Self::use_special_always_ordered_svd2() { + // SAFETY: the reference transmutes are OK since we checked that the types match exactly. + let matrix: &Matrix2 = unsafe { std::mem::transmute(&matrix) }; + let result = super::svd2::svd_ordered2(matrix, compute_u, compute_v); + let typed_result: &Self = unsafe { std::mem::transmute(&result) }; + return Some(typed_result.clone()); + } else if Self::use_special_always_ordered_svd3() { + // SAFETY: the reference transmutes are OK since we checked that the types match exactly. + let matrix: &Matrix3 = unsafe { std::mem::transmute(&matrix) }; + let result = super::svd3::svd_ordered3(matrix, compute_u, compute_v, eps, max_niter); + let typed_result: &Self = unsafe { std::mem::transmute(&result) }; + return Some(typed_result.clone()); + } + + let dim = min_nrows_ncols.value(); + + let m_amax = matrix.camax(); + + if !m_amax.is_zero() { + matrix.unscale_mut(m_amax.clone()); + } + + let bi_matrix = Bidiagonal::new(matrix); + let mut u = if compute_u { Some(bi_matrix.u()) } else { None }; + let mut v_t = if compute_v { + Some(bi_matrix.v_t()) + } else { + None + }; + let mut diagonal = bi_matrix.diagonal(); + let mut off_diagonal = bi_matrix.off_diagonal(); + + let mut niter = 0; + let (mut start, mut end) = Self::delimit_subproblem( + &mut diagonal, + &mut off_diagonal, + &mut u, + &mut v_t, + bi_matrix.is_upper_diagonal(), + dim - 1, + eps.clone(), + ); + + while end != start { + let subdim = end - start + 1; + + // Solve the subproblem. + #[allow(clippy::comparison_chain)] + if subdim > 2 { + let m = end - 1; + let n = end; + + let mut vec; + { + let dm = diagonal[m].clone(); + let dn = diagonal[n].clone(); + let fm = off_diagonal[m].clone(); + + let tmm = dm.clone() * dm.clone() + + off_diagonal[m - 1].clone() * off_diagonal[m - 1].clone(); + let tmn = dm * fm.clone(); + let tnn = dn.clone() * dn + fm.clone() * fm; + + let shift = symmetric_eigen::wilkinson_shift(tmm, tnn, tmn); + + vec = Vector2::new( + diagonal[start].clone() * diagonal[start].clone() - shift, + diagonal[start].clone() * off_diagonal[start].clone(), + ); + } + + for k in start..n { + let m12 = if k == n - 1 { + T::RealField::zero() + } else { + off_diagonal[k + 1].clone() + }; + + let mut subm = Matrix2x3::new( + diagonal[k].clone(), + off_diagonal[k].clone(), + T::RealField::zero(), + T::RealField::zero(), + diagonal[k + 1].clone(), + m12, + ); + + if let Some((rot1, norm1)) = GivensRotation::cancel_y(&vec) { + rot1.inverse() + .rotate_rows(&mut subm.fixed_columns_mut::<2>(0)); + let rot1 = GivensRotation::new_unchecked(rot1.c(), T::from_real(rot1.s())); + + if k > start { + // This is not the first iteration. + off_diagonal[k - 1] = norm1; + } + + let v = Vector2::new(subm[(0, 0)].clone(), subm[(1, 0)].clone()); + // TODO: does the case `v.y == 0` ever happen? + let (rot2, norm2) = GivensRotation::cancel_y(&v) + .unwrap_or((GivensRotation::identity(), subm[(0, 0)].clone())); + + rot2.rotate(&mut subm.fixed_columns_mut::<2>(1)); + let rot2 = GivensRotation::new_unchecked(rot2.c(), T::from_real(rot2.s())); + + subm[(0, 0)] = norm2; + + if let Some(ref mut v_t) = v_t { + if bi_matrix.is_upper_diagonal() { + rot1.rotate(&mut v_t.fixed_rows_mut::<2>(k)); + } else { + rot2.rotate(&mut v_t.fixed_rows_mut::<2>(k)); + } + } + + if let Some(ref mut u) = u { + if bi_matrix.is_upper_diagonal() { + rot2.inverse().rotate_rows(&mut u.fixed_columns_mut::<2>(k)); + } else { + rot1.inverse().rotate_rows(&mut u.fixed_columns_mut::<2>(k)); + } + } + + diagonal[k] = subm[(0, 0)].clone(); + diagonal[k + 1] = subm[(1, 1)].clone(); + off_diagonal[k] = subm[(0, 1)].clone(); + + if k != n - 1 { + off_diagonal[k + 1] = subm[(1, 2)].clone(); + } + + vec.x = subm[(0, 1)].clone(); + vec.y = subm[(0, 2)].clone(); + } else { + break; + } + } + } else if subdim == 2 { + // Solve the remaining 2x2 subproblem. + let (u2, s, v2) = compute_2x2_uptrig_svd( + diagonal[start].clone(), + off_diagonal[start].clone(), + diagonal[start + 1].clone(), + compute_u && bi_matrix.is_upper_diagonal() + || compute_v && !bi_matrix.is_upper_diagonal(), + compute_v && bi_matrix.is_upper_diagonal() + || compute_u && !bi_matrix.is_upper_diagonal(), + ); + let u2 = u2.map(|u2| GivensRotation::new_unchecked(u2.c(), T::from_real(u2.s()))); + let v2 = v2.map(|v2| GivensRotation::new_unchecked(v2.c(), T::from_real(v2.s()))); + + diagonal[start] = s[0].clone(); + diagonal[start + 1] = s[1].clone(); + off_diagonal[start] = T::RealField::zero(); + + if let Some(ref mut u) = u { + let rot = if bi_matrix.is_upper_diagonal() { + u2.clone().unwrap() + } else { + v2.clone().unwrap() + }; + rot.rotate_rows(&mut u.fixed_columns_mut::<2>(start)); + } + + if let Some(ref mut v_t) = v_t { + let rot = if bi_matrix.is_upper_diagonal() { + v2.unwrap() + } else { + u2.unwrap() + }; + rot.inverse().rotate(&mut v_t.fixed_rows_mut::<2>(start)); + } + + end -= 1; + } + + // Re-delimit the subproblem in case some decoupling occurred. + let sub = Self::delimit_subproblem( + &mut diagonal, + &mut off_diagonal, + &mut u, + &mut v_t, + bi_matrix.is_upper_diagonal(), + end, + eps.clone(), + ); + start = sub.0; + end = sub.1; + + niter += 1; + if niter == max_niter { + return None; + } + } + + diagonal *= m_amax; + + // Ensure all singular value are non-negative. + for i in 0..dim { + let sval = diagonal[i].clone(); + + if sval < T::RealField::zero() { + diagonal[i] = -sval; + + if let Some(ref mut u) = u { + u.column_mut(i).neg_mut(); + } + } + } + + Some(Self { + u, + v_t, + singular_values: diagonal, + }) + } + + /* + fn display_bidiag(b: &Bidiagonal, begin: usize, end: usize) { + for i in begin .. end { + for k in begin .. i { + print!(" "); + } + println!("{} {}", b.diagonal[i], b.off_diagonal[i]); + } + for k in begin .. end { + print!(" "); + } + println!("{}", b.diagonal[end]); + } + */ + + fn delimit_subproblem( + diagonal: &mut OVector>, + off_diagonal: &mut OVector, U1>>, + u: &mut Option>>, + v_t: &mut Option, C>>, + is_upper_diagonal: bool, + end: usize, + eps: T::RealField, + ) -> (usize, usize) { + let mut n = end; + + while n > 0 { + let m = n - 1; + + if off_diagonal[m].is_zero() + || off_diagonal[m].clone().norm1() + <= eps.clone() * (diagonal[n].clone().norm1() + diagonal[m].clone().norm1()) + { + off_diagonal[m] = T::RealField::zero(); + } else if diagonal[m].clone().norm1() <= eps { + diagonal[m] = T::RealField::zero(); + Self::cancel_horizontal_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m, + m + 1, + ); + + if m != 0 { + Self::cancel_vertical_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m - 1, + ); + } + } else if diagonal[n].clone().norm1() <= eps { + diagonal[n] = T::RealField::zero(); + Self::cancel_vertical_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m, + ); + } else { + break; + } + + n -= 1; + } + + if n == 0 { + return (0, 0); + } + + let mut new_start = n - 1; + while new_start > 0 { + let m = new_start - 1; + + if off_diagonal[m].clone().norm1() + <= eps.clone() * (diagonal[new_start].clone().norm1() + diagonal[m].clone().norm1()) + { + off_diagonal[m] = T::RealField::zero(); + break; + } + // TODO: write a test that enters this case. + else if diagonal[m].clone().norm1() <= eps { + diagonal[m] = T::RealField::zero(); + Self::cancel_horizontal_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m, + n, + ); + + if m != 0 { + Self::cancel_vertical_off_diagonal_elt( + diagonal, + off_diagonal, + u, + v_t, + is_upper_diagonal, + m - 1, + ); + } + break; + } + + new_start -= 1; + } + + (new_start, n) + } + + // Cancels the i-th off-diagonal element using givens rotations. + fn cancel_horizontal_off_diagonal_elt( + diagonal: &mut OVector>, + off_diagonal: &mut OVector, U1>>, + u: &mut Option>>, + v_t: &mut Option, C>>, + is_upper_diagonal: bool, + i: usize, + end: usize, + ) { + let mut v = Vector2::new(off_diagonal[i].clone(), diagonal[i + 1].clone()); + off_diagonal[i] = T::RealField::zero(); + + for k in i..end { + if let Some((rot, norm)) = GivensRotation::cancel_x(&v) { + let rot = GivensRotation::new_unchecked(rot.c(), T::from_real(rot.s())); + diagonal[k + 1] = norm; + + if is_upper_diagonal { + if let Some(ref mut u) = *u { + rot.inverse() + .rotate_rows(&mut u.fixed_columns_with_step_mut::<2>(i, k - i)); + } + } else if let Some(ref mut v_t) = *v_t { + rot.rotate(&mut v_t.fixed_rows_with_step_mut::<2>(i, k - i)); + } + + if k + 1 != end { + v.x = -rot.s().real() * off_diagonal[k + 1].clone(); + v.y = diagonal[k + 2].clone(); + off_diagonal[k + 1] *= rot.c(); + } + } else { + break; + } + } + } + + // Cancels the i-th off-diagonal element using givens rotations. + fn cancel_vertical_off_diagonal_elt( + diagonal: &mut OVector>, + off_diagonal: &mut OVector, U1>>, + u: &mut Option>>, + v_t: &mut Option, C>>, + is_upper_diagonal: bool, + i: usize, + ) { + let mut v = Vector2::new(diagonal[i].clone(), off_diagonal[i].clone()); + off_diagonal[i] = T::RealField::zero(); + + for k in (0..i + 1).rev() { + if let Some((rot, norm)) = GivensRotation::cancel_y(&v) { + let rot = GivensRotation::new_unchecked(rot.c(), T::from_real(rot.s())); + diagonal[k] = norm; + + if is_upper_diagonal { + if let Some(ref mut v_t) = *v_t { + rot.rotate(&mut v_t.fixed_rows_with_step_mut::<2>(k, i - k)); + } + } else if let Some(ref mut u) = *u { + rot.inverse() + .rotate_rows(&mut u.fixed_columns_with_step_mut::<2>(k, i - k)); + } + + if k > 0 { + v.x = diagonal[k - 1].clone(); + v.y = rot.s().real() * off_diagonal[k - 1].clone(); + off_diagonal[k - 1] *= rot.c(); + } + } else { + break; + } + } + } + + /// Computes the rank of the decomposed matrix, i.e., the number of singular values greater + /// than `eps`. + #[must_use] + pub fn rank(&self, eps: T::RealField) -> usize { + assert!( + eps >= T::RealField::zero(), + "SVD rank: the epsilon must be non-negative." + ); + self.singular_values.iter().filter(|e| **e > eps).count() + } + + /// Rebuild the original matrix. + /// + /// This is useful if some of the singular values have been manually modified. + /// Returns `Err` if the right- and left- singular vectors have not been + /// computed at construction-time. + pub fn recompose(self) -> Result, &'static str> { + match (self.u, self.v_t) { + (Some(mut u), Some(v_t)) => { + for i in 0..self.singular_values.len() { + let val = self.singular_values[i].clone(); + u.column_mut(i).scale_mut(val); + } + Ok(u * v_t) + } + (None, None) => Err("SVD recomposition: U and V^t have not been computed."), + (None, _) => Err("SVD recomposition: U has not been computed."), + (_, None) => Err("SVD recomposition: V^t has not been computed."), + } + } + + /// Computes the pseudo-inverse of the decomposed matrix. + /// + /// Any singular value smaller than `eps` is assumed to be zero. + /// Returns `Err` if the right- and left- singular vectors have not + /// been computed at construction-time. + pub fn pseudo_inverse(mut self, eps: T::RealField) -> Result, &'static str> + where + DefaultAllocator: Allocator, + { + if eps < T::RealField::zero() { + Err("SVD pseudo inverse: the epsilon must be non-negative.") + } else { + for i in 0..self.singular_values.len() { + let val = self.singular_values[i].clone(); + + if val > eps { + self.singular_values[i] = T::RealField::one() / val; + } else { + self.singular_values[i] = T::RealField::zero(); + } + } + + self.recompose().map(|m| m.adjoint()) + } + } + + /// Solves the system `self * x = b` where `self` is the decomposed matrix and `x` the unknown. + /// + /// Any singular value smaller than `eps` is assumed to be zero. + /// Returns `Err` if the singular vectors `U` and `V` have not been computed. + // TODO: make this more generic wrt the storage types and the dimensions for `b`. + pub fn solve( + &self, + b: &Matrix, + eps: T::RealField, + ) -> Result, &'static str> + where + S2: Storage, + DefaultAllocator: Allocator + Allocator, C2>, + ShapeConstraint: SameNumberOfRows, + { + if eps < T::RealField::zero() { + Err("SVD solve: the epsilon must be non-negative.") + } else { + match (&self.u, &self.v_t) { + (Some(u), Some(v_t)) => { + let mut ut_b = u.ad_mul(b); + + for j in 0..ut_b.ncols() { + let mut col = ut_b.column_mut(j); + + for i in 0..self.singular_values.len() { + let val = self.singular_values[i].clone(); + if val > eps { + col[i] = col[i].clone().unscale(val); + } else { + col[i] = T::zero(); + } + } + } + + Ok(v_t.ad_mul(&ut_b)) + } + (None, None) => Err("SVD solve: U and V^t have not been computed."), + (None, _) => Err("SVD solve: U has not been computed."), + (_, None) => Err("SVD solve: V^t has not been computed."), + } + } + } + + /// converts SVD results to Polar decomposition form of the original Matrix: `A = P' * U`. + /// + /// The polar decomposition used here is Left Polar Decomposition (or Reverse Polar Decomposition) + /// Returns None if the singular vectors of the SVD haven't been calculated + pub fn to_polar(&self) -> Option<(OMatrix, OMatrix)> + where + DefaultAllocator: Allocator //result + + Allocator, R> // adjoint + + Allocator> // mapped vals + + Allocator // result + + Allocator, DimMinimum>, // square matrix + { + match (&self.u, &self.v_t) { + (Some(u), Some(v_t)) => Some(( + u * OMatrix::from_diagonal(&self.singular_values.map(|e| T::from_real(e))) + * u.adjoint(), + u * v_t, + )), + _ => None, + } + } +} + +impl, C: Dim> SVD +where + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator>, // for sorted singular values +{ + /// Computes the Singular Value Decomposition of `matrix` using implicit shift. + /// The singular values are guaranteed to be sorted in descending order. + /// If this order is not required consider using `new_unordered`. + pub fn new(matrix: OMatrix, compute_u: bool, compute_v: bool) -> Self { + let mut svd = Self::new_unordered(matrix, compute_u, compute_v); + + if !Self::use_special_always_ordered_svd3() && !Self::use_special_always_ordered_svd2() { + svd.sort_by_singular_values(); + } + + svd + } + + /// Attempts to compute the Singular Value Decomposition of `matrix` using implicit shift. + /// The singular values are guaranteed to be sorted in descending order. + /// If this order is not required consider using `try_new_unordered`. + /// + /// # Arguments + /// + /// * `compute_u` − set this to `true` to enable the computation of left-singular vectors. + /// * `compute_v` − set this to `true` to enable the computation of right-singular vectors. + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_new( + matrix: OMatrix, + compute_u: bool, + compute_v: bool, + eps: T::RealField, + max_niter: usize, + ) -> Option { + Self::try_new_unordered(matrix, compute_u, compute_v, eps, max_niter).map(|mut svd| { + if !Self::use_special_always_ordered_svd3() && !Self::use_special_always_ordered_svd2() + { + svd.sort_by_singular_values(); + } + + svd + }) + } + + /// Sort the estimated components of the SVD by its singular values in descending order. + /// Such an ordering is often implicitly required when the decompositions are used for estimation or fitting purposes. + /// Using this function is only required if `new_unordered` or `try_new_unordered` were used and the specific sorting is required afterward. + pub fn sort_by_singular_values(&mut self) { + const VALUE_PROCESSED: usize = usize::MAX; + + // Collect the singular values with their original index, ... + let mut singular_values = self.singular_values.map_with_location(|r, _, e| (e, r)); + assert_ne!( + singular_values.data.shape().0.value(), + VALUE_PROCESSED, + "Too many singular values" + ); + + // ... sort the singular values, ... + singular_values + .as_mut_slice() + .sort_unstable_by(|(a, _), (b, _)| b.partial_cmp(a).expect("Singular value was NaN")); + + // ... and store them. + self.singular_values + .zip_apply(&singular_values, |value, (new_value, _)| { + value.clone_from(&new_value) + }); + + // Calculate required permutations given the sorted indices. + // We need to identify all circles to calculate the required swaps. + let mut permutations = + crate::PermutationSequence::identity_generic(singular_values.data.shape().0); + + for i in 0..singular_values.len() { + let mut index_1 = i; + let mut index_2 = singular_values[i].1; + + // Check whether the value was already visited ... + while index_2 != VALUE_PROCESSED // ... or a "double swap" must be avoided. + && singular_values[index_2].1 != VALUE_PROCESSED + { + // Add the permutation ... + permutations.append_permutation(index_1, index_2); + // ... and mark the value as visited. + singular_values[index_1].1 = VALUE_PROCESSED; + + index_1 = index_2; + index_2 = singular_values[index_1].1; + } + } + + // Permute the optional components + if let Some(u) = self.u.as_mut() { + permutations.permute_columns(u); + } + + if let Some(v_t) = self.v_t.as_mut() { + permutations.permute_rows(v_t); + } + } +} + +impl, C: Dim, S: Storage> Matrix +where + DimMinimum: DimSub, // for Bidiagonal. + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator> + + Allocator> + + Allocator, U1>>, +{ + /// Computes the singular values of this matrix. + /// The singular values are not guaranteed to be sorted in any particular order. + /// If a descending order is required, consider using `singular_values` instead. + #[must_use] + pub fn singular_values_unordered(&self) -> OVector> { + SVD::new_unordered(self.clone_owned(), false, false).singular_values + } + + /// Computes the rank of this matrix. + /// + /// All singular values below `eps` are considered equal to 0. + #[must_use] + pub fn rank(&self, eps: T::RealField) -> usize { + let svd = SVD::new_unordered(self.clone_owned(), false, false); + svd.rank(eps) + } + + /// Computes the pseudo-inverse of this matrix. + /// + /// All singular values below `eps` are considered equal to 0. + pub fn pseudo_inverse(self, eps: T::RealField) -> Result, &'static str> + where + DefaultAllocator: Allocator, + { + SVD::new_unordered(self.clone_owned(), true, true).pseudo_inverse(eps) + } +} + +impl, C: Dim, S: Storage> Matrix +where + DimMinimum: DimSub, + DefaultAllocator: Allocator + + Allocator + + Allocator + + Allocator, U1>> + + Allocator, C> + + Allocator> + + Allocator>, +{ + /// Computes the singular values of this matrix. + /// The singular values are guaranteed to be sorted in descending order. + /// If this order is not required consider using `singular_values_unordered`. + #[must_use] + pub fn singular_values(&self) -> OVector> { + SVD::new(self.clone_owned(), false, false).singular_values + } +} + +// Explicit formulae inspired from the paper "Computing the Singular Values of 2-by-2 Complex +// Matrices", Sanzheng Qiao and Xiaohong Wang. +// http://www.cas.mcmaster.ca/sqrl/papers/sqrl5.pdf +fn compute_2x2_uptrig_svd( + m11: T, + m12: T, + m22: T, + compute_u: bool, + compute_v: bool, +) -> ( + Option>, + Vector2, + Option>, +) { + let two: T::RealField = crate::convert(2.0f64); + let half: T::RealField = crate::convert(0.5f64); + + let denom = (m11.clone() + m22.clone()).hypot(m12.clone()) + + (m11.clone() - m22.clone()).hypot(m12.clone()); + + // NOTE: v1 is the singular value that is the closest to m22. + // This prevents cancellation issues when constructing the vector `csv` below. If we chose + // otherwise, we would have v1 ~= m11 when m12 is small. This would cause catastrophic + // cancellation on `v1 * v1 - m11 * m11` below. + let mut v1 = m11.clone() * m22.clone() * two / denom.clone(); + let mut v2 = half * denom; + + let mut u = None; + let mut v_t = None; + + if compute_u || compute_v { + let (csv, sgn_v) = GivensRotation::new( + m11.clone() * m12.clone(), + v1.clone() * v1.clone() - m11.clone() * m11.clone(), + ); + v1 *= sgn_v.clone(); + v2 *= sgn_v; + + if compute_v { + v_t = Some(csv.clone()); + } + + let cu = (m11.scale(csv.c()) + m12 * csv.s()) / v1.clone(); + let su = (m22 * csv.s()) / v1.clone(); + let (csu, sgn_u) = GivensRotation::new(cu, su); + v1 *= sgn_u.clone(); + v2 *= sgn_u; + + if compute_u { + u = Some(csu); + } + } + + (u, Vector2::new(v1, v2), v_t) +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd2.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd2.rs new file mode 100644 index 000000000..893bb4d51 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd2.rs @@ -0,0 +1,50 @@ +use crate::{Matrix2, RealField, Vector2, SVD, U2}; + +// Implementation of the 2D SVD from https://ieeexplore.ieee.org/document/486688 +// See also https://scicomp.stackexchange.com/questions/8899/robust-algorithm-for-2-times-2-svd +pub fn svd_ordered2( + m: &Matrix2, + compute_u: bool, + compute_v: bool, +) -> SVD { + let half: T = crate::convert(0.5); + let one: T = crate::convert(1.0); + + let e = (m.m11.clone() + m.m22.clone()) * half.clone(); + let f = (m.m11.clone() - m.m22.clone()) * half.clone(); + let g = (m.m21.clone() + m.m12.clone()) * half.clone(); + let h = (m.m21.clone() - m.m12.clone()) * half.clone(); + let q = (e.clone() * e.clone() + h.clone() * h.clone()).sqrt(); + let r = (f.clone() * f.clone() + g.clone() * g.clone()).sqrt(); + + // Note that the singular values are always sorted because sx >= sy + // because q >= 0 and r >= 0. + let sx = q.clone() + r.clone(); + let sy = q - r; + let sy_sign = if sy < T::zero() { -one } else { one }; + let singular_values = Vector2::new(sx, sy * sy_sign.clone()); + + if compute_u || compute_v { + let a1 = g.atan2(f); + let a2 = h.atan2(e); + let theta = (a2.clone() - a1.clone()) * half.clone(); + let phi = (a2 + a1) * half; + let (st, ct) = theta.sin_cos(); + let (sp, cp) = phi.sin_cos(); + + let u = Matrix2::new(cp.clone(), -sp.clone(), sp, cp); + let v_t = Matrix2::new(ct.clone(), -st.clone(), st * sy_sign.clone(), ct * sy_sign); + + SVD { + u: if compute_u { Some(u) } else { None }, + singular_values, + v_t: if compute_v { Some(v_t) } else { None }, + } + } else { + SVD { + u: None, + singular_values, + v_t: None, + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd3.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd3.rs new file mode 100644 index 000000000..fb3b67bb9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/svd3.rs @@ -0,0 +1,55 @@ +use crate::{Matrix3, SVD, U3}; +use simba::scalar::RealField; + +// For the 3x3 case, on the GPU, it is much more efficient to compute the SVD +// using an eigendecomposition followed by a QR decomposition. +// +// This is based on the paper "Computing the Singular Value Decomposition of 3 x 3 matrices with +// minimal branching and elementary floating point operations" from McAdams, et al. +pub fn svd_ordered3( + m: &Matrix3, + compute_u: bool, + compute_v: bool, + eps: T, + niter: usize, +) -> Option> { + let s = m.tr_mul(m); + let mut v = s.try_symmetric_eigen(eps, niter)?.eigenvectors; + let mut b = m * &v; + + // Sort singular values. This is a necessary step to ensure that + // the QR decompositions R matrix ends up diagonal. + let mut rho0 = b.column(0).norm_squared(); + let mut rho1 = b.column(1).norm_squared(); + let mut rho2 = b.column(2).norm_squared(); + + if rho0 < rho1 { + b.swap_columns(0, 1); + b.column_mut(1).neg_mut(); + v.swap_columns(0, 1); + v.column_mut(1).neg_mut(); + std::mem::swap(&mut rho0, &mut rho1); + } + if rho0 < rho2 { + b.swap_columns(0, 2); + b.column_mut(2).neg_mut(); + v.swap_columns(0, 2); + v.column_mut(2).neg_mut(); + std::mem::swap(&mut rho0, &mut rho2); + } + if rho1 < rho2 { + b.swap_columns(1, 2); + b.column_mut(2).neg_mut(); + v.swap_columns(1, 2); + v.column_mut(2).neg_mut(); + std::mem::swap(&mut rho0, &mut rho2); + } + + let qr = b.qr(); + + Some(SVD { + u: if compute_u { Some(qr.q()) } else { None }, + singular_values: qr.diag_internal().map(|e| e.abs()), + v_t: if compute_v { Some(v.transpose()) } else { None }, + }) +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_eigen.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_eigen.rs new file mode 100644 index 000000000..aa05f0e72 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_eigen.rs @@ -0,0 +1,423 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use approx::AbsDiffEq; +use num::Zero; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, Matrix2, OMatrix, OVector, SquareMatrix, Vector2}; +use crate::dimension::{Dim, DimDiff, DimSub, U1}; +use crate::storage::Storage; +use simba::scalar::ComplexField; + +use crate::linalg::givens::GivensRotation; +use crate::linalg::SymmetricTridiagonal; + +/// Eigendecomposition of a symmetric matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator, + OVector: Serialize, + OMatrix: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator, + OVector: Deserialize<'de>, + OMatrix: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct SymmetricEigen +where + DefaultAllocator: Allocator + Allocator, +{ + /// The eigenvectors of the decomposed matrix. + pub eigenvectors: OMatrix, + + /// The unsorted eigenvalues of the decomposed matrix. + pub eigenvalues: OVector, +} + +impl Copy for SymmetricEigen +where + DefaultAllocator: Allocator + Allocator, + OMatrix: Copy, + OVector: Copy, +{ +} + +impl SymmetricEigen +where + DefaultAllocator: Allocator + Allocator, +{ + /// Computes the eigendecomposition of the given symmetric matrix. + /// + /// Only the lower-triangular parts (including its diagonal) of `m` is read. + pub fn new(m: OMatrix) -> Self + where + D: DimSub, + DefaultAllocator: Allocator> + Allocator>, + { + Self::try_new(m, T::RealField::default_epsilon(), 0).unwrap() + } + + /// Computes the eigendecomposition of the given symmetric matrix with user-specified + /// convergence parameters. + /// + /// Only the lower-triangular part (including its diagonal) of `m` is read. + /// + /// # Arguments + /// + /// * `eps` − tolerance used to determine when a value converged to 0. + /// * `max_niter` − maximum total number of iterations performed by the algorithm. If this + /// number of iteration is exceeded, `None` is returned. If `niter == 0`, then the algorithm + /// continues indefinitely until convergence. + pub fn try_new(m: OMatrix, eps: T::RealField, max_niter: usize) -> Option + where + D: DimSub, + DefaultAllocator: Allocator> + Allocator>, + { + Self::do_decompose(m, true, eps, max_niter).map(|(vals, vecs)| SymmetricEigen { + eigenvectors: vecs.unwrap(), + eigenvalues: vals, + }) + } + + fn do_decompose( + mut matrix: OMatrix, + eigenvectors: bool, + eps: T::RealField, + max_niter: usize, + ) -> Option<(OVector, Option>)> + where + D: DimSub, + DefaultAllocator: Allocator> + Allocator>, + { + assert!( + matrix.is_square(), + "Unable to compute the eigendecomposition of a non-square matrix." + ); + let dim = matrix.nrows(); + let m_amax = matrix.camax(); + + if !m_amax.is_zero() { + matrix.unscale_mut(m_amax.clone()); + } + + let (mut q_mat, mut diag, mut off_diag); + + if eigenvectors { + let res = SymmetricTridiagonal::new(matrix).unpack(); + q_mat = Some(res.0); + diag = res.1; + off_diag = res.2; + } else { + let res = SymmetricTridiagonal::new(matrix).unpack_tridiagonal(); + q_mat = None; + diag = res.0; + off_diag = res.1; + } + + if dim == 1 { + diag.scale_mut(m_amax); + return Some((diag, q_mat)); + } + + let mut niter = 0; + let (mut start, mut end) = + Self::delimit_subproblem(&diag, &mut off_diag, dim - 1, eps.clone()); + + while end != start { + let subdim = end - start + 1; + + #[allow(clippy::comparison_chain)] + if subdim > 2 { + let m = end - 1; + let n = end; + + let mut vec = Vector2::new( + diag[start].clone() + - wilkinson_shift( + diag[m].clone().clone(), + diag[n].clone(), + off_diag[m].clone().clone(), + ), + off_diag[start].clone(), + ); + + for i in start..n { + let j = i + 1; + + if let Some((rot, norm)) = GivensRotation::cancel_y(&vec) { + if i > start { + // Not the first iteration. + off_diag[i - 1] = norm; + } + + let mii = diag[i].clone(); + let mjj = diag[j].clone(); + let mij = off_diag[i].clone(); + + let cc = rot.c() * rot.c(); + let ss = rot.s() * rot.s(); + let cs = rot.c() * rot.s(); + + let b = cs.clone() * crate::convert(2.0) * mij.clone(); + + diag[i] = (cc.clone() * mii.clone() + ss.clone() * mjj.clone()) - b.clone(); + diag[j] = (ss.clone() * mii.clone() + cc.clone() * mjj.clone()) + b; + off_diag[i] = cs * (mii - mjj) + mij * (cc - ss); + + if i != n - 1 { + vec.x = off_diag[i].clone(); + vec.y = -rot.s() * off_diag[i + 1].clone(); + off_diag[i + 1] *= rot.c(); + } + + if let Some(ref mut q) = q_mat { + let rot = GivensRotation::new_unchecked(rot.c(), T::from_real(rot.s())); + rot.inverse().rotate_rows(&mut q.fixed_columns_mut::<2>(i)); + } + } else { + break; + } + } + + if off_diag[m].clone().norm1() + <= eps.clone() * (diag[m].clone().norm1() + diag[n].clone().norm1()) + { + end -= 1; + } + } else if subdim == 2 { + let m = Matrix2::new( + diag[start].clone(), + off_diag[start].clone().conjugate(), + off_diag[start].clone(), + diag[start + 1].clone(), + ); + let eigvals = m.eigenvalues().unwrap(); + let basis = Vector2::new( + eigvals.x.clone() - diag[start + 1].clone(), + off_diag[start].clone(), + ); + + diag[start] = eigvals[0].clone(); + diag[start + 1] = eigvals[1].clone(); + + if let Some(ref mut q) = q_mat { + if let Some((rot, _)) = + GivensRotation::try_new(basis.x.clone(), basis.y.clone(), eps.clone()) + { + let rot = GivensRotation::new_unchecked(rot.c(), T::from_real(rot.s())); + rot.rotate_rows(&mut q.fixed_columns_mut::<2>(start)); + } + } + + end -= 1; + } + + // Re-delimit the subproblem in case some decoupling occurred. + let sub = Self::delimit_subproblem(&diag, &mut off_diag, end, eps.clone()); + + start = sub.0; + end = sub.1; + + niter += 1; + if niter == max_niter { + return None; + } + } + + diag.scale_mut(m_amax); + + Some((diag, q_mat)) + } + + fn delimit_subproblem( + diag: &OVector, + off_diag: &mut OVector>, + end: usize, + eps: T::RealField, + ) -> (usize, usize) + where + D: DimSub, + DefaultAllocator: Allocator>, + { + let mut n = end; + + while n > 0 { + let m = n - 1; + + if off_diag[m].clone().norm1() + > eps.clone() * (diag[n].clone().norm1() + diag[m].clone().norm1()) + { + break; + } + + n -= 1; + } + + if n == 0 { + return (0, 0); + } + + let mut new_start = n - 1; + while new_start > 0 { + let m = new_start - 1; + + if off_diag[m].clone().is_zero() + || off_diag[m].clone().norm1() + <= eps.clone() * (diag[new_start].clone().norm1() + diag[m].clone().norm1()) + { + off_diag[m] = T::RealField::zero(); + break; + } + + new_start -= 1; + } + + (new_start, n) + } + + /// Rebuild the original matrix. + /// + /// This is useful if some of the eigenvalues have been manually modified. + #[must_use] + pub fn recompose(&self) -> OMatrix { + let mut u_t = self.eigenvectors.clone(); + for i in 0..self.eigenvalues.len() { + let val = self.eigenvalues[i].clone(); + u_t.column_mut(i).scale_mut(val); + } + u_t.adjoint_mut(); + &self.eigenvectors * u_t + } +} + +/// Computes the wilkinson shift, i.e., the 2x2 symmetric matrix eigenvalue to its tailing +/// component `tnn`. +/// +/// The inputs are interpreted as the 2x2 matrix: +/// tmm tmn +/// tmn tnn +pub fn wilkinson_shift(tmm: T, tnn: T, tmn: T) -> T { + let sq_tmn = tmn.clone() * tmn; + if !sq_tmn.is_zero() { + // We have the guarantee that the denominator won't be zero. + let d = (tmm - tnn.clone()) * crate::convert(0.5); + tnn - sq_tmn.clone() / (d.clone() + d.clone().signum() * (d.clone() * d + sq_tmn).sqrt()) + } else { + tnn + } +} + +/* + * + * Computations of eigenvalues for symmetric matrices. + * + */ +impl, S: Storage> SquareMatrix +where + DefaultAllocator: + Allocator + Allocator> + Allocator + Allocator>, +{ + /// Computes the eigenvalues of this symmetric matrix. + /// + /// Only the lower-triangular part of the matrix is read. + #[must_use] + pub fn symmetric_eigenvalues(&self) -> OVector { + SymmetricEigen::do_decompose( + self.clone_owned(), + false, + T::RealField::default_epsilon(), + 0, + ) + .unwrap() + .0 + } +} + +#[cfg(test)] +mod test { + use crate::base::Matrix2; + + fn expected_shift(m: Matrix2) -> f64 { + let vals = m.eigenvalues().unwrap(); + + if (vals.x - m.m22).abs() < (vals.y - m.m22).abs() { + vals.x + } else { + vals.y + } + } + + #[cfg(feature = "rand")] + #[test] + fn wilkinson_shift_random() { + for _ in 0..1000 { + let m = Matrix2::::new_random(); + let m = m * m.transpose(); + + let expected = expected_shift(m); + let computed = super::wilkinson_shift(m.m11, m.m22, m.m12); + assert!(relative_eq!(expected, computed, epsilon = 1.0e-7)); + } + } + + #[test] + fn wilkinson_shift_zero() { + let m = Matrix2::new(0.0, 0.0, 0.0, 0.0); + assert!(relative_eq!( + expected_shift(m), + super::wilkinson_shift(m.m11, m.m22, m.m12) + )); + } + + #[test] + fn wilkinson_shift_zero_diagonal() { + let m = Matrix2::new(0.0, 42.0, 42.0, 0.0); + assert!(relative_eq!( + expected_shift(m), + super::wilkinson_shift(m.m11, m.m22, m.m12) + )); + } + + #[test] + fn wilkinson_shift_zero_off_diagonal() { + let m = Matrix2::new(42.0, 0.0, 0.0, 64.0); + assert!(relative_eq!( + expected_shift(m), + super::wilkinson_shift(m.m11, m.m22, m.m12) + )); + } + + #[test] + fn wilkinson_shift_zero_trace() { + let m = Matrix2::new(42.0, 20.0, 20.0, -42.0); + assert!(relative_eq!( + expected_shift(m), + super::wilkinson_shift(m.m11, m.m22, m.m12) + )); + } + + #[test] + fn wilkinson_shift_zero_diag_diff_and_zero_off_diagonal() { + let m = Matrix2::new(42.0, 0.0, 0.0, 42.0); + assert!(relative_eq!( + expected_shift(m), + super::wilkinson_shift(m.m11, m.m22, m.m12) + )); + } + + #[test] + fn wilkinson_shift_zero_det() { + let m = Matrix2::new(2.0, 4.0, 4.0, 8.0); + assert!(relative_eq!( + expected_shift(m), + super::wilkinson_shift(m.m11, m.m22, m.m12) + )); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_tridiagonal.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_tridiagonal.rs new file mode 100644 index 000000000..7caa06b39 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/symmetric_tridiagonal.rs @@ -0,0 +1,170 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::Allocator; +use crate::base::{DefaultAllocator, OMatrix, OVector}; +use crate::dimension::{Const, DimDiff, DimSub, U1}; +use simba::scalar::ComplexField; + +use crate::linalg::householder; +use crate::Matrix; +use std::mem::MaybeUninit; + +/// Tridiagonalization of a symmetric matrix. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Serialize, + OVector>: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(deserialize = "DefaultAllocator: Allocator + + Allocator>, + OMatrix: Deserialize<'de>, + OVector>: Deserialize<'de>")) +)] +#[derive(Clone, Debug)] +pub struct SymmetricTridiagonal> +where + DefaultAllocator: Allocator + Allocator>, +{ + tri: OMatrix, + off_diagonal: OVector>, +} + +impl> Copy for SymmetricTridiagonal +where + DefaultAllocator: Allocator + Allocator>, + OMatrix: Copy, + OVector>: Copy, +{ +} + +impl> SymmetricTridiagonal +where + DefaultAllocator: Allocator + Allocator>, +{ + /// Computes the tridiagonalization of the symmetric matrix `m`. + /// + /// Only the lower-triangular part (including the diagonal) of `m` is read. + pub fn new(mut m: OMatrix) -> Self { + let dim = m.shape_generic().0; + + assert!( + m.is_square(), + "Unable to compute the symmetric tridiagonal decomposition of a non-square matrix." + ); + assert!( + dim.value() != 0, + "Unable to compute the symmetric tridiagonal decomposition of an empty matrix." + ); + + let mut off_diagonal = Matrix::uninit(dim.sub(Const::<1>), Const::<1>); + let mut p = Matrix::zeros_generic(dim.sub(Const::<1>), Const::<1>); + + for i in 0..dim.value() - 1 { + let mut m = m.rows_range_mut(i + 1..); + let (mut axis, mut m) = m.columns_range_pair_mut(i, i + 1..); + + let (norm, not_zero) = householder::reflection_axis_mut(&mut axis); + off_diagonal[i] = MaybeUninit::new(norm); + + if not_zero { + let mut p = p.rows_range_mut(i..); + + p.hegemv(crate::convert(2.0), &m, &axis, T::zero()); + + let dot = axis.dotc(&p); + m.hegerc(-T::one(), &p, &axis, T::one()); + m.hegerc(-T::one(), &axis, &p, T::one()); + m.hegerc(dot * crate::convert(2.0), &axis, &axis, T::one()); + } + } + + // Safety: off_diagonal has been fully initialized. + let off_diagonal = unsafe { off_diagonal.assume_init() }; + Self { + tri: m, + off_diagonal, + } + } + + #[doc(hidden)] + // For debugging. + pub fn internal_tri(&self) -> &OMatrix { + &self.tri + } + + /// Retrieve the orthogonal transformation, diagonal, and off diagonal elements of this + /// decomposition. + pub fn unpack( + self, + ) -> ( + OMatrix, + OVector, + OVector>, + ) + where + DefaultAllocator: Allocator + Allocator>, + { + let diag = self.diagonal(); + let q = self.q(); + + (q, diag, self.off_diagonal.map(T::modulus)) + } + + /// Retrieve the diagonal, and off diagonal elements of this decomposition. + pub fn unpack_tridiagonal( + self, + ) -> ( + OVector, + OVector>, + ) + where + DefaultAllocator: Allocator + Allocator>, + { + (self.diagonal(), self.off_diagonal.map(T::modulus)) + } + + /// The diagonal components of this decomposition. + #[must_use] + pub fn diagonal(&self) -> OVector + where + DefaultAllocator: Allocator, + { + self.tri.map_diagonal(|e| e.real()) + } + + /// The off-diagonal components of this decomposition. + #[must_use] + pub fn off_diagonal(&self) -> OVector> + where + DefaultAllocator: Allocator>, + { + self.off_diagonal.map(T::modulus) + } + + /// Computes the orthogonal matrix `Q` of this decomposition. + #[must_use] + pub fn q(&self) -> OMatrix { + householder::assemble_q(&self.tri, self.off_diagonal.as_slice()) + } + + /// Recomputes the original symmetric matrix. + pub fn recompose(mut self) -> OMatrix { + let q = self.q(); + self.tri.fill_lower_triangle(T::zero(), 2); + self.tri.fill_upper_triangle(T::zero(), 2); + + for i in 0..self.off_diagonal.len() { + let val = T::from_real(self.off_diagonal[i].clone().modulus()); + self.tri[(i + 1, i)] = val.clone(); + self.tri[(i, i + 1)] = val; + } + + &q * self.tri * q.adjoint() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/udu.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/udu.rs new file mode 100644 index 000000000..fda4c9121 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/linalg/udu.rs @@ -0,0 +1,98 @@ +#[cfg(feature = "serde-serialize-no-std")] +use serde::{Deserialize, Serialize}; + +use crate::allocator::Allocator; +use crate::base::{Const, DefaultAllocator, OMatrix, OVector}; +use crate::dimension::Dim; +use simba::scalar::RealField; + +/// UDU factorization. +#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound(serialize = "OVector: Serialize, OMatrix: Serialize")) +)] +#[cfg_attr( + feature = "serde-serialize-no-std", + serde(bound( + deserialize = "OVector: Deserialize<'de>, OMatrix: Deserialize<'de>" + )) +)] +#[derive(Clone, Debug)] +pub struct UDU +where + DefaultAllocator: Allocator + Allocator, +{ + /// The upper triangular matrix resulting from the factorization + pub u: OMatrix, + /// The diagonal matrix resulting from the factorization + pub d: OVector, +} + +impl Copy for UDU +where + DefaultAllocator: Allocator + Allocator, + OVector: Copy, + OMatrix: Copy, +{ +} + +impl UDU +where + DefaultAllocator: Allocator + Allocator, +{ + /// Computes the UDU^T factorization. + /// + /// The input matrix `p` is assumed to be symmetric and this decomposition will only read + /// the upper-triangular part of `p`. + /// + /// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360 + pub fn new(p: OMatrix) -> Option { + let n = p.ncols(); + let n_dim = p.shape_generic().1; + + let mut d = OVector::zeros_generic(n_dim, Const::<1>); + let mut u = OMatrix::zeros_generic(n_dim, n_dim); + + d[n - 1] = p[(n - 1, n - 1)].clone(); + + if d[n - 1].is_zero() { + return None; + } + + u.column_mut(n - 1) + .axpy(T::one() / d[n - 1].clone(), &p.column(n - 1), T::zero()); + + for j in (0..n - 1).rev() { + let mut d_j = d[j].clone(); + for k in j + 1..n { + d_j += d[k].clone() * u[(j, k)].clone().powi(2); + } + + d[j] = p[(j, j)].clone() - d_j; + + if d[j].is_zero() { + return None; + } + + for i in (0..=j).rev() { + let mut u_ij = u[(i, j)].clone(); + for k in j + 1..n { + u_ij += d[k].clone() * u[(j, k)].clone() * u[(i, k)].clone(); + } + + u[(i, j)] = (p[(i, j)].clone() - u_ij) / d[j].clone(); + } + + u[(j, j)] = T::one(); + } + + Some(Self { u, d }) + } + + /// Returns the diagonal elements as a matrix + #[must_use] + pub fn d_matrix(&self) -> OMatrix { + OMatrix::from_diagonal(&self.d) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/proptest/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/proptest/mod.rs new file mode 100644 index 000000000..c2b2335c9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/proptest/mod.rs @@ -0,0 +1,476 @@ +//! `proptest`-related features for `nalgebra` data structures. +//! +//! **This module is only available when the `proptest-support` feature is enabled in `nalgebra`**. +//! +//! `proptest` is a library for *property-based testing*. While similar to `QuickCheck`, +//! which may be more familiar to some users, it has a more sophisticated design that +//! provides users with automatic invariant-preserving shrinking. This means that when using +//! `proptest`, you rarely need to write your own shrinkers - which is usually very difficult - +//! and can instead get this "for free". Moreover, `proptest` does not rely on a canonical +//! `Arbitrary` trait implementation like `QuickCheck`, though it does also provide this. For +//! more information, check out the [proptest docs](https://docs.rs/proptest/0.10.1/proptest/) +//! and the [proptest book](https://altsysrq.github.io/proptest-book/intro.html). +//! +//! This module provides users of `nalgebra` with tools to work with `nalgebra` types in +//! `proptest` tests. At present, this integration is at an early stage, and only +//! provides tools for generating matrices and vectors, and not any of the geometry types. +//! There are essentially two ways of using this functionality: +//! +//! - Using the [`matrix()`] function to generate matrices with constraints +//! on dimensions and elements. +//! - Relying on the [`Arbitrary`] implementation of [`OMatrix`]. +//! +//! The first variant is almost always preferred in practice. Read on to discover why. +//! +//! ### Using free function strategies +//! +//! In `proptest`, it is usually preferable to have free functions that generate *strategies*. +//! Currently, the [`matrix()`] function fills this role. The analogous function for +//! column vectors is [`vector()`]. Let's take a quick look at how it may be used: +//! ``` +//! use nalgebra::proptest::matrix; +//! use proptest::prelude::*; +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn my_test(a in matrix(-5 ..= 5, 2 ..= 4, 1..=4)) { +//! // Generates matrices with elements in the range -5 ..= 5, rows in 2..=4 and +//! // columns in 1..=4. +//! } +//! } +//! +//! # fn main() { my_test(); } +//! ``` +//! +//! In the above example, we generate matrices with constraints on the elements, as well as the +//! on the allowed dimensions. When a failing example is found, the resulting shrinking process +//! will preserve these invariants. We can use this to compose more advanced strategies. +//! For example, let's consider a toy example where we need to generate pairs of matrices +//! with exactly 3 rows fixed at compile-time and the same number of columns, but we want the +//! number of columns to vary. One way to do this is to use `proptest` combinators in combination +//! with [`matrix()`] as follows: +//! +//! ``` +//! use nalgebra::{Dyn, OMatrix, Const}; +//! use nalgebra::proptest::matrix; +//! use proptest::prelude::*; +//! +//! type MyMatrix = OMatrix, Dyn>; +//! +//! /// Returns a strategy for pairs of matrices with `U3` rows and the same number of +//! /// columns. +//! fn matrix_pairs() -> impl Strategy { +//! matrix(-5 ..= 5, Const::<3>, 0 ..= 10) +//! // We first generate the initial matrix `a`, and then depending on the concrete +//! // instances of `a`, we pick a second matrix with the same number of columns +//! .prop_flat_map(|a| { +//! let b = matrix(-5 .. 5, Const::<3>, a.ncols()); +//! // This returns a new tuple strategy where we keep `a` fixed while +//! // the second item is a strategy that generates instances with the same +//! // dimensions as `a` +//! (Just(a), b) +//! }) +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn my_test((a, b) in matrix_pairs()) { +//! // Let's double-check that the two matrices do indeed have the same number of +//! // columns +//! prop_assert_eq!(a.ncols(), b.ncols()); +//! } +//! } +//! +//! # fn main() { my_test(); } +//! ``` +//! +//! ### The `Arbitrary` implementation +//! +//! If you don't care about the dimensions of matrices, you can write tests like these: +//! +//! ``` +//! use nalgebra::{DMatrix, DVector, Dyn, Matrix3, OMatrix, Vector3, U3}; +//! use proptest::prelude::*; +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_dynamic(matrix: DMatrix) { +//! // This will generate arbitrary instances of `DMatrix` and also attempt +//! // to shrink/simplify them when test failures are encountered. +//! } +//! +//! # /* +//! #[test] +//! # */ +//! fn test_static_and_mixed(matrix: Matrix3, matrix2: OMatrix) { +//! // Test some property involving these matrices +//! } +//! +//! # /* +//! #[test] +//! # */ +//! fn test_vectors(fixed_size_vector: Vector3, dyn_vector: DVector) { +//! // Test some property involving these vectors +//! } +//! } +//! +//! # fn main() { test_dynamic(); test_static_and_mixed(); test_vectors(); } +//! ``` +//! +//! While this may be convenient, the default strategies for built-in types in `proptest` can +//! generate *any* number, including integers large enough to easily lead to overflow when used in +//! matrix operations, or even infinity or NaN values for floating-point types. Therefore +//! `Arbitrary` is rarely the method of choice for writing property-based tests. +//! +//! ### Notes on shrinking +//! +//! Due to some limitations of the current implementation, shrinking takes place by first +//! shrinking the matrix elements before trying to shrink the dimensions of the matrix. +//! This unfortunately often leads to the fact that a large number of shrinking iterations +//! are necessary to find a (nearly) minimal failing test case. As a workaround for this, +//! you can increase the maximum number of shrinking iterations when debugging. To do this, +//! simply set the `PROPTEST_MAX_SHRINK_ITERS` variable to a high number. For example: +//! +//! ```text +//! PROPTEST_MAX_SHRINK_ITERS=100000 cargo test my_failing_test +//! ``` +use crate::allocator::Allocator; +use crate::{Const, DefaultAllocator, Dim, DimName, Dyn, OMatrix, Scalar, U1}; +use proptest::arbitrary::Arbitrary; +use proptest::collection::vec; +use proptest::strategy::{BoxedStrategy, Just, NewTree, Strategy, ValueTree}; +use proptest::test_runner::TestRunner; + +use std::ops::RangeInclusive; + +/// Parameters for arbitrary matrix generation. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct MatrixParameters { + /// The range of rows that may be generated. + pub rows: DimRange, + /// The range of columns that may be generated. + pub cols: DimRange, + /// Parameters for the `Arbitrary` implementation of the scalar values. + pub value_parameters: NParameters, +} + +/// A range of allowed dimensions for use in generation of matrices. +/// +/// The `DimRange` type is used to encode the range of dimensions that can be used for generation +/// of matrices with `proptest`. In most cases, you do not need to concern yourself with +/// `DimRange` directly, as it supports conversion from other types such as `U3` or inclusive +/// ranges such as `5 ..= 6`. The latter example corresponds to dimensions from (inclusive) +/// `Dyn(5)` to `Dyn(6)` (inclusive). +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DimRange(RangeInclusive); + +impl DimRange { + /// The lower bound for dimensions generated. + pub fn lower_bound(&self) -> D { + *self.0.start() + } + + /// The upper bound for dimensions generated. + pub fn upper_bound(&self) -> D { + *self.0.end() + } +} + +impl From for DimRange { + fn from(dim: D) -> Self { + DimRange(dim..=dim) + } +} + +impl From> for DimRange { + fn from(range: RangeInclusive) -> Self { + DimRange(range) + } +} + +impl From> for DimRange { + fn from(range: RangeInclusive) -> Self { + DimRange::from(Dyn(*range.start())..=Dyn(*range.end())) + } +} + +impl DimRange { + /// Converts the `DimRange` into an instance of `RangeInclusive`. + pub fn to_range_inclusive(&self) -> RangeInclusive { + self.lower_bound().value()..=self.upper_bound().value() + } +} + +impl From for DimRange { + fn from(dim: usize) -> Self { + DimRange::from(Dyn(dim)) + } +} + +/// The default range used for Dyn dimensions when generating arbitrary matrices. +fn dynamic_dim_range() -> DimRange { + DimRange::from(0..=6) +} + +/// Create a strategy to generate matrices containing values drawn from the given strategy, +/// with rows and columns in the provided ranges. +/// +/// ## Examples +/// ``` +/// use nalgebra::proptest::matrix; +/// use nalgebra::{OMatrix, Const, Dyn}; +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn my_test(a in matrix(0 .. 5i32, Const::<3>, 0 ..= 5)) { +/// // Let's make sure we've got the correct type first +/// let a: OMatrix<_, Const::<3>, Dyn> = a; +/// prop_assert!(a.nrows() == 3); +/// prop_assert!(a.ncols() <= 5); +/// prop_assert!(a.iter().all(|x_ij| *x_ij >= 0 && *x_ij < 5)); +/// } +/// } +/// +/// # fn main() { my_test(); } +/// ``` +/// +/// ## Limitations +/// The current implementation has some limitations that lead to suboptimal shrinking behavior. +/// See the [module-level documentation](index.html) for more. +pub fn matrix( + value_strategy: ScalarStrategy, + rows: impl Into>, + cols: impl Into>, +) -> MatrixStrategy +where + ScalarStrategy: Strategy + Clone + 'static, + ScalarStrategy::Value: Scalar, + R: Dim, + C: Dim, + DefaultAllocator: Allocator, +{ + matrix_(value_strategy, rows.into(), cols.into()) +} + +/// Same as `matrix`, but without the additional anonymous generic types +fn matrix_( + value_strategy: ScalarStrategy, + rows: DimRange, + cols: DimRange, +) -> MatrixStrategy +where + ScalarStrategy: Strategy + Clone + 'static, + ScalarStrategy::Value: Scalar, + R: Dim, + C: Dim, + DefaultAllocator: Allocator, +{ + let nrows = rows.lower_bound().value()..=rows.upper_bound().value(); + let ncols = cols.lower_bound().value()..=cols.upper_bound().value(); + + // Even though we can use this function to generate fixed-size matrices, + // we currently generate all matrices with heap allocated Vec data. + // TODO: Avoid heap allocation for fixed-size matrices. + // Doing this *properly* would probably require us to implement a custom + // strategy and valuetree with custom shrinking logic, which is not trivial + + // Perhaps more problematic, however, is the poor shrinking behavior the current setup leads to. + // Shrinking in proptest basically happens in "reverse" of the combinators, so + // by first generating the dimensions and then the elements, we get shrinking that first + // tries to completely shrink the individual elements before trying to reduce the dimension. + // This is clearly the opposite of what we want. I can't find any good way around this + // short of writing our own custom value tree, which we should probably do at some point. + // TODO: Custom implementation of value tree for better shrinking behavior. + + let strategy = nrows + .prop_flat_map(move |nrows| (Just(nrows), ncols.clone())) + .prop_flat_map(move |(nrows, ncols)| { + ( + Just(nrows), + Just(ncols), + vec(value_strategy.clone(), nrows * ncols), + ) + }) + .prop_map(|(nrows, ncols, values)| { + // Note: R/C::from_usize will panic if nrows/ncols does not fit in the dimension type. + // However, this should never fail, because we should only be generating + // this stuff in the first place + OMatrix::from_iterator_generic(R::from_usize(nrows), C::from_usize(ncols), values) + }) + .boxed(); + + MatrixStrategy { strategy } +} + +/// Create a strategy to generate column vectors containing values drawn from the given strategy, +/// with length in the provided range. +/// +/// This is a convenience function for calling +/// [`matrix(value_strategy, length, U1)`](crate::matrix) and should +/// be used when you only want to generate column vectors, as it's simpler and makes the intent +/// clear. +pub fn vector( + value_strategy: ScalarStrategy, + length: impl Into>, +) -> MatrixStrategy +where + ScalarStrategy: Strategy + Clone + 'static, + ScalarStrategy::Value: Scalar, + D: Dim, + DefaultAllocator: Allocator, +{ + matrix_(value_strategy, length.into(), Const::<1>.into()) +} + +impl Default for MatrixParameters +where + NParameters: Default, + R: DimName, + C: DimName, +{ + fn default() -> Self { + Self { + rows: DimRange::from(R::name()), + cols: DimRange::from(C::name()), + value_parameters: NParameters::default(), + } + } +} + +impl Default for MatrixParameters +where + NParameters: Default, + R: DimName, +{ + fn default() -> Self { + Self { + rows: DimRange::from(R::name()), + cols: dynamic_dim_range(), + value_parameters: NParameters::default(), + } + } +} + +impl Default for MatrixParameters +where + NParameters: Default, + C: DimName, +{ + fn default() -> Self { + Self { + rows: dynamic_dim_range(), + cols: DimRange::from(C::name()), + value_parameters: NParameters::default(), + } + } +} + +impl Default for MatrixParameters +where + NParameters: Default, +{ + fn default() -> Self { + Self { + rows: dynamic_dim_range(), + cols: dynamic_dim_range(), + value_parameters: NParameters::default(), + } + } +} + +impl Arbitrary for OMatrix +where + T: Scalar + Arbitrary, + ::Strategy: Clone, + R: Dim, + C: Dim, + MatrixParameters: Default, + DefaultAllocator: Allocator, +{ + type Parameters = MatrixParameters; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + let value_strategy = T::arbitrary_with(args.value_parameters); + matrix(value_strategy, args.rows, args.cols) + } + + type Strategy = MatrixStrategy; +} + +/// A strategy for generating matrices. +#[derive(Debug, Clone)] +pub struct MatrixStrategy +where + NStrategy: Strategy, + NStrategy::Value: Scalar, + DefaultAllocator: Allocator, +{ + // For now we only internally hold a boxed strategy. The reason for introducing this + // separate wrapper struct is so that we can replace the strategy logic with custom logic + // later down the road without introducing significant breaking changes + strategy: BoxedStrategy>, +} + +impl Strategy for MatrixStrategy +where + NStrategy: Strategy, + NStrategy::Value: Scalar, + R: Dim, + C: Dim, + DefaultAllocator: Allocator, +{ + type Tree = MatrixValueTree; + type Value = OMatrix; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let underlying_tree = self.strategy.new_tree(runner)?; + Ok(MatrixValueTree { + value_tree: underlying_tree, + }) + } +} + +/// A value tree for matrices. +pub struct MatrixValueTree +where + T: Scalar, + R: Dim, + C: Dim, + DefaultAllocator: Allocator, +{ + // For now we only wrap a boxed value tree. The reason for wrapping is that this allows us + // to swap out the value tree logic down the road without significant breaking changes. + value_tree: Box>>, +} + +impl ValueTree for MatrixValueTree +where + T: Scalar, + R: Dim, + C: Dim, + DefaultAllocator: Allocator, +{ + type Value = OMatrix; + + fn current(&self) -> Self::Value { + self.value_tree.current() + } + + fn simplify(&mut self) -> bool { + self.value_tree.simplify() + } + + fn complicate(&mut self) -> bool { + self.value_tree.complicate() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix.rs new file mode 100644 index 000000000..b0e11ba5a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix.rs @@ -0,0 +1,542 @@ +use num::Zero; +use simba::scalar::ClosedAddAssign; +use std::iter; +use std::marker::PhantomData; +use std::ops::Range; +use std::slice; + +use crate::allocator::Allocator; +use crate::sparse::cs_utils; +use crate::{Const, DefaultAllocator, Dim, Dyn, Matrix, OVector, Scalar, Vector, U1}; + +pub struct ColumnEntries<'a, T> { + curr: usize, + i: &'a [usize], + v: &'a [T], +} + +impl<'a, T> ColumnEntries<'a, T> { + #[inline] + pub fn new(i: &'a [usize], v: &'a [T]) -> Self { + assert_eq!(i.len(), v.len()); + Self { curr: 0, i, v } + } +} + +impl<'a, T: Clone> Iterator for ColumnEntries<'a, T> { + type Item = (usize, T); + + #[inline] + fn next(&mut self) -> Option { + if self.curr >= self.i.len() { + None + } else { + let res = Some((unsafe { *self.i.get_unchecked(self.curr) }, unsafe { + self.v.get_unchecked(self.curr).clone() + })); + self.curr += 1; + res + } + } +} + +// TODO: this structure exists for now only because impl trait +// cannot be used for trait method return types. +/// Trait for iterable compressed-column matrix storage. +pub trait CsStorageIter<'a, T, R, C = U1> { + /// Iterator through all the rows of a specific columns. + /// + /// The elements are given as a tuple (`row_index`, value). + type ColumnEntries: Iterator; + /// Iterator through the row indices of a specific column. + type ColumnRowIndices: Iterator; + + /// Iterates through all the row indices of the j-th column. + fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices; + /// Iterates through all the entries of the j-th column. + fn column_entries(&'a self, j: usize) -> Self::ColumnEntries; +} + +/// Trait for mutably iterable compressed-column sparse matrix storage. +pub trait CsStorageIterMut<'a, T: 'a, R, C = U1> { + /// Mutable iterator through all the values of the sparse matrix. + type ValuesMut: Iterator; + /// Mutable iterator through all the rows of a specific columns. + /// + /// The elements are given as a tuple (`row_index`, value). + type ColumnEntriesMut: Iterator; + + /// A mutable iterator through the values buffer of the sparse matrix. + fn values_mut(&'a mut self) -> Self::ValuesMut; + /// Iterates mutably through all the entries of the j-th column. + fn column_entries_mut(&'a mut self, j: usize) -> Self::ColumnEntriesMut; +} + +/// Trait for compressed column sparse matrix storage. +pub trait CsStorage: for<'a> CsStorageIter<'a, T, R, C> { + /// The shape of the stored matrix. + fn shape(&self) -> (R, C); + /// Retrieve the i-th row index of the underlying row index buffer. + /// + /// # Safety + /// No bound-checking is performed. + unsafe fn row_index_unchecked(&self, i: usize) -> usize; + /// The i-th value on the contiguous value buffer of this storage. + /// + /// # Safety + /// No bound-checking is performed. + unsafe fn get_value_unchecked(&self, i: usize) -> &T; + /// The i-th value on the contiguous value buffer of this storage. + fn get_value(&self, i: usize) -> &T; + /// Retrieve the i-th row index of the underlying row index buffer. + fn row_index(&self, i: usize) -> usize; + /// The value indices for the `i`-th column. + fn column_range(&self, i: usize) -> Range; + /// The size of the value buffer (i.e. the entries known as possibly being non-zero). + fn len(&self) -> usize; +} + +/// Trait for compressed column sparse matrix mutable storage. +pub trait CsStorageMut: + CsStorage + for<'a> CsStorageIterMut<'a, T, R, C> +{ +} + +/// A storage of column-compressed sparse matrix based on a Vec. +#[derive(Clone, Debug, PartialEq)] +pub struct CsVecStorage +where + DefaultAllocator: Allocator, +{ + pub(crate) shape: (R, C), + pub(crate) p: OVector, + pub(crate) i: Vec, + pub(crate) vals: Vec, +} + +impl CsVecStorage +where + DefaultAllocator: Allocator, +{ + /// The value buffer of this storage. + #[must_use] + pub fn values(&self) -> &[T] { + &self.vals + } + + /// The column shifts buffer. + #[must_use] + pub fn p(&self) -> &[usize] { + self.p.as_slice() + } + + /// The row index buffers. + #[must_use] + pub fn i(&self) -> &[usize] { + &self.i + } +} + +impl CsVecStorage where DefaultAllocator: Allocator {} + +impl<'a, T: Scalar, R: Dim, C: Dim> CsStorageIter<'a, T, R, C> for CsVecStorage +where + DefaultAllocator: Allocator, +{ + type ColumnEntries = ColumnEntries<'a, T>; + type ColumnRowIndices = iter::Cloned>; + + #[inline] + fn column_entries(&'a self, j: usize) -> Self::ColumnEntries { + let rng = self.column_range(j); + ColumnEntries::new(&self.i[rng.clone()], &self.vals[rng]) + } + + #[inline] + fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices { + let rng = self.column_range(j); + self.i[rng].iter().cloned() + } +} + +impl CsStorage for CsVecStorage +where + DefaultAllocator: Allocator, +{ + #[inline] + fn shape(&self) -> (R, C) { + self.shape + } + + #[inline] + fn len(&self) -> usize { + self.vals.len() + } + + #[inline] + fn row_index(&self, i: usize) -> usize { + self.i[i] + } + + #[inline] + unsafe fn row_index_unchecked(&self, i: usize) -> usize { + *self.i.get_unchecked(i) + } + + #[inline] + unsafe fn get_value_unchecked(&self, i: usize) -> &T { + self.vals.get_unchecked(i) + } + + #[inline] + fn get_value(&self, i: usize) -> &T { + &self.vals[i] + } + + #[inline] + fn column_range(&self, j: usize) -> Range { + let end = if j + 1 == self.p.len() { + self.len() + } else { + self.p[j + 1] + }; + + self.p[j]..end + } +} + +impl<'a, T: Scalar, R: Dim, C: Dim> CsStorageIterMut<'a, T, R, C> for CsVecStorage +where + DefaultAllocator: Allocator, +{ + type ValuesMut = slice::IterMut<'a, T>; + type ColumnEntriesMut = iter::Zip>, slice::IterMut<'a, T>>; + + #[inline] + fn values_mut(&'a mut self) -> Self::ValuesMut { + self.vals.iter_mut() + } + + #[inline] + fn column_entries_mut(&'a mut self, j: usize) -> Self::ColumnEntriesMut { + let rng = self.column_range(j); + self.i[rng.clone()] + .iter() + .cloned() + .zip(self.vals[rng].iter_mut()) + } +} + +impl CsStorageMut for CsVecStorage where + DefaultAllocator: Allocator +{ +} + +/* +pub struct CsSliceStorage<'a, T: Scalar, R: Dim, C: DimAdd> { + shape: (R, C), + p: VectorSlice>, + i: VectorSlice, + vals: VectorSlice, +}*/ + +/// A compressed sparse column matrix. +#[derive(Clone, Debug, PartialEq)] +pub struct CsMatrix< + T: Scalar, + R: Dim = Dyn, + C: Dim = Dyn, + S: CsStorage = CsVecStorage, +> { + pub(crate) data: S, + _phantoms: PhantomData<(T, R, C)>, +} + +/// A column compressed sparse vector. +pub type CsVector> = CsMatrix; + +impl CsMatrix +where + DefaultAllocator: Allocator, +{ + /// Creates a new compressed sparse column matrix with the specified dimension and + /// `nvals` possible non-zero values. + pub fn new_uninitialized_generic(nrows: R, ncols: C, nvals: usize) -> Self { + let mut i = Vec::with_capacity(nvals); + unsafe { + i.set_len(nvals); + } + i.shrink_to_fit(); + + let mut vals = Vec::with_capacity(nvals); + unsafe { + vals.set_len(nvals); + } + vals.shrink_to_fit(); + + CsMatrix { + data: CsVecStorage { + shape: (nrows, ncols), + p: OVector::zeros_generic(ncols, Const::<1>), + i, + vals, + }, + _phantoms: PhantomData, + } + } + + /* + pub(crate) fn from_parts_generic( + nrows: R, + ncols: C, + p: OVector, + i: Vec, + vals: Vec, + ) -> Self + where + T: Zero + ClosedAddAssign, + DefaultAllocator: Allocator, + { + assert_eq!(ncols.value(), p.len(), "Invalid inptr size."); + assert_eq!(i.len(), vals.len(), "Invalid value size."); + + // Check p. + for ptr in &p { + assert!(*ptr < i.len(), "Invalid inptr value."); + } + + for ptr in p.as_slice().windows(2) { + assert!(ptr[0] <= ptr[1], "Invalid inptr ordering."); + } + + // Check i. + for i in &i { + assert!(*i < nrows.value(), "Invalid row ptr value.") + } + + let mut res = CsMatrix { + data: CsVecStorage { + shape: (nrows, ncols), + p, + i, + vals, + }, + _phantoms: PhantomData, + }; + + // Sort and remove duplicates. + res.sort(); + res.dedup(); + + res + }*/ +} + +/* +impl CsMatrix { + pub(crate) fn from_parts( + nrows: usize, + ncols: usize, + p: Vec, + i: Vec, + vals: Vec, + ) -> Self + { + let nrows = Dyn(nrows); + let ncols = Dyn(ncols); + let p = DVector::from_data(VecStorage::new(ncols, U1, p)); + Self::from_parts_generic(nrows, ncols, p, i, vals) + } +} +*/ + +impl> CsMatrix { + pub(crate) fn from_data(data: S) -> Self { + CsMatrix { + data, + _phantoms: PhantomData, + } + } + + /// The size of the data buffer. + #[must_use] + pub fn len(&self) -> usize { + self.data.len() + } + + /// The number of rows of this matrix. + #[must_use] + pub fn nrows(&self) -> usize { + self.data.shape().0.value() + } + + /// The number of rows of this matrix. + #[must_use] + pub fn ncols(&self) -> usize { + self.data.shape().1.value() + } + + /// The shape of this matrix. + #[must_use] + pub fn shape(&self) -> (usize, usize) { + let (nrows, ncols) = self.data.shape(); + (nrows.value(), ncols.value()) + } + + /// Whether this matrix is square or not. + #[must_use] + pub fn is_square(&self) -> bool { + let (nrows, ncols) = self.data.shape(); + nrows.value() == ncols.value() + } + + /// Should always return `true`. + /// + /// This method is generally used for debugging and should typically not be called in user code. + /// This checks that the row inner indices of this matrix are sorted. It takes `O(n)` time, + /// where n` is `self.len()`. + /// All operations of CSC matrices on nalgebra assume, and will return, sorted indices. + /// If at any time this `is_sorted` method returns `false`, then, something went wrong + /// and an issue should be open on the nalgebra repository with details on how to reproduce + /// this. + #[must_use] + pub fn is_sorted(&self) -> bool { + for j in 0..self.ncols() { + let mut curr = None; + for idx in self.data.column_row_indices(j) { + if let Some(curr) = curr { + if idx <= curr { + return false; + } + } + + curr = Some(idx); + } + } + + true + } + + /// Computes the transpose of this sparse matrix. + #[must_use = "This function does not mutate the matrix. Consider using the return value or removing the function call. There's also transpose_mut() for square matrices."] + pub fn transpose(&self) -> CsMatrix + where + DefaultAllocator: Allocator, + { + let (nrows, ncols) = self.data.shape(); + + let nvals = self.len(); + let mut res = CsMatrix::new_uninitialized_generic(ncols, nrows, nvals); + let mut workspace = Vector::zeros_generic(nrows, Const::<1>); + + // Compute p. + for i in 0..nvals { + let row_id = self.data.row_index(i); + workspace[row_id] += 1; + } + + let _ = cs_utils::cumsum(&mut workspace, &mut res.data.p); + + // Fill the result. + for j in 0..ncols.value() { + for (row_id, value) in self.data.column_entries(j) { + let shift = workspace[row_id]; + + res.data.vals[shift] = value; + res.data.i[shift] = j; + workspace[row_id] += 1; + } + } + + res + } +} + +impl> CsMatrix { + /// Iterator through all the mutable values of this sparse matrix. + #[inline] + pub fn values_mut(&mut self) -> impl Iterator { + self.data.values_mut() + } +} + +impl CsMatrix +where + DefaultAllocator: Allocator, +{ + pub(crate) fn sort(&mut self) + where + T: Zero, + DefaultAllocator: Allocator, + { + // Size = R + let nrows = self.data.shape().0; + let mut workspace = Matrix::zeros_generic(nrows, Const::<1>); + self.sort_with_workspace(workspace.as_mut_slice()); + } + + pub(crate) fn sort_with_workspace(&mut self, workspace: &mut [T]) { + assert!( + workspace.len() >= self.nrows(), + "Workspace must be able to hold at least self.nrows() elements." + ); + + for j in 0..self.ncols() { + // Scatter the row in the workspace. + for (irow, val) in self.data.column_entries(j) { + workspace[irow] = val; + } + + // Sort the index vector. + let range = self.data.column_range(j); + self.data.i[range.clone()].sort_unstable(); + + // Permute the values too. + for (i, irow) in range.clone().zip(self.data.i[range].iter().cloned()) { + self.data.vals[i] = workspace[irow].clone(); + } + } + } + + // Remove duplicate entries on a sorted CsMatrix. + pub(crate) fn dedup(&mut self) + where + T: Zero + ClosedAddAssign, + { + let mut curr_i = 0; + + for j in 0..self.ncols() { + let range = self.data.column_range(j); + self.data.p[j] = curr_i; + + if range.start != range.end { + let mut value = T::zero(); + let mut irow = self.data.i[range.start]; + + for idx in range { + let curr_irow = self.data.i[idx]; + + if curr_irow == irow { + value += self.data.vals[idx].clone(); + } else { + self.data.i[curr_i] = irow; + self.data.vals[curr_i] = value; + value = self.data.vals[idx].clone(); + irow = curr_irow; + curr_i += 1; + } + } + + // Handle the last entry. + self.data.i[curr_i] = irow; + self.data.vals[curr_i] = value; + curr_i += 1; + } + } + + self.data.i.truncate(curr_i); + self.data.i.shrink_to_fit(); + self.data.vals.truncate(curr_i); + self.data.vals.shrink_to_fit(); + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_cholesky.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_cholesky.rs new file mode 100644 index 000000000..741273d3a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_cholesky.rs @@ -0,0 +1,412 @@ +use std::iter; +use std::mem; + +use crate::allocator::Allocator; +use crate::sparse::{CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsVecStorage}; +use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, RealField}; + +/// The cholesky decomposition of a column compressed sparse matrix. +pub struct CsCholesky +where + DefaultAllocator: Allocator, +{ + // Non-zero pattern of the original matrix upper-triangular part. + // Unlike the original matrix, the `original_p` array does contain the last sentinel value + // equal to `original_i.len()` at the end. + original_p: Vec, + original_i: Vec, + // Decomposition result. + l: CsMatrix, + // Used only for the pattern. + // TODO: store only the nonzero pattern instead. + u: CsMatrix, + ok: bool, + // Workspaces. + work_x: OVector, + work_c: OVector, +} + +impl CsCholesky +where + DefaultAllocator: Allocator + Allocator, +{ + /// Computes the cholesky decomposition of the sparse matrix `m`. + pub fn new(m: &CsMatrix) -> Self { + let mut me = Self::new_symbolic(m); + let _ = me.decompose_left_looking(&m.data.vals); + me + } + /// Perform symbolic analysis for the given matrix. + /// + /// This does not access the numerical values of `m`. + pub fn new_symbolic(m: &CsMatrix) -> Self { + assert!( + m.is_square(), + "The matrix `m` must be square to compute its elimination tree." + ); + + let (l, u) = Self::nonzero_pattern(m); + + // Workspaces. + let work_x = Matrix::zeros_generic(m.data.shape().0, Const::<1>); + let work_c = Matrix::zeros_generic(m.data.shape().1, Const::<1>); + let mut original_p = m.data.p.as_slice().to_vec(); + original_p.push(m.data.i.len()); + + CsCholesky { + original_p, + original_i: m.data.i.clone(), + l, + u, + ok: false, + work_x, + work_c, + } + } + + /// The lower-triangular matrix of the cholesky decomposition. + #[must_use] + pub fn l(&self) -> Option<&CsMatrix> { + if self.ok { + Some(&self.l) + } else { + None + } + } + + /// Extracts the lower-triangular matrix of the cholesky decomposition. + pub fn unwrap_l(self) -> Option> { + if self.ok { + Some(self.l) + } else { + None + } + } + + /// Perform a numerical left-looking cholesky decomposition of a matrix with the same structure as the + /// one used to initialize `self`, but with different non-zero values provided by `values`. + pub fn decompose_left_looking(&mut self, values: &[T]) -> bool { + assert!( + values.len() >= self.original_i.len(), + "The set of values is too small." + ); + + let n = self.l.nrows(); + + // Reset `work_c` to the column pointers of `l`. + self.work_c.copy_from(&self.l.data.p); + + unsafe { + for k in 0..n { + // Scatter the k-th column of the original matrix with the values provided. + let range_k = + *self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1); + + *self.work_x.vget_unchecked_mut(k) = T::zero(); + for p in range_k.clone() { + let irow = *self.original_i.get_unchecked(p); + + if irow >= k { + *self.work_x.vget_unchecked_mut(irow) = values.get_unchecked(p).clone(); + } + } + + for j in self.u.data.column_row_indices(k) { + let factor = -self + .l + .data + .vals + .get_unchecked(*self.work_c.vget_unchecked(j)) + .clone(); + *self.work_c.vget_unchecked_mut(j) += 1; + + if j < k { + for (z, val) in self.l.data.column_entries(j) { + if z >= k { + *self.work_x.vget_unchecked_mut(z) += val * factor.clone(); + } + } + } + } + + let diag = self.work_x.vget_unchecked(k).clone(); + + if diag > T::zero() { + let denom = diag.sqrt(); + *self + .l + .data + .vals + .get_unchecked_mut(*self.l.data.p.vget_unchecked(k)) = denom.clone(); + + for (p, val) in self.l.data.column_entries_mut(k) { + *val = self.work_x.vget_unchecked(p).clone() / denom.clone(); + *self.work_x.vget_unchecked_mut(p) = T::zero(); + } + } else { + self.ok = false; + return false; + } + } + } + + self.ok = true; + true + } + + /// Perform a numerical up-looking cholesky decomposition of a matrix with the same structure as the + /// one used to initialize `self`, but with different non-zero values provided by `values`. + pub fn decompose_up_looking(&mut self, values: &[T]) -> bool { + assert!( + values.len() >= self.original_i.len(), + "The set of values is too small." + ); + + // Reset `work_c` to the column pointers of `l`. + self.work_c.copy_from(&self.l.data.p); + + // Perform the decomposition. + for k in 0..self.l.nrows() { + unsafe { + // Scatter the k-th column of the original matrix with the values provided. + let column_range = + *self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1); + + *self.work_x.vget_unchecked_mut(k) = T::zero(); + for p in column_range.clone() { + let irow = *self.original_i.get_unchecked(p); + + if irow <= k { + *self.work_x.vget_unchecked_mut(irow) = values.get_unchecked(p).clone(); + } + } + + let mut diag = self.work_x.vget_unchecked(k).clone(); + *self.work_x.vget_unchecked_mut(k) = T::zero(); + + // Triangular solve. + for irow in self.u.data.column_row_indices(k) { + if irow >= k { + continue; + } + + let lki = self.work_x.vget_unchecked(irow).clone() + / self + .l + .data + .vals + .get_unchecked(*self.l.data.p.vget_unchecked(irow)) + .clone(); + *self.work_x.vget_unchecked_mut(irow) = T::zero(); + + for p in + *self.l.data.p.vget_unchecked(irow) + 1..*self.work_c.vget_unchecked(irow) + { + *self + .work_x + .vget_unchecked_mut(*self.l.data.i.get_unchecked(p)) -= + self.l.data.vals.get_unchecked(p).clone() * lki.clone(); + } + + diag -= lki.clone() * lki.clone(); + let p = *self.work_c.vget_unchecked(irow); + *self.work_c.vget_unchecked_mut(irow) += 1; + *self.l.data.i.get_unchecked_mut(p) = k; + *self.l.data.vals.get_unchecked_mut(p) = lki; + } + + if diag <= T::zero() { + self.ok = false; + return false; + } + + // Deal with the diagonal element. + let p = *self.work_c.vget_unchecked(k); + *self.work_c.vget_unchecked_mut(k) += 1; + *self.l.data.i.get_unchecked_mut(p) = k; + *self.l.data.vals.get_unchecked_mut(p) = diag.sqrt(); + } + } + + self.ok = true; + true + } + + fn elimination_tree>(m: &CsMatrix) -> Vec { + let nrows = m.nrows(); + let mut forest: Vec<_> = iter::repeat(usize::max_value()).take(nrows).collect(); + let mut ancestor: Vec<_> = iter::repeat(usize::max_value()).take(nrows).collect(); + + for k in 0..nrows { + for irow in m.data.column_row_indices(k) { + let mut i = irow; + + while i < k { + let i_ancestor = ancestor[i]; + ancestor[i] = k; + + if i_ancestor == usize::max_value() { + forest[i] = k; + break; + } + + i = i_ancestor; + } + } + } + + forest + } + + fn reach>( + m: &CsMatrix, + j: usize, + max_j: usize, + tree: &[usize], + marks: &mut Vec, + out: &mut Vec, + ) { + marks.clear(); + marks.resize(tree.len(), false); + + // TODO: avoid all those allocations. + let mut tmp = Vec::new(); + let mut res = Vec::new(); + + for irow in m.data.column_row_indices(j) { + let mut curr = irow; + while curr != usize::max_value() && curr <= max_j && !marks[curr] { + marks[curr] = true; + tmp.push(curr); + curr = tree[curr]; + } + + tmp.append(&mut res); + mem::swap(&mut tmp, &mut res); + } + + out.append(&mut res); + } + + fn nonzero_pattern>( + m: &CsMatrix, + ) -> (CsMatrix, CsMatrix) { + let etree = Self::elimination_tree(m); + let (nrows, ncols) = m.data.shape(); + let mut rows = Vec::with_capacity(m.len()); + let mut cols = Matrix::zeros_generic(m.data.shape().0, Const::<1>); + let mut marks = Vec::new(); + + // NOTE: the following will actually compute the non-zero pattern of + // the transpose of l. + for i in 0..nrows.value() { + cols[i] = rows.len(); + Self::reach(m, i, i, &etree, &mut marks, &mut rows); + } + + let mut vals = Vec::with_capacity(rows.len()); + unsafe { + vals.set_len(rows.len()); + } + vals.shrink_to_fit(); + + let data = CsVecStorage { + shape: (nrows, ncols), + p: cols, + i: rows, + vals, + }; + + let u = CsMatrix::from_data(data); + // XXX: avoid this transpose. + let l = u.transpose(); + + (l, u) + } + + /* + * + * NOTE: All the following methods are untested and currently unused. + * + * + fn column_counts>( + m: &CsMatrix, + tree: &[usize], + ) -> Vec { + let len = m.data.shape().0.value(); + let mut counts: Vec<_> = iter::repeat(0).take(len).collect(); + let mut reach = Vec::new(); + let mut marks = Vec::new(); + + for i in 0..len { + Self::reach(m, i, i, tree, &mut marks, &mut reach); + + for j in reach.drain(..) { + counts[j] += 1; + } + } + + counts + } + + fn tree_postorder(tree: &[usize]) -> Vec { + // TODO: avoid all those allocations? + let mut first_child: Vec<_> = iter::repeat(usize::max_value()).take(tree.len()).collect(); + let mut other_children: Vec<_> = + iter::repeat(usize::max_value()).take(tree.len()).collect(); + + // Build the children list from the parent list. + // The set of children of the node `i` is given by the linked list + // starting at `first_child[i]`. The nodes of this list are then: + // { first_child[i], other_children[first_child[i]], other_children[other_children[first_child[i]], ... } + for (i, parent) in tree.iter().enumerate() { + if *parent != usize::max_value() { + let brother = first_child[*parent]; + first_child[*parent] = i; + other_children[i] = brother; + } + } + + let mut stack = Vec::with_capacity(tree.len()); + let mut postorder = Vec::with_capacity(tree.len()); + + for (i, node) in tree.iter().enumerate() { + if *node == usize::max_value() { + Self::dfs( + i, + &mut first_child, + &other_children, + &mut stack, + &mut postorder, + ) + } + } + + postorder + } + + fn dfs( + i: usize, + first_child: &mut [usize], + other_children: &[usize], + stack: &mut Vec, + result: &mut Vec, + ) { + stack.clear(); + stack.push(i); + + while let Some(n) = stack.pop() { + let child = first_child[n]; + + if child == usize::max_value() { + // No children left. + result.push(n); + } else { + stack.push(n); + stack.push(child); + first_child[n] = other_children[child]; + } + } + } + */ +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_conversion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_conversion.rs new file mode 100644 index 000000000..addf64d37 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_conversion.rs @@ -0,0 +1,113 @@ +use num::Zero; +use simba::scalar::ClosedAddAssign; + +use crate::allocator::Allocator; +use crate::sparse::cs_utils; +use crate::sparse::{CsMatrix, CsStorage}; +use crate::storage::Storage; +use crate::{DefaultAllocator, Dim, Dyn, Matrix, OMatrix, Scalar}; + +impl<'a, T: Scalar + Zero + ClosedAddAssign> CsMatrix { + /// Creates a column-compressed sparse matrix from a sparse matrix in triplet form. + pub fn from_triplet( + nrows: usize, + ncols: usize, + irows: &[usize], + icols: &[usize], + vals: &[T], + ) -> Self { + Self::from_triplet_generic(Dyn(nrows), Dyn(ncols), irows, icols, vals) + } +} + +impl<'a, T: Scalar + Zero + ClosedAddAssign, R: Dim, C: Dim> CsMatrix +where + DefaultAllocator: Allocator + Allocator, +{ + /// Creates a column-compressed sparse matrix from a sparse matrix in triplet form. + pub fn from_triplet_generic( + nrows: R, + ncols: C, + irows: &[usize], + icols: &[usize], + vals: &[T], + ) -> Self { + assert!(vals.len() == irows.len()); + assert!(vals.len() == icols.len()); + + let mut res = CsMatrix::new_uninitialized_generic(nrows, ncols, vals.len()); + let mut workspace = res.data.p.clone(); + + // Column count. + for j in icols.iter().cloned() { + workspace[j] += 1; + } + + let _ = cs_utils::cumsum(&mut workspace, &mut res.data.p); + + // Fill i and vals. + for ((i, j), val) in irows + .iter() + .cloned() + .zip(icols.iter().cloned()) + .zip(vals.iter().cloned()) + { + let offset = workspace[j]; + res.data.i[offset] = i; + res.data.vals[offset] = val; + workspace[j] = offset + 1; + } + + // Sort the result. + res.sort(); + res.dedup(); + res + } +} + +impl<'a, T: Scalar + Zero, R: Dim, C: Dim, S> From> for OMatrix +where + S: CsStorage, + DefaultAllocator: Allocator, +{ + fn from(m: CsMatrix) -> Self { + let (nrows, ncols) = m.data.shape(); + let mut res = OMatrix::zeros_generic(nrows, ncols); + + for j in 0..ncols.value() { + for (i, val) in m.data.column_entries(j) { + res[(i, j)] = val; + } + } + + res + } +} + +impl<'a, T: Scalar + Zero, R: Dim, C: Dim, S> From> for CsMatrix +where + S: Storage, + DefaultAllocator: Allocator + Allocator, +{ + fn from(m: Matrix) -> Self { + let (nrows, ncols) = m.data.shape(); + let len = m.iter().filter(|e| !e.is_zero()).count(); + let mut res = CsMatrix::new_uninitialized_generic(nrows, ncols, len); + let mut nz = 0; + + for j in 0..ncols.value() { + let column = m.column(j); + res.data.p[j] = nz; + + for i in 0..nrows.value() { + if !column[i].is_zero() { + res.data.i[nz] = i; + res.data.vals[nz] = column[i].clone(); + nz += 1; + } + } + } + + res + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_ops.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_ops.rs new file mode 100644 index 000000000..af99eca73 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_ops.rs @@ -0,0 +1,306 @@ +use num::{One, Zero}; +use simba::scalar::{ClosedAddAssign, ClosedMulAssign}; +use std::ops::{Add, Mul}; + +use crate::allocator::Allocator; +use crate::constraint::{AreMultipliable, DimEq, ShapeConstraint}; +use crate::sparse::{CsMatrix, CsStorage, CsStorageMut, CsVector}; +use crate::storage::StorageMut; +use crate::{Const, DefaultAllocator, Dim, Matrix, OVector, Scalar, Vector}; + +impl> CsMatrix { + fn scatter( + &self, + j: usize, + beta: T, + timestamps: &mut [usize], + timestamp: usize, + workspace: &mut [T], + mut nz: usize, + res: &mut CsMatrix, + ) -> usize + where + T: ClosedAddAssign + ClosedMulAssign, + DefaultAllocator: Allocator, + { + for (i, val) in self.data.column_entries(j) { + if timestamps[i] < timestamp { + timestamps[i] = timestamp; + res.data.i[nz] = i; + nz += 1; + workspace[i] = val * beta.clone(); + } else { + workspace[i] += val * beta.clone(); + } + } + + nz + } +} + +/* +impl CsVector { + pub fn axpy(&mut self, alpha: T, x: CsVector, beta: T) { + // First, compute the number of non-zero entries. + let mut nnzero = 0; + + // Allocate a size large enough. + self.data.set_column_len(0, nnzero); + + // Fill with the axpy. + let mut i = self.len(); + let mut j = x.len(); + let mut k = nnzero - 1; + let mut rid1 = self.data.row_index(0, i - 1); + let mut rid2 = x.data.row_index(0, j - 1); + + while k > 0 { + if rid1 == rid2 { + self.data.set_row_index(0, k, rid1); + self[k] = alpha * x[j] + beta * self[k]; + i -= 1; + j -= 1; + } else if rid1 < rid2 { + self.data.set_row_index(0, k, rid1); + self[k] = beta * self[i]; + i -= 1; + } else { + self.data.set_row_index(0, k, rid2); + self[k] = alpha * x[j]; + j -= 1; + } + + k -= 1; + } + } +} +*/ + +impl> + Vector +{ + /// Perform a sparse axpy operation: `self = alpha * x + beta * self` operation. + pub fn axpy_cs(&mut self, alpha: T, x: &CsVector, beta: T) + where + S2: CsStorage, + ShapeConstraint: DimEq, + { + if beta.is_zero() { + for i in 0..x.len() { + unsafe { + let k = x.data.row_index_unchecked(i); + let y = self.vget_unchecked_mut(k); + *y = alpha.clone() * x.data.get_value_unchecked(i).clone(); + } + } + } else { + // Needed to be sure even components not present on `x` are multiplied. + *self *= beta.clone(); + + for i in 0..x.len() { + unsafe { + let k = x.data.row_index_unchecked(i); + let y = self.vget_unchecked_mut(k); + *y += alpha.clone() * x.data.get_value_unchecked(i).clone(); + } + } + } + } + + /* + pub fn gemv_sparse(&mut self, alpha: T, a: &CsMatrix, x: &DVector, beta: T) + where + S2: CsStorage { + let col2 = a.column(0); + let val = unsafe { *x.vget_unchecked(0) }; + self.axpy_sparse(alpha * val, &col2, beta); + + for j in 1..ncols2 { + let col2 = a.column(j); + let val = unsafe { *x.vget_unchecked(j) }; + + self.axpy_sparse(alpha * val, &col2, T::one()); + } + } + */ +} + +impl<'a, 'b, T, R1, R2, C1, C2, S1, S2> Mul<&'b CsMatrix> + for &'a CsMatrix +where + T: Scalar + ClosedAddAssign + ClosedMulAssign + Zero, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, + S1: CsStorage, + S2: CsStorage, + ShapeConstraint: AreMultipliable, + DefaultAllocator: Allocator + Allocator + Allocator, +{ + type Output = CsMatrix; + + fn mul(self, rhs: &'b CsMatrix) -> Self::Output { + let (nrows1, ncols1) = self.data.shape(); + let (nrows2, ncols2) = rhs.data.shape(); + assert_eq!( + ncols1.value(), + nrows2.value(), + "Mismatched dimensions for matrix multiplication." + ); + + let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len()); + let mut workspace = OVector::::zeros_generic(nrows1, Const::<1>); + let mut nz = 0; + + for j in 0..ncols2.value() { + res.data.p[j] = nz; + let new_size_bound = nz + nrows1.value(); + res.data.i.resize(new_size_bound, 0); + res.data.vals.resize(new_size_bound, T::zero()); + + for (i, beta) in rhs.data.column_entries(j) { + for (k, val) in self.data.column_entries(i) { + workspace[k] += val.clone() * beta.clone(); + } + } + + for (i, val) in workspace.as_mut_slice().iter_mut().enumerate() { + if !val.is_zero() { + res.data.i[nz] = i; + res.data.vals[nz] = val.clone(); + *val = T::zero(); + nz += 1; + } + } + } + + // NOTE: the following has a lower complexity, but is slower in many cases, likely because + // of branching inside of the inner loop. + // + // let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len()); + // let mut timestamps = OVector::zeros_generic(nrows1, Const::<)>; + // let mut workspace = unsafe { OVector::new_uninitialized_generic(nrows1, Const::<)> }; + // let mut nz = 0; + // + // for j in 0..ncols2.value() { + // res.data.p[j] = nz; + // let new_size_bound = nz + nrows1.value(); + // res.data.i.resize(new_size_bound, 0); + // res.data.vals.resize(new_size_bound, T::zero()); + // + // for (i, val) in rhs.data.column_entries(j) { + // nz = self.scatter( + // i, + // val, + // timestamps.as_mut_slice(), + // j + 1, + // workspace.as_mut_slice(), + // nz, + // &mut res, + // ); + // } + // + // // Keep the output sorted. + // let range = res.data.p[j]..nz; + // res.data.i[range.clone()].sort(); + // + // for p in range { + // res.data.vals[p] = workspace[res.data.i[p]] + // } + // } + + res.data.i.truncate(nz); + res.data.i.shrink_to_fit(); + res.data.vals.truncate(nz); + res.data.vals.shrink_to_fit(); + res + } +} + +impl<'a, 'b, T, R1, R2, C1, C2, S1, S2> Add<&'b CsMatrix> + for &'a CsMatrix +where + T: Scalar + ClosedAddAssign + ClosedMulAssign + Zero + One, + R1: Dim, + C1: Dim, + R2: Dim, + C2: Dim, + S1: CsStorage, + S2: CsStorage, + ShapeConstraint: DimEq + DimEq, + DefaultAllocator: Allocator + Allocator + Allocator, +{ + type Output = CsMatrix; + + fn add(self, rhs: &'b CsMatrix) -> Self::Output { + let (nrows1, ncols1) = self.data.shape(); + let (nrows2, ncols2) = rhs.data.shape(); + assert_eq!( + (nrows1.value(), ncols1.value()), + (nrows2.value(), ncols2.value()), + "Mismatched dimensions for matrix sum." + ); + + let mut res = CsMatrix::new_uninitialized_generic(nrows1, ncols2, self.len() + rhs.len()); + let mut timestamps = OVector::zeros_generic(nrows1, Const::<1>); + let mut workspace = Matrix::zeros_generic(nrows1, Const::<1>); + let mut nz = 0; + + for j in 0..ncols2.value() { + res.data.p[j] = nz; + + nz = self.scatter( + j, + T::one(), + timestamps.as_mut_slice(), + j + 1, + workspace.as_mut_slice(), + nz, + &mut res, + ); + + nz = rhs.scatter( + j, + T::one(), + timestamps.as_mut_slice(), + j + 1, + workspace.as_mut_slice(), + nz, + &mut res, + ); + + // Keep the output sorted. + let range = res.data.p[j]..nz; + res.data.i[range.clone()].sort_unstable(); + + for p in range { + res.data.vals[p] = workspace[res.data.i[p]].clone() + } + } + + res.data.i.truncate(nz); + res.data.i.shrink_to_fit(); + res.data.vals.truncate(nz); + res.data.vals.shrink_to_fit(); + res + } +} + +impl<'a, 'b, T, R, C, S> Mul for CsMatrix +where + T: Scalar + ClosedAddAssign + ClosedMulAssign + Zero, + R: Dim, + C: Dim, + S: CsStorageMut, +{ + type Output = Self; + + fn mul(mut self, rhs: T) -> Self::Output { + for e in self.values_mut() { + *e *= rhs.clone() + } + + self + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_solve.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_solve.rs new file mode 100644 index 000000000..31e3e7371 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_matrix_solve.rs @@ -0,0 +1,289 @@ +use crate::allocator::Allocator; +use crate::constraint::{SameNumberOfRows, ShapeConstraint}; +use crate::sparse::{CsMatrix, CsStorage, CsVector}; +use crate::storage::{Storage, StorageMut}; +use crate::{Const, DefaultAllocator, Dim, Matrix, OMatrix, OVector, RealField}; + +impl> CsMatrix { + /// Solve a lower-triangular system with a dense right-hand-side. + #[must_use = "Did you mean to use solve_lower_triangular_mut()?"] + pub fn solve_lower_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut b = b.clone_owned(); + if self.solve_lower_triangular_mut(&mut b) { + Some(b) + } else { + None + } + } + + /// Solve a lower-triangular system with `self` transposed and a dense right-hand-side. + #[must_use = "Did you mean to use tr_solve_lower_triangular_mut()?"] + pub fn tr_solve_lower_triangular( + &self, + b: &Matrix, + ) -> Option> + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut b = b.clone_owned(); + if self.tr_solve_lower_triangular_mut(&mut b) { + Some(b) + } else { + None + } + } + + /// Solve in-place a lower-triangular system with a dense right-hand-side. + pub fn solve_lower_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let (nrows, ncols) = self.data.shape(); + assert_eq!(nrows.value(), ncols.value(), "The matrix must be square."); + assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions."); + + for j2 in 0..b.ncols() { + let mut b = b.column_mut(j2); + + for j in 0..ncols.value() { + let mut column = self.data.column_entries(j); + let mut diag_found = false; + + for (i, val) in &mut column { + if i == j { + if val.is_zero() { + return false; + } + + b[j] /= val; + diag_found = true; + break; + } + } + + if !diag_found { + return false; + } + + for (i, val) in column { + let bj = b[j].clone(); + b[i] -= bj * val; + } + } + } + + true + } + + /// Solve a lower-triangular system with `self` transposed and a dense right-hand-side. + pub fn tr_solve_lower_triangular_mut( + &self, + b: &mut Matrix, + ) -> bool + where + S2: StorageMut, + ShapeConstraint: SameNumberOfRows, + { + let (nrows, ncols) = self.data.shape(); + assert_eq!(nrows.value(), ncols.value(), "The matrix must be square."); + assert_eq!(nrows.value(), b.len(), "Mismatched matrix dimensions."); + + for j2 in 0..b.ncols() { + let mut b = b.column_mut(j2); + + for j in (0..ncols.value()).rev() { + let mut column = self.data.column_entries(j); + let mut diag = None; + + for (i, val) in &mut column { + if i == j { + if val.is_zero() { + return false; + } + + diag = Some(val); + break; + } + } + + if let Some(diag) = diag { + for (i, val) in column { + let bi = b[i].clone(); + b[j] -= val * bi; + } + + b[j] /= diag; + } else { + return false; + } + } + } + + true + } + + /// Solve a lower-triangular system with a sparse right-hand-side. + #[must_use] + pub fn solve_lower_triangular_cs( + &self, + b: &CsVector, + ) -> Option> + where + S2: CsStorage, + DefaultAllocator: Allocator + Allocator, + ShapeConstraint: SameNumberOfRows, + { + let mut reach = Vec::new(); + // We don't compute a postordered reach here because it will be sorted after anyway. + self.lower_triangular_reach(b, &mut reach); + // We sort the reach so the result matrix has sorted indices. + reach.sort_unstable(); + let mut workspace = Matrix::zeros_generic(b.data.shape().0, Const::<1>); + + for i in reach.iter().cloned() { + workspace[i] = T::zero(); + } + + for (i, val) in b.data.column_entries(0) { + workspace[i] = val; + } + + for j in reach.iter().cloned() { + let mut column = self.data.column_entries(j); + let mut diag_found = false; + + for (i, val) in &mut column { + if i == j { + if val.is_zero() { + break; + } + + workspace[j] /= val; + diag_found = true; + break; + } + } + + if !diag_found { + return None; + } + + for (i, val) in column { + let wj = workspace[j].clone(); + workspace[i] -= wj * val; + } + } + + // Copy the result into a sparse vector. + let mut result = + CsVector::new_uninitialized_generic(b.data.shape().0, Const::<1>, reach.len()); + + for (i, val) in reach.iter().zip(result.data.vals.iter_mut()) { + *val = workspace[*i].clone(); + } + + result.data.i = reach; + Some(result) + } + + /* + // Computes the reachable, post-ordered, nodes from `b`. + fn lower_triangular_reach_postordered( + &self, + b: &CsVector, + xi: &mut Vec, + ) where + S2: CsStorage, + DefaultAllocator: Allocator, + { + let mut visited = OVector::repeat_generic(self.data.shape().1, U1, false); + let mut stack = Vec::new(); + + for i in b.data.column_range(0) { + let row_index = b.data.row_index(i); + + if !visited[row_index] { + let rng = self.data.column_range(row_index); + stack.push((row_index, rng)); + self.lower_triangular_dfs(visited.as_mut_slice(), &mut stack, xi); + } + } + } + + fn lower_triangular_dfs( + &self, + visited: &mut [bool], + stack: &mut Vec<(usize, Range)>, + xi: &mut Vec, + ) + { + 'recursion: while let Some((j, rng)) = stack.pop() { + visited[j] = true; + + for i in rng.clone() { + let row_id = self.data.row_index(i); + if row_id > j && !visited[row_id] { + stack.push((j, (i + 1)..rng.end)); + stack.push((row_id, self.data.column_range(row_id))); + continue 'recursion; + } + } + + xi.push(j) + } + } + */ + + // Computes the nodes reachable from `b` in an arbitrary order. + fn lower_triangular_reach(&self, b: &CsVector, xi: &mut Vec) + where + S2: CsStorage, + DefaultAllocator: Allocator, + { + let mut visited = OVector::repeat_generic(self.data.shape().1, Const::<1>, false); + let mut stack = Vec::new(); + + for irow in b.data.column_row_indices(0) { + self.lower_triangular_bfs(irow, visited.as_mut_slice(), &mut stack, xi); + } + } + + fn lower_triangular_bfs( + &self, + start: usize, + visited: &mut [bool], + stack: &mut Vec, + xi: &mut Vec, + ) { + if !visited[start] { + stack.clear(); + stack.push(start); + xi.push(start); + visited[start] = true; + + while let Some(j) = stack.pop() { + for irow in self.data.column_row_indices(j) { + if irow > j && !visited[irow] { + stack.push(irow); + xi.push(irow); + visited[irow] = true; + } + } + } + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_utils.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_utils.rs new file mode 100644 index 000000000..a17d4b9f6 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/cs_utils.rs @@ -0,0 +1,18 @@ +use crate::allocator::Allocator; +use crate::{DefaultAllocator, Dim, OVector}; + +pub fn cumsum(a: &mut OVector, b: &mut OVector) -> usize +where + DefaultAllocator: Allocator, +{ + assert!(a.len() == b.len()); + let mut sum = 0; + + for i in 0..a.len() { + b[i] = sum; + sum += a[i]; + a[i] = b[i]; + } + + sum +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/mod.rs new file mode 100644 index 000000000..457c13bf5 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/sparse/mod.rs @@ -0,0 +1,13 @@ +//! Sparse matrices. + +pub use self::cs_matrix::{ + CsMatrix, CsStorage, CsStorageIter, CsStorageIterMut, CsStorageMut, CsVecStorage, CsVector, +}; +pub use self::cs_matrix_cholesky::CsCholesky; + +mod cs_matrix; +mod cs_matrix_cholesky; +mod cs_matrix_conversion; +mod cs_matrix_ops; +mod cs_matrix_solve; +pub(crate) mod cs_utils; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_dual_quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_dual_quaternion.rs new file mode 100644 index 000000000..b86757fc9 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_dual_quaternion.rs @@ -0,0 +1,324 @@ +use num::Zero; + +use alga::general::{ + AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, + AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Module, + Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::{ + AffineTransformation, DirectIsometry, FiniteDimVectorSpace, Isometry, NormedSpace, + ProjectiveTransformation, Similarity, Transformation, VectorSpace, +}; + +use crate::base::Vector3; +use crate::geometry::{ + DualQuaternion, Point3, Quaternion, Translation3, UnitDualQuaternion, UnitQuaternion, +}; + +impl Identity for DualQuaternion { + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl Identity for DualQuaternion { + #[inline] + fn identity() -> Self { + Self::zero() + } +} + +impl AbstractMagma for DualQuaternion { + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +impl AbstractMagma for DualQuaternion { + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self + rhs + } +} + +impl TwoSidedInverse for DualQuaternion { + #[inline] + fn two_sided_inverse(&self) -> Self { + -self + } +} + +macro_rules! impl_structures( + ($DualQuaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for $DualQuaternion { } + )*} +); + +impl_structures!( + DualQuaternion; + AbstractSemigroup, + AbstractMonoid, + + AbstractSemigroup, + AbstractQuasigroup, + AbstractMonoid, + AbstractLoop, + AbstractGroup, + AbstractGroupAbelian +); + +/* + * + * Vector space. + * + */ +impl AbstractModule for DualQuaternion { + type AbstractRing = T; + + #[inline] + fn multiply_by(&self, n: T) -> Self { + self * n + } +} + +impl Module for DualQuaternion { + type Ring = T; +} + +impl VectorSpace for DualQuaternion { + type Field = T; +} + +impl FiniteDimVectorSpace for DualQuaternion { + #[inline] + fn dimension() -> usize { + 8 + } + + #[inline] + fn canonical_basis_element(i: usize) -> Self { + if i < 4 { + DualQuaternion::from_real_and_dual( + Quaternion::canonical_basis_element(i), + Quaternion::zero(), + ) + } else { + DualQuaternion::from_real_and_dual( + Quaternion::zero(), + Quaternion::canonical_basis_element(i - 4), + ) + } + } + + #[inline] + fn dot(&self, other: &Self) -> T { + self.real.dot(&other.real) + self.dual.dot(&other.dual) + } + + #[inline] + unsafe fn component_unchecked(&self, i: usize) -> &T { + self.as_ref().get_unchecked(i) + } + + #[inline] + unsafe fn component_unchecked_mut(&mut self, i: usize) -> &mut T { + self.as_mut().get_unchecked_mut(i) + } +} + +impl NormedSpace for DualQuaternion { + type RealField = T; + type ComplexField = T; + + #[inline] + fn norm_squared(&self) -> T { + self.real.norm_squared() + } + + #[inline] + fn norm(&self) -> T { + self.real.norm() + } + + #[inline] + fn normalize(&self) -> Self { + self.normalize() + } + + #[inline] + fn normalize_mut(&mut self) -> T { + self.normalize_mut() + } + + #[inline] + fn try_normalize(&self, min_norm: T) -> Option { + let real_norm = self.real.norm(); + if real_norm > min_norm { + Some(Self::from_real_and_dual( + self.real / real_norm, + self.dual / real_norm, + )) + } else { + None + } + } + + #[inline] + fn try_normalize_mut(&mut self, min_norm: T) -> Option { + let real_norm = self.real.norm(); + if real_norm > min_norm { + self.real /= real_norm; + self.dual /= real_norm; + Some(real_norm) + } else { + None + } + } +} + +/* + * + * Implementations for UnitDualQuaternion. + * + */ +impl Identity for UnitDualQuaternion { + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl AbstractMagma + for UnitDualQuaternion +{ + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +impl TwoSidedInverse + for UnitDualQuaternion +{ + #[inline] + fn two_sided_inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +impl_structures!( + UnitDualQuaternion; + AbstractSemigroup, + AbstractQuasigroup, + AbstractMonoid, + AbstractLoop, + AbstractGroup +); + +impl Transformation> for UnitDualQuaternion { + #[inline] + fn transform_point(&self, pt: &Point3) -> Point3 { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &Vector3) -> Vector3 { + self.transform_vector(v) + } +} + +impl ProjectiveTransformation> + for UnitDualQuaternion +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point3) -> Point3 { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { + self.inverse_transform_vector(v) + } +} + +impl AffineTransformation> + for UnitDualQuaternion +{ + type Rotation = UnitQuaternion; + type NonUniformScaling = Id; + type Translation = Translation3; + + #[inline] + fn decompose(&self) -> (Self::Translation, Self::Rotation, Id, Self::Rotation) { + ( + self.translation(), + self.rotation(), + Id::new(), + UnitQuaternion::identity(), + ) + } + + #[inline] + fn append_translation(&self, translation: &Self::Translation) -> Self { + self * Self::from_parts(*translation, UnitQuaternion::identity()) + } + + #[inline] + fn prepend_translation(&self, translation: &Self::Translation) -> Self { + Self::from_parts(*translation, UnitQuaternion::identity()) * self + } + + #[inline] + fn append_rotation(&self, r: &Self::Rotation) -> Self { + r * self + } + + #[inline] + fn prepend_rotation(&self, r: &Self::Rotation) -> Self { + self * r + } + + #[inline] + fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } + + #[inline] + fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } +} + +impl Similarity> for UnitDualQuaternion { + type Scaling = Id; + + #[inline] + fn translation(&self) -> Translation3 { + self.translation() + } + + #[inline] + fn rotation(&self) -> UnitQuaternion { + self.rotation() + } + + #[inline] + fn scaling(&self) -> Id { + Id::new() + } +} + +macro_rules! marker_impl( + ($($Trait: ident),*) => {$( + impl $Trait> for UnitDualQuaternion { } + )*} +); + +marker_impl!(Isometry, DirectIsometry); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_isometry.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_isometry.rs new file mode 100644 index 000000000..d9091e5be --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_isometry.rs @@ -0,0 +1,199 @@ +use alga::general::{ + AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::Isometry as AlgaIsometry; +use alga::linear::{ + AffineTransformation, DirectIsometry, ProjectiveTransformation, Rotation, Similarity, + Transformation, +}; + +use crate::base::SVector; + +use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; + +/* + * + * Algebraic structures. + * + */ +impl Identity + for Isometry +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl TwoSidedInverse + for Isometry +where + R: Rotation> + AbstractRotation, +{ + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +impl AbstractMagma + for Isometry +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +macro_rules! impl_multiplicative_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for Isometry + where R: Rotation> + AbstractRotation { } + )*} +); + +impl_multiplicative_structures!( + AbstractSemigroup, + AbstractMonoid, + AbstractQuasigroup, + AbstractLoop, + AbstractGroup +); + +/* + * + * Transformation groups. + * + */ +impl Transformation> + for Isometry +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn transform_point(&self, pt: &Point) -> Point { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self.transform_vector(v) + } +} + +impl + ProjectiveTransformation> for Isometry +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point) -> Point { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } +} + +impl AffineTransformation> + for Isometry +where + R: Rotation> + AbstractRotation, +{ + type Rotation = R; + type NonUniformScaling = Id; + type Translation = Translation; + + #[inline] + fn decompose(&self) -> (Self::Translation, R, Id, R) { + ( + self.translation, + self.rotation.clone(), + Id::new(), + >::identity(), + ) + } + + #[inline] + fn append_translation(&self, t: &Self::Translation) -> Self { + t * self + } + + #[inline] + fn prepend_translation(&self, t: &Self::Translation) -> Self { + self * t + } + + #[inline] + fn append_rotation(&self, r: &Self::Rotation) -> Self { + let shift = Transformation::transform_vector(r, &self.translation.vector); + Isometry::from_parts(Translation::from(shift), r.clone() * self.rotation.clone()) + } + + #[inline] + fn prepend_rotation(&self, r: &Self::Rotation) -> Self { + Isometry::from_parts(self.translation, self.rotation.prepend_rotation(r)) + } + + #[inline] + fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { + self.clone() + } + + #[inline] + fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { + self.clone() + } + + #[inline] + fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &Point) -> Option { + let mut res = self.clone(); + res.append_rotation_wrt_point_mut(r, p); + Some(res) + } +} + +impl Similarity> + for Isometry +where + R: Rotation> + AbstractRotation, +{ + type Scaling = Id; + + #[inline] + fn translation(&self) -> Translation { + self.translation + } + + #[inline] + fn rotation(&self) -> R { + self.rotation.clone() + } + + #[inline] + fn scaling(&self) -> Id { + Id::new() + } +} + +macro_rules! marker_impl( + ($($Trait: ident),*) => {$( + impl $Trait> for Isometry + where R: Rotation> + AbstractRotation { } + )*} +); + +marker_impl!(AlgaIsometry, DirectIsometry); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_matrix.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_matrix.rs new file mode 100644 index 000000000..22d79e30e --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_matrix.rs @@ -0,0 +1,454 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::Vec; + +use num::{One, Zero}; + +use alga::general::{ + AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, + AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, ClosedAdd, ClosedMul, + ClosedNeg, ComplexField, Field, Identity, JoinSemilattice, Lattice, MeetSemilattice, Module, + Multiplicative, RingCommutative, TwoSidedInverse, +}; +use alga::linear::{ + FiniteDimInnerSpace, FiniteDimVectorSpace, InnerSpace, NormedSpace, VectorSpace, +}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{Dim, DimName}; +use crate::base::storage::{RawStorage, RawStorageMut}; +use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar}; +use std::mem::MaybeUninit; + +/* + * + * Additive structures. + * + */ +impl Identity for OMatrix +where + T: Scalar + Zero, + DefaultAllocator: Allocator, +{ + #[inline] + fn identity() -> Self { + Self::from_element(T::zero()) + } +} + +impl AbstractMagma for OMatrix +where + T: Scalar + ClosedAdd, + DefaultAllocator: Allocator, +{ + #[inline] + fn operate(&self, other: &Self) -> Self { + self + other + } +} + +impl TwoSidedInverse for OMatrix +where + T: Scalar + ClosedNeg, + DefaultAllocator: Allocator, +{ + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + -self + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + *self = -self.clone() + } +} + +macro_rules! inherit_additive_structure( + ($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$( + impl $marker<$operator> for OMatrix + where T: Scalar + $marker<$operator> $(+ $bounds)*, + DefaultAllocator: Allocator { } + )*} +); + +inherit_additive_structure!( + AbstractSemigroup + ClosedAdd, + AbstractMonoid + Zero + ClosedAdd, + AbstractQuasigroup + ClosedAdd + ClosedNeg, + AbstractLoop + Zero + ClosedAdd + ClosedNeg, + AbstractGroup + Zero + ClosedAdd + ClosedNeg, + AbstractGroupAbelian + Zero + ClosedAdd + ClosedNeg +); + +impl AbstractModule for OMatrix +where + T: Scalar + RingCommutative, + DefaultAllocator: Allocator, +{ + type AbstractRing = T; + + #[inline] + fn multiply_by(&self, n: T) -> Self { + self * n + } +} + +impl Module for OMatrix +where + T: Scalar + RingCommutative, + DefaultAllocator: Allocator, +{ + type Ring = T; +} + +impl VectorSpace for OMatrix +where + T: Scalar + Field, + DefaultAllocator: Allocator, +{ + type Field = T; +} + +impl FiniteDimVectorSpace for OMatrix +where + T: Scalar + Field, + DefaultAllocator: Allocator, +{ + #[inline] + fn dimension() -> usize { + R::dim() * C::dim() + } + + #[inline] + fn canonical_basis_element(i: usize) -> Self { + assert!(i < Self::dimension(), "Index out of bound."); + + let mut res = Self::zero(); + unsafe { + *res.data.get_unchecked_linear_mut(i) = T::one(); + } + + res + } + + #[inline] + fn dot(&self, other: &Self) -> T { + self.dot(other) + } + + #[inline] + unsafe fn component_unchecked(&self, i: usize) -> &T { + self.data.get_unchecked_linear(i) + } + + #[inline] + unsafe fn component_unchecked_mut(&mut self, i: usize) -> &mut T { + self.data.get_unchecked_linear_mut(i) + } +} + +impl< + T: ComplexField + simba::scalar::ComplexField::RealField>, + R: DimName, + C: DimName, + > NormedSpace for OMatrix +where + ::RealField: simba::scalar::RealField, + DefaultAllocator: Allocator, +{ + type RealField = ::RealField; + type ComplexField = T; + + #[inline] + fn norm_squared(&self) -> ::RealField { + self.norm_squared() + } + + #[inline] + fn norm(&self) -> ::RealField { + self.norm() + } + + #[inline] + #[must_use = "Did you mean to use normalize_mut()?"] + fn normalize(&self) -> Self { + self.normalize() + } + + #[inline] + fn normalize_mut(&mut self) -> ::RealField { + self.normalize_mut() + } + + #[inline] + #[must_use = "Did you mean to use try_normalize_mut()?"] + fn try_normalize(&self, min_norm: ::RealField) -> Option { + self.try_normalize(min_norm) + } + + #[inline] + fn try_normalize_mut( + &mut self, + min_norm: ::RealField, + ) -> Option<::RealField> { + self.try_normalize_mut(min_norm) + } +} + +impl< + T: ComplexField + simba::scalar::ComplexField::RealField>, + R: DimName, + C: DimName, + > InnerSpace for OMatrix +where + ::RealField: simba::scalar::RealField, + DefaultAllocator: Allocator, +{ + #[inline] + fn angle(&self, other: &Self) -> ::RealField { + self.angle(other) + } + + #[inline] + fn inner_product(&self, other: &Self) -> T { + self.dotc(other) + } +} + +// TODO: specialization will greatly simplify this implementation in the future. +// In particular: +// − use `x()` instead of `::canonical_basis_element` +// − use `::new(x, y, z)` instead of `::from_slice` +impl< + T: ComplexField + simba::scalar::ComplexField::RealField>, + R: DimName, + C: DimName, + > FiniteDimInnerSpace for OMatrix +where + ::RealField: simba::scalar::RealField, + DefaultAllocator: Allocator, +{ + #[inline] + fn orthonormalize(vs: &mut [Self]) -> usize { + let mut nbasis_elements = 0; + + for i in 0..vs.len() { + { + let (elt, basis) = vs[..i + 1].split_last_mut().unwrap(); + + for basis_element in &basis[..nbasis_elements] { + *elt -= &*basis_element * elt.dot(basis_element) + } + } + + if vs[i] + .try_normalize_mut(::RealField::zero()) + .is_some() + { + // TODO: this will be efficient on dynamically-allocated vectors but for + // statically-allocated ones, `.clone_from` would be better. + vs.swap(nbasis_elements, i); + nbasis_elements += 1; + + // All the other vectors will be dependent. + if nbasis_elements == Self::dimension() { + break; + } + } + } + + nbasis_elements + } + + #[inline] + fn orthonormal_subspace_basis(vs: &[Self], mut f: F) + where + F: FnMut(&Self) -> bool, + { + // TODO: is this necessary? + assert!( + vs.len() <= Self::dimension(), + "The given set of vectors has no chance of being a free family." + ); + + match Self::dimension() { + 1 => { + if vs.is_empty() { + let _ = f(&Self::canonical_basis_element(0)); + } + } + 2 => { + if vs.is_empty() { + let _ = f(&Self::canonical_basis_element(0)) + && f(&Self::canonical_basis_element(1)); + } else if vs.len() == 1 { + let v = &vs[0]; + let res = Self::from_column_slice(&[-v[1], v[0]]); + + let _ = f(&res.normalize()); + } + + // Otherwise, nothing. + } + 3 => { + if vs.is_empty() { + let _ = f(&Self::canonical_basis_element(0)) + && f(&Self::canonical_basis_element(1)) + && f(&Self::canonical_basis_element(2)); + } else if vs.len() == 1 { + let v = &vs[0]; + let mut a; + + if ComplexField::norm1(v[0]) > ComplexField::norm1(v[1]) { + a = Self::from_column_slice(&[v[2], T::zero(), -v[0]]); + } else { + a = Self::from_column_slice(&[T::zero(), -v[2], v[1]]); + }; + + let _ = a.normalize_mut(); + + if f(&a.cross(v)) { + let _ = f(&a); + } + } else if vs.len() == 2 { + let _ = f(&vs[0].cross(&vs[1]).normalize()); + } + } + _ => { + #[cfg(any(feature = "std", feature = "alloc"))] + { + // XXX: use a GenericArray instead. + let mut known_basis = Vec::new(); + + for v in vs.iter() { + known_basis.push(v.normalize()) + } + + for i in 0..Self::dimension() - vs.len() { + let mut elt = Self::canonical_basis_element(i); + + for v in &known_basis { + elt -= v * elt.dot(v) + } + + if let Some(subsp_elt) = + elt.try_normalize(::RealField::zero()) + { + if !f(&subsp_elt) { + return; + }; + + known_basis.push(subsp_elt); + } + } + } + #[cfg(all(not(feature = "std"), not(feature = "alloc")))] + { + panic!("Cannot compute the orthogonal subspace basis of a vector with a dimension greater than 3 \ + if #![no_std] is enabled and the 'alloc' feature is not enabled.") + } + } + } + } +} + +/* + * + * + * Multiplicative structures. + * + * + */ +impl Identity for OMatrix +where + T: Scalar + Zero + One, + DefaultAllocator: Allocator, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl AbstractMagma for OMatrix +where + T: Scalar + Zero + One + ClosedAdd + ClosedMul, + DefaultAllocator: Allocator, +{ + #[inline] + fn operate(&self, other: &Self) -> Self { + self * other + } +} + +macro_rules! impl_multiplicative_structure( + ($($marker: ident<$operator: ident> $(+ $bounds: ident)*),* $(,)*) => {$( + impl $marker<$operator> for OMatrix + where T: Scalar + Zero + One + ClosedAdd + ClosedMul + $marker<$operator> $(+ $bounds)*, + DefaultAllocator: Allocator { } + )*} +); + +impl_multiplicative_structure!( + AbstractSemigroup, + AbstractMonoid + One +); + +/* + * + * Ordering + * + */ +impl MeetSemilattice for OMatrix +where + T: Scalar + MeetSemilattice, + DefaultAllocator: Allocator, +{ + #[inline] + fn meet(&self, other: &Self) -> Self { + self.zip_map(other, |a, b| a.meet(&b)) + } +} + +impl JoinSemilattice for OMatrix +where + T: Scalar + JoinSemilattice, + DefaultAllocator: Allocator, +{ + #[inline] + fn join(&self, other: &Self) -> Self { + self.zip_map(other, |a, b| a.join(&b)) + } +} + +impl Lattice for OMatrix +where + T: Scalar + Lattice, + DefaultAllocator: Allocator, +{ + #[inline] + fn meet_join(&self, other: &Self) -> (Self, Self) { + let shape = self.shape_generic(); + assert!( + shape == other.shape_generic(), + "Matrix meet/join error: mismatched dimensions." + ); + + let mut mres = Matrix::uninit(shape.0, shape.1); + let mut jres = Matrix::uninit(shape.0, shape.1); + + for i in 0..shape.0.value() * shape.1.value() { + unsafe { + let mj = self + .data + .get_unchecked_linear(i) + .meet_join(other.data.get_unchecked_linear(i)); + *mres.data.get_unchecked_linear_mut(i) = MaybeUninit::new(mj.0); + *jres.data.get_unchecked_linear_mut(i) = MaybeUninit::new(mj.1); + } + } + + // Safety: both mres and jres are now completely initialized. + unsafe { (mres.assume_init(), jres.assume_init()) } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_point.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_point.rs new file mode 100644 index 000000000..43af0d848 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_point.rs @@ -0,0 +1,75 @@ +use alga::general::{Field, JoinSemilattice, Lattice, MeetSemilattice, RealField}; +use alga::linear::{AffineSpace, EuclideanSpace}; + +use crate::base::{SVector, Scalar}; + +use crate::geometry::Point; + +impl AffineSpace for Point +where + T: Scalar + Field, +{ + type Translation = SVector; +} + +impl EuclideanSpace for Point { + type Coordinates = SVector; + type RealField = T; + + #[inline] + fn origin() -> Self { + Self::origin() + } + + #[inline] + fn coordinates(&self) -> Self::Coordinates { + self.coords + } + + #[inline] + fn from_coordinates(coords: Self::Coordinates) -> Self { + Self::from(coords) + } + + #[inline] + fn scale_by(&self, n: T) -> Self { + self * n + } +} + +/* + * + * Ordering + * + */ +impl MeetSemilattice for Point +where + T: Scalar + MeetSemilattice, +{ + #[inline] + fn meet(&self, other: &Self) -> Self { + Self::from(self.coords.meet(&other.coords)) + } +} + +impl JoinSemilattice for Point +where + T: Scalar + JoinSemilattice, +{ + #[inline] + fn join(&self, other: &Self) -> Self { + Self::from(self.coords.join(&other.coords)) + } +} + +impl Lattice for Point +where + T: Scalar + Lattice, +{ + #[inline] + fn meet_join(&self, other: &Self) -> (Self, Self) { + let (meet, join) = self.coords.meet_join(&other.coords); + + (Self::from(meet), Self::from(join)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_quaternion.rs new file mode 100644 index 000000000..d42caa59f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_quaternion.rs @@ -0,0 +1,309 @@ +use num::Zero; + +use alga::general::{ + AbstractGroup, AbstractGroupAbelian, AbstractLoop, AbstractMagma, AbstractModule, + AbstractMonoid, AbstractQuasigroup, AbstractSemigroup, Additive, Id, Identity, Module, + Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::{ + AffineTransformation, DirectIsometry, FiniteDimVectorSpace, Isometry, NormedSpace, + OrthogonalTransformation, ProjectiveTransformation, Rotation, Similarity, Transformation, + VectorSpace, +}; + +use crate::base::{Vector3, Vector4}; +use crate::geometry::{Point3, Quaternion, UnitQuaternion}; + +impl Identity for Quaternion { + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl Identity for Quaternion { + #[inline] + fn identity() -> Self { + Self::zero() + } +} + +impl AbstractMagma for Quaternion { + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +impl AbstractMagma for Quaternion { + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self + rhs + } +} + +impl TwoSidedInverse for Quaternion { + #[inline] + fn two_sided_inverse(&self) -> Self { + -self + } +} + +macro_rules! impl_structures( + ($Quaternion: ident; $($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for $Quaternion { } + )*} +); + +impl_structures!( + Quaternion; + AbstractSemigroup, + AbstractMonoid, + + AbstractSemigroup, + AbstractQuasigroup, + AbstractMonoid, + AbstractLoop, + AbstractGroup, + AbstractGroupAbelian +); + +/* + * + * Vector space. + * + */ +impl AbstractModule for Quaternion { + type AbstractRing = T; + + #[inline] + fn multiply_by(&self, n: T) -> Self { + self * n + } +} + +impl Module for Quaternion { + type Ring = T; +} + +impl VectorSpace for Quaternion { + type Field = T; +} + +impl FiniteDimVectorSpace for Quaternion { + #[inline] + fn dimension() -> usize { + 4 + } + + #[inline] + fn canonical_basis_element(i: usize) -> Self { + Self::from(Vector4::canonical_basis_element(i)) + } + + #[inline] + fn dot(&self, other: &Self) -> T { + self.coords.dot(&other.coords) + } + + #[inline] + unsafe fn component_unchecked(&self, i: usize) -> &T { + self.coords.component_unchecked(i) + } + + #[inline] + unsafe fn component_unchecked_mut(&mut self, i: usize) -> &mut T { + self.coords.component_unchecked_mut(i) + } +} + +impl NormedSpace for Quaternion { + type RealField = T; + type ComplexField = T; + + #[inline] + fn norm_squared(&self) -> T { + self.coords.norm_squared() + } + + #[inline] + fn norm(&self) -> T { + self.as_vector().norm() + } + + #[inline] + fn normalize(&self) -> Self { + let v = self.coords.normalize(); + Self::from(v) + } + + #[inline] + fn normalize_mut(&mut self) -> T { + self.coords.normalize_mut() + } + + #[inline] + fn try_normalize(&self, min_norm: T) -> Option { + self.coords.try_normalize(min_norm).map(Self::from) + } + + #[inline] + fn try_normalize_mut(&mut self, min_norm: T) -> Option { + self.coords.try_normalize_mut(min_norm) + } +} + +/* + * + * Implementations for UnitQuaternion. + * + */ +impl Identity for UnitQuaternion { + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl AbstractMagma for UnitQuaternion { + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +impl TwoSidedInverse + for UnitQuaternion +{ + #[inline] + fn two_sided_inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +impl_structures!( + UnitQuaternion; + AbstractSemigroup, + AbstractQuasigroup, + AbstractMonoid, + AbstractLoop, + AbstractGroup +); + +impl Transformation> for UnitQuaternion { + #[inline] + fn transform_point(&self, pt: &Point3) -> Point3 { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &Vector3) -> Vector3 { + self.transform_vector(v) + } +} + +impl ProjectiveTransformation> + for UnitQuaternion +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point3) -> Point3 { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { + self.inverse_transform_vector(v) + } +} + +impl AffineTransformation> + for UnitQuaternion +{ + type Rotation = Self; + type NonUniformScaling = Id; + type Translation = Id; + + #[inline] + fn decompose(&self) -> (Id, Self, Id, Self) { + (Id::new(), *self, Id::new(), Self::identity()) + } + + #[inline] + fn append_translation(&self, _: &Self::Translation) -> Self { + *self + } + + #[inline] + fn prepend_translation(&self, _: &Self::Translation) -> Self { + *self + } + + #[inline] + fn append_rotation(&self, r: &Self::Rotation) -> Self { + r * self + } + + #[inline] + fn prepend_rotation(&self, r: &Self::Rotation) -> Self { + self * r + } + + #[inline] + fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } + + #[inline] + fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } +} + +impl Similarity> for UnitQuaternion { + type Scaling = Id; + + #[inline] + fn translation(&self) -> Id { + Id::new() + } + + #[inline] + fn rotation(&self) -> Self { + *self + } + + #[inline] + fn scaling(&self) -> Id { + Id::new() + } +} + +macro_rules! marker_impl( + ($($Trait: ident),*) => {$( + impl $Trait> for UnitQuaternion { } + )*} +); + +marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); + +impl Rotation> for UnitQuaternion { + #[inline] + fn powf(&self, n: T) -> Option { + Some(self.powf(n)) + } + + #[inline] + fn rotation_between(a: &Vector3, b: &Vector3) -> Option { + Self::rotation_between(a, b) + } + + #[inline] + fn scaled_rotation_between(a: &Vector3, b: &Vector3, s: T) -> Option { + Self::scaled_rotation_between(a, b, s) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_rotation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_rotation.rs new file mode 100644 index 000000000..de5bc15bb --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_rotation.rs @@ -0,0 +1,272 @@ +use alga::general::{ + AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::{ + self, AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, + ProjectiveTransformation, Similarity, Transformation, +}; + +use crate::base::SVector; +use crate::geometry::{Point, Rotation}; + +/* + * + * Algebraic structures. + * + */ +impl Identity + for Rotation +{ + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl TwoSidedInverse + for Rotation +{ + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + self.transpose() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.transpose_mut() + } +} + +impl AbstractMagma + for Rotation +{ + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +macro_rules! impl_multiplicative_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for Rotation + { } + )*} +); + +impl_multiplicative_structures!( + AbstractSemigroup, + AbstractMonoid, + AbstractQuasigroup, + AbstractLoop, + AbstractGroup +); + +/* + * + * Transformation groups. + * + */ +impl Transformation> + for Rotation +{ + #[inline] + fn transform_point(&self, pt: &Point) -> Point { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self.transform_vector(v) + } +} + +impl ProjectiveTransformation> + for Rotation +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point) -> Point { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } +} + +impl AffineTransformation> + for Rotation +{ + type Rotation = Self; + type NonUniformScaling = Id; + type Translation = Id; + + #[inline] + fn decompose(&self) -> (Id, Self, Id, Self) { + (Id::new(), *self, Id::new(), Self::identity()) + } + + #[inline] + fn append_translation(&self, _: &Self::Translation) -> Self { + *self + } + + #[inline] + fn prepend_translation(&self, _: &Self::Translation) -> Self { + *self + } + + #[inline] + fn append_rotation(&self, r: &Self::Rotation) -> Self { + r * self + } + + #[inline] + fn prepend_rotation(&self, r: &Self::Rotation) -> Self { + self * r + } + + #[inline] + fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } + + #[inline] + fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } +} + +impl Similarity> + for Rotation +{ + type Scaling = Id; + + #[inline] + fn translation(&self) -> Id { + Id::new() + } + + #[inline] + fn rotation(&self) -> Self { + *self + } + + #[inline] + fn scaling(&self) -> Id { + Id::new() + } +} + +macro_rules! marker_impl( + ($($Trait: ident),*) => {$( + impl $Trait> for Rotation + { } + )*} +); + +marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); + +/// Subgroups of the n-dimensional rotation group `SO(n)`. +impl linear::Rotation> + for Rotation +{ + #[inline] + fn powf(&self, _: T) -> Option { + // XXX: Add the general case. + // XXX: Use specialization for 2D and 3D. + unimplemented!() + } + + #[inline] + fn rotation_between(_: &SVector, _: &SVector) -> Option { + // XXX: Add the general case. + // XXX: Use specialization for 2D and 3D. + unimplemented!() + } + + #[inline] + fn scaled_rotation_between(_: &SVector, _: &SVector, _: T) -> Option { + // XXX: Add the general case. + // XXX: Use specialization for 2D and 3D. + unimplemented!() + } +} + +/* +impl Matrix for Rotation { + type Field = T; + type Row = Matrix; + type Column = Matrix; + type Transpose = Self; + + #[inline] + fn nrows(&self) -> usize { + self.submatrix.nrows() + } + + #[inline] + fn ncolumns(&self) -> usize { + self.submatrix.ncolumns() + } + + #[inline] + fn row(&self, i: usize) -> Self::Row { + self.submatrix.row(i) + } + + #[inline] + fn column(&self, i: usize) -> Self::Column { + self.submatrix.column(i) + } + + #[inline] + fn get(&self, i: usize, j: usize) -> Self::Field { + self.submatrix[(i, j)] + } + + #[inline] + unsafe fn get_unchecked(&self, i: usize, j: usize) -> Self::Field { + self.submatrix.at_fast(i, j) + } + + #[inline] + fn transpose(&self) -> Self::Transpose { + Rotation::from_matrix_unchecked(self.submatrix.transpose()) + } +} + +impl SquareMatrix for Rotation { + type Vector = Matrix; + + #[inline] + fn diagonal(&self) -> Self::Coordinates { + self.submatrix.diagonal() + } + + #[inline] + fn determinant(&self) -> Self::Field { + crate::one() + } + + #[inline] + fn try_inverse(&self) -> Option { + Some(::transpose(self)) + } + + #[inline] + fn try_inverse_mut(&mut self) -> bool { + self.transpose_mut(); + true + } + + #[inline] + fn transpose_mut(&mut self) { + self.submatrix.transpose_mut() + } +} + +impl InversibleSquareMatrix for Rotation { } +*/ diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_similarity.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_similarity.rs new file mode 100644 index 000000000..aaf57f010 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_similarity.rs @@ -0,0 +1,186 @@ +use alga::general::{ + AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, + AbstractSemigroup, Identity, Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::Similarity as AlgaSimilarity; +use alga::linear::{AffineTransformation, ProjectiveTransformation, Rotation, Transformation}; + +use crate::base::SVector; +use crate::geometry::{AbstractRotation, Point, Similarity, Translation}; + +/* + * + * Algebraic structures. + * + */ +impl Identity + for Similarity +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl TwoSidedInverse + for Similarity +where + R: Rotation> + AbstractRotation, +{ + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +impl AbstractMagma + for Similarity +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +macro_rules! impl_multiplicative_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for Similarity + where R: Rotation> + AbstractRotation, + { } + )*} +); + +impl_multiplicative_structures!( + AbstractSemigroup, + AbstractMonoid, + AbstractQuasigroup, + AbstractLoop, + AbstractGroup +); + +/* + * + * Transformation groups. + * + */ +impl Transformation> + for Similarity +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn transform_point(&self, pt: &Point) -> Point { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self.transform_vector(v) + } +} + +impl + ProjectiveTransformation> for Similarity +where + R: Rotation> + AbstractRotation, +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point) -> Point { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } +} + +impl AffineTransformation> + for Similarity +where + R: Rotation> + AbstractRotation, +{ + type NonUniformScaling = T; + type Rotation = R; + type Translation = Translation; + + #[inline] + fn decompose(&self) -> (Translation, R, T, R) { + ( + self.isometry.translation, + self.isometry.rotation.clone(), + self.scaling(), + >::identity(), + ) + } + + #[inline] + fn append_translation(&self, t: &Self::Translation) -> Self { + t * self + } + + #[inline] + fn prepend_translation(&self, t: &Self::Translation) -> Self { + self * t + } + + #[inline] + fn append_rotation(&self, r: &Self::Rotation) -> Self { + Similarity::from_isometry(self.isometry.append_rotation(r), self.scaling()) + } + + #[inline] + fn prepend_rotation(&self, r: &Self::Rotation) -> Self { + Similarity::from_isometry(self.isometry.prepend_rotation(r), self.scaling()) + } + + #[inline] + fn append_scaling(&self, s: &Self::NonUniformScaling) -> Self { + self.append_scaling(*s) + } + + #[inline] + fn prepend_scaling(&self, s: &Self::NonUniformScaling) -> Self { + self.prepend_scaling(*s) + } + + #[inline] + fn append_rotation_wrt_point(&self, r: &Self::Rotation, p: &Point) -> Option { + let mut res = self.clone(); + res.append_rotation_wrt_point_mut(r, p); + Some(res) + } +} + +impl AlgaSimilarity> + for Similarity +where + R: Rotation> + AbstractRotation, +{ + type Scaling = T; + + #[inline] + fn translation(&self) -> Translation { + self.isometry.translation() + } + + #[inline] + fn rotation(&self) -> R { + self.isometry.rotation() + } + + #[inline] + fn scaling(&self) -> T { + self.scaling() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_transform.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_transform.rs new file mode 100644 index 000000000..e7ef58c3b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_transform.rs @@ -0,0 +1,152 @@ +use alga::general::{ + AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, + AbstractSemigroup, Identity, Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::{ProjectiveTransformation, Transformation}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, SVector}; + +use crate::geometry::{Point, SubTCategoryOf, TCategory, TProjective, Transform}; + +/* + * + * Algebraic structures. + * + */ +impl Identity + for Transform +where + Const: DimNameAdd, + C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl TwoSidedInverse + for Transform +where + Const: DimNameAdd, + C: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + self.clone().inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +impl AbstractMagma + for Transform +where + Const: DimNameAdd, + C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +macro_rules! impl_multiplicative_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for Transform + where + Const: DimNameAdd, + C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> { } + )*} +); + +macro_rules! impl_inversible_multiplicative_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for Transform + where + Const: DimNameAdd, + C: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> { } + )*} +); + +impl_multiplicative_structures!( + AbstractSemigroup, + AbstractMonoid, +); + +impl_inversible_multiplicative_structures!( + AbstractQuasigroup, + AbstractLoop, + AbstractGroup +); + +/* + * + * Transformation groups. + * + */ +impl Transformation> for Transform +where + Const: DimNameAdd, + T: RealField + simba::scalar::RealField, + C: TCategory, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>>, +{ + #[inline] + fn transform_point(&self, pt: &Point) -> Point { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + self.transform_vector(v) + } +} + +impl ProjectiveTransformation> for Transform +where + Const: DimNameAdd, + T: RealField + simba::scalar::RealField, + C: SubTCategoryOf, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>>, +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point) -> Point { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + self.inverse_transform_vector(v) + } +} + +// TODO: we need to implement an SVD for this. +// +// impl AffineTransformation> for Transform +// where T: RealField, +// C: SubTCategoryOf, +// DefaultAllocator: Allocator, U1>, DimNameSum, U1>> { +// type PreRotation = Rotation; +// type NonUniformScaling = OVector; +// type PostRotation = Rotation; +// type Translation = Translation; +// +// #[inline] +// fn decompose(&self) -> (Self::Translation, Self::PostRotation, Self::NonUniformScaling, Self::PreRotation) { +// unimplemented!() +// } +// } diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_translation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_translation.rs new file mode 100644 index 000000000..dbba0637a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_translation.rs @@ -0,0 +1,196 @@ +use alga::general::{ + AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::Translation as AlgaTranslation; +use alga::linear::{ + AffineTransformation, DirectIsometry, Isometry, ProjectiveTransformation, Similarity, + Transformation, +}; + +use crate::base::SVector; +use crate::geometry::{Point, Translation}; + +/* + * + * Algebraic structures. + * + */ +impl Identity + for Translation +{ + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl TwoSidedInverse + for Translation +{ + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +impl AbstractMagma + for Translation +{ + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +macro_rules! impl_multiplicative_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for Translation + { } + )*} +); + +impl_multiplicative_structures!( + AbstractSemigroup, + AbstractMonoid, + AbstractQuasigroup, + AbstractLoop, + AbstractGroup +); + +/* + * + * Transformation groups. + * + */ +impl Transformation> + for Translation +{ + #[inline] + fn transform_point(&self, pt: &Point) -> Point { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &SVector) -> SVector { + *v + } +} + +impl ProjectiveTransformation> + for Translation +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point) -> Point { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &SVector) -> SVector { + *v + } +} + +impl AffineTransformation> + for Translation +{ + type Rotation = Id; + type NonUniformScaling = Id; + type Translation = Self; + + #[inline] + fn decompose(&self) -> (Self, Id, Id, Id) { + (*self, Id::new(), Id::new(), Id::new()) + } + + #[inline] + fn append_translation(&self, t: &Self::Translation) -> Self { + t * self + } + + #[inline] + fn prepend_translation(&self, t: &Self::Translation) -> Self { + self * t + } + + #[inline] + fn append_rotation(&self, _: &Self::Rotation) -> Self { + *self + } + + #[inline] + fn prepend_rotation(&self, _: &Self::Rotation) -> Self { + *self + } + + #[inline] + fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } + + #[inline] + fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } +} + +impl Similarity> + for Translation +{ + type Scaling = Id; + + #[inline] + fn translation(&self) -> Self { + *self + } + + #[inline] + fn rotation(&self) -> Id { + Id::new() + } + + #[inline] + fn scaling(&self) -> Id { + Id::new() + } +} + +macro_rules! marker_impl( + ($($Trait: ident),*) => {$( + impl $Trait> for Translation + { } + )*} +); + +marker_impl!(Isometry, DirectIsometry); + +/// Subgroups of the n-dimensional translation group `T(n)`. +impl AlgaTranslation> + for Translation +{ + #[inline] + fn to_vector(&self) -> SVector { + self.vector + } + + #[inline] + fn from_vector(v: SVector) -> Option { + Some(Self::from(v)) + } + + #[inline] + fn powf(&self, n: T) -> Option { + Some(Self::from(self.vector * n)) + } + + #[inline] + fn translation_between(a: &Point, b: &Point) -> Option { + Some(Self::from(b - a)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_unit_complex.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_unit_complex.rs new file mode 100644 index 000000000..ff15d648f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/alga_unit_complex.rs @@ -0,0 +1,170 @@ +use alga::general::{ + AbstractGroup, AbstractLoop, AbstractMagma, AbstractMonoid, AbstractQuasigroup, + AbstractSemigroup, Id, Identity, Multiplicative, RealField, TwoSidedInverse, +}; +use alga::linear::{ + AffineTransformation, DirectIsometry, Isometry, OrthogonalTransformation, + ProjectiveTransformation, Rotation, Similarity, Transformation, +}; + +use crate::base::Vector2; +use crate::geometry::{Point2, UnitComplex}; + +/* + * + * Implementations for UnitComplex. + * + */ +impl Identity for UnitComplex { + #[inline] + fn identity() -> Self { + Self::identity() + } +} + +impl AbstractMagma for UnitComplex { + #[inline] + fn operate(&self, rhs: &Self) -> Self { + self * rhs + } +} + +impl TwoSidedInverse for UnitComplex { + #[inline] + #[must_use = "Did you mean to use two_sided_inverse_mut()?"] + fn two_sided_inverse(&self) -> Self { + self.inverse() + } + + #[inline] + fn two_sided_inverse_mut(&mut self) { + self.inverse_mut() + } +} + +macro_rules! impl_structures( + ($($marker: ident<$operator: ident>),* $(,)*) => {$( + impl $marker<$operator> for UnitComplex { + } + )*} +); + +impl_structures!( + AbstractSemigroup, + AbstractQuasigroup, + AbstractMonoid, + AbstractLoop, + AbstractGroup +); + +impl Transformation> for UnitComplex { + #[inline] + fn transform_point(&self, pt: &Point2) -> Point2 { + self.transform_point(pt) + } + + #[inline] + fn transform_vector(&self, v: &Vector2) -> Vector2 { + self.transform_vector(v) + } +} + +impl ProjectiveTransformation> + for UnitComplex +{ + #[inline] + fn inverse_transform_point(&self, pt: &Point2) -> Point2 { + self.inverse_transform_point(pt) + } + + #[inline] + fn inverse_transform_vector(&self, v: &Vector2) -> Vector2 { + self.inverse_transform_vector(v) + } +} + +impl AffineTransformation> for UnitComplex { + type Rotation = Self; + type NonUniformScaling = Id; + type Translation = Id; + + #[inline] + fn decompose(&self) -> (Id, Self, Id, Self) { + (Id::new(), *self, Id::new(), Self::identity()) + } + + #[inline] + fn append_translation(&self, _: &Self::Translation) -> Self { + *self + } + + #[inline] + fn prepend_translation(&self, _: &Self::Translation) -> Self { + *self + } + + #[inline] + fn append_rotation(&self, r: &Self::Rotation) -> Self { + r * self + } + + #[inline] + fn prepend_rotation(&self, r: &Self::Rotation) -> Self { + self * r + } + + #[inline] + fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } + + #[inline] + fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { + *self + } +} + +impl Similarity> for UnitComplex { + type Scaling = Id; + + #[inline] + fn translation(&self) -> Id { + Id::new() + } + + #[inline] + fn rotation(&self) -> Self { + *self + } + + #[inline] + fn scaling(&self) -> Id { + Id::new() + } +} + +macro_rules! marker_impl( + ($($Trait: ident),*) => {$( + impl $Trait> for UnitComplex + { } + )*} +); + +marker_impl!(Isometry, DirectIsometry, OrthogonalTransformation); + +impl Rotation> for UnitComplex { + #[inline] + fn powf(&self, n: T) -> Option { + Some(self.powf(n)) + } + + #[inline] + fn rotation_between(a: &Vector2, b: &Vector2) -> Option { + Some(Self::rotation_between(a, b)) + } + + #[inline] + fn scaled_rotation_between(a: &Vector2, b: &Vector2, s: T) -> Option { + Some(Self::scaled_rotation_between(a, b, s)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/mod.rs new file mode 100644 index 000000000..ff34b08cb --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/alga/mod.rs @@ -0,0 +1,10 @@ +mod alga_dual_quaternion; +mod alga_isometry; +mod alga_matrix; +mod alga_point; +mod alga_quaternion; +mod alga_rotation; +mod alga_similarity; +mod alga_transform; +mod alga_translation; +mod alga_unit_complex; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_isometry.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_isometry.rs new file mode 100644 index 000000000..56fae8715 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_isometry.rs @@ -0,0 +1,145 @@ +use super::glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; +use crate::{Isometry2, Isometry3, Matrix3, Matrix4, Translation3, UnitQuaternion}; +use std::convert::TryFrom; + +impl From> for Mat3 { + fn from(iso: Isometry2) -> Mat3 { + iso.to_homogeneous().into() + } +} +impl From> for Mat4 { + fn from(iso: Isometry3) -> Mat4 { + iso.to_homogeneous().into() + } +} + +impl From> for DMat3 { + fn from(iso: Isometry2) -> DMat3 { + iso.to_homogeneous().into() + } +} +impl From> for DMat4 { + fn from(iso: Isometry3) -> DMat4 { + iso.to_homogeneous().into() + } +} + +impl From> for (Vec3, Quat) { + fn from(iso: Isometry3) -> (Vec3, Quat) { + (iso.translation.into(), iso.rotation.into()) + } +} + +impl From> for (DVec3, DQuat) { + fn from(iso: Isometry3) -> (DVec3, DQuat) { + (iso.translation.into(), iso.rotation.into()) + } +} + +impl From> for (Vec2, f32) { + fn from(iso: Isometry2) -> (Vec2, f32) { + let tra = Vec2::new(iso.translation.x, iso.translation.y); + let rot = iso.rotation.angle(); + (tra, rot) + } +} + +impl From> for (DVec2, f64) { + fn from(iso: Isometry2) -> (DVec2, f64) { + let tra = DVec2::new(iso.translation.x, iso.translation.y); + let rot = iso.rotation.angle(); + (tra, rot) + } +} + +impl From<(Vec3, Quat)> for Isometry3 { + fn from((tra, rot): (Vec3, Quat)) -> Self { + Isometry3::from_parts(tra.into(), rot.into()) + } +} + +impl From<(DVec3, DQuat)> for Isometry3 { + fn from((tra, rot): (DVec3, DQuat)) -> Self { + Isometry3::from_parts(tra.into(), rot.into()) + } +} + +impl From<(Vec2, f32)> for Isometry2 { + fn from((tra, rot): (Vec2, f32)) -> Self { + Isometry2::new(tra.into(), rot) + } +} + +impl From<(DVec2, f64)> for Isometry2 { + fn from((tra, rot): (DVec2, f64)) -> Self { + Isometry2::new(tra.into(), rot) + } +} + +impl From for Isometry3 { + fn from(rot: Quat) -> Self { + Isometry3::from_parts(Translation3::identity(), rot.into()) + } +} + +impl From for Isometry3 { + fn from(rot: DQuat) -> Self { + Isometry3::from_parts(Translation3::identity(), rot.into()) + } +} + +impl From for Isometry3 { + fn from(tra: Vec3) -> Self { + Isometry3::from_parts(tra.into(), UnitQuaternion::identity()) + } +} + +impl From for Isometry3 { + fn from(tra: DVec3) -> Self { + Isometry3::from_parts(tra.into(), UnitQuaternion::identity()) + } +} + +impl From for Isometry2 { + fn from(tra: Vec2) -> Self { + Isometry2::new(tra.into(), 0.0) + } +} + +impl From for Isometry2 { + fn from(tra: DVec2) -> Self { + Isometry2::new(tra.into(), 0.0) + } +} + +impl TryFrom for Isometry2 { + type Error = (); + + fn try_from(mat3: Mat3) -> Result, Self::Error> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Isometry3 { + type Error = (); + + fn try_from(mat4: Mat4) -> Result, Self::Error> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) + } +} + +impl TryFrom for Isometry2 { + type Error = (); + + fn try_from(mat3: DMat3) -> Result, Self::Error> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Isometry3 { + type Error = (); + + fn try_from(mat4: DMat4) -> Result, Self::Error> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_matrix.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_matrix.rs new file mode 100644 index 000000000..11d33ec6e --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_matrix.rs @@ -0,0 +1,286 @@ +use super::glam::{ + BVec2, BVec3, BVec4, DMat2, DMat3, DMat4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, Mat2, Mat3, + Mat4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4, +}; +use crate::storage::RawStorage; +use crate::{ + Matrix, Matrix2, Matrix3, Matrix4, Unit, UnitVector2, UnitVector3, UnitVector4, Vector, + Vector2, Vector3, Vector4, U2, U3, U4, +}; +use std::convert::TryFrom; + +macro_rules! impl_vec_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl From<$Vec2> for Vector2<$N> { + #[inline] + fn from(e: $Vec2) -> Vector2<$N> { + <[$N;2]>::from(e).into() + } + } + + impl From> for $Vec2 + where + S: RawStorage<$N, U2>, + { + #[inline] + fn from(e: Vector<$N, U2, S>) -> $Vec2 { + <$Vec2>::new(e[0], e[1]) + } + } + + impl From<$Vec3> for Vector3<$N> { + #[inline] + fn from(e: $Vec3) -> Vector3<$N> { + <[$N;3]>::from(e).into() + } + } + + impl From> for $Vec3 + where + S: RawStorage<$N, U3>, + { + #[inline] + fn from(e: Vector<$N, U3, S>) -> $Vec3 { + <$Vec3>::new(e[0], e[1], e[2]) + } + } + + impl From<$Vec4> for Vector4<$N> { + #[inline] + fn from(e: $Vec4) -> Vector4<$N> { + <[$N;4]>::from(e).into() + } + } + + impl From> for $Vec4 + where + S: RawStorage<$N, U4>, + { + #[inline] + fn from(e: Vector<$N, U4, S>) -> $Vec4 { + <$Vec4>::new(e[0], e[1], e[2], e[3]) + } + } + } +); + +impl_vec_conversion!(f32, Vec2, Vec3, Vec4); +impl_vec_conversion!(f64, DVec2, DVec3, DVec4); +impl_vec_conversion!(i32, IVec2, IVec3, IVec4); +impl_vec_conversion!(u32, UVec2, UVec3, UVec4); +impl_vec_conversion!(bool, BVec2, BVec3, BVec4); + +const ERR: &'static str = "Normalization failed."; + +macro_rules! impl_unit_vec_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl TryFrom<$Vec2> for UnitVector2<$N> { + type Error = &'static str; + #[inline] + fn try_from(e: $Vec2) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } + } + + impl From> for $Vec2 + { + #[inline] + fn from(e: UnitVector2<$N>) -> $Vec2 { + e.into_inner().into() + } + } + + impl TryFrom<$Vec3> for UnitVector3<$N> { + type Error = &'static str; + #[inline] + fn try_from(e: $Vec3) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } + } + + impl From> for $Vec3 + { + #[inline] + fn from(e: UnitVector3<$N>) -> $Vec3 { + e.into_inner().into() + } + } + + impl TryFrom<$Vec4> for UnitVector4<$N> { + type Error = &'static str; + #[inline] + fn try_from(e: $Vec4) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } + } + + impl From> for $Vec4 + { + #[inline] + fn from(e: UnitVector4<$N>) -> $Vec4 { + e.into_inner().into() + } + } + } +); + +impl_unit_vec_conversion!(f32, Vec2, Vec3, Vec4); +impl_unit_vec_conversion!(f64, DVec2, DVec3, DVec4); + +impl From for Vector3 { + #[inline] + fn from(e: Vec3A) -> Vector3 { + (*e.as_ref()).into() + } +} + +impl From> for Vec3A +where + S: RawStorage, +{ + #[inline] + fn from(e: Vector) -> Vec3A { + Vec3A::new(e[0], e[1], e[2]) + } +} + +impl TryFrom for UnitVector3 { + type Error = &'static str; + #[inline] + fn try_from(e: Vec3A) -> Result { + Unit::try_new(e.into(), 0.0).ok_or(ERR) + } +} + +impl From> for Vec3A { + #[inline] + fn from(e: UnitVector3) -> Vec3A { + e.into_inner().into() + } +} + +impl From for Matrix2 { + #[inline] + fn from(e: Mat2) -> Matrix2 { + e.to_cols_array_2d().into() + } +} + +impl From> for Mat2 +where + S: RawStorage, +{ + #[inline] + fn from(e: Matrix) -> Mat2 { + Mat2::from_cols( + Vec2::new(e[(0, 0)], e[(1, 0)]), + Vec2::new(e[(0, 1)], e[(1, 1)]), + ) + } +} + +impl From for Matrix3 { + #[inline] + fn from(e: Mat3) -> Matrix3 { + e.to_cols_array_2d().into() + } +} + +impl From> for Mat3 +where + S: RawStorage, +{ + #[inline] + fn from(e: Matrix) -> Mat3 { + Mat3::from_cols( + Vec3::new(e[(0, 0)], e[(1, 0)], e[(2, 0)]), + Vec3::new(e[(0, 1)], e[(1, 1)], e[(2, 1)]), + Vec3::new(e[(0, 2)], e[(1, 2)], e[(2, 2)]), + ) + } +} + +impl From for Matrix4 { + #[inline] + fn from(e: Mat4) -> Matrix4 { + e.to_cols_array_2d().into() + } +} + +impl From> for Mat4 +where + S: RawStorage, +{ + #[inline] + fn from(e: Matrix) -> Mat4 { + Mat4::from_cols( + Vec4::new(e[(0, 0)], e[(1, 0)], e[(2, 0)], e[(3, 0)]), + Vec4::new(e[(0, 1)], e[(1, 1)], e[(2, 1)], e[(3, 1)]), + Vec4::new(e[(0, 2)], e[(1, 2)], e[(2, 2)], e[(3, 2)]), + Vec4::new(e[(0, 3)], e[(1, 3)], e[(2, 3)], e[(3, 3)]), + ) + } +} + +impl From for Matrix2 { + #[inline] + fn from(e: DMat2) -> Matrix2 { + e.to_cols_array_2d().into() + } +} + +impl From> for DMat2 +where + S: RawStorage, +{ + #[inline] + fn from(e: Matrix) -> DMat2 { + DMat2::from_cols( + DVec2::new(e[(0, 0)], e[(1, 0)]), + DVec2::new(e[(0, 1)], e[(1, 1)]), + ) + } +} + +impl From for Matrix3 { + #[inline] + fn from(e: DMat3) -> Matrix3 { + e.to_cols_array_2d().into() + } +} + +impl From> for DMat3 +where + S: RawStorage, +{ + #[inline] + fn from(e: Matrix) -> DMat3 { + DMat3::from_cols( + DVec3::new(e[(0, 0)], e[(1, 0)], e[(2, 0)]), + DVec3::new(e[(0, 1)], e[(1, 1)], e[(2, 1)]), + DVec3::new(e[(0, 2)], e[(1, 2)], e[(2, 2)]), + ) + } +} + +impl From for Matrix4 { + #[inline] + fn from(e: DMat4) -> Matrix4 { + e.to_cols_array_2d().into() + } +} + +impl From> for DMat4 +where + S: RawStorage, +{ + #[inline] + fn from(e: Matrix) -> DMat4 { + DMat4::from_cols( + DVec4::new(e[(0, 0)], e[(1, 0)], e[(2, 0)], e[(3, 0)]), + DVec4::new(e[(0, 1)], e[(1, 1)], e[(2, 1)], e[(3, 1)]), + DVec4::new(e[(0, 2)], e[(1, 2)], e[(2, 2)], e[(3, 2)]), + DVec4::new(e[(0, 3)], e[(1, 3)], e[(2, 3)], e[(3, 3)]), + ) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_point.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_point.rs new file mode 100644 index 000000000..ac1c099bf --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_point.rs @@ -0,0 +1,71 @@ +use super::glam::{ + BVec2, BVec3, BVec4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, Vec2, Vec3, + Vec3A, Vec4, +}; +use crate::{Point2, Point3, Point4}; + +macro_rules! impl_point_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl From<$Vec2> for Point2<$N> { + #[inline] + fn from(e: $Vec2) -> Point2<$N> { + <[$N;2]>::from(e).into() + } + } + + impl From> for $Vec2 { + #[inline] + fn from(e: Point2<$N>) -> $Vec2 { + <$Vec2>::new(e[0], e[1]) + } + } + + impl From<$Vec3> for Point3<$N> { + #[inline] + fn from(e: $Vec3) -> Point3<$N> { + <[$N;3]>::from(e).into() + } + } + + impl From> for $Vec3 { + #[inline] + fn from(e: Point3<$N>) -> $Vec3 { + <$Vec3>::new(e[0], e[1], e[2]) + } + } + + impl From<$Vec4> for Point4<$N> { + #[inline] + fn from(e: $Vec4) -> Point4<$N> { + <[$N;4]>::from(e).into() + } + } + + impl From> for $Vec4 { + #[inline] + fn from(e: Point4<$N>) -> $Vec4 { + <$Vec4>::new(e[0], e[1], e[2], e[3]) + } + } + } +); + +impl_point_conversion!(f32, Vec2, Vec3, Vec4); +impl_point_conversion!(f64, DVec2, DVec3, DVec4); +impl_point_conversion!(i32, IVec2, IVec3, IVec4); +impl_point_conversion!(u32, UVec2, UVec3, UVec4); +impl_point_conversion!(bool, BVec2, BVec3, BVec4); + +impl From for Point3 { + #[inline] + fn from(e: Vec3A) -> Point3 { + (*e.as_ref()).into() + } +} + +impl From> for Vec3A { + #[inline] + fn from(e: Point3) -> Vec3A { + Vec3A::new(e[0], e[1], e[2]) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_quaternion.rs new file mode 100644 index 000000000..99cb3953c --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_quaternion.rs @@ -0,0 +1,58 @@ +use super::glam::{DQuat, Quat}; +use crate::{Quaternion, UnitQuaternion}; + +impl From for Quaternion { + #[inline] + fn from(e: Quat) -> Quaternion { + Quaternion::new(e.w, e.x, e.y, e.z) + } +} + +impl From> for Quat { + #[inline] + fn from(e: Quaternion) -> Quat { + Quat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From> for Quat { + #[inline] + fn from(e: UnitQuaternion) -> Quat { + Quat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From for Quaternion { + #[inline] + fn from(e: DQuat) -> Quaternion { + Quaternion::new(e.w, e.x, e.y, e.z) + } +} + +impl From> for DQuat { + #[inline] + fn from(e: Quaternion) -> DQuat { + DQuat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From> for DQuat { + #[inline] + fn from(e: UnitQuaternion) -> DQuat { + DQuat::from_xyzw(e.i, e.j, e.k, e.w) + } +} + +impl From for UnitQuaternion { + #[inline] + fn from(e: Quat) -> UnitQuaternion { + UnitQuaternion::new_normalize(Quaternion::from(e)) + } +} + +impl From for UnitQuaternion { + #[inline] + fn from(e: DQuat) -> UnitQuaternion { + UnitQuaternion::new_normalize(Quaternion::from(e)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_rotation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_rotation.rs new file mode 100644 index 000000000..ec1bfe472 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_rotation.rs @@ -0,0 +1,58 @@ +use super::glam::{DMat2, DQuat, Mat2, Quat}; +use crate::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; + +impl From> for Mat2 { + #[inline] + fn from(e: Rotation2) -> Mat2 { + e.into_inner().into() + } +} + +impl From> for DMat2 { + #[inline] + fn from(e: Rotation2) -> DMat2 { + e.into_inner().into() + } +} + +impl From> for Quat { + #[inline] + fn from(e: Rotation3) -> Quat { + UnitQuaternion::from(e).into() + } +} + +impl From> for DQuat { + #[inline] + fn from(e: Rotation3) -> DQuat { + UnitQuaternion::from(e).into() + } +} + +impl From for Rotation2 { + #[inline] + fn from(e: Mat2) -> Rotation2 { + UnitComplex::from(e).to_rotation_matrix() + } +} + +impl From for Rotation2 { + #[inline] + fn from(e: DMat2) -> Rotation2 { + UnitComplex::from(e).to_rotation_matrix() + } +} + +impl From for Rotation3 { + #[inline] + fn from(e: Quat) -> Rotation3 { + Rotation3::from(UnitQuaternion::from(e)) + } +} + +impl From for Rotation3 { + #[inline] + fn from(e: DQuat) -> Rotation3 { + Rotation3::from(UnitQuaternion::from(e)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_similarity.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_similarity.rs new file mode 100644 index 000000000..b28a4453b --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_similarity.rs @@ -0,0 +1,53 @@ +use super::glam::{DMat3, DMat4, Mat3, Mat4}; +use crate::{Matrix3, Matrix4, Similarity2, Similarity3}; +use std::convert::TryFrom; + +impl From> for Mat3 { + fn from(iso: Similarity2) -> Mat3 { + iso.to_homogeneous().into() + } +} +impl From> for Mat4 { + fn from(iso: Similarity3) -> Mat4 { + iso.to_homogeneous().into() + } +} + +impl From> for DMat3 { + fn from(iso: Similarity2) -> DMat3 { + iso.to_homogeneous().into() + } +} +impl From> for DMat4 { + fn from(iso: Similarity3) -> DMat4 { + iso.to_homogeneous().into() + } +} + +impl TryFrom for Similarity2 { + type Error = (); + fn try_from(mat3: Mat3) -> Result, ()> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Similarity3 { + type Error = (); + fn try_from(mat4: Mat4) -> Result, ()> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) + } +} + +impl TryFrom for Similarity2 { + type Error = (); + fn try_from(mat3: DMat3) -> Result, ()> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Similarity3 { + type Error = (); + fn try_from(mat4: DMat4) -> Result, ()> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_translation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_translation.rs new file mode 100644 index 000000000..deacb033f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_translation.rs @@ -0,0 +1,65 @@ +use super::glam::{DVec2, DVec3, DVec4, Vec2, Vec3, Vec3A, Vec4}; +use crate::{Translation2, Translation3, Translation4}; + +macro_rules! impl_translation_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl From<$Vec2> for Translation2<$N> { + #[inline] + fn from(e: $Vec2) -> Translation2<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec2 { + #[inline] + fn from(e: Translation2<$N>) -> $Vec2 { + e.vector.into() + } + } + + impl From<$Vec3> for Translation3<$N> { + #[inline] + fn from(e: $Vec3) -> Translation3<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec3 { + #[inline] + fn from(e: Translation3<$N>) -> $Vec3 { + e.vector.into() + } + } + + impl From<$Vec4> for Translation4<$N> { + #[inline] + fn from(e: $Vec4) -> Translation4<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec4 { + #[inline] + fn from(e: Translation4<$N>) -> $Vec4 { + e.vector.into() + } + } + } +); + +impl_translation_conversion!(f32, Vec2, Vec3, Vec4); +impl_translation_conversion!(f64, DVec2, DVec3, DVec4); + +impl From for Translation3 { + #[inline] + fn from(e: Vec3A) -> Translation3 { + (*e.as_ref()).into() + } +} + +impl From> for Vec3A { + #[inline] + fn from(e: Translation3) -> Vec3A { + e.vector.into() + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_unit_complex.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_unit_complex.rs new file mode 100644 index 000000000..675bba881 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/common/glam_unit_complex.rs @@ -0,0 +1,30 @@ +use super::glam::{DMat2, Mat2}; +use crate::{Complex, UnitComplex}; + +impl From> for Mat2 { + #[inline] + fn from(e: UnitComplex) -> Mat2 { + e.to_rotation_matrix().into_inner().into() + } +} + +impl From> for DMat2 { + #[inline] + fn from(e: UnitComplex) -> DMat2 { + e.to_rotation_matrix().into_inner().into() + } +} + +impl From for UnitComplex { + #[inline] + fn from(e: Mat2) -> UnitComplex { + UnitComplex::new_normalize(Complex::new(e.x_axis.x, e.x_axis.y)) + } +} + +impl From for UnitComplex { + #[inline] + fn from(e: DMat2) -> UnitComplex { + UnitComplex::new_normalize(Complex::new(e.x_axis.x, e.x_axis.y)) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/mod.rs new file mode 100644 index 000000000..65585f34a --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/mod.rs @@ -0,0 +1,28 @@ +#[cfg(feature = "glam014")] +mod v014; +#[cfg(feature = "glam015")] +mod v015; +#[cfg(feature = "glam016")] +mod v016; +#[cfg(feature = "glam017")] +mod v017; +#[cfg(feature = "glam018")] +mod v018; +#[cfg(feature = "glam019")] +mod v019; +#[cfg(feature = "glam020")] +mod v020; +#[cfg(feature = "glam021")] +mod v021; +#[cfg(feature = "glam022")] +mod v022; +#[cfg(feature = "glam023")] +mod v023; +#[cfg(feature = "glam024")] +mod v024; +#[cfg(feature = "glam025")] +mod v025; +#[cfg(feature = "glam027")] +mod v027; +#[cfg(feature = "glam028")] +mod v028; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v014/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v014/mod.rs new file mode 100644 index 000000000..3eb37d172 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v014/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam014 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v015/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v015/mod.rs new file mode 100644 index 000000000..946268dbc --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v015/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam015 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v016/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v016/mod.rs new file mode 100644 index 000000000..e02517403 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v016/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam016 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v017/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v017/mod.rs new file mode 100644 index 000000000..05cbb2690 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v017/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam017 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v018/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v018/mod.rs new file mode 100644 index 000000000..7e4e62df7 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v018/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam018 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v019/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v019/mod.rs new file mode 100644 index 000000000..d2770e06f --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v019/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam019 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v020/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v020/mod.rs new file mode 100644 index 000000000..b4e884140 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v020/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam020 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v021/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v021/mod.rs new file mode 100644 index 000000000..7d24f3039 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v021/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam021 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v022/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v022/mod.rs new file mode 100644 index 000000000..a0af473db --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v022/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam022 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v023/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v023/mod.rs new file mode 100644 index 000000000..f769749d2 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v023/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam023 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v024/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v024/mod.rs new file mode 100644 index 000000000..c1f792ae3 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v024/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam024 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v025/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v025/mod.rs new file mode 100644 index 000000000..e0a13eef1 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v025/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam025 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v027/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v027/mod.rs new file mode 100644 index 000000000..2889af97c --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v027/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam027 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v028/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v028/mod.rs new file mode 100644 index 000000000..fdba49b55 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/glam/v028/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam028 as glam; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_matrix.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_matrix.rs new file mode 100644 index 000000000..f28366f06 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_matrix.rs @@ -0,0 +1,131 @@ +use std::convert::{AsMut, AsRef, From, Into}; +use std::mem::{self, MaybeUninit}; +use std::ptr; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{Const, DimName, U1, U2, U3, U4}; +use crate::base::storage::{IsContiguous, RawStorage, RawStorageMut}; +use crate::base::{DefaultAllocator, Matrix, OMatrix, Scalar}; + +macro_rules! impl_from_into_mint_1D( + ($($NRows: ident => $VT:ident [$SZ: expr]);* $(;)*) => {$( + impl From> for OMatrix + where T: Scalar, + DefaultAllocator: Allocator<$NRows, U1> { + #[inline] + fn from(v: mint::$VT) -> Self { + unsafe { + let mut res = Matrix::uninit(<$NRows>::name(), Const::<1>); + // Copy the data. + ptr::copy_nonoverlapping(&v.x, res.data.ptr_mut() as *mut T, $SZ); + // Prevent from being dropped the originals we just copied. + mem::forget(v); + // The result is now fully initialized. + res.assume_init() + } + } + } + + impl Into> for Matrix + where T: Scalar, + S: RawStorage + IsContiguous { + #[inline] + fn into(self) -> mint::$VT { + // SAFETY: this is OK thanks to the IsContiguous bound. + unsafe { + let mut res: MaybeUninit> = MaybeUninit::uninit(); + // Copy the data. + ptr::copy_nonoverlapping(self.data.ptr(), res.as_mut_ptr() as *mut T, $SZ); + // Prevent from being dropped the originals we just copied. + mem::forget(self); + // The result is now fully initialized. + res.assume_init() + } + } + } + + impl AsRef> for Matrix + where T: Scalar, + S: RawStorage + IsContiguous { + #[inline] + fn as_ref(&self) -> &mint::$VT { + // SAFETY: this is OK thanks to the IsContiguous bound. + unsafe { + mem::transmute(self.data.ptr()) + } + } + } + + impl AsMut> for Matrix + where T: Scalar, + S: RawStorageMut + IsContiguous { + #[inline] + fn as_mut(&mut self) -> &mut mint::$VT { + // SAFETY: this is OK thanks to the IsContiguous bound. + unsafe { + mem::transmute(self.data.ptr_mut()) + } + } + } + )*} +); + +// Implement for vectors of dimension 2 .. 4. +impl_from_into_mint_1D!( + U2 => Vector2[2]; + U3 => Vector3[3]; + U4 => Vector4[4]; +); + +macro_rules! impl_from_into_mint_2D( + ($(($NRows: ty, $NCols: ty) => $MV:ident{ $($component:ident),* }[$SZRows: expr]);* $(;)*) => {$( + impl From> for OMatrix + where T: Scalar, + DefaultAllocator: Allocator<$NRows, $NCols> { + #[inline] + fn from(m: mint::$MV) -> Self { + unsafe { + let mut res = Matrix::uninit(<$NRows>::name(), <$NCols>::name()); + let mut ptr = res.data.ptr_mut(); + $( + ptr::copy_nonoverlapping(&m.$component.x, ptr as *mut T, $SZRows); + ptr = ptr.offset($SZRows); + )* + let _ = ptr; // Just to avoid some unused assignment warnings. + // Forget the original data to avoid double-free. + mem::forget(m); + res.assume_init() + } + } + } + + impl Into> for OMatrix + where T: Scalar, + DefaultAllocator: Allocator<$NRows, $NCols> { + #[inline] + fn into(self) -> mint::$MV { + unsafe { + let mut res: MaybeUninit> = MaybeUninit::uninit(); + let mut ptr = self.data.ptr(); + $( + ptr::copy_nonoverlapping(ptr, ptr::addr_of_mut!((*res.as_mut_ptr()).$component) as *mut T, $SZRows); + ptr = ptr.offset($SZRows); + )* + let _ = ptr; + // Forget the original data to avoid double-free. + mem::forget(self); + res.assume_init() + } + } + } + )*} +); + +// Implement for matrices with shape 2x2 .. 4x4. +impl_from_into_mint_2D!( + (U2, U2) => ColumnMatrix2{x, y}[2]; + (U2, U3) => ColumnMatrix2x3{x, y, z}[2]; + (U3, U3) => ColumnMatrix3{x, y, z}[3]; + (U3, U4) => ColumnMatrix3x4{x, y, z, w}[3]; + (U4, U4) => ColumnMatrix4{x, y, z, w}[4]; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_point.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_point.rs new file mode 100644 index 000000000..1d54fb149 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_point.rs @@ -0,0 +1,52 @@ +use crate::base::storage::{RawStorage, RawStorageMut}; +use crate::{OVector, Point, Scalar}; +use std::convert::{AsMut, AsRef}; + +macro_rules! impl_from_into_mint_1D( + ($($NRows: expr => $PT:ident, $VT:ident [$SZ: expr]);* $(;)*) => {$( + impl From> for Point + where T: Scalar { + #[inline] + fn from(p: mint::$PT) -> Self { + Self { + coords: OVector::from(mint::$VT::from(p)), + } + } + } + + impl Into> for Point + where T: Scalar { + #[inline] + fn into(self) -> mint::$PT { + let mint_vec: mint::$VT = self.coords.into(); + mint::$PT::from(mint_vec) + } + } + + impl AsRef> for Point + where T: Scalar { + #[inline] + fn as_ref(&self) -> &mint::$PT { + unsafe { + &*(self.coords.data.ptr() as *const mint::$PT) + } + } + } + + impl AsMut> for Point + where T: Scalar { + #[inline] + fn as_mut(&mut self) -> &mut mint::$PT { + unsafe { + &mut *(self.coords.data.ptr_mut() as *mut mint::$PT) + } + } + } + )*} +); + +// Implement for points of dimension 2, 3. +impl_from_into_mint_1D!( + 2 => Point2, Vector2[2]; + 3 => Point3, Vector3[3]; +); diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_quaternion.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_quaternion.rs new file mode 100644 index 000000000..dc02c4cb8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_quaternion.rs @@ -0,0 +1,33 @@ +use crate::{Quaternion, Scalar, SimdValue, UnitQuaternion}; + +impl From> for Quaternion { + fn from(q: mint::Quaternion) -> Self { + Self::new(q.s, q.v.x, q.v.y, q.v.z) + } +} + +impl Into> for Quaternion { + fn into(self) -> mint::Quaternion { + mint::Quaternion { + v: mint::Vector3 { + x: self[0].clone(), + y: self[1].clone(), + z: self[2].clone(), + }, + s: self[3].clone(), + } + } +} + +impl Into> for UnitQuaternion { + fn into(self) -> mint::Quaternion { + mint::Quaternion { + v: mint::Vector3 { + x: self[0].clone(), + y: self[1].clone(), + z: self[2].clone(), + }, + s: self[3].clone(), + } + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_rotation.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_rotation.rs new file mode 100644 index 000000000..db8f8de09 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mint_rotation.rs @@ -0,0 +1,7 @@ +use crate::{RealField, Rotation3}; + +impl From> for Rotation3 { + fn from(euler: mint::EulerAngles) -> Self { + Self::from_euler_angles(euler.a, euler.b, euler.c) + } +} diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mod.rs new file mode 100644 index 000000000..215829b79 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mint/mod.rs @@ -0,0 +1,4 @@ +mod mint_matrix; +mod mint_point; +mod mint_quaternion; +mod mint_rotation; diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mod.rs b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mod.rs new file mode 100644 index 000000000..b985688ea --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/src/third_party/mod.rs @@ -0,0 +1,5 @@ +#[cfg(feature = "alga")] +mod alga; +mod glam; +#[cfg(feature = "mint")] +mod mint; From cf0d79a4dc0943fee31dd30919000e1554218a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 13 Sep 2024 16:44:04 +0000 Subject: [PATCH 2/2] set up nalgebra benchmark clean build times - cargo check: 10.2s - cargo build: 10.9s - cargo build --release: 13.6s leaf crate build times: - check full: 4.9s - debug full: 5.4s - opt full: 7.6s --- collector/compile-benchmarks/README.md | 2 + collector/compile-benchmarks/REUSE.toml | 5 + .../nalgebra-0.33.0/.gitignore | 1 - .../nalgebra-0.33.0/0-println.patch | 12 + .../nalgebra-0.33.0/Cargo.lock | 1538 +++++++++++++++++ .../nalgebra-0.33.0/Cargo.toml | 2 + .../nalgebra-0.33.0/perf-config.json | 4 + 7 files changed, 1563 insertions(+), 1 deletion(-) create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/0-println.patch create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/Cargo.lock create mode 100644 collector/compile-benchmarks/nalgebra-0.33.0/perf-config.json diff --git a/collector/compile-benchmarks/README.md b/collector/compile-benchmarks/README.md index 28aca5c7d..21051db03 100644 --- a/collector/compile-benchmarks/README.md +++ b/collector/compile-benchmarks/README.md @@ -41,6 +41,8 @@ They mostly consist of real-world crates. - **libc-0.2.124**: An interface to `libc`. Contains many declarations of types, constants, and functions, but relatively little normal code. Stresses the parser. A very widely-used crate. +- **nalgebra-0.33.0**: A linear algebra library. It exercises the new trait solver + in different ways than the old solver. - **regex-1.5.5**: A regular expression parser. Used by many Rust programs. - **ripgrep-13.0.0**: A line-oriented search tool. A widely-used utility, and a binary crate. diff --git a/collector/compile-benchmarks/REUSE.toml b/collector/compile-benchmarks/REUSE.toml index 21193ac25..a1e1a312b 100644 --- a/collector/compile-benchmarks/REUSE.toml +++ b/collector/compile-benchmarks/REUSE.toml @@ -155,6 +155,11 @@ path = "match-stress/**" SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)" SPDX-License-Identifier = "MIT" +[[annotations]] +path = "nalgebra-0.33.0/**" +SPDX-FileCopyrightText = "Sébastien Crozet" +SPDX-License-Identifier = "Apache-2.0" + [[annotations]] path = "piston-image/**" SPDX-FileCopyrightText = "piston contributors" diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore b/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore index 6984ee171..87d187dfa 100644 --- a/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore +++ b/collector/compile-benchmarks/nalgebra-0.33.0/.gitignore @@ -4,7 +4,6 @@ doc lib TODO target/ -Cargo.lock *.orig *.swo site/ diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/0-println.patch b/collector/compile-benchmarks/nalgebra-0.33.0/0-println.patch new file mode 100644 index 000000000..1658a2f05 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/0-println.patch @@ -0,0 +1,12 @@ +diff --git a/src/base/matrix.rs b/src/base/matrix.rs +index 6f358a84..6c4eb739 100644 +--- a/src/base/matrix.rs ++++ b/src/base/matrix.rs +@@ -225,6 +225,7 @@ where + S: Default, + { + fn default() -> Self { ++ println!("testing"); + Matrix { + data: Default::default(), + _phantoms: PhantomData, diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.lock b/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.lock new file mode 100644 index 000000000..f08e8f641 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.lock @@ -0,0 +1,1538 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alga" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f823d037a7ec6ea2197046bafd4ae150e6bc36f9ca347404f46a46823fa84f2" +dependencies = [ + "approx 0.3.2", + "num-complex 0.2.4", + "num-traits", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-complex 0.4.6", + "num-traits", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_lex", + "indexmap 1.9.3", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cool_asserts" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee9f254e53f61e2688d3677fa2cbe4e9b950afd56f48819c98817417cf6b28ec" +dependencies = [ + "indent_write", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glam" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da" + +[[package]] +name = "glam" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb554f8ee44336b72d522e0a7fe86a29e09f839a36022fa869a7dfe941a54b" + +[[package]] +name = "glam" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4126c0479ccf7e8664c36a2d719f5f2c140fbb4f9090008098d2c291fa5b3f16" + +[[package]] +name = "glam" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01732b97afd8508eee3333a541b9f7610f454bb818669e66e90f5f57c93a776" + +[[package]] +name = "glam" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525a3e490ba77b8e326fb67d4b44b4bd2f920f44d4cc73ccec50adc68e3bee34" + +[[package]] +name = "glam" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8509e6791516e81c1a630d0bd7fbac36d2fa8712a9da8662e716b52d5051ca" + +[[package]] +name = "glam" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f" + +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + +[[package]] +name = "glam" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" + +[[package]] +name = "glam" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c" + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" + +[[package]] +name = "glam" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" + +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" + +[[package]] +name = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indent_write" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "matrixcompare" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37832ba820e47c93d66b4360198dccb004b43c74abc3ac1ce1fed54e65a80445" +dependencies = [ + "matrixcompare-core", + "num-traits", +] + +[[package]] +name = "matrixcompare-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0bdabb30db18805d5290b3da7ceaccbddba795620b86c02145d688e04900a73" + +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + +[[package]] +name = "nalgebra" +version = "0.33.0" +dependencies = [ + "alga", + "approx 0.5.1", + "bytemuck", + "cool_asserts", + "criterion", + "glam 0.14.0", + "glam 0.15.2", + "glam 0.16.0", + "glam 0.17.3", + "glam 0.18.0", + "glam 0.19.0", + "glam 0.20.5", + "glam 0.21.3", + "glam 0.22.0", + "glam 0.23.0", + "glam 0.24.2", + "glam 0.25.0", + "glam 0.27.0", + "glam 0.28.0", + "itertools 0.13.0", + "matrixcompare", + "matrixcompare-core", + "matrixmultiply", + "mint", + "nalgebra-macros", + "num-complex 0.4.6", + "num-rational", + "num-traits", + "pest", + "pest_derive", + "proptest", + "quickcheck", + "rand", + "rand_distr", + "rand_isaac", + "rand_xorshift", + "rayon", + "rkyv", + "serde", + "serde_json", + "simba", + "trybuild", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.5.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "unarray", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger", + "log", + "rand", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rand_isaac" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4373cd91b4f55722c553fb0f286edbb81ef3ff6eec7b99d1898a4110a0b28" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "safe_arch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "simba" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +dependencies = [ + "approx 0.5.1", + "libm", + "num-complex 0.4.6", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "trybuild" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a5f13f11071020bb12de7a16b925d2d58636175c20c11dc5f96cb64bb6c9b3" +dependencies = [ + "glob", + "serde", + "serde_derive", + "serde_json", + "termcolor", + "toml", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.67", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wide" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a040b111774ab63a19ef46bbc149398ab372b4ccdcfd719e9814dbd7dfd76c8" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml b/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml index 83548c341..79392a4da 100644 --- a/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml +++ b/collector/compile-benchmarks/nalgebra-0.33.0/Cargo.toml @@ -325,3 +325,5 @@ std = [ [badges.maintenance] status = "actively-developed" + +[workspace] diff --git a/collector/compile-benchmarks/nalgebra-0.33.0/perf-config.json b/collector/compile-benchmarks/nalgebra-0.33.0/perf-config.json new file mode 100644 index 000000000..710581fa8 --- /dev/null +++ b/collector/compile-benchmarks/nalgebra-0.33.0/perf-config.json @@ -0,0 +1,4 @@ +{ + "artifact": "library", + "category": "primary" +}