Merge pull request #837 from dimforge/proptest
Replace quickcheck by proptest
This commit is contained in:
commit
b97a3d0ab2
|
@ -1,128 +0,0 @@
|
||||||
version: 2.1
|
|
||||||
|
|
||||||
executors:
|
|
||||||
rust-nightly-executor:
|
|
||||||
docker:
|
|
||||||
- image: rustlang/rust:nightly
|
|
||||||
rust-executor:
|
|
||||||
docker:
|
|
||||||
- image: rust:latest
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-fmt:
|
|
||||||
executor: rust-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: install rustfmt
|
|
||||||
command: rustup component add rustfmt
|
|
||||||
- run:
|
|
||||||
name: check formatting
|
|
||||||
command: cargo fmt -- --check
|
|
||||||
clippy:
|
|
||||||
executor: rust-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: install clippy
|
|
||||||
command: rustup component add clippy
|
|
||||||
- run:
|
|
||||||
name: clippy
|
|
||||||
command: cargo clippy
|
|
||||||
build-native:
|
|
||||||
executor: rust-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: apt-get update
|
|
||||||
- run: apt-get install -y cmake gfortran libblas-dev liblapack-dev
|
|
||||||
- run:
|
|
||||||
name: build --no-default-feature
|
|
||||||
command: cargo build --no-default-features;
|
|
||||||
- run:
|
|
||||||
name: build (default features)
|
|
||||||
command: cargo build;
|
|
||||||
- run:
|
|
||||||
name: build --all-features
|
|
||||||
command: cargo build --all-features
|
|
||||||
- run:
|
|
||||||
name: build nalgebra-glm
|
|
||||||
command: cargo build -p nalgebra-glm --all-features
|
|
||||||
- run:
|
|
||||||
name: build nalgebra-lapack
|
|
||||||
command: cd nalgebra-lapack; cargo build
|
|
||||||
test-native:
|
|
||||||
executor: rust-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: test
|
|
||||||
command: cargo test --features arbitrary --features serde-serialize --features abomonation-serialize --features sparse --features debug --features io --features compare --features libm --features proptest-support --features slow-tests
|
|
||||||
- run:
|
|
||||||
name: test nalgebra-glm
|
|
||||||
command: cargo test -p nalgebra-glm --features arbitrary --features serde-serialize --features abomonation-serialize --features sparse --features debug --features io --features compare --features libm --features slow-tests
|
|
||||||
- run:
|
|
||||||
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
|
|
||||||
command: PROPTEST_CASES=10000 cargo test --manifest-path=nalgebra-sparse/Cargo.toml --features compare,proptest-support
|
|
||||||
- run:
|
|
||||||
name: test nalgebra-sparse (slow tests)
|
|
||||||
# Unfortunately, the "slow-tests" take so much time that we need to run them with --release
|
|
||||||
command: PROPTEST_CASES=10000 cargo test --release --manifest-path=nalgebra-sparse/Cargo.toml --features compare,proptest-support,slow-tests slow
|
|
||||||
build-wasm:
|
|
||||||
executor: rust-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: install cargo-web
|
|
||||||
command: cargo install -f cargo-web;
|
|
||||||
- run:
|
|
||||||
name: build --all-features
|
|
||||||
command: cargo web build --verbose --target wasm32-unknown-unknown;
|
|
||||||
- run:
|
|
||||||
name: build nalgebra-glm
|
|
||||||
command: cargo build -p nalgebra-glm --all-features
|
|
||||||
build-no-std:
|
|
||||||
executor: rust-nightly-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: install xargo
|
|
||||||
command: cp .circleci/Xargo.toml .; rustup component add rust-src; cargo install -f xargo;
|
|
||||||
- run:
|
|
||||||
name: build
|
|
||||||
command: xargo build --verbose --no-default-features --target=x86_64-unknown-linux-gnu;
|
|
||||||
- run:
|
|
||||||
name: build --features alloc
|
|
||||||
command: xargo build --verbose --no-default-features --features alloc --target=x86_64-unknown-linux-gnu;
|
|
||||||
build-nightly:
|
|
||||||
executor: rust-nightly-executor
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: build --all-features
|
|
||||||
command: cargo build --all-features
|
|
||||||
|
|
||||||
|
|
||||||
workflows:
|
|
||||||
version: 2
|
|
||||||
build:
|
|
||||||
jobs:
|
|
||||||
- check-fmt
|
|
||||||
- clippy
|
|
||||||
- build-native:
|
|
||||||
requires:
|
|
||||||
- check-fmt
|
|
||||||
- build-wasm:
|
|
||||||
requires:
|
|
||||||
- check-fmt
|
|
||||||
- build-no-std:
|
|
||||||
requires:
|
|
||||||
- check-fmt
|
|
||||||
- build-nightly:
|
|
||||||
requires:
|
|
||||||
- check-fmt
|
|
||||||
- test-native:
|
|
||||||
requires:
|
|
||||||
- build-native
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
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 --all-features
|
||||||
|
run: cargo build --all-features;
|
||||||
|
- name: Build nalgebra-glm
|
||||||
|
run: cargo build -p nalgebra-glm --all-features;
|
||||||
|
- name: Build nalgebra-lapack
|
||||||
|
run: cd nalgebra-lapack; cargo build;
|
||||||
|
- name: Build nalgebra-sparse
|
||||||
|
run: cd nalgebra-sparse; cargo build;
|
||||||
|
test-nalgebra:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# env:
|
||||||
|
# RUSTFLAGS: -D warnings
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: test
|
||||||
|
run: cargo test --features arbitrary --features serde-serialize,abomonation-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests;
|
||||||
|
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,abomonation-serialize,sparse,debug,io,compare,libm,proptest-support,slow-tests;
|
||||||
|
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
|
||||||
|
- 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,slow-tests slow
|
||||||
|
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
|
||||||
|
run: xargo build --verbose --no-default-features --target=x86_64-unknown-linux-gnu;
|
||||||
|
- name: build --feature alloc
|
||||||
|
run: xargo build --verbose --no-default-features --features alloc --target=x86_64-unknown-linux-gnu;
|
|
@ -10,3 +10,4 @@ Cargo.lock
|
||||||
site/
|
site/
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
|
proptest-regressions
|
22
Cargo.toml
22
Cargo.toml
|
@ -23,8 +23,7 @@ path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "std" ]
|
default = [ "std" ]
|
||||||
std = [ "matrixmultiply", "rand/std", "rand_distr", "simba/std" ]
|
std = [ "matrixmultiply", "rand/std", "rand/std_rng", "rand_distr", "simba/std" ]
|
||||||
stdweb = [ "rand/stdweb" ]
|
|
||||||
arbitrary = [ "quickcheck" ]
|
arbitrary = [ "quickcheck" ]
|
||||||
serde-serialize = [ "serde", "num-complex/serde" ]
|
serde-serialize = [ "serde", "num-complex/serde" ]
|
||||||
abomonation-serialize = [ "abomonation" ]
|
abomonation-serialize = [ "abomonation" ]
|
||||||
|
@ -44,29 +43,30 @@ slow-tests = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
typenum = "1.12"
|
typenum = "1.12"
|
||||||
generic-array = "0.14"
|
generic-array = "0.14"
|
||||||
rand = { version = "0.7", default-features = false }
|
rand = { version = "0.8", default-features = false }
|
||||||
|
getrandom = { version = "0.2", default-features = false, features = [ "js" ] } # For wasm
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
num-complex = { version = "0.3", default-features = false }
|
num-complex = { version = "0.3", default-features = false }
|
||||||
num-rational = { version = "0.3", default-features = false }
|
num-rational = { version = "0.3", default-features = false }
|
||||||
approx = { version = "0.4", default-features = false }
|
approx = { version = "0.4", default-features = false }
|
||||||
simba = { version = "0.3", default-features = false }
|
simba = { version = "0.4", default-features = false }
|
||||||
alga = { version = "0.9", default-features = false, optional = true }
|
alga = { version = "0.9", default-features = false, optional = true }
|
||||||
rand_distr = { version = "0.3", optional = true }
|
rand_distr = { version = "0.4", default-features = false, optional = true }
|
||||||
matrixmultiply = { version = "0.2", optional = true }
|
matrixmultiply = { version = "0.3", optional = true }
|
||||||
serde = { version = "1.0", default-features = false, features = [ "derive" ], optional = true }
|
serde = { version = "1.0", default-features = false, features = [ "derive" ], optional = true }
|
||||||
abomonation = { version = "0.7", optional = true }
|
abomonation = { version = "0.7", optional = true }
|
||||||
mint = { version = "0.5", optional = true }
|
mint = { version = "0.5", optional = true }
|
||||||
quickcheck = { version = "0.9", optional = true }
|
quickcheck = { version = "1", optional = true }
|
||||||
pest = { version = "2", optional = true }
|
pest = { version = "2", optional = true }
|
||||||
pest_derive = { version = "2", optional = true }
|
pest_derive = { version = "2", optional = true }
|
||||||
bytemuck = { version = "1.5", optional = true }
|
bytemuck = { version = "1.5", optional = true }
|
||||||
matrixcompare-core = { version = "0.1", optional = true }
|
matrixcompare-core = { version = "0.1", optional = true }
|
||||||
proptest = { version = "0.10", optional = true, default-features = false, features = ["std"] }
|
proptest = { version = "1", optional = true, default-features = false, features = ["std"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
rand_xorshift = "0.2"
|
rand_xorshift = "0.3"
|
||||||
rand_isaac = "0.2"
|
rand_isaac = "0.3"
|
||||||
### Uncomment this line before running benchmarks.
|
### Uncomment this line before running benchmarks.
|
||||||
### We can't just let this uncommented because that would break
|
### We can't just let this uncommented because that would break
|
||||||
### compilation for #[no-std] because of the terrible Cargo bug
|
### compilation for #[no-std] because of the terrible Cargo bug
|
||||||
|
@ -75,7 +75,7 @@ rand_isaac = "0.2"
|
||||||
|
|
||||||
# For matrix comparison macro
|
# For matrix comparison macro
|
||||||
matrixcompare = "0.2.0"
|
matrixcompare = "0.2.0"
|
||||||
itertools = "0.9"
|
itertools = "0.10"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [ "nalgebra-lapack", "nalgebra-glm", "nalgebra-sparse" ]
|
members = [ "nalgebra-lapack", "nalgebra-glm", "nalgebra-sparse" ]
|
||||||
|
|
|
@ -19,7 +19,6 @@ maintenance = { status = "actively-developed" }
|
||||||
[features]
|
[features]
|
||||||
default = [ "std" ]
|
default = [ "std" ]
|
||||||
std = [ "nalgebra/std", "simba/std" ]
|
std = [ "nalgebra/std", "simba/std" ]
|
||||||
stdweb = [ "nalgebra/stdweb" ]
|
|
||||||
arbitrary = [ "nalgebra/arbitrary" ]
|
arbitrary = [ "nalgebra/arbitrary" ]
|
||||||
serde-serialize = [ "nalgebra/serde-serialize" ]
|
serde-serialize = [ "nalgebra/serde-serialize" ]
|
||||||
abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
|
abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
|
||||||
|
@ -27,5 +26,5 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
approx = { version = "0.4", default-features = false }
|
approx = { version = "0.4", default-features = false }
|
||||||
simba = { version = "0.3", default-features = false }
|
simba = { version = "0.4", default-features = false }
|
||||||
nalgebra = { path = "..", version = "0.24", default-features = false }
|
nalgebra = { path = "..", version = "0.24", default-features = false }
|
||||||
|
|
|
@ -18,9 +18,11 @@ maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
serde-serialize = [ "serde", "serde_derive" ]
|
serde-serialize = [ "serde", "serde_derive" ]
|
||||||
|
proptest-support = [ "nalgebra/proptest-support" ]
|
||||||
|
arbitrary = [ "nalgebra/arbitrary" ]
|
||||||
|
|
||||||
# For BLAS/LAPACK
|
# For BLAS/LAPACK
|
||||||
default = ["openblas"]
|
default = ["netlib"]
|
||||||
openblas = ["lapack-src/openblas"]
|
openblas = ["lapack-src/openblas"]
|
||||||
netlib = ["lapack-src/netlib"]
|
netlib = ["lapack-src/netlib"]
|
||||||
accelerate = ["lapack-src/accelerate"]
|
accelerate = ["lapack-src/accelerate"]
|
||||||
|
@ -29,16 +31,17 @@ intel-mkl = ["lapack-src/intel-mkl"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version = "0.24", path = ".." }
|
nalgebra = { version = "0.24", path = ".." }
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-complex = { version = "0.2", default-features = false }
|
num-complex = { version = "0.3", default-features = false }
|
||||||
simba = "0.2"
|
simba = "0.4"
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
serde_derive = { version = "1.0", optional = true }
|
serde_derive = { version = "1.0", optional = true }
|
||||||
lapack = { version = "0.16", default-features = false }
|
lapack = { version = "0.17", default-features = false }
|
||||||
lapack-src = { version = "0.5", default-features = false }
|
lapack-src = { version = "0.6", default-features = false }
|
||||||
# clippy = "*"
|
# clippy = "*"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nalgebra = { version = "0.24", features = [ "arbitrary" ], path = ".." }
|
nalgebra = { version = "0.24", features = [ "arbitrary" ], path = ".." }
|
||||||
quickcheck = "0.9"
|
proptest = { version = "1", default-features = false, features = ["std"] }
|
||||||
approx = "0.3"
|
quickcheck = "1"
|
||||||
rand = "0.7"
|
approx = "0.4"
|
||||||
|
rand = "0.8"
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate approx;
|
extern crate approx;
|
||||||
|
#[cfg(not(feature = "proptest-support"))]
|
||||||
|
compile_error!("Tests must be run with `proptest-support`");
|
||||||
|
|
||||||
extern crate nalgebra as na;
|
extern crate nalgebra as na;
|
||||||
extern crate nalgebra_lapack as nl;
|
extern crate nalgebra_lapack as nl;
|
||||||
#[macro_use]
|
|
||||||
extern crate quickcheck;
|
extern crate lapack;
|
||||||
|
extern crate lapack_src;
|
||||||
|
|
||||||
mod linalg;
|
mod linalg;
|
||||||
|
#[path = "../../tests/proptest/mod.rs"]
|
||||||
|
mod proptest;
|
||||||
|
|
|
@ -1,37 +1,36 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use na::{DMatrix, DVector, Matrix3, Matrix4, Matrix4x3, Vector4};
|
use na::{DMatrix, DVector, Matrix4x3, Vector4};
|
||||||
use nl::Cholesky;
|
use nl::Cholesky;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn cholesky(m: DMatrix<f64>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
if m.len() != 0 {
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn cholesky(m in dmatrix()) {
|
||||||
let m = &m * m.transpose();
|
let m = &m * m.transpose();
|
||||||
if let Some(chol) = Cholesky::new(m.clone()) {
|
if let Some(chol) = Cholesky::new(m.clone()) {
|
||||||
let l = chol.unpack();
|
let l = chol.unpack();
|
||||||
let reconstructed_m = &l * l.transpose();
|
let reconstructed_m = &l * l.transpose();
|
||||||
|
|
||||||
return relative_eq!(reconstructed_m, m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(reconstructed_m, m, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cholesky_static(m: Matrix3<f64>) -> bool {
|
#[test]
|
||||||
|
fn cholesky_static(m in matrix3()) {
|
||||||
let m = &m * m.transpose();
|
let m = &m * m.transpose();
|
||||||
if let Some(chol) = Cholesky::new(m) {
|
if let Some(chol) = Cholesky::new(m) {
|
||||||
let l = chol.unpack();
|
let l = chol.unpack();
|
||||||
let reconstructed_m = &l * l.transpose();
|
let reconstructed_m = &l * l.transpose();
|
||||||
|
|
||||||
relative_eq!(reconstructed_m, m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(reconstructed_m, m, epsilon = 1.0e-7))
|
||||||
}
|
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
if n != 0 {
|
fn cholesky_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 15); // To avoid slowing down the test too much.
|
let n = cmp::min(n, 15); // To avoid slowing down the test too much.
|
||||||
let nb = cmp::min(nb, 15); // To avoid slowing down the test too much.
|
let nb = cmp::min(nb, 15); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
@ -44,33 +43,28 @@ quickcheck! {
|
||||||
let sol1 = chol.solve(&b1).unwrap();
|
let sol1 = chol.solve(&b1).unwrap();
|
||||||
let sol2 = chol.solve(&b2).unwrap();
|
let sol2 = chol.solve(&b2).unwrap();
|
||||||
|
|
||||||
return relative_eq!(&m * sol1, b1, epsilon = 1.0e-6) &&
|
prop_assert!(relative_eq!(&m * sol1, b1, epsilon = 1.0e-6));
|
||||||
relative_eq!(&m * sol2, b2, epsilon = 1.0e-6)
|
prop_assert!(relative_eq!(&m * sol2, b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn cholesky_solve_static(m in matrix4()) {
|
||||||
|
|
||||||
fn cholesky_solve_static(m: Matrix4<f64>) -> bool {
|
|
||||||
let m = &m * m.transpose();
|
let m = &m * m.transpose();
|
||||||
match Cholesky::new(m) {
|
if let Some(chol) = Cholesky::new(m) {
|
||||||
Some(chol) => {
|
|
||||||
let b1 = Vector4::new_random();
|
let b1 = Vector4::new_random();
|
||||||
let b2 = Matrix4x3::new_random();
|
let b2 = Matrix4x3::new_random();
|
||||||
|
|
||||||
let sol1 = chol.solve(&b1).unwrap();
|
let sol1 = chol.solve(&b1).unwrap();
|
||||||
let sol2 = chol.solve(&b2).unwrap();
|
let sol2 = chol.solve(&b2).unwrap();
|
||||||
|
|
||||||
relative_eq!(m * sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * sol2, b2, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-7));
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_inverse(n: usize) -> bool {
|
#[test]
|
||||||
if n != 0 {
|
fn cholesky_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 15); // To avoid slowing down the test too much.
|
let n = cmp::min(n, 15); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
let m = &m * m.transpose();
|
let m = &m * m.transpose();
|
||||||
|
@ -79,23 +73,18 @@ quickcheck! {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
return id1.is_identity(1.0e-6) && id2.is_identity(1.0e-6);
|
prop_assert!(id1.is_identity(1.0e-6) && id2.is_identity(1.0e-6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn cholesky_inverse_static(m in matrix4()) {
|
||||||
|
|
||||||
fn cholesky_inverse_static(m: Matrix4<f64>) -> bool {
|
|
||||||
let m = m * m.transpose();
|
let m = m * m.transpose();
|
||||||
match Cholesky::new(m.clone()).unwrap().inverse() {
|
if let Some(m1) = Cholesky::new(m.clone()).unwrap().inverse() {
|
||||||
Some(m1) => {
|
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5))
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,32 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use nl::Hessenberg;
|
|
||||||
use na::{DMatrix, Matrix4};
|
use na::{DMatrix, Matrix4};
|
||||||
|
use nl::Hessenberg;
|
||||||
|
|
||||||
quickcheck!{
|
use crate::proptest::*;
|
||||||
fn hessenberg(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
if n != 0 {
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn hessenberg(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 25);
|
let n = cmp::min(n, 25);
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
|
||||||
match Hessenberg::new(m.clone()) {
|
if let Some(hess) = Hessenberg::new(m.clone()) {
|
||||||
Some(hess) => {
|
|
||||||
let h = hess.h();
|
let h = hess.h();
|
||||||
let p = hess.p();
|
let p = hess.p();
|
||||||
|
|
||||||
relative_eq!(m, &p * h * p.transpose(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &p * h * p.transpose(), epsilon = 1.0e-7))
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hessenberg_static(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
match Hessenberg::new(m) {
|
fn hessenberg_static(m in matrix4()) {
|
||||||
Some(hess) => {
|
if let Some(hess) = Hessenberg::new(m) {
|
||||||
let h = hess.h();
|
let h = hess.h();
|
||||||
let p = hess.p();
|
let p = hess.p();
|
||||||
|
|
||||||
relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, p * h * p.transpose(), epsilon = 1.0e-7))
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use na::{DMatrix, DVector, Matrix3x4, Matrix4, Matrix4x3, Vector4};
|
use na::{DMatrix, DVector, Matrix4x3, Vector4};
|
||||||
use nl::LU;
|
use nl::LU;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn lup(m: DMatrix<f64>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
if m.len() != 0 {
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn lup(m in dmatrix()) {
|
||||||
let lup = LU::new(m.clone());
|
let lup = LU::new(m.clone());
|
||||||
let l = lup.l();
|
let l = lup.l();
|
||||||
let u = lup.u();
|
let u = lup.u();
|
||||||
|
@ -14,15 +17,12 @@ quickcheck! {
|
||||||
|
|
||||||
let computed2 = lup.p() * l * u;
|
let computed2 = lup.p() * l * u;
|
||||||
|
|
||||||
relative_eq!(computed1, m, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(computed1, m, epsilon = 1.0e-7));
|
||||||
relative_eq!(computed2, m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(computed2, m, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_static(m: Matrix3x4<f64>) -> bool {
|
#[test]
|
||||||
|
fn lu_static(m in matrix3x5()) {
|
||||||
let lup = LU::new(m);
|
let lup = LU::new(m);
|
||||||
let l = lup.l();
|
let l = lup.l();
|
||||||
let u = lup.u();
|
let u = lup.u();
|
||||||
|
@ -31,12 +31,12 @@ quickcheck! {
|
||||||
|
|
||||||
let computed2 = lup.p() * l * u;
|
let computed2 = lup.p() * l * u;
|
||||||
|
|
||||||
relative_eq!(computed1, m, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(computed1, m, epsilon = 1.0e-7));
|
||||||
relative_eq!(computed2, m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(computed2, m, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
if n != 0 {
|
fn lu_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 25); // To avoid slowing down the test too much.
|
let n = cmp::min(n, 25); // To avoid slowing down the test too much.
|
||||||
let nb = cmp::min(nb, 25); // To avoid slowing down the test too much.
|
let nb = cmp::min(nb, 25); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
@ -51,17 +51,14 @@ quickcheck! {
|
||||||
let tr_sol1 = lup.solve_transpose(&b1).unwrap();
|
let tr_sol1 = lup.solve_transpose(&b1).unwrap();
|
||||||
let tr_sol2 = lup.solve_transpose(&b2).unwrap();
|
let tr_sol2 = lup.solve_transpose(&b2).unwrap();
|
||||||
|
|
||||||
relative_eq!(&m * sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&m * sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(&m * sol2, b2, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&m * sol2, b2, epsilon = 1.0e-7));
|
||||||
relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_solve_static(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
|
fn lu_solve_static(m in matrix4()) {
|
||||||
let lup = LU::new(m);
|
let lup = LU::new(m);
|
||||||
let b1 = Vector4::new_random();
|
let b1 = Vector4::new_random();
|
||||||
let b2 = Matrix4x3::new_random();
|
let b2 = Matrix4x3::new_random();
|
||||||
|
@ -71,14 +68,14 @@ quickcheck! {
|
||||||
let tr_sol1 = lup.solve_transpose(&b1).unwrap();
|
let tr_sol1 = lup.solve_transpose(&b1).unwrap();
|
||||||
let tr_sol2 = lup.solve_transpose(&b2).unwrap();
|
let tr_sol2 = lup.solve_transpose(&b2).unwrap();
|
||||||
|
|
||||||
relative_eq!(m * sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * sol2, b2, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-7));
|
||||||
relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m.transpose() * tr_sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m.transpose() * tr_sol2, b2, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_inverse(n: usize) -> bool {
|
#[test]
|
||||||
if n != 0 {
|
fn lu_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 25); // To avoid slowing down the test too much.
|
let n = cmp::min(n, 25); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
|
||||||
|
@ -86,22 +83,17 @@ quickcheck! {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
return id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7);
|
prop_assert!(id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn lu_inverse_static(m in matrix4()) {
|
||||||
|
if let Some(m1) = LU::new(m.clone()).inverse() {
|
||||||
fn lu_inverse_static(m: Matrix4<f64>) -> bool {
|
|
||||||
match LU::new(m.clone()).inverse() {
|
|
||||||
Some(m1) => {
|
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5))
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
use na::{DMatrix, Matrix4x3};
|
|
||||||
use nl::QR;
|
use nl::QR;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn qr(m: DMatrix<f64>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn qr(m in dmatrix()) {
|
||||||
let qr = QR::new(m.clone());
|
let qr = QR::new(m.clone());
|
||||||
let q = qr.q();
|
let q = qr.q();
|
||||||
let r = qr.r();
|
let r = qr.r();
|
||||||
|
|
||||||
relative_eq!(m, q * r, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_static(m: Matrix4x3<f64>) -> bool {
|
#[test]
|
||||||
|
fn qr_static(m in matrix5x3()) {
|
||||||
let qr = QR::new(m);
|
let qr = QR::new(m);
|
||||||
let q = qr.q();
|
let q = qr.q();
|
||||||
let r = qr.r();
|
let r = qr.r();
|
||||||
|
|
||||||
relative_eq!(m, q * r, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,16 @@ use std::cmp;
|
||||||
use na::{DMatrix, Matrix4};
|
use na::{DMatrix, Matrix4};
|
||||||
use nl::Eigen;
|
use nl::Eigen;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn eigensystem(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
if n != 0 {
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn eigensystem(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 25);
|
let n = cmp::min(n, 25);
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
|
||||||
match Eigen::new(m.clone(), true, true) {
|
if let Some(eig) = Eigen::new(m.clone(), true, true) {
|
||||||
Some(eig) => {
|
|
||||||
let eigvals = DMatrix::from_diagonal(&eig.eigenvalues);
|
let eigvals = DMatrix::from_diagonal(&eig.eigenvalues);
|
||||||
let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap();
|
let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap();
|
||||||
let scaled_eigvectors = eig.eigenvectors.as_ref().unwrap() * &eigvals;
|
let scaled_eigvectors = eig.eigenvectors.as_ref().unwrap() * &eigvals;
|
||||||
|
@ -18,20 +20,14 @@ quickcheck! {
|
||||||
let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.as_ref().unwrap();
|
let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.as_ref().unwrap();
|
||||||
let scaled_left_eigvectors = eig.left_eigenvectors.as_ref().unwrap() * &eigvals;
|
let scaled_left_eigvectors = eig.left_eigenvectors.as_ref().unwrap() * &eigvals;
|
||||||
|
|
||||||
relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-7));
|
||||||
relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-7));
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eigensystem_static(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
match Eigen::new(m, true, true) {
|
fn eigensystem_static(m in matrix4()) {
|
||||||
Some(eig) => {
|
if let Some(eig) = Eigen::new(m, true, true) {
|
||||||
let eigvals = Matrix4::from_diagonal(&eig.eigenvalues);
|
let eigvals = Matrix4::from_diagonal(&eig.eigenvalues);
|
||||||
let transformed_eigvectors = m * eig.eigenvectors.unwrap();
|
let transformed_eigvectors = m * eig.eigenvectors.unwrap();
|
||||||
let scaled_eigvectors = eig.eigenvectors.unwrap() * eigvals;
|
let scaled_eigvectors = eig.eigenvectors.unwrap() * eigvals;
|
||||||
|
@ -39,10 +35,8 @@ quickcheck! {
|
||||||
let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.unwrap();
|
let transformed_left_eigvectors = m.transpose() * eig.left_eigenvectors.unwrap();
|
||||||
let scaled_left_eigvectors = eig.left_eigenvectors.unwrap() * eigvals;
|
let scaled_left_eigvectors = eig.left_eigenvectors.unwrap() * eigvals;
|
||||||
|
|
||||||
relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(transformed_eigvectors, scaled_eigvectors, epsilon = 1.0e-7));
|
||||||
relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(transformed_left_eigvectors, scaled_left_eigvectors, epsilon = 1.0e-7));
|
||||||
},
|
|
||||||
None => true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
use na::{DMatrix, Matrix4};
|
use na::DMatrix;
|
||||||
use nl::Schur;
|
use nl::Schur;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn schur(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn schur(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 10));
|
let n = cmp::max(1, cmp::min(n, 10));
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
|
||||||
let (vecs, vals) = Schur::new(m.clone()).unpack();
|
let (vecs, vals) = Schur::new(m.clone()).unpack();
|
||||||
|
|
||||||
relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(&vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schur_static(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
|
fn schur_static(m in matrix4()) {
|
||||||
let (vecs, vals) = Schur::new(m.clone()).unpack();
|
let (vecs, vals) = Schur::new(m.clone()).unpack();
|
||||||
|
prop_assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7))
|
||||||
relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +1,53 @@
|
||||||
use na::{DMatrix, Matrix3x4};
|
use na::{DMatrix, Matrix3x5};
|
||||||
use nl::SVD;
|
use nl::SVD;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn svd(m: DMatrix<f64>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
if m.nrows() != 0 && m.ncols() != 0 {
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn svd(m in dmatrix()) {
|
||||||
let svd = SVD::new(m.clone()).unwrap();
|
let svd = SVD::new(m.clone()).unwrap();
|
||||||
let sm = DMatrix::from_partial_diagonal(m.nrows(), m.ncols(), svd.singular_values.as_slice());
|
let sm = DMatrix::from_partial_diagonal(m.nrows(), m.ncols(), svd.singular_values.as_slice());
|
||||||
|
|
||||||
let reconstructed_m = &svd.u * sm * &svd.vt;
|
let reconstructed_m = &svd.u * sm * &svd.vt;
|
||||||
let reconstructed_m2 = svd.recompose();
|
let reconstructed_m2 = svd.recompose();
|
||||||
|
|
||||||
relative_eq!(reconstructed_m, m, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(reconstructed_m, m, epsilon = 1.0e-7));
|
||||||
relative_eq!(reconstructed_m2, reconstructed_m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(reconstructed_m2, reconstructed_m, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static(m: Matrix3x4<f64>) -> bool {
|
#[test]
|
||||||
|
fn svd_static(m in matrix3x5()) {
|
||||||
let svd = SVD::new(m).unwrap();
|
let svd = SVD::new(m).unwrap();
|
||||||
let sm = Matrix3x4::from_partial_diagonal(svd.singular_values.as_slice());
|
let sm = Matrix3x5::from_partial_diagonal(svd.singular_values.as_slice());
|
||||||
|
|
||||||
let reconstructed_m = &svd.u * &sm * &svd.vt;
|
let reconstructed_m = &svd.u * &sm * &svd.vt;
|
||||||
let reconstructed_m2 = svd.recompose();
|
let reconstructed_m2 = svd.recompose();
|
||||||
|
|
||||||
relative_eq!(reconstructed_m, m, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(reconstructed_m, m, epsilon = 1.0e-7));
|
||||||
relative_eq!(reconstructed_m2, m, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(reconstructed_m2, m, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
|
|
||||||
fn pseudo_inverse(m: DMatrix<f64>) -> bool {
|
|
||||||
if m.nrows() == 0 || m.ncols() == 0 {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pseudo_inverse(m in dmatrix()) {
|
||||||
let svd = SVD::new(m.clone()).unwrap();
|
let svd = SVD::new(m.clone()).unwrap();
|
||||||
let im = svd.pseudo_inverse(1.0e-7);
|
let im = svd.pseudo_inverse(1.0e-7);
|
||||||
|
|
||||||
if m.nrows() <= m.ncols() {
|
if m.nrows() <= m.ncols() {
|
||||||
return (&m * &im).is_identity(1.0e-7)
|
prop_assert!((&m * &im).is_identity(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.nrows() >= m.ncols() {
|
if m.nrows() >= m.ncols() {
|
||||||
return (im * m).is_identity(1.0e-7)
|
prop_assert!((im * m).is_identity(1.0e-7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn pseudo_inverse_static(m in matrix3x5()) {
|
||||||
|
|
||||||
fn pseudo_inverse_static(m: Matrix3x4<f64>) -> bool {
|
|
||||||
let svd = SVD::new(m).unwrap();
|
let svd = SVD::new(m).unwrap();
|
||||||
let im = svd.pseudo_inverse(1.0e-7);
|
let im = svd.pseudo_inverse(1.0e-7);
|
||||||
|
|
||||||
(m * im).is_identity(1.0e-7)
|
prop_assert!((m * im).is_identity(1.0e-7))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use na::{DMatrix, Matrix4};
|
use na::DMatrix;
|
||||||
use nl::SymmetricEigen;
|
use nl::SymmetricEigen;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn symmetric_eigen(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn symmetric_eigen(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 10));
|
let n = cmp::max(1, cmp::min(n, 10));
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
let eig = SymmetricEigen::new(m.clone());
|
let eig = SymmetricEigen::new(m.clone());
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symmetric_eigen_static(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
|
fn symmetric_eigen_static(m in matrix4()) {
|
||||||
let eig = SymmetricEigen::new(m);
|
let eig = SymmetricEigen::new(m);
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ slow-tests = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nalgebra = { version="0.24", path = "../" }
|
nalgebra = { version="0.24", path = "../" }
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
proptest = { version = "0.10", optional = true }
|
proptest = { version = "1.0", optional = true }
|
||||||
matrixcompare-core = { version = "0.1.0", optional = true }
|
matrixcompare-core = { version = "0.1.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
itertools = "0.9"
|
itertools = "0.10"
|
||||||
matrixcompare = { version = "0.2.0", features = [ "proptest-support" ] }
|
matrixcompare = { version = "0.2.0", features = [ "proptest-support" ] }
|
||||||
nalgebra = { version="0.24", path = "../", features = ["compare"] }
|
nalgebra = { version="0.24", path = "../", features = ["compare"] }
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,8 @@ where
|
||||||
// NOTE: The below line is the whole reason for the existence of this adapted code
|
// NOTE: The below line is the whole reason for the existence of this adapted code
|
||||||
// We need to be able to swap with the same element, so that some elements remain in
|
// We need to be able to swap with the same element, so that some elements remain in
|
||||||
// place rather being swapped
|
// place rather being swapped
|
||||||
// let end_index = rng.gen_range(start_index + 1, len);
|
// let end_index = rng.gen_range(start_index + 1..len);
|
||||||
let end_index = rng.gen_range(start_index, len);
|
let end_index = rng.gen_range(start_index..len);
|
||||||
if end_index - start_index <= max_swap {
|
if end_index - start_index <= max_swap {
|
||||||
value.shuffle_swap(start_index, end_index);
|
value.shuffle_swap(start_index, end_index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -824,8 +824,8 @@ where
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> MatrixMN<N, R, C> {
|
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> MatrixMN<N, R, C> {
|
||||||
let nrows = R::try_to_usize().unwrap_or_else(|| rng.gen_range(0, 10));
|
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));
|
let ncols = C::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10));
|
||||||
|
|
||||||
MatrixMN::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |_, _| rng.gen())
|
MatrixMN::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |_, _| rng.gen())
|
||||||
}
|
}
|
||||||
|
@ -841,9 +841,9 @@ where
|
||||||
Owned<N, R, C>: Clone + Send,
|
Owned<N, R, C>: Clone + Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
let nrows = R::try_to_usize().unwrap_or(g.gen_range(0, 10));
|
let nrows = R::try_to_usize().unwrap_or(usize::arbitrary(g) % 10);
|
||||||
let ncols = C::try_to_usize().unwrap_or(g.gen_range(0, 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), |_, _| {
|
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |_, _| {
|
||||||
N::arbitrary(g)
|
N::arbitrary(g)
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rand::Rng;
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reject<G: Gen, F: FnMut(&T) -> bool, T: Arbitrary>(g: &mut G, f: F) -> T {
|
pub fn reject<F: FnMut(&T) -> bool, T: Arbitrary>(g: &mut Gen, f: F) -> T {
|
||||||
use std::iter;
|
use std::iter;
|
||||||
iter::repeat(())
|
iter::repeat(())
|
||||||
.map(|_| Arbitrary::arbitrary(g))
|
.map(|_| Arbitrary::arbitrary(g))
|
||||||
|
|
|
@ -48,9 +48,8 @@ where
|
||||||
DefaultAllocator: Allocator<N, D, D>,
|
DefaultAllocator: Allocator<N, D, D>,
|
||||||
Owned<N, D, D>: Clone + Send,
|
Owned<N, D, D>: Clone + Send,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
use rand::Rng;
|
let dim = D::try_to_usize().unwrap_or(1 + usize::arbitrary(g) % 50);
|
||||||
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
|
|
||||||
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,8 @@ where
|
||||||
DefaultAllocator: Allocator<N, D, D>,
|
DefaultAllocator: Allocator<N, D, D>,
|
||||||
Owned<N, D, D>: Clone + Send,
|
Owned<N, D, D>: Clone + Send,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
use rand::Rng;
|
let dim = D::try_to_usize().unwrap_or(1 + usize::arbitrary(g) % 50);
|
||||||
let dim = D::try_to_usize().unwrap_or(g.gen_range(1, 50));
|
|
||||||
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
Self::new(D::from_usize(dim), || N::arbitrary(g))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ where
|
||||||
N::Element: SimdRealField,
|
N::Element: SimdRealField,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
Self::from_real_and_dual(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
|
Self::from_real_and_dual(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ where
|
||||||
N::Element: SimdRealField,
|
N::Element: SimdRealField,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
Self::new_normalize(Arbitrary::arbitrary(rng))
|
Self::new_normalize(Arbitrary::arbitrary(rng))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ where
|
||||||
DefaultAllocator: Allocator<N, D>,
|
DefaultAllocator: Allocator<N, D>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
|
Self::from_parts(Arbitrary::arbitrary(rng), Arbitrary::arbitrary(rng))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -705,7 +705,7 @@ impl<N: RealField + Arbitrary> Arbitrary for Orthographic3<N>
|
||||||
where
|
where
|
||||||
Matrix4<N>: Send,
|
Matrix4<N>: Send,
|
||||||
{
|
{
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
let left = Arbitrary::arbitrary(g);
|
let left = Arbitrary::arbitrary(g);
|
||||||
let right = helper::reject(g, |x: &N| *x > left);
|
let right = helper::reject(g, |x: &N| *x > left);
|
||||||
let bottom = Arbitrary::arbitrary(g);
|
let bottom = Arbitrary::arbitrary(g);
|
||||||
|
|
|
@ -283,7 +283,7 @@ where
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<N: RealField + Arbitrary> Arbitrary for Perspective3<N> {
|
impl<N: RealField + Arbitrary> Arbitrary for Perspective3<N> {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
let znear = Arbitrary::arbitrary(g);
|
let znear = Arbitrary::arbitrary(g);
|
||||||
let zfar = helper::reject(g, |&x: &N| !(x - znear).is_zero());
|
let zfar = helper::reject(g, |&x: &N| !(x - znear).is_zero());
|
||||||
let aspect = helper::reject(g, |&x: &N| !x.is_zero());
|
let aspect = helper::reject(g, |&x: &N| !x.is_zero());
|
||||||
|
|
|
@ -156,7 +156,7 @@ where
|
||||||
<DefaultAllocator as Allocator<N, D>>::Buffer: Send,
|
<DefaultAllocator as Allocator<N, D>>::Buffer: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
Self::from(VectorN::arbitrary(g))
|
Self::from(VectorN::arbitrary(g))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ where
|
||||||
Owned<N, U4>: Send,
|
Owned<N, U4>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
N::arbitrary(g),
|
N::arbitrary(g),
|
||||||
N::arbitrary(g),
|
N::arbitrary(g),
|
||||||
|
@ -845,7 +845,7 @@ where
|
||||||
Owned<N, U3>: Send,
|
Owned<N, U3>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
let axisangle = Vector3::arbitrary(g);
|
let axisangle = Vector3::arbitrary(g);
|
||||||
Self::from_scaled_axis(axisangle)
|
Self::from_scaled_axis(axisangle)
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ where
|
||||||
Owned<N, U2, U2>: Send,
|
Owned<N, U2, U2>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
Self::new(N::arbitrary(g))
|
Self::new(N::arbitrary(g))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -961,7 +961,7 @@ where
|
||||||
Owned<N, U3>: Send,
|
Owned<N, U3>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
Self::new(VectorN::arbitrary(g))
|
Self::new(VectorN::arbitrary(g))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ where
|
||||||
Owned<N, D>: Send,
|
Owned<N, D>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
let mut s: N = Arbitrary::arbitrary(rng);
|
let mut s: N = Arbitrary::arbitrary(rng);
|
||||||
while s.is_zero() {
|
while s.is_zero() {
|
||||||
s = Arbitrary::arbitrary(rng)
|
s = Arbitrary::arbitrary(rng)
|
||||||
|
|
|
@ -61,13 +61,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<N: Scalar + Arbitrary, D: DimName> Arbitrary for Translation<N, D>
|
impl<N: Scalar + Arbitrary + Send, D: DimName> Arbitrary for Translation<N, D>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<N, D>,
|
DefaultAllocator: Allocator<N, D>,
|
||||||
Owned<N, D>: Send,
|
Owned<N, D>: Send,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
let v: VectorN<N, D> = Arbitrary::arbitrary(rng);
|
let v: VectorN<N, D> = Arbitrary::arbitrary(rng);
|
||||||
Self::from(v)
|
Self::from(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,7 +395,7 @@ where
|
||||||
N::Element: SimdRealField,
|
N::Element: SimdRealField,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> Self {
|
fn arbitrary(g: &mut Gen) -> Self {
|
||||||
UnitComplex::from_angle(N::arbitrary(g))
|
UnitComplex::from_angle(N::arbitrary(g))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ impl<N: ComplexField, D: Dim, S: Storage<N, D, D>> Matrix<N, D, D, S> {
|
||||||
///
|
///
|
||||||
/// The input matrix `self` is assumed to be symmetric and this decomposition will only read
|
/// The input matrix `self` is assumed to be symmetric and this decomposition will only read
|
||||||
/// the upper-triangular part of `self`.
|
/// the upper-triangular part of `self`.
|
||||||
pub fn udu(self) -> UDU<N, D>
|
pub fn udu(self) -> Option<UDU<N, D>>
|
||||||
where
|
where
|
||||||
N: RealField,
|
N: RealField,
|
||||||
DefaultAllocator: Allocator<N, D> + Allocator<N, D, D>,
|
DefaultAllocator: Allocator<N, D> + Allocator<N, D, D>,
|
||||||
|
|
|
@ -48,7 +48,7 @@ where
|
||||||
/// the upper-triangular part of `p`.
|
/// the upper-triangular part of `p`.
|
||||||
///
|
///
|
||||||
/// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360
|
/// Ref.: "Optimal control and estimation-Dover Publications", Robert F. Stengel, (1994) page 360
|
||||||
pub fn new(p: MatrixN<N, D>) -> Self {
|
pub fn new(p: MatrixN<N, D>) -> Option<Self> {
|
||||||
let n = p.ncols();
|
let n = p.ncols();
|
||||||
let n_dim = p.data.shape().1;
|
let n_dim = p.data.shape().1;
|
||||||
|
|
||||||
|
@ -56,6 +56,11 @@ where
|
||||||
let mut u = MatrixN::zeros_generic(n_dim, n_dim);
|
let mut u = MatrixN::zeros_generic(n_dim, n_dim);
|
||||||
|
|
||||||
d[n - 1] = p[(n - 1, n - 1)];
|
d[n - 1] = p[(n - 1, n - 1)];
|
||||||
|
|
||||||
|
if d[n - 1].is_zero() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
u.column_mut(n - 1)
|
u.column_mut(n - 1)
|
||||||
.axpy(N::one() / d[n - 1], &p.column(n - 1), N::zero());
|
.axpy(N::one() / d[n - 1], &p.column(n - 1), N::zero());
|
||||||
|
|
||||||
|
@ -67,6 +72,10 @@ where
|
||||||
|
|
||||||
d[j] = p[(j, j)] - d_j;
|
d[j] = p[(j, j)] - d_j;
|
||||||
|
|
||||||
|
if d[j].is_zero() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
for i in (0..=j).rev() {
|
for i in (0..=j).rev() {
|
||||||
let mut u_ij = u[(i, j)];
|
let mut u_ij = u[(i, j)];
|
||||||
for k in j + 1..n {
|
for k in j + 1..n {
|
||||||
|
@ -79,7 +88,7 @@ where
|
||||||
u[(j, j)] = N::one();
|
u[(j, j)] = N::one();
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { u, d }
|
Some(Self { u, d })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the diagonal elements as a matrix
|
/// Returns the diagonal elements as a matrix
|
||||||
|
|
|
@ -408,7 +408,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A strategy for generating matrices.
|
/// A strategy for generating matrices.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MatrixStrategy<NStrategy, R: Dim, C: Dim>
|
pub struct MatrixStrategy<NStrategy, R: Dim, C: Dim>
|
||||||
where
|
where
|
||||||
NStrategy: Strategy,
|
NStrategy: Strategy,
|
||||||
|
|
|
@ -21,19 +21,20 @@ fn gemm_noncommutative() {
|
||||||
assert_eq!(res, Matrix2::zero());
|
assert_eq!(res, Matrix2::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod blas_quickcheck {
|
mod blas_proptest {
|
||||||
|
use crate::proptest::{PROPTEST_F64, PROPTEST_MATRIX_DIM};
|
||||||
use na::{DMatrix, DVector};
|
use na::{DMatrix, DVector};
|
||||||
use std::cmp;
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Symmetric operators.
|
* Symmetric operators.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn gemv_symm(n: usize, alpha: f64, beta: f64) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
fn gemv_symm(n in PROPTEST_MATRIX_DIM, alpha in PROPTEST_F64, beta in PROPTEST_F64) {
|
||||||
let a = DMatrix::<f64>::new_random(n, n);
|
let a = DMatrix::<f64>::new_random(n, n);
|
||||||
let a = &a * a.transpose();
|
let a = &a * a.transpose();
|
||||||
|
|
||||||
|
@ -44,18 +45,16 @@ mod blas_quickcheck {
|
||||||
y1.gemv(alpha, &a, &x, beta);
|
y1.gemv(alpha, &a, &x, beta);
|
||||||
y2.sygemv(alpha, &a.lower_triangle(), &x, beta);
|
y2.sygemv(alpha, &a.lower_triangle(), &x, beta);
|
||||||
|
|
||||||
if !relative_eq!(y1, y2, epsilon = 1.0e-10) {
|
prop_assert!(relative_eq!(y1, y2, epsilon = 1.0e-10));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
y1.gemv(alpha, &a, &x, 0.0);
|
y1.gemv(alpha, &a, &x, 0.0);
|
||||||
y2.sygemv(alpha, &a.lower_triangle(), &x, 0.0);
|
y2.sygemv(alpha, &a.lower_triangle(), &x, 0.0);
|
||||||
|
|
||||||
relative_eq!(y1, y2, epsilon = 1.0e-10)
|
prop_assert!(relative_eq!(y1, y2, epsilon = 1.0e-10))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gemv_tr(n: usize, alpha: f64, beta: f64) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
fn gemv_tr(n in PROPTEST_MATRIX_DIM, alpha in PROPTEST_F64, beta in PROPTEST_F64) {
|
||||||
let a = DMatrix::<f64>::new_random(n, n);
|
let a = DMatrix::<f64>::new_random(n, n);
|
||||||
let x = DVector::new_random(n);
|
let x = DVector::new_random(n);
|
||||||
let mut y1 = DVector::new_random(n);
|
let mut y1 = DVector::new_random(n);
|
||||||
|
@ -64,18 +63,16 @@ mod blas_quickcheck {
|
||||||
y1.gemv(alpha, &a, &x, beta);
|
y1.gemv(alpha, &a, &x, beta);
|
||||||
y2.gemv_tr(alpha, &a.transpose(), &x, beta);
|
y2.gemv_tr(alpha, &a.transpose(), &x, beta);
|
||||||
|
|
||||||
if !relative_eq!(y1, y2, epsilon = 1.0e-10) {
|
prop_assert!(relative_eq!(y1, y2, epsilon = 1.0e-10));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
y1.gemv(alpha, &a, &x, 0.0);
|
y1.gemv(alpha, &a, &x, 0.0);
|
||||||
y2.gemv_tr(alpha, &a.transpose(), &x, 0.0);
|
y2.gemv_tr(alpha, &a.transpose(), &x, 0.0);
|
||||||
|
|
||||||
relative_eq!(y1, y2, epsilon = 1.0e-10)
|
prop_assert!(relative_eq!(y1, y2, epsilon = 1.0e-10))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ger_symm(n: usize, alpha: f64, beta: f64) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
fn ger_symm(n in PROPTEST_MATRIX_DIM, alpha in PROPTEST_F64, beta in PROPTEST_F64) {
|
||||||
let a = DMatrix::<f64>::new_random(n, n);
|
let a = DMatrix::<f64>::new_random(n, n);
|
||||||
let mut a1 = &a * a.transpose();
|
let mut a1 = &a * a.transpose();
|
||||||
let mut a2 = a1.lower_triangle();
|
let mut a2 = a1.lower_triangle();
|
||||||
|
@ -86,18 +83,16 @@ mod blas_quickcheck {
|
||||||
a1.ger(alpha, &x, &y, beta);
|
a1.ger(alpha, &x, &y, beta);
|
||||||
a2.syger(alpha, &x, &y, beta);
|
a2.syger(alpha, &x, &y, beta);
|
||||||
|
|
||||||
if !relative_eq!(a1.lower_triangle(), a2) {
|
prop_assert!(relative_eq!(a1.lower_triangle(), a2));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
a1.ger(alpha, &x, &y, 0.0);
|
a1.ger(alpha, &x, &y, 0.0);
|
||||||
a2.syger(alpha, &x, &y, 0.0);
|
a2.syger(alpha, &x, &y, 0.0);
|
||||||
|
|
||||||
relative_eq!(a1.lower_triangle(), a2)
|
prop_assert!(relative_eq!(a1.lower_triangle(), a2))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quadform(n: usize, alpha: f64, beta: f64) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
fn quadform(n in PROPTEST_MATRIX_DIM, alpha in PROPTEST_F64, beta in PROPTEST_F64) {
|
||||||
let rhs = DMatrix::<f64>::new_random(6, n);
|
let rhs = DMatrix::<f64>::new_random(6, n);
|
||||||
let mid = DMatrix::<f64>::new_random(6, 6);
|
let mid = DMatrix::<f64>::new_random(6, 6);
|
||||||
let mut res = DMatrix::new_random(n, n);
|
let mut res = DMatrix::new_random(n, n);
|
||||||
|
@ -106,13 +101,11 @@ mod blas_quickcheck {
|
||||||
|
|
||||||
res.quadform(alpha, &mid, &rhs, beta);
|
res.quadform(alpha, &mid, &rhs, beta);
|
||||||
|
|
||||||
println!("{}{}", res, expected);
|
prop_assert!(relative_eq!(res, expected, epsilon = 1.0e-7))
|
||||||
|
|
||||||
relative_eq!(res, expected, epsilon = 1.0e-7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quadform_tr(n: usize, alpha: f64, beta: f64) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
fn quadform_tr(n in PROPTEST_MATRIX_DIM, alpha in PROPTEST_F64, beta in PROPTEST_F64) {
|
||||||
let lhs = DMatrix::<f64>::new_random(6, n);
|
let lhs = DMatrix::<f64>::new_random(6, n);
|
||||||
let mid = DMatrix::<f64>::new_random(n, n);
|
let mid = DMatrix::<f64>::new_random(n, n);
|
||||||
let mut res = DMatrix::new_random(6, 6);
|
let mut res = DMatrix::new_random(6, 6);
|
||||||
|
@ -121,9 +114,7 @@ mod blas_quickcheck {
|
||||||
|
|
||||||
res.quadform_tr(alpha, &lhs, &mid , beta);
|
res.quadform_tr(alpha, &lhs, &mid , beta);
|
||||||
|
|
||||||
println!("{}{}", res, expected);
|
prop_assert!(relative_eq!(res, expected, epsilon = 1.0e-7))
|
||||||
|
|
||||||
relative_eq!(res, expected, epsilon = 1.0e-7)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,49 @@
|
||||||
#![cfg(all(feature = "arbitrary", feature = "alga"))]
|
#![cfg(all(feature = "proptest-support", feature = "alga"))]
|
||||||
use alga::linear::Transformation;
|
use alga::linear::Transformation;
|
||||||
use na::{
|
use na::{
|
||||||
self, Affine3, Isometry3, Matrix2, Matrix2x3, Matrix2x4, Matrix2x5, Matrix2x6, Matrix3,
|
self, Affine3, Isometry3, Matrix2, Matrix2x3, Matrix2x4, Matrix2x5, Matrix2x6, Matrix3,
|
||||||
Matrix3x2, Matrix3x4, Matrix3x5, Matrix3x6, Matrix4, Matrix4x2, Matrix4x3, Matrix4x5,
|
Matrix3x2, Matrix3x4, Matrix3x5, Matrix3x6, Matrix4, Matrix4x2, Matrix4x3, Matrix4x5,
|
||||||
Matrix4x6, Matrix5, Matrix5x2, Matrix5x3, Matrix5x4, Matrix5x6, Matrix6, Matrix6x2, Matrix6x3,
|
Matrix4x6, Matrix5, Matrix5x2, Matrix5x3, Matrix5x4, Matrix5x6, Matrix6, Matrix6x2, Matrix6x3,
|
||||||
Matrix6x4, Matrix6x5, Point3, Projective3, Rotation3, RowVector1, RowVector2, RowVector3,
|
Matrix6x4, Matrix6x5, Projective3, Rotation3, RowVector1, RowVector2, RowVector3, RowVector4,
|
||||||
RowVector4, RowVector5, RowVector6, Similarity3, Transform3, Translation3, UnitQuaternion,
|
RowVector5, RowVector6, Similarity3, Transform3, UnitQuaternion, Vector1, Vector2, Vector3,
|
||||||
Vector1, Vector2, Vector3, Vector4, Vector5, Vector6,
|
Vector4, Vector5, Vector6,
|
||||||
};
|
};
|
||||||
use na::{DMatrix, DMatrixSlice, DMatrixSliceMut, MatrixSlice, MatrixSliceMut};
|
use na::{DMatrix, DMatrixSlice, DMatrixSliceMut, MatrixSlice, MatrixSliceMut};
|
||||||
use na::{U1, U3, U4};
|
use na::{U1, U3, U4};
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn translation_conversion(t: Translation3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
use proptest::{prop_assert, prop_assert_eq, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn translation_conversion(t in translation3(), v in vector3(), p in point3()) {
|
||||||
let iso: Isometry3<f64> = na::convert(t);
|
let iso: Isometry3<f64> = na::convert(t);
|
||||||
let sim: Similarity3<f64> = na::convert(t);
|
let sim: Similarity3<f64> = na::convert(t);
|
||||||
let aff: Affine3<f64> = na::convert(t);
|
let aff: Affine3<f64> = na::convert(t);
|
||||||
let prj: Projective3<f64> = na::convert(t);
|
let prj: Projective3<f64> = na::convert(t);
|
||||||
let tr: Transform3<f64> = na::convert(t);
|
let tr: Transform3<f64> = na::convert(t);
|
||||||
|
|
||||||
t == na::try_convert(iso).unwrap() &&
|
prop_assert_eq!(t, na::try_convert(iso).unwrap());
|
||||||
t == na::try_convert(sim).unwrap() &&
|
prop_assert_eq!(t, na::try_convert(sim).unwrap());
|
||||||
t == na::try_convert(aff).unwrap() &&
|
prop_assert_eq!(t, na::try_convert(aff).unwrap());
|
||||||
t == na::try_convert(prj).unwrap() &&
|
prop_assert_eq!(t, na::try_convert(prj).unwrap());
|
||||||
t == na::try_convert(tr).unwrap() &&
|
prop_assert_eq!(t, na::try_convert(tr).unwrap() );
|
||||||
|
|
||||||
t.transform_vector(&v) == iso * v &&
|
prop_assert_eq!(t.transform_vector(&v), iso * v);
|
||||||
t.transform_vector(&v) == sim * v &&
|
prop_assert_eq!(t.transform_vector(&v), sim * v);
|
||||||
t.transform_vector(&v) == aff * v &&
|
prop_assert_eq!(t.transform_vector(&v), aff * v);
|
||||||
t.transform_vector(&v) == prj * v &&
|
prop_assert_eq!(t.transform_vector(&v), prj * v);
|
||||||
t.transform_vector(&v) == tr * v &&
|
prop_assert_eq!(t.transform_vector(&v), tr * v);
|
||||||
|
|
||||||
t * p == iso * p &&
|
prop_assert_eq!(t * p, iso * p);
|
||||||
t * p == sim * p &&
|
prop_assert_eq!(t * p, sim * p);
|
||||||
t * p == aff * p &&
|
prop_assert_eq!(t * p, aff * p);
|
||||||
t * p == prj * p &&
|
prop_assert_eq!(t * p, prj * p);
|
||||||
t * p == tr * p
|
prop_assert_eq!(t * p, tr * p);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_conversion(r: Rotation3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_conversion(r in rotation3(), v in vector3(), p in point3()) {
|
||||||
let uq: UnitQuaternion<f64> = na::convert(r);
|
let uq: UnitQuaternion<f64> = na::convert(r);
|
||||||
let iso: Isometry3<f64> = na::convert(r);
|
let iso: Isometry3<f64> = na::convert(r);
|
||||||
let sim: Similarity3<f64> = na::convert(r);
|
let sim: Similarity3<f64> = na::convert(r);
|
||||||
|
@ -46,30 +51,31 @@ quickcheck! {
|
||||||
let prj: Projective3<f64> = na::convert(r);
|
let prj: Projective3<f64> = na::convert(r);
|
||||||
let tr: Transform3<f64> = na::convert(r);
|
let tr: Transform3<f64> = na::convert(r);
|
||||||
|
|
||||||
relative_eq!(r, na::try_convert(uq).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r, na::try_convert(uq).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(r, na::try_convert(iso).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r, na::try_convert(iso).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(r, na::try_convert(sim).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r, na::try_convert(sim).unwrap(), epsilon = 1.0e-7));
|
||||||
r == na::try_convert(aff).unwrap() &&
|
prop_assert_eq!(r, na::try_convert(aff).unwrap());
|
||||||
r == na::try_convert(prj).unwrap() &&
|
prop_assert_eq!(r, na::try_convert(prj).unwrap());
|
||||||
r == na::try_convert(tr).unwrap() &&
|
prop_assert_eq!(r, na::try_convert(tr).unwrap() );
|
||||||
|
|
||||||
// NOTE: we need relative_eq because Isometry and Similarity use quaternions.
|
// NOTE: we need relative_eq because Isometry and Similarity use quaternions.
|
||||||
relative_eq!(r * v, uq * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r * v, uq * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(r * v, iso * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r * v, iso * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(r * v, sim * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r * v, sim * v, epsilon = 1.0e-7));
|
||||||
r * v == aff * v &&
|
prop_assert_eq!(r * v, aff * v);
|
||||||
r * v == prj * v &&
|
prop_assert_eq!(r * v, prj * v);
|
||||||
r * v == tr * v &&
|
prop_assert_eq!(r * v, tr * v);
|
||||||
|
|
||||||
relative_eq!(r * p, uq * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r * p, uq * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(r * p, iso * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r * p, iso * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(r * p, sim * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(r * p, sim * p, epsilon = 1.0e-7));
|
||||||
r * p == aff * p &&
|
prop_assert_eq!(r * p, aff * p);
|
||||||
r * p == prj * p &&
|
prop_assert_eq!(r * p, prj * p);
|
||||||
r * p == tr * p
|
prop_assert_eq!(r * p, tr * p);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unit_quaternion_conversion(uq: UnitQuaternion<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_quaternion_conversion(uq in unit_quaternion(), v in vector3(), p in point3()) {
|
||||||
let rot: Rotation3<f64> = na::convert(uq);
|
let rot: Rotation3<f64> = na::convert(uq);
|
||||||
let iso: Isometry3<f64> = na::convert(uq);
|
let iso: Isometry3<f64> = na::convert(uq);
|
||||||
let sim: Similarity3<f64> = na::convert(uq);
|
let sim: Similarity3<f64> = na::convert(uq);
|
||||||
|
@ -77,68 +83,70 @@ quickcheck! {
|
||||||
let prj: Projective3<f64> = na::convert(uq);
|
let prj: Projective3<f64> = na::convert(uq);
|
||||||
let tr: Transform3<f64> = na::convert(uq);
|
let tr: Transform3<f64> = na::convert(uq);
|
||||||
|
|
||||||
uq == na::try_convert(iso).unwrap() &&
|
prop_assert_eq!(uq, na::try_convert(iso).unwrap());
|
||||||
uq == na::try_convert(sim).unwrap() &&
|
prop_assert_eq!(uq, na::try_convert(sim).unwrap());
|
||||||
relative_eq!(uq, na::try_convert(rot).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq, na::try_convert(rot).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(uq, na::try_convert(aff).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq, na::try_convert(aff).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(uq, na::try_convert(prj).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq, na::try_convert(prj).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(uq, na::try_convert(tr).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq, na::try_convert(tr).unwrap(), epsilon = 1.0e-7) );
|
||||||
|
|
||||||
// NOTE: iso and sim use unit quaternions for the rotation so conversions to them are exact.
|
// NOTE: iso and sim use unit quaternions for the rotation so conversions to them are exact.
|
||||||
relative_eq!(uq * v, rot * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * v, rot * v, epsilon = 1.0e-7));
|
||||||
uq * v == iso * v &&
|
prop_assert_eq!(uq * v, iso * v);
|
||||||
uq * v == sim * v &&
|
prop_assert_eq!(uq * v, sim * v);
|
||||||
relative_eq!(uq * v, aff * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * v, aff * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(uq * v, prj * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * v, prj * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(uq * v, tr * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * v, tr * v, epsilon = 1.0e-7));
|
||||||
|
|
||||||
relative_eq!(uq * p, rot * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * p, rot * p, epsilon = 1.0e-7));
|
||||||
uq * p == iso * p &&
|
prop_assert_eq!(uq * p, iso * p);
|
||||||
uq * p == sim * p &&
|
prop_assert_eq!(uq * p, sim * p);
|
||||||
relative_eq!(uq * p, aff * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * p, aff * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(uq * p, prj * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(uq * p, prj * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(uq * p, tr * p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(uq * p, tr * p, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isometry_conversion(iso: Isometry3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn isometry_conversion(iso in isometry3(), v in vector3(), p in point3()) {
|
||||||
let sim: Similarity3<f64> = na::convert(iso);
|
let sim: Similarity3<f64> = na::convert(iso);
|
||||||
let aff: Affine3<f64> = na::convert(iso);
|
let aff: Affine3<f64> = na::convert(iso);
|
||||||
let prj: Projective3<f64> = na::convert(iso);
|
let prj: Projective3<f64> = na::convert(iso);
|
||||||
let tr: Transform3<f64> = na::convert(iso);
|
let tr: Transform3<f64> = na::convert(iso);
|
||||||
|
|
||||||
|
|
||||||
iso == na::try_convert(sim).unwrap() &&
|
prop_assert_eq!(iso, na::try_convert(sim).unwrap());
|
||||||
relative_eq!(iso, na::try_convert(aff).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso, na::try_convert(aff).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(iso, na::try_convert(prj).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso, na::try_convert(prj).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(iso, na::try_convert(tr).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso, na::try_convert(tr).unwrap(), epsilon = 1.0e-7) );
|
||||||
|
|
||||||
iso * v == sim * v &&
|
prop_assert_eq!(iso * v, sim * v);
|
||||||
relative_eq!(iso * v, aff * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso * v, aff * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(iso * v, prj * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso * v, prj * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(iso * v, tr * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso * v, tr * v, epsilon = 1.0e-7));
|
||||||
|
|
||||||
iso * p == sim * p &&
|
prop_assert_eq!(iso * p, sim * p);
|
||||||
relative_eq!(iso * p, aff * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso * p, aff * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(iso * p, prj * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(iso * p, prj * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(iso * p, tr * p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(iso * p, tr * p, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn similarity_conversion(sim: Similarity3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn similarity_conversion(sim in similarity3(), v in vector3(), p in point3()) {
|
||||||
let aff: Affine3<f64> = na::convert(sim);
|
let aff: Affine3<f64> = na::convert(sim);
|
||||||
let prj: Projective3<f64> = na::convert(sim);
|
let prj: Projective3<f64> = na::convert(sim);
|
||||||
let tr: Transform3<f64> = na::convert(sim);
|
let tr: Transform3<f64> = na::convert(sim);
|
||||||
|
|
||||||
relative_eq!(sim, na::try_convert(aff).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim, na::try_convert(aff).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(sim, na::try_convert(prj).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim, na::try_convert(prj).unwrap(), epsilon = 1.0e-7));
|
||||||
relative_eq!(sim, na::try_convert(tr).unwrap(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim, na::try_convert(tr).unwrap(), epsilon = 1.0e-7));
|
||||||
|
|
||||||
relative_eq!(sim * v, aff * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim * v, aff * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(sim * v, prj * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim * v, prj * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(sim * v, tr * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim * v, tr * v, epsilon = 1.0e-7));
|
||||||
|
|
||||||
relative_eq!(sim * p, aff * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim * p, aff * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(sim * p, prj * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(sim * p, prj * p, epsilon = 1.0e-7));
|
||||||
relative_eq!(sim * p, tr * p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(sim * p, tr * p, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX test Transform
|
// XXX test Transform
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct RandComplex<N>(pub Complex<N>);
|
||||||
|
|
||||||
impl<N: Arbitrary + RealField> Arbitrary for RandComplex<N> {
|
impl<N: Arbitrary + RealField> Arbitrary for RandComplex<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
let im = Arbitrary::arbitrary(rng);
|
let im = Arbitrary::arbitrary(rng);
|
||||||
let re = Arbitrary::arbitrary(rng);
|
let re = Arbitrary::arbitrary(rng);
|
||||||
RandComplex(Complex::new(re, im))
|
RandComplex(Complex::new(re, im))
|
||||||
|
@ -38,7 +38,7 @@ pub struct RandScalar<N>(pub N);
|
||||||
|
|
||||||
impl<N: Arbitrary> Arbitrary for RandScalar<N> {
|
impl<N: Arbitrary> Arbitrary for RandScalar<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arbitrary<G: Gen>(rng: &mut G) -> Self {
|
fn arbitrary(rng: &mut Gen) -> Self {
|
||||||
RandScalar(Arbitrary::arbitrary(rng))
|
RandScalar(Arbitrary::arbitrary(rng))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -829,151 +829,145 @@ fn swizzle() {
|
||||||
assert_eq!(c.zyz(), Vector3::new(3.0, 2.0, 3.0));
|
assert_eq!(c.zyz(), Vector3::new(3.0, 2.0, 3.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod transposition_tests {
|
mod transposition_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use na::Matrix4x6;
|
use crate::proptest::{dmatrix, matrix, vector4, PROPTEST_F64};
|
||||||
|
use na::{U2, U3, U4, U6};
|
||||||
|
use proptest::{prop_assert, prop_assert_eq, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn transpose_transpose_is_self(m: Matrix2x3<f64>) -> bool {
|
#[test]
|
||||||
m.transpose().transpose() == m
|
fn transpose_transpose_is_self(m in matrix(PROPTEST_F64, U2, U3)) {
|
||||||
|
prop_assert_eq!(m.transpose().transpose(), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transpose_mut_transpose_mut_is_self(m: Matrix3<f64>) -> bool {
|
#[test]
|
||||||
|
fn transpose_mut_transpose_mut_is_self(m in matrix(PROPTEST_F64, U3, U3)) {
|
||||||
let mut mm = m;
|
let mut mm = m;
|
||||||
mm.transpose_mut();
|
mm.transpose_mut();
|
||||||
mm.transpose_mut();
|
mm.transpose_mut();
|
||||||
m == mm
|
prop_assert_eq!(m, mm)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transpose_transpose_is_id_dyn(m: DMatrix<f64>) -> bool {
|
#[test]
|
||||||
m.transpose().transpose() == m
|
fn transpose_transpose_is_id_dyn(m in dmatrix()) {
|
||||||
|
prop_assert_eq!(m.transpose().transpose(), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_transpose_components_dyn(m: DMatrix<f64>) -> bool {
|
#[test]
|
||||||
|
fn check_transpose_components_dyn(m in dmatrix()) {
|
||||||
let tr = m.transpose();
|
let tr = m.transpose();
|
||||||
let (nrows, ncols) = m.shape();
|
let (nrows, ncols) = m.shape();
|
||||||
|
|
||||||
if nrows != tr.shape().1 || ncols != tr.shape().0 {
|
prop_assert!(nrows == tr.shape().1 && ncols == tr.shape().0);
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0 .. nrows {
|
for i in 0 .. nrows {
|
||||||
for j in 0 .. ncols {
|
for j in 0 .. ncols {
|
||||||
if m[(i, j)] != tr[(j, i)] {
|
prop_assert_eq!(m[(i, j)], tr[(j, i)]);
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
#[test]
|
||||||
}
|
fn tr_mul_is_transpose_then_mul(m in matrix(PROPTEST_F64, U4, U6), v in vector4()) {
|
||||||
|
prop_assert!(relative_eq!(m.transpose() * v, m.tr_mul(&v), epsilon = 1.0e-7))
|
||||||
fn tr_mul_is_transpose_then_mul(m: Matrix4x6<f64>, v: Vector4<f64>) -> bool {
|
|
||||||
relative_eq!(m.transpose() * v, m.tr_mul(&v), epsilon = 1.0e-7)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod inversion_tests {
|
mod inversion_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::proptest::*;
|
||||||
use na::Matrix1;
|
use na::Matrix1;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn self_mul_inv_is_id_dim1(m: Matrix1<f64>) -> bool {
|
#[test]
|
||||||
|
fn self_mul_inv_is_id_dim1(m in matrix1()) {
|
||||||
if let Some(im) = m.try_inverse() {
|
if let Some(im) = m.try_inverse() {
|
||||||
let id = Matrix1::one();
|
let id = Matrix1::one();
|
||||||
relative_eq!(im * m, id, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(im * m, id, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * im, id, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * im, id, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_mul_inv_is_id_dim2(m: Matrix2<f64>) -> bool {
|
#[test]
|
||||||
|
fn self_mul_inv_is_id_dim2(m in matrix2()) {
|
||||||
if let Some(im) = m.try_inverse() {
|
if let Some(im) = m.try_inverse() {
|
||||||
let id = Matrix2::one();
|
let id = Matrix2::one();
|
||||||
relative_eq!(im * m, id, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(im * m, id, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * im, id, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * im, id, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_mul_inv_is_id_dim3(m: Matrix3<f64>) -> bool {
|
#[test]
|
||||||
|
fn self_mul_inv_is_id_dim3(m in matrix3()) {
|
||||||
if let Some(im) = m.try_inverse() {
|
if let Some(im) = m.try_inverse() {
|
||||||
let id = Matrix3::one();
|
let id = Matrix3::one();
|
||||||
relative_eq!(im * m, id, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(im * m, id, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * im, id, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * im, id, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_mul_inv_is_id_dim4(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
|
fn self_mul_inv_is_id_dim4(m in matrix4()) {
|
||||||
if let Some(im) = m.try_inverse() {
|
if let Some(im) = m.try_inverse() {
|
||||||
let id = Matrix4::one();
|
let id = Matrix4::one();
|
||||||
relative_eq!(im * m, id, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(im * m, id, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * im, id, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * im, id, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_mul_inv_is_id_dim6(m: Matrix6<f64>) -> bool {
|
#[test]
|
||||||
|
fn self_mul_inv_is_id_dim6(m in matrix6()) {
|
||||||
if let Some(im) = m.try_inverse() {
|
if let Some(im) = m.try_inverse() {
|
||||||
let id = Matrix6::one();
|
let id = Matrix6::one();
|
||||||
relative_eq!(im * m, id, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(im * m, id, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * im, id, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * im, id, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod normalization_tests {
|
mod normalization_tests {
|
||||||
use super::*;
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn normalized_vec_norm_is_one(v: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn normalized_vec_norm_is_one(v in vector3()) {
|
||||||
if let Some(nv) = v.try_normalize(1.0e-10) {
|
if let Some(nv) = v.try_normalize(1.0e-10) {
|
||||||
relative_eq!(nv.norm(), 1.0, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(nv.norm(), 1.0, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalized_vec_norm_is_one_dyn(v: DVector<f64>) -> bool {
|
#[test]
|
||||||
|
fn normalized_vec_norm_is_one_dyn(v in dvector()) {
|
||||||
if let Some(nv) = v.try_normalize(1.0e-10) {
|
if let Some(nv) = v.try_normalize(1.0e-10) {
|
||||||
relative_eq!(nv.norm(), 1.0, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(nv.norm(), 1.0, epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "arbitrary", feature = "alga"))]
|
#[cfg(all(feature = "proptest-support", feature = "alga"))]
|
||||||
// TODO: move this to alga ?
|
// TODO: move this to alga ?
|
||||||
mod finite_dim_inner_space_tests {
|
mod finite_dim_inner_space_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::proptest::*;
|
||||||
use alga::linear::FiniteDimInnerSpace;
|
use alga::linear::FiniteDimInnerSpace;
|
||||||
|
use proptest::collection::vec;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
macro_rules! finite_dim_inner_space_test(
|
macro_rules! finite_dim_inner_space_test(
|
||||||
($($Vector: ident, $orthonormal_subspace: ident, $orthonormalization: ident);* $(;)*) => {$(
|
($($Vector: ident, $vstrategy: ident, $orthonormal_subspace: ident, $orthonormalization: ident);* $(;)*) => {$(
|
||||||
quickcheck!{
|
proptest! {
|
||||||
fn $orthonormal_subspace(vs: Vec<$Vector<f64>>) -> bool {
|
#[test]
|
||||||
|
fn $orthonormal_subspace(vs in vec($vstrategy(), 0..10)) {
|
||||||
let mut given_basis = vs.clone();
|
let mut given_basis = vs.clone();
|
||||||
let given_basis_dim = $Vector::orthonormalize(&mut given_basis[..]);
|
let given_basis_dim = $Vector::orthonormalize(&mut given_basis[..]);
|
||||||
let mut ortho_basis = Vec::new();
|
let mut ortho_basis = Vec::new();
|
||||||
|
@ -982,29 +976,21 @@ mod finite_dim_inner_space_tests {
|
||||||
|e| { ortho_basis.push(*e); true }
|
|e| { ortho_basis.push(*e); true }
|
||||||
);
|
);
|
||||||
|
|
||||||
if !is_subspace_basis(&ortho_basis[..]) {
|
prop_assert!(is_subspace_basis(&ortho_basis[..]));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for v in vs {
|
for v in vs {
|
||||||
for b in &ortho_basis {
|
for b in &ortho_basis {
|
||||||
if !relative_eq!(v.dot(b), 0.0, epsilon = 1.0e-7) {
|
prop_assert!(relative_eq!(v.dot(b), 0.0, epsilon = 1.0e-7));
|
||||||
println!("Found dot product: {} · {} = {}", v, b, v.dot(b));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
#[test]
|
||||||
}
|
fn $orthonormalization(vs in vec($vstrategy(), 0..10)) {
|
||||||
|
|
||||||
fn $orthonormalization(vs: Vec<$Vector<f64>>) -> bool {
|
|
||||||
let mut basis = vs.clone();
|
let mut basis = vs.clone();
|
||||||
let subdim = $Vector::orthonormalize(&mut basis[..]);
|
let subdim = $Vector::orthonormalize(&mut basis[..]);
|
||||||
|
|
||||||
if !is_subspace_basis(&basis[.. subdim]) {
|
prop_assert!(is_subspace_basis(&basis[.. subdim]));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for mut e in vs {
|
for mut e in vs {
|
||||||
for b in &basis[.. subdim] {
|
for b in &basis[.. subdim] {
|
||||||
|
@ -1012,26 +998,20 @@ mod finite_dim_inner_space_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any element of `e` must be a linear combination of the basis elements.
|
// Any element of `e` must be a linear combination of the basis elements.
|
||||||
if !relative_eq!(e.norm(), 0.0, epsilon = 1.0e-7) {
|
prop_assert!(relative_eq!(e.norm(), 0.0, epsilon = 1.0e-7));
|
||||||
println!("Orthonormalization; element decomposition failure: {}", e);
|
|
||||||
println!("... the non-zero norm is: {}", e.norm());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)*}
|
)*}
|
||||||
);
|
);
|
||||||
|
|
||||||
finite_dim_inner_space_test!(
|
finite_dim_inner_space_test!(
|
||||||
Vector1, orthonormal_subspace_basis1, orthonormalize1;
|
Vector1, vector1, orthonormal_subspace_basis1, orthonormalize1;
|
||||||
Vector2, orthonormal_subspace_basis2, orthonormalize2;
|
Vector2, vector2, orthonormal_subspace_basis2, orthonormalize2;
|
||||||
Vector3, orthonormal_subspace_basis3, orthonormalize3;
|
Vector3, vector3, orthonormal_subspace_basis3, orthonormalize3;
|
||||||
Vector4, orthonormal_subspace_basis4, orthonormalize4;
|
Vector4, vector4, orthonormal_subspace_basis4, orthonormalize4;
|
||||||
Vector5, orthonormal_subspace_basis5, orthonormalize5;
|
Vector5, vector5, orthonormal_subspace_basis5, orthonormalize5;
|
||||||
Vector6, orthonormal_subspace_basis6, orthonormalize6;
|
Vector6, vector6, orthonormal_subspace_basis6, orthonormalize6;
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1039,7 +1019,6 @@ mod finite_dim_inner_space_tests {
|
||||||
* Helper functions.
|
* Helper functions.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#[cfg(feature = "arbitrary")]
|
|
||||||
fn is_subspace_basis<T: FiniteDimInnerSpace<RealField = f64, ComplexField = f64> + Display>(
|
fn is_subspace_basis<T: FiniteDimInnerSpace<RealField = f64, ComplexField = f64> + Display>(
|
||||||
vs: &[T],
|
vs: &[T],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
|
@ -4,34 +4,32 @@
|
||||||
//! The tests here only check that the necessary trait implementations are correctly implemented,
|
//! The tests here only check that the necessary trait implementations are correctly implemented,
|
||||||
//! in addition to some sanity checks with example input.
|
//! in addition to some sanity checks with example input.
|
||||||
|
|
||||||
|
use matrixcompare::assert_matrix_eq;
|
||||||
use nalgebra::{MatrixMN, U4, U5};
|
use nalgebra::{MatrixMN, U4, U5};
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
use nalgebra::DMatrix;
|
use {
|
||||||
|
crate::proptest::*,
|
||||||
|
matrixcompare::DenseAccess,
|
||||||
|
nalgebra::DMatrix,
|
||||||
|
proptest::{prop_assert_eq, proptest},
|
||||||
|
};
|
||||||
|
|
||||||
use matrixcompare::assert_matrix_eq;
|
#[cfg(feature = "proptest-support")]
|
||||||
|
proptest! {
|
||||||
#[cfg(feature = "arbitrary")]
|
#[test]
|
||||||
use matrixcompare::DenseAccess;
|
fn fetch_single_is_equivalent_to_index_f64(matrix in dmatrix()) {
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
|
||||||
quickcheck! {
|
|
||||||
fn fetch_single_is_equivalent_to_index_f64(matrix: DMatrix<f64>) -> bool {
|
|
||||||
for i in 0 .. matrix.nrows() {
|
for i in 0 .. matrix.nrows() {
|
||||||
for j in 0 .. matrix.ncols() {
|
for j in 0 .. matrix.ncols() {
|
||||||
if matrix.fetch_single(i, j) != *matrix.index((i, j)) {
|
prop_assert_eq!(matrix.fetch_single(i, j), *matrix.index((i, j)));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
#[test]
|
||||||
}
|
fn matrixcompare_shape_agrees_with_matrix(matrix in dmatrix()) {
|
||||||
|
prop_assert_eq!(matrix.nrows(), <DMatrix<f64> as matrixcompare::Matrix<f64>>::rows(&matrix));
|
||||||
fn matrixcompare_shape_agrees_with_matrix(matrix: DMatrix<f64>) -> bool {
|
prop_assert_eq!(matrix.ncols(), <DMatrix<f64> as matrixcompare::Matrix<f64>>::cols(&matrix));
|
||||||
matrix.nrows() == <DMatrix<f64> as matrixcompare::Matrix<f64>>::rows(&matrix)
|
|
||||||
&&
|
|
||||||
matrix.ncols() == <DMatrix<f64> as matrixcompare::Matrix<f64>>::cols(&matrix)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,40 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use na::{
|
use na::{DualQuaternion, Point3, UnitDualQuaternion, Vector3};
|
||||||
DualQuaternion, Isometry3, Point3, Translation3, UnitDualQuaternion, UnitQuaternion, Vector3,
|
|
||||||
};
|
|
||||||
|
|
||||||
quickcheck!(
|
use crate::proptest::*;
|
||||||
fn isometry_equivalence(iso: Isometry3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest!(
|
||||||
|
#[test]
|
||||||
|
fn isometry_equivalence(iso in isometry3(), p in point3(), v in vector3()) {
|
||||||
let dq = UnitDualQuaternion::from_isometry(&iso);
|
let dq = UnitDualQuaternion::from_isometry(&iso);
|
||||||
|
|
||||||
relative_eq!(iso * p, dq * p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(iso * p, dq * p, epsilon = 1.0e-7));
|
||||||
&& relative_eq!(iso * v, dq * v, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(iso * v, dq * v, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse_is_identity(i: UnitDualQuaternion<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn inverse_is_identity(i in unit_dual_quaternion(), p in point3(), v in vector3()) {
|
||||||
let ii = i.inverse();
|
let ii = i.inverse();
|
||||||
|
|
||||||
relative_eq!(i * ii, UnitDualQuaternion::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(i * ii, UnitDualQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(ii * i, UnitDualQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(ii * i, UnitDualQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
|
&& relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
|
&& relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
|
&& relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((ii * i) * v, v, epsilon = 1.0e-7)
|
&& relative_eq!((ii * i) * v, v, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
#[test]
|
||||||
fn multiply_equals_alga_transform(
|
fn multiply_equals_alga_transform(
|
||||||
dq: UnitDualQuaternion<f64>,
|
dq in unit_dual_quaternion(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
dq * v == dq.transform_vector(&v)
|
prop_assert!(dq * v == dq.transform_vector(&v)
|
||||||
&& dq * p == dq.transform_point(&p)
|
&& dq * p == dq.transform_point(&p)
|
||||||
&& relative_eq!(
|
&& relative_eq!(
|
||||||
dq.inverse() * v,
|
dq.inverse() * v,
|
||||||
|
@ -41,44 +45,46 @@ quickcheck!(
|
||||||
dq.inverse() * p,
|
dq.inverse() * p,
|
||||||
dq.inverse_transform_point(&p),
|
dq.inverse_transform_point(&p),
|
||||||
epsilon = 1.0e-7
|
epsilon = 1.0e-7
|
||||||
)
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
#[test]
|
||||||
fn composition(
|
fn composition(
|
||||||
dq: UnitDualQuaternion<f64>,
|
dq in unit_dual_quaternion(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
// (rotation × dual quaternion) * point = rotation × (dual quaternion * point)
|
// (rotation × dual quaternion) * point = rotation × (dual quaternion * point)
|
||||||
relative_eq!((uq * dq) * v, uq * (dq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * dq) * v, uq * (dq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * dq) * p, uq * (dq * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * dq) * p, uq * (dq * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (dual quaternion × rotation) * point = dual quaternion × (rotation * point)
|
// (dual quaternion × rotation) * point = dual quaternion × (rotation * point)
|
||||||
relative_eq!((dq * uq) * v, dq * (uq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((dq * uq) * v, dq * (uq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((dq * uq) * p, dq * (uq * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((dq * uq) * p, dq * (uq * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × dual quaternion) * point = translation × (dual quaternion * point)
|
// (translation × dual quaternion) * point = translation × (dual quaternion * point)
|
||||||
relative_eq!((t * dq) * v, (dq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * dq) * v, (dq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * dq) * p, t * (dq * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * dq) * p, t * (dq * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (dual quaternion × translation) * point = dual quaternion × (translation * point)
|
// (dual quaternion × translation) * point = dual quaternion × (translation * point)
|
||||||
relative_eq!((dq * t) * v, dq * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((dq * t) * v, dq * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((dq * t) * p, dq * (t * p), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!((dq * t) * p, dq * (t * p), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
#[test]
|
||||||
fn all_op_exist(
|
fn all_op_exist(
|
||||||
dq: DualQuaternion<f64>,
|
dq in dual_quaternion(),
|
||||||
udq: UnitDualQuaternion<f64>,
|
udq in unit_dual_quaternion(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
s: f64,
|
s in PROPTEST_F64,
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
let dqMs: DualQuaternion<_> = dq * s;
|
let dqMs: DualQuaternion<_> = dq * s;
|
||||||
|
|
||||||
let dqMdq: DualQuaternion<_> = dq * dq;
|
let dqMdq: DualQuaternion<_> = dq * dq;
|
||||||
|
@ -145,7 +151,7 @@ quickcheck!(
|
||||||
iDuq1 /= uq;
|
iDuq1 /= uq;
|
||||||
iDuq2 /= &uq;
|
iDuq2 /= &uq;
|
||||||
|
|
||||||
dqMs == dqMs1
|
prop_assert!(dqMs == dqMs1
|
||||||
&& dqMdq == dqMdq1
|
&& dqMdq == dqMdq1
|
||||||
&& dqMdq == dqMdq2
|
&& dqMdq == dqMdq2
|
||||||
&& dqMudq == dqMudq1
|
&& dqMudq == dqMudq1
|
||||||
|
@ -199,6 +205,6 @@ quickcheck!(
|
||||||
&& uqMi == &uq * udq
|
&& uqMi == &uq * udq
|
||||||
&& uqDi == &uq / &udq
|
&& uqDi == &uq / &udq
|
||||||
&& uqDi == uq / &udq
|
&& uqDi == uq / &udq
|
||||||
&& uqDi == &uq / udq
|
&& uqDi == &uq / udq)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,67 +1,74 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use na::{
|
use na::{Isometry3, Point3, Vector3};
|
||||||
Isometry2, Isometry3, Point2, Point3, Rotation2, Rotation3, Translation2, Translation3,
|
|
||||||
UnitComplex, UnitQuaternion, Vector2, Vector3,
|
|
||||||
};
|
|
||||||
|
|
||||||
quickcheck!(
|
use crate::proptest::*;
|
||||||
fn append_rotation_wrt_point_to_id(r: UnitQuaternion<f64>, p: Point3<f64>) -> bool {
|
use proptest::{prop_assert, prop_assert_eq, proptest};
|
||||||
|
|
||||||
|
proptest!(
|
||||||
|
#[test]
|
||||||
|
fn append_rotation_wrt_point_to_id(r in unit_quaternion(), p in point3()) {
|
||||||
let mut iso = Isometry3::identity();
|
let mut iso = Isometry3::identity();
|
||||||
iso.append_rotation_wrt_point_mut(&r, &p);
|
iso.append_rotation_wrt_point_mut(&r, &p);
|
||||||
|
|
||||||
iso == Isometry3::rotation_wrt_point(r, p)
|
prop_assert_eq!(iso, Isometry3::rotation_wrt_point(r, p))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_wrt_point_invariance(r: UnitQuaternion<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_wrt_point_invariance(r in unit_quaternion(), p in point3()) {
|
||||||
let iso = Isometry3::rotation_wrt_point(r, p);
|
let iso = Isometry3::rotation_wrt_point(r, p);
|
||||||
|
|
||||||
relative_eq!(iso * p, p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(iso * p, p, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn look_at_rh_3(eye: Point3<f64>, target: Point3<f64>, up: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn look_at_rh_3(eye in point3(), target in point3(), up in vector3()) {
|
||||||
let viewmatrix = Isometry3::look_at_rh(&eye, &target, &up);
|
let viewmatrix = Isometry3::look_at_rh(&eye, &target, &up);
|
||||||
|
|
||||||
let origin = Point3::origin();
|
let origin = Point3::origin();
|
||||||
relative_eq!(viewmatrix * eye, origin, epsilon = 1.0e-7)
|
|
||||||
|
prop_assert!(relative_eq!(viewmatrix * eye, origin, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(
|
&& relative_eq!(
|
||||||
(viewmatrix * (target - eye)).normalize(),
|
(viewmatrix * (target - eye)).normalize(),
|
||||||
-Vector3::z(),
|
-Vector3::z(),
|
||||||
epsilon = 1.0e-7
|
epsilon = 1.0e-7
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn observer_frame_3(eye: Point3<f64>, target: Point3<f64>, up: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn observer_frame_3(eye in point3(), target in point3(), up in vector3()) {
|
||||||
let observer = Isometry3::face_towards(&eye, &target, &up);
|
let observer = Isometry3::face_towards(&eye, &target, &up);
|
||||||
|
|
||||||
let origin = Point3::origin();
|
let origin = Point3::origin();
|
||||||
relative_eq!(observer * origin, eye, epsilon = 1.0e-7)
|
|
||||||
|
prop_assert!(relative_eq!(observer * origin, eye, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(
|
&& relative_eq!(
|
||||||
observer * Vector3::z(),
|
observer * Vector3::z(),
|
||||||
(target - eye).normalize(),
|
(target - eye).normalize(),
|
||||||
epsilon = 1.0e-7
|
epsilon = 1.0e-7
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse_is_identity(i: Isometry3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn inverse_is_identity(i in isometry3(), p in point3(), v in vector3()) {
|
||||||
let ii = i.inverse();
|
let ii = i.inverse();
|
||||||
|
|
||||||
relative_eq!(i * ii, Isometry3::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(i * ii, Isometry3::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(ii * i, Isometry3::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(ii * i, Isometry3::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
|
&& relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
|
&& relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
|
&& relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((ii * i) * v, v, epsilon = 1.0e-7)
|
&& relative_eq!((ii * i) * v, v, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse_is_parts_inversion(t: Translation3<f64>, r: UnitQuaternion<f64>) -> bool {
|
#[test]
|
||||||
|
fn inverse_is_parts_inversion(t in translation3(), r in unit_quaternion()) {
|
||||||
let i = t * r;
|
let i = t * r;
|
||||||
i.inverse() == r.inverse() * t.inverse()
|
prop_assert!(i.inverse() == r.inverse() * t.inverse())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiply_equals_alga_transform(i: Isometry3<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
i * v == i.transform_vector(&v)
|
fn multiply_equals_alga_transform(i in isometry3(), v in vector3(), p in point3()) {
|
||||||
|
prop_assert!(i * v == i.transform_vector(&v)
|
||||||
&& i * p == i.transform_point(&p)
|
&& i * p == i.transform_point(&p)
|
||||||
&& relative_eq!(
|
&& relative_eq!(
|
||||||
i.inverse() * v,
|
i.inverse() * v,
|
||||||
|
@ -72,94 +79,97 @@ quickcheck!(
|
||||||
i.inverse() * p,
|
i.inverse() * p,
|
||||||
i.inverse_transform_point(&p),
|
i.inverse_transform_point(&p),
|
||||||
epsilon = 1.0e-7
|
epsilon = 1.0e-7
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn composition2(
|
fn composition2(
|
||||||
i: Isometry2<f64>,
|
i in isometry2(),
|
||||||
uc: UnitComplex<f64>,
|
uc in unit_complex(),
|
||||||
r: Rotation2<f64>,
|
r in rotation2(),
|
||||||
t: Translation2<f64>,
|
t in translation2(),
|
||||||
v: Vector2<f64>,
|
v in vector2(),
|
||||||
p: Point2<f64>
|
p in point2()
|
||||||
) -> bool {
|
) {
|
||||||
// (rotation × translation) * point = rotation × (translation * point)
|
// (rotation × translation) * point = rotation × (translation * point)
|
||||||
relative_eq!((uc * t) * v, uc * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uc * t) * v, uc * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((uc * t) * p, uc * (t * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uc * t) * p, uc * (t * p), epsilon = 1.0e-7));
|
||||||
relative_eq!((r * t) * p, r * (t * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((r * t) * p, r * (t * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × rotation) * point = translation × (rotation * point)
|
// (translation × rotation) * point = translation × (rotation * point)
|
||||||
(t * uc) * v == uc * v &&
|
prop_assert_eq!((t * uc) * v, uc * v);
|
||||||
(t * r) * v == r * v &&
|
prop_assert_eq!((t * r) * v, r * v);
|
||||||
(t * uc) * p == t * (uc * p) &&
|
prop_assert_eq!((t * uc) * p, t * (uc * p));
|
||||||
(t * r) * p == t * (r * p) &&
|
prop_assert_eq!((t * r) * p, t * (r * p));
|
||||||
|
|
||||||
// (rotation × isometry) * point = rotation × (isometry * point)
|
// (rotation × isometry) * point = rotation × (isometry * point)
|
||||||
relative_eq!((uc * i) * v, uc * (i * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uc * i) * v, uc * (i * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((uc * i) * p, uc * (i * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uc * i) * p, uc * (i * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × rotation) * point = isometry × (rotation * point)
|
// (isometry × rotation) * point = isometry × (rotation * point)
|
||||||
relative_eq!((i * uc) * v, i * (uc * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * uc) * v, i * (uc * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((i * uc) * p, i * (uc * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * uc) * p, i * (uc * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × isometry) * point = translation × (isometry * point)
|
// (translation × isometry) * point = translation × (isometry * point)
|
||||||
relative_eq!((t * i) * v, (i * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * i) * v, (i * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * i) * p, t * (i * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * i) * p, t * (i * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × translation) * point = isometry × (translation * point)
|
// (isometry × translation) * point = isometry × (translation * point)
|
||||||
relative_eq!((i * t) * v, i * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * t) * v, i * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn composition3(
|
fn composition3(
|
||||||
i: Isometry3<f64>,
|
i in isometry3(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
r: Rotation3<f64>,
|
r in rotation3(),
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
// (rotation × translation) * point = rotation × (translation * point)
|
// (rotation × translation) * point = rotation × (translation * point)
|
||||||
relative_eq!((uq * t) * v, uq * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * t) * v, uq * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((r * t) * v, r * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * t) * p, uq * (t * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * t) * p, uq * (t * p), epsilon = 1.0e-7));
|
||||||
relative_eq!((r * t) * p, r * (t * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((r * t) * p, r * (t * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × rotation) * point = translation × (rotation * point)
|
// (translation × rotation) * point = translation × (rotation * point)
|
||||||
(t * uq) * v == uq * v &&
|
prop_assert_eq!((t * uq) * v, uq * v);
|
||||||
(t * r) * v == r * v &&
|
prop_assert_eq!((t * r) * v, r * v);
|
||||||
(t * uq) * p == t * (uq * p) &&
|
prop_assert_eq!((t * uq) * p, t * (uq * p));
|
||||||
(t * r) * p == t * (r * p) &&
|
prop_assert_eq!((t * r) * p, t * (r * p));
|
||||||
|
|
||||||
// (rotation × isometry) * point = rotation × (isometry * point)
|
// (rotation × isometry) * point = rotation × (isometry * point)
|
||||||
relative_eq!((uq * i) * v, uq * (i * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * i) * v, uq * (i * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * i) * p, uq * (i * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * i) * p, uq * (i * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × rotation) * point = isometry × (rotation * point)
|
// (isometry × rotation) * point = isometry × (rotation * point)
|
||||||
relative_eq!((i * uq) * v, i * (uq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * uq) * v, i * (uq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((i * uq) * p, i * (uq * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * uq) * p, i * (uq * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × isometry) * point = translation × (isometry * point)
|
// (translation × isometry) * point = translation × (isometry * point)
|
||||||
relative_eq!((t * i) * v, (i * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * i) * v, (i * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * i) * p, t * (i * p), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * i) * p, t * (i * p), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × translation) * point = isometry × (translation * point)
|
// (isometry × translation) * point = isometry × (translation * point)
|
||||||
relative_eq!((i * t) * v, i * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * t) * v, i * v, epsilon = 1.0e-7));
|
||||||
relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!((i * t) * p, i * (t * p), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn all_op_exist(
|
fn all_op_exist(
|
||||||
i: Isometry3<f64>,
|
i in isometry3(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>,
|
p in point3(),
|
||||||
r: Rotation3<f64>
|
r in rotation3()
|
||||||
) -> bool {
|
) {
|
||||||
let iMi = i * i;
|
let iMi = i * i;
|
||||||
let iMuq = i * uq;
|
let iMuq = i * uq;
|
||||||
let iDi = i / i;
|
let iDi = i / i;
|
||||||
|
@ -210,7 +220,7 @@ quickcheck!(
|
||||||
iDuq1 /= uq;
|
iDuq1 /= uq;
|
||||||
iDuq2 /= &uq;
|
iDuq2 /= &uq;
|
||||||
|
|
||||||
iMt == iMt1
|
prop_assert!(iMt == iMt1
|
||||||
&& iMt == iMt2
|
&& iMt == iMt2
|
||||||
&& iMi == iMi1
|
&& iMi == iMi1
|
||||||
&& iMi == iMi2
|
&& iMi == iMi2
|
||||||
|
@ -261,6 +271,6 @@ quickcheck!(
|
||||||
&& rMt == &r * t
|
&& rMt == &r * t
|
||||||
&& uqMt == &uq * &t
|
&& uqMt == &uq * &t
|
||||||
&& uqMt == uq * &t
|
&& uqMt == uq * &t
|
||||||
&& uqMt == &uq * t
|
&& uqMt == &uq * t)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -92,11 +92,3 @@ fn to_homogeneous() {
|
||||||
|
|
||||||
assert_eq!(a.to_homogeneous(), expected);
|
assert_eq!(a.to_homogeneous(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
|
||||||
quickcheck!(
|
|
||||||
fn point_sub(pt1: Point3<f64>, pt2: Point3<f64>) -> bool {
|
|
||||||
let dpt = &pt2 - &pt1;
|
|
||||||
relative_eq!(pt2, pt1 + dpt, epsilon = 1.0e-7)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
|
@ -33,27 +33,32 @@ fn perspective_matrix_point_transformation() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
use na::{Orthographic3, Perspective3, Point3};
|
use na::{Orthographic3, Perspective3};
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn perspective_project_unproject(pt: Point3<f64>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn perspective_project_unproject(pt in point3()) {
|
||||||
let proj = Perspective3::new(800.0 / 600.0, 3.14 / 2.0, 1.0, 1000.0);
|
let proj = Perspective3::new(800.0 / 600.0, 3.14 / 2.0, 1.0, 1000.0);
|
||||||
|
|
||||||
let projected = proj.project_point(&pt);
|
let projected = proj.project_point(&pt);
|
||||||
let unprojected = proj.unproject_point(&projected);
|
let unprojected = proj.unproject_point(&projected);
|
||||||
|
|
||||||
relative_eq!(pt, unprojected, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(pt, unprojected, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn orthographic_project_unproject(pt: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn orthographic_project_unproject(pt in point3()) {
|
||||||
let proj = Orthographic3::new(1.0, 2.0, -3.0, -2.5, 10.0, 900.0);
|
let proj = Orthographic3::new(1.0, 2.0, -3.0, -2.5, 10.0, 900.0);
|
||||||
|
|
||||||
let projected = proj.project_point(&pt);
|
let projected = proj.project_point(&pt);
|
||||||
let unprojected = proj.unproject_point(&projected);
|
let unprojected = proj.unproject_point(&projected);
|
||||||
|
|
||||||
relative_eq!(pt, unprojected, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(pt, unprojected, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use na::{Point3, Quaternion, Rotation3, Unit, UnitQuaternion, Vector3};
|
use na::{Unit, UnitQuaternion};
|
||||||
|
|
||||||
quickcheck!(
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest!(
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Euler angles.
|
* Euler angles.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn from_euler_angles(r: f64, p: f64, y: f64) -> bool {
|
#[test]
|
||||||
|
fn from_euler_angles(r in PROPTEST_F64, p in PROPTEST_F64, y in PROPTEST_F64) {
|
||||||
let roll = UnitQuaternion::from_euler_angles(r, 0.0, 0.0);
|
let roll = UnitQuaternion::from_euler_angles(r, 0.0, 0.0);
|
||||||
let pitch = UnitQuaternion::from_euler_angles(0.0, p, 0.0);
|
let pitch = UnitQuaternion::from_euler_angles(0.0, p, 0.0);
|
||||||
let yaw = UnitQuaternion::from_euler_angles(0.0, 0.0, y);
|
let yaw = UnitQuaternion::from_euler_angles(0.0, 0.0, y);
|
||||||
|
@ -20,20 +24,21 @@ quickcheck!(
|
||||||
let rpitch = pitch.to_rotation_matrix();
|
let rpitch = pitch.to_rotation_matrix();
|
||||||
let ryaw = yaw.to_rotation_matrix();
|
let ryaw = yaw.to_rotation_matrix();
|
||||||
|
|
||||||
relative_eq!(rroll[(0, 0)], 1.0, epsilon = 1.0e-7) && // rotation wrt. x axis.
|
prop_assert!(relative_eq!(rroll[(0, 0)], 1.0, epsilon = 1.0e-7)); // rotation wrt. x axis.
|
||||||
relative_eq!(rpitch[(1, 1)], 1.0, epsilon = 1.0e-7) && // rotation wrt. y axis.
|
prop_assert!(relative_eq!(rpitch[(1, 1)], 1.0, epsilon = 1.0e-7)); // rotation wrt. y axis.
|
||||||
relative_eq!(ryaw[(2, 2)], 1.0, epsilon = 1.0e-7) && // rotation wrt. z axis.
|
prop_assert!(relative_eq!(ryaw[(2, 2)], 1.0, epsilon = 1.0e-7)); // rotation wrt. z axis.
|
||||||
relative_eq!(yaw * pitch * roll, rpy, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(yaw * pitch * roll, rpy, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn euler_angles(r: f64, p: f64, y: f64) -> bool {
|
#[test]
|
||||||
|
fn euler_angles(r in PROPTEST_F64, p in PROPTEST_F64, y in PROPTEST_F64) {
|
||||||
let rpy = UnitQuaternion::from_euler_angles(r, p, y);
|
let rpy = UnitQuaternion::from_euler_angles(r, p, y);
|
||||||
let (roll, pitch, yaw) = rpy.euler_angles();
|
let (roll, pitch, yaw) = rpy.euler_angles();
|
||||||
relative_eq!(
|
prop_assert!(relative_eq!(
|
||||||
UnitQuaternion::from_euler_angles(roll, pitch, yaw),
|
UnitQuaternion::from_euler_angles(roll, pitch, yaw),
|
||||||
rpy,
|
rpy,
|
||||||
epsilon = 1.0e-7
|
epsilon = 1.0e-7
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -41,12 +46,13 @@ quickcheck!(
|
||||||
* From/to rotation matrix.
|
* From/to rotation matrix.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_quaternion_rotation_conversion(q: UnitQuaternion<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_quaternion_rotation_conversion(q in unit_quaternion()) {
|
||||||
let r = q.to_rotation_matrix();
|
let r = q.to_rotation_matrix();
|
||||||
let qq = UnitQuaternion::from_rotation_matrix(&r);
|
let qq = UnitQuaternion::from_rotation_matrix(&r);
|
||||||
let rr = qq.to_rotation_matrix();
|
let rr = qq.to_rotation_matrix();
|
||||||
|
|
||||||
relative_eq!(q, qq, epsilon = 1.0e-7) && relative_eq!(r, rr, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(q, qq, epsilon = 1.0e-7) && relative_eq!(r, rr, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -55,24 +61,25 @@ quickcheck!(
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn unit_quaternion_transformation(
|
fn unit_quaternion_transformation(
|
||||||
q: UnitQuaternion<f64>,
|
q in unit_quaternion(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
let r = q.to_rotation_matrix();
|
let r = q.to_rotation_matrix();
|
||||||
let rv = r * v;
|
let rv = r * v;
|
||||||
let rp = r * p;
|
let rp = r * p;
|
||||||
|
|
||||||
relative_eq!(q * v, rv, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(q * v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(q * &v, rv, epsilon = 1.0e-7)
|
&& relative_eq!(q * &v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&q * v, rv, epsilon = 1.0e-7)
|
&& relative_eq!(&q * v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&q * &v, rv, epsilon = 1.0e-7)
|
&& relative_eq!(&q * &v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(q * p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(q * p, rp, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(q * &p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(q * &p, rp, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&q * p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(&q * p, rp, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&q * &p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(&q * &p, rp, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -80,16 +87,17 @@ quickcheck!(
|
||||||
* Inversion.
|
* Inversion.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_quaternion_inv(q: UnitQuaternion<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_quaternion_inv(q in unit_quaternion()) {
|
||||||
let iq = q.inverse();
|
let iq = q.inverse();
|
||||||
relative_eq!(&iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(&iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(iq * &q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(&iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(iq * q, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(&q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(q * &iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(&q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(q * iq, UnitQuaternion::identity(), epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -97,14 +105,15 @@ quickcheck!(
|
||||||
* Quaterion * Vector == Rotation * Vector
|
* Quaterion * Vector == Rotation * Vector
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_quaternion_mul_vector(q: UnitQuaternion<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_quaternion_mul_vector(q in unit_quaternion(), v in vector3(), p in point3()) {
|
||||||
let r = q.to_rotation_matrix();
|
let r = q.to_rotation_matrix();
|
||||||
|
|
||||||
relative_eq!(q * v, r * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(q * v, r * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(q * p, r * p, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(q * p, r * p, epsilon = 1.0e-7));
|
||||||
// Equivalence q = -q
|
// Equivalence q = -q
|
||||||
relative_eq!(UnitQuaternion::new_unchecked(-q.into_inner()) * v, r * v, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(UnitQuaternion::new_unchecked(-q.into_inner()) * v, r * v, epsilon = 1.0e-7));
|
||||||
relative_eq!(UnitQuaternion::new_unchecked(-q.into_inner()) * p, r * p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(UnitQuaternion::new_unchecked(-q.into_inner()) * p, r * p, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -112,23 +121,25 @@ quickcheck!(
|
||||||
* Unit quaternion double-covering.
|
* Unit quaternion double-covering.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_quaternion_double_covering(q: UnitQuaternion<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_quaternion_double_covering(q in unit_quaternion()) {
|
||||||
let mq = UnitQuaternion::new_unchecked(-q.into_inner());
|
let mq = UnitQuaternion::new_unchecked(-q.into_inner());
|
||||||
mq == q && mq.angle() == q.angle() && mq.axis() == q.axis()
|
prop_assert!(mq == q && mq.angle() == q.angle() && mq.axis() == q.axis())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that all operators (incl. all combinations of references) work.
|
// Test that all operators (incl. all combinations of references) work.
|
||||||
// See the top comment on `geometry/quaternion_ops.rs` for details on which operations are
|
// See the top comment on `geometry/quaternion_ops.rs` for details on which operations are
|
||||||
// supported.
|
// supported.
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn all_op_exist(
|
fn all_op_exist(
|
||||||
q: Quaternion<f64>,
|
q in quaternion(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>,
|
p in point3(),
|
||||||
r: Rotation3<f64>,
|
r in rotation3(),
|
||||||
s: f64
|
s in PROPTEST_F64
|
||||||
) -> bool {
|
) {
|
||||||
let uv = Unit::new_normalize(v);
|
let uv = Unit::new_normalize(v);
|
||||||
|
|
||||||
let qpq = q + q;
|
let qpq = q + q;
|
||||||
|
@ -196,7 +207,7 @@ quickcheck!(
|
||||||
uqDr1 /= r;
|
uqDr1 /= r;
|
||||||
uqDr2 /= &r;
|
uqDr2 /= &r;
|
||||||
|
|
||||||
qMs1 == qMs
|
prop_assert!(qMs1 == qMs
|
||||||
&& qMq1 == qMq
|
&& qMq1 == qMq
|
||||||
&& qMq1 == qMq2
|
&& qMq1 == qMq2
|
||||||
&& qpq1 == qpq
|
&& qpq1 == qpq
|
||||||
|
@ -250,6 +261,6 @@ quickcheck!(
|
||||||
&& uqMv == &uq * v
|
&& uqMv == &uq * v
|
||||||
&& uqMuv == &uq * &uv
|
&& uqMuv == &uq * &uv
|
||||||
&& uqMuv == uq * &uv
|
&& uqMuv == uq * &uv
|
||||||
&& uqMuv == &uq * uv
|
&& uqMuv == &uq * uv)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,44 +30,50 @@ fn quaternion_euler_angles_issue_494() {
|
||||||
assert_eq!(angs.2, 0.0);
|
assert_eq!(angs.2, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
use na::{self, Rotation2, Rotation3, Unit, Vector2, Vector3};
|
use na::{self, Rotation2, Rotation3, Unit};
|
||||||
use simba::scalar::RealField;
|
use simba::scalar::RealField;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, prop_assert_eq, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Euler angles.
|
* Euler angles.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn from_euler_angles(r: f64, p: f64, y: f64) -> bool {
|
#[test]
|
||||||
|
fn from_euler_angles(r in PROPTEST_F64, p in PROPTEST_F64, y in PROPTEST_F64) {
|
||||||
let roll = Rotation3::from_euler_angles(r, 0.0, 0.0);
|
let roll = Rotation3::from_euler_angles(r, 0.0, 0.0);
|
||||||
let pitch = Rotation3::from_euler_angles(0.0, p, 0.0);
|
let pitch = Rotation3::from_euler_angles(0.0, p, 0.0);
|
||||||
let yaw = Rotation3::from_euler_angles(0.0, 0.0, y);
|
let yaw = Rotation3::from_euler_angles(0.0, 0.0, y);
|
||||||
|
|
||||||
let rpy = Rotation3::from_euler_angles(r, p, y);
|
let rpy = Rotation3::from_euler_angles(r, p, y);
|
||||||
|
|
||||||
roll[(0, 0)] == 1.0 && // rotation wrt. x axis.
|
prop_assert_eq!(roll[(0, 0)], 1.0); // rotation wrt. x axis.
|
||||||
pitch[(1, 1)] == 1.0 && // rotation wrt. y axis.
|
prop_assert_eq!(pitch[(1, 1)], 1.0); // rotation wrt. y axis.
|
||||||
yaw[(2, 2)] == 1.0 && // rotation wrt. z axis.
|
prop_assert_eq!(yaw[(2, 2)], 1.0); // rotation wrt. z axis.
|
||||||
yaw * pitch * roll == rpy
|
prop_assert_eq!(yaw * pitch * roll, rpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn euler_angles(r: f64, p: f64, y: f64) -> bool {
|
#[test]
|
||||||
|
fn euler_angles(r in PROPTEST_F64, p in PROPTEST_F64, y in PROPTEST_F64) {
|
||||||
let rpy = Rotation3::from_euler_angles(r, p, y);
|
let rpy = Rotation3::from_euler_angles(r, p, y);
|
||||||
let (roll, pitch, yaw) = rpy.euler_angles();
|
let (roll, pitch, yaw) = rpy.euler_angles();
|
||||||
relative_eq!(Rotation3::from_euler_angles(roll, pitch, yaw), rpy, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(Rotation3::from_euler_angles(roll, pitch, yaw), rpy, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn euler_angles_gimble_lock(r: f64, y: f64) -> bool {
|
#[test]
|
||||||
|
fn euler_angles_gimble_lock(r in PROPTEST_F64, y in PROPTEST_F64) {
|
||||||
let pos = Rotation3::from_euler_angles(r, f64::frac_pi_2(), y);
|
let pos = Rotation3::from_euler_angles(r, f64::frac_pi_2(), y);
|
||||||
let neg = Rotation3::from_euler_angles(r, -f64::frac_pi_2(), y);
|
let neg = Rotation3::from_euler_angles(r, -f64::frac_pi_2(), y);
|
||||||
let (pos_r, pos_p, pos_y) = pos.euler_angles();
|
let (pos_r, pos_p, pos_y) = pos.euler_angles();
|
||||||
let (neg_r, neg_p, neg_y) = neg.euler_angles();
|
let (neg_r, neg_p, neg_y) = neg.euler_angles();
|
||||||
relative_eq!(Rotation3::from_euler_angles(pos_r, pos_p, pos_y), pos, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(Rotation3::from_euler_angles(pos_r, pos_p, pos_y), pos, epsilon = 1.0e-7));
|
||||||
relative_eq!(Rotation3::from_euler_angles(neg_r, neg_p, neg_y), neg, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(Rotation3::from_euler_angles(neg_r, neg_p, neg_y), neg, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -75,26 +81,28 @@ mod quickcheck_tests {
|
||||||
* Inversion is transposition.
|
* Inversion is transposition.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn rotation_inv_3(a: Rotation3<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_inv_3(a in rotation3()) {
|
||||||
let ta = a.transpose();
|
let ta = a.transpose();
|
||||||
let ia = a.inverse();
|
let ia = a.inverse();
|
||||||
|
|
||||||
ta == ia &&
|
prop_assert_eq!(ta, ia);
|
||||||
relative_eq!(&ta * &a, Rotation3::identity(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&ta * &a, Rotation3::identity(), epsilon = 1.0e-7));
|
||||||
relative_eq!(&ia * a, Rotation3::identity(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&ia * a, Rotation3::identity(), epsilon = 1.0e-7));
|
||||||
relative_eq!( a * &ta, Rotation3::identity(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!( a * &ta, Rotation3::identity(), epsilon = 1.0e-7));
|
||||||
relative_eq!( a * ia, Rotation3::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!( a * ia, Rotation3::identity(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_inv_2(a: Rotation2<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_inv_2(a in rotation2()) {
|
||||||
let ta = a.transpose();
|
let ta = a.transpose();
|
||||||
let ia = a.inverse();
|
let ia = a.inverse();
|
||||||
|
|
||||||
ta == ia &&
|
prop_assert_eq!(ta, ia);
|
||||||
relative_eq!(&ta * &a, Rotation2::identity(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&ta * &a, Rotation2::identity(), epsilon = 1.0e-7));
|
||||||
relative_eq!(&ia * a, Rotation2::identity(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&ia * a, Rotation2::identity(), epsilon = 1.0e-7));
|
||||||
relative_eq!( a * &ta, Rotation2::identity(), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!( a * &ta, Rotation2::identity(), epsilon = 1.0e-7));
|
||||||
relative_eq!( a * ia, Rotation2::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!( a * ia, Rotation2::identity(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -102,12 +110,14 @@ mod quickcheck_tests {
|
||||||
* Angle between vectors.
|
* Angle between vectors.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn angle_is_commutative_2(a: Vector2<f64>, b: Vector2<f64>) -> bool {
|
#[test]
|
||||||
a.angle(&b) == b.angle(&a)
|
fn angle_is_commutative_2(a in vector2(), b in vector2()) {
|
||||||
|
prop_assert_eq!(a.angle(&b), b.angle(&a))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn angle_is_commutative_3(a: Vector3<f64>, b: Vector3<f64>) -> bool {
|
#[test]
|
||||||
a.angle(&b) == b.angle(&a)
|
fn angle_is_commutative_3(a in vector3(), b in vector3()) {
|
||||||
|
prop_assert_eq!(a.angle(&b), b.angle(&a))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -115,50 +125,46 @@ mod quickcheck_tests {
|
||||||
* Rotation matrix between vectors.
|
* Rotation matrix between vectors.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn rotation_between_is_anticommutative_2(a: Vector2<f64>, b: Vector2<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_between_is_anticommutative_2(a in vector2(), b in vector2()) {
|
||||||
let rab = Rotation2::rotation_between(&a, &b);
|
let rab = Rotation2::rotation_between(&a, &b);
|
||||||
let rba = Rotation2::rotation_between(&b, &a);
|
let rba = Rotation2::rotation_between(&b, &a);
|
||||||
|
|
||||||
relative_eq!(rab * rba, Rotation2::identity())
|
prop_assert!(relative_eq!(rab * rba, Rotation2::identity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_between_is_anticommutative_3(a: Vector3<f64>, b: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_between_is_anticommutative_3(a in vector3(), b in vector3()) {
|
||||||
let rots = (Rotation3::rotation_between(&a, &b), Rotation3::rotation_between(&b, &a));
|
let rots = (Rotation3::rotation_between(&a, &b), Rotation3::rotation_between(&b, &a));
|
||||||
if let (Some(rab), Some(rba)) = rots {
|
if let (Some(rab), Some(rba)) = rots {
|
||||||
relative_eq!(rab * rba, Rotation3::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(rab * rba, Rotation3::identity(), epsilon = 1.0e-7));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_between_is_identity(v2: Vector2<f64>, v3: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_between_is_identity(v2 in vector2(), v3 in vector3()) {
|
||||||
let vv2 = 3.42 * v2;
|
let vv2 = 3.42 * v2;
|
||||||
let vv3 = 4.23 * v3;
|
let vv3 = 4.23 * v3;
|
||||||
|
|
||||||
relative_eq!(v2.angle(&vv2), 0.0, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(v2.angle(&vv2), 0.0, epsilon = 1.0e-7));
|
||||||
relative_eq!(v3.angle(&vv3), 0.0, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(v3.angle(&vv3), 0.0, epsilon = 1.0e-7));
|
||||||
relative_eq!(Rotation2::rotation_between(&v2, &vv2), Rotation2::identity()) &&
|
prop_assert!(relative_eq!(Rotation2::rotation_between(&v2, &vv2), Rotation2::identity()));
|
||||||
Rotation3::rotation_between(&v3, &vv3).unwrap() == Rotation3::identity()
|
prop_assert_eq!(Rotation3::rotation_between(&v3, &vv3).unwrap(), Rotation3::identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_between_2(a: Vector2<f64>, b: Vector2<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_between_2(a in vector2(), b in vector2()) {
|
||||||
if !relative_eq!(a.angle(&b), 0.0, epsilon = 1.0e-7) {
|
if !relative_eq!(a.angle(&b), 0.0, epsilon = 1.0e-7) {
|
||||||
let r = Rotation2::rotation_between(&a, &b);
|
let r = Rotation2::rotation_between(&a, &b);
|
||||||
relative_eq!((r * a).angle(&b), 0.0, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!((r * a).angle(&b), 0.0, epsilon = 1.0e-7))
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotation_between_3(a: Vector3<f64>, b: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn rotation_between_3(a in vector3(), b in vector3()) {
|
||||||
if !relative_eq!(a.angle(&b), 0.0, epsilon = 1.0e-7) {
|
if !relative_eq!(a.angle(&b), 0.0, epsilon = 1.0e-7) {
|
||||||
let r = Rotation3::rotation_between(&a, &b).unwrap();
|
let r = Rotation3::rotation_between(&a, &b).unwrap();
|
||||||
relative_eq!((r * a).angle(&b), 0.0, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!((r * a).angle(&b), 0.0, epsilon = 1.0e-7))
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,25 +174,27 @@ mod quickcheck_tests {
|
||||||
* Rotation construction.
|
* Rotation construction.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn new_rotation_2(angle: f64) -> bool {
|
#[test]
|
||||||
|
fn new_rotation_2(angle in PROPTEST_F64) {
|
||||||
let r = Rotation2::new(angle);
|
let r = Rotation2::new(angle);
|
||||||
|
|
||||||
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
||||||
relative_eq!(r.angle(), angle, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(r.angle(), angle, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_rotation_3(axisangle: Vector3<f64>) -> bool {
|
#[test]
|
||||||
|
fn new_rotation_3(axisangle in vector3()) {
|
||||||
let r = Rotation3::new(axisangle);
|
let r = Rotation3::new(axisangle);
|
||||||
|
|
||||||
if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, 0.0) {
|
if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, 0.0) {
|
||||||
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
||||||
(relative_eq!(r.angle(), angle, epsilon = 1.0e-7) &&
|
prop_assert!((relative_eq!(r.angle(), angle, epsilon = 1.0e-7) &&
|
||||||
relative_eq!(r.axis().unwrap(), axis, epsilon = 1.0e-7)) ||
|
relative_eq!(r.axis().unwrap(), axis, epsilon = 1.0e-7)) ||
|
||||||
(relative_eq!(r.angle(), -angle, epsilon = 1.0e-7) &&
|
(relative_eq!(r.angle(), -angle, epsilon = 1.0e-7) &&
|
||||||
relative_eq!(r.axis().unwrap(), -axis, epsilon = 1.0e-7))
|
relative_eq!(r.axis().unwrap(), -axis, epsilon = 1.0e-7)))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
r == Rotation3::identity()
|
prop_assert_eq!(r, Rotation3::identity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,28 +203,30 @@ mod quickcheck_tests {
|
||||||
* Rotation pow.
|
* Rotation pow.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn powf_rotation_2(angle: f64, pow: f64) -> bool {
|
#[test]
|
||||||
|
fn powf_rotation_2(angle in PROPTEST_F64, pow in PROPTEST_F64) {
|
||||||
let r = Rotation2::new(angle).powf(pow);
|
let r = Rotation2::new(angle).powf(pow);
|
||||||
|
|
||||||
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
||||||
let pangle = na::wrap(angle * pow, -f64::pi(), f64::pi());
|
let pangle = na::wrap(angle * pow, -f64::pi(), f64::pi());
|
||||||
relative_eq!(r.angle(), pangle, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(r.angle(), pangle, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn powf_rotation_3(axisangle: Vector3<f64>, pow: f64) -> bool {
|
#[test]
|
||||||
|
fn powf_rotation_3(axisangle in vector3(), pow in PROPTEST_F64) {
|
||||||
let r = Rotation3::new(axisangle).powf(pow);
|
let r = Rotation3::new(axisangle).powf(pow);
|
||||||
|
|
||||||
if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, 0.0) {
|
if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, 0.0) {
|
||||||
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
let angle = na::wrap(angle, -f64::pi(), f64::pi());
|
||||||
let pangle = na::wrap(angle * pow, -f64::pi(), f64::pi());
|
let pangle = na::wrap(angle * pow, -f64::pi(), f64::pi());
|
||||||
|
|
||||||
(relative_eq!(r.angle(), pangle, epsilon = 1.0e-7) &&
|
prop_assert!((relative_eq!(r.angle(), pangle, epsilon = 1.0e-7) &&
|
||||||
relative_eq!(r.axis().unwrap(), axis, epsilon = 1.0e-7)) ||
|
relative_eq!(r.axis().unwrap(), axis, epsilon = 1.0e-7)) ||
|
||||||
(relative_eq!(r.angle(), -pangle, epsilon = 1.0e-7) &&
|
(relative_eq!(r.angle(), -pangle, epsilon = 1.0e-7) &&
|
||||||
relative_eq!(r.axis().unwrap(), -axis, epsilon = 1.0e-7))
|
relative_eq!(r.axis().unwrap(), -axis, epsilon = 1.0e-7)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
r == Rotation3::identity()
|
prop_assert_eq!(r, Rotation3::identity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,45 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use na::{Isometry3, Point3, Similarity3, Translation3, UnitQuaternion, Vector3};
|
use na::Similarity3;
|
||||||
|
|
||||||
quickcheck!(
|
use crate::proptest::*;
|
||||||
fn inverse_is_identity(i: Similarity3<f64>, p: Point3<f64>, v: Vector3<f64>) -> bool {
|
use proptest::{prop_assert, prop_assert_eq, proptest};
|
||||||
|
|
||||||
|
proptest!(
|
||||||
|
#[test]
|
||||||
|
fn inverse_is_identity(i in similarity3(), p in point3(), v in vector3()) {
|
||||||
let ii = i.inverse();
|
let ii = i.inverse();
|
||||||
|
|
||||||
relative_eq!(i * ii, Similarity3::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(i * ii, Similarity3::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(ii * i, Similarity3::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(ii * i, Similarity3::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
|
&& relative_eq!((i * ii) * p, p, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
|
&& relative_eq!((ii * i) * p, p, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
|
&& relative_eq!((i * ii) * v, v, epsilon = 1.0e-7)
|
||||||
&& relative_eq!((ii * i) * v, v, epsilon = 1.0e-7)
|
&& relative_eq!((ii * i) * v, v, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn inverse_is_parts_inversion(
|
fn inverse_is_parts_inversion(
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
r: UnitQuaternion<f64>,
|
r in unit_quaternion(),
|
||||||
scaling: f64
|
scaling in PROPTEST_F64
|
||||||
) -> bool {
|
) {
|
||||||
if relative_eq!(scaling, 0.0) {
|
if !relative_eq!(scaling, 0.0) {
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let s = Similarity3::from_isometry(t * r, scaling);
|
let s = Similarity3::from_isometry(t * r, scaling);
|
||||||
s.inverse() == Similarity3::from_scaling(1.0 / scaling) * r.inverse() * t.inverse()
|
prop_assert_eq!(s.inverse(), Similarity3::from_scaling(1.0 / scaling) * r.inverse() * t.inverse())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn multiply_equals_alga_transform(
|
fn multiply_equals_alga_transform(
|
||||||
s: Similarity3<f64>,
|
s in similarity3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
s * v == s.transform_vector(&v)
|
prop_assert!(s * v == s.transform_vector(&v)
|
||||||
&& s * p == s.transform_point(&p)
|
&& s * p == s.transform_point(&p)
|
||||||
&& relative_eq!(
|
&& relative_eq!(
|
||||||
s.inverse() * v,
|
s.inverse() * v,
|
||||||
|
@ -46,114 +50,114 @@ quickcheck!(
|
||||||
s.inverse() * p,
|
s.inverse() * p,
|
||||||
s.inverse_transform_point(&p),
|
s.inverse_transform_point(&p),
|
||||||
epsilon = 1.0e-7
|
epsilon = 1.0e-7
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn composition(
|
fn composition(
|
||||||
i: Isometry3<f64>,
|
i in isometry3(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>,
|
p in point3(),
|
||||||
scaling: f64
|
scaling in PROPTEST_F64
|
||||||
) -> bool {
|
) {
|
||||||
if relative_eq!(scaling, 0.0) {
|
if !relative_eq!(scaling, 0.0) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let s = Similarity3::from_scaling(scaling);
|
let s = Similarity3::from_scaling(scaling);
|
||||||
|
|
||||||
// (rotation × translation × scaling) × point = rotation × (translation × (scaling × point))
|
// (rotation × translation × scaling) × point = rotation × (translation × (scaling × point))
|
||||||
relative_eq!((uq * t * s) * v, uq * (scaling * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * t * s) * v, uq * (scaling * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * t * s) * p, uq * (t * (scaling * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * t * s) * p, uq * (t * (scaling * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × rotation × scaling) × point = translation × (rotation × (scaling × point))
|
// (translation × rotation × scaling) × point = translation × (rotation × (scaling × point))
|
||||||
relative_eq!((t * uq * s) * v, uq * (scaling * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * uq * s) * v, uq * (scaling * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * uq * s) * p, t * (uq * (scaling * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * uq * s) * p, t * (uq * (scaling * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (rotation × isometry × scaling) × point = rotation × (isometry × (scaling × point))
|
// (rotation × isometry × scaling) × point = rotation × (isometry × (scaling × point))
|
||||||
relative_eq!((uq * i * s) * v, uq * (i * (scaling * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * i * s) * v, uq * (i * (scaling * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * i * s) * p, uq * (i * (scaling * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * i * s) * p, uq * (i * (scaling * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × rotation × scaling) × point = isometry × (rotation × (scaling × point))
|
// (isometry × rotation × scaling) × point = isometry × (rotation × (scaling × point))
|
||||||
relative_eq!((i * uq * s) * v, i * (uq * (scaling * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * uq * s) * v, i * (uq * (scaling * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((i * uq * s) * p, i * (uq * (scaling * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * uq * s) * p, i * (uq * (scaling * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × isometry × scaling) × point = translation × (isometry × (scaling × point))
|
// (translation × isometry × scaling) × point = translation × (isometry × (scaling × point))
|
||||||
relative_eq!((t * i * s) * v, (i * (scaling * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * i * s) * v, (i * (scaling * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * i * s) * p, t * (i * (scaling * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * i * s) * p, t * (i * (scaling * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × translation × scaling) × point = isometry × (translation × (scaling × point))
|
// (isometry × translation × scaling) × point = isometry × (translation × (scaling × point))
|
||||||
relative_eq!((i * t * s) * v, i * (scaling * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * t * s) * v, i * (scaling * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((i * t * s) * p, i * (t * (scaling * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * t * s) * p, i * (t * (scaling * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same as before but with scaling on the middle.
|
* Same as before but with scaling on the middle.
|
||||||
*/
|
*/
|
||||||
// (rotation × scaling × translation) × point = rotation × (scaling × (translation × point))
|
// (rotation × scaling × translation) × point = rotation × (scaling × (translation × point))
|
||||||
relative_eq!((uq * s * t) * v, uq * (scaling * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * s * t) * v, uq * (scaling * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * s * t) * p, uq * (scaling * (t * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * s * t) * p, uq * (scaling * (t * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × scaling × rotation) × point = translation × (scaling × (rotation × point))
|
// (translation × scaling × rotation) × point = translation × (scaling × (rotation × point))
|
||||||
relative_eq!((t * s * uq) * v, scaling * (uq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * s * uq) * v, scaling * (uq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * s * uq) * p, t * (scaling * (uq * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * s * uq) * p, t * (scaling * (uq * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (rotation × scaling × isometry) × point = rotation × (scaling × (isometry × point))
|
// (rotation × scaling × isometry) × point = rotation × (scaling × (isometry × point))
|
||||||
relative_eq!((uq * s * i) * v, uq * (scaling * (i * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * s * i) * v, uq * (scaling * (i * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((uq * s * i) * p, uq * (scaling * (i * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((uq * s * i) * p, uq * (scaling * (i * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × scaling × rotation) × point = isometry × (scaling × (rotation × point))
|
// (isometry × scaling × rotation) × point = isometry × (scaling × (rotation × point))
|
||||||
relative_eq!((i * s * uq) * v, i * (scaling * (uq * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * s * uq) * v, i * (scaling * (uq * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((i * s * uq) * p, i * (scaling * (uq * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * s * uq) * p, i * (scaling * (uq * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (translation × scaling × isometry) × point = translation × (scaling × (isometry × point))
|
// (translation × scaling × isometry) × point = translation × (scaling × (isometry × point))
|
||||||
relative_eq!((t * s * i) * v, (scaling * (i * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * s * i) * v, (scaling * (i * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((t * s * i) * p, t * (scaling * (i * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((t * s * i) * p, t * (scaling * (i * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (isometry × scaling × translation) × point = isometry × (scaling × (translation × point))
|
// (isometry × scaling × translation) × point = isometry × (scaling × (translation × point))
|
||||||
relative_eq!((i * s * t) * v, i * (scaling * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * s * t) * v, i * (scaling * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((i * s * t) * p, i * (scaling * (t * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((i * s * t) * p, i * (scaling * (t * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same as before but with scaling on the left.
|
* Same as before but with scaling on the left.
|
||||||
*/
|
*/
|
||||||
// (scaling × rotation × translation) × point = scaling × (rotation × (translation × point))
|
// (scaling × rotation × translation) × point = scaling × (rotation × (translation × point))
|
||||||
relative_eq!((s * uq * t) * v, scaling * (uq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * uq * t) * v, scaling * (uq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((s * uq * t) * p, scaling * (uq * (t * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * uq * t) * p, scaling * (uq * (t * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (scaling × translation × rotation) × point = scaling × (translation × (rotation × point))
|
// (scaling × translation × rotation) × point = scaling × (translation × (rotation × point))
|
||||||
relative_eq!((s * t * uq) * v, scaling * (uq * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * t * uq) * v, scaling * (uq * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((s * t * uq) * p, scaling * (t * (uq * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * t * uq) * p, scaling * (t * (uq * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (scaling × rotation × isometry) × point = scaling × (rotation × (isometry × point))
|
// (scaling × rotation × isometry) × point = scaling × (rotation × (isometry × point))
|
||||||
relative_eq!((s * uq * i) * v, scaling * (uq * (i * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * uq * i) * v, scaling * (uq * (i * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((s * uq * i) * p, scaling * (uq * (i * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * uq * i) * p, scaling * (uq * (i * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (scaling × isometry × rotation) × point = scaling × (isometry × (rotation × point))
|
// (scaling × isometry × rotation) × point = scaling × (isometry × (rotation × point))
|
||||||
relative_eq!((s * i * uq) * v, scaling * (i * (uq * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * i * uq) * v, scaling * (i * (uq * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((s * i * uq) * p, scaling * (i * (uq * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * i * uq) * p, scaling * (i * (uq * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (scaling × translation × isometry) × point = scaling × (translation × (isometry × point))
|
// (scaling × translation × isometry) × point = scaling × (translation × (isometry × point))
|
||||||
relative_eq!((s * t * i) * v, (scaling * (i * v)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * t * i) * v, (scaling * (i * v)), epsilon = 1.0e-7));
|
||||||
relative_eq!((s * t * i) * p, scaling * (t * (i * p)), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * t * i) * p, scaling * (t * (i * p)), epsilon = 1.0e-7));
|
||||||
|
|
||||||
// (scaling × isometry × translation) × point = scaling × (isometry × (translation × point))
|
// (scaling × isometry × translation) × point = scaling × (isometry × (translation × point))
|
||||||
relative_eq!((s * i * t) * v, scaling * (i * v), epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!((s * i * t) * v, scaling * (i * v), epsilon = 1.0e-7));
|
||||||
relative_eq!((s * i * t) * p, scaling * (i * (t * p)), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!((s * i * t) * p, scaling * (i * (t * p)), epsilon = 1.0e-7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn all_op_exist(
|
fn all_op_exist(
|
||||||
s: Similarity3<f64>,
|
s in similarity3(),
|
||||||
i: Isometry3<f64>,
|
i in isometry3(),
|
||||||
uq: UnitQuaternion<f64>,
|
uq in unit_quaternion(),
|
||||||
t: Translation3<f64>,
|
t in translation3(),
|
||||||
v: Vector3<f64>,
|
v in vector3(),
|
||||||
p: Point3<f64>
|
p in point3()
|
||||||
) -> bool {
|
) {
|
||||||
let sMs = s * s;
|
let sMs = s * s;
|
||||||
let sMuq = s * uq;
|
let sMuq = s * uq;
|
||||||
let sDs = s / s;
|
let sDs = s / s;
|
||||||
|
@ -216,7 +220,7 @@ quickcheck!(
|
||||||
sDi1 /= i;
|
sDi1 /= i;
|
||||||
sDi2 /= &i;
|
sDi2 /= &i;
|
||||||
|
|
||||||
sMt == sMt1
|
prop_assert!(sMt == sMt1
|
||||||
&& sMt == sMt2
|
&& sMt == sMt2
|
||||||
&& sMs == sMs1
|
&& sMs == sMs1
|
||||||
&& sMs == sMs2
|
&& sMs == sMs2
|
||||||
|
@ -271,6 +275,6 @@ quickcheck!(
|
||||||
&& iMs == &i * s
|
&& iMs == &i * s
|
||||||
&& iDs == &i / &s
|
&& iDs == &i / &s
|
||||||
&& iDs == i / &s
|
&& iDs == i / &s
|
||||||
&& iDs == &i / s
|
&& iDs == &i / s)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use na::{Point2, Rotation2, Unit, UnitComplex, Vector2};
|
use na::{Unit, UnitComplex};
|
||||||
|
|
||||||
quickcheck!(
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest!(
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* From/to rotation matrix.
|
* From/to rotation matrix.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_complex_rotation_conversion(c: UnitComplex<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_complex_rotation_conversion(c in unit_complex()) {
|
||||||
let r = c.to_rotation_matrix();
|
let r = c.to_rotation_matrix();
|
||||||
let cc = UnitComplex::from_rotation_matrix(&r);
|
let cc = UnitComplex::from_rotation_matrix(&r);
|
||||||
let rr = cc.to_rotation_matrix();
|
let rr = cc.to_rotation_matrix();
|
||||||
|
|
||||||
relative_eq!(c, cc, epsilon = 1.0e-7) && relative_eq!(r, rr, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(c, cc, epsilon = 1.0e-7));
|
||||||
|
prop_assert!(relative_eq!(r, rr, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -22,19 +27,20 @@ quickcheck!(
|
||||||
* Point/Vector transformation.
|
* Point/Vector transformation.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_complex_transformation(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_complex_transformation(c in unit_complex(), v in vector2(), p in point2()) {
|
||||||
let r = c.to_rotation_matrix();
|
let r = c.to_rotation_matrix();
|
||||||
let rv = r * v;
|
let rv = r * v;
|
||||||
let rp = r * p;
|
let rp = r * p;
|
||||||
|
|
||||||
relative_eq!(c * v, rv, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(c * v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(c * &v, rv, epsilon = 1.0e-7)
|
&& relative_eq!(c * &v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&c * v, rv, epsilon = 1.0e-7)
|
&& relative_eq!(&c * v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&c * &v, rv, epsilon = 1.0e-7)
|
&& relative_eq!(&c * &v, rv, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(c * p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(c * p, rp, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(c * &p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(c * &p, rp, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&c * p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(&c * p, rp, epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&c * &p, rp, epsilon = 1.0e-7)
|
&& relative_eq!(&c * &p, rp, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -42,39 +48,43 @@ quickcheck!(
|
||||||
* Inversion.
|
* Inversion.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_complex_inv(c: UnitComplex<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_complex_inv(c in unit_complex()) {
|
||||||
let iq = c.inverse();
|
let iq = c.inverse();
|
||||||
relative_eq!(&iq * &c, UnitComplex::identity(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(&iq * &c, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(iq * &c, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(iq * &c, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&iq * c, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(&iq * c, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(iq * c, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(iq * c, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&c * &iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(&c * &iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(c * &iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(c * &iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(&c * iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(&c * iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
||||||
&& relative_eq!(c * iq, UnitComplex::identity(), epsilon = 1.0e-7)
|
&& relative_eq!(c * iq, UnitComplex::identity(), epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Quaterion * Vector == Rotation * Vector
|
* Quaternion * Vector == Rotation * Vector
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fn unit_complex_mul_vector(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool {
|
#[test]
|
||||||
|
fn unit_complex_mul_vector(c in unit_complex(), v in vector2(), p in point2()) {
|
||||||
let r = c.to_rotation_matrix();
|
let r = c.to_rotation_matrix();
|
||||||
|
|
||||||
relative_eq!(c * v, r * v, epsilon = 1.0e-7) && relative_eq!(c * p, r * p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(c * v, r * v, epsilon = 1.0e-7));
|
||||||
|
prop_assert!(relative_eq!(c * p, r * p, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that all operators (incl. all combinations of references) work.
|
// Test that all operators (incl. all combinations of references) work.
|
||||||
// See the top comment on `geometry/quaternion_ops.rs` for details on which operations are
|
// See the top comment on `geometry/quaternion_ops.rs` for details on which operations are
|
||||||
// supported.
|
// supported.
|
||||||
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn all_op_exist(
|
fn all_op_exist(
|
||||||
uc: UnitComplex<f64>,
|
uc in unit_complex(),
|
||||||
v: Vector2<f64>,
|
v in vector2(),
|
||||||
p: Point2<f64>,
|
p in point2(),
|
||||||
r: Rotation2<f64>
|
r in rotation2()
|
||||||
) -> bool {
|
) {
|
||||||
let uv = Unit::new_normalize(v);
|
let uv = Unit::new_normalize(v);
|
||||||
|
|
||||||
let ucMuc = uc * uc;
|
let ucMuc = uc * uc;
|
||||||
|
@ -112,7 +122,7 @@ quickcheck!(
|
||||||
ucDr1 /= r;
|
ucDr1 /= r;
|
||||||
ucDr2 /= &r;
|
ucDr2 /= &r;
|
||||||
|
|
||||||
ucMuc1 == ucMuc
|
prop_assert!(ucMuc1 == ucMuc
|
||||||
&& ucMuc1 == ucMuc2
|
&& ucMuc1 == ucMuc2
|
||||||
&& ucMr1 == ucMr
|
&& ucMr1 == ucMr
|
||||||
&& ucMr1 == ucMr2
|
&& ucMr1 == ucMr2
|
||||||
|
@ -146,6 +156,6 @@ quickcheck!(
|
||||||
&& ucMv == &uc * v
|
&& ucMv == &uc * v
|
||||||
&& ucMuv == &uc * &uv
|
&& ucMuv == &uc * &uv
|
||||||
&& ucMuv == uc * &uv
|
&& ucMuv == uc * &uv
|
||||||
&& ucMuv == &uc * uv
|
&& ucMuv == &uc * uv)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,9 +12,6 @@ extern crate approx;
|
||||||
extern crate mint;
|
extern crate mint;
|
||||||
extern crate nalgebra as na;
|
extern crate nalgebra as na;
|
||||||
extern crate num_traits as num;
|
extern crate num_traits as num;
|
||||||
#[cfg(feature = "arbitrary")]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate quickcheck;
|
|
||||||
|
|
||||||
mod core;
|
mod core;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
|
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
use na::balancing;
|
use na::balancing;
|
||||||
use na::{DMatrix, Matrix4};
|
use na::DMatrix;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn balancing_parlett_reinsch(n: usize) -> bool {
|
use proptest::{prop_assert_eq, proptest};
|
||||||
let n = cmp::min(n, 10);
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn balancing_parlett_reinsch(n in PROPTEST_MATRIX_DIM) {
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
let mut balanced = m.clone();
|
let mut balanced = m.clone();
|
||||||
let d = balancing::balance_parlett_reinsch(&mut balanced);
|
let d = balancing::balance_parlett_reinsch(&mut balanced);
|
||||||
balancing::unbalance(&mut balanced, &d);
|
balancing::unbalance(&mut balanced, &d);
|
||||||
|
|
||||||
balanced == m
|
prop_assert_eq!(balanced, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balancing_parlett_reinsch_static(m: Matrix4<f64>) -> bool {
|
#[test]
|
||||||
|
fn balancing_parlett_reinsch_static(m in matrix4()) {
|
||||||
let mut balanced = m;
|
let mut balanced = m;
|
||||||
let d = balancing::balance_parlett_reinsch(&mut balanced);
|
let d = balancing::balance_parlett_reinsch(&mut balanced);
|
||||||
balancing::unbalance(&mut balanced, &d);
|
balancing::unbalance(&mut balanced, &d);
|
||||||
|
|
||||||
balanced == m
|
prop_assert_eq!(balanced, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,61 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{DMatrix, Matrix2, Matrix3x5, Matrix4, Matrix5x3};
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn bidiagonal(m: DMatrix<$scalar>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
if m.len() == 0 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn bidiagonal(m in dmatrix_($scalar)) {
|
||||||
let bidiagonal = m.clone().bidiagonalize();
|
let bidiagonal = m.clone().bidiagonalize();
|
||||||
let (u, d, v_t) = bidiagonal.unpack();
|
let (u, d, v_t) = bidiagonal.unpack();
|
||||||
|
|
||||||
relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bidiagonal_static_5_3(m: Matrix5x3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn bidiagonal_static_5_3(m in matrix5x3_($scalar)) {
|
||||||
let bidiagonal = m.bidiagonalize();
|
let bidiagonal = m.bidiagonalize();
|
||||||
let (u, d, v_t) = bidiagonal.unpack();
|
let (u, d, v_t) = bidiagonal.unpack();
|
||||||
|
|
||||||
relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bidiagonal_static_3_5(m: Matrix3x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn bidiagonal_static_3_5(m in matrix3x5_($scalar)) {
|
||||||
let bidiagonal = m.bidiagonalize();
|
let bidiagonal = m.bidiagonalize();
|
||||||
let (u, d, v_t) = bidiagonal.unpack();
|
let (u, d, v_t) = bidiagonal.unpack();
|
||||||
|
|
||||||
relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bidiagonal_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn bidiagonal_static_square(m in matrix4_($scalar)) {
|
||||||
let bidiagonal = m.bidiagonalize();
|
let bidiagonal = m.bidiagonalize();
|
||||||
let (u, d, v_t) = bidiagonal.unpack();
|
let (u, d, v_t) = bidiagonal.unpack();
|
||||||
|
|
||||||
relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bidiagonal_static_square_2x2(m: Matrix2<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn bidiagonal_static_square_2x2(m in matrix2_($scalar)) {
|
||||||
let bidiagonal = m.bidiagonalize();
|
let bidiagonal = m.bidiagonalize();
|
||||||
let (u, d, v_t) = bidiagonal.unpack();
|
let (u, d, v_t) = bidiagonal.unpack();
|
||||||
|
|
||||||
relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &u * d * &v_t, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64());
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bidiagonal_identity() {
|
fn bidiagonal_identity() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![cfg(all(feature = "arbitrary", feature = "debug"))]
|
#![cfg(all(feature = "proptest-support", feature = "debug"))]
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: ty) => {
|
||||||
|
@ -9,32 +9,30 @@ macro_rules! gen_tests(
|
||||||
use rand::random;
|
use rand::random;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn cholesky(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
let m = RandomSDP::new(Dynamic::new(n.max(1).min(50)), || random::<$scalar>().0).unwrap();
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn cholesky(n in PROPTEST_MATRIX_DIM) {
|
||||||
|
let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
||||||
let l = m.clone().cholesky().unwrap().unpack();
|
let l = m.clone().cholesky().unwrap().unpack();
|
||||||
relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_static(_m: RandomSDP<f64, U4>) -> bool {
|
#[test]
|
||||||
|
fn cholesky_static(_n in PROPTEST_MATRIX_DIM) {
|
||||||
let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
||||||
let chol = m.cholesky().unwrap();
|
let chol = m.cholesky().unwrap();
|
||||||
let l = chol.unpack();
|
let l = chol.unpack();
|
||||||
|
|
||||||
if !relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7) {
|
prop_assert!(relative_eq!(m, &l * l.adjoint(), epsilon = 1.0e-7));
|
||||||
false
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
let n = n.max(1).min(50);
|
fn cholesky_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
||||||
let nb = cmp::min(nb, 50); // To avoid slowing down the test too much.
|
|
||||||
|
|
||||||
let chol = m.clone().cholesky().unwrap();
|
let chol = m.clone().cholesky().unwrap();
|
||||||
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
||||||
|
@ -43,11 +41,12 @@ macro_rules! gen_tests(
|
||||||
let sol1 = chol.solve(&b1);
|
let sol1 = chol.solve(&b1);
|
||||||
let sol2 = chol.solve(&b2);
|
let sol2 = chol.solve(&b2);
|
||||||
|
|
||||||
relative_eq!(&m * &sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(&m * &sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(&m * &sol2, b2, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(&m * &sol2, b2, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_solve_static(_n: usize) -> bool {
|
#[test]
|
||||||
|
fn cholesky_solve_static(_n in PROPTEST_MATRIX_DIM) {
|
||||||
let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
||||||
let chol = m.clone().cholesky().unwrap();
|
let chol = m.clone().cholesky().unwrap();
|
||||||
let b1 = Vector4::<$scalar>::new_random().map(|e| e.0);
|
let b1 = Vector4::<$scalar>::new_random().map(|e| e.0);
|
||||||
|
@ -56,29 +55,32 @@ macro_rules! gen_tests(
|
||||||
let sol1 = chol.solve(&b1);
|
let sol1 = chol.solve(&b1);
|
||||||
let sol2 = chol.solve(&b2);
|
let sol2 = chol.solve(&b2);
|
||||||
|
|
||||||
relative_eq!(m * sol1, b1, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-7));
|
||||||
relative_eq!(m * sol2, b2, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_inverse(n: usize) -> bool {
|
#[test]
|
||||||
let m = RandomSDP::new(Dynamic::new(n.max(1).min(50)), || random::<$scalar>().0).unwrap();
|
fn cholesky_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
|
let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
||||||
let m1 = m.clone().cholesky().unwrap().inverse();
|
let m1 = m.clone().cholesky().unwrap().inverse();
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7)
|
prop_assert!(id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_inverse_static(_n: usize) -> bool {
|
#[test]
|
||||||
|
fn cholesky_inverse_static(_n in PROPTEST_MATRIX_DIM) {
|
||||||
let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
let m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
||||||
let m1 = m.clone().cholesky().unwrap().inverse();
|
let m1 = m.clone().cholesky().unwrap().inverse();
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7)
|
prop_assert!(id1.is_identity(1.0e-7) && id2.is_identity(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_rank_one_update(_n: usize) -> bool {
|
#[test]
|
||||||
|
fn cholesky_rank_one_update(_n in PROPTEST_MATRIX_DIM) {
|
||||||
let mut m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
let mut m = RandomSDP::new(U4, || random::<$scalar>().0).unwrap();
|
||||||
let x = Vector4::<$scalar>::new_random().map(|e| e.0);
|
let x = Vector4::<$scalar>::new_random().map(|e| e.0);
|
||||||
|
|
||||||
|
@ -96,10 +98,11 @@ macro_rules! gen_tests(
|
||||||
// updates m manually
|
// updates m manually
|
||||||
m.gerc(sigma_scalar, &x, &x, one); // m += sigma * x * x.adjoint()
|
m.gerc(sigma_scalar, &x, &x, one); // m += sigma * x * x.adjoint()
|
||||||
|
|
||||||
relative_eq!(m, m_chol_updated, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, m_chol_updated, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_insert_column(n: usize) -> bool {
|
#[test]
|
||||||
|
fn cholesky_insert_column(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = n.max(1).min(10);
|
let n = n.max(1).min(10);
|
||||||
let j = random::<usize>() % n;
|
let j = random::<usize>() % n;
|
||||||
let m_updated = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
let m_updated = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
||||||
|
@ -112,10 +115,11 @@ macro_rules! gen_tests(
|
||||||
let chol = m.clone().cholesky().unwrap().insert_column(j, col);
|
let chol = m.clone().cholesky().unwrap().insert_column(j, col);
|
||||||
let m_chol_updated = chol.l() * chol.l().adjoint();
|
let m_chol_updated = chol.l() * chol.l().adjoint();
|
||||||
|
|
||||||
relative_eq!(m_updated, m_chol_updated, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m_updated, m_chol_updated, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cholesky_remove_column(n: usize) -> bool {
|
#[test]
|
||||||
|
fn cholesky_remove_column(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = n.max(1).min(10);
|
let n = n.max(1).min(10);
|
||||||
let j = random::<usize>() % n;
|
let j = random::<usize>() % n;
|
||||||
let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
let m = RandomSDP::new(Dynamic::new(n), || random::<$scalar>().0).unwrap();
|
||||||
|
@ -127,7 +131,7 @@ macro_rules! gen_tests(
|
||||||
// remove column from m
|
// remove column from m
|
||||||
let m_updated = m.remove_column(j).remove_row(j);
|
let m_updated = m.remove_column(j).remove_row(j);
|
||||||
|
|
||||||
relative_eq!(m_updated, m_chol_updated, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m_updated, m_chol_updated, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,133 +22,124 @@ fn col_piv_qr() {
|
||||||
assert!(relative_eq!(m, qr, epsilon = 1.0e-7));
|
assert!(relative_eq!(m, qr, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr ,$scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{DMatrix, DVector, Matrix3x5, Matrix4, Matrix4x3, Matrix5x3, Vector4};
|
use na::{DMatrix, DVector, Matrix4x3, Vector4};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
#[allow(unused_imports)]
|
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
|
||||||
|
|
||||||
quickcheck! {
|
#[allow(unused_imports)]
|
||||||
fn col_piv_qr(m: DMatrix<$scalar>) -> bool {
|
use crate::core::helper::{RandComplex, RandScalar};
|
||||||
let m = m.map(|e| e.0);
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn col_piv_qr(m in dmatrix_($scalar)) {
|
||||||
let col_piv_qr = m.clone().col_piv_qr();
|
let col_piv_qr = m.clone().col_piv_qr();
|
||||||
let (q, r, p) = col_piv_qr.unpack();
|
let (q, r, p) = col_piv_qr.unpack();
|
||||||
let mut qr = &q * &r;
|
let mut qr = &q * &r;
|
||||||
p.inv_permute_columns(&mut qr);
|
p.inv_permute_columns(&mut qr);
|
||||||
|
|
||||||
println!("m: {}", m);
|
prop_assert!(relative_eq!(m, &qr, epsilon = 1.0e-7));
|
||||||
println!("col_piv_qr: {}", &q * &r);
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
|
|
||||||
relative_eq!(m, &qr, epsilon = 1.0e-7) &&
|
|
||||||
q.is_orthogonal(1.0e-7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_piv_qr_static_5_3(m: Matrix5x3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn col_piv_qr_static_5_3(m in matrix5x3_($scalar)) {
|
||||||
let col_piv_qr = m.col_piv_qr();
|
let col_piv_qr = m.col_piv_qr();
|
||||||
let (q, r, p) = col_piv_qr.unpack();
|
let (q, r, p) = col_piv_qr.unpack();
|
||||||
let mut qr = q * r;
|
let mut qr = q * r;
|
||||||
p.inv_permute_columns(&mut qr);
|
p.inv_permute_columns(&mut qr);
|
||||||
|
|
||||||
relative_eq!(m, qr, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m, qr, epsilon = 1.0e-7));
|
||||||
q.is_orthogonal(1.0e-7)
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_piv_qr_static_3_5(m: Matrix3x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn col_piv_qr_static_3_5(m in matrix3x5_($scalar)) {
|
||||||
let col_piv_qr = m.col_piv_qr();
|
let col_piv_qr = m.col_piv_qr();
|
||||||
let (q, r, p) = col_piv_qr.unpack();
|
let (q, r, p) = col_piv_qr.unpack();
|
||||||
let mut qr = q * r;
|
let mut qr = q * r;
|
||||||
p.inv_permute_columns(&mut qr);
|
p.inv_permute_columns(&mut qr);
|
||||||
|
|
||||||
relative_eq!(m, qr, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m, qr, epsilon = 1.0e-7));
|
||||||
q.is_orthogonal(1.0e-7)
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_piv_qr_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn col_piv_qr_static_square(m in matrix4_($scalar)) {
|
||||||
let col_piv_qr = m.col_piv_qr();
|
let col_piv_qr = m.col_piv_qr();
|
||||||
let (q, r, p) = col_piv_qr.unpack();
|
let (q, r, p) = col_piv_qr.unpack();
|
||||||
let mut qr = q * r;
|
let mut qr = q * r;
|
||||||
p.inv_permute_columns(&mut qr);
|
p.inv_permute_columns(&mut qr);
|
||||||
|
|
||||||
println!("{}{}{}{}", q, r, qr, m);
|
prop_assert!(relative_eq!(m, qr, epsilon = 1.0e-7));
|
||||||
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
relative_eq!(m, qr, epsilon = 1.0e-7) &&
|
|
||||||
q.is_orthogonal(1.0e-7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_piv_qr_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
|
fn col_piv_qr_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
if n != 0 && nb != 0 {
|
if n != 0 && nb != 0 {
|
||||||
let n = cmp::min(n, 50); // To avoid slowing down the test too much.
|
let n = cmp::min(n, 50); // To avoid slowing down the test too much.
|
||||||
let nb = cmp::min(nb, 50); // To avoid slowing down the test too much.
|
let nb = cmp::min(nb, 50); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
let col_piv_qr = m.clone().col_piv_qr();
|
let col_piv_qr = m.clone().col_piv_qr();
|
||||||
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
let b1 = DVector::<$scalar_type>::new_random(n).map(|e| e.0);
|
||||||
let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0);
|
let b2 = DMatrix::<$scalar_type>::new_random(n, nb).map(|e| e.0);
|
||||||
|
|
||||||
if col_piv_qr.is_invertible() {
|
if col_piv_qr.is_invertible() {
|
||||||
let sol1 = col_piv_qr.solve(&b1).unwrap();
|
let sol1 = col_piv_qr.solve(&b1).unwrap();
|
||||||
let sol2 = col_piv_qr.solve(&b2).unwrap();
|
let sol2 = col_piv_qr.solve(&b2).unwrap();
|
||||||
|
|
||||||
return relative_eq!(&m * sol1, b1, epsilon = 1.0e-6) &&
|
prop_assert!(relative_eq!(&m * sol1, b1, epsilon = 1.0e-6));
|
||||||
relative_eq!(&m * sol2, b2, epsilon = 1.0e-6)
|
prop_assert!(relative_eq!(&m * sol2, b2, epsilon = 1.0e-6));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn col_piv_qr_solve_static(m in matrix4_($scalar)) {
|
||||||
|
|
||||||
fn col_piv_qr_solve_static(m: Matrix4<$scalar>) -> bool {
|
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
let col_piv_qr = m.col_piv_qr();
|
let col_piv_qr = m.col_piv_qr();
|
||||||
let b1 = Vector4::<$scalar>::new_random().map(|e| e.0);
|
let b1 = Vector4::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0);
|
let b2 = Matrix4x3::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
|
|
||||||
if col_piv_qr.is_invertible() {
|
if col_piv_qr.is_invertible() {
|
||||||
let sol1 = col_piv_qr.solve(&b1).unwrap();
|
let sol1 = col_piv_qr.solve(&b1).unwrap();
|
||||||
let sol2 = col_piv_qr.solve(&b2).unwrap();
|
let sol2 = col_piv_qr.solve(&b2).unwrap();
|
||||||
|
|
||||||
relative_eq!(m * sol1, b1, epsilon = 1.0e-6) &&
|
prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-6));
|
||||||
relative_eq!(m * sol2, b2, epsilon = 1.0e-6)
|
prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-6));
|
||||||
}
|
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_piv_qr_inverse(n: usize) -> bool {
|
#[test]
|
||||||
|
fn col_piv_qr_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
if let Some(m1) = m.clone().col_piv_qr().try_inverse() {
|
if let Some(m1) = m.clone().col_piv_qr().try_inverse() {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
}
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_piv_qr_inverse_static(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn col_piv_qr_inverse_static(m in matrix4_($scalar)) {
|
||||||
let col_piv_qr = m.col_piv_qr();
|
let col_piv_qr = m.col_piv_qr();
|
||||||
|
|
||||||
if let Some(m1) = col_piv_qr.try_inverse() {
|
if let Some(m1) = col_piv_qr.try_inverse() {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
}
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +147,6 @@ mod quickcheck_tests {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,74 @@
|
||||||
use na::DMatrix;
|
use na::DMatrix;
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{DMatrix, Matrix2, Matrix3, Matrix4};
|
use na::DMatrix;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn symmetric_eigen(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn symmetric_eigen(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 10));
|
let n = cmp::max(1, cmp::min(n, 10));
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part();
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0).hermitian_part();
|
||||||
let eig = m.clone().symmetric_eigen();
|
let eig = m.clone().symmetric_eigen();
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symmetric_eigen_singular(n: usize) -> bool {
|
#[test]
|
||||||
|
fn symmetric_eigen_singular(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 10));
|
let n = cmp::max(1, cmp::min(n, 10));
|
||||||
let mut m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part();
|
let mut m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0).hermitian_part();
|
||||||
m.row_mut(n / 2).fill(na::zero());
|
m.row_mut(n / 2).fill(na::zero());
|
||||||
m.column_mut(n / 2).fill(na::zero());
|
m.column_mut(n / 2).fill(na::zero());
|
||||||
let eig = m.clone().symmetric_eigen();
|
let eig = m.clone().symmetric_eigen();
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symmetric_eigen_static_square_4x4(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0).hermitian_part();
|
fn symmetric_eigen_static_square_4x4(m in matrix4_($scalar)) {
|
||||||
|
let m = m.hermitian_part();
|
||||||
let eig = m.symmetric_eigen();
|
let eig = m.symmetric_eigen();
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symmetric_eigen_static_square_3x3(m: Matrix3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0).hermitian_part();
|
fn symmetric_eigen_static_square_3x3(m in matrix3_($scalar)) {
|
||||||
|
let m = m.hermitian_part();
|
||||||
let eig = m.symmetric_eigen();
|
let eig = m.symmetric_eigen();
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symmetric_eigen_static_square_2x2(m: Matrix2<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0).hermitian_part();
|
fn symmetric_eigen_static_square_2x2(m in matrix2_($scalar)) {
|
||||||
|
let m = m.hermitian_part();
|
||||||
let eig = m.symmetric_eigen();
|
let eig = m.symmetric_eigen();
|
||||||
let recomp = eig.recompose();
|
let recomp = eig.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test proposed on the issue #176 of rulinalg.
|
// Test proposed on the issue #176 of rulinalg.
|
||||||
|
|
|
@ -71,7 +71,6 @@ mod tests {
|
||||||
let m22 = ad_2.exp() * (delta * delta_2.cosh() + (d - a) * delta_2.sinh());
|
let m22 = ad_2.exp() * (delta * delta_2.cosh() + (d - a) * delta_2.sinh());
|
||||||
|
|
||||||
let f = Matrix2::new(m11, m12, m21, m22) / delta;
|
let f = Matrix2::new(m11, m12, m21, m22) / delta;
|
||||||
println!("a: {}", m);
|
|
||||||
assert!(relative_eq!(f, m.exp(), epsilon = 1.0e-7));
|
assert!(relative_eq!(f, m.exp(), epsilon = 1.0e-7));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,101 +40,96 @@ fn full_piv_lu_simple_with_pivot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use num::One;
|
use num::One;
|
||||||
use na::{DMatrix, Matrix4, Matrix4x3, Matrix5x3, Matrix3x5, DVector, Vector4};
|
use na::{DMatrix, Matrix4x3, DVector, Vector4};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn full_piv_lu(m: DMatrix<$scalar>) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
let mut m = m.map(|e| e.0);
|
|
||||||
if m.len() == 0 {
|
|
||||||
m = DMatrix::<$scalar>::new_random(1, 1).map(|e| e.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn full_piv_lu(m in dmatrix_($scalar)) {
|
||||||
let lu = m.clone().full_piv_lu();
|
let lu = m.clone().full_piv_lu();
|
||||||
let (p, l, u, q) = lu.unpack();
|
let (p, l, u, q) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
q.inv_permute_columns(&mut lu);
|
q.inv_permute_columns(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_piv_lu_static_3_5(m: Matrix3x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn full_piv_lu_static_3_5(m in matrix3x5_($scalar)) {
|
||||||
let lu = m.full_piv_lu();
|
let lu = m.full_piv_lu();
|
||||||
let (p, l, u, q) = lu.unpack();
|
let (p, l, u, q) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
q.inv_permute_columns(&mut lu);
|
q.inv_permute_columns(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_piv_lu_static_5_3(m: Matrix5x3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn full_piv_lu_static_5_3(m in matrix5x3_($scalar)) {
|
||||||
let lu = m.full_piv_lu();
|
let lu = m.full_piv_lu();
|
||||||
let (p, l, u, q) = lu.unpack();
|
let (p, l, u, q) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
q.inv_permute_columns(&mut lu);
|
q.inv_permute_columns(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_piv_lu_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn full_piv_lu_static_square(m in matrix4_($scalar)) {
|
||||||
let lu = m.full_piv_lu();
|
let lu = m.full_piv_lu();
|
||||||
let (p, l, u, q) = lu.unpack();
|
let (p, l, u, q) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
q.inv_permute_columns(&mut lu);
|
q.inv_permute_columns(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_piv_lu_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
if n != 0 && nb != 0 {
|
fn full_piv_lu_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 50); // To avoid slowing down the test too much.
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
let nb = cmp::min(nb, 50); // To avoid slowing down the test too much.
|
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
|
||||||
|
|
||||||
let lu = m.clone().full_piv_lu();
|
let lu = m.clone().full_piv_lu();
|
||||||
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
let b1 = DVector::<$scalar_type>::new_random(n).map(|e| e.0);
|
||||||
let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0);
|
let b2 = DMatrix::<$scalar_type>::new_random(n, nb).map(|e| e.0);
|
||||||
|
|
||||||
let sol1 = lu.solve(&b1);
|
let sol1 = lu.solve(&b1);
|
||||||
let sol2 = lu.solve(&b2);
|
let sol2 = lu.solve(&b2);
|
||||||
|
|
||||||
return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) &&
|
prop_assert!(sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6));
|
||||||
(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6))
|
prop_assert!(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn full_piv_lu_solve_static(m in matrix4_($scalar)) {
|
||||||
|
|
||||||
fn full_piv_lu_solve_static(m: Matrix4<$scalar>) -> bool {
|
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
let lu = m.full_piv_lu();
|
let lu = m.full_piv_lu();
|
||||||
let b1 = Vector4::<$scalar>::new_random().map(|e| e.0);
|
let b1 = Vector4::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0);
|
let b2 = Matrix4x3::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
|
|
||||||
let sol1 = lu.solve(&b1);
|
let sol1 = lu.solve(&b1);
|
||||||
let sol2 = lu.solve(&b2);
|
let sol2 = lu.solve(&b2);
|
||||||
|
|
||||||
return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) &&
|
prop_assert!(sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6));
|
||||||
(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6))
|
prop_assert!(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_piv_lu_inverse(n: usize) -> bool {
|
#[test]
|
||||||
|
fn full_piv_lu_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
let mut l = m.lower_triangle();
|
let mut l = m.lower_triangle();
|
||||||
let mut u = m.upper_triangle();
|
let mut u = m.upper_triangle();
|
||||||
|
@ -148,21 +143,20 @@ mod quickcheck_tests {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
return id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5);
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_piv_lu_inverse_static(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn full_piv_lu_inverse_static(m in matrix4_($scalar)) {
|
||||||
let lu = m.full_piv_lu();
|
let lu = m.full_piv_lu();
|
||||||
|
|
||||||
if let Some(m1) = lu.try_inverse() {
|
if let Some(m1) = lu.try_inverse() {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
}
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,8 +164,8 @@ mod quickcheck_tests {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
|
|
||||||
use na::Matrix2;
|
use na::Matrix2;
|
||||||
|
|
||||||
|
@ -11,40 +11,41 @@ fn hessenberg_simple() {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{DMatrix, Matrix2, Matrix4};
|
use na::DMatrix;
|
||||||
use std::cmp;
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
|
||||||
quickcheck! {
|
use crate::proptest::*;
|
||||||
fn hessenberg(n: usize) -> bool {
|
use proptest::{prop_assert, proptest};
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn hessenberg(n in PROPTEST_MATRIX_DIM) {
|
||||||
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
let hess = m.clone().hessenberg();
|
let hess = m.clone().hessenberg();
|
||||||
let (p, h) = hess.unpack();
|
let (p, h) = hess.unpack();
|
||||||
relative_eq!(m, &p * h * p.adjoint(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, &p * h * p.adjoint(), epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hessenberg_static_mat2(m: Matrix2<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn hessenberg_static_mat2(m in matrix2_($scalar)) {
|
||||||
let hess = m.hessenberg();
|
let hess = m.hessenberg();
|
||||||
let (p, h) = hess.unpack();
|
let (p, h) = hess.unpack();
|
||||||
relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hessenberg_static(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn hessenberg_static(m in matrix4_($scalar)) {
|
||||||
let hess = m.hessenberg();
|
let hess = m.hessenberg();
|
||||||
let (p, h) = hess.unpack();
|
let (p, h) = hess.unpack();
|
||||||
relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, p * h * p.adjoint(), epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
|
|
|
@ -38,103 +38,88 @@ fn lu_simple_with_pivot() {
|
||||||
assert!(relative_eq!(m, lu, epsilon = 1.0e-7));
|
assert!(relative_eq!(m, lu, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
#[allow(unused_imports)]
|
|
||||||
use crate::core::helper::{RandComplex, RandScalar};
|
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use std::cmp;
|
use na::{DMatrix, Matrix4x3, DVector, Vector4};
|
||||||
use na::{DMatrix, Matrix4, Matrix4x3, Matrix5x3, Matrix3x5, DVector, Vector4};
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn lu(m: DMatrix<$scalar>) -> bool {
|
#[test]
|
||||||
let mut m = m;
|
fn lu(m in dmatrix_($scalar)) {
|
||||||
if m.len() == 0 {
|
|
||||||
m = DMatrix::<$scalar>::new_random(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
|
|
||||||
let lu = m.clone().lu();
|
let lu = m.clone().lu();
|
||||||
let (p, l, u) = lu.unpack();
|
let (p, l, u) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_static_3_5(m: Matrix3x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn lu_static_3_5(m in matrix3x5_($scalar)) {
|
||||||
let lu = m.lu();
|
let lu = m.lu();
|
||||||
let (p, l, u) = lu.unpack();
|
let (p, l, u) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_static_5_3(m: Matrix5x3<$scalar>) -> bool {
|
fn lu_static_5_3(m in matrix5x3_($scalar)) {
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
let lu = m.lu();
|
let lu = m.lu();
|
||||||
let (p, l, u) = lu.unpack();
|
let (p, l, u) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn lu_static_square(m in matrix4_($scalar)) {
|
||||||
let lu = m.lu();
|
let lu = m.lu();
|
||||||
let (p, l, u) = lu.unpack();
|
let (p, l, u) = lu.unpack();
|
||||||
let mut lu = l * u;
|
let mut lu = l * u;
|
||||||
p.inv_permute_rows(&mut lu);
|
p.inv_permute_rows(&mut lu);
|
||||||
|
|
||||||
relative_eq!(m, lu, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, lu, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
if n != 0 && nb != 0 {
|
fn lu_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 50); // To avoid slowing down the test too much.
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
let nb = cmp::min(nb, 50); // To avoid slowing down the test too much.
|
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
|
||||||
|
|
||||||
let lu = m.clone().lu();
|
let lu = m.clone().lu();
|
||||||
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
let b1 = DVector::<$scalar_type>::new_random(n).map(|e| e.0);
|
||||||
let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0);
|
let b2 = DMatrix::<$scalar_type>::new_random(n, nb).map(|e| e.0);
|
||||||
|
|
||||||
let sol1 = lu.solve(&b1);
|
let sol1 = lu.solve(&b1);
|
||||||
let sol2 = lu.solve(&b2);
|
let sol2 = lu.solve(&b2);
|
||||||
|
|
||||||
return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) &&
|
prop_assert!(sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6));
|
||||||
(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6))
|
prop_assert!(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn lu_solve_static(m in matrix4_($scalar)) {
|
||||||
|
|
||||||
fn lu_solve_static(m: Matrix4<$scalar>) -> bool {
|
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
let lu = m.lu();
|
let lu = m.lu();
|
||||||
let b1 = Vector4::<$scalar>::new_random().map(|e| e.0);
|
let b1 = Vector4::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0);
|
let b2 = Matrix4x3::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
|
|
||||||
let sol1 = lu.solve(&b1);
|
let sol1 = lu.solve(&b1);
|
||||||
let sol2 = lu.solve(&b2);
|
let sol2 = lu.solve(&b2);
|
||||||
|
|
||||||
return (sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6)) &&
|
prop_assert!(sol1.is_none() || relative_eq!(&m * sol1.unwrap(), b1, epsilon = 1.0e-6));
|
||||||
(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6))
|
prop_assert!(sol2.is_none() || relative_eq!(&m * sol2.unwrap(), b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_inverse(n: usize) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
fn lu_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
let mut l = m.lower_triangle();
|
let mut l = m.lower_triangle();
|
||||||
let mut u = m.upper_triangle();
|
let mut u = m.upper_triangle();
|
||||||
|
|
||||||
|
@ -147,21 +132,20 @@ mod quickcheck_tests {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
return id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5);
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lu_inverse_static(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn lu_inverse_static(m in matrix4_($scalar)) {
|
||||||
let lu = m.lu();
|
let lu = m.lu();
|
||||||
|
|
||||||
if let Some(m1) = lu.try_inverse() {
|
if let Some(m1) = lu.try_inverse() {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
}
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +153,6 @@ mod quickcheck_tests {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,126 +1,112 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{DMatrix, DVector, Matrix3x5, Matrix4, Matrix4x3, Matrix5x3, Vector4};
|
use na::{DMatrix, DVector, Matrix4x3, Vector4};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn qr(m: DMatrix<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn qr(m in dmatrix_($scalar)) {
|
||||||
let qr = m.clone().qr();
|
let qr = m.clone().qr();
|
||||||
let q = qr.q();
|
let q = qr.q();
|
||||||
let r = qr.r();
|
let r = qr.r();
|
||||||
|
|
||||||
println!("m: {}", m);
|
prop_assert!(relative_eq!(m, &q * r, epsilon = 1.0e-7));
|
||||||
println!("qr: {}", &q * &r);
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
|
|
||||||
relative_eq!(m, &q * r, epsilon = 1.0e-7) &&
|
|
||||||
q.is_orthogonal(1.0e-7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_static_5_3(m: Matrix5x3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn qr_static_5_3(m in matrix5x3_($scalar)) {
|
||||||
let qr = m.qr();
|
let qr = m.qr();
|
||||||
let q = qr.q();
|
let q = qr.q();
|
||||||
let r = qr.r();
|
let r = qr.r();
|
||||||
|
|
||||||
relative_eq!(m, q * r, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7));
|
||||||
q.is_orthogonal(1.0e-7)
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_static_3_5(m: Matrix3x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn qr_static_3_5(m in matrix3x5_($scalar)) {
|
||||||
let qr = m.qr();
|
let qr = m.qr();
|
||||||
let q = qr.q();
|
let q = qr.q();
|
||||||
let r = qr.r();
|
let r = qr.r();
|
||||||
|
|
||||||
relative_eq!(m, q * r, epsilon = 1.0e-7) &&
|
prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7));
|
||||||
q.is_orthogonal(1.0e-7)
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn qr_static_square(m in matrix4_($scalar)) {
|
||||||
let qr = m.qr();
|
let qr = m.qr();
|
||||||
let q = qr.q();
|
let q = qr.q();
|
||||||
let r = qr.r();
|
let r = qr.r();
|
||||||
|
|
||||||
println!("{}{}{}{}", q, r, q * r, m);
|
prop_assert!(relative_eq!(m, q * r, epsilon = 1.0e-7));
|
||||||
|
prop_assert!(q.is_orthogonal(1.0e-7));
|
||||||
relative_eq!(m, q * r, epsilon = 1.0e-7) &&
|
|
||||||
q.is_orthogonal(1.0e-7)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
if n != 0 && nb != 0 {
|
fn qr_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::min(n, 50); // To avoid slowing down the test too much.
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
let nb = cmp::min(nb, 50); // To avoid slowing down the test too much.
|
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
|
||||||
|
|
||||||
let qr = m.clone().qr();
|
let qr = m.clone().qr();
|
||||||
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
let b1 = DVector::<$scalar_type>::new_random(n).map(|e| e.0);
|
||||||
let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0);
|
let b2 = DMatrix::<$scalar_type>::new_random(n, nb).map(|e| e.0);
|
||||||
|
|
||||||
if qr.is_invertible() {
|
if qr.is_invertible() {
|
||||||
let sol1 = qr.solve(&b1).unwrap();
|
let sol1 = qr.solve(&b1).unwrap();
|
||||||
let sol2 = qr.solve(&b2).unwrap();
|
let sol2 = qr.solve(&b2).unwrap();
|
||||||
|
|
||||||
return relative_eq!(&m * sol1, b1, epsilon = 1.0e-6) &&
|
prop_assert!(relative_eq!(&m * sol1, b1, epsilon = 1.0e-6));
|
||||||
relative_eq!(&m * sol2, b2, epsilon = 1.0e-6)
|
prop_assert!(relative_eq!(&m * sol2, b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
#[test]
|
||||||
}
|
fn qr_solve_static(m in matrix4_($scalar)) {
|
||||||
|
|
||||||
fn qr_solve_static(m: Matrix4<$scalar>) -> bool {
|
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
let qr = m.qr();
|
let qr = m.qr();
|
||||||
let b1 = Vector4::<$scalar>::new_random().map(|e| e.0);
|
let b1 = Vector4::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
let b2 = Matrix4x3::<$scalar>::new_random().map(|e| e.0);
|
let b2 = Matrix4x3::<$scalar_type>::new_random().map(|e| e.0);
|
||||||
|
|
||||||
if qr.is_invertible() {
|
if qr.is_invertible() {
|
||||||
let sol1 = qr.solve(&b1).unwrap();
|
let sol1 = qr.solve(&b1).unwrap();
|
||||||
let sol2 = qr.solve(&b2).unwrap();
|
let sol2 = qr.solve(&b2).unwrap();
|
||||||
|
|
||||||
relative_eq!(m * sol1, b1, epsilon = 1.0e-6) &&
|
prop_assert!(relative_eq!(m * sol1, b1, epsilon = 1.0e-6));
|
||||||
relative_eq!(m * sol2, b2, epsilon = 1.0e-6)
|
prop_assert!(relative_eq!(m * sol2, b2, epsilon = 1.0e-6));
|
||||||
}
|
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_inverse(n: usize) -> bool {
|
#[test]
|
||||||
|
fn qr_inverse(n in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
let n = cmp::max(1, cmp::min(n, 15)); // To avoid slowing down the test too much.
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
if let Some(m1) = m.clone().qr().try_inverse() {
|
if let Some(m1) = m.clone().qr().try_inverse() {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
}
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qr_inverse_static(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn qr_inverse_static(m in matrix4_($scalar)) {
|
||||||
let qr = m.qr();
|
let qr = m.qr();
|
||||||
|
|
||||||
if let Some(m1) = qr.try_inverse() {
|
if let Some(m1) = qr.try_inverse() {
|
||||||
let id1 = &m * &m1;
|
let id1 = &m * &m1;
|
||||||
let id2 = &m1 * &m;
|
let id2 = &m1 * &m;
|
||||||
|
|
||||||
id1.is_identity(1.0e-5) && id2.is_identity(1.0e-5)
|
prop_assert!(id1.is_identity(1.0e-5));
|
||||||
}
|
prop_assert!(id2.is_identity(1.0e-5));
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,5 +114,5 @@ macro_rules! gen_tests(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
|
|
|
@ -13,72 +13,49 @@ fn schur_simpl_mat3() {
|
||||||
assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7));
|
assert!(relative_eq!(vecs * vals * vecs.transpose(), m, epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use std::cmp;
|
use na::DMatrix;
|
||||||
use na::{DMatrix, Matrix2, Matrix3, Matrix4};
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn schur(n: usize) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 10));
|
fn schur(n in PROPTEST_MATRIX_DIM) {
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
let (vecs, vals) = m.clone().schur().unpack();
|
let (vecs, vals) = m.clone().schur().unpack();
|
||||||
|
prop_assert!(relative_eq!(&vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7));
|
||||||
if !relative_eq!(&vecs * &vals * vecs.adjoint(), m, epsilon = 1.0e-7) {
|
|
||||||
println!("{:.5}{:.5}", m, &vecs * &vals * vecs.adjoint());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
relative_eq!(&vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7)
|
#[test]
|
||||||
}
|
fn schur_static_mat2(m in matrix2_($scalar)) {
|
||||||
|
|
||||||
fn schur_static_mat2(m: Matrix2<$scalar>) -> bool {
|
|
||||||
let m = m.map(|e| e.0);
|
|
||||||
let (vecs, vals) = m.clone().schur().unpack();
|
let (vecs, vals) = m.clone().schur().unpack();
|
||||||
|
prop_assert!(relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7));
|
||||||
let ok = relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7);
|
|
||||||
if !ok {
|
|
||||||
println!("Vecs: {:.5} Vals: {:.5}", vecs, vals);
|
|
||||||
println!("Reconstruction:{}{}", m, &vecs * &vals * vecs.adjoint());
|
|
||||||
}
|
|
||||||
ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schur_static_mat3(m: Matrix3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn schur_static_mat3(m in matrix3_($scalar)) {
|
||||||
let (vecs, vals) = m.clone().schur().unpack();
|
let (vecs, vals) = m.clone().schur().unpack();
|
||||||
|
prop_assert!(relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7));
|
||||||
let ok = relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7);
|
|
||||||
if !ok {
|
|
||||||
println!("Vecs: {:.5} Vals: {:.5}", vecs, vals);
|
|
||||||
println!("{:.5}{:.5}", m, &vecs * &vals * vecs.adjoint());
|
|
||||||
}
|
|
||||||
ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schur_static_mat4(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn schur_static_mat4(m in matrix4_($scalar)) {
|
||||||
let (vecs, vals) = m.clone().schur().unpack();
|
let (vecs, vals) = m.clone().schur().unpack();
|
||||||
|
prop_assert!(relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7));
|
||||||
let ok = relative_eq!(vecs * vals * vecs.adjoint(), m, epsilon = 1.0e-7);
|
|
||||||
if !ok {
|
|
||||||
println!("{:.5}{:.5}", m, &vecs * &vals * vecs.adjoint());
|
|
||||||
}
|
|
||||||
|
|
||||||
ok
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{Matrix4, Matrix4x5, ComplexField};
|
use na::{Matrix4, ComplexField};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
fn unzero_diagonal<N: ComplexField>(a: &mut Matrix4<N>) {
|
fn unzero_diagonal<N: ComplexField>(a: &mut Matrix4<N>) {
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
|
@ -15,50 +17,50 @@ macro_rules! gen_tests(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn solve_lower_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool {
|
#[test]
|
||||||
let b = b.map(|e| e.0);
|
fn solve_lower_triangular(a in matrix4_($scalar), b in matrix4x5_($scalar)) {
|
||||||
let mut a = a.map(|e| e.0);
|
let mut a = a;
|
||||||
unzero_diagonal(&mut a);
|
unzero_diagonal(&mut a);
|
||||||
let tri = a.lower_triangle();
|
let tri = a.lower_triangle();
|
||||||
let x = a.solve_lower_triangular(&b).unwrap();
|
let x = a.solve_lower_triangular(&b).unwrap();
|
||||||
|
|
||||||
relative_eq!(tri * x, b, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(tri * x, b, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve_upper_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool {
|
#[test]
|
||||||
let b = b.map(|e| e.0);
|
fn solve_upper_triangular(a in matrix4_($scalar), b in matrix4x5_($scalar)) {
|
||||||
let mut a = a.map(|e| e.0);
|
let mut a = a;
|
||||||
unzero_diagonal(&mut a);
|
unzero_diagonal(&mut a);
|
||||||
let tri = a.upper_triangle();
|
let tri = a.upper_triangle();
|
||||||
let x = a.solve_upper_triangular(&b).unwrap();
|
let x = a.solve_upper_triangular(&b).unwrap();
|
||||||
|
|
||||||
relative_eq!(tri * x, b, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(tri * x, b, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tr_solve_lower_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool {
|
#[test]
|
||||||
let b = b.map(|e| e.0);
|
fn tr_solve_lower_triangular(a in matrix4_($scalar), b in matrix4x5_($scalar)) {
|
||||||
let mut a = a.map(|e| e.0);
|
let mut a = a;
|
||||||
unzero_diagonal(&mut a);
|
unzero_diagonal(&mut a);
|
||||||
let tri = a.lower_triangle();
|
let tri = a.lower_triangle();
|
||||||
let x = a.tr_solve_lower_triangular(&b).unwrap();
|
let x = a.tr_solve_lower_triangular(&b).unwrap();
|
||||||
|
|
||||||
relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tr_solve_upper_triangular(a: Matrix4<$scalar>, b: Matrix4x5<$scalar>) -> bool {
|
#[test]
|
||||||
let b = b.map(|e| e.0);
|
fn tr_solve_upper_triangular(a in matrix4_($scalar), b in matrix4x5_($scalar)) {
|
||||||
let mut a = a.map(|e| e.0);
|
let mut a = a;
|
||||||
unzero_diagonal(&mut a);
|
unzero_diagonal(&mut a);
|
||||||
let tri = a.upper_triangle();
|
let tri = a.upper_triangle();
|
||||||
let x = a.tr_solve_upper_triangular(&b).unwrap();
|
let x = a.tr_solve_upper_triangular(&b).unwrap();
|
||||||
|
|
||||||
relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(tri.transpose() * x, b, epsilon = 1.0e-7))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64());
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64);
|
||||||
|
|
|
@ -1,162 +1,143 @@
|
||||||
use na::{DMatrix, Matrix6};
|
use na::{DMatrix, Matrix6};
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr, $scalar_type: ty) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{
|
use na::{
|
||||||
DMatrix, DVector, Matrix2, Matrix2x5, Matrix3, Matrix3x5, Matrix4, Matrix5x2, Matrix5x3,
|
DMatrix, DVector, Matrix2, Matrix3, Matrix4,
|
||||||
ComplexField
|
ComplexField
|
||||||
};
|
};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn svd(m: DMatrix<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd(m in dmatrix_($scalar)) {
|
||||||
if m.len() > 0 {
|
|
||||||
let svd = m.clone().svd(true, true);
|
let svd = m.clone().svd(true, true);
|
||||||
let recomp_m = svd.clone().recompose().unwrap();
|
let recomp_m = svd.clone().recompose().unwrap();
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
let ds = DMatrix::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = DMatrix::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(&u * ds * &v_t, recomp_m, epsilon = 1.0e-5) &&
|
prop_assert!(relative_eq!(&u * ds * &v_t, recomp_m, epsilon = 1.0e-5));
|
||||||
relative_eq!(m, recomp_m, epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m, recomp_m, epsilon = 1.0e-5));
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static_5_3(m: Matrix5x3<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_static_5_3(m in matrix5x3_($scalar)) {
|
||||||
let svd = m.svd(true, true);
|
let svd = m.svd(true, true);
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
let ds = Matrix3::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = Matrix3::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5) &&
|
prop_assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5));
|
||||||
u.is_orthogonal(1.0e-5) &&
|
prop_assert!(u.is_orthogonal(1.0e-5));
|
||||||
v_t.is_orthogonal(1.0e-5)
|
prop_assert!(v_t.is_orthogonal(1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static_5_2(m: Matrix5x2<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_static_5_2(m in matrix5x2_($scalar)) {
|
||||||
let svd = m.svd(true, true);
|
let svd = m.svd(true, true);
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5) &&
|
prop_assert!(relative_eq!(m, &u * ds * &v_t, epsilon = 1.0e-5));
|
||||||
u.is_orthogonal(1.0e-5) &&
|
prop_assert!(u.is_orthogonal(1.0e-5));
|
||||||
v_t.is_orthogonal(1.0e-5)
|
prop_assert!(v_t.is_orthogonal(1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static_3_5(m: Matrix3x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_static_3_5(m in matrix3x5_($scalar)) {
|
||||||
let svd = m.svd(true, true);
|
let svd = m.svd(true, true);
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
|
|
||||||
let ds = Matrix3::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = Matrix3::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static_2_5(m: Matrix2x5<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_static_2_5(m in matrix2x5_($scalar)) {
|
||||||
let svd = m.svd(true, true);
|
let svd = m.svd(true, true);
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5)
|
prop_assert!(relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_static_square(m in matrix4_($scalar)) {
|
||||||
let svd = m.svd(true, true);
|
let svd = m.svd(true, true);
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
let ds = Matrix4::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = Matrix4::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) &&
|
prop_assert!(relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5));
|
||||||
u.is_orthogonal(1.0e-5) &&
|
prop_assert!(u.is_orthogonal(1.0e-5));
|
||||||
v_t.is_orthogonal(1.0e-5)
|
prop_assert!(v_t.is_orthogonal(1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_static_square_2x2(m: Matrix2<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_static_square_2x2(m in matrix2_($scalar)) {
|
||||||
let svd = m.svd(true, true);
|
let svd = m.svd(true, true);
|
||||||
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
let (u, s, v_t) = (svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
|
||||||
let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
let ds = Matrix2::from_diagonal(&s.map(|e| ComplexField::from_real(e)));
|
||||||
|
|
||||||
s.iter().all(|e| *e >= 0.0) &&
|
prop_assert!(s.iter().all(|e| *e >= 0.0));
|
||||||
relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5) &&
|
prop_assert!(relative_eq!(m, u * ds * v_t, epsilon = 1.0e-5));
|
||||||
u.is_orthogonal(1.0e-5) &&
|
prop_assert!(u.is_orthogonal(1.0e-5));
|
||||||
v_t.is_orthogonal(1.0e-5)
|
prop_assert!(v_t.is_orthogonal(1.0e-5));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_pseudo_inverse(m: DMatrix<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0);
|
fn svd_pseudo_inverse(m in dmatrix_($scalar)) {
|
||||||
|
|
||||||
if m.len() > 0 {
|
|
||||||
let svd = m.clone().svd(true, true);
|
let svd = m.clone().svd(true, true);
|
||||||
let pinv = svd.pseudo_inverse(1.0e-10).unwrap();
|
let pinv = svd.pseudo_inverse(1.0e-10).unwrap();
|
||||||
|
|
||||||
if m.nrows() > m.ncols() {
|
if m.nrows() > m.ncols() {
|
||||||
(pinv * m).is_identity(1.0e-5)
|
prop_assert!((pinv * m).is_identity(1.0e-5))
|
||||||
}
|
} else {
|
||||||
else {
|
prop_assert!((m * pinv).is_identity(1.0e-5))
|
||||||
(m * pinv).is_identity(1.0e-5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn svd_solve(n: usize, nb: usize) -> bool {
|
#[test]
|
||||||
|
fn svd_solve(n in PROPTEST_MATRIX_DIM, nb in PROPTEST_MATRIX_DIM) {
|
||||||
let n = cmp::max(1, cmp::min(n, 10));
|
let n = cmp::max(1, cmp::min(n, 10));
|
||||||
let nb = cmp::min(nb, 10);
|
let nb = cmp::min(nb, 10);
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0);
|
let m = DMatrix::<$scalar_type>::new_random(n, n).map(|e| e.0);
|
||||||
|
|
||||||
let svd = m.clone().svd(true, true);
|
let svd = m.clone().svd(true, true);
|
||||||
|
|
||||||
if svd.rank(1.0e-7) == n {
|
if svd.rank(1.0e-7) == n {
|
||||||
let b1 = DVector::<$scalar>::new_random(n).map(|e| e.0);
|
let b1 = DVector::<$scalar_type>::new_random(n).map(|e| e.0);
|
||||||
let b2 = DMatrix::<$scalar>::new_random(n, nb).map(|e| e.0);
|
let b2 = DMatrix::<$scalar_type>::new_random(n, nb).map(|e| e.0);
|
||||||
|
|
||||||
let sol1 = svd.solve(&b1, 1.0e-7).unwrap();
|
let sol1 = svd.solve(&b1, 1.0e-7).unwrap();
|
||||||
let sol2 = svd.solve(&b2, 1.0e-7).unwrap();
|
let sol2 = svd.solve(&b2, 1.0e-7).unwrap();
|
||||||
|
|
||||||
let recomp = svd.recompose().unwrap();
|
let recomp = svd.recompose().unwrap();
|
||||||
if !relative_eq!(m, recomp, epsilon = 1.0e-6) {
|
|
||||||
println!("{}{}", m, recomp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !relative_eq!(&m * &sol1, b1, epsilon = 1.0e-6) {
|
prop_assert!(relative_eq!(m, recomp, epsilon = 1.0e-6));
|
||||||
println!("Problem 1: {:.6}{:.6}", b1, &m * sol1);
|
prop_assert!(relative_eq!(&m * &sol1, b1, epsilon = 1.0e-6));
|
||||||
return false;
|
prop_assert!(relative_eq!(&m * &sol2, b2, epsilon = 1.0e-6));
|
||||||
}
|
}
|
||||||
if !relative_eq!(&m * &sol2, b2, epsilon = 1.0e-6) {
|
|
||||||
println!("Problem 2: {:.6}{:.6}", b2, &m * sol2);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64(), RandComplex<f64>);
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64, RandScalar<f64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test proposed on the issue #176 of rulinalg.
|
// Test proposed on the issue #176 of rulinalg.
|
||||||
|
|
|
@ -1,54 +1,56 @@
|
||||||
#![cfg(feature = "arbitrary")]
|
#![cfg(feature = "proptest-support")]
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
use na::{DMatrix, Matrix2, Matrix4};
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn symm_tridiagonal(n: usize) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 50));
|
fn symm_tridiagonal(m in dmatrix_($scalar)) {
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part();
|
let m = &m * m.adjoint();
|
||||||
let tri = m.clone().symmetric_tridiagonalize();
|
let tri = m.clone().symmetric_tridiagonalize();
|
||||||
let recomp = tri.recompose();
|
let recomp = tri.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symm_tridiagonal_singular(n: usize) -> bool {
|
#[test]
|
||||||
let n = cmp::max(1, cmp::min(n, 4));
|
fn symm_tridiagonal_singular(m in dmatrix_($scalar)) {
|
||||||
let mut m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part();
|
let mut m = &m * m.adjoint();
|
||||||
|
let n = m.nrows();
|
||||||
m.row_mut(n / 2).fill(na::zero());
|
m.row_mut(n / 2).fill(na::zero());
|
||||||
m.column_mut(n / 2).fill(na::zero());
|
m.column_mut(n / 2).fill(na::zero());
|
||||||
let tri = m.clone().symmetric_tridiagonalize();
|
let tri = m.clone().symmetric_tridiagonalize();
|
||||||
let recomp = tri.recompose();
|
let recomp = tri.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symm_tridiagonal_static_square(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0).hermitian_part();
|
fn symm_tridiagonal_static_square(m in matrix4_($scalar)) {
|
||||||
|
let m = m.hermitian_part();
|
||||||
let tri = m.symmetric_tridiagonalize();
|
let tri = m.symmetric_tridiagonalize();
|
||||||
let recomp = tri.recompose();
|
let recomp = tri.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symm_tridiagonal_static_square_2x2(m: Matrix2<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0).hermitian_part();
|
fn symm_tridiagonal_static_square_2x2(m in matrix2_($scalar)) {
|
||||||
|
let m = m.hermitian_part();
|
||||||
let tri = m.symmetric_tridiagonalize();
|
let tri = m.symmetric_tridiagonalize();
|
||||||
let recomp = tri.recompose();
|
let recomp = tri.recompose();
|
||||||
|
|
||||||
relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m.lower_triangle(), recomp.lower_triangle(), epsilon = 1.0e-7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(complex, RandComplex<f64>);
|
gen_tests!(complex, complex_f64());
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64);
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn udu_simple() {
|
||||||
-1.0, 2.0, -1.0,
|
-1.0, 2.0, -1.0,
|
||||||
0.0, -1.0, 2.0);
|
0.0, -1.0, 2.0);
|
||||||
|
|
||||||
let udu = m.udu();
|
let udu = m.udu().unwrap();
|
||||||
|
|
||||||
// Rebuild
|
// Rebuild
|
||||||
let p = udu.u * udu.d_matrix() * udu.u.transpose();
|
let p = udu.u * udu.d_matrix() * udu.u.transpose();
|
||||||
|
@ -23,50 +23,54 @@ fn udu_non_sym_panic() {
|
||||||
let m = Matrix3::new(
|
let m = Matrix3::new(
|
||||||
2.0, -1.0, 0.0,
|
2.0, -1.0, 0.0,
|
||||||
1.0, -2.0, 3.0,
|
1.0, -2.0, 3.0,
|
||||||
-2.0, 1.0, 0.0);
|
-2.0, 1.0, 0.3);
|
||||||
|
|
||||||
let udu = m.udu();
|
let udu = m.udu().unwrap();
|
||||||
// Rebuild
|
// Rebuild
|
||||||
let p = udu.u * udu.d_matrix() * udu.u.transpose();
|
let p = udu.u * udu.d_matrix() * udu.u.transpose();
|
||||||
|
|
||||||
assert!(relative_eq!(m, p, epsilon = 3.0e-16));
|
assert!(relative_eq!(m, p, epsilon = 3.0e-16));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "proptest-support")]
|
||||||
mod quickcheck_tests {
|
mod proptest_tests {
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandComplex, RandScalar};
|
use crate::core::helper::{RandComplex, RandScalar};
|
||||||
|
|
||||||
macro_rules! gen_tests(
|
macro_rules! gen_tests(
|
||||||
($module: ident, $scalar: ty) => {
|
($module: ident, $scalar: expr) => {
|
||||||
mod $module {
|
mod $module {
|
||||||
use na::{DMatrix, Matrix4};
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::core::helper::{RandScalar, RandComplex};
|
use crate::core::helper::{RandScalar, RandComplex};
|
||||||
|
use crate::proptest::*;
|
||||||
|
use proptest::{prop_assert, proptest};
|
||||||
|
|
||||||
quickcheck! {
|
proptest! {
|
||||||
fn udu(n: usize) -> bool {
|
#[test]
|
||||||
let n = std::cmp::max(1, std::cmp::min(n, 10));
|
fn udu(m in dmatrix_($scalar)) {
|
||||||
let m = DMatrix::<$scalar>::new_random(n, n).map(|e| e.0).hermitian_part();
|
let m = &m * m.adjoint();
|
||||||
|
|
||||||
let udu = m.clone().udu();
|
if let Some(udu) = m.clone().udu() {
|
||||||
let p = &udu.u * &udu.d_matrix() * &udu.u.transpose();
|
let p = &udu.u * &udu.d_matrix() * &udu.u.transpose();
|
||||||
|
println!("m: {}, p: {}", m, p);
|
||||||
|
|
||||||
relative_eq!(m, p, epsilon = 1.0e-7)
|
prop_assert!(relative_eq!(m, p, epsilon = 1.0e-7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn udu_static(m: Matrix4<$scalar>) -> bool {
|
#[test]
|
||||||
let m = m.map(|e| e.0).hermitian_part();
|
fn udu_static(m in matrix4_($scalar)) {
|
||||||
|
let m = m.hermitian_part();
|
||||||
|
|
||||||
let udu = m.udu();
|
if let Some(udu) = m.udu() {
|
||||||
let p = udu.u * udu.d_matrix() * udu.u.transpose();
|
let p = udu.u * udu.d_matrix() * udu.u.transpose();
|
||||||
|
prop_assert!(relative_eq!(m, p, epsilon = 1.0e-7));
|
||||||
relative_eq!(m, p, epsilon = 1.0e-7)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gen_tests!(f64, RandScalar<f64>);
|
gen_tests!(f64, PROPTEST_F64);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,162 @@
|
||||||
//! Tests for proptest-related functionality.
|
//! Tests for proptest-related functionality.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use nalgebra::allocator::Allocator;
|
||||||
use nalgebra::base::dimension::*;
|
use nalgebra::base::dimension::*;
|
||||||
use nalgebra::proptest::{matrix, DimRange, MatrixStrategy};
|
use nalgebra::proptest::{DimRange, MatrixStrategy};
|
||||||
use nalgebra::{DMatrix, DVector, Dim, Matrix3, MatrixMN, Vector3};
|
use nalgebra::{
|
||||||
|
DMatrix, DVector, DefaultAllocator, Dim, DualQuaternion, Isometry2, Isometry3, Matrix3,
|
||||||
|
MatrixMN, Point2, Point3, Quaternion, Rotation2, Rotation3, Scalar, Similarity3, Translation2,
|
||||||
|
Translation3, UnitComplex, UnitDualQuaternion, UnitQuaternion, Vector3, U2, U3, U4, U7, U8,
|
||||||
|
};
|
||||||
|
use num_complex::Complex;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use proptest::strategy::ValueTree;
|
use proptest::strategy::{Strategy, ValueTree};
|
||||||
use proptest::test_runner::TestRunner;
|
use proptest::test_runner::TestRunner;
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
|
pub const PROPTEST_MATRIX_DIM: RangeInclusive<usize> = 1..=20;
|
||||||
|
pub const PROPTEST_F64: RangeInclusive<f64> = -100.0..=100.0;
|
||||||
|
|
||||||
|
pub use nalgebra::proptest::{matrix, vector};
|
||||||
|
|
||||||
|
pub fn point2() -> impl Strategy<Value = Point2<f64>> {
|
||||||
|
vector2().prop_map(|v| Point2::from(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn point3() -> impl Strategy<Value = Point3<f64>> {
|
||||||
|
vector3().prop_map(|v| Point3::from(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translation2() -> impl Strategy<Value = Translation2<f64>> {
|
||||||
|
vector2().prop_map(|v| Translation2::from(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translation3() -> impl Strategy<Value = Translation3<f64>> {
|
||||||
|
vector3().prop_map(|v| Translation3::from(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation2() -> impl Strategy<Value = Rotation2<f64>> {
|
||||||
|
PROPTEST_F64.prop_map(|v| Rotation2::new(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation3() -> impl Strategy<Value = Rotation3<f64>> {
|
||||||
|
vector3().prop_map(|v| Rotation3::new(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unit_complex() -> impl Strategy<Value = UnitComplex<f64>> {
|
||||||
|
PROPTEST_F64.prop_map(|v| UnitComplex::new(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isometry2() -> impl Strategy<Value = Isometry2<f64>> {
|
||||||
|
vector3().prop_map(|v| Isometry2::new(v.xy(), v.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isometry3() -> impl Strategy<Value = Isometry3<f64>> {
|
||||||
|
vector6().prop_map(|v| Isometry3::new(v.xyz(), Vector3::new(v.w, v.a, v.b)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn similarity2() -> impl Strategy<Value = Similarity2<f64>> {
|
||||||
|
// vector4().prop_map(|v| Similarity2::new(v.xy(), v.z, v.w))
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn similarity3() -> impl Strategy<Value = Similarity3<f64>> {
|
||||||
|
vector(PROPTEST_F64, U7)
|
||||||
|
.prop_map(|v| Similarity3::new(v.xyz(), Vector3::new(v[3], v[4], v[5]), v[6]))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unit_dual_quaternion() -> impl Strategy<Value = UnitDualQuaternion<f64>> {
|
||||||
|
isometry3().prop_map(|iso| UnitDualQuaternion::from_isometry(&iso))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dual_quaternion() -> impl Strategy<Value = DualQuaternion<f64>> {
|
||||||
|
vector(PROPTEST_F64, U8).prop_map(|v| {
|
||||||
|
DualQuaternion::from_real_and_dual(
|
||||||
|
Quaternion::new(v[0], v[1], v[2], v[3]),
|
||||||
|
Quaternion::new(v[4], v[5], v[6], v[7]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quaternion() -> impl Strategy<Value = Quaternion<f64>> {
|
||||||
|
vector4().prop_map(|v| Quaternion::from(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unit_quaternion() -> impl Strategy<Value = UnitQuaternion<f64>> {
|
||||||
|
vector3().prop_map(|v| UnitQuaternion::new(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn complex_f64() -> impl Strategy<Value = Complex<f64>> + Clone {
|
||||||
|
vector(PROPTEST_F64, U2).prop_map(|v| Complex::new(v.x, v.y))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dmatrix() -> impl Strategy<Value = DMatrix<f64>> {
|
||||||
|
matrix(PROPTEST_F64, PROPTEST_MATRIX_DIM, PROPTEST_MATRIX_DIM)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dvector() -> impl Strategy<Value = DVector<f64>> {
|
||||||
|
vector(PROPTEST_F64, PROPTEST_MATRIX_DIM)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dmatrix_<ScalarStrategy>(
|
||||||
|
scalar_strategy: ScalarStrategy,
|
||||||
|
) -> impl Strategy<Value = DMatrix<ScalarStrategy::Value>>
|
||||||
|
where
|
||||||
|
ScalarStrategy: Strategy + Clone + 'static,
|
||||||
|
ScalarStrategy::Value: Scalar,
|
||||||
|
DefaultAllocator: Allocator<ScalarStrategy::Value, Dynamic, Dynamic>,
|
||||||
|
{
|
||||||
|
matrix(scalar_strategy, PROPTEST_MATRIX_DIM, PROPTEST_MATRIX_DIM)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn dvector_<T>(range: RangeInclusive<T>) -> impl Strategy<Value = DVector<T>>
|
||||||
|
// where
|
||||||
|
// RangeInclusive<T>: Strategy<Value = T>,
|
||||||
|
// T: Scalar + PartialEq + Copy,
|
||||||
|
// DefaultAllocator: Allocator<T, Dynamic>,
|
||||||
|
// {
|
||||||
|
// vector(range, PROPTEST_MATRIX_DIM)
|
||||||
|
// }
|
||||||
|
|
||||||
|
macro_rules! define_strategies(
|
||||||
|
($($strategy_: ident $strategy: ident<$nrows: ident, $ncols: ident>),*) => {$(
|
||||||
|
pub fn $strategy() -> impl Strategy<Value = MatrixMN<f64, $nrows, $ncols>> {
|
||||||
|
matrix(PROPTEST_F64, $nrows, $ncols)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn $strategy_<ScalarStrategy>(scalar_strategy: ScalarStrategy) -> impl Strategy<Value = MatrixMN<ScalarStrategy::Value, $nrows, $ncols>>
|
||||||
|
where
|
||||||
|
ScalarStrategy: Strategy + Clone + 'static,
|
||||||
|
ScalarStrategy::Value: Scalar,
|
||||||
|
DefaultAllocator: Allocator<ScalarStrategy::Value, $nrows, $ncols> {
|
||||||
|
matrix(scalar_strategy, $nrows, $ncols)
|
||||||
|
}
|
||||||
|
)*}
|
||||||
|
);
|
||||||
|
|
||||||
|
define_strategies!(
|
||||||
|
matrix1_ matrix1<U1, U1>,
|
||||||
|
matrix2_ matrix2<U2, U2>,
|
||||||
|
matrix3_ matrix3<U3, U3>,
|
||||||
|
matrix4_ matrix4<U4, U4>,
|
||||||
|
matrix5_ matrix5<U5, U5>,
|
||||||
|
matrix6_ matrix6<U6, U6>,
|
||||||
|
|
||||||
|
matrix5x2_ matrix5x2<U5, U2>,
|
||||||
|
matrix2x5_ matrix2x5<U2, U5>,
|
||||||
|
matrix5x3_ matrix5x3<U5, U3>,
|
||||||
|
matrix3x5_ matrix3x5<U3, U5>,
|
||||||
|
matrix5x4_ matrix5x4<U5, U4>,
|
||||||
|
matrix4x5_ matrix4x5<U4, U5>,
|
||||||
|
|
||||||
|
vector1_ vector1<U1, U1>,
|
||||||
|
vector2_ vector2<U2, U1>,
|
||||||
|
vector3_ vector3<U3, U1>,
|
||||||
|
vector4_ vector4<U4, U1>,
|
||||||
|
vector5_ vector5<U5, U1>,
|
||||||
|
vector6_ vector6<U6, U1>
|
||||||
|
);
|
||||||
|
|
||||||
/// Generate a proptest that tests that all matrices generated with the
|
/// Generate a proptest that tests that all matrices generated with the
|
||||||
/// provided rows and columns conform to the constraints defined by the
|
/// provided rows and columns conform to the constraints defined by the
|
||||||
|
|
|
@ -43,7 +43,6 @@ fn cs_matrix_from_triplet() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let cs_mat = CsMatrix::from_triplet(4, 5, &irows, &icols, &vals);
|
let cs_mat = CsMatrix::from_triplet(4, 5, &irows, &icols, &vals);
|
||||||
println!("Mat from triplet: {:?}", cs_mat);
|
|
||||||
assert!(cs_mat.is_sorted());
|
assert!(cs_mat.is_sorted());
|
||||||
assert_eq!(cs_mat, cs_expected);
|
assert_eq!(cs_mat, cs_expected);
|
||||||
|
|
||||||
|
@ -62,7 +61,6 @@ fn cs_matrix_from_triplet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let cs_mat = CsMatrix::from_triplet(4, 5, &irows, &icols, &vals);
|
let cs_mat = CsMatrix::from_triplet(4, 5, &irows, &icols, &vals);
|
||||||
println!("Mat from triplet: {:?}", cs_mat);
|
|
||||||
assert!(cs_mat.is_sorted());
|
assert!(cs_mat.is_sorted());
|
||||||
assert_eq!(cs_mat, cs_expected);
|
assert_eq!(cs_mat, cs_expected);
|
||||||
|
|
||||||
|
@ -80,7 +78,6 @@ fn cs_matrix_from_triplet() {
|
||||||
vals.append(&mut va);
|
vals.append(&mut va);
|
||||||
|
|
||||||
let cs_mat = CsMatrix::from_triplet(4, 5, &irows, &icols, &vals);
|
let cs_mat = CsMatrix::from_triplet(4, 5, &irows, &icols, &vals);
|
||||||
println!("Mat from triplet: {:?}", cs_mat);
|
|
||||||
assert!(cs_mat.is_sorted());
|
assert!(cs_mat.is_sorted());
|
||||||
assert_eq!(cs_mat, cs_expected * 2.0);
|
assert_eq!(cs_mat, cs_expected * 2.0);
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ fn cs_matrix_market() {
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let cs_mat = io::cs_matrix_from_matrix_market_str(file_str).unwrap();
|
let cs_mat = io::cs_matrix_from_matrix_market_str(file_str).unwrap();
|
||||||
println!("CS mat: {:?}", cs_mat);
|
|
||||||
let mat: DMatrix<_> = cs_mat.into();
|
let mat: DMatrix<_> = cs_mat.into();
|
||||||
let expected = DMatrix::from_row_slice(5, 5, &[
|
let expected = DMatrix::from_row_slice(5, 5, &[
|
||||||
1.0, 0.0, 0.0, 6.0, 0.0,
|
1.0, 0.0, 0.0, 6.0, 0.0,
|
||||||
|
|
Loading…
Reference in New Issue