Merge Index-refactoring branch with default, fix PastixSupport, remove some useless typedefs

This commit is contained in:
Gael Guennebaud
2015-02-13 10:03:53 +01:00
227 changed files with 32433 additions and 5999 deletions

View File

@@ -228,6 +228,7 @@ ei_add_test(stddeque)
ei_add_test(sparse_basic)
ei_add_test(sparse_vector)
ei_add_test(sparse_product)
ei_add_test(sparse_ref)
ei_add_test(sparse_solvers)
ei_add_test(sparse_permutations)
ei_add_test(simplicial_cholesky)

View File

@@ -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>()) );

View File

@@ -12,13 +12,15 @@
template<typename T> void test_conjugate_gradient_T()
{
ConjugateGradient<SparseMatrix<T>, Lower> cg_colmajor_lower_diag;
ConjugateGradient<SparseMatrix<T>, Upper> cg_colmajor_upper_diag;
ConjugateGradient<SparseMatrix<T>, Lower > cg_colmajor_lower_diag;
ConjugateGradient<SparseMatrix<T>, Upper > cg_colmajor_upper_diag;
ConjugateGradient<SparseMatrix<T>, Lower|Upper> cg_colmajor_loup_diag;
ConjugateGradient<SparseMatrix<T>, Lower, IdentityPreconditioner> cg_colmajor_lower_I;
ConjugateGradient<SparseMatrix<T>, Upper, IdentityPreconditioner> cg_colmajor_upper_I;
CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_lower_diag) );
CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_upper_diag) );
CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_loup_diag) );
CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_lower_I) );
CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_upper_I) );
}

View File

@@ -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()

View File

@@ -99,10 +99,16 @@ template<typename Scalar, int Mode, int Options> void transformations()
Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
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();

View File

@@ -47,8 +47,8 @@
// protected by parenthesis against macro expansion, the min()/max() macros
// are defined here and any not-parenthesized min/max call will cause a
// compiler error.
#define min(A,B) please_protect_your_min_with_parentheses
#define max(A,B) please_protect_your_max_with_parentheses
//#define min(A,B) please_protect_your_min_with_parentheses
//#define max(A,B) please_protect_your_max_with_parentheses
#define FORBIDDEN_IDENTIFIER (this_identifier_is_forbidden_to_avoid_clashes) this_identifier_is_forbidden_to_avoid_clashes
// B0 is defined in POSIX header termios.h
@@ -237,6 +237,7 @@ inline void verify_impl(bool condition, const char *testname, const char *file,
#define VERIFY(a) ::verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a))
#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b))
#define VERIFY_IS_NOT_EQUAL(a, b) VERIFY(!test_is_equal(a, b))
#define VERIFY_IS_APPROX(a, b) VERIFY(test_isApprox(a, b))
#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b))
#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b))

View File

@@ -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);

View File

@@ -261,6 +261,22 @@ template<typename Scalar> void packetmath()
VERIFY(isApproxAbs(data2[j], data1[i+j*PacketSize], refvalue) && "ptranspose");
}
}
if (internal::packet_traits<Scalar>::HasBlend) {
Packet thenPacket = internal::pload<Packet>(data1);
Packet elsePacket = internal::pload<Packet>(data2);
EIGEN_ALIGN_DEFAULT internal::Selector<PacketSize> selector;
for (int i = 0; i < PacketSize; ++i) {
selector.select[i] = i;
}
Packet blend = internal::pblend(selector, thenPacket, elsePacket);
EIGEN_ALIGN_DEFAULT Scalar result[size];
internal::pstore(result, blend);
for (int i = 0; i < PacketSize; ++i) {
VERIFY(isApproxAbs(result[i], (selector.select[i] ? data1[i] : data2[i]), refvalue));
}
}
}
template<typename Scalar> void packetmath_real()

View File

@@ -39,15 +39,16 @@ void test_product_large()
// check the functions to setup blocking sizes compile and do not segfault
// FIXME check they do what they are supposed to do !!
std::ptrdiff_t l1 = internal::random<int>(10000,20000);
std::ptrdiff_t l2 = internal::random<int>(1000000,2000000);
setCpuCacheSizes(l1,l2);
std::ptrdiff_t l2 = internal::random<int>(100000,200000);
std::ptrdiff_t l3 = internal::random<int>(1000000,2000000);
setCpuCacheSizes(l1,l2,l3);
VERIFY(l1==l1CacheSize());
VERIFY(l2==l2CacheSize());
std::ptrdiff_t k1 = internal::random<int>(10,100)*16;
std::ptrdiff_t m1 = internal::random<int>(10,100)*16;
std::ptrdiff_t n1 = internal::random<int>(10,100)*16;
// only makes sure it compiles fine
internal::computeProductBlockingSizes<float,float>(k1,m1,n1);
internal::computeProductBlockingSizes<float,float>(k1,m1,n1,1);
}
{

View File

@@ -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
}

View File

@@ -408,6 +408,26 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
m.setFromTriplets(triplets.begin(), triplets.end());
VERIFY_IS_APPROX(m, refMat);
}
// test Map
{
DenseMatrix refMat2(rows, cols), refMat3(rows, cols);
SparseMatrixType m2(rows, cols), m3(rows, cols);
initSparse<Scalar>(density, refMat2, m2);
initSparse<Scalar>(density, refMat3, m3);
{
Map<SparseMatrixType> mapMat2(m2.rows(), m2.cols(), m2.nonZeros(), m2.outerIndexPtr(), m2.innerIndexPtr(), m2.valuePtr(), m2.innerNonZeroPtr());
Map<SparseMatrixType> mapMat3(m3.rows(), m3.cols(), m3.nonZeros(), m3.outerIndexPtr(), m3.innerIndexPtr(), m3.valuePtr(), m3.innerNonZeroPtr());
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
}
{
MappedSparseMatrix<Scalar,SparseMatrixType::Options,StorageIndex> mapMat2(m2.rows(), m2.cols(), m2.nonZeros(), m2.outerIndexPtr(), m2.innerIndexPtr(), m2.valuePtr(), m2.innerNonZeroPtr());
MappedSparseMatrix<Scalar,SparseMatrixType::Options,StorageIndex> mapMat3(m3.rows(), m3.cols(), m3.nonZeros(), m3.outerIndexPtr(), m3.innerIndexPtr(), m3.valuePtr(), m3.innerNonZeroPtr());
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
}
}
// test triangularView
{

99
test/sparse_ref.cpp Normal file
View File

@@ -0,0 +1,99 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 20015 Gael Guennebaud <gael.guennebaud@inria.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/.
// This unit test cannot be easily written to work with EIGEN_DEFAULT_TO_ROW_MAJOR
#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR
#undef EIGEN_DEFAULT_TO_ROW_MAJOR
#endif
static long int nb_temporaries;
inline void on_temporary_creation() {
// here's a great place to set a breakpoint when debugging failures in this test!
nb_temporaries++;
}
#define EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN { on_temporary_creation(); }
#include "main.h"
#include <Eigen/SparseCore>
#define VERIFY_EVALUATION_COUNT(XPR,N) {\
nb_temporaries = 0; \
XPR; \
if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
VERIFY( (#XPR) && nb_temporaries==N ); \
}
template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
{
// verify that ref-to-const don't have LvalueBit
typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
VERIFY( !(internal::traits<Ref<ConstPlainObjectType> >::Flags & LvalueBit) );
VERIFY( !(internal::traits<Ref<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
VERIFY( !(Ref<ConstPlainObjectType>::Flags & LvalueBit) );
VERIFY( !(Ref<ConstPlainObjectType, Aligned>::Flags & LvalueBit) );
}
template<typename B>
EIGEN_DONT_INLINE void call_ref_1(Ref<SparseMatrix<float> > a, const B &b) { VERIFY_IS_EQUAL(a.toDense(),b.toDense()); }
template<typename B>
EIGEN_DONT_INLINE void call_ref_2(const Ref<const SparseMatrix<float> >& a, const B &b) { VERIFY_IS_EQUAL(a.toDense(),b.toDense()); }
void call_ref()
{
// SparseVector<std::complex<float> > ca = VectorXcf::Random(10).sparseView();
// SparseVector<float> a = VectorXf::Random(10).sparseView();
SparseMatrix<float> A = MatrixXf::Random(10,10).sparseView(0.5,1);
SparseMatrix<float,RowMajor> B = MatrixXf::Random(10,10).sparseView(0.5,1);
const SparseMatrix<float>& Ac(A);
Block<SparseMatrix<float> > Ab(A,0,1, 3,3);
const Block<SparseMatrix<float> > Abc(A,0,1,3,3);
VERIFY_EVALUATION_COUNT( call_ref_1(A, A), 0);
// VERIFY_EVALUATION_COUNT( call_ref_1(Ac, Ac), 0); // does not compile on purpose
VERIFY_EVALUATION_COUNT( call_ref_2(A, A), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(A.transpose(), A.transpose()), 1);
VERIFY_EVALUATION_COUNT( call_ref_2(Ac,Ac), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(A+A,2*Ac), 1);
VERIFY_EVALUATION_COUNT( call_ref_2(B, B), 1);
VERIFY_EVALUATION_COUNT( call_ref_2(B.transpose(), B.transpose()), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(A*A, A*A), 1);
Ref<SparseMatrix<float> > Ar(A);
VERIFY_IS_APPROX(Ar+Ar, A+A);
VERIFY_EVALUATION_COUNT( call_ref_1(Ar, A), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(Ar, A), 0);
Ref<SparseMatrix<float,RowMajor> > Br(B);
VERIFY_EVALUATION_COUNT( call_ref_1(Br.transpose(), Br.transpose()), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(Br, Br), 1);
VERIFY_EVALUATION_COUNT( call_ref_2(Br.transpose(), Br.transpose()), 0);
Ref<const SparseMatrix<float> > Arc(A);
// VERIFY_EVALUATION_COUNT( call_ref_1(Arc, Arc), 0); // does not compile on purpose
VERIFY_EVALUATION_COUNT( call_ref_2(Arc, Arc), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(A.middleCols(1,3), A.middleCols(1,3)), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(A.col(2), A.col(2)), 0);
VERIFY_EVALUATION_COUNT( call_ref_2(A.block(1,1,3,3), A.block(1,1,3,3)), 1); // should be 0 (allocate starts/nnz only)
}
void test_sparse_ref()
{
for(int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1( check_const_correctness(SparseMatrix<float>()) );
CALL_SUBTEST_1( check_const_correctness(SparseMatrix<double,RowMajor>()) );
CALL_SUBTEST_2( call_ref() );
}
}

View File

@@ -32,7 +32,7 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
x = solver.solve(b);
if (solver.info() != Success)
{
std::cerr << "sparse solver testing: solving failed\n";
std::cerr << "sparse solver testing: solving failed (" << typeid(Solver).name() << ")\n";
return;
}
VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
@@ -75,7 +75,8 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
xm = solver.solve(bm);
if (solver.info() != Success)
{
std::cerr << "sparse solver testing: solving failed\n";
std::cerr << "sparse solver testing: solving with a Map failed\n";
exit(0);
return;
}
VERIFY(oldb.isApprox(bm) && "sparse solver testing: the rhs should not be modified!");
@@ -194,7 +195,10 @@ int generate_sparse_spd_problem(Solver& , typename Solver::MatrixType& A, typena
dA = dM * dM.adjoint();
halfA.resize(size,size);
halfA.template selfadjointView<Solver::UpLo>().rankUpdate(M);
if(Solver::UpLo==(Lower|Upper))
halfA = A;
else
halfA.template selfadjointView<Solver::UpLo>().rankUpdate(M);
return size;
}