mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Pulled the latest changes from the trunk
This commit is contained in:
@@ -139,17 +139,12 @@ endif(TEST_LIB)
|
||||
set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Official")
|
||||
add_custom_target(BuildOfficial)
|
||||
|
||||
option(EIGEN_TEST_EVALUATORS "Enable work in progress evaluators" OFF)
|
||||
if(EIGEN_TEST_EVALUATORS)
|
||||
add_definitions("-DEIGEN_TEST_EVALUATORS=1")
|
||||
add_definitions("-DEIGEN_ENABLE_EVALUATORS=1")
|
||||
endif(EIGEN_TEST_EVALUATORS)
|
||||
|
||||
ei_add_test(meta)
|
||||
ei_add_test(sizeof)
|
||||
ei_add_test(dynalloc)
|
||||
ei_add_test(nomalloc)
|
||||
ei_add_test(first_aligned)
|
||||
ei_add_test(nullary)
|
||||
ei_add_test(mixingtypes)
|
||||
ei_add_test(packetmath)
|
||||
ei_add_test(unalignedassert)
|
||||
@@ -165,6 +160,9 @@ ei_add_test(redux)
|
||||
ei_add_test(visitor)
|
||||
ei_add_test(block)
|
||||
ei_add_test(corners)
|
||||
ei_add_test(swap)
|
||||
ei_add_test(resize)
|
||||
ei_add_test(conservative_resize)
|
||||
ei_add_test(product_small)
|
||||
ei_add_test(product_large)
|
||||
ei_add_test(product_extra)
|
||||
@@ -193,6 +191,7 @@ ei_add_test(product_trsolve)
|
||||
ei_add_test(product_mmtr)
|
||||
ei_add_test(product_notemporary)
|
||||
ei_add_test(stable_norm)
|
||||
ei_add_test(permutationmatrices)
|
||||
ei_add_test(bandmatrix)
|
||||
ei_add_test(cholesky)
|
||||
ei_add_test(lu)
|
||||
@@ -212,30 +211,31 @@ ei_add_test(real_qz)
|
||||
ei_add_test(eigensolver_generalized_real)
|
||||
ei_add_test(jacobi)
|
||||
ei_add_test(jacobisvd)
|
||||
ei_add_test(bdcsvd)
|
||||
ei_add_test(householder)
|
||||
ei_add_test(geo_orthomethods)
|
||||
ei_add_test(geo_homogeneous)
|
||||
ei_add_test(geo_quaternion)
|
||||
ei_add_test(geo_transformations)
|
||||
ei_add_test(geo_eulerangles)
|
||||
ei_add_test(geo_hyperplane)
|
||||
ei_add_test(geo_parametrizedline)
|
||||
ei_add_test(geo_alignedbox)
|
||||
ei_add_test(geo_hyperplane)
|
||||
ei_add_test(geo_transformations)
|
||||
ei_add_test(geo_homogeneous)
|
||||
ei_add_test(stdvector)
|
||||
ei_add_test(stdvector_overload)
|
||||
ei_add_test(stdlist)
|
||||
ei_add_test(stddeque)
|
||||
ei_add_test(resize)
|
||||
ei_add_test(sparse_vector)
|
||||
ei_add_test(sparse_basic)
|
||||
ei_add_test(sparse_vector)
|
||||
ei_add_test(sparse_product)
|
||||
ei_add_test(sparse_solvers)
|
||||
ei_add_test(umeyama)
|
||||
ei_add_test(householder)
|
||||
ei_add_test(swap)
|
||||
ei_add_test(conservative_resize)
|
||||
ei_add_test(permutationmatrices)
|
||||
ei_add_test(sparse_permutations)
|
||||
ei_add_test(nullary)
|
||||
ei_add_test(simplicial_cholesky)
|
||||
ei_add_test(conjugate_gradient)
|
||||
ei_add_test(bicgstab)
|
||||
ei_add_test(sparselu)
|
||||
ei_add_test(sparseqr)
|
||||
ei_add_test(umeyama)
|
||||
ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
ei_add_test(zerosized)
|
||||
ei_add_test(dontalign)
|
||||
@@ -249,13 +249,7 @@ ei_add_test(special_numbers)
|
||||
ei_add_test(rvalue_types)
|
||||
ei_add_test(dense_storage)
|
||||
|
||||
ei_add_test(simplicial_cholesky)
|
||||
ei_add_test(conjugate_gradient)
|
||||
ei_add_test(bicgstab)
|
||||
ei_add_test(sparselu)
|
||||
ei_add_test(sparseqr)
|
||||
|
||||
# ei_add_test(denseLM)
|
||||
# # ei_add_test(denseLM)
|
||||
|
||||
if(QT4_FOUND)
|
||||
ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}")
|
||||
@@ -313,7 +307,7 @@ endif()
|
||||
option(EIGEN_TEST_NVCC "Enable NVCC support in unit tests" OFF)
|
||||
if(EIGEN_TEST_NVCC)
|
||||
|
||||
find_package(CUDA)
|
||||
find_package(CUDA 5.0)
|
||||
if(CUDA_FOUND)
|
||||
|
||||
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
|
||||
@@ -331,3 +325,6 @@ endif(CUDA_FOUND)
|
||||
|
||||
endif(EIGEN_TEST_NVCC)
|
||||
|
||||
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/failtests)
|
||||
add_test(NAME failtests WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/failtests COMMAND ${CMAKE_COMMAND} ${Eigen_SOURCE_DIR} -G "${CMAKE_GENERATOR}" -DEIGEN_FAILTEST=ON)
|
||||
|
||||
@@ -64,6 +64,7 @@ template<typename MatrixType> void adjoint(const MatrixType& m)
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
|
||||
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
|
||||
const Index PacketSize = internal::packet_traits<Scalar>::size;
|
||||
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
@@ -108,6 +109,17 @@ template<typename MatrixType> void adjoint(const MatrixType& m)
|
||||
VERIFY_IS_APPROX(m3,m1.transpose());
|
||||
m3.transposeInPlace();
|
||||
VERIFY_IS_APPROX(m3,m1);
|
||||
|
||||
if(PacketSize<m3.rows() && PacketSize<m3.cols())
|
||||
{
|
||||
m3 = m1;
|
||||
Index i = internal::random<Index>(0,m3.rows()-PacketSize);
|
||||
Index j = internal::random<Index>(0,m3.cols()-PacketSize);
|
||||
m3.template block<PacketSize,PacketSize>(i,j).transposeInPlace();
|
||||
VERIFY_IS_APPROX( (m3.template block<PacketSize,PacketSize>(i,j)), (m1.template block<PacketSize,PacketSize>(i,j).transpose()) );
|
||||
m3.template block<PacketSize,PacketSize>(i,j).transposeInPlace();
|
||||
VERIFY_IS_APPROX(m3,m1);
|
||||
}
|
||||
|
||||
// check inplace adjoint
|
||||
m3 = m1;
|
||||
@@ -129,9 +141,19 @@ void test_adjoint()
|
||||
CALL_SUBTEST_1( adjoint(Matrix<float, 1, 1>()) );
|
||||
CALL_SUBTEST_2( adjoint(Matrix3d()) );
|
||||
CALL_SUBTEST_3( adjoint(Matrix4f()) );
|
||||
|
||||
CALL_SUBTEST_4( adjoint(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
|
||||
CALL_SUBTEST_5( adjoint(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_6( adjoint(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
|
||||
// Complement for 128 bits vectorization:
|
||||
CALL_SUBTEST_8( adjoint(Matrix2d()) );
|
||||
CALL_SUBTEST_9( adjoint(Matrix<int,4,4>()) );
|
||||
|
||||
// 256 bits vectorization:
|
||||
CALL_SUBTEST_10( adjoint(Matrix<float,8,8>()) );
|
||||
CALL_SUBTEST_11( adjoint(Matrix<double,4,4>()) );
|
||||
CALL_SUBTEST_12( adjoint(Matrix<int,8,8>()) );
|
||||
}
|
||||
// test a large static matrix only once
|
||||
CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
|
||||
|
||||
@@ -81,6 +81,31 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
|
||||
m3 = m1;
|
||||
VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
|
||||
|
||||
// Conversion from scalar
|
||||
VERIFY_IS_APPROX((m3 = s1), ArrayType::Constant(rows,cols,s1));
|
||||
VERIFY_IS_APPROX((m3 = 1), ArrayType::Constant(rows,cols,1));
|
||||
VERIFY_IS_APPROX((m3.topLeftCorner(rows,cols) = 1), ArrayType::Constant(rows,cols,1));
|
||||
typedef Array<Scalar,
|
||||
ArrayType::RowsAtCompileTime==Dynamic?2:ArrayType::RowsAtCompileTime,
|
||||
ArrayType::ColsAtCompileTime==Dynamic?2:ArrayType::ColsAtCompileTime,
|
||||
ArrayType::Options> FixedArrayType;
|
||||
FixedArrayType f1(s1);
|
||||
VERIFY_IS_APPROX(f1, FixedArrayType::Constant(s1));
|
||||
FixedArrayType f2(numext::real(s1));
|
||||
VERIFY_IS_APPROX(f2, FixedArrayType::Constant(numext::real(s1)));
|
||||
FixedArrayType f3((int)100*numext::real(s1));
|
||||
VERIFY_IS_APPROX(f3, FixedArrayType::Constant((int)100*numext::real(s1)));
|
||||
f1.setRandom();
|
||||
FixedArrayType f4(f1.data());
|
||||
VERIFY_IS_APPROX(f4, f1);
|
||||
|
||||
// Check possible conflicts with 1D ctor
|
||||
typedef Array<Scalar, Dynamic, 1> OneDArrayType;
|
||||
OneDArrayType o1(rows);
|
||||
VERIFY(o1.size()==rows);
|
||||
OneDArrayType o4((int)rows);
|
||||
VERIFY(o4.size()==rows);
|
||||
}
|
||||
|
||||
template<typename ArrayType> void comparisons(const ArrayType& m)
|
||||
|
||||
111
test/bdcsvd.cpp
Normal file
111
test/bdcsvd.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2013 Gauthier Brun <brun.gauthier@gmail.com>
|
||||
// Copyright (C) 2013 Nicolas Carre <nicolas.carre@ensimag.fr>
|
||||
// Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr>
|
||||
// Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/
|
||||
|
||||
// discard stack allocation as that too bypasses malloc
|
||||
#define EIGEN_STACK_ALLOCATION_LIMIT 0
|
||||
#define EIGEN_RUNTIME_NO_MALLOC
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/SVD>
|
||||
#include <iostream>
|
||||
#include <Eigen/LU>
|
||||
|
||||
|
||||
#define SVD_DEFAULT(M) BDCSVD<M>
|
||||
#define SVD_FOR_MIN_NORM(M) BDCSVD<M>
|
||||
#include "svd_common.h"
|
||||
|
||||
// Check all variants of JacobiSVD
|
||||
template<typename MatrixType>
|
||||
void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
|
||||
{
|
||||
MatrixType m = a;
|
||||
if(pickrandom)
|
||||
svd_fill_random(m);
|
||||
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<BDCSVD<MatrixType> >(m, false) ));
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void bdcsvd_method()
|
||||
{
|
||||
enum { Size = MatrixType::RowsAtCompileTime };
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef Matrix<RealScalar, Size, 1> RealVecType;
|
||||
MatrixType m = MatrixType::Identity();
|
||||
VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones());
|
||||
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU());
|
||||
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV());
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
}
|
||||
|
||||
// compare the Singular values returned with Jacobi and Bdc
|
||||
template<typename MatrixType>
|
||||
void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0)
|
||||
{
|
||||
MatrixType m = MatrixType::Random(a.rows(), a.cols());
|
||||
BDCSVD<MatrixType> bdc_svd(m);
|
||||
JacobiSVD<MatrixType> jacobi_svd(m);
|
||||
VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues());
|
||||
if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU());
|
||||
if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU());
|
||||
if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV());
|
||||
if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV());
|
||||
}
|
||||
|
||||
void test_bdcsvd()
|
||||
{
|
||||
CALL_SUBTEST_3(( svd_verify_assert<BDCSVD<Matrix3f> >(Matrix3f()) ));
|
||||
CALL_SUBTEST_4(( svd_verify_assert<BDCSVD<Matrix4d> >(Matrix4d()) ));
|
||||
CALL_SUBTEST_7(( svd_verify_assert<BDCSVD<MatrixXf> >(MatrixXf(10,12)) ));
|
||||
CALL_SUBTEST_8(( svd_verify_assert<BDCSVD<MatrixXcd> >(MatrixXcd(7,5)) ));
|
||||
|
||||
CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd<Matrix2cd>) ));
|
||||
CALL_SUBTEST_1(( svd_all_trivial_2x2(bdcsvd<Matrix2d>) ));
|
||||
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_3(( bdcsvd<Matrix3f>() ));
|
||||
CALL_SUBTEST_4(( bdcsvd<Matrix4d>() ));
|
||||
CALL_SUBTEST_5(( bdcsvd<Matrix<float,3,5> >() ));
|
||||
|
||||
int r = internal::random<int>(1, EIGEN_TEST_MAX_SIZE/2),
|
||||
c = internal::random<int>(1, EIGEN_TEST_MAX_SIZE/2);
|
||||
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(r)
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(c)
|
||||
|
||||
CALL_SUBTEST_6(( bdcsvd(Matrix<double,Dynamic,2>(r,2)) ));
|
||||
CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) ));
|
||||
CALL_SUBTEST_7(( compare_bdc_jacobi(MatrixXf(r,c)) ));
|
||||
CALL_SUBTEST_10(( bdcsvd(MatrixXd(r,c)) ));
|
||||
CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) ));
|
||||
CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) ));
|
||||
CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) ));
|
||||
|
||||
// Test on inf/nan matrix
|
||||
CALL_SUBTEST_7( (svd_inf_nan<BDCSVD<MatrixXf>, MatrixXf>()) );
|
||||
CALL_SUBTEST_10( (svd_inf_nan<BDCSVD<MatrixXd>, MatrixXd>()) );
|
||||
}
|
||||
|
||||
// test matrixbase method
|
||||
CALL_SUBTEST_1(( bdcsvd_method<Matrix2cd>() ));
|
||||
CALL_SUBTEST_3(( bdcsvd_method<Matrix3f>() ));
|
||||
|
||||
// Test problem size constructors
|
||||
CALL_SUBTEST_7( BDCSVD<MatrixXf>(10,10) );
|
||||
|
||||
// Check that preallocation avoids subsequent mallocs
|
||||
CALL_SUBTEST_9( svd_preallocate() );
|
||||
|
||||
CALL_SUBTEST_2( svd_underoverflow() );
|
||||
}
|
||||
|
||||
@@ -130,6 +130,14 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
|
||||
VERIFY(numext::real(ones.col(c1).dot(ones.col(c2))) == RealScalar(rows));
|
||||
VERIFY(numext::real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols));
|
||||
|
||||
// chekc that linear acccessors works on blocks
|
||||
m1 = m1_copy;
|
||||
if((MatrixType::Flags&RowMajorBit)==0)
|
||||
VERIFY_IS_EQUAL(m1.leftCols(c1).coeff(r1+c1*rows), m1(r1,c1));
|
||||
else
|
||||
VERIFY_IS_EQUAL(m1.topRows(r1).coeff(c1+r1*cols), m1(r1,c1));
|
||||
|
||||
|
||||
// now test some block-inside-of-block.
|
||||
|
||||
|
||||
@@ -316,33 +316,35 @@ template<typename MatrixType> void cholesky_definiteness(const MatrixType& m)
|
||||
{
|
||||
eigen_assert(m.rows() == 2 && m.cols() == 2);
|
||||
MatrixType mat;
|
||||
LDLT<MatrixType> ldlt(2);
|
||||
|
||||
{
|
||||
mat << 1, 0, 0, -1;
|
||||
LDLT<MatrixType> ldlt(mat);
|
||||
ldlt.compute(mat);
|
||||
VERIFY(!ldlt.isNegative());
|
||||
VERIFY(!ldlt.isPositive());
|
||||
}
|
||||
{
|
||||
mat << 1, 2, 2, 1;
|
||||
LDLT<MatrixType> ldlt(mat);
|
||||
ldlt.compute(mat);
|
||||
VERIFY(!ldlt.isNegative());
|
||||
VERIFY(!ldlt.isPositive());
|
||||
}
|
||||
{
|
||||
mat << 0, 0, 0, 0;
|
||||
LDLT<MatrixType> ldlt(mat);
|
||||
ldlt.compute(mat);
|
||||
VERIFY(ldlt.isNegative());
|
||||
VERIFY(ldlt.isPositive());
|
||||
}
|
||||
{
|
||||
mat << 0, 0, 0, 1;
|
||||
LDLT<MatrixType> ldlt(mat);
|
||||
ldlt.compute(mat);
|
||||
VERIFY(!ldlt.isNegative());
|
||||
VERIFY(ldlt.isPositive());
|
||||
}
|
||||
{
|
||||
mat << -1, 0, 0, 0;
|
||||
LDLT<MatrixType> ldlt(mat);
|
||||
ldlt.compute(mat);
|
||||
VERIFY(ldlt.isNegative());
|
||||
VERIFY(!ldlt.isPositive());
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ struct redux {
|
||||
};
|
||||
|
||||
template<typename T1, typename T2>
|
||||
struct prod {
|
||||
struct prod_test {
|
||||
EIGEN_DEVICE_FUNC
|
||||
void operator()(int i, const typename T1::Scalar* in, typename T1::Scalar* out) const
|
||||
{
|
||||
@@ -125,8 +125,8 @@ void test_cuda_basic()
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(redux<Array4f>(), nthreads, in, out) );
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(redux<Matrix3f>(), nthreads, in, out) );
|
||||
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(prod<Matrix3f,Matrix3f>(), nthreads, in, out) );
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(prod<Matrix4f,Vector4f>(), nthreads, in, out) );
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(prod_test<Matrix3f,Matrix3f>(), nthreads, in, out) );
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(prod_test<Matrix4f,Vector4f>(), nthreads, in, out) );
|
||||
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(diagonal<Matrix3f,Vector3f>(), nthreads, in, out) );
|
||||
CALL_SUBTEST( run_and_compare_to_cuda(diagonal<Matrix4f,Vector4f>(), nthreads, in, out) );
|
||||
|
||||
@@ -84,6 +84,13 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
|
||||
VERIFY_IS_APPROX(m1 * (rdm1 * s1), (m1 * rdm1) * s1);
|
||||
VERIFY_IS_APPROX(m1 * (s1 * rdm1), (m1 * rdm1) * s1);
|
||||
|
||||
// Diagonal to dense
|
||||
sq_m1.setRandom();
|
||||
sq_m2 = sq_m1;
|
||||
VERIFY_IS_APPROX( (sq_m1 += (s1*v1).asDiagonal()), sq_m2 += (s1*v1).asDiagonal().toDenseMatrix() );
|
||||
VERIFY_IS_APPROX( (sq_m1 -= (s1*v1).asDiagonal()), sq_m2 -= (s1*v1).asDiagonal().toDenseMatrix() );
|
||||
VERIFY_IS_APPROX( (sq_m1 = (s1*v1).asDiagonal()), (s1*v1).asDiagonal().toDenseMatrix() );
|
||||
}
|
||||
|
||||
void test_diagonalmatrices()
|
||||
|
||||
@@ -111,8 +111,17 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
|
||||
|
||||
// test Tridiagonalization's methods
|
||||
Tridiagonalization<MatrixType> tridiag(symmC);
|
||||
// FIXME tridiag.matrixQ().adjoint() does not work
|
||||
VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().diagonal());
|
||||
VERIFY_IS_APPROX(tridiag.subDiagonal(), tridiag.matrixT().template diagonal<-1>());
|
||||
MatrixType T = tridiag.matrixT();
|
||||
if(rows>1 && cols>1) {
|
||||
// FIXME check that upper and lower part are 0:
|
||||
//VERIFY(T.topRightCorner(rows-2, cols-2).template triangularView<Upper>().isZero());
|
||||
}
|
||||
VERIFY_IS_APPROX(tridiag.diagonal(), T.diagonal().real());
|
||||
VERIFY_IS_APPROX(tridiag.subDiagonal(), T.template diagonal<1>().real());
|
||||
VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint());
|
||||
VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint());
|
||||
|
||||
// Test computation of eigenvalues from tridiagonal matrix
|
||||
if(rows > 1)
|
||||
@@ -136,11 +145,14 @@ void test_eigensolver_selfadjoint()
|
||||
{
|
||||
int s = 0;
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
// trivial test for 1x1 matrices:
|
||||
CALL_SUBTEST_1( selfadjointeigensolver(Matrix<float, 1, 1>()));
|
||||
CALL_SUBTEST_1( selfadjointeigensolver(Matrix<double, 1, 1>()));
|
||||
// very important to test 3x3 and 2x2 matrices since we provide special paths for them
|
||||
CALL_SUBTEST_1( selfadjointeigensolver(Matrix2f()) );
|
||||
CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) );
|
||||
CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
|
||||
CALL_SUBTEST_1( selfadjointeigensolver(Matrix3d()) );
|
||||
CALL_SUBTEST_12( selfadjointeigensolver(Matrix2f()) );
|
||||
CALL_SUBTEST_12( selfadjointeigensolver(Matrix2d()) );
|
||||
CALL_SUBTEST_13( selfadjointeigensolver(Matrix3f()) );
|
||||
CALL_SUBTEST_13( selfadjointeigensolver(Matrix3d()) );
|
||||
CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
|
||||
s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
|
||||
CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) );
|
||||
|
||||
@@ -1,7 +1,78 @@
|
||||
#define EIGEN_ENABLE_EVALUATORS
|
||||
|
||||
#include "main.h"
|
||||
|
||||
using internal::copy_using_evaluator;
|
||||
namespace Eigen {
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
EIGEN_STRONG_INLINE
|
||||
DstXprType& copy_using_evaluator(const EigenBase<DstXprType> &dst, const SrcXprType &src)
|
||||
{
|
||||
call_assignment(dst.const_cast_derived(), src.derived(), internal::assign_op<typename DstXprType::Scalar>());
|
||||
return dst.const_cast_derived();
|
||||
}
|
||||
|
||||
template<typename DstXprType, template <typename> class StorageBase, typename SrcXprType>
|
||||
EIGEN_STRONG_INLINE
|
||||
const DstXprType& copy_using_evaluator(const NoAlias<DstXprType, StorageBase>& dst, const SrcXprType &src)
|
||||
{
|
||||
call_assignment(dst, src.derived(), internal::assign_op<typename DstXprType::Scalar>());
|
||||
return dst.expression();
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
EIGEN_STRONG_INLINE
|
||||
DstXprType& copy_using_evaluator(const PlainObjectBase<DstXprType> &dst, const SrcXprType &src)
|
||||
{
|
||||
#ifdef EIGEN_NO_AUTOMATIC_RESIZING
|
||||
eigen_assert((dst.size()==0 || (IsVectorAtCompileTime ? (dst.size() == src.size())
|
||||
: (dst.rows() == src.rows() && dst.cols() == src.cols())))
|
||||
&& "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined");
|
||||
#else
|
||||
dst.const_cast_derived().resizeLike(src.derived());
|
||||
#endif
|
||||
|
||||
call_assignment(dst.const_cast_derived(), src.derived(), internal::assign_op<typename DstXprType::Scalar>());
|
||||
return dst.const_cast_derived();
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
void add_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src)
|
||||
{
|
||||
typedef typename DstXprType::Scalar Scalar;
|
||||
call_assignment(const_cast<DstXprType&>(dst), src.derived(), internal::add_assign_op<Scalar>());
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
void subtract_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src)
|
||||
{
|
||||
typedef typename DstXprType::Scalar Scalar;
|
||||
call_assignment(const_cast<DstXprType&>(dst), src.derived(), internal::sub_assign_op<Scalar>());
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
void multiply_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src)
|
||||
{
|
||||
typedef typename DstXprType::Scalar Scalar;
|
||||
call_assignment(dst.const_cast_derived(), src.derived(), internal::mul_assign_op<Scalar>());
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
void divide_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src)
|
||||
{
|
||||
typedef typename DstXprType::Scalar Scalar;
|
||||
call_assignment(dst.const_cast_derived(), src.derived(), internal::div_assign_op<Scalar>());
|
||||
}
|
||||
|
||||
template<typename DstXprType, typename SrcXprType>
|
||||
void swap_using_evaluator(const DstXprType& dst, const SrcXprType& src)
|
||||
{
|
||||
typedef typename DstXprType::Scalar Scalar;
|
||||
call_assignment(dst.const_cast_derived(), src.const_cast_derived(), internal::swap_assign_op<Scalar>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define VERIFY_IS_APPROX_EVALUATOR(DEST,EXPR) VERIFY_IS_APPROX(copy_using_evaluator(DEST,(EXPR)), (EXPR).eval());
|
||||
@@ -72,8 +143,19 @@ void test_evaluators()
|
||||
c = a*a;
|
||||
copy_using_evaluator(a, prod(a,a));
|
||||
VERIFY_IS_APPROX(a,c);
|
||||
|
||||
// check compound assignment of products
|
||||
d = c;
|
||||
add_assign_using_evaluator(c.noalias(), prod(a,b));
|
||||
d.noalias() += a*b;
|
||||
VERIFY_IS_APPROX(c, d);
|
||||
|
||||
d = c;
|
||||
subtract_assign_using_evaluator(c.noalias(), prod(a,b));
|
||||
d.noalias() -= a*b;
|
||||
VERIFY_IS_APPROX(c, d);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// test product with all possible sizes
|
||||
int s = internal::random<int>(1,100);
|
||||
@@ -124,7 +206,7 @@ void test_evaluators()
|
||||
|
||||
// this does not work because Random is eval-before-nested:
|
||||
// copy_using_evaluator(w, Vector2d::Random().transpose());
|
||||
|
||||
|
||||
// test CwiseUnaryOp
|
||||
VERIFY_IS_APPROX_EVALUATOR(v2, 3 * v);
|
||||
VERIFY_IS_APPROX_EVALUATOR(w, (3 * v).transpose());
|
||||
@@ -327,4 +409,56 @@ void test_evaluators()
|
||||
arr_ref.row(1) /= (arr_ref.row(2) + 1);
|
||||
VERIFY_IS_APPROX(arr, arr_ref);
|
||||
}
|
||||
|
||||
{
|
||||
// test triangular shapes
|
||||
MatrixXd A = MatrixXd::Random(6,6), B(6,6), C(6,6), D(6,6);
|
||||
A.setRandom();B.setRandom();
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView<Upper>(), MatrixXd(A.triangularView<Upper>()));
|
||||
|
||||
A.setRandom();B.setRandom();
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView<UnitLower>(), MatrixXd(A.triangularView<UnitLower>()));
|
||||
|
||||
A.setRandom();B.setRandom();
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView<UnitUpper>(), MatrixXd(A.triangularView<UnitUpper>()));
|
||||
|
||||
A.setRandom();B.setRandom();
|
||||
C = B; C.triangularView<Upper>() = A;
|
||||
copy_using_evaluator(B.triangularView<Upper>(), A);
|
||||
VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView<Upper>(), A)");
|
||||
|
||||
A.setRandom();B.setRandom();
|
||||
C = B; C.triangularView<Lower>() = A.triangularView<Lower>();
|
||||
copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Lower>());
|
||||
VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Lower>())");
|
||||
|
||||
|
||||
A.setRandom();B.setRandom();
|
||||
C = B; C.triangularView<Lower>() = A.triangularView<Upper>().transpose();
|
||||
copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Upper>().transpose());
|
||||
VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Lower>().transpose())");
|
||||
|
||||
|
||||
A.setRandom();B.setRandom(); C = B; D = A;
|
||||
C.triangularView<Upper>().swap(D.triangularView<Upper>());
|
||||
swap_using_evaluator(B.triangularView<Upper>(), A.triangularView<Upper>());
|
||||
VERIFY(B.isApprox(C) && "swap_using_evaluator(B.triangularView<Upper>(), A.triangularView<Upper>())");
|
||||
|
||||
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.triangularView<Upper>(),A), MatrixXd(A.triangularView<Upper>()*A));
|
||||
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.selfadjointView<Upper>(),A), MatrixXd(A.selfadjointView<Upper>()*A));
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
// test diagonal shapes
|
||||
VectorXd d = VectorXd::Random(6);
|
||||
MatrixXd A = MatrixXd::Random(6,6), B(6,6);
|
||||
A.setRandom();B.setRandom();
|
||||
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(d.asDiagonal(),A), MatrixXd(d.asDiagonal()*A));
|
||||
VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(A,d.asDiagonal()), MatrixXd(A*d.asDiagonal()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ template<typename Scalar,int Size> void homogeneous(void)
|
||||
hv0 << v0, 1;
|
||||
VERIFY_IS_APPROX(v0.homogeneous(), hv0);
|
||||
VERIFY_IS_APPROX(v0, hv0.hnormalized());
|
||||
|
||||
VERIFY_IS_APPROX(v0.homogeneous().sum(), hv0.sum());
|
||||
VERIFY_IS_APPROX(v0.homogeneous().minCoeff(), hv0.minCoeff());
|
||||
VERIFY_IS_APPROX(v0.homogeneous().maxCoeff(), hv0.maxCoeff());
|
||||
|
||||
hm0 << m0, ones.transpose();
|
||||
VERIFY_IS_APPROX(m0.colwise().homogeneous(), hm0);
|
||||
@@ -57,7 +61,6 @@ template<typename Scalar,int Size> void homogeneous(void)
|
||||
|
||||
VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t2,
|
||||
v0.transpose().rowwise().homogeneous() * t2);
|
||||
m0.transpose().rowwise().homogeneous().eval();
|
||||
VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t2,
|
||||
m0.transpose().rowwise().homogeneous() * t2);
|
||||
|
||||
@@ -82,7 +85,7 @@ template<typename Scalar,int Size> void homogeneous(void)
|
||||
VERIFY_IS_APPROX(aff * pts.colwise().homogeneous(), (aff * pts1).colwise().hnormalized());
|
||||
VERIFY_IS_APPROX(caff * pts.colwise().homogeneous(), (caff * pts1).colwise().hnormalized());
|
||||
VERIFY_IS_APPROX(proj * pts.colwise().homogeneous(), (proj * pts1));
|
||||
|
||||
|
||||
VERIFY_IS_APPROX((aff * pts1).colwise().hnormalized(), aff * pts);
|
||||
VERIFY_IS_APPROX((caff * pts1).colwise().hnormalized(), caff * pts);
|
||||
|
||||
|
||||
@@ -124,6 +124,33 @@ template<typename Scalar> void lines()
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar> void planes()
|
||||
{
|
||||
using std::abs;
|
||||
typedef Hyperplane<Scalar, 3> Plane;
|
||||
typedef Matrix<Scalar,3,1> Vector;
|
||||
typedef Matrix<Scalar,4,1> CoeffsType;
|
||||
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
Vector v0 = Vector::Random();
|
||||
Vector v1(v0), v2(v0);
|
||||
if(internal::random<double>(0,1)>0.25)
|
||||
v1 += Vector::Random();
|
||||
if(internal::random<double>(0,1)>0.25)
|
||||
v2 += v1 * std::pow(internal::random<Scalar>(0,1),internal::random<int>(1,16));
|
||||
if(internal::random<double>(0,1)>0.25)
|
||||
v2 += Vector::Random() * std::pow(internal::random<Scalar>(0,1),internal::random<int>(1,16));
|
||||
|
||||
Plane p0 = Plane::Through(v0, v1, v2);
|
||||
|
||||
VERIFY_IS_APPROX(p0.normal().norm(), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(p0.absDistance(v0), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(p0.absDistance(v1), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(p0.absDistance(v2), Scalar(1));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar> void hyperplane_alignment()
|
||||
{
|
||||
typedef Hyperplane<Scalar,3,AutoAlign> Plane3a;
|
||||
@@ -163,5 +190,7 @@ void test_geo_hyperplane()
|
||||
CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
|
||||
CALL_SUBTEST_1( lines<float>() );
|
||||
CALL_SUBTEST_3( lines<double>() );
|
||||
CALL_SUBTEST_2( planes<float>() );
|
||||
CALL_SUBTEST_5( planes<double>() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,16 @@ template<typename Scalar> void orthomethods_3()
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(Vector3::Random()).dot(v1), Scalar(1));
|
||||
Matrix3 mat3;
|
||||
mat3 << v0.normalized(),
|
||||
(v0.cross(v1)).normalized(),
|
||||
(v0.cross(v1).cross(v0)).normalized();
|
||||
VERIFY(mat3.isUnitary());
|
||||
|
||||
|
||||
mat3.setRandom();
|
||||
VERIFY_IS_APPROX(v0.cross(mat3*v1), -(mat3*v1).cross(v0));
|
||||
VERIFY_IS_APPROX(v0.cross(mat3.lazyProduct(v1)), -(mat3.lazyProduct(v1)).cross(v0));
|
||||
|
||||
// colwise/rowwise cross product
|
||||
mat3.setRandom();
|
||||
@@ -47,6 +51,13 @@ template<typename Scalar> void orthomethods_3()
|
||||
int i = internal::random<int>(0,2);
|
||||
mcross = mat3.colwise().cross(vec3);
|
||||
VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
|
||||
|
||||
VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1));
|
||||
|
||||
VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));
|
||||
|
||||
mcross = mat3.rowwise().cross(vec3);
|
||||
VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
|
||||
|
||||
@@ -57,6 +68,7 @@ template<typename Scalar> void orthomethods_3()
|
||||
v40.w() = v41.w() = v42.w() = 0;
|
||||
v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>());
|
||||
VERIFY_IS_APPROX(v40.cross3(v41), v42);
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v40.cross3(Vector4::Random()).dot(v40), Scalar(1));
|
||||
|
||||
// check mixed product
|
||||
typedef Matrix<RealScalar, 3, 1> RealVector3;
|
||||
|
||||
@@ -98,11 +98,17 @@ template<typename Scalar, int Mode, int Options> void transformations()
|
||||
Matrix3 matrot1, m;
|
||||
|
||||
Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
|
||||
Scalar s0 = internal::random<Scalar>();
|
||||
Scalar s0 = internal::random<Scalar>(), s1 = internal::random<Scalar>();
|
||||
|
||||
while(v0.norm() < test_precision<Scalar>()) v0 = Vector3::Random();
|
||||
while(v1.norm() < test_precision<Scalar>()) v1 = Vector3::Random();
|
||||
|
||||
VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
|
||||
VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
|
||||
VERIFY_IS_APPROX(cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
|
||||
if(abs(cos(a)) > test_precision<Scalar>())
|
||||
{
|
||||
VERIFY_IS_APPROX(cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
|
||||
}
|
||||
m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
|
||||
VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
|
||||
VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
|
||||
@@ -123,11 +129,18 @@ template<typename Scalar, int Mode, int Options> void transformations()
|
||||
// angle-axis conversion
|
||||
AngleAxisx aa = AngleAxisx(q1);
|
||||
VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
|
||||
VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
|
||||
|
||||
if(abs(aa.angle()) > NumTraits<Scalar>::dummy_precision())
|
||||
{
|
||||
VERIFY( !(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1) );
|
||||
}
|
||||
|
||||
aa.fromRotationMatrix(aa.toRotationMatrix());
|
||||
VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
|
||||
VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
|
||||
if(abs(aa.angle()) > NumTraits<Scalar>::dummy_precision())
|
||||
{
|
||||
VERIFY( !(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1) );
|
||||
}
|
||||
|
||||
// AngleAxis
|
||||
VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
|
||||
@@ -347,7 +360,9 @@ template<typename Scalar, int Mode, int Options> void transformations()
|
||||
// test transform inversion
|
||||
t0.setIdentity();
|
||||
t0.translate(v0);
|
||||
t0.linear().setRandom();
|
||||
do {
|
||||
t0.linear().setRandom();
|
||||
} while(t0.linear().jacobiSvd().singularValues()(2)<test_precision<Scalar>());
|
||||
Matrix4 t044 = Matrix4::Zero();
|
||||
t044(3,3) = 1;
|
||||
t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
|
||||
@@ -394,9 +409,29 @@ template<typename Scalar, int Mode, int Options> void transformations()
|
||||
Rotation2D<double> r2d1d = r2d1.template cast<double>();
|
||||
VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
|
||||
|
||||
t20 = Translation2(v20) * (Rotation2D<Scalar>(s0) * Eigen::Scaling(s0));
|
||||
t21 = Translation2(v20) * Rotation2D<Scalar>(s0) * Eigen::Scaling(s0);
|
||||
Rotation2D<Scalar> R0(s0), R1(s1);
|
||||
|
||||
t20 = Translation2(v20) * (R0 * Eigen::Scaling(s0));
|
||||
t21 = Translation2(v20) * R0 * Eigen::Scaling(s0);
|
||||
VERIFY_IS_APPROX(t20,t21);
|
||||
|
||||
t20 = Translation2(v20) * (R0 * R0.inverse() * Eigen::Scaling(s0));
|
||||
t21 = Translation2(v20) * Eigen::Scaling(s0);
|
||||
VERIFY_IS_APPROX(t20,t21);
|
||||
|
||||
VERIFY_IS_APPROX(s0, (R0.slerp(0, R1)).angle());
|
||||
VERIFY_IS_APPROX(s1, (R0.slerp(1, R1)).angle());
|
||||
VERIFY_IS_APPROX(s0, (R0.slerp(0.5, R0)).angle());
|
||||
VERIFY_IS_APPROX(Scalar(0), (R0.slerp(0.5, R0.inverse())).angle());
|
||||
|
||||
// check basic features
|
||||
{
|
||||
Rotation2D<Scalar> r1; // default ctor
|
||||
r1 = Rotation2D<Scalar>(s0); // copy assignment
|
||||
VERIFY_IS_APPROX(r1.angle(),s0);
|
||||
Rotation2D<Scalar> r2(r1); // copy ctor
|
||||
VERIFY_IS_APPROX(r2.angle(),s0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar> void transform_alignment()
|
||||
|
||||
@@ -68,6 +68,15 @@ template<typename MatrixType> void inverse(const MatrixType& m)
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1));
|
||||
m3.computeInverseWithCheck(m4, invertible);
|
||||
VERIFY( rows==1 ? invertible : !invertible );
|
||||
|
||||
// check with submatrices
|
||||
{
|
||||
Matrix<Scalar, MatrixType::RowsAtCompileTime+1, MatrixType::RowsAtCompileTime+1, MatrixType::Options> m3;
|
||||
m3.setRandom();
|
||||
m3.topLeftCorner(rows,rows) = m1;
|
||||
m2 = m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>().inverse();
|
||||
VERIFY_IS_APPROX( (m3.template topLeftCorner<MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime>()), m2.inverse() );
|
||||
}
|
||||
#endif
|
||||
|
||||
// check in-place inversion
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
@@ -14,273 +14,47 @@
|
||||
#include "main.h"
|
||||
#include <Eigen/SVD>
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
void jacobisvd_check_full(const MatrixType& m, const JacobiSVD<MatrixType, QRPreconditioner>& svd)
|
||||
{
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime> MatrixUType;
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime> MatrixVType;
|
||||
|
||||
MatrixType sigma = MatrixType::Zero(rows,cols);
|
||||
sigma.diagonal() = svd.singularValues().template cast<Scalar>();
|
||||
MatrixUType u = svd.matrixU();
|
||||
MatrixVType v = svd.matrixV();
|
||||
|
||||
VERIFY_IS_APPROX(m, u * sigma * v.adjoint());
|
||||
VERIFY_IS_UNITARY(u);
|
||||
VERIFY_IS_UNITARY(v);
|
||||
}
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
void jacobisvd_compare_to_full(const MatrixType& m,
|
||||
unsigned int computationOptions,
|
||||
const JacobiSVD<MatrixType, QRPreconditioner>& referenceSvd)
|
||||
{
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
Index diagSize = (std::min)(rows, cols);
|
||||
|
||||
JacobiSVD<MatrixType, QRPreconditioner> svd(m, computationOptions);
|
||||
|
||||
VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues());
|
||||
if(computationOptions & ComputeFullU)
|
||||
VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU());
|
||||
if(computationOptions & ComputeThinU)
|
||||
VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize));
|
||||
if(computationOptions & ComputeFullV)
|
||||
VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV());
|
||||
if(computationOptions & ComputeThinV)
|
||||
VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize));
|
||||
}
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, Dynamic> RhsType;
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, Dynamic> SolutionType;
|
||||
|
||||
RhsType rhs = RhsType::Random(rows, internal::random<Index>(1, cols));
|
||||
JacobiSVD<MatrixType, QRPreconditioner> svd(m, computationOptions);
|
||||
|
||||
if(internal::is_same<RealScalar,double>::value) svd.setThreshold(1e-8);
|
||||
else if(internal::is_same<RealScalar,float>::value) svd.setThreshold(1e-4);
|
||||
|
||||
SolutionType x = svd.solve(rhs);
|
||||
|
||||
RealScalar residual = (m*x-rhs).norm();
|
||||
// Check that there is no significantly better solution in the neighborhood of x
|
||||
if(!test_isMuchSmallerThan(residual,rhs.norm()))
|
||||
{
|
||||
// If the residual is very small, then we have an exact solution, so we are already good.
|
||||
for(int k=0;k<x.rows();++k)
|
||||
{
|
||||
SolutionType y(x);
|
||||
y.row(k).array() += 2*NumTraits<RealScalar>::epsilon();
|
||||
RealScalar residual_y = (m*y-rhs).norm();
|
||||
VERIFY( test_isApprox(residual_y,residual) || residual < residual_y );
|
||||
|
||||
y.row(k) = x.row(k).array() - 2*NumTraits<RealScalar>::epsilon();
|
||||
residual_y = (m*y-rhs).norm();
|
||||
VERIFY( test_isApprox(residual_y,residual) || residual < residual_y );
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate normal equation which works also for least-squares solutions
|
||||
if(internal::is_same<RealScalar,double>::value)
|
||||
{
|
||||
// This test is not stable with single precision.
|
||||
// This is probably because squaring m signicantly affects the precision.
|
||||
VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs);
|
||||
}
|
||||
|
||||
// check minimal norm solutions
|
||||
{
|
||||
// generate a full-rank m x n problem with m<n
|
||||
enum {
|
||||
RankAtCompileTime2 = ColsAtCompileTime==Dynamic ? Dynamic : (ColsAtCompileTime)/2+1,
|
||||
RowsAtCompileTime3 = ColsAtCompileTime==Dynamic ? Dynamic : ColsAtCompileTime+1
|
||||
};
|
||||
typedef Matrix<Scalar, RankAtCompileTime2, ColsAtCompileTime> MatrixType2;
|
||||
typedef Matrix<Scalar, RankAtCompileTime2, 1> RhsType2;
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, RankAtCompileTime2> MatrixType2T;
|
||||
Index rank = RankAtCompileTime2==Dynamic ? internal::random<Index>(1,cols) : Index(RankAtCompileTime2);
|
||||
MatrixType2 m2(rank,cols);
|
||||
int guard = 0;
|
||||
do {
|
||||
m2.setRandom();
|
||||
} while(m2.jacobiSvd().setThreshold(test_precision<Scalar>()).rank()!=rank && (++guard)<10);
|
||||
VERIFY(guard<10);
|
||||
RhsType2 rhs2 = RhsType2::Random(rank);
|
||||
// use QR to find a reference minimal norm solution
|
||||
HouseholderQR<MatrixType2T> qr(m2.adjoint());
|
||||
Matrix<Scalar,Dynamic,1> tmp = qr.matrixQR().topLeftCorner(rank,rank).template triangularView<Upper>().adjoint().solve(rhs2);
|
||||
tmp.conservativeResize(cols);
|
||||
tmp.tail(cols-rank).setZero();
|
||||
SolutionType x21 = qr.householderQ() * tmp;
|
||||
// now check with SVD
|
||||
JacobiSVD<MatrixType2, ColPivHouseholderQRPreconditioner> svd2(m2, computationOptions);
|
||||
SolutionType x22 = svd2.solve(rhs2);
|
||||
VERIFY_IS_APPROX(m2*x21, rhs2);
|
||||
VERIFY_IS_APPROX(m2*x22, rhs2);
|
||||
VERIFY_IS_APPROX(x21, x22);
|
||||
|
||||
// Now check with a rank deficient matrix
|
||||
typedef Matrix<Scalar, RowsAtCompileTime3, ColsAtCompileTime> MatrixType3;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime3, 1> RhsType3;
|
||||
Index rows3 = RowsAtCompileTime3==Dynamic ? internal::random<Index>(rank+1,2*cols) : Index(RowsAtCompileTime3);
|
||||
Matrix<Scalar,RowsAtCompileTime3,Dynamic> C = Matrix<Scalar,RowsAtCompileTime3,Dynamic>::Random(rows3,rank);
|
||||
MatrixType3 m3 = C * m2;
|
||||
RhsType3 rhs3 = C * rhs2;
|
||||
JacobiSVD<MatrixType3, ColPivHouseholderQRPreconditioner> svd3(m3, computationOptions);
|
||||
SolutionType x3 = svd3.solve(rhs3);
|
||||
VERIFY_IS_APPROX(m3*x3, rhs3);
|
||||
VERIFY_IS_APPROX(m3*x21, rhs3);
|
||||
VERIFY_IS_APPROX(m2*x3, rhs2);
|
||||
|
||||
VERIFY_IS_APPROX(x21, x3);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
void jacobisvd_test_all_computation_options(const MatrixType& m)
|
||||
{
|
||||
if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols())
|
||||
return;
|
||||
JacobiSVD<MatrixType, QRPreconditioner> fullSvd(m, ComputeFullU|ComputeFullV);
|
||||
CALL_SUBTEST(( jacobisvd_check_full(m, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeFullU | ComputeFullV) ));
|
||||
|
||||
#if defined __INTEL_COMPILER
|
||||
// remark #111: statement is unreachable
|
||||
#pragma warning disable 111
|
||||
#endif
|
||||
if(QRPreconditioner == FullPivHouseholderQRPreconditioner)
|
||||
return;
|
||||
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullU, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullV, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, 0, fullSvd) ));
|
||||
|
||||
if (MatrixType::ColsAtCompileTime == Dynamic) {
|
||||
// thin U/V are only available with dynamic number of columns
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU , fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeFullU | ComputeThinV) ));
|
||||
CALL_SUBTEST(( jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeThinU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeThinU | ComputeThinV) ));
|
||||
|
||||
// test reconstruction
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index diagSize = (std::min)(m.rows(), m.cols());
|
||||
JacobiSVD<MatrixType, QRPreconditioner> svd(m, ComputeThinU | ComputeThinV);
|
||||
VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint());
|
||||
}
|
||||
}
|
||||
#define SVD_DEFAULT(M) JacobiSVD<M>
|
||||
#define SVD_FOR_MIN_NORM(M) JacobiSVD<M,ColPivHouseholderQRPreconditioner>
|
||||
#include "svd_common.h"
|
||||
|
||||
// Check all variants of JacobiSVD
|
||||
template<typename MatrixType>
|
||||
void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
|
||||
{
|
||||
MatrixType m = a;
|
||||
if(pickrandom)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index diagSize = (std::min)(a.rows(), a.cols());
|
||||
RealScalar s = std::numeric_limits<RealScalar>::max_exponent10/4;
|
||||
s = internal::random<RealScalar>(1,s);
|
||||
Matrix<RealScalar,Dynamic,1> d = Matrix<RealScalar,Dynamic,1>::Random(diagSize);
|
||||
for(Index k=0; k<diagSize; ++k)
|
||||
d(k) = d(k)*std::pow(RealScalar(10),internal::random<RealScalar>(-s,s));
|
||||
m = Matrix<Scalar,Dynamic,Dynamic>::Random(a.rows(),diagSize) * d.asDiagonal() * Matrix<Scalar,Dynamic,Dynamic>::Random(diagSize,a.cols());
|
||||
// cancel some coeffs
|
||||
Index n = internal::random<Index>(0,m.size()-1);
|
||||
for(Index i=0; i<n; ++i)
|
||||
m(internal::random<Index>(0,m.rows()-1), internal::random<Index>(0,m.cols()-1)) = Scalar(0);
|
||||
}
|
||||
svd_fill_random(m);
|
||||
|
||||
CALL_SUBTEST(( jacobisvd_test_all_computation_options<MatrixType, FullPivHouseholderQRPreconditioner>(m) ));
|
||||
CALL_SUBTEST(( jacobisvd_test_all_computation_options<MatrixType, ColPivHouseholderQRPreconditioner>(m) ));
|
||||
CALL_SUBTEST(( jacobisvd_test_all_computation_options<MatrixType, HouseholderQRPreconditioner>(m) ));
|
||||
CALL_SUBTEST(( jacobisvd_test_all_computation_options<MatrixType, NoQRPreconditioner>(m) ));
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner> >(m, true) )); // check full only
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner> >(m, false) ));
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, HouseholderQRPreconditioner> >(m, false) ));
|
||||
if(m.rows()==m.cols())
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, NoQRPreconditioner> >(m, false) ));
|
||||
}
|
||||
|
||||
template<typename MatrixType> void jacobisvd_verify_assert(const MatrixType& m)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
svd_verify_assert<JacobiSVD<MatrixType> >(m);
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, 1> RhsType;
|
||||
|
||||
RhsType rhs(rows);
|
||||
|
||||
JacobiSVD<MatrixType> svd;
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.singularValues())
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
|
||||
MatrixType a = MatrixType::Zero(rows, cols);
|
||||
a.setZero();
|
||||
svd.compute(a, 0);
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
svd.singularValues();
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
|
||||
if (ColsAtCompileTime == Dynamic)
|
||||
{
|
||||
svd.compute(a, ComputeThinU);
|
||||
svd.matrixU();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
|
||||
svd.compute(a, ComputeThinV);
|
||||
svd.matrixV();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
|
||||
JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner> svd_fullqr;
|
||||
VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeFullU|ComputeThinV))
|
||||
VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeThinV))
|
||||
VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeFullV))
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU))
|
||||
VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV))
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
@@ -296,165 +70,17 @@ void jacobisvd_method()
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
}
|
||||
|
||||
// work around stupid msvc error when constructing at compile time an expression that involves
|
||||
// a division by zero, even if the numeric type has floating point
|
||||
template<typename Scalar>
|
||||
EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); }
|
||||
|
||||
// workaround aggressive optimization in ICC
|
||||
template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
|
||||
|
||||
template<typename MatrixType>
|
||||
void jacobisvd_inf_nan()
|
||||
{
|
||||
// all this function does is verify we don't iterate infinitely on nan/inf values
|
||||
|
||||
JacobiSVD<MatrixType> svd;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
Scalar some_inf = Scalar(1) / zero<Scalar>();
|
||||
VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf));
|
||||
svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV);
|
||||
|
||||
Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
VERIFY(nan != nan);
|
||||
svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV);
|
||||
|
||||
MatrixType m = MatrixType::Zero(10,10);
|
||||
m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_inf;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
m = MatrixType::Zero(10,10);
|
||||
m(internal::random<int>(0,9), internal::random<int>(0,9)) = nan;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
// regression test for bug 791
|
||||
m.resize(3,3);
|
||||
m << 0, 2*NumTraits<Scalar>::epsilon(), 0.5,
|
||||
0, -0.5, 0,
|
||||
nan, 0, 0;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
m.resize(4,4);
|
||||
m << 1, 0, 0, 0,
|
||||
0, 3, 1, 2e-308,
|
||||
1, 0, 1, nan,
|
||||
0, nan, nan, 0;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
}
|
||||
|
||||
// Regression test for bug 286: JacobiSVD loops indefinitely with some
|
||||
// matrices containing denormal numbers.
|
||||
void jacobisvd_underoverflow()
|
||||
{
|
||||
#if defined __INTEL_COMPILER
|
||||
// shut up warning #239: floating point underflow
|
||||
#pragma warning push
|
||||
#pragma warning disable 239
|
||||
#endif
|
||||
Matrix2d M;
|
||||
M << -7.90884e-313, -4.94e-324,
|
||||
0, 5.60844e-313;
|
||||
JacobiSVD<Matrix2d> svd;
|
||||
svd.compute(M,ComputeFullU|ComputeFullV);
|
||||
jacobisvd_check_full(M,svd);
|
||||
|
||||
VectorXd value_set(9);
|
||||
value_set << 0, 1, -1, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -4.94e-223, 4.94e-223;
|
||||
Array4i id(0,0,0,0);
|
||||
int k = 0;
|
||||
do
|
||||
{
|
||||
M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3));
|
||||
svd.compute(M,ComputeFullU|ComputeFullV);
|
||||
jacobisvd_check_full(M,svd);
|
||||
|
||||
id(k)++;
|
||||
if(id(k)>=value_set.size())
|
||||
{
|
||||
while(k<3 && id(k)>=value_set.size()) id(++k)++;
|
||||
id.head(k).setZero();
|
||||
k=0;
|
||||
}
|
||||
|
||||
} while((id<int(value_set.size())).all());
|
||||
|
||||
#if defined __INTEL_COMPILER
|
||||
#pragma warning pop
|
||||
#endif
|
||||
|
||||
// Check for overflow:
|
||||
Matrix3d M3;
|
||||
M3 << 4.4331978442502944e+307, -5.8585363752028680e+307, 6.4527017443412964e+307,
|
||||
3.7841695601406358e+307, 2.4331702789740617e+306, -3.5235707140272905e+307,
|
||||
-8.7190887618028355e+307, -7.3453213709232193e+307, -2.4367363684472105e+307;
|
||||
|
||||
JacobiSVD<Matrix3d> svd3;
|
||||
svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely
|
||||
jacobisvd_check_full(M3,svd3);
|
||||
}
|
||||
|
||||
void jacobisvd_preallocate()
|
||||
{
|
||||
Vector3f v(3.f, 2.f, 1.f);
|
||||
MatrixXf m = v.asDiagonal();
|
||||
|
||||
internal::set_is_malloc_allowed(false);
|
||||
VERIFY_RAISES_ASSERT(VectorXf tmp(10);)
|
||||
JacobiSVD<MatrixXf> svd;
|
||||
internal::set_is_malloc_allowed(true);
|
||||
svd.compute(m);
|
||||
VERIFY_IS_APPROX(svd.singularValues(), v);
|
||||
|
||||
JacobiSVD<MatrixXf> svd2(3,3);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
VERIFY_IS_APPROX(svd2.singularValues(), v);
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixU());
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixV());
|
||||
svd2.compute(m, ComputeFullU | ComputeFullV);
|
||||
VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
|
||||
VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
|
||||
JacobiSVD<MatrixXf> svd3(3,3,ComputeFullU|ComputeFullV);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
VERIFY_IS_APPROX(svd2.singularValues(), v);
|
||||
VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
|
||||
VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m, ComputeFullU|ComputeFullV);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
}
|
||||
|
||||
void test_jacobisvd()
|
||||
{
|
||||
CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) ));
|
||||
CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) ));
|
||||
CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) ));
|
||||
CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) ));
|
||||
|
||||
CALL_SUBTEST_11(svd_all_trivial_2x2(jacobisvd<Matrix2cd>));
|
||||
CALL_SUBTEST_12(svd_all_trivial_2x2(jacobisvd<Matrix2d>));
|
||||
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
Matrix2cd m;
|
||||
m << 0, 1,
|
||||
0, 1;
|
||||
CALL_SUBTEST_1(( jacobisvd(m, false) ));
|
||||
m << 1, 0,
|
||||
1, 0;
|
||||
CALL_SUBTEST_1(( jacobisvd(m, false) ));
|
||||
|
||||
Matrix2d n;
|
||||
n << 0, 0,
|
||||
0, 0;
|
||||
CALL_SUBTEST_2(( jacobisvd(n, false) ));
|
||||
n << 0, 0,
|
||||
0, 1;
|
||||
CALL_SUBTEST_2(( jacobisvd(n, false) ));
|
||||
|
||||
CALL_SUBTEST_3(( jacobisvd<Matrix3f>() ));
|
||||
CALL_SUBTEST_4(( jacobisvd<Matrix4d>() ));
|
||||
CALL_SUBTEST_5(( jacobisvd<Matrix<float,3,5> >() ));
|
||||
@@ -473,8 +99,8 @@ void test_jacobisvd()
|
||||
(void) c;
|
||||
|
||||
// Test on inf/nan matrix
|
||||
CALL_SUBTEST_7( jacobisvd_inf_nan<MatrixXf>() );
|
||||
CALL_SUBTEST_10( jacobisvd_inf_nan<MatrixXd>() );
|
||||
CALL_SUBTEST_7( (svd_inf_nan<JacobiSVD<MatrixXf>, MatrixXf>()) );
|
||||
CALL_SUBTEST_10( (svd_inf_nan<JacobiSVD<MatrixXd>, MatrixXd>()) );
|
||||
}
|
||||
|
||||
CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) ));
|
||||
@@ -488,8 +114,7 @@ void test_jacobisvd()
|
||||
CALL_SUBTEST_7( JacobiSVD<MatrixXf>(10,10) );
|
||||
|
||||
// Check that preallocation avoids subsequent mallocs
|
||||
CALL_SUBTEST_9( jacobisvd_preallocate() );
|
||||
CALL_SUBTEST_9( svd_preallocate() );
|
||||
|
||||
// Regression check for bug 286
|
||||
CALL_SUBTEST_2( jacobisvd_underoverflow() );
|
||||
CALL_SUBTEST_2( svd_underoverflow() );
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
static bool g_called;
|
||||
|
||||
#define EIGEN_SPECIAL_SCALAR_MULTIPLE_PLUGIN { g_called = true; }
|
||||
|
||||
#include "main.h"
|
||||
@@ -93,6 +92,8 @@ template<typename MatrixType> void real_complex(DenseIndex rows = MatrixType::Ro
|
||||
|
||||
void test_linearstructure()
|
||||
{
|
||||
g_called = true;
|
||||
VERIFY(g_called); // avoid `unneeded-internal-declaration` warning.
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1( linearStructure(Matrix<float, 1, 1>()) );
|
||||
CALL_SUBTEST_2( linearStructure(Matrix2f()) );
|
||||
@@ -107,4 +108,19 @@ void test_linearstructure()
|
||||
CALL_SUBTEST_10( real_complex<Matrix4cd>() );
|
||||
CALL_SUBTEST_10( real_complex<MatrixXcf>(10,10) );
|
||||
}
|
||||
|
||||
#ifdef EIGEN_TEST_PART_4
|
||||
{
|
||||
// make sure that /=scalar and /scalar do not overflow
|
||||
// rational: 1.0/4.94e-320 overflow, but m/4.94e-320 should not
|
||||
Matrix4d m2, m3;
|
||||
m3 = m2 = Matrix4d::Random()*1e-20;
|
||||
m2 = m2 / 4.9e-320;
|
||||
VERIFY_IS_APPROX(m2.cwiseQuotient(m2), Matrix4d::Ones());
|
||||
m3 /= 4.9e-320;
|
||||
VERIFY_IS_APPROX(m3.cwiseQuotient(m3), Matrix4d::Ones());
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
33
test/main.h
33
test/main.h
@@ -61,7 +61,7 @@
|
||||
#endif
|
||||
|
||||
// shuts down ICC's remark #593: variable "XXX" was set but never used
|
||||
#define TEST_SET_BUT_UNUSED_VARIABLE(X) X = X + 0;
|
||||
#define TEST_SET_BUT_UNUSED_VARIABLE(X) EIGEN_UNUSED_VARIABLE(X)
|
||||
|
||||
// the following file is automatically generated by cmake
|
||||
#include "split_test_helper.h"
|
||||
@@ -76,7 +76,7 @@
|
||||
#endif
|
||||
|
||||
// bounds integer values for AltiVec
|
||||
#ifdef __ALTIVEC__
|
||||
#if defined(__ALTIVEC__) || defined(__VSX__)
|
||||
#define EIGEN_MAKING_DOCS
|
||||
#endif
|
||||
|
||||
@@ -94,6 +94,9 @@ namespace Eigen
|
||||
static bool g_has_set_repeat, g_has_set_seed;
|
||||
}
|
||||
|
||||
#define TRACK std::cerr << __FILE__ << " " << __LINE__ << std::endl
|
||||
// #define TRACK while()
|
||||
|
||||
#define EI_PP_MAKE_STRING2(S) #S
|
||||
#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
|
||||
|
||||
@@ -312,13 +315,7 @@ inline bool test_isApproxOrLessThan(const long double& a, const long double& b)
|
||||
template<typename Type1, typename Type2>
|
||||
inline bool test_isApprox(const Type1& a, const Type2& b)
|
||||
{
|
||||
#ifdef EIGEN_TEST_EVALUATORS
|
||||
typename internal::eval<Type1>::type a_eval(a);
|
||||
typename internal::eval<Type2>::type b_eval(b);
|
||||
return a_eval.isApprox(b_eval, test_precision<typename Type1::Scalar>());
|
||||
#else
|
||||
return a.isApprox(b, test_precision<typename Type1::Scalar>());
|
||||
#endif
|
||||
}
|
||||
|
||||
// The idea behind this function is to compare the two scalars a and b where
|
||||
@@ -436,6 +433,26 @@ void randomPermutationVector(PermutationVectorType& v, typename PermutationVecto
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> bool isNotNaN(const T& x)
|
||||
{
|
||||
return x==x;
|
||||
}
|
||||
|
||||
template<typename T> bool isNaN(const T& x)
|
||||
{
|
||||
return x!=x;
|
||||
}
|
||||
|
||||
template<typename T> bool isInf(const T& x)
|
||||
{
|
||||
return x > NumTraits<T>::highest();
|
||||
}
|
||||
|
||||
template<typename T> bool isMinusInf(const T& x)
|
||||
{
|
||||
return x < NumTraits<T>::lowest();
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
template<typename T> struct GetDifferentType;
|
||||
|
||||
@@ -53,10 +53,11 @@ template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
|
||||
mf+mf;
|
||||
VERIFY_RAISES_ASSERT(mf+md);
|
||||
VERIFY_RAISES_ASSERT(mf+mcf);
|
||||
VERIFY_RAISES_ASSERT(vf=vd);
|
||||
VERIFY_RAISES_ASSERT(vf+=vd);
|
||||
VERIFY_RAISES_ASSERT(mcd=md);
|
||||
|
||||
// the following do not even compile since the introduction of evaluators
|
||||
// VERIFY_RAISES_ASSERT(vf=vd);
|
||||
// VERIFY_RAISES_ASSERT(vf+=vd);
|
||||
// VERIFY_RAISES_ASSERT(mcd=md);
|
||||
|
||||
// check scalar products
|
||||
VERIFY_IS_APPROX(vcf * sf , vcf * complex<float>(sf));
|
||||
VERIFY_IS_APPROX(sd * vcd, complex<double>(sd) * vcd);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
template <typename MatrixType> void run_nesting_ops(const MatrixType& _m)
|
||||
{
|
||||
typename MatrixType::Nested m(_m);
|
||||
typename internal::nested_eval<MatrixType,2>::type m(_m);
|
||||
|
||||
// Make really sure that we are in debug mode!
|
||||
VERIFY_RAISES_ASSERT(eigen_assert(false));
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
// discard stack allocation as that too bypasses malloc
|
||||
#define EIGEN_STACK_ALLOCATION_LIMIT 0
|
||||
// any heap allocation will raise an assert
|
||||
#define EIGEN_NO_MALLOC
|
||||
#define EIGEN_RUNTIME_NO_MALLOC
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/Cholesky>
|
||||
@@ -165,8 +165,62 @@ void ctms_decompositions()
|
||||
Eigen::JacobiSVD<Matrix> jSVD; jSVD.compute(A, ComputeFullU | ComputeFullV);
|
||||
}
|
||||
|
||||
void test_zerosized() {
|
||||
// default constructors:
|
||||
Eigen::MatrixXd A;
|
||||
Eigen::VectorXd v;
|
||||
// explicit zero-sized:
|
||||
Eigen::ArrayXXd A0(0,0);
|
||||
Eigen::ArrayXd v0(0);
|
||||
|
||||
// assigning empty objects to each other:
|
||||
A=A0;
|
||||
v=v0;
|
||||
}
|
||||
|
||||
template<typename MatrixType> void test_reference(const MatrixType& m) {
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
enum { Flag = MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor};
|
||||
enum { TransposeFlag = !MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor};
|
||||
typename MatrixType::Index rows = m.rows(), cols=m.cols();
|
||||
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Flag > MatrixX;
|
||||
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, TransposeFlag> MatrixXT;
|
||||
// Dynamic reference:
|
||||
typedef Eigen::Ref<const MatrixX > Ref;
|
||||
typedef Eigen::Ref<const MatrixXT > RefT;
|
||||
|
||||
Ref r1(m);
|
||||
Ref r2(m.block(rows/3, cols/4, rows/2, cols/2));
|
||||
RefT r3(m.transpose());
|
||||
RefT r4(m.topLeftCorner(rows/2, cols/2).transpose());
|
||||
|
||||
VERIFY_RAISES_ASSERT(RefT r5(m));
|
||||
VERIFY_RAISES_ASSERT(Ref r6(m.transpose()));
|
||||
VERIFY_RAISES_ASSERT(Ref r7(Scalar(2) * m));
|
||||
|
||||
// Copy constructors shall also never malloc
|
||||
Ref r8 = r1;
|
||||
RefT r9 = r3;
|
||||
|
||||
// Initializing from a compatible Ref shall also never malloc
|
||||
Eigen::Ref<const MatrixX, Unaligned, Stride<Dynamic, Dynamic> > r10=r8, r11=m;
|
||||
|
||||
// Initializing from an incompatible Ref will malloc:
|
||||
typedef Eigen::Ref<const MatrixX, Aligned> RefAligned;
|
||||
VERIFY_RAISES_ASSERT(RefAligned r12=r10);
|
||||
VERIFY_RAISES_ASSERT(Ref r13=r10); // r10 has more dynamic strides
|
||||
|
||||
}
|
||||
|
||||
void test_nomalloc()
|
||||
{
|
||||
// create some dynamic objects
|
||||
Eigen::MatrixXd M1 = MatrixXd::Random(3,3);
|
||||
Ref<const MatrixXd> R1 = 2.0*M1; // Ref requires temporary
|
||||
|
||||
// from here on prohibit malloc:
|
||||
Eigen::internal::set_is_malloc_allowed(false);
|
||||
|
||||
// check that our operator new is indeed called:
|
||||
VERIFY_RAISES_ASSERT(MatrixXd dummy(MatrixXd::Random(3,3)));
|
||||
CALL_SUBTEST_1(nomalloc(Matrix<float, 1, 1>()) );
|
||||
@@ -176,4 +230,9 @@ void test_nomalloc()
|
||||
// Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms)
|
||||
CALL_SUBTEST_4(ctms_decompositions<float>());
|
||||
|
||||
CALL_SUBTEST_5(test_zerosized());
|
||||
|
||||
CALL_SUBTEST_6(test_reference(Matrix<float,32,32>()));
|
||||
CALL_SUBTEST_7(test_reference(R1));
|
||||
CALL_SUBTEST_8(Ref<MatrixXd> R2 = M1.topRows<2>(); test_reference(R2));
|
||||
}
|
||||
|
||||
@@ -80,7 +80,9 @@ void testVectorType(const VectorType& base)
|
||||
Matrix<Scalar,1,Dynamic> col_vector(size);
|
||||
row_vector.setLinSpaced(size,low,high);
|
||||
col_vector.setLinSpaced(size,low,high);
|
||||
VERIFY( row_vector.isApprox(col_vector.transpose(), NumTraits<Scalar>::epsilon()));
|
||||
// when using the extended precision (e.g., FPU) the relative error might exceed 1 bit
|
||||
// when computing the squared sum in isApprox, thus the 2x factor.
|
||||
VERIFY( row_vector.isApprox(col_vector.transpose(), Scalar(2)*NumTraits<Scalar>::epsilon()));
|
||||
|
||||
Matrix<Scalar,Dynamic,1> size_changer(size+50);
|
||||
size_changer.setLinSpaced(size,low,high);
|
||||
|
||||
@@ -156,7 +156,7 @@ template<typename Scalar> void packetmath()
|
||||
CHECK_CWISE2(REF_ADD, internal::padd);
|
||||
CHECK_CWISE2(REF_SUB, internal::psub);
|
||||
CHECK_CWISE2(REF_MUL, internal::pmul);
|
||||
#ifndef EIGEN_VECTORIZE_ALTIVEC
|
||||
#if !defined(EIGEN_VECTORIZE_ALTIVEC) && !defined(EIGEN_VECTORIZE_VSX)
|
||||
if (!internal::is_same<Scalar,int>::value)
|
||||
CHECK_CWISE2(REF_DIV, internal::pdiv);
|
||||
#endif
|
||||
@@ -313,6 +313,12 @@ template<typename Scalar> void packetmath_real()
|
||||
data2[i] = internal::random<Scalar>(-87,88);
|
||||
}
|
||||
CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasExp, std::exp, internal::pexp);
|
||||
{
|
||||
data1[0] = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
packet_helper<internal::packet_traits<Scalar>::HasExp,Packet> h;
|
||||
h.store(data2, internal::pexp(h.load(data1)));
|
||||
VERIFY(isNaN(data2[0]));
|
||||
}
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
{
|
||||
@@ -321,8 +327,22 @@ template<typename Scalar> void packetmath_real()
|
||||
}
|
||||
if(internal::random<float>(0,1)<0.1)
|
||||
data1[internal::random<int>(0, PacketSize)] = 0;
|
||||
CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasLog, std::log, internal::plog);
|
||||
CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasSqrt, std::sqrt, internal::psqrt);
|
||||
CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasLog, std::log, internal::plog);
|
||||
{
|
||||
data1[0] = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
packet_helper<internal::packet_traits<Scalar>::HasLog,Packet> h;
|
||||
h.store(data2, internal::plog(h.load(data1)));
|
||||
VERIFY(isNaN(data2[0]));
|
||||
data1[0] = -1.0f;
|
||||
h.store(data2, internal::plog(h.load(data1)));
|
||||
VERIFY(isNaN(data2[0]));
|
||||
#if !EIGEN_FAST_MATH
|
||||
h.store(data2, internal::psqrt(h.load(data1)));
|
||||
VERIFY(isNaN(data2[0]));
|
||||
VERIFY(isNaN(data2[1]));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Scalar> void packetmath_notcomplex()
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
ref2 = ref1 = DEST; \
|
||||
DEST.template triangularView<TRI>() OP; \
|
||||
ref1 OP; \
|
||||
ref2.template triangularView<TRI>() = ref1; \
|
||||
ref2.template triangularView<TRI>() \
|
||||
= ref1.template triangularView<TRI>(); \
|
||||
VERIFY_IS_APPROX(DEST,ref2); \
|
||||
}
|
||||
|
||||
|
||||
@@ -113,8 +113,7 @@ template<typename MatrixType> void product_notemporary(const MatrixType& m)
|
||||
VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 0 );
|
||||
|
||||
// Zero temporaries for ... CoeffBasedProductMode
|
||||
// - does not work with GCC because of the <..>, we'ld need variadic macros ...
|
||||
//VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 );
|
||||
VERIFY_EVALUATION_COUNT( m3.col(0).template head<5>() * m3.col(0).transpose() + m3.col(0).template head<5>() * m3.col(0).transpose(), 0 );
|
||||
|
||||
// Check matrix * vectors
|
||||
VERIFY_EVALUATION_COUNT( cvres.noalias() = m1 * cv1, 0 );
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#define EIGEN_NO_STATIC_ASSERT
|
||||
#include "product.h"
|
||||
#include <Eigen/LU>
|
||||
|
||||
// regression test for bug 447
|
||||
void product1x1()
|
||||
@@ -46,5 +47,14 @@ void test_product_small()
|
||||
Vector3f v = Vector3f::Random();
|
||||
VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v);
|
||||
}
|
||||
|
||||
{
|
||||
// regression test for pull-request #93
|
||||
Eigen::Matrix<double, 1, 1> A; A.setRandom();
|
||||
Eigen::Matrix<double, 18, 1> B; B.setRandom();
|
||||
Eigen::Matrix<double, 1, 18> C; C.setRandom();
|
||||
VERIFY_IS_APPROX(B * A.inverse(), B * A.inverse()[0]);
|
||||
VERIFY_IS_APPROX(A.inverse() * C, A.inverse()[0] * C);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -40,7 +40,11 @@ template<typename MatrixType> void qr()
|
||||
MatrixType c = qr.matrixQ() * r * qr.colsPermutation().inverse();
|
||||
|
||||
VERIFY_IS_APPROX(m1, c);
|
||||
|
||||
|
||||
// stress the ReturnByValue mechanism
|
||||
MatrixType tmp;
|
||||
VERIFY_IS_APPROX(tmp.noalias() = qr.matrixQ() * r, (qr.matrixQ() * r).eval());
|
||||
|
||||
MatrixType m2 = MatrixType::Random(cols,cols2);
|
||||
MatrixType m3 = m1*m2;
|
||||
m2 = MatrixType::Random(cols,cols2);
|
||||
|
||||
@@ -182,15 +182,15 @@ void call_ref()
|
||||
|
||||
VERIFY_EVALUATION_COUNT( call_ref_1(a,a), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_1(b,b.transpose()), 0);
|
||||
// call_ref_1(ac); // does not compile because ac is const
|
||||
// call_ref_1(ac,a<c); // does not compile because ac is const
|
||||
VERIFY_EVALUATION_COUNT( call_ref_1(ab,ab), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_1(a.head(4),a.head(4)), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_1(abc,abc), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_1(A.col(3),A.col(3)), 0);
|
||||
// call_ref_1(A.row(3)); // does not compile because innerstride!=1
|
||||
// call_ref_1(A.row(3),A.row(3)); // does not compile because innerstride!=1
|
||||
VERIFY_EVALUATION_COUNT( call_ref_3(A.row(3),A.row(3).transpose()), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_4(A.row(3),A.row(3).transpose()), 0);
|
||||
// call_ref_1(a+a); // does not compile for obvious reason
|
||||
// call_ref_1(a+a, a+a); // does not compile for obvious reason
|
||||
|
||||
MatrixXf tmp = A*A.col(1);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_2(A*A.col(1), tmp), 1); // evaluated into a temp
|
||||
@@ -211,7 +211,7 @@ void call_ref()
|
||||
VERIFY_EVALUATION_COUNT( call_ref_5(a,a), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_5(a.head(3),a.head(3)), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_5(A,A), 0);
|
||||
// call_ref_5(A.transpose()); // does not compile
|
||||
// call_ref_5(A.transpose(),A.transpose()); // does not compile because storage order does not match
|
||||
VERIFY_EVALUATION_COUNT( call_ref_5(A.block(1,1,2,2),A.block(1,1,2,2)), 0);
|
||||
VERIFY_EVALUATION_COUNT( call_ref_5(b,b), 0); // storage order do not match, but this is a degenerate case that should work
|
||||
VERIFY_EVALUATION_COUNT( call_ref_5(a.row(3),a.row(3)), 0);
|
||||
|
||||
@@ -18,6 +18,9 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
const Index rows = ref.rows();
|
||||
const Index cols = ref.cols();
|
||||
const Index inner = ref.innerSize();
|
||||
const Index outer = ref.outerSize();
|
||||
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
enum { Flags = SparseMatrixType::Flags };
|
||||
|
||||
@@ -36,23 +39,22 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
std::vector<Vector2> nonzeroCoords;
|
||||
initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);
|
||||
|
||||
if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
|
||||
return;
|
||||
|
||||
// test coeff and coeffRef
|
||||
for (int i=0; i<(int)zeroCoords.size(); ++i)
|
||||
for (std::size_t i=0; i<zeroCoords.size(); ++i)
|
||||
{
|
||||
VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
|
||||
if(internal::is_same<SparseMatrixType,SparseMatrix<Scalar,Flags> >::value)
|
||||
VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
|
||||
VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[i].x(),zeroCoords[i].y()) = 5 );
|
||||
}
|
||||
VERIFY_IS_APPROX(m, refMat);
|
||||
|
||||
m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
|
||||
refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
|
||||
if(!nonzeroCoords.empty()) {
|
||||
m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
|
||||
refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
|
||||
}
|
||||
|
||||
VERIFY_IS_APPROX(m, refMat);
|
||||
/*
|
||||
|
||||
// test InnerIterators and Block expressions
|
||||
for (int t=0; t<10; ++t)
|
||||
{
|
||||
@@ -61,23 +63,25 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
int w = internal::random<int>(1,cols-j-1);
|
||||
int h = internal::random<int>(1,rows-i-1);
|
||||
|
||||
// VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
|
||||
VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
|
||||
for(int c=0; c<w; c++)
|
||||
{
|
||||
VERIFY_IS_APPROX(m.block(i,j,h,w).col(c), refMat.block(i,j,h,w).col(c));
|
||||
for(int r=0; r<h; r++)
|
||||
{
|
||||
// VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
|
||||
// FIXME col().coeff() not implemented yet
|
||||
// VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
|
||||
}
|
||||
}
|
||||
// for(int r=0; r<h; r++)
|
||||
// {
|
||||
// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
|
||||
// for(int c=0; c<w; c++)
|
||||
// {
|
||||
// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
|
||||
// }
|
||||
// }
|
||||
for(int r=0; r<h; r++)
|
||||
{
|
||||
VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
|
||||
for(int c=0; c<w; c++)
|
||||
{
|
||||
// FIXME row().coeff() not implemented yet
|
||||
// VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int c=0; c<cols; c++)
|
||||
@@ -91,8 +95,8 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
VERIFY_IS_APPROX(m.row(r) + m.row(r), (m + m).row(r));
|
||||
VERIFY_IS_APPROX(m.row(r) + m.row(r), refMat.row(r) + refMat.row(r));
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// test assertion
|
||||
VERIFY_RAISES_ASSERT( m.coeffRef(-1,1) = 0 );
|
||||
VERIFY_RAISES_ASSERT( m.coeffRef(0,m.cols()) = 0 );
|
||||
@@ -165,11 +169,11 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
// test innerVector()
|
||||
{
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType m2(rows, rows);
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
Index j0 = internal::random<Index>(0,rows-1);
|
||||
Index j1 = internal::random<Index>(0,rows-1);
|
||||
Index j0 = internal::random<Index>(0,outer-1);
|
||||
Index j1 = internal::random<Index>(0,outer-1);
|
||||
if(SparseMatrixType::IsRowMajor)
|
||||
VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.row(j0));
|
||||
else
|
||||
@@ -180,42 +184,41 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
else
|
||||
VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
|
||||
|
||||
SparseMatrixType m3(rows,rows);
|
||||
m3.reserve(VectorXi::Constant(rows,int(rows/2)));
|
||||
for(Index j=0; j<rows; ++j)
|
||||
for(Index k=0; k<j; ++k)
|
||||
SparseMatrixType m3(rows,cols);
|
||||
m3.reserve(VectorXi::Constant(outer,int(inner/2)));
|
||||
for(Index j=0; j<outer; ++j)
|
||||
for(Index k=0; k<(std::min)(j,inner); ++k)
|
||||
m3.insertByOuterInner(j,k) = k+1;
|
||||
for(Index j=0; j<rows; ++j)
|
||||
for(Index j=0; j<(std::min)(outer, inner); ++j)
|
||||
{
|
||||
VERIFY(j==numext::real(m3.innerVector(j).nonZeros()));
|
||||
if(j>0)
|
||||
VERIFY(j==numext::real(m3.innerVector(j).lastCoeff()));
|
||||
}
|
||||
m3.makeCompressed();
|
||||
for(Index j=0; j<rows; ++j)
|
||||
for(Index j=0; j<(std::min)(outer, inner); ++j)
|
||||
{
|
||||
VERIFY(j==numext::real(m3.innerVector(j).nonZeros()));
|
||||
if(j>0)
|
||||
VERIFY(j==numext::real(m3.innerVector(j).lastCoeff()));
|
||||
}
|
||||
|
||||
|
||||
VERIFY(m3.innerVector(j0).nonZeros() == m3.transpose().innerVector(j0).nonZeros());
|
||||
|
||||
//m2.innerVector(j0) = 2*m2.innerVector(j1);
|
||||
//refMat2.col(j0) = 2*refMat2.col(j1);
|
||||
//VERIFY_IS_APPROX(m2, refMat2);
|
||||
// m2.innerVector(j0) = 2*m2.innerVector(j1);
|
||||
// refMat2.col(j0) = 2*refMat2.col(j1);
|
||||
// VERIFY_IS_APPROX(m2, refMat2);
|
||||
}
|
||||
|
||||
// test innerVectors()
|
||||
{
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType m2(rows, rows);
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
if(internal::random<float>(0,1)>0.5) m2.makeCompressed();
|
||||
|
||||
Index j0 = internal::random<Index>(0,rows-2);
|
||||
Index j1 = internal::random<Index>(0,rows-2);
|
||||
Index n0 = internal::random<Index>(1,rows-(std::max)(j0,j1));
|
||||
Index j0 = internal::random<Index>(0,outer-2);
|
||||
Index j1 = internal::random<Index>(0,outer-2);
|
||||
Index n0 = internal::random<Index>(1,outer-(std::max)(j0,j1));
|
||||
if(SparseMatrixType::IsRowMajor)
|
||||
VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(j0,0,n0,cols));
|
||||
else
|
||||
@@ -239,22 +242,23 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
VERIFY_IS_APPROX(m2, refMat2);
|
||||
}
|
||||
|
||||
|
||||
// test basic computations
|
||||
{
|
||||
DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
|
||||
DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
|
||||
DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
|
||||
DenseMatrix refM4 = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType m1(rows, rows);
|
||||
SparseMatrixType m2(rows, rows);
|
||||
SparseMatrixType m3(rows, rows);
|
||||
SparseMatrixType m4(rows, rows);
|
||||
DenseMatrix refM1 = DenseMatrix::Zero(rows, cols);
|
||||
DenseMatrix refM2 = DenseMatrix::Zero(rows, cols);
|
||||
DenseMatrix refM3 = DenseMatrix::Zero(rows, cols);
|
||||
DenseMatrix refM4 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m1(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
SparseMatrixType m3(rows, cols);
|
||||
SparseMatrixType m4(rows, cols);
|
||||
initSparse<Scalar>(density, refM1, m1);
|
||||
initSparse<Scalar>(density, refM2, m2);
|
||||
initSparse<Scalar>(density, refM3, m3);
|
||||
initSparse<Scalar>(density, refM4, m4);
|
||||
|
||||
VERIFY_IS_APPROX(m1*s1, refM1*s1);
|
||||
VERIFY_IS_APPROX(m1+m2, refM1+refM2);
|
||||
VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
|
||||
VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2));
|
||||
@@ -269,7 +273,7 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
if(SparseMatrixType::IsRowMajor)
|
||||
VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.row(0).dot(refM2.row(0)));
|
||||
else
|
||||
VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.col(0).dot(refM2.row(0)));
|
||||
VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.col(0)), refM1.col(0).dot(refM2.col(0)));
|
||||
|
||||
DenseVector rv = DenseVector::Random(m1.cols());
|
||||
DenseVector cv = DenseVector::Random(m1.rows());
|
||||
@@ -296,25 +300,29 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
// test transpose
|
||||
{
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType m2(rows, rows);
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
|
||||
VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());
|
||||
|
||||
VERIFY_IS_APPROX(SparseMatrixType(m2.adjoint()), refMat2.adjoint());
|
||||
|
||||
// check isApprox handles opposite storage order
|
||||
typename Transpose<SparseMatrixType>::PlainObject m3(m2);
|
||||
VERIFY(m2.isApprox(m3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// test generic blocks
|
||||
{
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType m2(rows, rows);
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
Index j0 = internal::random<Index>(0,rows-2);
|
||||
Index j1 = internal::random<Index>(0,rows-2);
|
||||
Index n0 = internal::random<Index>(1,rows-(std::max)(j0,j1));
|
||||
Index j0 = internal::random<Index>(0,outer-2);
|
||||
Index j1 = internal::random<Index>(0,outer-2);
|
||||
Index n0 = internal::random<Index>(1,outer-(std::max)(j0,j1));
|
||||
if(SparseMatrixType::IsRowMajor)
|
||||
VERIFY_IS_APPROX(m2.block(j0,0,n0,cols), refMat2.block(j0,0,n0,cols));
|
||||
else
|
||||
@@ -341,8 +349,8 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
// test prune
|
||||
{
|
||||
SparseMatrixType m2(rows, rows);
|
||||
DenseMatrix refM2(rows, rows);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
DenseMatrix refM2(rows, cols);
|
||||
refM2.setZero();
|
||||
int countFalseNonZero = 0;
|
||||
int countTrueNonZero = 0;
|
||||
@@ -403,8 +411,8 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
// test triangularView
|
||||
{
|
||||
DenseMatrix refMat2(rows, rows), refMat3(rows, rows);
|
||||
SparseMatrixType m2(rows, rows), m3(rows, rows);
|
||||
DenseMatrix refMat2(rows, cols), refMat3(rows, cols);
|
||||
SparseMatrixType m2(rows, cols), m3(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
refMat3 = refMat2.template triangularView<Lower>();
|
||||
m3 = m2.template triangularView<Lower>();
|
||||
@@ -414,13 +422,16 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
m3 = m2.template triangularView<Upper>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
|
||||
refMat3 = refMat2.template triangularView<UnitUpper>();
|
||||
m3 = m2.template triangularView<UnitUpper>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
if(inner>=outer) // FIXME this should be implemented for outer>inner as well
|
||||
{
|
||||
refMat3 = refMat2.template triangularView<UnitUpper>();
|
||||
m3 = m2.template triangularView<UnitUpper>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
|
||||
refMat3 = refMat2.template triangularView<UnitLower>();
|
||||
m3 = m2.template triangularView<UnitLower>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
refMat3 = refMat2.template triangularView<UnitLower>();
|
||||
m3 = m2.template triangularView<UnitLower>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
}
|
||||
|
||||
refMat3 = refMat2.template triangularView<StrictlyUpper>();
|
||||
m3 = m2.template triangularView<StrictlyUpper>();
|
||||
@@ -440,6 +451,11 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
refMat3 = refMat2.template selfadjointView<Lower>();
|
||||
m3 = m2.template selfadjointView<Lower>();
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
|
||||
// selfadjointView only works for square matrices:
|
||||
SparseMatrixType m4(rows, rows+1);
|
||||
VERIFY_RAISES_ASSERT(m4.template selfadjointView<Lower>());
|
||||
VERIFY_RAISES_ASSERT(m4.template selfadjointView<Upper>());
|
||||
}
|
||||
|
||||
// test sparseView
|
||||
@@ -452,16 +468,23 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
// test diagonal
|
||||
{
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType m2(rows, rows);
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
VERIFY_IS_APPROX(m2.diagonal(), refMat2.diagonal().eval());
|
||||
VERIFY_IS_APPROX(const_cast<const SparseMatrixType&>(m2).diagonal(), refMat2.diagonal().eval());
|
||||
|
||||
initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag);
|
||||
m2.diagonal() += refMat2.diagonal();
|
||||
refMat2.diagonal() += refMat2.diagonal();
|
||||
VERIFY_IS_APPROX(m2, refMat2);
|
||||
}
|
||||
|
||||
// test conservative resize
|
||||
{
|
||||
std::vector< std::pair<Index,Index> > inc;
|
||||
inc.push_back(std::pair<Index,Index>(-3,-2));
|
||||
if(rows > 3 && cols > 2)
|
||||
inc.push_back(std::pair<Index,Index>(-3,-2));
|
||||
inc.push_back(std::pair<Index,Index>(0,0));
|
||||
inc.push_back(std::pair<Index,Index>(3,2));
|
||||
inc.push_back(std::pair<Index,Index>(3,0));
|
||||
@@ -502,19 +525,54 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename SparseMatrixType>
|
||||
void big_sparse_triplet(typename SparseMatrixType::Index rows, typename SparseMatrixType::Index cols, double density) {
|
||||
typedef typename SparseMatrixType::Index Index;
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
typedef Triplet<Scalar,Index> TripletType;
|
||||
std::vector<TripletType> triplets;
|
||||
double nelements = density * rows*cols;
|
||||
VERIFY(nelements>=0 && nelements < NumTraits<Index>::highest());
|
||||
Index ntriplets = Index(nelements);
|
||||
triplets.reserve(ntriplets);
|
||||
Scalar sum = Scalar(0);
|
||||
for(Index i=0;i<ntriplets;++i)
|
||||
{
|
||||
Index r = internal::random<Index>(0,rows-1);
|
||||
Index c = internal::random<Index>(0,cols-1);
|
||||
Scalar v = internal::random<Scalar>();
|
||||
triplets.push_back(TripletType(r,c,v));
|
||||
sum += v;
|
||||
}
|
||||
SparseMatrixType m(rows,cols);
|
||||
m.setFromTriplets(triplets.begin(), triplets.end());
|
||||
VERIFY(m.nonZeros() <= ntriplets);
|
||||
VERIFY_IS_APPROX(sum, m.sum());
|
||||
}
|
||||
|
||||
|
||||
void test_sparse_basic()
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
int s = Eigen::internal::random<int>(1,50);
|
||||
EIGEN_UNUSED_VARIABLE(s);
|
||||
int r = Eigen::internal::random<int>(1,100), c = Eigen::internal::random<int>(1,100);
|
||||
if(Eigen::internal::random<int>(0,4) == 0) {
|
||||
r = c; // check square matrices in 25% of tries
|
||||
}
|
||||
EIGEN_UNUSED_VARIABLE(r+c);
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(1, 1)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(8, 8)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, ColMajor>(s, s)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, RowMajor>(s, s)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(s, s)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,ColMajor,long int>(s, s)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,RowMajor,long int>(s, s)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, ColMajor>(r, c)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, RowMajor>(r, c)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(r, c)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,ColMajor,long int>(r, c)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,RowMajor,long int>(r, c)) ));
|
||||
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,ColMajor,short int>(short(s), short(s))) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,RowMajor,short int>(short(s), short(s))) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,ColMajor,short int>(short(r), short(c))) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double,RowMajor,short int>(short(r), short(c))) ));
|
||||
}
|
||||
|
||||
// Regression test for bug 900: (manually insert higher values here, if you have enough RAM):
|
||||
CALL_SUBTEST_3((big_sparse_triplet<SparseMatrix<float, RowMajor, int> >(10000, 10000, 0.125)));
|
||||
CALL_SUBTEST_4((big_sparse_triplet<SparseMatrix<double, ColMajor, long int> >(10000, 10000, 0.125)));
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
enum { Flags = SparseMatrixType::Flags };
|
||||
|
||||
double density = (std::max)(8./(rows*cols), 0.1);
|
||||
double density = (std::max)(8./(rows*cols), 0.2);
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
|
||||
typedef Matrix<Scalar,Dynamic,1> DenseVector;
|
||||
typedef Matrix<Scalar,1,Dynamic> RowDenseVector;
|
||||
@@ -77,17 +77,27 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
m4 = m2; refMat4 = refMat2;
|
||||
VERIFY_IS_APPROX(m4=m4*m3, refMat4=refMat4*refMat3);
|
||||
|
||||
// sparse * dense
|
||||
// sparse * dense matrix
|
||||
VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=m2*refMat3t.transpose(), refMat4=refMat2*refMat3t.transpose());
|
||||
VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3, refMat4=refMat2t.transpose()*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose());
|
||||
|
||||
VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=dm4+m2*refMat3, refMat4=refMat4+refMat2*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=m2*(refMat3+refMat3), refMat4=refMat2*(refMat3+refMat3));
|
||||
VERIFY_IS_APPROX(dm4=m2t.transpose()*(refMat3+refMat5)*0.5, refMat4=refMat2t.transpose()*(refMat3+refMat5)*0.5);
|
||||
|
||||
// sparse * dense vector
|
||||
VERIFY_IS_APPROX(dm4.col(0)=m2*refMat3.col(0), refMat4.col(0)=refMat2*refMat3.col(0));
|
||||
VERIFY_IS_APPROX(dm4.col(0)=m2*refMat3t.transpose().col(0), refMat4.col(0)=refMat2*refMat3t.transpose().col(0));
|
||||
VERIFY_IS_APPROX(dm4.col(0)=m2t.transpose()*refMat3.col(0), refMat4.col(0)=refMat2t.transpose()*refMat3.col(0));
|
||||
VERIFY_IS_APPROX(dm4.col(0)=m2t.transpose()*refMat3t.transpose().col(0), refMat4.col(0)=refMat2t.transpose()*refMat3t.transpose().col(0));
|
||||
|
||||
// dense * sparse
|
||||
VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=dm4+refMat2*m3, refMat4=refMat4+refMat2*refMat3);
|
||||
VERIFY_IS_APPROX(dm4+=refMat2*m3, refMat4+=refMat2*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=refMat2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose());
|
||||
VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3);
|
||||
VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose());
|
||||
@@ -99,7 +109,7 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
Index c1 = internal::random<Index>(0,cols-1);
|
||||
Index r1 = internal::random<Index>(0,depth-1);
|
||||
DenseMatrix dm5 = DenseMatrix::Random(depth, cols);
|
||||
|
||||
|
||||
VERIFY_IS_APPROX( m4=m2.col(c)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose());
|
||||
VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count());
|
||||
VERIFY_IS_APPROX( m4=m2.middleCols(c,1)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose());
|
||||
@@ -143,11 +153,11 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
RowSpVector rv0(depth), rv1;
|
||||
RowDenseVector drv0(depth), drv1(rv1);
|
||||
initSparse(2*density,drv0, rv0);
|
||||
|
||||
VERIFY_IS_APPROX(cv1=rv0*m3, dcv1=drv0*refMat3);
|
||||
|
||||
VERIFY_IS_APPROX(cv1=m3*cv0, dcv1=refMat3*dcv0);
|
||||
VERIFY_IS_APPROX(rv1=rv0*m3, drv1=drv0*refMat3);
|
||||
VERIFY_IS_APPROX(cv1=m3*cv0, dcv1=refMat3*dcv0);
|
||||
VERIFY_IS_APPROX(cv1=m3t.adjoint()*cv0, dcv1=refMat3t.adjoint()*dcv0);
|
||||
VERIFY_IS_APPROX(cv1=rv0*m3, dcv1=drv0*refMat3);
|
||||
VERIFY_IS_APPROX(rv1=m3*cv0, drv1=refMat3*dcv0);
|
||||
}
|
||||
|
||||
@@ -184,7 +194,7 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
VERIFY_IS_APPROX(d3=d1*m2.transpose(), refM3=d1*refM2.transpose());
|
||||
}
|
||||
|
||||
// test self adjoint products
|
||||
// test self-adjoint and traingular-view products
|
||||
{
|
||||
DenseMatrix b = DenseMatrix::Random(rows, rows);
|
||||
DenseMatrix x = DenseMatrix::Random(rows, rows);
|
||||
@@ -192,9 +202,12 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
|
||||
DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
|
||||
DenseMatrix refS = DenseMatrix::Zero(rows, rows);
|
||||
DenseMatrix refA = DenseMatrix::Zero(rows, rows);
|
||||
SparseMatrixType mUp(rows, rows);
|
||||
SparseMatrixType mLo(rows, rows);
|
||||
SparseMatrixType mS(rows, rows);
|
||||
SparseMatrixType mA(rows, rows);
|
||||
initSparse<Scalar>(density, refA, mA);
|
||||
do {
|
||||
initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
|
||||
} while (refUp.isZero());
|
||||
@@ -214,19 +227,30 @@ template<typename SparseMatrixType> void sparse_product()
|
||||
VERIFY_IS_APPROX(mS, refS);
|
||||
VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
|
||||
|
||||
// sparse selfadjointView with dense matrices
|
||||
VERIFY_IS_APPROX(x=mUp.template selfadjointView<Upper>()*b, refX=refS*b);
|
||||
VERIFY_IS_APPROX(x=mLo.template selfadjointView<Lower>()*b, refX=refS*b);
|
||||
VERIFY_IS_APPROX(x=mS.template selfadjointView<Upper|Lower>()*b, refX=refS*b);
|
||||
|
||||
// sparse selfadjointView * sparse
|
||||
// sparse selfadjointView with sparse matrices
|
||||
SparseMatrixType mSres(rows,rows);
|
||||
VERIFY_IS_APPROX(mSres = mLo.template selfadjointView<Lower>()*mS,
|
||||
refX = refLo.template selfadjointView<Lower>()*refS);
|
||||
// sparse * sparse selfadjointview
|
||||
VERIFY_IS_APPROX(mSres = mS * mLo.template selfadjointView<Lower>(),
|
||||
refX = refS * refLo.template selfadjointView<Lower>());
|
||||
|
||||
// sparse triangularView with dense matrices
|
||||
VERIFY_IS_APPROX(x=mA.template triangularView<Upper>()*b, refX=refA.template triangularView<Upper>()*b);
|
||||
VERIFY_IS_APPROX(x=mA.template triangularView<Lower>()*b, refX=refA.template triangularView<Lower>()*b);
|
||||
VERIFY_IS_APPROX(x=b*mA.template triangularView<Upper>(), refX=b*refA.template triangularView<Upper>());
|
||||
VERIFY_IS_APPROX(x=b*mA.template triangularView<Lower>(), refX=b*refA.template triangularView<Lower>());
|
||||
|
||||
// sparse triangularView with sparse matrices
|
||||
VERIFY_IS_APPROX(mSres = mA.template triangularView<Lower>()*mS, refX = refA.template triangularView<Lower>()*refS);
|
||||
VERIFY_IS_APPROX(mSres = mS * mA.template triangularView<Lower>(), refX = refS * refA.template triangularView<Lower>());
|
||||
VERIFY_IS_APPROX(mSres = mA.template triangularView<Upper>()*mS, refX = refA.template triangularView<Upper>()*refS);
|
||||
VERIFY_IS_APPROX(mSres = mS * mA.template triangularView<Upper>(), refX = refS * refA.template triangularView<Upper>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// New test for Bug in SparseTimeDenseProduct
|
||||
|
||||
@@ -15,6 +15,7 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
|
||||
{
|
||||
typedef typename Solver::MatrixType Mat;
|
||||
typedef typename Mat::Scalar Scalar;
|
||||
typedef typename Mat::Index Index;
|
||||
|
||||
DenseRhs refX = dA.lu().solve(db);
|
||||
{
|
||||
@@ -35,8 +36,8 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
|
||||
return;
|
||||
}
|
||||
VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
|
||||
|
||||
VERIFY(x.isApprox(refX,test_precision<Scalar>()));
|
||||
|
||||
x.setZero();
|
||||
// test the analyze/factorize API
|
||||
solver.analyzePattern(A);
|
||||
@@ -54,8 +55,31 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
|
||||
return;
|
||||
}
|
||||
VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
|
||||
|
||||
VERIFY(x.isApprox(refX,test_precision<Scalar>()));
|
||||
|
||||
|
||||
x.setZero();
|
||||
// test with Map
|
||||
MappedSparseMatrix<Scalar,Mat::Options,Index> Am(A.rows(), A.cols(), A.nonZeros(), const_cast<Index*>(A.outerIndexPtr()), const_cast<Index*>(A.innerIndexPtr()), const_cast<Scalar*>(A.valuePtr()));
|
||||
solver.compute(Am);
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
DenseRhs dx(refX);
|
||||
dx.setZero();
|
||||
Map<DenseRhs> xm(dx.data(), dx.rows(), dx.cols());
|
||||
Map<const DenseRhs> bm(db.data(), db.rows(), db.cols());
|
||||
xm = solver.solve(bm);
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse solver testing: solving failed\n";
|
||||
return;
|
||||
}
|
||||
VERIFY(oldb.isApprox(bm) && "sparse solver testing: the rhs should not be modified!");
|
||||
VERIFY(xm.isApprox(refX,test_precision<Scalar>()));
|
||||
}
|
||||
|
||||
// test dense Block as the result and rhs:
|
||||
@@ -67,6 +91,15 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
|
||||
VERIFY(oldb.isApprox(db) && "sparse solver testing: the rhs should not be modified!");
|
||||
VERIFY(x.isApprox(refX,test_precision<Scalar>()));
|
||||
}
|
||||
|
||||
// test uncompressed inputs
|
||||
{
|
||||
Mat A2 = A;
|
||||
A2.reserve((ArrayXf::Random(A.outerSize())+2).template cast<typename Mat::Index>().eval());
|
||||
solver.compute(A2);
|
||||
Rhs x = solver.solve(b);
|
||||
VERIFY(x.isApprox(refX,test_precision<Scalar>()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Solver, typename Rhs>
|
||||
@@ -124,7 +157,23 @@ void check_sparse_determinant(Solver& solver, const typename Solver::MatrixType&
|
||||
Scalar refDet = dA.determinant();
|
||||
VERIFY_IS_APPROX(refDet,solver.determinant());
|
||||
}
|
||||
template<typename Solver, typename DenseMat>
|
||||
void check_sparse_abs_determinant(Solver& solver, const typename Solver::MatrixType& A, const DenseMat& dA)
|
||||
{
|
||||
using std::abs;
|
||||
typedef typename Solver::MatrixType Mat;
|
||||
typedef typename Mat::Scalar Scalar;
|
||||
|
||||
solver.compute(A);
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse solver testing: factorization failed (check_sparse_abs_determinant)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
Scalar refDet = abs(dA.determinant());
|
||||
VERIFY_IS_APPROX(refDet,solver.absDeterminant());
|
||||
}
|
||||
|
||||
template<typename Solver, typename DenseMat>
|
||||
int generate_sparse_spd_problem(Solver& , typename Solver::MatrixType& A, typename Solver::MatrixType& halfA, DenseMat& dA, int maxSize = 300)
|
||||
@@ -324,3 +373,20 @@ template<typename Solver> void check_sparse_square_determinant(Solver& solver)
|
||||
check_sparse_determinant(solver, A, dA);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Solver> void check_sparse_square_abs_determinant(Solver& solver)
|
||||
{
|
||||
typedef typename Solver::MatrixType Mat;
|
||||
typedef typename Mat::Scalar Scalar;
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
|
||||
|
||||
// generate the problem
|
||||
Mat A;
|
||||
DenseMatrix dA;
|
||||
generate_sparse_square_problem(solver, A, dA, 30);
|
||||
A.makeCompressed();
|
||||
for (int i = 0; i < g_repeat; i++) {
|
||||
check_sparse_abs_determinant(solver, A, dA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ template<typename Scalar,typename Index> void sparse_vector(int rows, int cols)
|
||||
SparseVectorType v1(rows), v2(rows), v3(rows);
|
||||
DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
|
||||
DenseVector refV1 = DenseVector::Random(rows),
|
||||
refV2 = DenseVector::Random(rows),
|
||||
refV3 = DenseVector::Random(rows);
|
||||
refV2 = DenseVector::Random(rows),
|
||||
refV3 = DenseVector::Random(rows);
|
||||
|
||||
std::vector<int> zerocoords, nonzerocoords;
|
||||
initSparse<Scalar>(densityVec, refV1, v1, &zerocoords, &nonzerocoords);
|
||||
@@ -52,6 +52,20 @@ template<typename Scalar,typename Index> void sparse_vector(int rows, int cols)
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(v1, refV1);
|
||||
|
||||
// test coeffRef with reallocation
|
||||
{
|
||||
SparseVectorType v1(rows);
|
||||
DenseVector v2 = DenseVector::Zero(rows);
|
||||
for(int k=0; k<rows; ++k)
|
||||
{
|
||||
int i = internal::random<int>(0,rows-1);
|
||||
Scalar v = internal::random<Scalar>();
|
||||
v1.coeffRef(i) += v;
|
||||
v2.coeffRef(i) += v;
|
||||
}
|
||||
VERIFY_IS_APPROX(v1,v2);
|
||||
}
|
||||
|
||||
v1.coeffRef(nonzerocoords[0]) = Scalar(5);
|
||||
refV1.coeffRef(nonzerocoords[0]) = Scalar(5);
|
||||
@@ -71,6 +85,7 @@ template<typename Scalar,typename Index> void sparse_vector(int rows, int cols)
|
||||
VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2));
|
||||
VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2));
|
||||
|
||||
VERIFY_IS_APPROX(m1*v2, refM1*refV2);
|
||||
VERIFY_IS_APPROX(v1.dot(m1*v2), refV1.dot(refM1*refV2));
|
||||
int i = internal::random<int>(0,rows-1);
|
||||
VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i)));
|
||||
|
||||
@@ -44,6 +44,9 @@ template<typename T> void test_sparselu_T()
|
||||
check_sparse_square_solving(sparselu_colamd);
|
||||
check_sparse_square_solving(sparselu_amd);
|
||||
check_sparse_square_solving(sparselu_natural);
|
||||
|
||||
check_sparse_square_abs_determinant(sparselu_colamd);
|
||||
check_sparse_square_abs_determinant(sparselu_amd);
|
||||
}
|
||||
|
||||
void test_sparselu()
|
||||
|
||||
@@ -9,26 +9,6 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
template<typename T> bool isNotNaN(const T& x)
|
||||
{
|
||||
return x==x;
|
||||
}
|
||||
|
||||
template<typename T> bool isNaN(const T& x)
|
||||
{
|
||||
return x!=x;
|
||||
}
|
||||
|
||||
template<typename T> bool isInf(const T& x)
|
||||
{
|
||||
return x > NumTraits<T>::highest();
|
||||
}
|
||||
|
||||
template<typename T> bool isMinusInf(const T& x)
|
||||
{
|
||||
return x < NumTraits<T>::lowest();
|
||||
}
|
||||
|
||||
// workaround aggressive optimization in ICC
|
||||
template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
|
||||
|
||||
@@ -130,7 +110,7 @@ template<typename MatrixType> void stable_norm(const MatrixType& m)
|
||||
// NaN
|
||||
{
|
||||
v = vrand;
|
||||
v(i,j) = RealScalar(0)/RealScalar(0);
|
||||
v(i,j) = std::numeric_limits<RealScalar>::quiet_NaN();
|
||||
VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm()));
|
||||
VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm()));
|
||||
VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm()));
|
||||
@@ -141,7 +121,7 @@ template<typename MatrixType> void stable_norm(const MatrixType& m)
|
||||
// +inf
|
||||
{
|
||||
v = vrand;
|
||||
v(i,j) = RealScalar(1)/RealScalar(0);
|
||||
v(i,j) = std::numeric_limits<RealScalar>::infinity();
|
||||
VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm()));
|
||||
VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm()));
|
||||
VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm()));
|
||||
@@ -152,7 +132,7 @@ template<typename MatrixType> void stable_norm(const MatrixType& m)
|
||||
// -inf
|
||||
{
|
||||
v = vrand;
|
||||
v(i,j) = RealScalar(-1)/RealScalar(0);
|
||||
v(i,j) = -std::numeric_limits<RealScalar>::infinity();
|
||||
VERIFY(!isFinite(v.squaredNorm())); VERIFY(isInf(v.squaredNorm()));
|
||||
VERIFY(!isFinite(v.norm())); VERIFY(isInf(v.norm()));
|
||||
VERIFY(!isFinite(v.stableNorm())); VERIFY(isInf(v.stableNorm()));
|
||||
@@ -165,8 +145,8 @@ template<typename MatrixType> void stable_norm(const MatrixType& m)
|
||||
Index i2 = internal::random<Index>(0,rows-1);
|
||||
Index j2 = internal::random<Index>(0,cols-1);
|
||||
v = vrand;
|
||||
v(i,j) = RealScalar(-1)/RealScalar(0);
|
||||
v(i2,j2) = RealScalar(0)/RealScalar(0);
|
||||
v(i,j) = -std::numeric_limits<RealScalar>::infinity();
|
||||
v(i2,j2) = std::numeric_limits<RealScalar>::quiet_NaN();
|
||||
VERIFY(!isFinite(v.squaredNorm())); VERIFY(isNaN(v.squaredNorm()));
|
||||
VERIFY(!isFinite(v.norm())); VERIFY(isNaN(v.norm()));
|
||||
VERIFY(!isFinite(v.stableNorm())); VERIFY(isNaN(v.stableNorm()));
|
||||
|
||||
493
test/svd_common.h
Normal file
493
test/svd_common.h
Normal file
@@ -0,0 +1,493 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef SVD_DEFAULT
|
||||
#error a macro SVD_DEFAULT(MatrixType) must be defined prior to including svd_common.h
|
||||
#endif
|
||||
|
||||
#ifndef SVD_FOR_MIN_NORM
|
||||
#error a macro SVD_FOR_MIN_NORM(MatrixType) must be defined prior to including svd_common.h
|
||||
#endif
|
||||
|
||||
// Check that the matrix m is properly reconstructed and that the U and V factors are unitary
|
||||
// The SVD must have already been computed.
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_check_full(const MatrixType& m, const SvdType& svd)
|
||||
{
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime> MatrixUType;
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime> MatrixVType;
|
||||
|
||||
MatrixType sigma = MatrixType::Zero(rows,cols);
|
||||
sigma.diagonal() = svd.singularValues().template cast<Scalar>();
|
||||
MatrixUType u = svd.matrixU();
|
||||
MatrixVType v = svd.matrixV();
|
||||
VERIFY_IS_APPROX(m, u * sigma * v.adjoint());
|
||||
VERIFY_IS_UNITARY(u);
|
||||
VERIFY_IS_UNITARY(v);
|
||||
}
|
||||
|
||||
// Compare partial SVD defined by computationOptions to a full SVD referenceSvd
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_compare_to_full(const MatrixType& m,
|
||||
unsigned int computationOptions,
|
||||
const SvdType& referenceSvd)
|
||||
{
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
Index diagSize = (std::min)(rows, cols);
|
||||
|
||||
SvdType svd(m, computationOptions);
|
||||
|
||||
VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues());
|
||||
if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU());
|
||||
if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize));
|
||||
if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV());
|
||||
if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize));
|
||||
}
|
||||
|
||||
//
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_least_square(const MatrixType& m, unsigned int computationOptions)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, Dynamic> RhsType;
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, Dynamic> SolutionType;
|
||||
|
||||
RhsType rhs = RhsType::Random(rows, internal::random<Index>(1, cols));
|
||||
SvdType svd(m, computationOptions);
|
||||
|
||||
if(internal::is_same<RealScalar,double>::value) svd.setThreshold(1e-8);
|
||||
else if(internal::is_same<RealScalar,float>::value) svd.setThreshold(1e-4);
|
||||
|
||||
SolutionType x = svd.solve(rhs);
|
||||
|
||||
// evaluate normal equation which works also for least-squares solutions
|
||||
if(internal::is_same<RealScalar,double>::value || svd.rank()==m.diagonal().size())
|
||||
{
|
||||
// This test is not stable with single precision.
|
||||
// This is probably because squaring m signicantly affects the precision.
|
||||
VERIFY_IS_APPROX(m.adjoint()*(m*x),m.adjoint()*rhs);
|
||||
}
|
||||
|
||||
RealScalar residual = (m*x-rhs).norm();
|
||||
// Check that there is no significantly better solution in the neighborhood of x
|
||||
if(!test_isMuchSmallerThan(residual,rhs.norm()))
|
||||
{
|
||||
// ^^^ If the residual is very small, then we have an exact solution, so we are already good.
|
||||
for(Index k=0;k<x.rows();++k)
|
||||
{
|
||||
SolutionType y(x);
|
||||
y.row(k) = (1.+2*NumTraits<RealScalar>::epsilon())*x.row(k);
|
||||
RealScalar residual_y = (m*y-rhs).norm();
|
||||
VERIFY( test_isApprox(residual_y,residual) || residual < residual_y );
|
||||
|
||||
y.row(k) = (1.-2*NumTraits<RealScalar>::epsilon())*x.row(k);
|
||||
residual_y = (m*y-rhs).norm();
|
||||
VERIFY( test_isApprox(residual_y,residual) || residual < residual_y );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check minimal norm solutions, the inoput matrix m is only used to recover problem size
|
||||
template<typename MatrixType>
|
||||
void svd_min_norm(const MatrixType& m, unsigned int computationOptions)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, Dynamic> SolutionType;
|
||||
|
||||
// generate a full-rank m x n problem with m<n
|
||||
enum {
|
||||
RankAtCompileTime2 = ColsAtCompileTime==Dynamic ? Dynamic : (ColsAtCompileTime)/2+1,
|
||||
RowsAtCompileTime3 = ColsAtCompileTime==Dynamic ? Dynamic : ColsAtCompileTime+1
|
||||
};
|
||||
typedef Matrix<Scalar, RankAtCompileTime2, ColsAtCompileTime> MatrixType2;
|
||||
typedef Matrix<Scalar, RankAtCompileTime2, 1> RhsType2;
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, RankAtCompileTime2> MatrixType2T;
|
||||
Index rank = RankAtCompileTime2==Dynamic ? internal::random<Index>(1,cols) : Index(RankAtCompileTime2);
|
||||
MatrixType2 m2(rank,cols);
|
||||
int guard = 0;
|
||||
do {
|
||||
m2.setRandom();
|
||||
} while(SVD_FOR_MIN_NORM(MatrixType2)(m2).setThreshold(test_precision<Scalar>()).rank()!=rank && (++guard)<10);
|
||||
VERIFY(guard<10);
|
||||
|
||||
RhsType2 rhs2 = RhsType2::Random(rank);
|
||||
// use QR to find a reference minimal norm solution
|
||||
HouseholderQR<MatrixType2T> qr(m2.adjoint());
|
||||
Matrix<Scalar,Dynamic,1> tmp = qr.matrixQR().topLeftCorner(rank,rank).template triangularView<Upper>().adjoint().solve(rhs2);
|
||||
tmp.conservativeResize(cols);
|
||||
tmp.tail(cols-rank).setZero();
|
||||
SolutionType x21 = qr.householderQ() * tmp;
|
||||
// now check with SVD
|
||||
SVD_FOR_MIN_NORM(MatrixType2) svd2(m2, computationOptions);
|
||||
SolutionType x22 = svd2.solve(rhs2);
|
||||
VERIFY_IS_APPROX(m2*x21, rhs2);
|
||||
VERIFY_IS_APPROX(m2*x22, rhs2);
|
||||
VERIFY_IS_APPROX(x21, x22);
|
||||
|
||||
// Now check with a rank deficient matrix
|
||||
typedef Matrix<Scalar, RowsAtCompileTime3, ColsAtCompileTime> MatrixType3;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime3, 1> RhsType3;
|
||||
Index rows3 = RowsAtCompileTime3==Dynamic ? internal::random<Index>(rank+1,2*cols) : Index(RowsAtCompileTime3);
|
||||
Matrix<Scalar,RowsAtCompileTime3,Dynamic> C = Matrix<Scalar,RowsAtCompileTime3,Dynamic>::Random(rows3,rank);
|
||||
MatrixType3 m3 = C * m2;
|
||||
RhsType3 rhs3 = C * rhs2;
|
||||
SVD_FOR_MIN_NORM(MatrixType3) svd3(m3, computationOptions);
|
||||
SolutionType x3 = svd3.solve(rhs3);
|
||||
VERIFY_IS_APPROX(m3*x3, rhs3);
|
||||
VERIFY_IS_APPROX(m3*x21, rhs3);
|
||||
VERIFY_IS_APPROX(m2*x3, rhs2);
|
||||
VERIFY_IS_APPROX(x21, x3);
|
||||
}
|
||||
|
||||
// Check full, compare_to_full, least_square, and min_norm for all possible compute-options
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_test_all_computation_options(const MatrixType& m, bool full_only)
|
||||
{
|
||||
// if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols())
|
||||
// return;
|
||||
SvdType fullSvd(m, ComputeFullU|ComputeFullV);
|
||||
CALL_SUBTEST(( svd_check_full(m, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeFullU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeFullV) ));
|
||||
|
||||
#if defined __INTEL_COMPILER
|
||||
// remark #111: statement is unreachable
|
||||
#pragma warning disable 111
|
||||
#endif
|
||||
if(full_only)
|
||||
return;
|
||||
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, 0, fullSvd) ));
|
||||
|
||||
if (MatrixType::ColsAtCompileTime == Dynamic) {
|
||||
// thin U/V are only available with dynamic number of columns
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU , fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) ));
|
||||
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeFullU | ComputeThinV) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeThinU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeThinU | ComputeThinV) ));
|
||||
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeThinV) ));
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeThinV) ));
|
||||
|
||||
// test reconstruction
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index diagSize = (std::min)(m.rows(), m.cols());
|
||||
SvdType svd(m, ComputeThinU | ComputeThinV);
|
||||
VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void svd_fill_random(MatrixType &m)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index diagSize = (std::min)(m.rows(), m.cols());
|
||||
RealScalar s = std::numeric_limits<RealScalar>::max_exponent10/4;
|
||||
s = internal::random<RealScalar>(1,s);
|
||||
Matrix<RealScalar,Dynamic,1> d = Matrix<RealScalar,Dynamic,1>::Random(diagSize);
|
||||
for(Index k=0; k<diagSize; ++k)
|
||||
d(k) = d(k)*std::pow(RealScalar(10),internal::random<RealScalar>(-s,s));
|
||||
|
||||
bool dup = internal::random<int>(0,10) < 3;
|
||||
bool unit_uv = internal::random<int>(0,10) < (dup?7:3); // if we duplicate some diagonal entries, then increase the chance to preserve them using unitary U and V factors
|
||||
|
||||
// duplicate some singular values
|
||||
if(dup)
|
||||
{
|
||||
Index n = internal::random<Index>(0,d.size()-1);
|
||||
for(Index i=0; i<n; ++i)
|
||||
d(internal::random<Index>(0,d.size()-1)) = d(internal::random<Index>(0,d.size()-1));
|
||||
}
|
||||
|
||||
Matrix<Scalar,Dynamic,Dynamic> U(m.rows(),diagSize);
|
||||
Matrix<Scalar,Dynamic,Dynamic> VT(diagSize,m.cols());
|
||||
if(unit_uv)
|
||||
{
|
||||
// in very rare cases let's try with a pure diagonal matrix
|
||||
if(internal::random<int>(0,10) < 1)
|
||||
{
|
||||
U.setIdentity();
|
||||
VT.setIdentity();
|
||||
}
|
||||
else
|
||||
{
|
||||
createRandomPIMatrixOfRank(diagSize,U.rows(), U.cols(), U);
|
||||
createRandomPIMatrixOfRank(diagSize,VT.rows(), VT.cols(), VT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
U.setRandom();
|
||||
VT.setRandom();
|
||||
}
|
||||
|
||||
m = U * d.asDiagonal() * VT;
|
||||
|
||||
// (partly) cancel some coeffs
|
||||
if(!(dup && unit_uv))
|
||||
{
|
||||
Matrix<Scalar,Dynamic,1> samples(7);
|
||||
samples << 0, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -1./NumTraits<RealScalar>::highest(), 1./NumTraits<RealScalar>::highest();
|
||||
Index n = internal::random<Index>(0,m.size()-1);
|
||||
for(Index i=0; i<n; ++i)
|
||||
m(internal::random<Index>(0,m.rows()-1), internal::random<Index>(0,m.cols()-1)) = samples(internal::random<Index>(0,6));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// work around stupid msvc error when constructing at compile time an expression that involves
|
||||
// a division by zero, even if the numeric type has floating point
|
||||
template<typename Scalar>
|
||||
EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); }
|
||||
|
||||
// workaround aggressive optimization in ICC
|
||||
template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
|
||||
|
||||
// all this function does is verify we don't iterate infinitely on nan/inf values
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_inf_nan()
|
||||
{
|
||||
SvdType svd;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
Scalar some_inf = Scalar(1) / zero<Scalar>();
|
||||
VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf));
|
||||
svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV);
|
||||
|
||||
Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
VERIFY(nan != nan);
|
||||
svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV);
|
||||
|
||||
MatrixType m = MatrixType::Zero(10,10);
|
||||
m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_inf;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
m = MatrixType::Zero(10,10);
|
||||
m(internal::random<int>(0,9), internal::random<int>(0,9)) = nan;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
// regression test for bug 791
|
||||
m.resize(3,3);
|
||||
m << 0, 2*NumTraits<Scalar>::epsilon(), 0.5,
|
||||
0, -0.5, 0,
|
||||
nan, 0, 0;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
m.resize(4,4);
|
||||
m << 1, 0, 0, 0,
|
||||
0, 3, 1, 2e-308,
|
||||
1, 0, 1, nan,
|
||||
0, nan, nan, 0;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
}
|
||||
|
||||
// Regression test for bug 286: JacobiSVD loops indefinitely with some
|
||||
// matrices containing denormal numbers.
|
||||
void svd_underoverflow()
|
||||
{
|
||||
#if defined __INTEL_COMPILER
|
||||
// shut up warning #239: floating point underflow
|
||||
#pragma warning push
|
||||
#pragma warning disable 239
|
||||
#endif
|
||||
Matrix2d M;
|
||||
M << -7.90884e-313, -4.94e-324,
|
||||
0, 5.60844e-313;
|
||||
SVD_DEFAULT(Matrix2d) svd;
|
||||
svd.compute(M,ComputeFullU|ComputeFullV);
|
||||
CALL_SUBTEST( svd_check_full(M,svd) );
|
||||
|
||||
// Check all 2x2 matrices made with the following coefficients:
|
||||
VectorXd value_set(9);
|
||||
value_set << 0, 1, -1, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -4.94e-223, 4.94e-223;
|
||||
Array4i id(0,0,0,0);
|
||||
int k = 0;
|
||||
do
|
||||
{
|
||||
M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3));
|
||||
svd.compute(M,ComputeFullU|ComputeFullV);
|
||||
CALL_SUBTEST( svd_check_full(M,svd) );
|
||||
|
||||
id(k)++;
|
||||
if(id(k)>=value_set.size())
|
||||
{
|
||||
while(k<3 && id(k)>=value_set.size()) id(++k)++;
|
||||
id.head(k).setZero();
|
||||
k=0;
|
||||
}
|
||||
|
||||
} while((id<int(value_set.size())).all());
|
||||
|
||||
#if defined __INTEL_COMPILER
|
||||
#pragma warning pop
|
||||
#endif
|
||||
|
||||
// Check for overflow:
|
||||
Matrix3d M3;
|
||||
M3 << 4.4331978442502944e+307, -5.8585363752028680e+307, 6.4527017443412964e+307,
|
||||
3.7841695601406358e+307, 2.4331702789740617e+306, -3.5235707140272905e+307,
|
||||
-8.7190887618028355e+307, -7.3453213709232193e+307, -2.4367363684472105e+307;
|
||||
|
||||
SVD_DEFAULT(Matrix3d) svd3;
|
||||
svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely
|
||||
CALL_SUBTEST( svd_check_full(M3,svd3) );
|
||||
}
|
||||
|
||||
// void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
|
||||
|
||||
template<typename MatrixType>
|
||||
void svd_all_trivial_2x2( void (*cb)(const MatrixType&,bool) )
|
||||
{
|
||||
MatrixType M;
|
||||
VectorXd value_set(3);
|
||||
value_set << 0, 1, -1;
|
||||
Array4i id(0,0,0,0);
|
||||
int k = 0;
|
||||
do
|
||||
{
|
||||
M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3));
|
||||
|
||||
cb(M,false);
|
||||
|
||||
id(k)++;
|
||||
if(id(k)>=value_set.size())
|
||||
{
|
||||
while(k<3 && id(k)>=value_set.size()) id(++k)++;
|
||||
id.head(k).setZero();
|
||||
k=0;
|
||||
}
|
||||
|
||||
} while((id<int(value_set.size())).all());
|
||||
}
|
||||
|
||||
void svd_preallocate()
|
||||
{
|
||||
Vector3f v(3.f, 2.f, 1.f);
|
||||
MatrixXf m = v.asDiagonal();
|
||||
|
||||
internal::set_is_malloc_allowed(false);
|
||||
VERIFY_RAISES_ASSERT(VectorXf tmp(10);)
|
||||
SVD_DEFAULT(MatrixXf) svd;
|
||||
internal::set_is_malloc_allowed(true);
|
||||
svd.compute(m);
|
||||
VERIFY_IS_APPROX(svd.singularValues(), v);
|
||||
|
||||
SVD_DEFAULT(MatrixXf) svd2(3,3);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
VERIFY_IS_APPROX(svd2.singularValues(), v);
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixU());
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixV());
|
||||
svd2.compute(m, ComputeFullU | ComputeFullV);
|
||||
VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
|
||||
VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
|
||||
SVD_DEFAULT(MatrixXf) svd3(3,3,ComputeFullU|ComputeFullV);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
VERIFY_IS_APPROX(svd2.singularValues(), v);
|
||||
VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
|
||||
VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m, ComputeFullU|ComputeFullV);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
}
|
||||
|
||||
template<typename SvdType,typename MatrixType>
|
||||
void svd_verify_assert(const MatrixType& m)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::Index Index;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, 1> RhsType;
|
||||
RhsType rhs(rows);
|
||||
SvdType svd;
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.singularValues())
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
MatrixType a = MatrixType::Zero(rows, cols);
|
||||
a.setZero();
|
||||
svd.compute(a, 0);
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
svd.singularValues();
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
|
||||
if (ColsAtCompileTime == Dynamic)
|
||||
{
|
||||
svd.compute(a, ComputeThinU);
|
||||
svd.matrixU();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
svd.compute(a, ComputeThinV);
|
||||
svd.matrixV();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU))
|
||||
VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV))
|
||||
}
|
||||
}
|
||||
|
||||
#undef SVD_DEFAULT
|
||||
#undef SVD_FOR_MIN_NORM
|
||||
@@ -41,9 +41,15 @@ template<typename MatrixType> void swap(const MatrixType& m)
|
||||
OtherMatrixType m3_copy = m3;
|
||||
|
||||
// test swapping 2 matrices of same type
|
||||
Scalar *d1=m1.data(), *d2=m2.data();
|
||||
m1.swap(m2);
|
||||
VERIFY_IS_APPROX(m1,m2_copy);
|
||||
VERIFY_IS_APPROX(m2,m1_copy);
|
||||
if(MatrixType::SizeAtCompileTime==Dynamic)
|
||||
{
|
||||
VERIFY(m1.data()==d2);
|
||||
VERIFY(m2.data()==d1);
|
||||
}
|
||||
m1 = m1_copy;
|
||||
m2 = m2_copy;
|
||||
|
||||
|
||||
@@ -27,19 +27,37 @@ std::string demangle_unrolling(int t)
|
||||
if(t==CompleteUnrolling) return "CompleteUnrolling";
|
||||
return "?";
|
||||
}
|
||||
std::string demangle_flags(int f)
|
||||
{
|
||||
std::string res;
|
||||
if(f&RowMajorBit) res += " | RowMajor";
|
||||
if(f&PacketAccessBit) res += " | Packet";
|
||||
if(f&LinearAccessBit) res += " | Linear";
|
||||
if(f&LvalueBit) res += " | Lvalue";
|
||||
if(f&DirectAccessBit) res += " | Direct";
|
||||
if(f&AlignedBit) res += " | Aligned";
|
||||
if(f&NestByRefBit) res += " | NestByRef";
|
||||
if(f&NoPreferredStorageOrderBit) res += " | NoPreferredStorageOrderBit";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename Dst, typename Src>
|
||||
bool test_assign(const Dst&, const Src&, int traversal, int unrolling)
|
||||
{
|
||||
internal::assign_traits<Dst,Src>::debug();
|
||||
bool res = internal::assign_traits<Dst,Src>::Traversal==traversal
|
||||
&& internal::assign_traits<Dst,Src>::Unrolling==unrolling;
|
||||
typedef internal::copy_using_evaluator_traits<internal::evaluator<Dst>,internal::evaluator<Src>, internal::assign_op<typename Dst::Scalar> > traits;
|
||||
bool res = traits::Traversal==traversal && traits::Unrolling==unrolling;
|
||||
if(!res)
|
||||
{
|
||||
std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl;
|
||||
std::cerr << " " << demangle_flags(internal::evaluator<Src>::Flags) << std::endl;
|
||||
std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl;
|
||||
std::cerr << " " << demangle_flags(internal::evaluator<Dst>::Flags) << std::endl;
|
||||
traits::debug();
|
||||
std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
|
||||
<< " got " << demangle_traversal(internal::assign_traits<Dst,Src>::Traversal) << "\n";
|
||||
<< " got " << demangle_traversal(traits::Traversal) << "\n";
|
||||
std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
|
||||
<< " got " << demangle_unrolling(internal::assign_traits<Dst,Src>::Unrolling) << "\n";
|
||||
<< " got " << demangle_unrolling(traits::Unrolling) << "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -47,15 +65,19 @@ bool test_assign(const Dst&, const Src&, int traversal, int unrolling)
|
||||
template<typename Dst, typename Src>
|
||||
bool test_assign(int traversal, int unrolling)
|
||||
{
|
||||
internal::assign_traits<Dst,Src>::debug();
|
||||
bool res = internal::assign_traits<Dst,Src>::Traversal==traversal
|
||||
&& internal::assign_traits<Dst,Src>::Unrolling==unrolling;
|
||||
typedef internal::copy_using_evaluator_traits<internal::evaluator<Dst>,internal::evaluator<Src>, internal::assign_op<typename Dst::Scalar> > traits;
|
||||
bool res = traits::Traversal==traversal && traits::Unrolling==unrolling;
|
||||
if(!res)
|
||||
{
|
||||
std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl;
|
||||
std::cerr << " " << demangle_flags(internal::evaluator<Src>::Flags) << std::endl;
|
||||
std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl;
|
||||
std::cerr << " " << demangle_flags(internal::evaluator<Dst>::Flags) << std::endl;
|
||||
traits::debug();
|
||||
std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
|
||||
<< " got " << demangle_traversal(internal::assign_traits<Dst,Src>::Traversal) << "\n";
|
||||
<< " got " << demangle_traversal(traits::Traversal) << "\n";
|
||||
std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
|
||||
<< " got " << demangle_unrolling(internal::assign_traits<Dst,Src>::Unrolling) << "\n";
|
||||
<< " got " << demangle_unrolling(traits::Unrolling) << "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -63,10 +85,15 @@ bool test_assign(int traversal, int unrolling)
|
||||
template<typename Xpr>
|
||||
bool test_redux(const Xpr&, int traversal, int unrolling)
|
||||
{
|
||||
typedef internal::redux_traits<internal::scalar_sum_op<typename Xpr::Scalar>,Xpr> traits;
|
||||
typedef internal::redux_traits<internal::scalar_sum_op<typename Xpr::Scalar>,internal::redux_evaluator<Xpr> > traits;
|
||||
|
||||
bool res = traits::Traversal==traversal && traits::Unrolling==unrolling;
|
||||
if(!res)
|
||||
{
|
||||
std::cerr << demangle_flags(Xpr::Flags) << std::endl;
|
||||
std::cerr << demangle_flags(internal::evaluator<Xpr>::Flags) << std::endl;
|
||||
traits::debug();
|
||||
|
||||
std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
|
||||
<< " got " << demangle_traversal(traits::Traversal) << "\n";
|
||||
std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
|
||||
|
||||
@@ -104,8 +104,8 @@ template<typename ArrayType> void vectorwiseop_array(const ArrayType& m)
|
||||
|
||||
m2 = m1;
|
||||
// yes, there might be an aliasing issue there but ".rowwise() /="
|
||||
// is suppposed to evaluate " m2.colwise().sum()" into to temporary to avoid
|
||||
// evaluating the reducions multiple times
|
||||
// is supposed to evaluate " m2.colwise().sum()" into a temporary to avoid
|
||||
// evaluating the reduction multiple times
|
||||
if(ArrayType::RowsAtCompileTime>2 || ArrayType::RowsAtCompileTime==Dynamic)
|
||||
{
|
||||
m2.rowwise() /= m2.colwise().sum();
|
||||
|
||||
Reference in New Issue
Block a user