aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2012-11-02 10:59:05 +0000
committerXiaotao Duan <xiaotao@google.com>2012-11-07 14:17:48 -0800
commitc981c48f5bc9aefeffc0bcb0cc3934c2fae179dd (patch)
tree54d1c7d66098154c1d7c5bd414394ef4cf255810 /test
parent63f67d748682b46d58be31235a0a2d64d81b998c (diff)
downloadeigen-c981c48f5bc9aefeffc0bcb0cc3934c2fae179dd.tar.gz
Added a README.android and a MODULE_LICENSE_MPL2 file. Added empty Android.mk and CleanSpec.mk to optimize Android build. Non MPL2 license code is disabled in ./Eigen/src/Core/util/NonMPL2.h. Trying to include such files will lead to an error. Change-Id: I0e148b7c3e83999bcc4dfaa5809d33bfac2aac32
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt243
-rw-r--r--test/adjoint.cpp141
-rw-r--r--test/array.cpp303
-rw-r--r--test/array_for_matrix.cpp205
-rw-r--r--test/array_replicate.cpp70
-rw-r--r--test/array_reverse.cpp128
-rw-r--r--test/bandmatrix.cpp74
-rw-r--r--test/basicstuff.cpp215
-rw-r--r--test/bicgstab.cpp30
-rw-r--r--test/block.cpp222
-rw-r--r--test/cholesky.cpp310
-rw-r--r--test/cholmod_support.cpp56
-rw-r--r--test/commainitializer.cpp46
-rw-r--r--test/conjugate_gradient.cpp30
-rw-r--r--test/conservative_resize.cpp114
-rw-r--r--test/corners.cpp98
-rw-r--r--test/cwiseop.cpp165
-rw-r--r--test/determinant.cpp67
-rw-r--r--test/diagonal.cpp83
-rw-r--r--test/diagonalmatrices.cpp94
-rw-r--r--test/dontalign.cpp63
-rw-r--r--test/dynalloc.cpp133
-rw-r--r--test/eigen2/CMakeLists.txt60
-rw-r--r--test/eigen2/eigen2_adjoint.cpp101
-rw-r--r--test/eigen2/eigen2_alignedbox.cpp60
-rw-r--r--test/eigen2/eigen2_array.cpp142
-rw-r--r--test/eigen2/eigen2_basicstuff.cpp108
-rw-r--r--test/eigen2/eigen2_bug_132.cpp26
-rw-r--r--test/eigen2/eigen2_cholesky.cpp113
-rw-r--r--test/eigen2/eigen2_commainitializer.cpp46
-rw-r--r--test/eigen2/eigen2_cwiseop.cpp158
-rw-r--r--test/eigen2/eigen2_determinant.cpp61
-rw-r--r--test/eigen2/eigen2_dynalloc.cpp131
-rw-r--r--test/eigen2/eigen2_eigensolver.cpp146
-rw-r--r--test/eigen2/eigen2_first_aligned.cpp49
-rw-r--r--test/eigen2/eigen2_geometry.cpp431
-rw-r--r--test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp434
-rw-r--r--test/eigen2/eigen2_hyperplane.cpp126
-rw-r--r--test/eigen2/eigen2_inverse.cpp63
-rw-r--r--test/eigen2/eigen2_linearstructure.cpp84
-rw-r--r--test/eigen2/eigen2_lu.cpp122
-rw-r--r--test/eigen2/eigen2_map.cpp114
-rw-r--r--test/eigen2/eigen2_meta.cpp60
-rw-r--r--test/eigen2/eigen2_miscmatrices.cpp48
-rw-r--r--test/eigen2/eigen2_mixingtypes.cpp77
-rw-r--r--test/eigen2/eigen2_newstdvector.cpp149
-rw-r--r--test/eigen2/eigen2_nomalloc.cpp63
-rw-r--r--test/eigen2/eigen2_packetmath.cpp132
-rw-r--r--test/eigen2/eigen2_parametrizedline.cpp62
-rw-r--r--test/eigen2/eigen2_prec_inverse_4x4.cpp84
-rw-r--r--test/eigen2/eigen2_product_large.cpp45
-rw-r--r--test/eigen2/eigen2_product_small.cpp22
-rw-r--r--test/eigen2/eigen2_qr.cpp69
-rw-r--r--test/eigen2/eigen2_qtvector.cpp158
-rw-r--r--test/eigen2/eigen2_regression.cpp136
-rw-r--r--test/eigen2/eigen2_sizeof.cpp31
-rw-r--r--test/eigen2/eigen2_smallvectors.cpp42
-rw-r--r--test/eigen2/eigen2_sparse_basic.cpp317
-rw-r--r--test/eigen2/eigen2_sparse_product.cpp115
-rw-r--r--test/eigen2/eigen2_sparse_solvers.cpp200
-rw-r--r--test/eigen2/eigen2_sparse_vector.cpp84
-rw-r--r--test/eigen2/eigen2_stdvector.cpp148
-rw-r--r--test/eigen2/eigen2_submatrices.cpp148
-rw-r--r--test/eigen2/eigen2_sum.cpp71
-rw-r--r--test/eigen2/eigen2_svd.cpp87
-rw-r--r--test/eigen2/eigen2_swap.cpp83
-rw-r--r--test/eigen2/eigen2_triangular.cpp158
-rw-r--r--test/eigen2/eigen2_unalignedassert.cpp116
-rw-r--r--test/eigen2/eigen2_visitor.cpp116
-rw-r--r--test/eigen2/gsl_helper.h175
-rw-r--r--test/eigen2/main.h399
-rw-r--r--test/eigen2/product.h132
-rwxr-xr-xtest/eigen2/runtest.sh28
-rw-r--r--test/eigen2/sparse.h154
-rw-r--r--test/eigen2/testsuite.cmake197
-rw-r--r--test/eigen2support.cpp64
-rw-r--r--test/eigensolver_complex.cpp115
-rw-r--r--test/eigensolver_generic.cpp115
-rw-r--r--test/eigensolver_selfadjoint.cpp146
-rw-r--r--test/exceptions.cpp109
-rw-r--r--test/first_aligned.cpp51
-rw-r--r--test/geo_alignedbox.cpp171
-rw-r--r--test/geo_eulerangles.cpp54
-rw-r--r--test/geo_homogeneous.cpp103
-rw-r--r--test/geo_hyperplane.cpp157
-rw-r--r--test/geo_orthomethods.cpp121
-rw-r--r--test/geo_parametrizedline.cpp105
-rw-r--r--test/geo_quaternion.cpp255
-rw-r--r--test/geo_transformations.cpp487
-rw-r--r--test/hessenberg.cpp62
-rw-r--r--test/householder.cpp123
-rw-r--r--test/integer_types.cpp161
-rw-r--r--test/inverse.cpp102
-rw-r--r--test/jacobi.cpp81
-rw-r--r--test/jacobisvd.cpp350
-rw-r--r--test/linearstructure.cpp83
-rw-r--r--test/lu.cpp207
-rw-r--r--test/main.h472
-rw-r--r--test/map.cpp144
-rw-r--r--test/mapstaticmethods.cpp173
-rw-r--r--test/mapstride.cpp146
-rw-r--r--test/meta.cpp76
-rw-r--r--test/miscmatrices.cpp48
-rw-r--r--test/mixingtypes.cpp132
-rw-r--r--test/nesting_ops.cpp41
-rw-r--r--test/nomalloc.cpp174
-rw-r--r--test/nullary.cpp123
-rw-r--r--test/packetmath.cpp345
-rw-r--r--test/pardiso_support.cpp29
-rw-r--r--test/pastix_support.cpp44
-rw-r--r--test/permutationmatrices.cpp117
-rw-r--r--test/prec_inverse_4x4.cpp68
-rw-r--r--test/product.h143
-rw-r--r--test/product_extra.cpp148
-rw-r--r--test/product_large.cpp64
-rw-r--r--test/product_mmtr.cpp65
-rw-r--r--test/product_notemporary.cpp138
-rw-r--r--test/product_selfadjoint.cpp81
-rw-r--r--test/product_small.cpp50
-rw-r--r--test/product_symm.cpp96
-rw-r--r--test/product_syrk.cpp98
-rw-r--r--test/product_trmm.cpp108
-rw-r--r--test/product_trmv.cpp89
-rw-r--r--test/product_trsolve.cpp93
-rw-r--r--test/qr.cpp126
-rw-r--r--test/qr_colpivoting.cpp150
-rw-r--r--test/qr_fullpivoting.cpp132
-rw-r--r--test/qtvector.cpp158
-rw-r--r--test/redux.cpp158
-rw-r--r--test/resize.cpp41
-rwxr-xr-xtest/runtest.sh20
-rw-r--r--test/schur_complex.cpp74
-rw-r--r--test/schur_real.cpp93
-rw-r--r--test/selfadjoint.cpp62
-rw-r--r--test/simplicial_cholesky.cpp40
-rw-r--r--test/sizeof.cpp34
-rw-r--r--test/sizeoverflow.cpp66
-rw-r--r--test/smallvectors.cpp67
-rw-r--r--test/sparse.h182
-rw-r--r--test/sparse_basic.cpp395
-rw-r--r--test/sparse_permutations.cpp187
-rw-r--r--test/sparse_product.cpp204
-rw-r--r--test/sparse_solver.h309
-rw-r--r--test/sparse_solvers.cpp112
-rw-r--r--test/sparse_vector.cpp91
-rw-r--r--test/stable_norm.cpp110
-rw-r--r--test/stddeque.cpp132
-rw-r--r--test/stdlist.cpp132
-rw-r--r--test/stdvector.cpp148
-rw-r--r--test/stdvector_overload.cpp161
-rw-r--r--test/superlu_support.cpp22
-rw-r--r--test/swap.cpp83
-rw-r--r--test/testsuite.cmake229
-rw-r--r--test/triangular.cpp235
-rw-r--r--test/umeyama.cpp183
-rw-r--r--test/umfpack_support.cpp31
-rw-r--r--test/unalignedassert.cpp127
-rw-r--r--test/unalignedcount.cpp44
-rw-r--r--test/upperbidiagonalization.cpp41
-rw-r--r--test/vectorization_logic.cpp235
-rw-r--r--test/vectorwiseop.cpp172
-rw-r--r--test/visitor.cpp118
-rw-r--r--test/zerosized.cpp59
163 files changed, 20861 insertions, 0 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 000000000..6f8fc4ae3
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,243 @@
+
+# generate split test header file
+message(STATUS ${CMAKE_CURRENT_BINARY_DIR})
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h "")
+foreach(i RANGE 1 999)
+ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h
+ "#ifdef EIGEN_TEST_PART_${i}\n"
+ "#define CALL_SUBTEST_${i}(FUNC) CALL_SUBTEST(FUNC)\n"
+ "#else\n"
+ "#define CALL_SUBTEST_${i}(FUNC)\n"
+ "#endif\n\n"
+ )
+endforeach()
+
+# configure blas/lapack (use Eigen's ones)
+set(BLAS_FOUND TRUE)
+set(LAPACK_FOUND TRUE)
+set(BLAS_LIBRARIES eigen_blas)
+set(LAPACK_LIBRARIES eigen_lapack)
+
+set(EIGEN_TEST_MATRIX_DIR "" CACHE STRING "Enable testing of realword sparse matrices contained in the specified path")
+if(EIGEN_TEST_MATRIX_DIR)
+ if(NOT WIN32)
+ message(STATUS "Test realworld sparse matrices: ${EIGEN_TEST_MATRIX_DIR}")
+ add_definitions( -DTEST_REAL_CASES="${EIGEN_TEST_MATRIX_DIR}" )
+ else(NOT WIN32)
+ message(STATUS "REAL CASES CAN NOT BE CURRENTLY TESTED ON WIN32")
+ endif(NOT WIN32)
+endif(EIGEN_TEST_MATRIX_DIR)
+
+set(SPARSE_LIBS " ")
+
+find_package(Cholmod)
+if(CHOLMOD_FOUND AND BLAS_FOUND AND LAPACK_FOUND)
+ add_definitions("-DEIGEN_CHOLMOD_SUPPORT")
+ include_directories(${CHOLMOD_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+ set(CHOLMOD_ALL_LIBS ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "Cholmod, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "Cholmod, ")
+endif()
+
+find_package(Umfpack)
+if(UMFPACK_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_UMFPACK_SUPPORT")
+ include_directories(${UMFPACK_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
+ set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "UmfPack, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "UmfPack, ")
+endif()
+
+find_package(SuperLU)
+if(SUPERLU_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_SUPERLU_SUPPORT")
+ include_directories(${SUPERLU_INCLUDES})
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
+ set(SUPERLU_ALL_LIBS ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "SuperLU, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "SuperLU, ")
+endif()
+
+
+find_package(Pastix)
+find_package(Scotch)
+find_package(Metis)
+if(PASTIX_FOUND AND BLAS_FOUND)
+ add_definitions("-DEIGEN_PASTIX_SUPPORT")
+ include_directories(${PASTIX_INCLUDES})
+ if(SCOTCH_FOUND)
+ include_directories(${SCOTCH_INCLUDES})
+ set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${SCOTCH_LIBRARIES})
+ elseif(METIS_FOUND)
+ include_directories(${METIS_INCLUDES})
+ set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${METIS_LIBRARIES})
+ else(SCOTCH_FOUND)
+ ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ")
+ endif(SCOTCH_FOUND)
+ set(SPARSE_LIBS ${SPARSE_LIBS} ${PASTIX_LIBRARIES} ${ORDERING_LIBRARIES} ${BLAS_LIBRARIES})
+ set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES} ${BLAS_LIBRARIES})
+ ei_add_property(EIGEN_TESTED_BACKENDS "PaStiX, ")
+else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ")
+endif()
+
+option(EIGEN_TEST_NOQT "Disable Qt support in unit tests" OFF)
+if(NOT EIGEN_TEST_NOQT)
+ find_package(Qt4)
+ if(QT4_FOUND)
+ include(${QT_USE_FILE})
+ ei_add_property(EIGEN_TESTED_BACKENDS "Qt4 support, ")
+ else()
+ ei_add_property(EIGEN_MISSING_BACKENDS "Qt4 support, ")
+ endif()
+endif(NOT EIGEN_TEST_NOQT)
+
+if(TEST_LIB)
+ add_definitions("-DEIGEN_EXTERN_INSTANTIATIONS=1")
+endif(TEST_LIB)
+
+ei_add_test(meta)
+ei_add_test(sizeof)
+ei_add_test(dynalloc)
+ei_add_test(nomalloc)
+ei_add_test(first_aligned)
+ei_add_test(mixingtypes)
+ei_add_test(packetmath)
+ei_add_test(unalignedassert)
+ei_add_test(vectorization_logic)
+ei_add_test(basicstuff)
+ei_add_test(linearstructure)
+ei_add_test(integer_types)
+ei_add_test(cwiseop)
+ei_add_test(unalignedcount)
+ei_add_test(exceptions)
+ei_add_test(redux)
+ei_add_test(visitor)
+ei_add_test(block)
+ei_add_test(corners)
+ei_add_test(product_small)
+ei_add_test(product_large)
+ei_add_test(product_extra)
+ei_add_test(diagonalmatrices)
+ei_add_test(adjoint)
+ei_add_test(diagonal)
+ei_add_test(miscmatrices)
+ei_add_test(commainitializer)
+ei_add_test(smallvectors)
+ei_add_test(map)
+ei_add_test(mapstride)
+ei_add_test(mapstaticmethods)
+ei_add_test(array)
+ei_add_test(array_for_matrix)
+ei_add_test(array_replicate)
+ei_add_test(array_reverse)
+ei_add_test(triangular)
+ei_add_test(selfadjoint)
+ei_add_test(product_selfadjoint)
+ei_add_test(product_symm)
+ei_add_test(product_syrk)
+ei_add_test(product_trmv)
+ei_add_test(product_trmm)
+ei_add_test(product_trsolve)
+ei_add_test(product_mmtr)
+ei_add_test(product_notemporary)
+ei_add_test(stable_norm)
+ei_add_test(bandmatrix)
+ei_add_test(cholesky)
+ei_add_test(lu)
+ei_add_test(determinant)
+ei_add_test(inverse)
+ei_add_test(qr)
+ei_add_test(qr_colpivoting)
+ei_add_test(qr_fullpivoting)
+ei_add_test(upperbidiagonalization)
+ei_add_test(hessenberg)
+ei_add_test(schur_real)
+ei_add_test(schur_complex)
+ei_add_test(eigensolver_selfadjoint)
+ei_add_test(eigensolver_generic)
+ei_add_test(eigensolver_complex)
+ei_add_test(jacobi)
+ei_add_test(jacobisvd)
+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(stdvector)
+ei_add_test(stdvector_overload)
+ei_add_test(stdlist)
+ei_add_test(stddeque)
+ei_add_test(resize)
+if(QT4_FOUND)
+ ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}")
+endif(QT4_FOUND)
+ei_add_test(sparse_vector)
+ei_add_test(sparse_basic)
+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(eigen2support)
+ei_add_test(nullary)
+ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}")
+ei_add_test(zerosized)
+ei_add_test(dontalign)
+ei_add_test(sizeoverflow)
+ei_add_test(prec_inverse_4x4)
+ei_add_test(vectorwiseop)
+
+ei_add_test(simplicial_cholesky)
+ei_add_test(conjugate_gradient)
+ei_add_test(bicgstab)
+
+
+if(UMFPACK_FOUND)
+ ei_add_test(umfpack_support "" "${UMFPACK_ALL_LIBS}")
+endif()
+
+if(SUPERLU_FOUND)
+ ei_add_test(superlu_support "" "${SUPERLU_ALL_LIBS}")
+endif()
+
+if(CHOLMOD_FOUND)
+ ei_add_test(cholmod_support "" "${CHOLMOD_ALL_LIBS}")
+endif()
+
+if(PARDISO_FOUND)
+ ei_add_test(pardiso_support "" "${PARDISO_ALL_LIBS}")
+endif()
+
+if(PASTIX_FOUND AND (SCOTCH_FOUND OR METIS_FOUND))
+ ei_add_test(pastix_support "" "${PASTIX_ALL_LIBS}")
+endif()
+
+string(TOLOWER "${CMAKE_CXX_COMPILER}" cmake_cxx_compiler_tolower)
+if(cmake_cxx_compiler_tolower MATCHES "qcc")
+ set(CXX_IS_QCC "ON")
+endif()
+
+ei_add_property(EIGEN_TESTING_SUMMARY "CXX: ${CMAKE_CXX_COMPILER}\n")
+if(CMAKE_COMPILER_IS_GNUCXX AND NOT CXX_IS_QCC)
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version COMMAND head -n 1 OUTPUT_VARIABLE EIGEN_CXX_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE)
+ ei_add_property(EIGEN_TESTING_SUMMARY "CXX_VERSION: ${EIGEN_CXX_VERSION_STRING}\n")
+endif()
+ei_add_property(EIGEN_TESTING_SUMMARY "CXX_FLAGS: ${CMAKE_CXX_FLAGS}\n")
+ei_add_property(EIGEN_TESTING_SUMMARY "Sparse lib flags: ${SPARSE_LIBS}\n")
+
+option(EIGEN_TEST_EIGEN2 "Run whole Eigen2 test suite against EIGEN2_SUPPORT" OFF)
+if(EIGEN_TEST_EIGEN2)
+ add_subdirectory(eigen2)
+endif()
diff --git a/test/adjoint.cpp b/test/adjoint.cpp
new file mode 100644
index 000000000..b6cf0a68b
--- /dev/null
+++ b/test/adjoint.cpp
@@ -0,0 +1,141 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+template<typename MatrixType> void adjoint(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Transpose.h Conjugate.h Dot.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ square = SquareMatrixType::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // check basic compatibility of adjoint, transpose, conjugate
+ VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1);
+ VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(), m1);
+
+ // check multiplicative behavior
+ VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(), m2.adjoint() * m1);
+ VERIFY_IS_APPROX((s1 * m1).adjoint(), internal::conj(s1) * m1.adjoint());
+
+ // check basic properties of dot, norm, norm2
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ RealScalar ref = NumTraits<Scalar>::IsInteger ? RealScalar(0) : (std::max)((s1 * v1 + s2 * v2).norm(),v3.norm());
+ VERIFY(test_isApproxWithRef((s1 * v1 + s2 * v2).dot(v3), internal::conj(s1) * v1.dot(v3) + internal::conj(s2) * v2.dot(v3), ref));
+ VERIFY(test_isApproxWithRef(v3.dot(s1 * v1 + s2 * v2), s1*v3.dot(v1)+s2*v3.dot(v2), ref));
+ VERIFY_IS_APPROX(internal::conj(v1.dot(v2)), v2.dot(v1));
+ VERIFY_IS_APPROX(internal::real(v1.dot(v1)), v1.squaredNorm());
+ if(!NumTraits<Scalar>::IsInteger) {
+ VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm());
+ // check normalized() and normalize()
+ VERIFY_IS_APPROX(v1, v1.norm() * v1.normalized());
+ v3 = v1;
+ v3.normalize();
+ VERIFY_IS_APPROX(v1, v1.norm() * v3);
+ VERIFY_IS_APPROX(v3, v1.normalized());
+ VERIFY_IS_APPROX(v3.norm(), RealScalar(1));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(vzero.dot(v1)), static_cast<RealScalar>(1));
+
+ // check compatibility of dot and adjoint
+
+ ref = NumTraits<Scalar>::IsInteger ? 0 : (std::max)((std::max)(v1.norm(),v2.norm()),(std::max)((square * v2).norm(),(square.adjoint() * v1).norm()));
+ VERIFY(test_isApproxWithRef(v1.dot(square * v2), (square.adjoint() * v1).dot(v2), ref));
+
+ // like in testBasicStuff, test operator() to check const-qualification
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+ VERIFY_IS_APPROX(m1.conjugate()(r,c), internal::conj(m1(r,c)));
+ VERIFY_IS_APPROX(m1.adjoint()(c,r), internal::conj(m1(r,c)));
+
+ if(!NumTraits<Scalar>::IsInteger)
+ {
+ // check that Random().normalized() works: tricky as the random xpr must be evaluated by
+ // normalized() in order to produce a consistent result.
+ VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1));
+ }
+
+ // check inplace transpose
+ m3 = m1;
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1.transpose());
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1);
+
+ // check inplace adjoint
+ m3 = m1;
+ m3.adjointInPlace();
+ VERIFY_IS_APPROX(m3,m1.adjoint());
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1.conjugate());
+
+ // check mixed dot product
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ RealVectorType rv1 = RealVectorType::Random(rows);
+ VERIFY_IS_APPROX(v1.dot(rv1.template cast<Scalar>()), v1.dot(rv1));
+ VERIFY_IS_APPROX(rv1.template cast<Scalar>().dot(v1), rv1.dot(v1));
+}
+
+void test_adjoint()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ 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))) );
+ }
+ // test a large static matrix only once
+ CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
+
+#ifdef EIGEN_TEST_PART_4
+ {
+ MatrixXcf a(10,10), b(10,10);
+ VERIFY_RAISES_ASSERT(a = a.transpose());
+ VERIFY_RAISES_ASSERT(a = a.transpose() + b);
+ VERIFY_RAISES_ASSERT(a = b + a.transpose());
+ VERIFY_RAISES_ASSERT(a = a.conjugate().transpose());
+ VERIFY_RAISES_ASSERT(a = a.adjoint());
+ VERIFY_RAISES_ASSERT(a = a.adjoint() + b);
+ VERIFY_RAISES_ASSERT(a = b + a.adjoint());
+
+ // no assertion should be triggered for these cases:
+ a.transpose() = a.transpose();
+ a.transpose() += a.transpose();
+ a.transpose() += a.transpose() + b;
+ a.transpose() = a.adjoint();
+ a.transpose() += a.adjoint();
+ a.transpose() += a.adjoint() + b;
+ }
+#endif
+}
+
diff --git a/test/array.cpp b/test/array.cpp
new file mode 100644
index 000000000..3548fa641
--- /dev/null
+++ b/test/array.cpp
@@ -0,0 +1,303 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename ArrayType> void array(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<Scalar, ArrayType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Array<Scalar, 1, ArrayType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2 = ArrayType::Random(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType cv1 = ColVectorType::Random(rows);
+ RowVectorType rv1 = RowVectorType::Random(cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1 + s1, s1 + m1);
+ VERIFY_IS_APPROX(m1 + s1, ArrayType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX(s1 - m1, (-m1)+s1 );
+ VERIFY_IS_APPROX(m1 - s1, m1 - ArrayType::Constant(rows,cols,s1));
+ VERIFY_IS_APPROX(s1 - m1, ArrayType::Constant(rows,cols,s1) - m1);
+ VERIFY_IS_APPROX((m1*Scalar(2)) - s2, (m1+m1) - ArrayType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3 += s2;
+ VERIFY_IS_APPROX(m3, m1 + s2);
+ m3 = m1;
+ m3 -= s1;
+ VERIFY_IS_APPROX(m3, m1 - s1);
+
+ // scalar operators via Maps
+ m3 = m1;
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) -= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 - m2);
+
+ m3 = m1;
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) += ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 + m2);
+
+ m3 = m1;
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) *= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 * m2);
+
+ m3 = m1;
+ m2 = ArrayType::Random(rows,cols);
+ m2 = (m2==0).select(1,m2);
+ ArrayType::Map(m1.data(), m1.rows(), m1.cols()) /= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
+ VERIFY_IS_APPROX(m1, m3 / m2);
+
+ // reductions
+ VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
+ if (!internal::isApprox(m1.sum(), (m1+m2).sum(), test_precision<Scalar>()))
+ VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));
+
+ // vector-wise ops
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
+}
+
+template<typename ArrayType> void comparisons(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<Scalar, ArrayType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2 = ArrayType::Random(rows, cols),
+ m3(rows, cols);
+
+ VERIFY(((m1 + Scalar(1)) > m1).all());
+ VERIFY(((m1 - Scalar(1)) < m1).all());
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY(! (m1 < m3).all() );
+ VERIFY(! (m1 > m3).all() );
+ }
+
+ // comparisons to scalar
+ VERIFY( (m1 != (m1(r,c)+1) ).any() );
+ VERIFY( (m1 > (m1(r,c)-1) ).any() );
+ VERIFY( (m1 < (m1(r,c)+1) ).any() );
+ VERIFY( (m1 == m1(r,c) ).any() );
+
+ // test Select
+ VERIFY_IS_APPROX( (m1<m2).select(m1,m2), m1.cwiseMin(m2) );
+ VERIFY_IS_APPROX( (m1>m2).select(m1,m2), m1.cwiseMax(m2) );
+ Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
+ VERIFY_IS_APPROX( (m1.abs()<ArrayType::Constant(rows,cols,mid))
+ .select(ArrayType::Zero(rows,cols),m1), m3);
+ // shorter versions:
+ VERIFY_IS_APPROX( (m1.abs()<ArrayType::Constant(rows,cols,mid))
+ .select(0,m1), m3);
+ VERIFY_IS_APPROX( (m1.abs()>=ArrayType::Constant(rows,cols,mid))
+ .select(m1,0), m3);
+ // even shorter version:
+ VERIFY_IS_APPROX( (m1.abs()<mid).select(0,m1), m3);
+
+ // count
+ VERIFY(((m1.abs()+1)>RealScalar(0.1)).count() == rows*cols);
+
+ // and/or
+ VERIFY( (m1<RealScalar(0) && m1>RealScalar(0)).count() == 0);
+ VERIFY( (m1<RealScalar(0) || m1>=RealScalar(0)).count() == rows*cols);
+ RealScalar a = m1.abs().mean();
+ VERIFY( (m1<-a || m1>a).count() == (m1.abs()>a).count());
+
+ typedef Array<typename ArrayType::Index, Dynamic, 1> ArrayOfIndices;
+
+ // TODO allows colwise/rowwise for array
+ VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).colwise().count(), ArrayOfIndices::Constant(cols,rows).transpose());
+ VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).rowwise().count(), ArrayOfIndices::Constant(rows, cols));
+}
+
+template<typename ArrayType> void array_real(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2 = ArrayType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ // these tests are mostly to check possible compilation issues.
+ VERIFY_IS_APPROX(m1.sin(), std::sin(m1));
+ VERIFY_IS_APPROX(m1.sin(), internal::sin(m1));
+ VERIFY_IS_APPROX(m1.cos(), std::cos(m1));
+ VERIFY_IS_APPROX(m1.cos(), internal::cos(m1));
+ VERIFY_IS_APPROX(m1.asin(), std::asin(m1));
+ VERIFY_IS_APPROX(m1.asin(), internal::asin(m1));
+ VERIFY_IS_APPROX(m1.acos(), std::acos(m1));
+ VERIFY_IS_APPROX(m1.acos(), internal::acos(m1));
+ VERIFY_IS_APPROX(m1.tan(), std::tan(m1));
+ VERIFY_IS_APPROX(m1.tan(), internal::tan(m1));
+
+ VERIFY_IS_APPROX(internal::cos(m1+RealScalar(3)*m2), internal::cos((m1+RealScalar(3)*m2).eval()));
+ VERIFY_IS_APPROX(std::cos(m1+RealScalar(3)*m2), std::cos((m1+RealScalar(3)*m2).eval()));
+
+ VERIFY_IS_APPROX(m1.abs().sqrt(), std::sqrt(std::abs(m1)));
+ VERIFY_IS_APPROX(m1.abs().sqrt(), internal::sqrt(internal::abs(m1)));
+ VERIFY_IS_APPROX(m1.abs(), internal::sqrt(internal::abs2(m1)));
+
+ VERIFY_IS_APPROX(internal::abs2(internal::real(m1)) + internal::abs2(internal::imag(m1)), internal::abs2(m1));
+ VERIFY_IS_APPROX(internal::abs2(std::real(m1)) + internal::abs2(std::imag(m1)), internal::abs2(m1));
+ if(!NumTraits<Scalar>::IsComplex)
+ VERIFY_IS_APPROX(internal::real(m1), m1);
+
+ VERIFY_IS_APPROX(m1.abs().log(), std::log(std::abs(m1)));
+ VERIFY_IS_APPROX(m1.abs().log(), internal::log(internal::abs(m1)));
+
+ VERIFY_IS_APPROX(m1.exp(), std::exp(m1));
+ VERIFY_IS_APPROX(m1.exp() * m2.exp(), std::exp(m1+m2));
+ VERIFY_IS_APPROX(m1.exp(), internal::exp(m1));
+ VERIFY_IS_APPROX(m1.exp() / m2.exp(), std::exp(m1-m2));
+
+ VERIFY_IS_APPROX(m1.pow(2), m1.square());
+ VERIFY_IS_APPROX(std::pow(m1,2), m1.square());
+
+ ArrayType exponents = ArrayType::Constant(rows, cols, RealScalar(2));
+ VERIFY_IS_APPROX(std::pow(m1,exponents), m1.square());
+
+ m3 = m1.abs();
+ VERIFY_IS_APPROX(m3.pow(RealScalar(0.5)), m3.sqrt());
+ VERIFY_IS_APPROX(std::pow(m3,RealScalar(0.5)), m3.sqrt());
+
+ // scalar by array division
+ const RealScalar tiny = std::sqrt(std::numeric_limits<RealScalar>::epsilon());
+ s1 += Scalar(tiny);
+ m1 += ArrayType::Constant(rows,cols,Scalar(tiny));
+ VERIFY_IS_APPROX(s1/m1, s1 * m1.inverse());
+}
+
+template<typename ArrayType> void array_complex(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2(rows, cols);
+
+ for (Index i = 0; i < m.rows(); ++i)
+ for (Index j = 0; j < m.cols(); ++j)
+ m2(i,j) = std::sqrt(m1(i,j));
+
+ VERIFY_IS_APPROX(m1.sqrt(), m2);
+ VERIFY_IS_APPROX(m1.sqrt(), std::sqrt(m1));
+ VERIFY_IS_APPROX(m1.sqrt(), internal::sqrt(m1));
+}
+
+template<typename ArrayType> void min_max(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ArrayType m1 = ArrayType::Random(rows, cols);
+
+ // min/max with array
+ Scalar maxM1 = m1.maxCoeff();
+ Scalar minM1 = m1.minCoeff();
+
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, minM1), (m1.min)(ArrayType::Constant(rows,cols, minM1)));
+ VERIFY_IS_APPROX(m1, (m1.min)(ArrayType::Constant(rows,cols, maxM1)));
+
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, maxM1), (m1.max)(ArrayType::Constant(rows,cols, maxM1)));
+ VERIFY_IS_APPROX(m1, (m1.max)(ArrayType::Constant(rows,cols, minM1)));
+
+ // min/max with scalar input
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, minM1), (m1.min)( minM1));
+ VERIFY_IS_APPROX(m1, (m1.min)( maxM1));
+
+ VERIFY_IS_APPROX(ArrayType::Constant(rows,cols, maxM1), (m1.max)( maxM1));
+ VERIFY_IS_APPROX(m1, (m1.max)( minM1));
+
+}
+
+void test_array()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( array(Array22f()) );
+ CALL_SUBTEST_3( array(Array44d()) );
+ CALL_SUBTEST_4( array(ArrayXXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( array(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( array(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( comparisons(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( comparisons(Array22f()) );
+ CALL_SUBTEST_3( comparisons(Array44d()) );
+ CALL_SUBTEST_5( comparisons(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( comparisons(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( min_max(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( min_max(Array22f()) );
+ CALL_SUBTEST_3( min_max(Array44d()) );
+ CALL_SUBTEST_5( min_max(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( min_max(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array_real(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( array_real(Array22f()) );
+ CALL_SUBTEST_3( array_real(Array44d()) );
+ CALL_SUBTEST_5( array_real(ArrayXXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_4( array_complex(ArrayXXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<int>::type, int >::value));
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<float>::type, float >::value));
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<Array2i>::type, ArrayBase<Array2i> >::value));
+ typedef CwiseUnaryOp<internal::scalar_sum_op<double>, ArrayXd > Xpr;
+ VERIFY((internal::is_same< internal::global_math_functions_filtering_base<Xpr>::type,
+ ArrayBase<Xpr>
+ >::value));
+}
diff --git a/test/array_for_matrix.cpp b/test/array_for_matrix.cpp
new file mode 100644
index 000000000..4b637c3a6
--- /dev/null
+++ b/test/array_for_matrix.cpp
@@ -0,0 +1,205 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void array_for_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType cv1 = ColVectorType::Random(rows);
+ RowVectorType rv1 = RowVectorType::Random(cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
+ VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX(((m1*Scalar(2)).array() - s2).matrix(), (m1+m1) - MatrixType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3.array() += s2;
+ VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
+ m3 = m1;
+ m3.array() -= s1;
+ VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());
+
+ // reductions
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum().sum() - m1.sum(), m1.cwiseAbs().maxCoeff());
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum().sum() - m1.sum(), m1.cwiseAbs().maxCoeff());
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum() + m2.colwise().sum() - (m1+m2).colwise().sum(), (m1+m2).cwiseAbs().maxCoeff());
+ VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum() - m2.rowwise().sum() - (m1-m2).rowwise().sum(), (m1-m2).cwiseAbs().maxCoeff());
+ VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));
+
+ // vector-wise ops
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
+ m3 = m1;
+ VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
+
+ // empty objects
+ VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(), RowVectorType::Zero(cols));
+ VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));
+
+ // verify the const accessors exist
+ const Scalar& ref_m1 = m.matrix().array().coeffRef(0);
+ const Scalar& ref_m2 = m.matrix().array().coeffRef(0,0);
+ const Scalar& ref_a1 = m.array().matrix().coeffRef(0);
+ const Scalar& ref_a2 = m.array().matrix().coeffRef(0,0);
+ VERIFY(&ref_a1 == &ref_m1);
+ VERIFY(&ref_a2 == &ref_m2);
+}
+
+template<typename MatrixType> void comparisons(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
+ VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY(! (m1.array() < m3.array()).all() );
+ VERIFY(! (m1.array() > m3.array()).all() );
+ }
+
+ // comparisons to scalar
+ VERIFY( (m1.array() != (m1(r,c)+1) ).any() );
+ VERIFY( (m1.array() > (m1(r,c)-1) ).any() );
+ VERIFY( (m1.array() < (m1(r,c)+1) ).any() );
+ VERIFY( (m1.array() == m1(r,c) ).any() );
+
+ // test Select
+ VERIFY_IS_APPROX( (m1.array()<m2.array()).select(m1,m2), m1.cwiseMin(m2) );
+ VERIFY_IS_APPROX( (m1.array()>m2.array()).select(m1,m2), m1.cwiseMax(m2) );
+ Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
+ VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
+ .select(MatrixType::Zero(rows,cols),m1), m3);
+ // shorter versions:
+ VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
+ .select(0,m1), m3);
+ VERIFY_IS_APPROX( (m1.array().abs()>=MatrixType::Constant(rows,cols,mid).array())
+ .select(m1,0), m3);
+ // even shorter version:
+ VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);
+
+ // count
+ VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);
+
+ typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;
+
+ // TODO allows colwise/rowwise for array
+ VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
+ VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
+}
+
+template<typename VectorType> void lpNorm(const VectorType& v)
+{
+ VectorType u = VectorType::Random(v.size());
+
+ VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
+ VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
+ VERIFY_IS_APPROX(u.template lpNorm<2>(), internal::sqrt(u.array().abs().square().sum()));
+ VERIFY_IS_APPROX(internal::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum());
+}
+
+template<typename MatrixType> void cwise_min_max(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+
+ // min/max with array
+ Scalar maxM1 = m1.maxCoeff();
+ Scalar minM1 = m1.minCoeff();
+
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, minM1), m1.cwiseMin(MatrixType::Constant(rows,cols, minM1)));
+ VERIFY_IS_APPROX(m1, m1.cwiseMin(MatrixType::Constant(rows,cols, maxM1)));
+
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1), m1.cwiseMax(MatrixType::Constant(rows,cols, maxM1)));
+ VERIFY_IS_APPROX(m1, m1.cwiseMax(MatrixType::Constant(rows,cols, minM1)));
+
+ // min/max with scalar input
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, minM1), m1.cwiseMin( minM1));
+ VERIFY_IS_APPROX(m1, m1.cwiseMin( maxM1));
+
+ VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1), m1.cwiseMax( maxM1));
+ VERIFY_IS_APPROX(m1, m1.cwiseMax( minM1));
+
+}
+
+void test_array_for_matrix()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array_for_matrix(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( array_for_matrix(Matrix2f()) );
+ CALL_SUBTEST_3( array_for_matrix(Matrix4d()) );
+ CALL_SUBTEST_4( array_for_matrix(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( array_for_matrix(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( array_for_matrix(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( comparisons(Matrix2f()) );
+ CALL_SUBTEST_3( comparisons(Matrix4d()) );
+ CALL_SUBTEST_5( comparisons(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( comparisons(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( cwise_min_max(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( cwise_min_max(Matrix2f()) );
+ CALL_SUBTEST_3( cwise_min_max(Matrix4d()) );
+ CALL_SUBTEST_5( cwise_min_max(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( cwise_min_max(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( lpNorm(Vector2f()) );
+ CALL_SUBTEST_7( lpNorm(Vector3d()) );
+ CALL_SUBTEST_8( lpNorm(Vector4f()) );
+ CALL_SUBTEST_5( lpNorm(VectorXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( lpNorm(VectorXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/array_replicate.cpp b/test/array_replicate.cpp
new file mode 100644
index 000000000..94da7425b
--- /dev/null
+++ b/test/array_replicate.cpp
@@ -0,0 +1,70 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void replicate(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Replicate.cpp
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic> MatrixX;
+ typedef Matrix<Scalar, Dynamic, 1> VectorX;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+
+ VectorType v1 = VectorType::Random(rows);
+
+ MatrixX x1, x2;
+ VectorX vx1;
+
+ int f1 = internal::random<int>(1,10),
+ f2 = internal::random<int>(1,10);
+
+ x1.resize(rows*f1,cols*f2);
+ for(int j=0; j<f2; j++)
+ for(int i=0; i<f1; i++)
+ x1.block(i*rows,j*cols,rows,cols) = m1;
+ VERIFY_IS_APPROX(x1, m1.replicate(f1,f2));
+
+ x2.resize(2*rows,3*cols);
+ x2 << m2, m2, m2,
+ m2, m2, m2;
+ VERIFY_IS_APPROX(x2, (m2.template replicate<2,3>()));
+
+ x2.resize(rows,f1);
+ for (int j=0; j<f1; ++j)
+ x2.col(j) = v1;
+ VERIFY_IS_APPROX(x2, v1.rowwise().replicate(f1));
+
+ vx1.resize(rows*f2);
+ for (int j=0; j<f2; ++j)
+ vx1.segment(j*rows,rows) = v1;
+ VERIFY_IS_APPROX(vx1, v1.colwise().replicate(f2));
+}
+
+void test_array_replicate()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( replicate(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( replicate(Vector2f()) );
+ CALL_SUBTEST_3( replicate(Vector3d()) );
+ CALL_SUBTEST_4( replicate(Vector4f()) );
+ CALL_SUBTEST_5( replicate(VectorXf(16)) );
+ CALL_SUBTEST_6( replicate(VectorXcd(10)) );
+ }
+}
diff --git a/test/array_reverse.cpp b/test/array_reverse.cpp
new file mode 100644
index 000000000..fbe7a9901
--- /dev/null
+++ b/test/array_reverse.cpp
@@ -0,0 +1,128 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2009 Ricard Marxer <email@ricardmarxer.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/.
+
+#include "main.h"
+#include <iostream>
+
+using namespace std;
+
+template<typename MatrixType> void reverse(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols);
+ VectorType v1 = VectorType::Random(rows);
+
+ MatrixType m1_r = m1.reverse();
+ // Verify that MatrixBase::reverse() works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_r(i, j), m1(rows - 1 - i, cols - 1 - j));
+ }
+ }
+
+ Reverse<MatrixType> m1_rd(m1);
+ // Verify that a Reverse default (in both directions) of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rd(i, j), m1(rows - 1 - i, cols - 1 - j));
+ }
+ }
+
+ Reverse<MatrixType, BothDirections> m1_rb(m1);
+ // Verify that a Reverse in both directions of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rb(i, j), m1(rows - 1 - i, cols - 1 - j));
+ }
+ }
+
+ Reverse<MatrixType, Vertical> m1_rv(m1);
+ // Verify that a Reverse in the vertical directions of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rv(i, j), m1(rows - 1 - i, j));
+ }
+ }
+
+ Reverse<MatrixType, Horizontal> m1_rh(m1);
+ // Verify that a Reverse in the horizontal directions of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rh(i, j), m1(i, cols - 1 - j));
+ }
+ }
+
+ VectorType v1_r = v1.reverse();
+ // Verify that a VectorType::reverse() of an expression works
+ for ( int i = 0; i < rows; i++ ) {
+ VERIFY_IS_APPROX(v1_r(i), v1(rows - 1 - i));
+ }
+
+ MatrixType m1_cr = m1.colwise().reverse();
+ // Verify that PartialRedux::reverse() works (for colwise())
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_cr(i, j), m1(rows - 1 - i, j));
+ }
+ }
+
+ MatrixType m1_rr = m1.rowwise().reverse();
+ // Verify that PartialRedux::reverse() works (for rowwise())
+ for ( int i = 0; i < rows; i++ ) {
+ for ( int j = 0; j < cols; j++ ) {
+ VERIFY_IS_APPROX(m1_rr(i, j), m1(i, cols - 1 - j));
+ }
+ }
+
+ Scalar x = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ m1.reverse()(r, c) = x;
+ VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c));
+
+ /*
+ m1.colwise().reverse()(r, c) = x;
+ VERIFY_IS_APPROX(x, m1(rows - 1 - r, c));
+
+ m1.rowwise().reverse()(r, c) = x;
+ VERIFY_IS_APPROX(x, m1(r, cols - 1 - c));
+ */
+}
+
+void test_array_reverse()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( reverse(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( reverse(Matrix2f()) );
+ CALL_SUBTEST_3( reverse(Matrix4f()) );
+ CALL_SUBTEST_4( reverse(Matrix4d()) );
+ CALL_SUBTEST_5( reverse(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_6( reverse(MatrixXi(6, 3)) );
+ CALL_SUBTEST_7( reverse(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_8( reverse(Matrix<float, 100, 100>()) );
+ CALL_SUBTEST_9( reverse(Matrix<float,Dynamic,Dynamic,RowMajor>(6,3)) );
+ }
+#ifdef EIGEN_TEST_PART_3
+ Vector4f x; x << 1, 2, 3, 4;
+ Vector4f y; y << 4, 3, 2, 1;
+ VERIFY(x.reverse()[1] == 3);
+ VERIFY(x.reverse() == y);
+#endif
+}
diff --git a/test/bandmatrix.cpp b/test/bandmatrix.cpp
new file mode 100644
index 000000000..5e4e8e07b
--- /dev/null
+++ b/test/bandmatrix.cpp
@@ -0,0 +1,74 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void bandmatrix(const MatrixType& _m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrixType;
+
+ Index rows = _m.rows();
+ Index cols = _m.cols();
+ Index supers = _m.supers();
+ Index subs = _m.subs();
+
+ MatrixType m(rows,cols,supers,subs);
+
+ DenseMatrixType dm1(rows,cols);
+ dm1.setZero();
+
+ m.diagonal().setConstant(123);
+ dm1.diagonal().setConstant(123);
+ for (int i=1; i<=m.supers();++i)
+ {
+ m.diagonal(i).setConstant(static_cast<RealScalar>(i));
+ dm1.diagonal(i).setConstant(static_cast<RealScalar>(i));
+ }
+ for (int i=1; i<=m.subs();++i)
+ {
+ m.diagonal(-i).setConstant(-static_cast<RealScalar>(i));
+ dm1.diagonal(-i).setConstant(-static_cast<RealScalar>(i));
+ }
+ //std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n\n\n";
+ VERIFY_IS_APPROX(dm1,m.toDenseMatrix());
+
+ for (int i=0; i<cols; ++i)
+ {
+ m.col(i).setConstant(static_cast<RealScalar>(i+1));
+ dm1.col(i).setConstant(static_cast<RealScalar>(i+1));
+ }
+ Index d = (std::min)(rows,cols);
+ Index a = std::max<Index>(0,cols-d-supers);
+ Index b = std::max<Index>(0,rows-d-subs);
+ if(a>0) dm1.block(0,d+supers,rows,a).setZero();
+ dm1.block(0,supers+1,cols-supers-1-a,cols-supers-1-a).template triangularView<Upper>().setZero();
+ dm1.block(subs+1,0,rows-subs-1-b,rows-subs-1-b).template triangularView<Lower>().setZero();
+ if(b>0) dm1.block(d+subs,0,b,cols).setZero();
+ //std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n";
+ VERIFY_IS_APPROX(dm1,m.toDenseMatrix());
+
+}
+
+using Eigen::internal::BandMatrix;
+
+void test_bandmatrix()
+{
+ typedef BandMatrix<float>::Index Index;
+
+ for(int i = 0; i < 10*g_repeat ; i++) {
+ Index rows = internal::random<Index>(1,10);
+ Index cols = internal::random<Index>(1,10);
+ Index sups = internal::random<Index>(0,cols-1);
+ Index subs = internal::random<Index>(0,rows-1);
+ CALL_SUBTEST(bandmatrix(BandMatrix<float>(rows,cols,sups,subs)) );
+ }
+}
diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp
new file mode 100644
index 000000000..48db531c1
--- /dev/null
+++ b/test/basicstuff.cpp
@@ -0,0 +1,215 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+template<typename MatrixType> void basicStuff(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+ SquareMatrixType sm1 = SquareMatrixType::Random(rows,rows), sm2(rows,rows);
+
+ Scalar x = 0;
+ while(x == Scalar(0)) x = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ m1.coeffRef(r,c) = x;
+ VERIFY_IS_APPROX(x, m1.coeff(r,c));
+ m1(r,c) = x;
+ VERIFY_IS_APPROX(x, m1(r,c));
+ v1.coeffRef(r) = x;
+ VERIFY_IS_APPROX(x, v1.coeff(r));
+ v1(r) = x;
+ VERIFY_IS_APPROX(x, v1(r));
+ v1[r] = x;
+ VERIFY_IS_APPROX(x, v1[r]);
+
+ VERIFY_IS_APPROX( v1, v1);
+ VERIFY_IS_NOT_APPROX( v1, 2*v1);
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1);
+ if(!NumTraits<Scalar>::IsInteger)
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1.norm());
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1);
+ VERIFY_IS_APPROX( vzero, v1-v1);
+ VERIFY_IS_APPROX( m1, m1);
+ VERIFY_IS_NOT_APPROX( m1, 2*m1);
+ VERIFY_IS_MUCH_SMALLER_THAN( mzero, m1);
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1);
+ VERIFY_IS_APPROX( mzero, m1-m1);
+
+ // always test operator() on each read-only expression class,
+ // in order to check const-qualifiers.
+ // indeed, if an expression class (here Zero) is meant to be read-only,
+ // hence has no _write() method, the corresponding MatrixBase method (here zero())
+ // should return a const-qualified object so that it is the const-qualified
+ // operator() that gets called, which in turn calls _read().
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1));
+
+ // now test copying a row-vector into a (column-)vector and conversely.
+ square.col(r) = square.row(r).eval();
+ Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
+ rv = square.row(r);
+ cv = square.col(r);
+
+ VERIFY_IS_APPROX(rv, cv.transpose());
+
+ if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
+ {
+ VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1)));
+ }
+
+ if(cols!=1 && rows!=1)
+ {
+ VERIFY_RAISES_ASSERT(m1[0]);
+ VERIFY_RAISES_ASSERT((m1+m1)[0]);
+ }
+
+ VERIFY_IS_APPROX(m3 = m1,m1);
+ MatrixType m4;
+ VERIFY_IS_APPROX(m4 = m1,m1);
+
+ m3.real() = m1.real();
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real());
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real());
+
+ // check == / != operators
+ VERIFY(m1==m1);
+ VERIFY(m1!=m2);
+ VERIFY(!(m1==m2));
+ VERIFY(!(m1!=m1));
+ m1 = m2;
+ VERIFY(m1==m2);
+ VERIFY(!(m1!=m2));
+
+ // check automatic transposition
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i) = sm1.row(i);
+ VERIFY_IS_APPROX(sm2,sm1.transpose());
+
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i).noalias() = sm1.row(i);
+ VERIFY_IS_APPROX(sm2,sm1.transpose());
+
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i).noalias() += sm1.row(i);
+ VERIFY_IS_APPROX(sm2,sm1.transpose());
+
+ sm2.setZero();
+ for(typename MatrixType::Index i=0;i<rows;++i)
+ sm2.col(i).noalias() -= sm1.row(i);
+ VERIFY_IS_APPROX(sm2,-sm1.transpose());
+}
+
+template<typename MatrixType> void basicStuffComplex(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> RealMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ VERIFY(internal::real(s1)==internal::real_ref(s1));
+ VERIFY(internal::imag(s1)==internal::imag_ref(s1));
+ internal::real_ref(s1) = internal::real(s2);
+ internal::imag_ref(s1) = internal::imag(s2);
+ VERIFY(internal::isApprox(s1, s2, NumTraits<RealScalar>::epsilon()));
+ // extended precision in Intel FPUs means that s1 == s2 in the line above is not guaranteed.
+
+ RealMatrixType rm1 = RealMatrixType::Random(rows,cols),
+ rm2 = RealMatrixType::Random(rows,cols);
+ MatrixType cm(rows,cols);
+ cm.real() = rm1;
+ cm.imag() = rm2;
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).real(), rm1);
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).imag(), rm2);
+ rm1.setZero();
+ rm2.setZero();
+ rm1 = cm.real();
+ rm2 = cm.imag();
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).real(), rm1);
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).imag(), rm2);
+ cm.real().setZero();
+ VERIFY(static_cast<const MatrixType&>(cm).real().isZero());
+ VERIFY(!static_cast<const MatrixType&>(cm).imag().isZero());
+}
+
+#ifdef EIGEN_TEST_PART_2
+void casting()
+{
+ Matrix4f m = Matrix4f::Random(), m2;
+ Matrix4d n = m.cast<double>();
+ VERIFY(m.isApprox(n.cast<float>()));
+ m2 = m.cast<float>(); // check the specialization when NewType == Type
+ VERIFY(m.isApprox(m2));
+}
+#endif
+
+template <typename Scalar>
+void fixedSizeMatrixConstruction()
+{
+ const Scalar raw[3] = {1,2,3};
+ Matrix<Scalar,3,1> m(raw);
+ Array<Scalar,3,1> a(raw);
+ VERIFY(m(0) == 1);
+ VERIFY(m(1) == 2);
+ VERIFY(m(2) == 3);
+ VERIFY(a(0) == 1);
+ VERIFY(a(1) == 2);
+ VERIFY(a(2) == 3);
+}
+
+void test_basicstuff()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( basicStuff(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( basicStuff(Matrix4d()) );
+ CALL_SUBTEST_3( basicStuff(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( basicStuff(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( basicStuff(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( basicStuff(Matrix<float, 100, 100>()) );
+ CALL_SUBTEST_7( basicStuff(Matrix<long double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+
+ CALL_SUBTEST_3( basicStuffComplex(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( basicStuffComplex(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+
+ CALL_SUBTEST_1(fixedSizeMatrixConstruction<unsigned char>());
+ CALL_SUBTEST_1(fixedSizeMatrixConstruction<double>());
+ CALL_SUBTEST_1(fixedSizeMatrixConstruction<double>());
+
+ CALL_SUBTEST_2(casting());
+}
diff --git a/test/bicgstab.cpp b/test/bicgstab.cpp
new file mode 100644
index 000000000..f327e2fac
--- /dev/null
+++ b/test/bicgstab.cpp
@@ -0,0 +1,30 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse_solver.h"
+#include <Eigen/IterativeLinearSolvers>
+
+template<typename T> void test_bicgstab_T()
+{
+ BiCGSTAB<SparseMatrix<T>, DiagonalPreconditioner<T> > bicgstab_colmajor_diag;
+ BiCGSTAB<SparseMatrix<T>, IdentityPreconditioner > bicgstab_colmajor_I;
+ BiCGSTAB<SparseMatrix<T>, IncompleteLUT<T> > bicgstab_colmajor_ilut;
+ //BiCGSTAB<SparseMatrix<T>, SSORPreconditioner<T> > bicgstab_colmajor_ssor;
+
+ CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_diag) );
+// CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_I) );
+ CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_ilut) );
+ //CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_ssor) );
+}
+
+void test_bicgstab()
+{
+ CALL_SUBTEST_1(test_bicgstab_T<double>());
+ CALL_SUBTEST_2(test_bicgstab_T<std::complex<double> >());
+}
diff --git a/test/block.cpp b/test/block.cpp
new file mode 100644
index 000000000..0969262ca
--- /dev/null
+++ b/test/block.cpp
@@ -0,0 +1,222 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 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/.
+
+#define EIGEN_NO_STATIC_ASSERT // otherwise we fail at compile time on unused paths
+#include "main.h"
+
+template<typename MatrixType> void block(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic> DynamicMatrixType;
+ typedef Matrix<Scalar, Dynamic, 1> DynamicVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m1_copy = m1,
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ ones = MatrixType::Ones(rows, cols);
+ VectorType v1 = VectorType::Random(rows);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index r1 = internal::random<Index>(0,rows-1);
+ Index r2 = internal::random<Index>(r1,rows-1);
+ Index c1 = internal::random<Index>(0,cols-1);
+ Index c2 = internal::random<Index>(c1,cols-1);
+
+ //check row() and col()
+ VERIFY_IS_EQUAL(m1.col(c1).transpose(), m1.transpose().row(c1));
+ //check operator(), both constant and non-constant, on row() and col()
+ m1 = m1_copy;
+ m1.row(r1) += s1 * m1_copy.row(r2);
+ VERIFY_IS_APPROX(m1.row(r1), m1_copy.row(r1) + s1 * m1_copy.row(r2));
+ // check nested block xpr on lhs
+ m1.row(r1).row(0) += s1 * m1_copy.row(r2);
+ VERIFY_IS_APPROX(m1.row(r1), m1_copy.row(r1) + Scalar(2) * s1 * m1_copy.row(r2));
+ m1 = m1_copy;
+ m1.col(c1) += s1 * m1_copy.col(c2);
+ VERIFY_IS_APPROX(m1.col(c1), m1_copy.col(c1) + s1 * m1_copy.col(c2));
+ m1.col(c1).col(0) += s1 * m1_copy.col(c2);
+ VERIFY_IS_APPROX(m1.col(c1), m1_copy.col(c1) + Scalar(2) * s1 * m1_copy.col(c2));
+
+ //check block()
+ Matrix<Scalar,Dynamic,Dynamic> b1(1,1); b1(0,0) = m1(r1,c1);
+
+ RowVectorType br1(m1.block(r1,0,1,cols));
+ VectorType bc1(m1.block(0,c1,rows,1));
+ VERIFY_IS_EQUAL(b1, m1.block(r1,c1,1,1));
+ VERIFY_IS_EQUAL(m1.row(r1), br1);
+ VERIFY_IS_EQUAL(m1.col(c1), bc1);
+ //check operator(), both constant and non-constant, on block()
+ m1.block(r1,c1,r2-r1+1,c2-c1+1) = s1 * m2.block(0, 0, r2-r1+1,c2-c1+1);
+ m1.block(r1,c1,r2-r1+1,c2-c1+1)(r2-r1,c2-c1) = m2.block(0, 0, r2-r1+1,c2-c1+1)(0,0);
+
+ enum {
+ BlockRows = 2,
+ BlockCols = 5
+ };
+ if (rows>=5 && cols>=8)
+ {
+ // test fixed block() as lvalue
+ m1.template block<BlockRows,BlockCols>(1,1) *= s1;
+ // test operator() on fixed block() both as constant and non-constant
+ m1.template block<BlockRows,BlockCols>(1,1)(0, 3) = m1.template block<2,5>(1,1)(1,2);
+ // check that fixed block() and block() agree
+ Matrix<Scalar,Dynamic,Dynamic> b = m1.template block<BlockRows,BlockCols>(3,3);
+ VERIFY_IS_EQUAL(b, m1.block(3,3,BlockRows,BlockCols));
+ }
+
+ if (rows>2)
+ {
+ // test sub vectors
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.block(0,0,2,1));
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.head(2));
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.segment(0,2));
+ VERIFY_IS_EQUAL(v1.template head<2>(), v1.template segment<2>(0));
+ Index i = rows-2;
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.block(i,0,2,1));
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.tail(2));
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.segment(i,2));
+ VERIFY_IS_EQUAL(v1.template tail<2>(), v1.template segment<2>(i));
+ i = internal::random<Index>(0,rows-2);
+ VERIFY_IS_EQUAL(v1.segment(i,2), v1.template segment<2>(i));
+ }
+
+ // stress some basic stuffs with block matrices
+ VERIFY(internal::real(ones.col(c1).sum()) == RealScalar(rows));
+ VERIFY(internal::real(ones.row(r1).sum()) == RealScalar(cols));
+
+ VERIFY(internal::real(ones.col(c1).dot(ones.col(c2))) == RealScalar(rows));
+ VERIFY(internal::real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols));
+
+ // now test some block-inside-of-block.
+
+ // expressions with direct access
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2)) , (m1.block(r2,c2,rows-r2,cols-c2)) );
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,r2-r1+1,c2-c1+1).row(0)) , (m1.row(r1).segment(c1,c2-c1+1)) );
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,r2-r1+1,c2-c1+1).col(0)) , (m1.col(c1).segment(r1,r2-r1+1)) );
+ VERIFY_IS_EQUAL( (m1.block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0)) , (m1.row(r1).segment(c1,c2-c1+1)).transpose() );
+ VERIFY_IS_EQUAL( (m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , (m1.row(r1).segment(c1,c2-c1+1)).transpose() );
+
+ // expressions without direct access
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2)) , ((m1+m2).block(r2,c2,rows-r2,cols-c2)) );
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).row(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)) );
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).col(0)) , ((m1+m2).col(c1).segment(r1,r2-r1+1)) );
+ VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() );
+ VERIFY_IS_EQUAL( ((m1+m2).transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() );
+
+ // evaluation into plain matrices from expressions with direct access (stress MapBase)
+ DynamicMatrixType dm;
+ DynamicVectorType dv;
+ dm.setZero();
+ dm = m1.block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2);
+ VERIFY_IS_EQUAL(dm, (m1.block(r2,c2,rows-r2,cols-c2)));
+ dm.setZero();
+ dv.setZero();
+ dm = m1.block(r1,c1,r2-r1+1,c2-c1+1).row(0).transpose();
+ dv = m1.row(r1).segment(c1,c2-c1+1);
+ VERIFY_IS_EQUAL(dv, dm);
+ dm.setZero();
+ dv.setZero();
+ dm = m1.col(c1).segment(r1,r2-r1+1);
+ dv = m1.block(r1,c1,r2-r1+1,c2-c1+1).col(0);
+ VERIFY_IS_EQUAL(dv, dm);
+ dm.setZero();
+ dv.setZero();
+ dm = m1.block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0);
+ dv = m1.row(r1).segment(c1,c2-c1+1);
+ VERIFY_IS_EQUAL(dv, dm);
+ dm.setZero();
+ dv.setZero();
+ dm = m1.row(r1).segment(c1,c2-c1+1).transpose();
+ dv = m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0);
+ VERIFY_IS_EQUAL(dv, dm);
+}
+
+
+template<typename MatrixType>
+void compare_using_data_and_stride(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index size = m.size();
+ Index innerStride = m.innerStride();
+ Index outerStride = m.outerStride();
+ Index rowStride = m.rowStride();
+ Index colStride = m.colStride();
+ const typename MatrixType::Scalar* data = m.data();
+
+ for(int j=0;j<cols;++j)
+ for(int i=0;i<rows;++i)
+ VERIFY(m.coeff(i,j) == data[i*rowStride + j*colStride]);
+
+ if(!MatrixType::IsVectorAtCompileTime)
+ {
+ for(int j=0;j<cols;++j)
+ for(int i=0;i<rows;++i)
+ VERIFY(m.coeff(i,j) == data[(MatrixType::Flags&RowMajorBit)
+ ? i*outerStride + j*innerStride
+ : j*outerStride + i*innerStride]);
+ }
+
+ if(MatrixType::IsVectorAtCompileTime)
+ {
+ VERIFY(innerStride == int((&m.coeff(1))-(&m.coeff(0))));
+ for (int i=0;i<size;++i)
+ VERIFY(m.coeff(i) == data[i*innerStride]);
+ }
+}
+
+template<typename MatrixType>
+void data_and_stride(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r1 = internal::random<Index>(0,rows-1);
+ Index r2 = internal::random<Index>(r1,rows-1);
+ Index c1 = internal::random<Index>(0,cols-1);
+ Index c2 = internal::random<Index>(c1,cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+ compare_using_data_and_stride(m1.block(r1, c1, r2-r1+1, c2-c1+1));
+ compare_using_data_and_stride(m1.transpose().block(c1, r1, c2-c1+1, r2-r1+1));
+ compare_using_data_and_stride(m1.row(r1));
+ compare_using_data_and_stride(m1.col(c1));
+ compare_using_data_and_stride(m1.row(r1).transpose());
+ compare_using_data_and_stride(m1.col(c1).transpose());
+}
+
+void test_block()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( block(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( block(Matrix4d()) );
+ CALL_SUBTEST_3( block(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( block(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( block(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_6( block(MatrixXf(20, 20)) );
+
+ CALL_SUBTEST_8( block(Matrix<float,Dynamic,4>(3, 4)) );
+
+#ifndef EIGEN_DEFAULT_TO_ROW_MAJOR
+ CALL_SUBTEST_6( data_and_stride(MatrixXf(internal::random(5,50), internal::random(5,50))) );
+ CALL_SUBTEST_7( data_and_stride(Matrix<int,Dynamic,Dynamic,RowMajor>(internal::random(5,50), internal::random(5,50))) );
+#endif
+ }
+}
diff --git a/test/cholesky.cpp b/test/cholesky.cpp
new file mode 100644
index 000000000..14e01c006
--- /dev/null
+++ b/test/cholesky.cpp
@@ -0,0 +1,310 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#ifndef EIGEN_NO_ASSERTION_CHECKING
+#define EIGEN_NO_ASSERTION_CHECKING
+#endif
+
+static int nb_temporaries;
+
+#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { if(size!=0) nb_temporaries++; }
+
+#include "main.h"
+#include <Eigen/Cholesky>
+#include <Eigen/QR>
+
+#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 MatrixType,template <typename,int> class CholType> void test_chol_update(const MatrixType& symm)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType symmLo = symm.template triangularView<Lower>();
+ MatrixType symmUp = symm.template triangularView<Upper>();
+ MatrixType symmCpy = symm;
+
+ CholType<MatrixType,Lower> chollo(symmLo);
+ CholType<MatrixType,Upper> cholup(symmUp);
+
+ for (int k=0; k<10; ++k)
+ {
+ VectorType vec = VectorType::Random(symm.rows());
+ RealScalar sigma = internal::random<RealScalar>();
+ symmCpy += sigma * vec * vec.adjoint();
+
+ // we are doing some downdates, so it might be the case that the matrix is not SPD anymore
+ CholType<MatrixType,Lower> chol(symmCpy);
+ if(chol.info()!=Success)
+ break;
+
+ chollo.rankUpdate(vec, sigma);
+ VERIFY_IS_APPROX(symmCpy, chollo.reconstructedMatrix());
+
+ cholup.rankUpdate(vec, sigma);
+ VERIFY_IS_APPROX(symmCpy, cholup.reconstructedMatrix());
+ }
+}
+
+template<typename MatrixType> void cholesky(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ LLT.h LDLT.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType a0 = MatrixType::Random(rows,cols);
+ VectorType vecB = VectorType::Random(rows), vecX(rows);
+ MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
+ SquareMatrixType symm = a0 * a0.adjoint();
+ // let's make sure the matrix is not singular or near singular
+ for (int k=0; k<3; ++k)
+ {
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ symm += a1 * a1.adjoint();
+ }
+
+ SquareMatrixType symmUp = symm.template triangularView<Upper>();
+ SquareMatrixType symmLo = symm.template triangularView<Lower>();
+
+ // to test if really Cholesky only uses the upper triangular part, uncomment the following
+ // FIXME: currently that fails !!
+ //symm.template part<StrictlyLower>().setZero();
+
+ {
+ LLT<SquareMatrixType,Lower> chollo(symmLo);
+ VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
+ vecX = chollo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = chollo.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ // test the upper mode
+ LLT<SquareMatrixType,Upper> cholup(symmUp);
+ VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix());
+ vecX = cholup.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = cholup.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ MatrixType neg = -symmLo;
+ chollo.compute(neg);
+ VERIFY(chollo.info()==NumericalIssue);
+
+ VERIFY_IS_APPROX(MatrixType(chollo.matrixL().transpose().conjugate()), MatrixType(chollo.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(chollo.matrixU().transpose().conjugate()), MatrixType(chollo.matrixL()));
+ VERIFY_IS_APPROX(MatrixType(cholup.matrixL().transpose().conjugate()), MatrixType(cholup.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(cholup.matrixU().transpose().conjugate()), MatrixType(cholup.matrixL()));
+ }
+
+ // LDLT
+ {
+ int sign = internal::random<int>()%2 ? 1 : -1;
+
+ if(sign == -1)
+ {
+ symm = -symm; // test a negative matrix
+ }
+
+ SquareMatrixType symmUp = symm.template triangularView<Upper>();
+ SquareMatrixType symmLo = symm.template triangularView<Lower>();
+
+ LDLT<SquareMatrixType,Lower> ldltlo(symmLo);
+ VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
+ vecX = ldltlo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = ldltlo.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ LDLT<SquareMatrixType,Upper> ldltup(symmUp);
+ VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
+ vecX = ldltup.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ matX = ldltup.solve(matB);
+ VERIFY_IS_APPROX(symm * matX, matB);
+
+ VERIFY_IS_APPROX(MatrixType(ldltlo.matrixL().transpose().conjugate()), MatrixType(ldltlo.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(ldltlo.matrixU().transpose().conjugate()), MatrixType(ldltlo.matrixL()));
+ VERIFY_IS_APPROX(MatrixType(ldltup.matrixL().transpose().conjugate()), MatrixType(ldltup.matrixU()));
+ VERIFY_IS_APPROX(MatrixType(ldltup.matrixU().transpose().conjugate()), MatrixType(ldltup.matrixL()));
+
+ if(MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ // note : each inplace permutation requires a small temporary vector (mask)
+
+ // check inplace solve
+ matX = matB;
+ VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0);
+ VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval());
+
+
+ matX = matB;
+ VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0);
+ VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval());
+ }
+
+ // restore
+ if(sign == -1)
+ symm = -symm;
+ }
+
+ // test some special use cases of SelfCwiseBinaryOp:
+ MatrixType m1 = MatrixType::Random(rows,cols), m2(rows,cols);
+ m2 = m1;
+ m2 += symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB));
+ m2 = m1;
+ m2 -= symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB));
+ m2 = m1;
+ m2.noalias() += symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB));
+ m2 = m1;
+ m2.noalias() -= symmLo.template selfadjointView<Lower>().llt().solve(matB);
+ VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB));
+
+ // update/downdate
+ CALL_SUBTEST(( test_chol_update<SquareMatrixType,LLT>(symm) ));
+ CALL_SUBTEST(( test_chol_update<SquareMatrixType,LDLT>(symm) ));
+}
+
+template<typename MatrixType> void cholesky_cplx(const MatrixType& m)
+{
+ // classic test
+ cholesky(m);
+
+ // test mixing real/scalar types
+
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RealMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealMatrixType a0 = RealMatrixType::Random(rows,cols);
+ VectorType vecB = VectorType::Random(rows), vecX(rows);
+ MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
+ RealMatrixType symm = a0 * a0.adjoint();
+ // let's make sure the matrix is not singular or near singular
+ for (int k=0; k<3; ++k)
+ {
+ RealMatrixType a1 = RealMatrixType::Random(rows,cols);
+ symm += a1 * a1.adjoint();
+ }
+
+ {
+ RealMatrixType symmLo = symm.template triangularView<Lower>();
+
+ LLT<RealMatrixType,Lower> chollo(symmLo);
+ VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
+ vecX = chollo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+// matX = chollo.solve(matB);
+// VERIFY_IS_APPROX(symm * matX, matB);
+ }
+
+ // LDLT
+ {
+ int sign = internal::random<int>()%2 ? 1 : -1;
+
+ if(sign == -1)
+ {
+ symm = -symm; // test a negative matrix
+ }
+
+ RealMatrixType symmLo = symm.template triangularView<Lower>();
+
+ LDLT<RealMatrixType,Lower> ldltlo(symmLo);
+ VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
+ vecX = ldltlo.solve(vecB);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+// matX = ldltlo.solve(matB);
+// VERIFY_IS_APPROX(symm * matX, matB);
+ }
+}
+
+// regression test for bug 241
+template<typename MatrixType> void cholesky_bug241(const MatrixType& m)
+{
+ eigen_assert(m.rows() == 2 && m.cols() == 2);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType matA;
+ matA << 1, 1, 1, 1;
+ VectorType vecB;
+ vecB << 1, 1;
+ VectorType vecX = matA.ldlt().solve(vecB);
+ VERIFY_IS_APPROX(matA * vecX, vecB);
+}
+
+template<typename MatrixType> void cholesky_verify_assert()
+{
+ MatrixType tmp;
+
+ LLT<MatrixType> llt;
+ VERIFY_RAISES_ASSERT(llt.matrixL())
+ VERIFY_RAISES_ASSERT(llt.matrixU())
+ VERIFY_RAISES_ASSERT(llt.solve(tmp))
+ VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp))
+
+ LDLT<MatrixType> ldlt;
+ VERIFY_RAISES_ASSERT(ldlt.matrixL())
+ VERIFY_RAISES_ASSERT(ldlt.permutationP())
+ VERIFY_RAISES_ASSERT(ldlt.vectorD())
+ VERIFY_RAISES_ASSERT(ldlt.isPositive())
+ VERIFY_RAISES_ASSERT(ldlt.isNegative())
+ VERIFY_RAISES_ASSERT(ldlt.solve(tmp))
+ VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp))
+}
+
+void test_cholesky()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) );
+ CALL_SUBTEST_3( cholesky(Matrix2d()) );
+ CALL_SUBTEST_3( cholesky_bug241(Matrix2d()) );
+ CALL_SUBTEST_4( cholesky(Matrix3f()) );
+ CALL_SUBTEST_5( cholesky(Matrix4d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_2( cholesky(MatrixXd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_6( cholesky_cplx(MatrixXcd(s,s)) );
+ }
+
+ CALL_SUBTEST_4( cholesky_verify_assert<Matrix3f>() );
+ CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() );
+ CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() );
+ CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() );
+
+ // Test problem size constructors
+ CALL_SUBTEST_9( LLT<MatrixXf>(10) );
+ CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/cholmod_support.cpp b/test/cholmod_support.cpp
new file mode 100644
index 000000000..8f8be3c0e
--- /dev/null
+++ b/test/cholmod_support.cpp
@@ -0,0 +1,56 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse_solver.h"
+
+#include <Eigen/CholmodSupport>
+
+template<typename T> void test_cholmod_T()
+{
+ CholmodDecomposition<SparseMatrix<T>, Lower> g_chol_colmajor_lower; g_chol_colmajor_lower.setMode(CholmodSupernodalLLt);
+ CholmodDecomposition<SparseMatrix<T>, Upper> g_chol_colmajor_upper; g_chol_colmajor_upper.setMode(CholmodSupernodalLLt);
+ CholmodDecomposition<SparseMatrix<T>, Lower> g_llt_colmajor_lower; g_llt_colmajor_lower.setMode(CholmodSimplicialLLt);
+ CholmodDecomposition<SparseMatrix<T>, Upper> g_llt_colmajor_upper; g_llt_colmajor_upper.setMode(CholmodSimplicialLLt);
+ CholmodDecomposition<SparseMatrix<T>, Lower> g_ldlt_colmajor_lower; g_ldlt_colmajor_lower.setMode(CholmodLDLt);
+ CholmodDecomposition<SparseMatrix<T>, Upper> g_ldlt_colmajor_upper; g_ldlt_colmajor_upper.setMode(CholmodLDLt);
+
+ CholmodSupernodalLLT<SparseMatrix<T>, Lower> chol_colmajor_lower;
+ CholmodSupernodalLLT<SparseMatrix<T>, Upper> chol_colmajor_upper;
+ CholmodSimplicialLLT<SparseMatrix<T>, Lower> llt_colmajor_lower;
+ CholmodSimplicialLLT<SparseMatrix<T>, Upper> llt_colmajor_upper;
+ CholmodSimplicialLDLT<SparseMatrix<T>, Lower> ldlt_colmajor_lower;
+ CholmodSimplicialLDLT<SparseMatrix<T>, Upper> ldlt_colmajor_upper;
+
+ check_sparse_spd_solving(g_chol_colmajor_lower);
+ check_sparse_spd_solving(g_chol_colmajor_upper);
+ check_sparse_spd_solving(g_llt_colmajor_lower);
+ check_sparse_spd_solving(g_llt_colmajor_upper);
+ check_sparse_spd_solving(g_ldlt_colmajor_lower);
+ check_sparse_spd_solving(g_ldlt_colmajor_upper);
+
+ check_sparse_spd_solving(chol_colmajor_lower);
+ check_sparse_spd_solving(chol_colmajor_upper);
+ check_sparse_spd_solving(llt_colmajor_lower);
+ check_sparse_spd_solving(llt_colmajor_upper);
+ check_sparse_spd_solving(ldlt_colmajor_lower);
+ check_sparse_spd_solving(ldlt_colmajor_upper);
+
+// check_sparse_spd_determinant(chol_colmajor_lower);
+// check_sparse_spd_determinant(chol_colmajor_upper);
+// check_sparse_spd_determinant(llt_colmajor_lower);
+// check_sparse_spd_determinant(llt_colmajor_upper);
+// check_sparse_spd_determinant(ldlt_colmajor_lower);
+// check_sparse_spd_determinant(ldlt_colmajor_upper);
+}
+
+void test_cholmod_support()
+{
+ CALL_SUBTEST_1(test_cholmod_T<double>());
+ CALL_SUBTEST_2(test_cholmod_T<std::complex<double> >());
+}
diff --git a/test/commainitializer.cpp b/test/commainitializer.cpp
new file mode 100644
index 000000000..99102b966
--- /dev/null
+++ b/test/commainitializer.cpp
@@ -0,0 +1,46 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+void test_commainitializer()
+{
+ Matrix3d m3;
+ Matrix4d m4;
+
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8) );
+
+ #ifndef _MSC_VER
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) );
+ #endif
+
+ double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ Matrix3d ref = Map<Matrix<double,3,3,RowMajor> >(data);
+
+ m3 = Matrix3d::Random();
+ m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+ VERIFY_IS_APPROX(m3, ref );
+
+ Vector3d vec[3];
+ vec[0] << 1, 4, 7;
+ vec[1] << 2, 5, 8;
+ vec[2] << 3, 6, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0], vec[1], vec[2];
+ VERIFY_IS_APPROX(m3, ref);
+
+ vec[0] << 1, 2, 3;
+ vec[1] << 4, 5, 6;
+ vec[2] << 7, 8, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0].transpose(),
+ 4, 5, 6,
+ vec[2].transpose();
+ VERIFY_IS_APPROX(m3, ref);
+}
diff --git a/test/conjugate_gradient.cpp b/test/conjugate_gradient.cpp
new file mode 100644
index 000000000..869051b31
--- /dev/null
+++ b/test/conjugate_gradient.cpp
@@ -0,0 +1,30 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse_solver.h"
+#include <Eigen/IterativeLinearSolvers>
+
+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, 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_lower_I) );
+ CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_upper_I) );
+}
+
+void test_conjugate_gradient()
+{
+ CALL_SUBTEST_1(test_conjugate_gradient_T<double>());
+ CALL_SUBTEST_2(test_conjugate_gradient_T<std::complex<double> >());
+}
diff --git a/test/conservative_resize.cpp b/test/conservative_resize.cpp
new file mode 100644
index 000000000..4d11e4075
--- /dev/null
+++ b/test/conservative_resize.cpp
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@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/.
+
+#include "main.h"
+
+#include <Eigen/Core>
+
+using namespace Eigen;
+
+template <typename Scalar, int Storage>
+void run_matrix_tests()
+{
+ typedef Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Storage> MatrixType;
+ typedef typename MatrixType::Index Index;
+
+ MatrixType m, n;
+
+ // boundary cases ...
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(1,50);
+ VERIFY_IS_APPROX(m, n.block(0,0,1,50));
+
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(50,1);
+ VERIFY_IS_APPROX(m, n.block(0,0,50,1));
+
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(50,50);
+ VERIFY_IS_APPROX(m, n.block(0,0,50,50));
+
+ // random shrinking ...
+ for (int i=0; i<25; ++i)
+ {
+ const Index rows = internal::random<Index>(1,50);
+ const Index cols = internal::random<Index>(1,50);
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResize(rows,cols);
+ VERIFY_IS_APPROX(m, n.block(0,0,rows,cols));
+ }
+
+ // random growing with zeroing ...
+ for (int i=0; i<25; ++i)
+ {
+ const Index rows = internal::random<Index>(50,75);
+ const Index cols = internal::random<Index>(50,75);
+ m = n = MatrixType::Random(50,50);
+ m.conservativeResizeLike(MatrixType::Zero(rows,cols));
+ VERIFY_IS_APPROX(m.block(0,0,n.rows(),n.cols()), n);
+ VERIFY( rows<=50 || m.block(50,0,rows-50,cols).sum() == Scalar(0) );
+ VERIFY( cols<=50 || m.block(0,50,rows,cols-50).sum() == Scalar(0) );
+ }
+}
+
+template <typename Scalar>
+void run_vector_tests()
+{
+ typedef Matrix<Scalar, 1, Eigen::Dynamic> MatrixType;
+
+ MatrixType m, n;
+
+ // boundary cases ...
+ m = n = MatrixType::Random(50);
+ m.conservativeResize(1);
+ VERIFY_IS_APPROX(m, n.segment(0,1));
+
+ m = n = MatrixType::Random(50);
+ m.conservativeResize(50);
+ VERIFY_IS_APPROX(m, n.segment(0,50));
+
+ // random shrinking ...
+ for (int i=0; i<50; ++i)
+ {
+ const int size = internal::random<int>(1,50);
+ m = n = MatrixType::Random(50);
+ m.conservativeResize(size);
+ VERIFY_IS_APPROX(m, n.segment(0,size));
+ }
+
+ // random growing with zeroing ...
+ for (int i=0; i<50; ++i)
+ {
+ const int size = internal::random<int>(50,100);
+ m = n = MatrixType::Random(50);
+ m.conservativeResizeLike(MatrixType::Zero(size));
+ VERIFY_IS_APPROX(m.segment(0,50), n);
+ VERIFY( size<=50 || m.segment(50,size-50).sum() == Scalar(0) );
+ }
+}
+
+void test_conservative_resize()
+{
+ CALL_SUBTEST_1((run_matrix_tests<int, Eigen::RowMajor>()));
+ CALL_SUBTEST_1((run_matrix_tests<int, Eigen::ColMajor>()));
+ CALL_SUBTEST_2((run_matrix_tests<float, Eigen::RowMajor>()));
+ CALL_SUBTEST_2((run_matrix_tests<float, Eigen::ColMajor>()));
+ CALL_SUBTEST_3((run_matrix_tests<double, Eigen::RowMajor>()));
+ CALL_SUBTEST_3((run_matrix_tests<double, Eigen::ColMajor>()));
+ CALL_SUBTEST_4((run_matrix_tests<std::complex<float>, Eigen::RowMajor>()));
+ CALL_SUBTEST_4((run_matrix_tests<std::complex<float>, Eigen::ColMajor>()));
+ CALL_SUBTEST_5((run_matrix_tests<std::complex<double>, Eigen::RowMajor>()));
+ CALL_SUBTEST_6((run_matrix_tests<std::complex<double>, Eigen::ColMajor>()));
+
+ CALL_SUBTEST_1((run_vector_tests<int>()));
+ CALL_SUBTEST_2((run_vector_tests<float>()));
+ CALL_SUBTEST_3((run_vector_tests<double>()));
+ CALL_SUBTEST_4((run_vector_tests<std::complex<float> >()));
+ CALL_SUBTEST_5((run_vector_tests<std::complex<double> >()));
+}
diff --git a/test/corners.cpp b/test/corners.cpp
new file mode 100644
index 000000000..4705c5f05
--- /dev/null
+++ b/test/corners.cpp
@@ -0,0 +1,98 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 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/.
+
+#include "main.h"
+
+#define COMPARE_CORNER(A,B) \
+ VERIFY_IS_EQUAL(matrix.A, matrix.B); \
+ VERIFY_IS_EQUAL(const_matrix.A, const_matrix.B);
+
+template<typename MatrixType> void corners(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(1,rows);
+ Index c = internal::random<Index>(1,cols);
+
+ MatrixType matrix = MatrixType::Random(rows,cols);
+ const MatrixType const_matrix = MatrixType::Random(rows,cols);
+
+ COMPARE_CORNER(topLeftCorner(r,c), block(0,0,r,c));
+ COMPARE_CORNER(topRightCorner(r,c), block(0,cols-c,r,c));
+ COMPARE_CORNER(bottomLeftCorner(r,c), block(rows-r,0,r,c));
+ COMPARE_CORNER(bottomRightCorner(r,c), block(rows-r,cols-c,r,c));
+
+ Index sr = internal::random<Index>(1,rows) - 1;
+ Index nr = internal::random<Index>(1,rows-sr);
+ Index sc = internal::random<Index>(1,cols) - 1;
+ Index nc = internal::random<Index>(1,cols-sc);
+
+ COMPARE_CORNER(topRows(r), block(0,0,r,cols));
+ COMPARE_CORNER(middleRows(sr,nr), block(sr,0,nr,cols));
+ COMPARE_CORNER(bottomRows(r), block(rows-r,0,r,cols));
+ COMPARE_CORNER(leftCols(c), block(0,0,rows,c));
+ COMPARE_CORNER(middleCols(sc,nc), block(0,sc,rows,nc));
+ COMPARE_CORNER(rightCols(c), block(0,cols-c,rows,c));
+}
+
+template<typename MatrixType, int CRows, int CCols, int SRows, int SCols> void corners_fixedsize()
+{
+ MatrixType matrix = MatrixType::Random();
+ const MatrixType const_matrix = MatrixType::Random();
+
+ enum {
+ rows = MatrixType::RowsAtCompileTime,
+ cols = MatrixType::ColsAtCompileTime,
+ r = CRows,
+ c = CCols,
+ sr = SRows,
+ sc = SCols
+ };
+
+ VERIFY_IS_EQUAL((matrix.template topLeftCorner<r,c>()), (matrix.template block<r,c>(0,0)));
+ VERIFY_IS_EQUAL((matrix.template topRightCorner<r,c>()), (matrix.template block<r,c>(0,cols-c)));
+ VERIFY_IS_EQUAL((matrix.template bottomLeftCorner<r,c>()), (matrix.template block<r,c>(rows-r,0)));
+ VERIFY_IS_EQUAL((matrix.template bottomRightCorner<r,c>()), (matrix.template block<r,c>(rows-r,cols-c)));
+
+ VERIFY_IS_EQUAL((matrix.template topRows<r>()), (matrix.template block<r,cols>(0,0)));
+ VERIFY_IS_EQUAL((matrix.template middleRows<r>(sr)), (matrix.template block<r,cols>(sr,0)));
+ VERIFY_IS_EQUAL((matrix.template bottomRows<r>()), (matrix.template block<r,cols>(rows-r,0)));
+ VERIFY_IS_EQUAL((matrix.template leftCols<c>()), (matrix.template block<rows,c>(0,0)));
+ VERIFY_IS_EQUAL((matrix.template middleCols<c>(sc)), (matrix.template block<rows,c>(0,sc)));
+ VERIFY_IS_EQUAL((matrix.template rightCols<c>()), (matrix.template block<rows,c>(0,cols-c)));
+
+ VERIFY_IS_EQUAL((const_matrix.template topLeftCorner<r,c>()), (const_matrix.template block<r,c>(0,0)));
+ VERIFY_IS_EQUAL((const_matrix.template topRightCorner<r,c>()), (const_matrix.template block<r,c>(0,cols-c)));
+ VERIFY_IS_EQUAL((const_matrix.template bottomLeftCorner<r,c>()), (const_matrix.template block<r,c>(rows-r,0)));
+ VERIFY_IS_EQUAL((const_matrix.template bottomRightCorner<r,c>()), (const_matrix.template block<r,c>(rows-r,cols-c)));
+
+ VERIFY_IS_EQUAL((const_matrix.template topRows<r>()), (const_matrix.template block<r,cols>(0,0)));
+ VERIFY_IS_EQUAL((const_matrix.template middleRows<r>(sr)), (const_matrix.template block<r,cols>(sr,0)));
+ VERIFY_IS_EQUAL((const_matrix.template bottomRows<r>()), (const_matrix.template block<r,cols>(rows-r,0)));
+ VERIFY_IS_EQUAL((const_matrix.template leftCols<c>()), (const_matrix.template block<rows,c>(0,0)));
+ VERIFY_IS_EQUAL((const_matrix.template middleCols<c>(sc)), (const_matrix.template block<rows,c>(0,sc)));
+ VERIFY_IS_EQUAL((const_matrix.template rightCols<c>()), (const_matrix.template block<rows,c>(0,cols-c)));
+}
+
+void test_corners()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( corners(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( corners(Matrix4d()) );
+ CALL_SUBTEST_3( corners(Matrix<int,10,12>()) );
+ CALL_SUBTEST_4( corners(MatrixXcf(5, 7)) );
+ CALL_SUBTEST_5( corners(MatrixXf(21, 20)) );
+
+ CALL_SUBTEST_1(( corners_fixedsize<Matrix<float, 1, 1>, 1, 1, 0, 0>() ));
+ CALL_SUBTEST_2(( corners_fixedsize<Matrix4d,2,2,1,1>() ));
+ CALL_SUBTEST_3(( corners_fixedsize<Matrix<int,10,12>,4,7,5,2>() ));
+ }
+}
diff --git a/test/cwiseop.cpp b/test/cwiseop.cpp
new file mode 100644
index 000000000..ca6e4211c
--- /dev/null
+++ b/test/cwiseop.cpp
@@ -0,0 +1,165 @@
+// 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) 2006-2008 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/.
+
+#define EIGEN2_SUPPORT
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+#include <functional>
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef max
+#undef max
+#endif
+
+using namespace std;
+
+template<typename Scalar> struct AddIfNull {
+ const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;}
+ enum { Cost = NumTraits<Scalar>::AddCost };
+};
+
+template<typename MatrixType> void cwiseops(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ mones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows);
+ VectorType vzero = VectorType::Zero(rows),
+ vones = VectorType::Ones(rows),
+ v3(rows);
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ // test Zero, Ones, Constant, and the set* variants
+ m3 = MatrixType::Constant(rows, cols, s1);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ {
+ VERIFY_IS_APPROX(mzero(i,j), Scalar(0));
+ VERIFY_IS_APPROX(mones(i,j), Scalar(1));
+ VERIFY_IS_APPROX(m3(i,j), s1);
+ }
+ VERIFY(mzero.isZero());
+ VERIFY(mones.isOnes());
+ VERIFY(m3.isConstant(s1));
+ VERIFY(identity.isIdentity());
+ VERIFY_IS_APPROX(m4.setConstant(s1), m3);
+ VERIFY_IS_APPROX(m4.setConstant(rows,cols,s1), m3);
+ VERIFY_IS_APPROX(m4.setZero(), mzero);
+ VERIFY_IS_APPROX(m4.setZero(rows,cols), mzero);
+ VERIFY_IS_APPROX(m4.setOnes(), mones);
+ VERIFY_IS_APPROX(m4.setOnes(rows,cols), mones);
+ m4.fill(s1);
+ VERIFY_IS_APPROX(m4, m3);
+
+ VERIFY_IS_APPROX(v3.setConstant(rows, s1), VectorType::Constant(rows,s1));
+ VERIFY_IS_APPROX(v3.setZero(rows), vzero);
+ VERIFY_IS_APPROX(v3.setOnes(rows), vones);
+
+ m2 = m2.template binaryExpr<AddIfNull<Scalar> >(mones);
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2());
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube());
+
+ VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1));
+ VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1));
+ m3 = m1; m3.cwise() += 1;
+ VERIFY_IS_APPROX(m1 + mones, m3);
+ m3 = m1; m3.cwise() -= 1;
+ VERIFY_IS_APPROX(m1 - mones, m3);
+
+ VERIFY_IS_APPROX(m2, m2.cwise() * mones);
+ VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1);
+ m3 = m1;
+ m3.cwise() *= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() * m2);
+
+ VERIFY_IS_APPROX(mones, m2.cwise()/m2);
+ if(!NumTraits<Scalar>::IsInteger)
+ {
+ VERIFY_IS_APPROX(m1.cwise() / m2, m1.cwise() * (m2.cwise().inverse()));
+ m3 = m1.cwise().abs().cwise().sqrt();
+ VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs());
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1);
+ VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse());
+ m3 = m1.cwise().abs();
+ VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt());
+
+// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
+ VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
+ m3 = m1;
+ m3.cwise() /= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() / m2);
+ }
+
+ // check min
+ VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) );
+ VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones );
+
+ // check max
+ VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) );
+ VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones );
+
+ VERIFY( (m1.cwise() == m1).all() );
+ VERIFY( (m1.cwise() != m2).any() );
+ VERIFY(!(m1.cwise() == (m1+mones)).any() );
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY( (m1.cwise() == m3).any() );
+ VERIFY( !(m1.cwise() == m3).all() );
+ }
+ VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() );
+ VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() );
+
+ VERIFY( (m1.cwise()<m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()<m1.unaryExpr(bind2nd(minus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()>m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).any() );
+}
+
+void test_cwiseop()
+{
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( cwiseops(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( cwiseops(Matrix4d()) );
+ CALL_SUBTEST_3( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_5( cwiseops(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( cwiseops(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/determinant.cpp b/test/determinant.cpp
new file mode 100644
index 000000000..e93f2f297
--- /dev/null
+++ b/test/determinant.cpp
@@ -0,0 +1,67 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void determinant(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Determinant.h
+ */
+ typedef typename MatrixType::Index Index;
+ Index size = m.rows();
+
+ MatrixType m1(size, size), m2(size, size);
+ m1.setRandom();
+ m2.setRandom();
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar x = internal::random<Scalar>();
+ VERIFY_IS_APPROX(MatrixType::Identity(size, size).determinant(), Scalar(1));
+ VERIFY_IS_APPROX((m1*m2).eval().determinant(), m1.determinant() * m2.determinant());
+ if(size==1) return;
+ Index i = internal::random<Index>(0, size-1);
+ Index j;
+ do {
+ j = internal::random<Index>(0, size-1);
+ } while(j==i);
+ m2 = m1;
+ m2.row(i).swap(m2.row(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ m2 = m1;
+ m2.col(i).swap(m2.col(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ VERIFY_IS_APPROX(m2.determinant(), m2.transpose().determinant());
+ VERIFY_IS_APPROX(internal::conj(m2.determinant()), m2.adjoint().determinant());
+ m2 = m1;
+ m2.row(i) += x*m2.row(j);
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant());
+ m2 = m1;
+ m2.row(i) *= x;
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant() * x);
+
+ // check empty matrix
+ VERIFY_IS_APPROX(m2.block(0,0,0,0).determinant(), Scalar(1));
+}
+
+void test_determinant()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( determinant(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( determinant(Matrix<double, 2, 2>()) );
+ CALL_SUBTEST_3( determinant(Matrix<double, 3, 3>()) );
+ CALL_SUBTEST_4( determinant(Matrix<double, 4, 4>()) );
+ CALL_SUBTEST_5( determinant(Matrix<std::complex<double>, 10, 10>()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_6( determinant(MatrixXd(s, s)) );
+ }
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/diagonal.cpp b/test/diagonal.cpp
new file mode 100644
index 000000000..95cd10372
--- /dev/null
+++ b/test/diagonal.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void diagonal(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+
+ //check diagonal()
+ VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal());
+ m2.diagonal() = 2 * m1.diagonal();
+ m2.diagonal()[0] *= 3;
+
+ if (rows>2)
+ {
+ enum {
+ N1 = MatrixType::RowsAtCompileTime>1 ? 1 : 0,
+ N2 = MatrixType::RowsAtCompileTime>2 ? -2 : 0
+ };
+
+ // check sub/super diagonal
+ if(m1.template diagonal<N1>().RowsAtCompileTime!=Dynamic)
+ {
+ VERIFY(m1.template diagonal<N1>().RowsAtCompileTime == m1.diagonal(N1).size());
+ }
+ if(m1.template diagonal<N2>().RowsAtCompileTime!=Dynamic)
+ {
+ VERIFY(m1.template diagonal<N2>().RowsAtCompileTime == m1.diagonal(N2).size());
+ }
+
+ m2.template diagonal<N1>() = 2 * m1.template diagonal<N1>();
+ VERIFY_IS_APPROX(m2.template diagonal<N1>(), static_cast<Scalar>(2) * m1.diagonal(N1));
+ m2.template diagonal<N1>()[0] *= 3;
+ VERIFY_IS_APPROX(m2.template diagonal<N1>()[0], static_cast<Scalar>(6) * m1.template diagonal<N1>()[0]);
+
+
+ m2.template diagonal<N2>() = 2 * m1.template diagonal<N2>();
+ m2.template diagonal<N2>()[0] *= 3;
+ VERIFY_IS_APPROX(m2.template diagonal<N2>()[0], static_cast<Scalar>(6) * m1.template diagonal<N2>()[0]);
+
+ m2.diagonal(N1) = 2 * m1.diagonal(N1);
+ VERIFY_IS_APPROX(m2.diagonal<N1>(), static_cast<Scalar>(2) * m1.diagonal(N1));
+ m2.diagonal(N1)[0] *= 3;
+ VERIFY_IS_APPROX(m2.diagonal(N1)[0], static_cast<Scalar>(6) * m1.diagonal(N1)[0]);
+
+ m2.diagonal(N2) = 2 * m1.diagonal(N2);
+ VERIFY_IS_APPROX(m2.diagonal<N2>(), static_cast<Scalar>(2) * m1.diagonal(N2));
+ m2.diagonal(N2)[0] *= 3;
+ VERIFY_IS_APPROX(m2.diagonal(N2)[0], static_cast<Scalar>(6) * m1.diagonal(N2)[0]);
+ }
+}
+
+void test_diagonal()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( diagonal(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( diagonal(Matrix<float, 4, 9>()) );
+ CALL_SUBTEST_1( diagonal(Matrix<float, 7, 3>()) );
+ CALL_SUBTEST_2( diagonal(Matrix4d()) );
+ CALL_SUBTEST_2( diagonal(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( diagonal(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( diagonal(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_1( diagonal(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_1( diagonal(Matrix<float,Dynamic,4>(3, 4)) );
+ }
+}
diff --git a/test/diagonalmatrices.cpp b/test/diagonalmatrices.cpp
new file mode 100644
index 000000000..3f5776dfc
--- /dev/null
+++ b/test/diagonalmatrices.cpp
@@ -0,0 +1,94 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#include "main.h"
+using namespace std;
+template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef Matrix<Scalar, Rows, 1> VectorType;
+ typedef Matrix<Scalar, 1, Cols> RowVectorType;
+ typedef Matrix<Scalar, Rows, Rows> SquareMatrixType;
+ typedef DiagonalMatrix<Scalar, Rows> LeftDiagonalMatrix;
+ typedef DiagonalMatrix<Scalar, Cols> RightDiagonalMatrix;
+ typedef Matrix<Scalar, Rows==Dynamic?Dynamic:2*Rows, Cols==Dynamic?Dynamic:2*Cols> BigMatrix;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows);
+ RowVectorType rv1 = RowVectorType::Random(cols),
+ rv2 = RowVectorType::Random(cols);
+ LeftDiagonalMatrix ldm1(v1), ldm2(v2);
+ RightDiagonalMatrix rdm1(rv1), rdm2(rv2);
+
+ SquareMatrixType sq_m1 (v1.asDiagonal());
+ VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
+ sq_m1 = v1.asDiagonal();
+ VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
+ SquareMatrixType sq_m2 = v1.asDiagonal();
+ VERIFY_IS_APPROX(sq_m1, sq_m2);
+
+ ldm1 = v1.asDiagonal();
+ LeftDiagonalMatrix ldm3(v1);
+ VERIFY_IS_APPROX(ldm1.diagonal(), ldm3.diagonal());
+ LeftDiagonalMatrix ldm4 = v1.asDiagonal();
+ VERIFY_IS_APPROX(ldm1.diagonal(), ldm4.diagonal());
+
+ sq_m1.block(0,0,rows,rows) = ldm1;
+ VERIFY_IS_APPROX(sq_m1, ldm1.toDenseMatrix());
+ sq_m1.transpose() = ldm1;
+ VERIFY_IS_APPROX(sq_m1, ldm1.toDenseMatrix());
+
+ Index i = internal::random<Index>(0, rows-1);
+ Index j = internal::random<Index>(0, cols-1);
+
+ VERIFY_IS_APPROX( ((ldm1 * m1)(i,j)) , ldm1.diagonal()(i) * m1(i,j) );
+ VERIFY_IS_APPROX( ((ldm1 * (m1+m2))(i,j)) , ldm1.diagonal()(i) * (m1+m2)(i,j) );
+ VERIFY_IS_APPROX( ((m1 * rdm1)(i,j)) , rdm1.diagonal()(j) * m1(i,j) );
+ VERIFY_IS_APPROX( ((v1.asDiagonal() * m1)(i,j)) , v1(i) * m1(i,j) );
+ VERIFY_IS_APPROX( ((m1 * rv1.asDiagonal())(i,j)) , rv1(j) * m1(i,j) );
+ VERIFY_IS_APPROX( (((v1+v2).asDiagonal() * m1)(i,j)) , (v1+v2)(i) * m1(i,j) );
+ VERIFY_IS_APPROX( (((v1+v2).asDiagonal() * (m1+m2))(i,j)) , (v1+v2)(i) * (m1+m2)(i,j) );
+ VERIFY_IS_APPROX( ((m1 * (rv1+rv2).asDiagonal())(i,j)) , (rv1+rv2)(j) * m1(i,j) );
+ VERIFY_IS_APPROX( (((m1+m2) * (rv1+rv2).asDiagonal())(i,j)) , (rv1+rv2)(j) * (m1+m2)(i,j) );
+
+ BigMatrix big;
+ big.setZero(2*rows, 2*cols);
+
+ big.block(i,j,rows,cols) = m1;
+ big.block(i,j,rows,cols) = v1.asDiagonal() * big.block(i,j,rows,cols);
+
+ VERIFY_IS_APPROX((big.block(i,j,rows,cols)) , v1.asDiagonal() * m1 );
+
+ big.block(i,j,rows,cols) = m1;
+ big.block(i,j,rows,cols) = big.block(i,j,rows,cols) * rv1.asDiagonal();
+ VERIFY_IS_APPROX((big.block(i,j,rows,cols)) , m1 * rv1.asDiagonal() );
+
+}
+
+void test_diagonalmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( diagonalmatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( diagonalmatrices(Matrix3f()) );
+ CALL_SUBTEST_3( diagonalmatrices(Matrix<double,3,3,RowMajor>()) );
+ CALL_SUBTEST_4( diagonalmatrices(Matrix4d()) );
+ CALL_SUBTEST_5( diagonalmatrices(Matrix<float,4,4,RowMajor>()) );
+ CALL_SUBTEST_6( diagonalmatrices(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_7( diagonalmatrices(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( diagonalmatrices(Matrix<double,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_9( diagonalmatrices(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/dontalign.cpp b/test/dontalign.cpp
new file mode 100644
index 000000000..4643cfed6
--- /dev/null
+++ b/test/dontalign.cpp
@@ -0,0 +1,63 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+#if defined EIGEN_TEST_PART_1 || defined EIGEN_TEST_PART_2 || defined EIGEN_TEST_PART_3 || defined EIGEN_TEST_PART_4
+#define EIGEN_DONT_ALIGN
+#elif defined EIGEN_TEST_PART_5 || defined EIGEN_TEST_PART_6 || defined EIGEN_TEST_PART_7 || defined EIGEN_TEST_PART_8
+#define EIGEN_DONT_ALIGN_STATICALLY
+#endif
+
+#include "main.h"
+#include <Eigen/Dense>
+
+template<typename MatrixType>
+void dontalign(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ SquareMatrixType square = SquareMatrixType::Random(rows,rows);
+ VectorType v = VectorType::Random(rows);
+
+ VERIFY_IS_APPROX(v, square * square.colPivHouseholderQr().solve(v));
+ square = square.inverse().eval();
+ a = square * a;
+ square = square*square;
+ v = square * v;
+ v = a.adjoint() * v;
+ VERIFY(square.determinant() != Scalar(0));
+
+ // bug 219: MapAligned() was giving an assert with EIGEN_DONT_ALIGN, because Map Flags were miscomputed
+ Scalar* array = internal::aligned_new<Scalar>(rows);
+ v = VectorType::MapAligned(array, rows);
+ internal::aligned_delete(array, rows);
+}
+
+void test_dontalign()
+{
+#if defined EIGEN_TEST_PART_1 || defined EIGEN_TEST_PART_5
+ dontalign(Matrix3d());
+ dontalign(Matrix4f());
+#elif defined EIGEN_TEST_PART_2 || defined EIGEN_TEST_PART_6
+ dontalign(Matrix3cd());
+ dontalign(Matrix4cf());
+#elif defined EIGEN_TEST_PART_3 || defined EIGEN_TEST_PART_7
+ dontalign(Matrix<float, 32, 32>());
+ dontalign(Matrix<std::complex<float>, 32, 32>());
+#elif defined EIGEN_TEST_PART_4 || defined EIGEN_TEST_PART_8
+ dontalign(MatrixXd(32, 32));
+ dontalign(MatrixXcf(32, 32));
+#endif
+}
diff --git a/test/dynalloc.cpp b/test/dynalloc.cpp
new file mode 100644
index 000000000..c7ccbffef
--- /dev/null
+++ b/test/dynalloc.cpp
@@ -0,0 +1,133 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+#if EIGEN_ALIGN
+#define ALIGNMENT 16
+#else
+#define ALIGNMENT 1
+#endif
+
+void check_handmade_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)internal::handmade_aligned_malloc(i);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ internal::handmade_aligned_free(p);
+ }
+}
+
+void check_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)internal::aligned_malloc(i);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ internal::aligned_free(p);
+ }
+}
+
+void check_aligned_new()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ float *p = internal::aligned_new<float>(i);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ internal::aligned_delete(p,i);
+ }
+}
+
+void check_aligned_stack_alloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ ei_declare_aligned_stack_constructed_variable(float,p,i,0);
+ VERIFY(size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ }
+}
+
+
+// test compilation with both a struct and a class...
+struct MyStruct
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+class MyClassA
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+template<typename T> void check_dynaligned()
+{
+ T* obj = new T;
+ VERIFY(size_t(obj)%ALIGNMENT==0);
+ delete obj;
+}
+
+void test_dynalloc()
+{
+ // low level dynamic memory allocation
+ CALL_SUBTEST(check_handmade_aligned_malloc());
+ CALL_SUBTEST(check_aligned_malloc());
+ CALL_SUBTEST(check_aligned_new());
+ CALL_SUBTEST(check_aligned_stack_alloc());
+
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ CALL_SUBTEST(check_dynaligned<Vector4f>() );
+ CALL_SUBTEST(check_dynaligned<Vector2d>() );
+ CALL_SUBTEST(check_dynaligned<Matrix4f>() );
+ CALL_SUBTEST(check_dynaligned<Vector4d>() );
+ CALL_SUBTEST(check_dynaligned<Vector4i>() );
+ }
+
+ // check static allocation, who knows ?
+ #if EIGEN_ALIGN_STATICALLY
+ {
+ MyStruct foo0; VERIFY(size_t(foo0.avec.data())%ALIGNMENT==0);
+ MyClassA fooA; VERIFY(size_t(fooA.avec.data())%ALIGNMENT==0);
+ }
+
+ // dynamic allocation, single object
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct(); VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA(); VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete foo0;
+ delete fooA;
+ }
+
+ // dynamic allocation, array
+ const int N = 10;
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct[N]; VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA[N]; VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete[] foo0;
+ delete[] fooA;
+ }
+ #endif
+
+}
diff --git a/test/eigen2/CMakeLists.txt b/test/eigen2/CMakeLists.txt
new file mode 100644
index 000000000..84931e037
--- /dev/null
+++ b/test/eigen2/CMakeLists.txt
@@ -0,0 +1,60 @@
+add_custom_target(eigen2_buildtests)
+add_custom_target(eigen2_check COMMAND "ctest -R eigen2")
+add_dependencies(eigen2_check eigen2_buildtests)
+add_dependencies(buildtests eigen2_buildtests)
+
+add_definitions("-DEIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API")
+
+ei_add_test(eigen2_meta)
+ei_add_test(eigen2_sizeof)
+ei_add_test(eigen2_dynalloc)
+ei_add_test(eigen2_nomalloc)
+#ei_add_test(eigen2_first_aligned)
+ei_add_test(eigen2_mixingtypes)
+#ei_add_test(eigen2_packetmath)
+ei_add_test(eigen2_unalignedassert)
+#ei_add_test(eigen2_vectorization_logic)
+ei_add_test(eigen2_basicstuff)
+ei_add_test(eigen2_linearstructure)
+ei_add_test(eigen2_cwiseop)
+ei_add_test(eigen2_sum)
+ei_add_test(eigen2_product_small)
+ei_add_test(eigen2_product_large ${EI_OFLAG})
+ei_add_test(eigen2_adjoint)
+ei_add_test(eigen2_submatrices)
+ei_add_test(eigen2_miscmatrices)
+ei_add_test(eigen2_commainitializer)
+ei_add_test(eigen2_smallvectors)
+ei_add_test(eigen2_map)
+ei_add_test(eigen2_array)
+ei_add_test(eigen2_triangular)
+ei_add_test(eigen2_cholesky " " "${GSL_LIBRARIES}")
+ei_add_test(eigen2_lu ${EI_OFLAG})
+ei_add_test(eigen2_determinant ${EI_OFLAG})
+ei_add_test(eigen2_inverse)
+ei_add_test(eigen2_qr)
+ei_add_test(eigen2_eigensolver " " "${GSL_LIBRARIES}")
+ei_add_test(eigen2_svd)
+ei_add_test(eigen2_geometry)
+ei_add_test(eigen2_geometry_with_eigen2_prefix)
+ei_add_test(eigen2_hyperplane)
+ei_add_test(eigen2_parametrizedline)
+ei_add_test(eigen2_alignedbox)
+ei_add_test(eigen2_regression)
+ei_add_test(eigen2_stdvector)
+ei_add_test(eigen2_newstdvector)
+if(QT4_FOUND)
+ ei_add_test(eigen2_qtvector " " "${QT_QTCORE_LIBRARY}")
+endif(QT4_FOUND)
+# no support for eigen2 sparse module
+# if(NOT EIGEN_DEFAULT_TO_ROW_MAJOR)
+# ei_add_test(eigen2_sparse_vector)
+# ei_add_test(eigen2_sparse_basic)
+# ei_add_test(eigen2_sparse_solvers " " "${SPARSE_LIBS}")
+# ei_add_test(eigen2_sparse_product)
+# endif()
+ei_add_test(eigen2_swap)
+ei_add_test(eigen2_visitor)
+ei_add_test(eigen2_bug_132)
+
+ei_add_test(eigen2_prec_inverse_4x4 ${EI_OFLAG})
diff --git a/test/eigen2/eigen2_adjoint.cpp b/test/eigen2/eigen2_adjoint.cpp
new file mode 100644
index 000000000..8ec9c9202
--- /dev/null
+++ b/test/eigen2/eigen2_adjoint.cpp
@@ -0,0 +1,101 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void adjoint(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Transpose.h Conjugate.h Dot.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ int rows = m.rows();
+ int cols = m.cols();
+
+ RealScalar largerEps = test_precision<RealScalar>();
+ if (ei_is_same_type<RealScalar,float>::ret)
+ largerEps = RealScalar(1e-3f);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = SquareMatrixType::Identity(rows, rows),
+ square = SquareMatrixType::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = ei_random<Scalar>(),
+ s2 = ei_random<Scalar>();
+
+ // check basic compatibility of adjoint, transpose, conjugate
+ VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1);
+ VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(), m1);
+
+ // check multiplicative behavior
+ VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(), m2.adjoint() * m1);
+ VERIFY_IS_APPROX((s1 * m1).adjoint(), ei_conj(s1) * m1.adjoint());
+
+ // check basic properties of dot, norm, norm2
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ VERIFY(ei_isApprox((s1 * v1 + s2 * v2).eigen2_dot(v3), s1 * v1.eigen2_dot(v3) + s2 * v2.eigen2_dot(v3), largerEps));
+ VERIFY(ei_isApprox(v3.eigen2_dot(s1 * v1 + s2 * v2), ei_conj(s1)*v3.eigen2_dot(v1)+ei_conj(s2)*v3.eigen2_dot(v2), largerEps));
+ VERIFY_IS_APPROX(ei_conj(v1.eigen2_dot(v2)), v2.eigen2_dot(v1));
+ VERIFY_IS_APPROX(ei_real(v1.eigen2_dot(v1)), v1.squaredNorm());
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm());
+ VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(vzero.eigen2_dot(v1)), static_cast<RealScalar>(1));
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast<RealScalar>(1));
+
+ // check compatibility of dot and adjoint
+ VERIFY(ei_isApprox(v1.eigen2_dot(square * v2), (square.adjoint() * v1).eigen2_dot(v2), largerEps));
+
+ // like in testBasicStuff, test operator() to check const-qualification
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+ VERIFY_IS_APPROX(m1.conjugate()(r,c), ei_conj(m1(r,c)));
+ VERIFY_IS_APPROX(m1.adjoint()(c,r), ei_conj(m1(r,c)));
+
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ {
+ // check that Random().normalized() works: tricky as the random xpr must be evaluated by
+ // normalized() in order to produce a consistent result.
+ VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1));
+ }
+
+ // check inplace transpose
+ m3 = m1;
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1.transpose());
+ m3.transposeInPlace();
+ VERIFY_IS_APPROX(m3,m1);
+
+}
+
+void test_eigen2_adjoint()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( adjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( adjoint(Matrix3d()) );
+ CALL_SUBTEST_3( adjoint(Matrix4f()) );
+ CALL_SUBTEST_4( adjoint(MatrixXcf(4, 4)) );
+ CALL_SUBTEST_5( adjoint(MatrixXi(8, 12)) );
+ CALL_SUBTEST_6( adjoint(MatrixXf(21, 21)) );
+ }
+ // test a large matrix only once
+ CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
+}
+
diff --git a/test/eigen2/eigen2_alignedbox.cpp b/test/eigen2/eigen2_alignedbox.cpp
new file mode 100644
index 000000000..35043b958
--- /dev/null
+++ b/test/eigen2/eigen2_alignedbox.cpp
@@ -0,0 +1,60 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename BoxType> void alignedbox(const BoxType& _box)
+{
+ /* this test covers the following files:
+ AlignedBox.h
+ */
+
+ const int dim = _box.dim();
+ typedef typename BoxType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+ RealScalar s1 = ei_random<RealScalar>(0,1);
+
+ BoxType b0(dim);
+ BoxType b1(VectorType::Random(dim),VectorType::Random(dim));
+ BoxType b2;
+
+ b0.extend(p0);
+ b0.extend(p1);
+ VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));
+ VERIFY(!b0.contains(p0 + (1+s1)*(p1-p0)));
+
+ (b2 = b0).extend(b1);
+ VERIFY(b2.contains(b0));
+ VERIFY(b2.contains(b1));
+ VERIFY_IS_APPROX(b2.clamp(b0), b0);
+
+ // casting
+ const int Dim = BoxType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ AlignedBox<OtherScalar,Dim> hp1f = b0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),b0);
+ AlignedBox<Scalar,Dim> hp1d = b0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),b0);
+}
+
+void test_eigen2_alignedbox()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( alignedbox(AlignedBox<float,2>()) );
+ CALL_SUBTEST_2( alignedbox(AlignedBox<float,3>()) );
+ CALL_SUBTEST_3( alignedbox(AlignedBox<double,4>()) );
+ }
+}
diff --git a/test/eigen2/eigen2_array.cpp b/test/eigen2/eigen2_array.cpp
new file mode 100644
index 000000000..c1ff40ce7
--- /dev/null
+++ b/test/eigen2/eigen2_array.cpp
@@ -0,0 +1,142 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/Array>
+
+template<typename MatrixType> void array(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Array.cpp
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = ei_random<Scalar>(),
+ s2 = ei_random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1.cwise() + s1, s1 + m1.cwise());
+ VERIFY_IS_APPROX(m1.cwise() + s1, MatrixType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX((m1*Scalar(2)).cwise() - s2, (m1+m1) - MatrixType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3.cwise() += s2;
+ VERIFY_IS_APPROX(m3, m1.cwise() + s2);
+ m3 = m1;
+ m3.cwise() -= s1;
+ VERIFY_IS_APPROX(m3, m1.cwise() - s1);
+
+ // reductions
+ VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
+ if (!ei_isApprox(m1.sum(), (m1+m2).sum()))
+ VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
+ VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));
+}
+
+template<typename MatrixType> void comparisons(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ VERIFY(((m1.cwise() + Scalar(1)).cwise() > m1).all());
+ VERIFY(((m1.cwise() - Scalar(1)).cwise() < m1).all());
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY(! (m1.cwise() < m3).all() );
+ VERIFY(! (m1.cwise() > m3).all() );
+ }
+
+ // comparisons to scalar
+ VERIFY( (m1.cwise() != (m1(r,c)+1) ).any() );
+ VERIFY( (m1.cwise() > (m1(r,c)-1) ).any() );
+ VERIFY( (m1.cwise() < (m1(r,c)+1) ).any() );
+ VERIFY( (m1.cwise() == m1(r,c) ).any() );
+
+ // test Select
+ VERIFY_IS_APPROX( (m1.cwise()<m2).select(m1,m2), m1.cwise().min(m2) );
+ VERIFY_IS_APPROX( (m1.cwise()>m2).select(m1,m2), m1.cwise().max(m2) );
+ Scalar mid = (m1.cwise().abs().minCoeff() + m1.cwise().abs().maxCoeff())/Scalar(2);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ m3(i,j) = ei_abs(m1(i,j))<mid ? 0 : m1(i,j);
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()<MatrixType::Constant(rows,cols,mid))
+ .select(MatrixType::Zero(rows,cols),m1), m3);
+ // shorter versions:
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()<MatrixType::Constant(rows,cols,mid))
+ .select(0,m1), m3);
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()>=MatrixType::Constant(rows,cols,mid))
+ .select(m1,0), m3);
+ // even shorter version:
+ VERIFY_IS_APPROX( (m1.cwise().abs().cwise()<mid).select(0,m1), m3);
+
+ // count
+ VERIFY(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).count() == rows*cols);
+ VERIFY_IS_APPROX(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).colwise().count().template cast<int>(), RowVectorXi::Constant(cols,rows));
+ VERIFY_IS_APPROX(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).rowwise().count().template cast<int>(), VectorXi::Constant(rows, cols));
+}
+
+template<typename VectorType> void lpNorm(const VectorType& v)
+{
+ VectorType u = VectorType::Random(v.size());
+
+ VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwise().abs().maxCoeff());
+ VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwise().abs().sum());
+ VERIFY_IS_APPROX(u.template lpNorm<2>(), ei_sqrt(u.cwise().abs().cwise().square().sum()));
+ VERIFY_IS_APPROX(ei_pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.cwise().abs().cwise().pow(5).sum());
+}
+
+void test_eigen2_array()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( array(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( array(Matrix2f()) );
+ CALL_SUBTEST_3( array(Matrix4d()) );
+ CALL_SUBTEST_4( array(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_5( array(MatrixXf(8, 12)) );
+ CALL_SUBTEST_6( array(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( comparisons(Matrix2f()) );
+ CALL_SUBTEST_3( comparisons(Matrix4d()) );
+ CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) );
+ CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( lpNorm(Vector2f()) );
+ CALL_SUBTEST_3( lpNorm(Vector3d()) );
+ CALL_SUBTEST_4( lpNorm(Vector4f()) );
+ CALL_SUBTEST_5( lpNorm(VectorXf(16)) );
+ CALL_SUBTEST_7( lpNorm(VectorXcd(10)) );
+ }
+}
diff --git a/test/eigen2/eigen2_basicstuff.cpp b/test/eigen2/eigen2_basicstuff.cpp
new file mode 100644
index 000000000..4fa16d5ae
--- /dev/null
+++ b/test/eigen2/eigen2_basicstuff.cpp
@@ -0,0 +1,108 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void basicStuff(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar x = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ m1.coeffRef(r,c) = x;
+ VERIFY_IS_APPROX(x, m1.coeff(r,c));
+ m1(r,c) = x;
+ VERIFY_IS_APPROX(x, m1(r,c));
+ v1.coeffRef(r) = x;
+ VERIFY_IS_APPROX(x, v1.coeff(r));
+ v1(r) = x;
+ VERIFY_IS_APPROX(x, v1(r));
+ v1[r] = x;
+ VERIFY_IS_APPROX(x, v1[r]);
+
+ VERIFY_IS_APPROX( v1, v1);
+ VERIFY_IS_NOT_APPROX( v1, 2*v1);
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1.norm());
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1);
+ VERIFY_IS_APPROX( vzero, v1-v1);
+ VERIFY_IS_APPROX( m1, m1);
+ VERIFY_IS_NOT_APPROX( m1, 2*m1);
+ VERIFY_IS_MUCH_SMALLER_THAN( mzero, m1);
+ VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1);
+ VERIFY_IS_APPROX( mzero, m1-m1);
+
+ // always test operator() on each read-only expression class,
+ // in order to check const-qualifiers.
+ // indeed, if an expression class (here Zero) is meant to be read-only,
+ // hence has no _write() method, the corresponding MatrixBase method (here zero())
+ // should return a const-qualified object so that it is the const-qualified
+ // operator() that gets called, which in turn calls _read().
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1));
+
+ // now test copying a row-vector into a (column-)vector and conversely.
+ square.col(r) = square.row(r).eval();
+ Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
+ rv = square.row(r);
+ cv = square.col(r);
+ VERIFY_IS_APPROX(rv, cv.transpose());
+
+ if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
+ {
+ VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1)));
+ }
+
+ VERIFY_IS_APPROX(m3 = m1,m1);
+ MatrixType m4;
+ VERIFY_IS_APPROX(m4 = m1,m1);
+
+ // test swap
+ m3 = m1;
+ m1.swap(m2);
+ VERIFY_IS_APPROX(m3, m2);
+ if(rows*cols>=3)
+ {
+ VERIFY_IS_NOT_APPROX(m3, m1);
+ }
+}
+
+void test_eigen2_basicstuff()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( basicStuff(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( basicStuff(Matrix4d()) );
+ CALL_SUBTEST_3( basicStuff(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( basicStuff(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( basicStuff(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_6( basicStuff(Matrix<float, 100, 100>()) );
+ CALL_SUBTEST_7( basicStuff(Matrix<long double,Dynamic,Dynamic>(10,10)) );
+ }
+}
diff --git a/test/eigen2/eigen2_bug_132.cpp b/test/eigen2/eigen2_bug_132.cpp
new file mode 100644
index 000000000..7fe3610ce
--- /dev/null
+++ b/test/eigen2/eigen2_bug_132.cpp
@@ -0,0 +1,26 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2010 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/.
+
+#include "main.h"
+
+void test_eigen2_bug_132() {
+ int size = 100;
+ MatrixXd A(size, size);
+ VectorXd b(size), c(size);
+ {
+ VectorXd y = A.transpose() * (b-c); // bug 132: infinite recursion in coeffRef
+ VectorXd z = (b-c).transpose() * A; // bug 132: infinite recursion in coeffRef
+ }
+
+ // the following ones weren't failing, but let's include them for completeness:
+ {
+ VectorXd y = A * (b-c);
+ VectorXd z = (b-c).transpose() * A.transpose();
+ }
+}
diff --git a/test/eigen2/eigen2_cholesky.cpp b/test/eigen2/eigen2_cholesky.cpp
new file mode 100644
index 000000000..9c4b6f561
--- /dev/null
+++ b/test/eigen2/eigen2_cholesky.cpp
@@ -0,0 +1,113 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#define EIGEN_NO_ASSERTION_CHECKING
+#include "main.h"
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+
+#ifdef HAS_GSL
+#include "gsl_helper.h"
+#endif
+
+template<typename MatrixType> void cholesky(const MatrixType& m)
+{
+ /* this test covers the following files:
+ LLT.h LDLT.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ MatrixType a0 = MatrixType::Random(rows,cols);
+ VectorType vecB = VectorType::Random(rows), vecX(rows);
+ MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
+ SquareMatrixType symm = a0 * a0.adjoint();
+ // let's make sure the matrix is not singular or near singular
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ symm += a1 * a1.adjoint();
+
+ #ifdef HAS_GSL
+ if (ei_is_same_type<RealScalar,double>::ret)
+ {
+ typedef GslTraits<Scalar> Gsl;
+ typename Gsl::Matrix gMatA=0, gSymm=0;
+ typename Gsl::Vector gVecB=0, gVecX=0;
+ convert<MatrixType>(symm, gSymm);
+ convert<MatrixType>(symm, gMatA);
+ convert<VectorType>(vecB, gVecB);
+ convert<VectorType>(vecB, gVecX);
+ Gsl::cholesky(gMatA);
+ Gsl::cholesky_solve(gMatA, gVecB, gVecX);
+ VectorType vecX(rows), _vecX, _vecB;
+ convert(gVecX, _vecX);
+ symm.llt().solve(vecB, &vecX);
+ Gsl::prod(gSymm, gVecX, gVecB);
+ convert(gVecB, _vecB);
+ // test gsl itself !
+ VERIFY_IS_APPROX(vecB, _vecB);
+ VERIFY_IS_APPROX(vecX, _vecX);
+
+ Gsl::free(gMatA);
+ Gsl::free(gSymm);
+ Gsl::free(gVecB);
+ Gsl::free(gVecX);
+ }
+ #endif
+
+ {
+ LDLT<SquareMatrixType> ldlt(symm);
+ VERIFY(ldlt.isPositiveDefinite());
+ // in eigen3, LDLT is pivoting
+ //VERIFY_IS_APPROX(symm, ldlt.matrixL() * ldlt.vectorD().asDiagonal() * ldlt.matrixL().adjoint());
+ ldlt.solve(vecB, &vecX);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ ldlt.solve(matB, &matX);
+ VERIFY_IS_APPROX(symm * matX, matB);
+ }
+
+ {
+ LLT<SquareMatrixType> chol(symm);
+ VERIFY(chol.isPositiveDefinite());
+ VERIFY_IS_APPROX(symm, chol.matrixL() * chol.matrixL().adjoint());
+ chol.solve(vecB, &vecX);
+ VERIFY_IS_APPROX(symm * vecX, vecB);
+ chol.solve(matB, &matX);
+ VERIFY_IS_APPROX(symm * matX, matB);
+ }
+
+#if 0 // cholesky is not rank-revealing anyway
+ // test isPositiveDefinite on non definite matrix
+ if (rows>4)
+ {
+ SquareMatrixType symm = a0.block(0,0,rows,cols-4) * a0.block(0,0,rows,cols-4).adjoint();
+ LLT<SquareMatrixType> chol(symm);
+ VERIFY(!chol.isPositiveDefinite());
+ LDLT<SquareMatrixType> cholnosqrt(symm);
+ VERIFY(!cholnosqrt.isPositiveDefinite());
+ }
+#endif
+}
+
+void test_eigen2_cholesky()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( cholesky(Matrix2d()) );
+ CALL_SUBTEST_3( cholesky(Matrix3f()) );
+ CALL_SUBTEST_4( cholesky(Matrix4d()) );
+ CALL_SUBTEST_5( cholesky(MatrixXcd(7,7)) );
+ CALL_SUBTEST_6( cholesky(MatrixXf(17,17)) );
+ CALL_SUBTEST_7( cholesky(MatrixXd(33,33)) );
+ }
+}
diff --git a/test/eigen2/eigen2_commainitializer.cpp b/test/eigen2/eigen2_commainitializer.cpp
new file mode 100644
index 000000000..e0f901e0b
--- /dev/null
+++ b/test/eigen2/eigen2_commainitializer.cpp
@@ -0,0 +1,46 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+
+void test_eigen2_commainitializer()
+{
+ Matrix3d m3;
+ Matrix4d m4;
+
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8) );
+
+ #ifndef _MSC_VER
+ VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) );
+ #endif
+
+ double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ Matrix3d ref = Map<Matrix<double,3,3,RowMajor> >(data);
+
+ m3 = Matrix3d::Random();
+ m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+ VERIFY_IS_APPROX(m3, ref );
+
+ Vector3d vec[3];
+ vec[0] << 1, 4, 7;
+ vec[1] << 2, 5, 8;
+ vec[2] << 3, 6, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0], vec[1], vec[2];
+ VERIFY_IS_APPROX(m3, ref);
+
+ vec[0] << 1, 2, 3;
+ vec[1] << 4, 5, 6;
+ vec[2] << 7, 8, 9;
+ m3 = Matrix3d::Random();
+ m3 << vec[0].transpose(),
+ 4, 5, 6,
+ vec[2].transpose();
+ VERIFY_IS_APPROX(m3, ref);
+}
diff --git a/test/eigen2/eigen2_cwiseop.cpp b/test/eigen2/eigen2_cwiseop.cpp
new file mode 100644
index 000000000..4391d19b4
--- /dev/null
+++ b/test/eigen2/eigen2_cwiseop.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+#include <functional>
+#include <Eigen/Array>
+
+using namespace std;
+
+template<typename Scalar> struct AddIfNull {
+ const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;}
+ enum { Cost = NumTraits<Scalar>::AddCost };
+};
+
+template<typename MatrixType> void cwiseops(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ mones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows),
+ vones = VectorType::Ones(rows),
+ v3(rows);
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ // test Zero, Ones, Constant, and the set* variants
+ m3 = MatrixType::Constant(rows, cols, s1);
+ for (int j=0; j<cols; ++j)
+ for (int i=0; i<rows; ++i)
+ {
+ VERIFY_IS_APPROX(mzero(i,j), Scalar(0));
+ VERIFY_IS_APPROX(mones(i,j), Scalar(1));
+ VERIFY_IS_APPROX(m3(i,j), s1);
+ }
+ VERIFY(mzero.isZero());
+ VERIFY(mones.isOnes());
+ VERIFY(m3.isConstant(s1));
+ VERIFY(identity.isIdentity());
+ VERIFY_IS_APPROX(m4.setConstant(s1), m3);
+ VERIFY_IS_APPROX(m4.setConstant(rows,cols,s1), m3);
+ VERIFY_IS_APPROX(m4.setZero(), mzero);
+ VERIFY_IS_APPROX(m4.setZero(rows,cols), mzero);
+ VERIFY_IS_APPROX(m4.setOnes(), mones);
+ VERIFY_IS_APPROX(m4.setOnes(rows,cols), mones);
+ m4.fill(s1);
+ VERIFY_IS_APPROX(m4, m3);
+
+ VERIFY_IS_APPROX(v3.setConstant(rows, s1), VectorType::Constant(rows,s1));
+ VERIFY_IS_APPROX(v3.setZero(rows), vzero);
+ VERIFY_IS_APPROX(v3.setOnes(rows), vones);
+
+ m2 = m2.template binaryExpr<AddIfNull<Scalar> >(mones);
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2());
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube());
+
+ VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1));
+ VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1));
+ m3 = m1; m3.cwise() += 1;
+ VERIFY_IS_APPROX(m1 + mones, m3);
+ m3 = m1; m3.cwise() -= 1;
+ VERIFY_IS_APPROX(m1 - mones, m3);
+
+ VERIFY_IS_APPROX(m2, m2.cwise() * mones);
+ VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1);
+ m3 = m1;
+ m3.cwise() *= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() * m2);
+
+ VERIFY_IS_APPROX(mones, m2.cwise()/m2);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ {
+ VERIFY_IS_APPROX(m1.cwise() / m2, m1.cwise() * (m2.cwise().inverse()));
+ m3 = m1.cwise().abs().cwise().sqrt();
+ VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs());
+ VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs());
+
+ VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
+ m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1);
+ VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse());
+ m3 = m1.cwise().abs();
+ VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt());
+
+// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
+ VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
+ m3 = m1;
+ m3.cwise() /= m2;
+ VERIFY_IS_APPROX(m3, m1.cwise() / m2);
+ }
+
+ // check min
+ VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) );
+ VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones );
+
+ // check max
+ VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) );
+ VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 );
+ VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones );
+
+ VERIFY( (m1.cwise() == m1).all() );
+ VERIFY( (m1.cwise() != m2).any() );
+ VERIFY(!(m1.cwise() == (m1+mones)).any() );
+ if (rows*cols>1)
+ {
+ m3 = m1;
+ m3(r,c) += 1;
+ VERIFY( (m1.cwise() == m3).any() );
+ VERIFY( !(m1.cwise() == m3).all() );
+ }
+ VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() );
+ VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() );
+ VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() );
+
+ VERIFY( (m1.cwise()<m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()<m1.unaryExpr(bind2nd(minus<Scalar>(), Scalar(1)))).all() );
+ VERIFY( !(m1.cwise()>m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).any() );
+}
+
+void test_eigen2_cwiseop()
+{
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( cwiseops(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( cwiseops(Matrix4d()) );
+ CALL_SUBTEST_3( cwiseops(MatrixXf(3, 3)) );
+ CALL_SUBTEST_3( cwiseops(MatrixXf(22, 22)) );
+ CALL_SUBTEST_4( cwiseops(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( cwiseops(MatrixXd(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_determinant.cpp b/test/eigen2/eigen2_determinant.cpp
new file mode 100644
index 000000000..c7b4ad053
--- /dev/null
+++ b/test/eigen2/eigen2_determinant.cpp
@@ -0,0 +1,61 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void determinant(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Determinant.h
+ */
+ int size = m.rows();
+
+ MatrixType m1(size, size), m2(size, size);
+ m1.setRandom();
+ m2.setRandom();
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar x = ei_random<Scalar>();
+ VERIFY_IS_APPROX(MatrixType::Identity(size, size).determinant(), Scalar(1));
+ VERIFY_IS_APPROX((m1*m2).determinant(), m1.determinant() * m2.determinant());
+ if(size==1) return;
+ int i = ei_random<int>(0, size-1);
+ int j;
+ do {
+ j = ei_random<int>(0, size-1);
+ } while(j==i);
+ m2 = m1;
+ m2.row(i).swap(m2.row(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ m2 = m1;
+ m2.col(i).swap(m2.col(j));
+ VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
+ VERIFY_IS_APPROX(m2.determinant(), m2.transpose().determinant());
+ VERIFY_IS_APPROX(ei_conj(m2.determinant()), m2.adjoint().determinant());
+ m2 = m1;
+ m2.row(i) += x*m2.row(j);
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant());
+ m2 = m1;
+ m2.row(i) *= x;
+ VERIFY_IS_APPROX(m2.determinant(), m1.determinant() * x);
+}
+
+void test_eigen2_determinant()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( determinant(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( determinant(Matrix<double, 2, 2>()) );
+ CALL_SUBTEST_3( determinant(Matrix<double, 3, 3>()) );
+ CALL_SUBTEST_4( determinant(Matrix<double, 4, 4>()) );
+ CALL_SUBTEST_5( determinant(Matrix<std::complex<double>, 10, 10>()) );
+ CALL_SUBTEST_6( determinant(MatrixXd(20, 20)) );
+ }
+ CALL_SUBTEST_6( determinant(MatrixXd(200, 200)) );
+}
diff --git a/test/eigen2/eigen2_dynalloc.cpp b/test/eigen2/eigen2_dynalloc.cpp
new file mode 100644
index 000000000..1891a9e33
--- /dev/null
+++ b/test/eigen2/eigen2_dynalloc.cpp
@@ -0,0 +1,131 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+#define ALIGNMENT 16
+#else
+#define ALIGNMENT 1
+#endif
+
+void check_handmade_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)ei_handmade_aligned_malloc(i);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ ei_handmade_aligned_free(p);
+ }
+}
+
+void check_aligned_malloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ char *p = (char*)ei_aligned_malloc(i);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ ei_aligned_free(p);
+ }
+}
+
+void check_aligned_new()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ float *p = ei_aligned_new<float>(i);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ ei_aligned_delete(p,i);
+ }
+}
+
+void check_aligned_stack_alloc()
+{
+ for(int i = 1; i < 1000; i++)
+ {
+ ei_declare_aligned_stack_constructed_variable(float, p, i, 0);
+ VERIFY(std::size_t(p)%ALIGNMENT==0);
+ // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
+ for(int j = 0; j < i; j++) p[j]=0;
+ }
+}
+
+
+// test compilation with both a struct and a class...
+struct MyStruct
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+class MyClassA
+{
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ char dummychar;
+ Vector4f avec;
+};
+
+template<typename T> void check_dynaligned()
+{
+ T* obj = new T;
+ VERIFY(std::size_t(obj)%ALIGNMENT==0);
+ delete obj;
+}
+
+void test_eigen2_dynalloc()
+{
+ // low level dynamic memory allocation
+ CALL_SUBTEST(check_handmade_aligned_malloc());
+ CALL_SUBTEST(check_aligned_malloc());
+ CALL_SUBTEST(check_aligned_new());
+ CALL_SUBTEST(check_aligned_stack_alloc());
+
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ CALL_SUBTEST( check_dynaligned<Vector4f>() );
+ CALL_SUBTEST( check_dynaligned<Vector2d>() );
+ CALL_SUBTEST( check_dynaligned<Matrix4f>() );
+ CALL_SUBTEST( check_dynaligned<Vector4d>() );
+ CALL_SUBTEST( check_dynaligned<Vector4i>() );
+ }
+
+ // check static allocation, who knows ?
+ {
+ MyStruct foo0; VERIFY(std::size_t(foo0.avec.data())%ALIGNMENT==0);
+ MyClassA fooA; VERIFY(std::size_t(fooA.avec.data())%ALIGNMENT==0);
+ }
+
+ // dynamic allocation, single object
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct(); VERIFY(std::size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA(); VERIFY(std::size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete foo0;
+ delete fooA;
+ }
+
+ // dynamic allocation, array
+ const int N = 10;
+ for (int i=0; i<g_repeat*100; ++i)
+ {
+ MyStruct *foo0 = new MyStruct[N]; VERIFY(std::size_t(foo0->avec.data())%ALIGNMENT==0);
+ MyClassA *fooA = new MyClassA[N]; VERIFY(std::size_t(fooA->avec.data())%ALIGNMENT==0);
+ delete[] foo0;
+ delete[] fooA;
+ }
+
+}
diff --git a/test/eigen2/eigen2_eigensolver.cpp b/test/eigen2/eigen2_eigensolver.cpp
new file mode 100644
index 000000000..48b4ace43
--- /dev/null
+++ b/test/eigen2/eigen2_eigensolver.cpp
@@ -0,0 +1,146 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+#ifdef HAS_GSL
+#include "gsl_helper.h"
+#endif
+
+template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
+{
+ /* this test covers the following files:
+ EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+
+ MatrixType b = MatrixType::Random(rows,cols);
+ MatrixType b1 = MatrixType::Random(rows,cols);
+ MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
+
+ SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
+ // generalized eigen pb
+ SelfAdjointEigenSolver<MatrixType> eiSymmGen(symmA, symmB);
+
+ #ifdef HAS_GSL
+ if (ei_is_same_type<RealScalar,double>::ret)
+ {
+ typedef GslTraits<Scalar> Gsl;
+ typename Gsl::Matrix gEvec=0, gSymmA=0, gSymmB=0;
+ typename GslTraits<RealScalar>::Vector gEval=0;
+ RealVectorType _eval;
+ MatrixType _evec;
+ convert<MatrixType>(symmA, gSymmA);
+ convert<MatrixType>(symmB, gSymmB);
+ convert<MatrixType>(symmA, gEvec);
+ gEval = GslTraits<RealScalar>::createVector(rows);
+
+ Gsl::eigen_symm(gSymmA, gEval, gEvec);
+ convert(gEval, _eval);
+ convert(gEvec, _evec);
+
+ // test gsl itself !
+ VERIFY((symmA * _evec).isApprox(_evec * _eval.asDiagonal(), largerEps));
+
+ // compare with eigen
+ VERIFY_IS_APPROX(_eval, eiSymm.eigenvalues());
+ VERIFY_IS_APPROX(_evec.cwise().abs(), eiSymm.eigenvectors().cwise().abs());
+
+ // generalized pb
+ Gsl::eigen_symm_gen(gSymmA, gSymmB, gEval, gEvec);
+ convert(gEval, _eval);
+ convert(gEvec, _evec);
+ // test GSL itself:
+ VERIFY((symmA * _evec).isApprox(symmB * (_evec * _eval.asDiagonal()), largerEps));
+
+ // compare with eigen
+ MatrixType normalized_eivec = eiSymmGen.eigenvectors()*eiSymmGen.eigenvectors().colwise().norm().asDiagonal().inverse();
+ VERIFY_IS_APPROX(_eval, eiSymmGen.eigenvalues());
+ VERIFY_IS_APPROX(_evec.cwiseAbs(), normalized_eivec.cwiseAbs());
+
+ Gsl::free(gSymmA);
+ Gsl::free(gSymmB);
+ GslTraits<RealScalar>::free(gEval);
+ Gsl::free(gEvec);
+ }
+ #endif
+
+ VERIFY((symmA * eiSymm.eigenvectors()).isApprox(
+ eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps));
+
+ // generalized eigen problem Ax = lBx
+ VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox(
+ symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+ MatrixType sqrtSymmA = eiSymm.operatorSqrt();
+ VERIFY_IS_APPROX(symmA, sqrtSymmA*sqrtSymmA);
+ VERIFY_IS_APPROX(sqrtSymmA, symmA*eiSymm.operatorInverseSqrt());
+}
+
+template<typename MatrixType> void eigensolver(const MatrixType& m)
+{
+ /* this test covers the following files:
+ EigenSolver.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ // RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+
+ EigenSolver<MatrixType> ei0(symmA);
+ VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX((symmA.template cast<Complex>()) * (ei0.pseudoEigenvectors().template cast<Complex>()),
+ (ei0.pseudoEigenvectors().template cast<Complex>()) * (ei0.eigenvalues().asDiagonal()));
+
+ EigenSolver<MatrixType> ei1(a);
+ VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX(a.template cast<Complex>() * ei1.eigenvectors(),
+ ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
+
+}
+
+void test_eigen2_eigensolver()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ // very important to test a 3x3 matrix since we provide a special path for it
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
+ CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
+ CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(7,7)) );
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXcd(5,5)) );
+ CALL_SUBTEST_5( selfadjointeigensolver(MatrixXd(19,19)) );
+
+ CALL_SUBTEST_6( eigensolver(Matrix4f()) );
+ CALL_SUBTEST_5( eigensolver(MatrixXd(17,17)) );
+ }
+}
+
diff --git a/test/eigen2/eigen2_first_aligned.cpp b/test/eigen2/eigen2_first_aligned.cpp
new file mode 100644
index 000000000..51bb3cad1
--- /dev/null
+++ b/test/eigen2/eigen2_first_aligned.cpp
@@ -0,0 +1,49 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#include "main.h"
+
+template<typename Scalar>
+void test_eigen2_first_aligned_helper(Scalar *array, int size)
+{
+ const int packet_size = sizeof(Scalar) * ei_packet_traits<Scalar>::size;
+ VERIFY(((std::size_t(array) + sizeof(Scalar) * ei_alignmentOffset(array, size)) % packet_size) == 0);
+}
+
+template<typename Scalar>
+void test_eigen2_none_aligned_helper(Scalar *array, int size)
+{
+ VERIFY(ei_packet_traits<Scalar>::size == 1 || ei_alignmentOffset(array, size) == size);
+}
+
+struct some_non_vectorizable_type { float x; };
+
+void test_eigen2_first_aligned()
+{
+ EIGEN_ALIGN_128 float array_float[100];
+ test_first_aligned_helper(array_float, 50);
+ test_first_aligned_helper(array_float+1, 50);
+ test_first_aligned_helper(array_float+2, 50);
+ test_first_aligned_helper(array_float+3, 50);
+ test_first_aligned_helper(array_float+4, 50);
+ test_first_aligned_helper(array_float+5, 50);
+
+ EIGEN_ALIGN_128 double array_double[100];
+ test_first_aligned_helper(array_double, 50);
+ test_first_aligned_helper(array_double+1, 50);
+ test_first_aligned_helper(array_double+2, 50);
+
+ double *array_double_plus_4_bytes = (double*)(std::size_t(array_double)+4);
+ test_none_aligned_helper(array_double_plus_4_bytes, 50);
+ test_none_aligned_helper(array_double_plus_4_bytes+1, 50);
+
+ some_non_vectorizable_type array_nonvec[100];
+ test_first_aligned_helper(array_nonvec, 100);
+ test_none_aligned_helper(array_nonvec, 100);
+}
diff --git a/test/eigen2/eigen2_geometry.cpp b/test/eigen2/eigen2_geometry.cpp
new file mode 100644
index 000000000..70b4ab5f1
--- /dev/null
+++ b/test/eigen2/eigen2_geometry.cpp
@@ -0,0 +1,431 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar> void geometry(void)
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+ typedef Transform<Scalar,2> Transform2;
+ typedef Transform<Scalar,3> Transform3;
+ typedef Scaling<Scalar,2> Scaling2;
+ typedef Scaling<Scalar,3> Scaling3;
+ typedef Translation<Scalar,2> Translation2;
+ typedef Translation<Scalar,3> Translation3;
+
+ Scalar largeEps = test_precision<Scalar>();
+ if (ei_is_same_type<Scalar,float>::ret)
+ largeEps = 1e-2f;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random();
+ Vector2 u0 = Vector2::Random();
+ Matrix3 matrot1;
+
+ Scalar a = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ // cross product
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1));
+ Matrix3 m;
+ m << v0.normalized(),
+ (v0.cross(v1)).normalized(),
+ (v0.cross(v1).cross(v0)).normalized();
+ VERIFY(m.isUnitary());
+
+ // Quaternion: Identity(), setIdentity();
+ Quaternionx q1, q2;
+ q2.setIdentity();
+ VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
+ q1.coeffs().setRandom();
+ VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
+
+ // unitOrthogonal
+ VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1));
+
+
+ VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
+ VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
+ VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_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);
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // angular distance
+ Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle());
+ if (refangle>Scalar(M_PI))
+ refangle = Scalar(2)*Scalar(M_PI) - refangle;
+
+ if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
+ {
+ VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps));
+ }
+
+ // rotation matrix conversion
+ VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
+ VERIFY_IS_APPROX(q1 * q2 * v2,
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
+
+ VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox(
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
+
+ q2 = q1.toRotationMatrix();
+ VERIFY_IS_APPROX(q1*v1,q2*v1);
+
+ matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
+ * AngleAxisx(Scalar(0.2), Vector3::UnitY())
+ * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
+ VERIFY_IS_APPROX(matrot1 * v1,
+ AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
+
+ // angle-axis conversion
+ AngleAxisx aa = q1;
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+
+ // from two vector creation
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+
+ // inverse and conjugate
+ VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
+ VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
+
+ // AngleAxis
+ VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
+ Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
+
+ AngleAxisx aa1;
+ m = q1.toRotationMatrix();
+ aa1 = m;
+ VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
+ Quaternionx(m).toRotationMatrix());
+
+ // Transform
+ // TODO complete the tests !
+ a = 0;
+ while (ei_abs(a)<Scalar(0.1))
+ a = ei_random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
+ q1 = AngleAxisx(a, v0.normalized());
+ Transform3 t0, t1, t2;
+ // first test setIdentity() and Identity()
+ t0.setIdentity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+ t0.matrix().setZero();
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.linear() = q1.toRotationMatrix();
+ t1.setIdentity();
+ t1.linear() = q1.toRotationMatrix();
+
+ v0 << 50, 2, 1;//= ei_random_matrix<Vector3>().cwiseProduct(Vector3(10,2,0.5));
+ t0.scale(v0);
+ t1.prescale(v0);
+
+ VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x());
+ //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x()));
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwise().inverse());
+ t1.translate(-v0);
+
+ VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+ VERIFY_IS_APPROX(t1*v1, t0*v1);
+
+ t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
+ t1.setIdentity(); t1.scale(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
+ VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
+
+ // More transform constructors, operator=, operator*=
+
+ Matrix3 mat3 = Matrix3::Random();
+ Matrix4 mat4;
+ mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
+ Transform3 tmat3(mat3), tmat4(mat4);
+ tmat4.matrix()(3,3) = Scalar(1);
+ VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
+
+ Scalar a3 = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Vector3 v3 = Vector3::Random().normalized();
+ AngleAxisx aa3(a3, v3);
+ Transform3 t3(aa3);
+ Transform3 t4;
+ t4 = aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+ t4.rotate(AngleAxisx(-a3,v3));
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+
+ v3 = Vector3::Random();
+ Translation3 tv3(v3);
+ Transform3 t5(tv3);
+ t4 = tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+ t4.translate(-v3);
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+
+ Scaling3 sv3(v3);
+ Transform3 t6(sv3);
+ t4 = sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+ t4.scale(v3.cwise().inverse());
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+
+ // matrix * transform
+ VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix());
+
+ // chained Transform product
+ VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
+
+ // check that Transform product doesn't have aliasing problems
+ t5 = t4;
+ t5 = t5*t5;
+ VERIFY_IS_APPROX(t5, t4*t4);
+
+ // 2D transformation
+ Transform2 t20, t21;
+ Vector2 v20 = Vector2::Random();
+ Vector2 v21 = Vector2::Random();
+ for (int k=0; k<2; ++k)
+ if (ei_abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
+ VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
+ t21.pretranslate(v20).scale(v21).matrix());
+
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
+ VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
+ * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
+
+ // Transform - new API
+ // 3D
+ t0.setIdentity();
+ t0.rotate(q1).scale(v0).translate(v0);
+ // mat * scaling and mat * translation
+ t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // mat * transformation and scaling * translation
+ t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.prerotate(q1).prescale(v0).pretranslate(v0);
+ // translation * scaling and transformation * mat
+ t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // scaling * mat and translation * mat
+ t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.scale(v0).translate(v0).rotate(q1);
+ // translation * mat and scaling * transformation
+ t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * scaling
+ t0.scale(v0);
+ t1 = t1 * Scaling3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * translation
+ t0.translate(v0);
+ t1 = t1 * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // translation * transformation
+ t0.pretranslate(v0);
+ t1 = Translation3(v0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // transform * quaternion
+ t0.rotate(q1);
+ t1 = t1 * q1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * quaternion
+ t0.translate(v1).rotate(q1);
+ t1 = t1 * (Translation3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // scaling * quaternion
+ t0.scale(v1).rotate(q1);
+ t1 = t1 * (Scaling3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * transform
+ t0.prerotate(q1);
+ t1 = q1 * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * translation
+ t0.rotate(q1).translate(v1);
+ t1 = t1 * (q1 * Translation3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * scaling
+ t0.rotate(q1).scale(v1);
+ t1 = t1 * (q1 * Scaling3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * vector
+ t0.setIdentity();
+ t0.translate(v0);
+ VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1);
+
+ // scaling * vector
+ t0.setIdentity();
+ t0.scale(v0);
+ VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1);
+
+ // test transform inversion
+ t0.setIdentity();
+ t0.translate(v0);
+ t0.linear().setRandom();
+ VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse());
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse());
+
+ // test extract rotation and scaling
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1);
+
+ Matrix3 mat_rotation, mat_scaling;
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ t0.computeRotationScaling(&mat_rotation, &mat_scaling);
+ VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+ t0.computeScalingRotation(&mat_scaling, &mat_rotation);
+ VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+
+ // test casting
+ Transform<float,3> t1f = t1.template cast<float>();
+ VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
+ Transform<double,3> t1d = t1.template cast<double>();
+ VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
+
+ Translation3 tr1(v0);
+ Translation<float,3> tr1f = tr1.template cast<float>();
+ VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
+ Translation<double,3> tr1d = tr1.template cast<double>();
+ VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
+
+ Scaling3 sc1(v0);
+ Scaling<float,3> sc1f = sc1.template cast<float>();
+ VERIFY_IS_APPROX(sc1f.template cast<Scalar>(),sc1);
+ Scaling<double,3> sc1d = sc1.template cast<double>();
+ VERIFY_IS_APPROX(sc1d.template cast<Scalar>(),sc1);
+
+ Quaternion<float> q1f = q1.template cast<float>();
+ VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
+ Quaternion<double> q1d = q1.template cast<double>();
+ VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
+
+ AngleAxis<float> aa1f = aa1.template cast<float>();
+ VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
+ AngleAxis<double> aa1d = aa1.template cast<double>();
+ VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
+
+ Rotation2D<Scalar> r2d1(ei_random<Scalar>());
+ Rotation2D<float> r2d1f = r2d1.template cast<float>();
+ VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
+ Rotation2D<double> r2d1d = r2d1.template cast<double>();
+ VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
+
+ m = q1;
+// m.col(1) = Vector3(0,ei_random<Scalar>(),ei_random<Scalar>()).normalized();
+// m.col(0) = Vector3(-1,0,0).normalized();
+// m.col(2) = m.col(0).cross(m.col(1));
+ #define VERIFY_EULER(I,J,K, X,Y,Z) { \
+ Vector3 ea = m.eulerAngles(I,J,K); \
+ Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \
+ VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
+ }
+ VERIFY_EULER(0,1,2, X,Y,Z);
+ VERIFY_EULER(0,1,0, X,Y,X);
+ VERIFY_EULER(0,2,1, X,Z,Y);
+ VERIFY_EULER(0,2,0, X,Z,X);
+
+ VERIFY_EULER(1,2,0, Y,Z,X);
+ VERIFY_EULER(1,2,1, Y,Z,Y);
+ VERIFY_EULER(1,0,2, Y,X,Z);
+ VERIFY_EULER(1,0,1, Y,X,Y);
+
+ VERIFY_EULER(2,0,1, Z,X,Y);
+ VERIFY_EULER(2,0,2, Z,X,Z);
+ VERIFY_EULER(2,1,0, Z,Y,X);
+ VERIFY_EULER(2,1,2, Z,Y,Z);
+
+ // colwise/rowwise cross product
+ mat3.setRandom();
+ Vector3 vec3 = Vector3::Random();
+ Matrix3 mcross;
+ int i = ei_random<int>(0,2);
+ mcross = mat3.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
+ mcross = mat3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
+
+
+}
+
+void test_eigen2_geometry()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( geometry<float>() );
+ CALL_SUBTEST_2( geometry<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp b/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp
new file mode 100644
index 000000000..f83b57249
--- /dev/null
+++ b/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp
@@ -0,0 +1,434 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#define EIGEN2_SUPPORT_STAGE15_RESOLVE_API_CONFLICTS_WARN
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar> void geometry(void)
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef eigen2_Quaternion<Scalar> Quaternionx;
+ typedef eigen2_AngleAxis<Scalar> AngleAxisx;
+ typedef eigen2_Transform<Scalar,2> Transform2;
+ typedef eigen2_Transform<Scalar,3> Transform3;
+ typedef eigen2_Scaling<Scalar,2> Scaling2;
+ typedef eigen2_Scaling<Scalar,3> Scaling3;
+ typedef eigen2_Translation<Scalar,2> Translation2;
+ typedef eigen2_Translation<Scalar,3> Translation3;
+
+ Scalar largeEps = test_precision<Scalar>();
+ if (ei_is_same_type<Scalar,float>::ret)
+ largeEps = 1e-2f;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random();
+ Vector2 u0 = Vector2::Random();
+ Matrix3 matrot1;
+
+ Scalar a = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ // cross product
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1));
+ Matrix3 m;
+ m << v0.normalized(),
+ (v0.cross(v1)).normalized(),
+ (v0.cross(v1).cross(v0)).normalized();
+ VERIFY(m.isUnitary());
+
+ // Quaternion: Identity(), setIdentity();
+ Quaternionx q1, q2;
+ q2.setIdentity();
+ VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
+ q1.coeffs().setRandom();
+ VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
+
+ // unitOrthogonal
+ VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1));
+
+
+ VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
+ VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
+ VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_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);
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // angular distance
+ Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle());
+ if (refangle>Scalar(M_PI))
+ refangle = Scalar(2)*Scalar(M_PI) - refangle;
+
+ if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
+ {
+ VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps));
+ }
+
+ // rotation matrix conversion
+ VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
+ VERIFY_IS_APPROX(q1 * q2 * v2,
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
+
+ VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox(
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
+
+ q2 = q1.toRotationMatrix();
+ VERIFY_IS_APPROX(q1*v1,q2*v1);
+
+ matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
+ * AngleAxisx(Scalar(0.2), Vector3::UnitY())
+ * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
+ VERIFY_IS_APPROX(matrot1 * v1,
+ AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
+
+ // angle-axis conversion
+ AngleAxisx aa = q1;
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+
+ // from two vector creation
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+ VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
+
+ // inverse and conjugate
+ VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
+ VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
+
+ // AngleAxis
+ VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
+ Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
+
+ AngleAxisx aa1;
+ m = q1.toRotationMatrix();
+ aa1 = m;
+ VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
+ Quaternionx(m).toRotationMatrix());
+
+ // Transform
+ // TODO complete the tests !
+ a = 0;
+ while (ei_abs(a)<Scalar(0.1))
+ a = ei_random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
+ q1 = AngleAxisx(a, v0.normalized());
+ Transform3 t0, t1, t2;
+ // first test setIdentity() and Identity()
+ t0.setIdentity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+ t0.matrix().setZero();
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.linear() = q1.toRotationMatrix();
+ t1.setIdentity();
+ t1.linear() = q1.toRotationMatrix();
+
+ v0 << 50, 2, 1;//= ei_random_matrix<Vector3>().cwiseProduct(Vector3(10,2,0.5));
+ t0.scale(v0);
+ t1.prescale(v0);
+
+ VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x());
+ //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x()));
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwise().inverse());
+ t1.translate(-v0);
+
+ VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+ VERIFY_IS_APPROX(t1*v1, t0*v1);
+
+ t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
+ t1.setIdentity(); t1.scale(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
+ VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
+
+ // More transform constructors, operator=, operator*=
+
+ Matrix3 mat3 = Matrix3::Random();
+ Matrix4 mat4;
+ mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
+ Transform3 tmat3(mat3), tmat4(mat4);
+ tmat4.matrix()(3,3) = Scalar(1);
+ VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
+
+ Scalar a3 = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Vector3 v3 = Vector3::Random().normalized();
+ AngleAxisx aa3(a3, v3);
+ Transform3 t3(aa3);
+ Transform3 t4;
+ t4 = aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+ t4.rotate(AngleAxisx(-a3,v3));
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+
+ v3 = Vector3::Random();
+ Translation3 tv3(v3);
+ Transform3 t5(tv3);
+ t4 = tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+ t4.translate(-v3);
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+
+ Scaling3 sv3(v3);
+ Transform3 t6(sv3);
+ t4 = sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+ t4.scale(v3.cwise().inverse());
+ VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
+ t4 *= sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+
+ // matrix * transform
+ VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix());
+
+ // chained Transform product
+ VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
+
+ // check that Transform product doesn't have aliasing problems
+ t5 = t4;
+ t5 = t5*t5;
+ VERIFY_IS_APPROX(t5, t4*t4);
+
+ // 2D transformation
+ Transform2 t20, t21;
+ Vector2 v20 = Vector2::Random();
+ Vector2 v21 = Vector2::Random();
+ for (int k=0; k<2; ++k)
+ if (ei_abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
+ VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
+ t21.pretranslate(v20).scale(v21).matrix());
+
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
+ VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
+ * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
+
+ // Transform - new API
+ // 3D
+ t0.setIdentity();
+ t0.rotate(q1).scale(v0).translate(v0);
+ // mat * scaling and mat * translation
+ t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // mat * transformation and scaling * translation
+ t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.prerotate(q1).prescale(v0).pretranslate(v0);
+ // translation * scaling and transformation * mat
+ t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // scaling * mat and translation * mat
+ t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.scale(v0).translate(v0).rotate(q1);
+ // translation * mat and scaling * transformation
+ t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * scaling
+ t0.scale(v0);
+ t1 = t1 * Scaling3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * translation
+ t0.translate(v0);
+ t1 = t1 * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // translation * transformation
+ t0.pretranslate(v0);
+ t1 = Translation3(v0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // transform * quaternion
+ t0.rotate(q1);
+ t1 = t1 * q1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * quaternion
+ t0.translate(v1).rotate(q1);
+ t1 = t1 * (Translation3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // scaling * quaternion
+ t0.scale(v1).rotate(q1);
+ t1 = t1 * (Scaling3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * transform
+ t0.prerotate(q1);
+ t1 = q1 * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * translation
+ t0.rotate(q1).translate(v1);
+ t1 = t1 * (q1 * Translation3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * scaling
+ t0.rotate(q1).scale(v1);
+ t1 = t1 * (q1 * Scaling3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * vector
+ t0.setIdentity();
+ t0.translate(v0);
+ VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1);
+
+ // scaling * vector
+ t0.setIdentity();
+ t0.scale(v0);
+ VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1);
+
+ // test transform inversion
+ t0.setIdentity();
+ t0.translate(v0);
+ t0.linear().setRandom();
+ VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse());
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse());
+
+ // test extract rotation and scaling
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1);
+
+ Matrix3 mat_rotation, mat_scaling;
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ t0.computeRotationScaling(&mat_rotation, &mat_scaling);
+ VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+ t0.computeScalingRotation(&mat_scaling, &mat_rotation);
+ VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+
+ // test casting
+ eigen2_Transform<float,3> t1f = t1.template cast<float>();
+ VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
+ eigen2_Transform<double,3> t1d = t1.template cast<double>();
+ VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
+
+ Translation3 tr1(v0);
+ eigen2_Translation<float,3> tr1f = tr1.template cast<float>();
+ VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
+ eigen2_Translation<double,3> tr1d = tr1.template cast<double>();
+ VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
+
+ Scaling3 sc1(v0);
+ eigen2_Scaling<float,3> sc1f = sc1.template cast<float>();
+ VERIFY_IS_APPROX(sc1f.template cast<Scalar>(),sc1);
+ eigen2_Scaling<double,3> sc1d = sc1.template cast<double>();
+ VERIFY_IS_APPROX(sc1d.template cast<Scalar>(),sc1);
+
+ eigen2_Quaternion<float> q1f = q1.template cast<float>();
+ VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
+ eigen2_Quaternion<double> q1d = q1.template cast<double>();
+ VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
+
+ eigen2_AngleAxis<float> aa1f = aa1.template cast<float>();
+ VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
+ eigen2_AngleAxis<double> aa1d = aa1.template cast<double>();
+ VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
+
+ eigen2_Rotation2D<Scalar> r2d1(ei_random<Scalar>());
+ eigen2_Rotation2D<float> r2d1f = r2d1.template cast<float>();
+ VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
+ eigen2_Rotation2D<double> r2d1d = r2d1.template cast<double>();
+ VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
+
+ m = q1;
+// m.col(1) = Vector3(0,ei_random<Scalar>(),ei_random<Scalar>()).normalized();
+// m.col(0) = Vector3(-1,0,0).normalized();
+// m.col(2) = m.col(0).cross(m.col(1));
+ #define VERIFY_EULER(I,J,K, X,Y,Z) { \
+ Vector3 ea = m.eulerAngles(I,J,K); \
+ Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \
+ VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
+ }
+ VERIFY_EULER(0,1,2, X,Y,Z);
+ VERIFY_EULER(0,1,0, X,Y,X);
+ VERIFY_EULER(0,2,1, X,Z,Y);
+ VERIFY_EULER(0,2,0, X,Z,X);
+
+ VERIFY_EULER(1,2,0, Y,Z,X);
+ VERIFY_EULER(1,2,1, Y,Z,Y);
+ VERIFY_EULER(1,0,2, Y,X,Z);
+ VERIFY_EULER(1,0,1, Y,X,Y);
+
+ VERIFY_EULER(2,0,1, Z,X,Y);
+ VERIFY_EULER(2,0,2, Z,X,Z);
+ VERIFY_EULER(2,1,0, Z,Y,X);
+ VERIFY_EULER(2,1,2, Z,Y,Z);
+
+ // colwise/rowwise cross product
+ mat3.setRandom();
+ Vector3 vec3 = Vector3::Random();
+ Matrix3 mcross;
+ int i = ei_random<int>(0,2);
+ mcross = mat3.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
+ mcross = mat3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
+
+
+}
+
+void test_eigen2_geometry_with_eigen2_prefix()
+{
+ std::cout << "eigen2 support: " << EIGEN2_SUPPORT_STAGE << std::endl;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( geometry<float>() );
+ CALL_SUBTEST_2( geometry<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_hyperplane.cpp b/test/eigen2/eigen2_hyperplane.cpp
new file mode 100644
index 000000000..f3f85e14d
--- /dev/null
+++ b/test/eigen2/eigen2_hyperplane.cpp
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
+{
+ /* this test covers the following files:
+ Hyperplane.h
+ */
+
+ const int dim = _plane.dim();
+ typedef typename HyperplaneType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime,
+ HyperplaneType::AmbientDimAtCompileTime> MatrixType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType n0 = VectorType::Random(dim).normalized();
+ VectorType n1 = VectorType::Random(dim).normalized();
+
+ HyperplaneType pl0(n0, p0);
+ HyperplaneType pl1(n1, p1);
+ HyperplaneType pl2 = pl1;
+
+ Scalar s0 = ei_random<Scalar>();
+ Scalar s1 = ei_random<Scalar>();
+
+ VERIFY_IS_APPROX( n1.eigen2_dot(n1), Scalar(1) );
+
+ VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) );
+ VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1) );
+
+ // transform
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ MatrixType rot = MatrixType::Random(dim,dim).qr().matrixQ();
+ Scaling<Scalar,HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
+ Translation<Scalar,HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());
+
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
+ .absDistance((rot*scaling*translation) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
+ .absDistance((rot*translation) * p1), Scalar(1) );
+ }
+
+ // casting
+ const int Dim = HyperplaneType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ Hyperplane<OtherScalar,Dim> hp1f = pl1.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),pl1);
+ Hyperplane<Scalar,Dim> hp1d = pl1.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),pl1);
+}
+
+template<typename Scalar> void lines()
+{
+ typedef Hyperplane<Scalar, 2> HLine;
+ typedef ParametrizedLine<Scalar, 2> PLine;
+ typedef Matrix<Scalar,2,1> Vector;
+ typedef Matrix<Scalar,3,1> CoeffsType;
+
+ for(int i = 0; i < 10; i++)
+ {
+ Vector center = Vector::Random();
+ Vector u = Vector::Random();
+ Vector v = Vector::Random();
+ Scalar a = ei_random<Scalar>();
+ while (ei_abs(a-1) < 1e-4) a = ei_random<Scalar>();
+ while (u.norm() < 1e-4) u = Vector::Random();
+ while (v.norm() < 1e-4) v = Vector::Random();
+
+ HLine line_u = HLine::Through(center + u, center + a*u);
+ HLine line_v = HLine::Through(center + v, center + a*v);
+
+ // the line equations should be normalized so that a^2+b^2=1
+ VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));
+
+ Vector result = line_u.intersection(line_v);
+
+ // the lines should intersect at the point we called "center"
+ VERIFY_IS_APPROX(result, center);
+
+ // check conversions between two types of lines
+ PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable
+ CoeffsType converted_coeffs(HLine(pl).coeffs());
+ converted_coeffs *= line_u.coeffs()(0)/converted_coeffs(0);
+ VERIFY(line_u.coeffs().isApprox(converted_coeffs));
+ }
+}
+
+void test_eigen2_hyperplane()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( hyperplane(Hyperplane<float,2>()) );
+ CALL_SUBTEST_2( hyperplane(Hyperplane<float,3>()) );
+ CALL_SUBTEST_3( hyperplane(Hyperplane<double,4>()) );
+ CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
+ CALL_SUBTEST_5( lines<float>() );
+ CALL_SUBTEST_6( lines<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_inverse.cpp b/test/eigen2/eigen2_inverse.cpp
new file mode 100644
index 000000000..5de1dfefa
--- /dev/null
+++ b/test/eigen2/eigen2_inverse.cpp
@@ -0,0 +1,63 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void inverse(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Inverse.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = MatrixType::Identity(rows, rows);
+
+ while(ei_abs(m1.determinant()) < RealScalar(0.1) && rows <= 8)
+ {
+ m1 = MatrixType::Random(rows, cols);
+ }
+
+ m2 = m1.inverse();
+ VERIFY_IS_APPROX(m1, m2.inverse() );
+
+ m1.computeInverse(&m2);
+ VERIFY_IS_APPROX(m1, m2.inverse() );
+
+ VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));
+
+ VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
+ VERIFY_IS_APPROX(identity, m1 * m1.inverse() );
+
+ VERIFY_IS_APPROX(m1, m1.inverse().inverse() );
+
+ // since for the general case we implement separately row-major and col-major, test that
+ VERIFY_IS_APPROX(m1.transpose().inverse(), m1.inverse().transpose());
+}
+
+void test_eigen2_inverse()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( inverse(Matrix2d()) );
+ CALL_SUBTEST_3( inverse(Matrix3f()) );
+ CALL_SUBTEST_4( inverse(Matrix4f()) );
+ CALL_SUBTEST_5( inverse(MatrixXf(8,8)) );
+ CALL_SUBTEST_6( inverse(MatrixXcd(7,7)) );
+ }
+}
diff --git a/test/eigen2/eigen2_linearstructure.cpp b/test/eigen2/eigen2_linearstructure.cpp
new file mode 100644
index 000000000..22f02c396
--- /dev/null
+++ b/test/eigen2/eigen2_linearstructure.cpp
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void linearStructure(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Sum.h Difference.h Opposite.h ScalarMultiple.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+
+ Scalar s1 = ei_random<Scalar>();
+ while (ei_abs(s1)<1e-3) s1 = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ VERIFY_IS_APPROX(-(-m1), m1);
+ VERIFY_IS_APPROX(m1+m1, 2*m1);
+ VERIFY_IS_APPROX(m1+m2-m1, m2);
+ VERIFY_IS_APPROX(-m2+m1+m2, m1);
+ VERIFY_IS_APPROX(m1*s1, s1*m1);
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2);
+ m3 = m2; m3 += m1;
+ VERIFY_IS_APPROX(m3, m1+m2);
+ m3 = m2; m3 -= m1;
+ VERIFY_IS_APPROX(m3, m2-m1);
+ m3 = m2; m3 *= s1;
+ VERIFY_IS_APPROX(m3, s1*m2);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ {
+ m3 = m2; m3 /= s1;
+ VERIFY_IS_APPROX(m3, m2/s1);
+ }
+
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c)));
+ VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c)));
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c)));
+ VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1);
+ if(NumTraits<Scalar>::HasFloatingPoint)
+ VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1);
+
+ // use .block to disable vectorization and compare to the vectorized version
+ VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1);
+ VERIFY_IS_APPROX(m1.cwise() * m1.block(0,0,rows,cols), m1.cwise() * m1);
+ VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1);
+ VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1);
+}
+
+void test_eigen2_linearstructure()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( linearStructure(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( linearStructure(Matrix2f()) );
+ CALL_SUBTEST_3( linearStructure(Vector3d()) );
+ CALL_SUBTEST_4( linearStructure(Matrix4d()) );
+ CALL_SUBTEST_5( linearStructure(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_6( linearStructure(MatrixXf(8, 12)) );
+ CALL_SUBTEST_7( linearStructure(MatrixXi(8, 12)) );
+ CALL_SUBTEST_8( linearStructure(MatrixXcd(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_lu.cpp b/test/eigen2/eigen2_lu.cpp
new file mode 100644
index 000000000..e993b1c7c
--- /dev/null
+++ b/test/eigen2/eigen2_lu.cpp
@@ -0,0 +1,122 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/LU>
+
+template<typename Derived>
+void doSomeRankPreservingOperations(Eigen::MatrixBase<Derived>& m)
+{
+ typedef typename Derived::RealScalar RealScalar;
+ for(int a = 0; a < 3*(m.rows()+m.cols()); a++)
+ {
+ RealScalar d = Eigen::ei_random<RealScalar>(-1,1);
+ int i = Eigen::ei_random<int>(0,m.rows()-1); // i is a random row number
+ int j;
+ do {
+ j = Eigen::ei_random<int>(0,m.rows()-1);
+ } while (i==j); // j is another one (must be different)
+ m.row(i) += d * m.row(j);
+
+ i = Eigen::ei_random<int>(0,m.cols()-1); // i is a random column number
+ do {
+ j = Eigen::ei_random<int>(0,m.cols()-1);
+ } while (i==j); // j is another one (must be different)
+ m.col(i) += d * m.col(j);
+ }
+}
+
+template<typename MatrixType> void lu_non_invertible()
+{
+ /* this test covers the following files:
+ LU.h
+ */
+ // NOTE there seems to be a problem with too small sizes -- could easily lie in the doSomeRankPreservingOperations function
+ int rows = ei_random<int>(20,200), cols = ei_random<int>(20,200), cols2 = ei_random<int>(20,200);
+ int rank = ei_random<int>(1, std::min(rows, cols)-1);
+
+ MatrixType m1(rows, cols), m2(cols, cols2), m3(rows, cols2), k(1,1);
+ m1 = MatrixType::Random(rows,cols);
+ if(rows <= cols)
+ for(int i = rank; i < rows; i++) m1.row(i).setZero();
+ else
+ for(int i = rank; i < cols; i++) m1.col(i).setZero();
+ doSomeRankPreservingOperations(m1);
+
+ LU<MatrixType> lu(m1);
+ typename LU<MatrixType>::KernelResultType m1kernel = lu.kernel();
+ typename LU<MatrixType>::ImageResultType m1image = lu.image();
+
+ VERIFY(rank == lu.rank());
+ VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
+ VERIFY(!lu.isInjective());
+ VERIFY(!lu.isInvertible());
+ VERIFY(lu.isSurjective() == (lu.rank() == rows));
+ VERIFY((m1 * m1kernel).isMuchSmallerThan(m1));
+ VERIFY(m1image.lu().rank() == rank);
+ MatrixType sidebyside(m1.rows(), m1.cols() + m1image.cols());
+ sidebyside << m1, m1image;
+ VERIFY(sidebyside.lu().rank() == rank);
+ m2 = MatrixType::Random(cols,cols2);
+ m3 = m1*m2;
+ m2 = MatrixType::Random(cols,cols2);
+ lu.solve(m3, &m2);
+ VERIFY_IS_APPROX(m3, m1*m2);
+ /* solve now always returns true
+ m3 = MatrixType::Random(rows,cols2);
+ VERIFY(!lu.solve(m3, &m2));
+ */
+}
+
+template<typename MatrixType> void lu_invertible()
+{
+ /* this test covers the following files:
+ LU.h
+ */
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ int size = ei_random<int>(10,200);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (ei_is_same_type<RealScalar,float>::ret)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ LU<MatrixType> lu(m1);
+ VERIFY(0 == lu.dimensionOfKernel());
+ VERIFY(size == lu.rank());
+ VERIFY(lu.isInjective());
+ VERIFY(lu.isSurjective());
+ VERIFY(lu.isInvertible());
+ VERIFY(lu.image().lu().isInvertible());
+ m3 = MatrixType::Random(size,size);
+ lu.solve(m3, &m2);
+ VERIFY_IS_APPROX(m3, m1*m2);
+ VERIFY_IS_APPROX(m2, lu.inverse()*m3);
+ m3 = MatrixType::Random(size,size);
+ VERIFY(lu.solve(m3, &m2));
+}
+
+void test_eigen2_lu()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lu_non_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( lu_non_invertible<MatrixXd>() );
+ CALL_SUBTEST_3( lu_non_invertible<MatrixXcf>() );
+ CALL_SUBTEST_4( lu_non_invertible<MatrixXcd>() );
+ CALL_SUBTEST_1( lu_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( lu_invertible<MatrixXd>() );
+ CALL_SUBTEST_3( lu_invertible<MatrixXcf>() );
+ CALL_SUBTEST_4( lu_invertible<MatrixXcd>() );
+ }
+}
diff --git a/test/eigen2/eigen2_map.cpp b/test/eigen2/eigen2_map.cpp
new file mode 100644
index 000000000..4a1c4e11a
--- /dev/null
+++ b/test/eigen2/eigen2_map.cpp
@@ -0,0 +1,114 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2007-2010 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/.
+
+#include "main.h"
+
+template<typename VectorType> void map_class_vector(const VectorType& m)
+{
+ typedef typename VectorType::Scalar Scalar;
+
+ int size = m.size();
+
+ // test Map.h
+ Scalar* array1 = ei_aligned_new<Scalar>(size);
+ Scalar* array2 = ei_aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ Map<VectorType, Aligned>(array1, size) = VectorType::Random(size);
+ Map<VectorType>(array2, size) = Map<VectorType>(array1, size);
+ Map<VectorType>(array3unaligned, size) = Map<VectorType>((const Scalar*)array1, size); // test non-const-correctness support in eigen2
+ VectorType ma1 = Map<VectorType>(array1, size);
+ VectorType ma2 = Map<VectorType, Aligned>(array2, size);
+ VectorType ma3 = Map<VectorType>(array3unaligned, size);
+ VERIFY_IS_APPROX(ma1, ma2);
+ VERIFY_IS_APPROX(ma1, ma3);
+
+ ei_aligned_delete(array1, size);
+ ei_aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename MatrixType> void map_class_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ int rows = m.rows(), cols = m.cols(), size = rows*cols;
+
+ // test Map.h
+ Scalar* array1 = ei_aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array1[i] = Scalar(1);
+ Scalar* array2 = ei_aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array2[i] = Scalar(1);
+ Scalar* array3 = new Scalar[size+1];
+ for(int i = 0; i < size+1; i++) array3[i] = Scalar(1);
+ Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3;
+ Map<MatrixType, Aligned>(array1, rows, cols) = MatrixType::Ones(rows,cols);
+ Map<MatrixType>(array2, rows, cols) = Map<MatrixType>((const Scalar*)array1, rows, cols); // test non-const-correctness support in eigen2
+ Map<MatrixType>(array3unaligned, rows, cols) = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma1 = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma2 = Map<MatrixType, Aligned>(array2, rows, cols);
+ VERIFY_IS_APPROX(ma1, ma2);
+ MatrixType ma3 = Map<MatrixType>(array3unaligned, rows, cols);
+ VERIFY_IS_APPROX(ma1, ma3);
+
+ ei_aligned_delete(array1, size);
+ ei_aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename VectorType> void map_static_methods(const VectorType& m)
+{
+ typedef typename VectorType::Scalar Scalar;
+
+ int size = m.size();
+
+ // test Map.h
+ Scalar* array1 = ei_aligned_new<Scalar>(size);
+ Scalar* array2 = ei_aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ VectorType::MapAligned(array1, size) = VectorType::Random(size);
+ VectorType::Map(array2, size) = VectorType::Map(array1, size);
+ VectorType::Map(array3unaligned, size) = VectorType::Map(array1, size);
+ VectorType ma1 = VectorType::Map(array1, size);
+ VectorType ma2 = VectorType::MapAligned(array2, size);
+ VectorType ma3 = VectorType::Map(array3unaligned, size);
+ VERIFY_IS_APPROX(ma1, ma2);
+ VERIFY_IS_APPROX(ma1, ma3);
+
+ ei_aligned_delete(array1, size);
+ ei_aligned_delete(array2, size);
+ delete[] array3;
+}
+
+
+void test_eigen2_map()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( map_class_vector(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_vector(Vector4d()) );
+ CALL_SUBTEST_3( map_class_vector(RowVector4f()) );
+ CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) );
+ CALL_SUBTEST_5( map_class_vector(VectorXi(12)) );
+
+ CALL_SUBTEST_1( map_class_matrix(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_matrix(Matrix4d()) );
+ CALL_SUBTEST_6( map_class_matrix(Matrix<float,3,5>()) );
+ CALL_SUBTEST_4( map_class_matrix(MatrixXcf(ei_random<int>(1,10),ei_random<int>(1,10))) );
+ CALL_SUBTEST_5( map_class_matrix(MatrixXi(ei_random<int>(1,10),ei_random<int>(1,10))) );
+
+ CALL_SUBTEST_1( map_static_methods(Matrix<double, 1, 1>()) );
+ CALL_SUBTEST_2( map_static_methods(Vector3f()) );
+ CALL_SUBTEST_7( map_static_methods(RowVector3d()) );
+ CALL_SUBTEST_4( map_static_methods(VectorXcd(8)) );
+ CALL_SUBTEST_5( map_static_methods(VectorXf(12)) );
+ }
+}
diff --git a/test/eigen2/eigen2_meta.cpp b/test/eigen2/eigen2_meta.cpp
new file mode 100644
index 000000000..1d01bd84d
--- /dev/null
+++ b/test/eigen2/eigen2_meta.cpp
@@ -0,0 +1,60 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+
+void test_eigen2_meta()
+{
+ typedef float & FloatRef;
+ typedef const float & ConstFloatRef;
+
+ VERIFY((ei_meta_if<(3<4),ei_meta_true, ei_meta_false>::ret::ret));
+ VERIFY(( ei_is_same_type<float,float>::ret));
+ VERIFY((!ei_is_same_type<float,double>::ret));
+ VERIFY((!ei_is_same_type<float,float&>::ret));
+ VERIFY((!ei_is_same_type<float,const float&>::ret));
+
+ VERIFY(( ei_is_same_type<float,ei_cleantype<const float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<const float*>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<const float*&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float**>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float**&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float* const *&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_cleantype<float* const>::type >::ret));
+
+ VERIFY(( ei_is_same_type<float*,ei_unconst<const float*>::type >::ret));
+ VERIFY(( ei_is_same_type<float&,ei_unconst<const float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float&,ei_unconst<ConstFloatRef>::type >::ret));
+
+ VERIFY(( ei_is_same_type<float&,ei_unconst<float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_unref<float&>::type >::ret));
+ VERIFY(( ei_is_same_type<const float,ei_unref<const float&>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_unpointer<float*>::type >::ret));
+ VERIFY(( ei_is_same_type<const float,ei_unpointer<const float*>::type >::ret));
+ VERIFY(( ei_is_same_type<float,ei_unpointer<float* const >::type >::ret));
+
+ VERIFY(ei_meta_sqrt<1>::ret == 1);
+ #define VERIFY_META_SQRT(X) VERIFY(ei_meta_sqrt<X>::ret == int(ei_sqrt(double(X))))
+ VERIFY_META_SQRT(2);
+ VERIFY_META_SQRT(3);
+ VERIFY_META_SQRT(4);
+ VERIFY_META_SQRT(5);
+ VERIFY_META_SQRT(6);
+ VERIFY_META_SQRT(8);
+ VERIFY_META_SQRT(9);
+ VERIFY_META_SQRT(15);
+ VERIFY_META_SQRT(16);
+ VERIFY_META_SQRT(17);
+ VERIFY_META_SQRT(255);
+ VERIFY_META_SQRT(256);
+ VERIFY_META_SQRT(257);
+ VERIFY_META_SQRT(1023);
+ VERIFY_META_SQRT(1024);
+ VERIFY_META_SQRT(1025);
+}
diff --git a/test/eigen2/eigen2_miscmatrices.cpp b/test/eigen2/eigen2_miscmatrices.cpp
new file mode 100644
index 000000000..8bbb20cc8
--- /dev/null
+++ b/test/eigen2/eigen2_miscmatrices.cpp
@@ -0,0 +1,48 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void miscMatrices(const MatrixType& m)
+{
+ /* this test covers the following files:
+ DiagonalMatrix.h Ones.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ int rows = m.rows();
+ int cols = m.cols();
+
+ int r = ei_random<int>(0, rows-1), r2 = ei_random<int>(0, rows-1), c = ei_random<int>(0, cols-1);
+ VERIFY_IS_APPROX(MatrixType::Ones(rows,cols)(r,c), static_cast<Scalar>(1));
+ MatrixType m1 = MatrixType::Ones(rows,cols);
+ VERIFY_IS_APPROX(m1(r,c), static_cast<Scalar>(1));
+ VectorType v1 = VectorType::Random(rows);
+ v1[0];
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ square = v1.asDiagonal();
+ if(r==r2) VERIFY_IS_APPROX(square(r,r2), v1[r]);
+ else VERIFY_IS_MUCH_SMALLER_THAN(square(r,r2), static_cast<Scalar>(1));
+ square = MatrixType::Zero(rows, rows);
+ square.diagonal() = VectorType::Ones(rows);
+ VERIFY_IS_APPROX(square, MatrixType::Identity(rows, rows));
+}
+
+void test_eigen2_miscmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( miscMatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( miscMatrices(Matrix4d()) );
+ CALL_SUBTEST_3( miscMatrices(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( miscMatrices(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( miscMatrices(MatrixXcd(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_mixingtypes.cpp b/test/eigen2/eigen2_mixingtypes.cpp
new file mode 100644
index 000000000..fb5ac5dda
--- /dev/null
+++ b/test/eigen2/eigen2_mixingtypes.cpp
@@ -0,0 +1,77 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 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 EIGEN_NO_STATIC_ASSERT
+#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
+#endif
+
+#ifndef EIGEN_DONT_VECTORIZE
+#define EIGEN_DONT_VECTORIZE // SSE intrinsics aren't designed to allow mixing types
+#endif
+
+#include "main.h"
+
+
+template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
+{
+ typedef Matrix<float, SizeAtCompileType, SizeAtCompileType> Mat_f;
+ typedef Matrix<double, SizeAtCompileType, SizeAtCompileType> Mat_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, SizeAtCompileType> Mat_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, SizeAtCompileType> Mat_cd;
+ typedef Matrix<float, SizeAtCompileType, 1> Vec_f;
+ typedef Matrix<double, SizeAtCompileType, 1> Vec_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, 1> Vec_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, 1> Vec_cd;
+
+ Mat_f mf(size,size);
+ Mat_d md(size,size);
+ Mat_cf mcf(size,size);
+ Mat_cd mcd(size,size);
+ Vec_f vf(size,1);
+ Vec_d vd(size,1);
+ Vec_cf vcf(size,1);
+ Vec_cd vcd(size,1);
+
+ 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);
+
+ mf*mf;
+ md*mcd;
+ mcd*md;
+ mf*vcf;
+ mcf*vf;
+ mcf *= mf;
+ vcd = md*vcd;
+ vcf = mcf*vf;
+#if 0
+ // these are know generating hard build errors in eigen3
+ VERIFY_RAISES_ASSERT(mf*md);
+ VERIFY_RAISES_ASSERT(mcf*mcd);
+ VERIFY_RAISES_ASSERT(mcf*vcd);
+ VERIFY_RAISES_ASSERT(vcf = mf*vf);
+
+ vf.eigen2_dot(vf);
+ VERIFY_RAISES_ASSERT(vd.eigen2_dot(vf));
+ VERIFY_RAISES_ASSERT(vcf.eigen2_dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h
+ // especially as that might be rewritten as cwise product .sum() which would make that automatic.
+#endif
+}
+
+void test_eigen2_mixingtypes()
+{
+ // check that our operator new is indeed called:
+ CALL_SUBTEST_1(mixingtypes<3>());
+ CALL_SUBTEST_2(mixingtypes<4>());
+ CALL_SUBTEST_3(mixingtypes<Dynamic>(20));
+}
diff --git a/test/eigen2/eigen2_newstdvector.cpp b/test/eigen2/eigen2_newstdvector.cpp
new file mode 100644
index 000000000..5f9009901
--- /dev/null
+++ b/test/eigen2/eigen2_newstdvector.cpp
@@ -0,0 +1,149 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#define EIGEN_USE_NEW_STDVECTOR
+#include "main.h"
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_eigen2_newstdvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Transform2f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3d()));
+ //CALL_SUBTEST(check_stdvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
+}
diff --git a/test/eigen2/eigen2_nomalloc.cpp b/test/eigen2/eigen2_nomalloc.cpp
new file mode 100644
index 000000000..e234abe4b
--- /dev/null
+++ b/test/eigen2/eigen2_nomalloc.cpp
@@ -0,0 +1,63 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2006-2008 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/.
+
+// this hack is needed to make this file compiles with -pedantic (gcc)
+#ifdef __GNUC__
+#define throw(X)
+#endif
+// 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
+
+#include "main.h"
+
+template<typename MatrixType> void nomalloc(const MatrixType& m)
+{
+ /* this test check no dynamic memory allocation are issued with fixed-size matrices
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX(m1.cwise() * m1.block(0,0,rows,cols), m1.cwise() * m1);
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+}
+
+void test_eigen2_nomalloc()
+{
+ // 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>()) );
+ CALL_SUBTEST_2( nomalloc(Matrix4d()) );
+ CALL_SUBTEST_3( nomalloc(Matrix<float,32,32>()) );
+}
diff --git a/test/eigen2/eigen2_packetmath.cpp b/test/eigen2/eigen2_packetmath.cpp
new file mode 100644
index 000000000..b1f325fe7
--- /dev/null
+++ b/test/eigen2/eigen2_packetmath.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+// using namespace Eigen;
+
+template<typename Scalar> bool areApprox(const Scalar* a, const Scalar* b, int size)
+{
+ for (int i=0; i<size; ++i)
+ if (!ei_isApprox(a[i],b[i])) return false;
+ return true;
+}
+
+#define CHECK_CWISE(REFOP, POP) { \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i], data1[i+PacketSize]); \
+ ei_pstore(data2, POP(ei_pload(data1), ei_pload(data1+PacketSize))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+#define REF_ADD(a,b) ((a)+(b))
+#define REF_SUB(a,b) ((a)-(b))
+#define REF_MUL(a,b) ((a)*(b))
+#define REF_DIV(a,b) ((a)/(b))
+
+namespace std {
+
+template<> const complex<float>& min(const complex<float>& a, const complex<float>& b)
+{ return a.real() < b.real() ? a : b; }
+
+template<> const complex<float>& max(const complex<float>& a, const complex<float>& b)
+{ return a.real() < b.real() ? b : a; }
+
+}
+
+template<typename Scalar> void packetmath()
+{
+ typedef typename ei_packet_traits<Scalar>::type Packet;
+ const int PacketSize = ei_packet_traits<Scalar>::size;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN_128 Scalar data1[ei_packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN_128 Scalar data2[ei_packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN_128 Packet packets[PacketSize*2];
+ EIGEN_ALIGN_128 Scalar ref[ei_packet_traits<Scalar>::size*4];
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = ei_random<Scalar>();
+ data2[i] = ei_random<Scalar>();
+ }
+
+ ei_pstore(data2, ei_pload(data1));
+ VERIFY(areApprox(data1, data2, PacketSize) && "aligned load/store");
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ ei_pstore(data2, ei_ploadu(data1+offset));
+ VERIFY(areApprox(data1+offset, data2, PacketSize) && "ei_ploadu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ ei_pstoreu(data2+offset, ei_pload(data1));
+ VERIFY(areApprox(data1, data2+offset, PacketSize) && "ei_pstoreu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ packets[0] = ei_pload(data1);
+ packets[1] = ei_pload(data1+PacketSize);
+ if (offset==0) ei_palign<0>(packets[0], packets[1]);
+ else if (offset==1) ei_palign<1>(packets[0], packets[1]);
+ else if (offset==2) ei_palign<2>(packets[0], packets[1]);
+ else if (offset==3) ei_palign<3>(packets[0], packets[1]);
+ ei_pstore(data2, packets[0]);
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[i+offset];
+
+ typedef Matrix<Scalar, PacketSize, 1> Vector;
+ VERIFY(areApprox(ref, data2, PacketSize) && "ei_palign");
+ }
+
+ CHECK_CWISE(REF_ADD, ei_padd);
+ CHECK_CWISE(REF_SUB, ei_psub);
+ CHECK_CWISE(REF_MUL, ei_pmul);
+ #ifndef EIGEN_VECTORIZE_ALTIVEC
+ if (!ei_is_same_type<Scalar,int>::ret)
+ CHECK_CWISE(REF_DIV, ei_pdiv);
+ #endif
+ CHECK_CWISE(std::min, ei_pmin);
+ CHECK_CWISE(std::max, ei_pmax);
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[0];
+ ei_pstore(data2, ei_pset1(data1[0]));
+ VERIFY(areApprox(ref, data2, PacketSize) && "ei_pset1");
+
+ VERIFY(ei_isApprox(data1[0], ei_pfirst(ei_pload(data1))) && "ei_pfirst");
+
+ ref[0] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] += data1[i];
+ VERIFY(ei_isApprox(ref[0], ei_predux(ei_pload(data1))) && "ei_predux");
+
+ for (int j=0; j<PacketSize; ++j)
+ {
+ ref[j] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[j] += data1[i+j*PacketSize];
+ packets[j] = ei_pload(data1+j*PacketSize);
+ }
+ ei_pstore(data2, ei_preduxp(packets));
+ VERIFY(areApprox(ref, data2, PacketSize) && "ei_preduxp");
+}
+
+void test_eigen2_packetmath()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( packetmath<float>() );
+ CALL_SUBTEST_2( packetmath<double>() );
+ CALL_SUBTEST_3( packetmath<int>() );
+ CALL_SUBTEST_4( packetmath<std::complex<float> >() );
+ }
+}
diff --git a/test/eigen2/eigen2_parametrizedline.cpp b/test/eigen2/eigen2_parametrizedline.cpp
new file mode 100644
index 000000000..814728870
--- /dev/null
+++ b/test/eigen2/eigen2_parametrizedline.cpp
@@ -0,0 +1,62 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename LineType> void parametrizedline(const LineType& _line)
+{
+ /* this test covers the following files:
+ ParametrizedLine.h
+ */
+
+ const int dim = _line.dim();
+ typedef typename LineType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime,
+ LineType::AmbientDimAtCompileTime> MatrixType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType d0 = VectorType::Random(dim).normalized();
+
+ LineType l0(p0, d0);
+
+ Scalar s0 = ei_random<Scalar>();
+ Scalar s1 = ei_abs(ei_random<Scalar>());
+
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0), RealScalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0+s0*d0), RealScalar(1) );
+ VERIFY_IS_APPROX( (l0.projection(p1)-p1).norm(), l0.distance(p1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(l0.projection(p1)), RealScalar(1) );
+ VERIFY_IS_APPROX( Scalar(l0.distance((p0+s0*d0) + d0.unitOrthogonal() * s1)), s1 );
+
+ // casting
+ const int Dim = LineType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ ParametrizedLine<OtherScalar,Dim> hp1f = l0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),l0);
+ ParametrizedLine<Scalar,Dim> hp1d = l0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),l0);
+}
+
+void test_eigen2_parametrizedline()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( parametrizedline(ParametrizedLine<float,2>()) );
+ CALL_SUBTEST_2( parametrizedline(ParametrizedLine<float,3>()) );
+ CALL_SUBTEST_3( parametrizedline(ParametrizedLine<double,4>()) );
+ CALL_SUBTEST_4( parametrizedline(ParametrizedLine<std::complex<double>,5>()) );
+ }
+}
diff --git a/test/eigen2/eigen2_prec_inverse_4x4.cpp b/test/eigen2/eigen2_prec_inverse_4x4.cpp
new file mode 100644
index 000000000..8bfa55694
--- /dev/null
+++ b/test/eigen2/eigen2_prec_inverse_4x4.cpp
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#include "main.h"
+#include <Eigen/LU>
+#include <algorithm>
+
+template<typename T> std::string type_name() { return "other"; }
+template<> std::string type_name<float>() { return "float"; }
+template<> std::string type_name<double>() { return "double"; }
+template<> std::string type_name<int>() { return "int"; }
+template<> std::string type_name<std::complex<float> >() { return "complex<float>"; }
+template<> std::string type_name<std::complex<double> >() { return "complex<double>"; }
+template<> std::string type_name<std::complex<int> >() { return "complex<int>"; }
+
+#define EIGEN_DEBUG_VAR(x) std::cerr << #x << " = " << x << std::endl;
+
+template<typename T> inline typename NumTraits<T>::Real epsilon()
+{
+ return std::numeric_limits<typename NumTraits<T>::Real>::epsilon();
+}
+
+template<typename MatrixType> void inverse_permutation_4x4()
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ Vector4i indices(0,1,2,3);
+ for(int i = 0; i < 24; ++i)
+ {
+ MatrixType m = MatrixType::Zero();
+ m(indices(0),0) = 1;
+ m(indices(1),1) = 1;
+ m(indices(2),2) = 1;
+ m(indices(3),3) = 1;
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() / epsilon<Scalar>() );
+ VERIFY(error == 0.0);
+ std::next_permutation(indices.data(),indices.data()+4);
+ }
+}
+
+template<typename MatrixType> void inverse_general_4x4(int repeat)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ double error_sum = 0., error_max = 0.;
+ for(int i = 0; i < repeat; ++i)
+ {
+ MatrixType m;
+ RealScalar absdet;
+ do {
+ m = MatrixType::Random();
+ absdet = ei_abs(m.determinant());
+ } while(absdet < 10 * epsilon<Scalar>());
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / epsilon<Scalar>() );
+ error_sum += error;
+ error_max = std::max(error_max, error);
+ }
+ std::cerr << "inverse_general_4x4, Scalar = " << type_name<Scalar>() << std::endl;
+ double error_avg = error_sum / repeat;
+ EIGEN_DEBUG_VAR(error_avg);
+ EIGEN_DEBUG_VAR(error_max);
+ VERIFY(error_avg < (NumTraits<Scalar>::IsComplex ? 8.0 : 1.25));
+ VERIFY(error_max < (NumTraits<Scalar>::IsComplex ? 64.0 : 20.0));
+}
+
+void test_eigen2_prec_inverse_4x4()
+{
+ CALL_SUBTEST_1((inverse_permutation_4x4<Matrix4f>()));
+ CALL_SUBTEST_1(( inverse_general_4x4<Matrix4f>(200000 * g_repeat) ));
+
+ CALL_SUBTEST_2((inverse_permutation_4x4<Matrix<double,4,4,RowMajor> >()));
+ CALL_SUBTEST_2(( inverse_general_4x4<Matrix<double,4,4,RowMajor> >(200000 * g_repeat) ));
+
+ CALL_SUBTEST_3((inverse_permutation_4x4<Matrix4cf>()));
+ CALL_SUBTEST_3((inverse_general_4x4<Matrix4cf>(50000 * g_repeat)));
+}
diff --git a/test/eigen2/eigen2_product_large.cpp b/test/eigen2/eigen2_product_large.cpp
new file mode 100644
index 000000000..5149ef748
--- /dev/null
+++ b/test/eigen2/eigen2_product_large.cpp
@@ -0,0 +1,45 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "product.h"
+
+void test_eigen2_product_large()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(MatrixXf(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ CALL_SUBTEST_2( product(MatrixXd(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ CALL_SUBTEST_3( product(MatrixXi(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ CALL_SUBTEST_4( product(MatrixXcf(ei_random<int>(1,50), ei_random<int>(1,50))) );
+ CALL_SUBTEST_5( product(Matrix<float,Dynamic,Dynamic,RowMajor>(ei_random<int>(1,320), ei_random<int>(1,320))) );
+ }
+
+#ifdef EIGEN_TEST_PART_6
+ {
+ // test a specific issue in DiagonalProduct
+ int N = 1000000;
+ VectorXf v = VectorXf::Ones(N);
+ MatrixXf m = MatrixXf::Ones(N,3);
+ m = (v+v).asDiagonal() * m;
+ VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2));
+ }
+
+ {
+ // test deferred resizing in Matrix::operator=
+ MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a;
+ VERIFY_IS_APPROX((a = a * b), (c * b).eval());
+ }
+
+ {
+ MatrixXf mat1(10,10); mat1.setRandom();
+ MatrixXf mat2(32,10); mat2.setRandom();
+ MatrixXf result = mat1.row(2)*mat2.transpose();
+ VERIFY_IS_APPROX(result, (mat1.row(2)*mat2.transpose()).eval());
+ }
+#endif
+}
diff --git a/test/eigen2/eigen2_product_small.cpp b/test/eigen2/eigen2_product_small.cpp
new file mode 100644
index 000000000..4cd8c102f
--- /dev/null
+++ b/test/eigen2/eigen2_product_small.cpp
@@ -0,0 +1,22 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "product.h"
+
+void test_eigen2_product_small()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(Matrix<float, 3, 2>()) );
+ CALL_SUBTEST_2( product(Matrix<int, 3, 5>()) );
+ CALL_SUBTEST_3( product(Matrix3d()) );
+ CALL_SUBTEST_4( product(Matrix4d()) );
+ CALL_SUBTEST_5( product(Matrix4f()) );
+ }
+}
diff --git a/test/eigen2/eigen2_qr.cpp b/test/eigen2/eigen2_qr.cpp
new file mode 100644
index 000000000..76977e4c1
--- /dev/null
+++ b/test/eigen2/eigen2_qr.cpp
@@ -0,0 +1,69 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr(const MatrixType& m)
+{
+ /* this test covers the following files:
+ QR.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ QR<MatrixType> qrOfA(a);
+ VERIFY_IS_APPROX(a, qrOfA.matrixQ() * qrOfA.matrixR());
+ VERIFY_IS_NOT_APPROX(a+MatrixType::Identity(rows, cols), qrOfA.matrixQ() * qrOfA.matrixR());
+
+ #if 0 // eigenvalues module not yet ready
+ SquareMatrixType b = a.adjoint() * a;
+
+ // check tridiagonalization
+ Tridiagonalization<SquareMatrixType> tridiag(b);
+ VERIFY_IS_APPROX(b, tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint());
+
+ // check hessenberg decomposition
+ HessenbergDecomposition<SquareMatrixType> hess(b);
+ VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint());
+ VERIFY_IS_APPROX(tridiag.matrixT(), hess.matrixH());
+ b = SquareMatrixType::Random(cols,cols);
+ hess.compute(b);
+ VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint());
+ #endif
+}
+
+void test_eigen2_qr()
+{
+ for(int i = 0; i < 1; i++) {
+ CALL_SUBTEST_1( qr(Matrix2f()) );
+ CALL_SUBTEST_2( qr(Matrix4d()) );
+ CALL_SUBTEST_3( qr(MatrixXf(12,8)) );
+ CALL_SUBTEST_4( qr(MatrixXcd(5,5)) );
+ CALL_SUBTEST_4( qr(MatrixXcd(7,3)) );
+ }
+
+#ifdef EIGEN_TEST_PART_5
+ // small isFullRank test
+ {
+ Matrix3d mat;
+ mat << 1, 45, 1, 2, 2, 2, 1, 2, 3;
+ VERIFY(mat.qr().isFullRank());
+ mat << 1, 1, 1, 2, 2, 2, 1, 2, 3;
+ //always returns true in eigen2support
+ //VERIFY(!mat.qr().isFullRank());
+ }
+
+#endif
+}
diff --git a/test/eigen2/eigen2_qtvector.cpp b/test/eigen2/eigen2_qtvector.cpp
new file mode 100644
index 000000000..6cfb58a26
--- /dev/null
+++ b/test/eigen2/eigen2_qtvector.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
+// Copyright (C) 2008 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/.
+
+#define EIGEN_WORK_AROUND_QT_BUG_CALLING_WRONG_OPERATOR_NEW_FIXED_IN_QT_4_5
+
+#include "main.h"
+
+#include <Eigen/Geometry>
+#include <Eigen/QtAlignedMalloc>
+
+#include <QtCore/QVector>
+
+template<typename MatrixType>
+void check_qtvector_matrix(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ QVector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], y);
+ }
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_qtvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ QVector<TransformType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_qtvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ QVector<QuaternionType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_eigen2_qtvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_qtvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_qtvector_matrix(Matrix3f()));
+ CALL_SUBTEST_1(check_qtvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_2(check_qtvector_matrix(Matrix2f()));
+ CALL_SUBTEST_2(check_qtvector_matrix(Vector4f()));
+ CALL_SUBTEST_2(check_qtvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_qtvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_qtvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_qtvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_qtvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_qtvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_qtvector_transform(Transform2f()));
+ CALL_SUBTEST_4(check_qtvector_transform(Transform3f()));
+ CALL_SUBTEST_4(check_qtvector_transform(Transform3d()));
+ //CALL_SUBTEST_4(check_qtvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_qtvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_qtvector_quaternion(Quaternionf()));
+}
diff --git a/test/eigen2/eigen2_regression.cpp b/test/eigen2/eigen2_regression.cpp
new file mode 100644
index 000000000..c68b58da8
--- /dev/null
+++ b/test/eigen2/eigen2_regression.cpp
@@ -0,0 +1,136 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/LeastSquares>
+
+template<typename VectorType,
+ typename HyperplaneType>
+void makeNoisyCohyperplanarPoints(int numPoints,
+ VectorType **points,
+ HyperplaneType *hyperplane,
+ typename VectorType::Scalar noiseAmplitude)
+{
+ typedef typename VectorType::Scalar Scalar;
+ const int size = points[0]->size();
+ // pick a random hyperplane, store the coefficients of its equation
+ hyperplane->coeffs().resize(size + 1);
+ for(int j = 0; j < size + 1; j++)
+ {
+ do {
+ hyperplane->coeffs().coeffRef(j) = ei_random<Scalar>();
+ } while(ei_abs(hyperplane->coeffs().coeff(j)) < 0.5);
+ }
+
+ // now pick numPoints random points on this hyperplane
+ for(int i = 0; i < numPoints; i++)
+ {
+ VectorType& cur_point = *(points[i]);
+ do
+ {
+ cur_point = VectorType::Random(size)/*.normalized()*/;
+ // project cur_point onto the hyperplane
+ Scalar x = - (hyperplane->coeffs().start(size).cwise()*cur_point).sum();
+ cur_point *= hyperplane->coeffs().coeff(size) / x;
+ } while( cur_point.norm() < 0.5
+ || cur_point.norm() > 2.0 );
+ }
+
+ // add some noise to these points
+ for(int i = 0; i < numPoints; i++ )
+ *(points[i]) += noiseAmplitude * VectorType::Random(size);
+}
+
+template<typename VectorType>
+void check_linearRegression(int numPoints,
+ VectorType **points,
+ const VectorType& original,
+ typename VectorType::Scalar tolerance)
+{
+ int size = points[0]->size();
+ assert(size==2);
+ VectorType result(size);
+ linearRegression(numPoints, points, &result, 1);
+ typename VectorType::Scalar error = (result - original).norm() / original.norm();
+ VERIFY(ei_abs(error) < ei_abs(tolerance));
+}
+
+template<typename VectorType,
+ typename HyperplaneType>
+void check_fitHyperplane(int numPoints,
+ VectorType **points,
+ const HyperplaneType& original,
+ typename VectorType::Scalar tolerance)
+{
+ int size = points[0]->size();
+ HyperplaneType result(size);
+ fitHyperplane(numPoints, points, &result);
+ result.coeffs() *= original.coeffs().coeff(size)/result.coeffs().coeff(size);
+ typename VectorType::Scalar error = (result.coeffs() - original.coeffs()).norm() / original.coeffs().norm();
+ std::cout << ei_abs(error) << " xxx " << ei_abs(tolerance) << std::endl;
+ VERIFY(ei_abs(error) < ei_abs(tolerance));
+}
+
+void test_eigen2_regression()
+{
+ for(int i = 0; i < g_repeat; i++)
+ {
+#ifdef EIGEN_TEST_PART_1
+ {
+ Vector2f points2f [1000];
+ Vector2f *points2f_ptrs [1000];
+ for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]);
+ Vector2f coeffs2f;
+ Hyperplane<float,2> coeffs3f;
+ makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f);
+ coeffs2f[0] = -coeffs3f.coeffs()[0]/coeffs3f.coeffs()[1];
+ coeffs2f[1] = -coeffs3f.coeffs()[2]/coeffs3f.coeffs()[1];
+ CALL_SUBTEST(check_linearRegression(10, points2f_ptrs, coeffs2f, 0.05f));
+ CALL_SUBTEST(check_linearRegression(100, points2f_ptrs, coeffs2f, 0.01f));
+ CALL_SUBTEST(check_linearRegression(1000, points2f_ptrs, coeffs2f, 0.002f));
+ }
+#endif
+#ifdef EIGEN_TEST_PART_2
+ {
+ Vector2f points2f [1000];
+ Vector2f *points2f_ptrs [1000];
+ for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]);
+ Hyperplane<float,2> coeffs3f;
+ makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f);
+ CALL_SUBTEST(check_fitHyperplane(10, points2f_ptrs, coeffs3f, 0.05f));
+ CALL_SUBTEST(check_fitHyperplane(100, points2f_ptrs, coeffs3f, 0.01f));
+ CALL_SUBTEST(check_fitHyperplane(1000, points2f_ptrs, coeffs3f, 0.002f));
+ }
+#endif
+#ifdef EIGEN_TEST_PART_3
+ {
+ Vector4d points4d [1000];
+ Vector4d *points4d_ptrs [1000];
+ for(int i = 0; i < 1000; i++) points4d_ptrs[i] = &(points4d[i]);
+ Hyperplane<double,4> coeffs5d;
+ makeNoisyCohyperplanarPoints(1000, points4d_ptrs, &coeffs5d, 0.01);
+ CALL_SUBTEST(check_fitHyperplane(10, points4d_ptrs, coeffs5d, 0.05));
+ CALL_SUBTEST(check_fitHyperplane(100, points4d_ptrs, coeffs5d, 0.01));
+ CALL_SUBTEST(check_fitHyperplane(1000, points4d_ptrs, coeffs5d, 0.002));
+ }
+#endif
+#ifdef EIGEN_TEST_PART_4
+ {
+ VectorXcd *points11cd_ptrs[1000];
+ for(int i = 0; i < 1000; i++) points11cd_ptrs[i] = new VectorXcd(11);
+ Hyperplane<std::complex<double>,Dynamic> *coeffs12cd = new Hyperplane<std::complex<double>,Dynamic>(11);
+ makeNoisyCohyperplanarPoints(1000, points11cd_ptrs, coeffs12cd, 0.01);
+ CALL_SUBTEST(check_fitHyperplane(100, points11cd_ptrs, *coeffs12cd, 0.025));
+ CALL_SUBTEST(check_fitHyperplane(1000, points11cd_ptrs, *coeffs12cd, 0.006));
+ delete coeffs12cd;
+ for(int i = 0; i < 1000; i++) delete points11cd_ptrs[i];
+ }
+#endif
+ }
+}
diff --git a/test/eigen2/eigen2_sizeof.cpp b/test/eigen2/eigen2_sizeof.cpp
new file mode 100644
index 000000000..ec1af5a06
--- /dev/null
+++ b/test/eigen2/eigen2_sizeof.cpp
@@ -0,0 +1,31 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+
+template<typename MatrixType> void verifySizeOf(const MatrixType&)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ if (MatrixType::RowsAtCompileTime!=Dynamic && MatrixType::ColsAtCompileTime!=Dynamic)
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar)*MatrixType::SizeAtCompileTime);
+ else
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index));
+}
+
+void test_eigen2_sizeof()
+{
+ CALL_SUBTEST( verifySizeOf(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST( verifySizeOf(Matrix4d()) );
+ CALL_SUBTEST( verifySizeOf(Matrix<double, 4, 2>()) );
+ CALL_SUBTEST( verifySizeOf(Matrix<bool, 7, 5>()) );
+ CALL_SUBTEST( verifySizeOf(MatrixXcf(3, 3)) );
+ CALL_SUBTEST( verifySizeOf(MatrixXi(8, 12)) );
+ CALL_SUBTEST( verifySizeOf(MatrixXcd(20, 20)) );
+ CALL_SUBTEST( verifySizeOf(Matrix<float, 100, 100>()) );
+}
diff --git a/test/eigen2/eigen2_smallvectors.cpp b/test/eigen2/eigen2_smallvectors.cpp
new file mode 100644
index 000000000..03962b17d
--- /dev/null
+++ b/test/eigen2/eigen2_smallvectors.cpp
@@ -0,0 +1,42 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename Scalar> void smallVectors()
+{
+ typedef Matrix<Scalar, 1, 2> V2;
+ typedef Matrix<Scalar, 3, 1> V3;
+ typedef Matrix<Scalar, 1, 4> V4;
+ Scalar x1 = ei_random<Scalar>(),
+ x2 = ei_random<Scalar>(),
+ x3 = ei_random<Scalar>(),
+ x4 = ei_random<Scalar>();
+ V2 v2(x1, x2);
+ V3 v3(x1, x2, x3);
+ V4 v4(x1, x2, x3, x4);
+ VERIFY_IS_APPROX(x1, v2.x());
+ VERIFY_IS_APPROX(x1, v3.x());
+ VERIFY_IS_APPROX(x1, v4.x());
+ VERIFY_IS_APPROX(x2, v2.y());
+ VERIFY_IS_APPROX(x2, v3.y());
+ VERIFY_IS_APPROX(x2, v4.y());
+ VERIFY_IS_APPROX(x3, v3.z());
+ VERIFY_IS_APPROX(x3, v4.z());
+ VERIFY_IS_APPROX(x4, v4.w());
+}
+
+void test_eigen2_smallvectors()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST( smallVectors<int>() );
+ CALL_SUBTEST( smallVectors<float>() );
+ CALL_SUBTEST( smallVectors<double>() );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_basic.cpp b/test/eigen2/eigen2_sparse_basic.cpp
new file mode 100644
index 000000000..049077670
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_basic.cpp
@@ -0,0 +1,317 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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/.
+
+#include "sparse.h"
+
+template<typename SetterType,typename DenseType, typename Scalar, int Options>
+bool test_random_setter(SparseMatrix<Scalar,Options>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
+{
+ typedef SparseMatrix<Scalar,Options> SparseType;
+ {
+ sm.setZero();
+ SetterType w(sm);
+ std::vector<Vector2i> remaining = nonzeroCoords;
+ while(!remaining.empty())
+ {
+ int i = ei_random<int>(0,remaining.size()-1);
+ w(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
+ remaining[i] = remaining.back();
+ remaining.pop_back();
+ }
+ }
+ return sm.isApprox(ref);
+}
+
+template<typename SetterType,typename DenseType, typename T>
+bool test_random_setter(DynamicSparseMatrix<T>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
+{
+ sm.setZero();
+ std::vector<Vector2i> remaining = nonzeroCoords;
+ while(!remaining.empty())
+ {
+ int i = ei_random<int>(0,remaining.size()-1);
+ sm.coeffRef(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
+ remaining[i] = remaining.back();
+ remaining.pop_back();
+ }
+ return sm.isApprox(ref);
+}
+
+template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
+{
+ const int rows = ref.rows();
+ const int cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = std::max(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m(rows, cols);
+ DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
+ DenseVector vec1 = DenseVector::Random(rows);
+ Scalar s1 = ei_random<Scalar>();
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> 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)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
+ if(ei_is_same_type<SparseMatrixType,SparseMatrix<Scalar,Flags> >::ret)
+ VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].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);
+
+ VERIFY_IS_APPROX(m, refMat);
+ /*
+ // test InnerIterators and Block expressions
+ for (int t=0; t<10; ++t)
+ {
+ int j = ei_random<int>(0,cols-1);
+ int i = ei_random<int>(0,rows-1);
+ int w = ei_random<int>(1,cols-j-1);
+ int h = ei_random<int>(1,rows-i-1);
+
+// 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));
+ }
+ }
+// 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 c=0; c<cols; c++)
+ {
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
+ }
+
+ for(int r=0; r<rows; r++)
+ {
+ 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 SparseSetters
+ // coherent setter
+ // TODO extend the MatrixSetter
+// {
+// m.setZero();
+// VERIFY_IS_NOT_APPROX(m, refMat);
+// SparseSetter<SparseMatrixType, FullyCoherentAccessPattern> w(m);
+// for (int i=0; i<nonzeroCoords.size(); ++i)
+// {
+// w->coeffRef(nonzeroCoords[i].x(),nonzeroCoords[i].y()) = refMat.coeff(nonzeroCoords[i].x(),nonzeroCoords[i].y());
+// }
+// }
+// VERIFY_IS_APPROX(m, refMat);
+
+ // random setter
+// {
+// m.setZero();
+// VERIFY_IS_NOT_APPROX(m, refMat);
+// SparseSetter<SparseMatrixType, RandomAccessPattern> w(m);
+// std::vector<Vector2i> remaining = nonzeroCoords;
+// while(!remaining.empty())
+// {
+// int i = ei_random<int>(0,remaining.size()-1);
+// w->coeffRef(remaining[i].x(),remaining[i].y()) = refMat.coeff(remaining[i].x(),remaining[i].y());
+// remaining[i] = remaining.back();
+// remaining.pop_back();
+// }
+// }
+// VERIFY_IS_APPROX(m, refMat);
+
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdMapTraits> >(m,refMat,nonzeroCoords) ));
+ #ifdef EIGEN_UNORDERED_MAP_SUPPORT
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdUnorderedMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+ #ifdef _DENSE_HASH_MAP_H_
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleDenseHashMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+ #ifdef _SPARSE_HASH_MAP_H_
+ VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleSparseHashMapTraits> >(m,refMat,nonzeroCoords) ));
+ #endif
+
+ // test fillrand
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ m2.startFill();
+ for (int j=0; j<cols; ++j)
+ {
+ for (int k=0; k<rows/2; ++k)
+ {
+ int i = ei_random<int>(0,rows-1);
+ if (m1.coeff(i,j)==Scalar(0))
+ m2.fillrand(i,j) = m1(i,j) = ei_random<Scalar>();
+ }
+ }
+ m2.endFill();
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test RandomSetter
+ /*{
+ SparseMatrixType m1(rows,cols), m2(rows,cols);
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
+ initSparse<Scalar>(density, refM1, m1);
+ {
+ Eigen::RandomSetter<SparseMatrixType > setter(m2);
+ for (int j=0; j<m1.outerSize(); ++j)
+ for (typename SparseMatrixType::InnerIterator i(m1,j); i; ++i)
+ setter(i.index(), j) = i.value();
+ }
+ VERIFY_IS_APPROX(m1, m2);
+ }*/
+// std::cerr << m.transpose() << "\n\n" << refMat.transpose() << "\n\n";
+// VERIFY_IS_APPROX(m, refMat);
+
+ // 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);
+ initSparse<Scalar>(density, refM1, m1);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ initSparse<Scalar>(density, refM4, m4);
+
+ VERIFY_IS_APPROX(m1+m2, refM1+refM2);
+ VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
+ VERIFY_IS_APPROX(m3.cwise()*(m1+m2), refM3.cwise()*(refM1+refM2));
+ VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);
+
+ VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
+ VERIFY_IS_APPROX(m1/=s1, refM1/=s1);
+
+ VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
+ VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
+
+ VERIFY_IS_APPROX(m1.col(0).eigen2_dot(refM2.row(0)), refM1.col(0).eigen2_dot(refM2.row(0)));
+
+ refM4.setRandom();
+ // sparse cwise* dense
+ VERIFY_IS_APPROX(m3.cwise()*refM4, refM3.cwise()*refM4);
+// VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
+ }
+
+ // test innerVector()
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = ei_random(0,rows-1);
+ int j1 = ei_random(0,rows-1);
+ VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
+ VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
+ //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);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = ei_random(0,rows-2);
+ int j1 = ei_random(0,rows-2);
+ int n0 = ei_random<int>(1,rows-std::max(j0,j1));
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
+ refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
+ //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
+ //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
+ }
+
+ // test transpose
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
+ VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());
+ }
+
+ // test prune
+ {
+ SparseMatrixType m2(rows, rows);
+ DenseMatrix refM2(rows, rows);
+ refM2.setZero();
+ int countFalseNonZero = 0;
+ int countTrueNonZero = 0;
+ m2.startFill();
+ for (int j=0; j<m2.outerSize(); ++j)
+ for (int i=0; i<m2.innerSize(); ++i)
+ {
+ float x = ei_random<float>(0,1);
+ if (x<0.1)
+ {
+ // do nothing
+ }
+ else if (x<0.5)
+ {
+ countFalseNonZero++;
+ m2.fill(i,j) = Scalar(0);
+ }
+ else
+ {
+ countTrueNonZero++;
+ m2.fill(i,j) = refM2(i,j) = Scalar(1);
+ }
+ }
+ m2.endFill();
+ VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ m2.prune(1);
+ VERIFY(countTrueNonZero==m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ }
+}
+
+void test_eigen2_sparse_basic()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(8, 8)) );
+ CALL_SUBTEST_2( sparse_basic(SparseMatrix<std::complex<double> >(16, 16)) );
+ CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(33, 33)) );
+
+ CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix<double>(8, 8)) );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_product.cpp b/test/eigen2/eigen2_sparse_product.cpp
new file mode 100644
index 000000000..d28e76dff
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_product.cpp
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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/.
+
+#include "sparse.h"
+
+template<typename SparseMatrixType> void sparse_product(const SparseMatrixType& ref)
+{
+ const int rows = ref.rows();
+ const int cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = std::max(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ // test matrix-matrix product
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refMat3 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refMat4 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix dm4 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ SparseMatrixType m4(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ initSparse<Scalar>(density, refMat3, m3);
+ initSparse<Scalar>(density, refMat4, m4);
+ VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(m4=m2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
+ VERIFY_IS_APPROX(m4=m2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
+ VERIFY_IS_APPROX(m4=m2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
+
+ // sparse * dense
+ VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(dm4=m2*refMat3.transpose(), refMat4=refMat2*refMat3.transpose());
+ VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3, refMat4=refMat2.transpose()*refMat3);
+ VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
+
+ // dense * sparse
+ VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(dm4=refMat2*m3.transpose(), refMat4=refMat2*refMat3.transpose());
+ VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3, refMat4=refMat2.transpose()*refMat3);
+ VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose());
+
+ VERIFY_IS_APPROX(m3=m3*m3, refMat3=refMat3*refMat3);
+ }
+
+ // test matrix - diagonal product
+ if(false) // it compiles, but the precision is terrible. probably doesn't matter in this branch....
+ {
+ DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
+ DiagonalMatrix<DenseVector> d1(DenseVector::Random(rows));
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1);
+ VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1);
+ VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2);
+ VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose());
+ }
+
+ // test self adjoint products
+ {
+ DenseMatrix b = DenseMatrix::Random(rows, rows);
+ DenseMatrix x = DenseMatrix::Random(rows, rows);
+ DenseMatrix refX = DenseMatrix::Random(rows, rows);
+ DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refS = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType mUp(rows, rows);
+ SparseMatrixType mLo(rows, rows);
+ SparseMatrixType mS(rows, rows);
+ do {
+ initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
+ } while (refUp.isZero());
+ refLo = refUp.transpose().conjugate();
+ mLo = mUp.transpose().conjugate();
+ refS = refUp + refLo;
+ refS.diagonal() *= 0.5;
+ mS = mUp + mLo;
+ for (int k=0; k<mS.outerSize(); ++k)
+ for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it)
+ if (it.index() == k)
+ it.valueRef() *= 0.5;
+
+ VERIFY_IS_APPROX(refS.adjoint(), refS);
+ VERIFY_IS_APPROX(mS.transpose().conjugate(), mS);
+ VERIFY_IS_APPROX(mS, refS);
+ VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mUp.template marked<UpperTriangular|SelfAdjoint>()*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mLo.template marked<LowerTriangular|SelfAdjoint>()*b, refX=refS*b);
+ VERIFY_IS_APPROX(x=mS.template marked<SelfAdjoint>()*b, refX=refS*b);
+ }
+
+}
+
+void test_eigen2_sparse_product()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_product(SparseMatrix<double>(8, 8)) );
+ CALL_SUBTEST_2( sparse_product(SparseMatrix<std::complex<double> >(16, 16)) );
+ CALL_SUBTEST_1( sparse_product(SparseMatrix<double>(33, 33)) );
+
+ CALL_SUBTEST_3( sparse_product(DynamicSparseMatrix<double>(8, 8)) );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_solvers.cpp b/test/eigen2/eigen2_sparse_solvers.cpp
new file mode 100644
index 000000000..3aef27ab4
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_solvers.cpp
@@ -0,0 +1,200 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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/.
+
+#include "sparse.h"
+
+template<typename Scalar> void
+initSPD(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ SparseMatrix<Scalar>& sparseMat)
+{
+ Matrix<Scalar,Dynamic,Dynamic> aux(refMat.rows(),refMat.cols());
+ initSparse(density,refMat,sparseMat);
+ refMat = refMat * refMat.adjoint();
+ for (int k=0; k<2; ++k)
+ {
+ initSparse(density,aux,sparseMat,ForceNonZeroDiag);
+ refMat += aux * aux.adjoint();
+ }
+ sparseMat.startFill();
+ for (int j=0 ; j<sparseMat.cols(); ++j)
+ for (int i=j ; i<sparseMat.rows(); ++i)
+ if (refMat(i,j)!=Scalar(0))
+ sparseMat.fill(i,j) = refMat(i,j);
+ sparseMat.endFill();
+}
+
+template<typename Scalar> void sparse_solvers(int rows, int cols)
+{
+ double density = std::max(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ // Scalar eps = 1e-6;
+
+ DenseVector vec1 = DenseVector::Random(rows);
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+
+ // test triangular solver
+ {
+ DenseVector vec2 = vec1, vec3 = vec1;
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
+
+ // lower
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().solveTriangular(vec2),
+ m2.template marked<LowerTriangular>().solveTriangular(vec3));
+
+ // lower - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<LowerTriangular>().transpose().solveTriangular(vec2),
+ m2.template marked<LowerTriangular>().transpose().solveTriangular(vec3));
+
+ // upper
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<UpperTriangular>().solveTriangular(vec2),
+ m2.template marked<UpperTriangular>().solveTriangular(vec3));
+
+ // upper - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template marked<UpperTriangular>().transpose().solveTriangular(vec2),
+ m2.template marked<UpperTriangular>().transpose().solveTriangular(vec3));
+ }
+
+ // test LLT
+ {
+ // TODO fix the issue with complex (see SparseLLT::solveInPlace)
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2(rows, cols);
+
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector refX(cols), x(cols);
+
+ initSPD(density, refMat2, m2);
+
+ refMat2.llt().solve(b, &refX);
+ typedef SparseMatrix<Scalar,LowerTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix> (m2).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: default");
+ }
+ #ifdef EIGEN_CHOLMOD_SUPPORT
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Cholmod>(m2).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: cholmod");
+ #endif
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ #ifdef EIGEN_TAUCS_SUPPORT
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,IncompleteFactorization).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (IncompleteFactorization)");
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalMultifrontal).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalMultifrontal)");
+ x = b;
+ SparseLLT<SparseSelfAdjointMatrix,Taucs>(m2,SupernodalLeftLooking).solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LLT: taucs (SupernodalLeftLooking)");
+ #endif
+ }
+ }
+
+ // test LDLT
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ // TODO fix the issue with complex (see SparseLDLT::solveInPlace)
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2(rows, cols);
+
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector refX(cols), x(cols);
+
+ //initSPD(density, refMat2, m2);
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0);
+ refMat2 += refMat2.adjoint();
+ refMat2.diagonal() *= 0.5;
+
+ refMat2.ldlt().solve(b, &refX);
+ typedef SparseMatrix<Scalar,UpperTriangular|SelfAdjoint> SparseSelfAdjointMatrix;
+ x = b;
+ SparseLDLT<SparseSelfAdjointMatrix> ldlt(m2);
+ if (ldlt.succeeded())
+ ldlt.solveInPlace(x);
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LDLT: default");
+ }
+
+ // test LU
+ {
+ static int count = 0;
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2(rows, cols);
+
+ DenseVector b = DenseVector::Random(cols);
+ DenseVector refX(cols), x(cols);
+
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag, &zeroCoords, &nonzeroCoords);
+
+ LU<DenseMatrix> refLu(refMat2);
+ refLu.solve(b, &refX);
+ #if defined(EIGEN_SUPERLU_SUPPORT) || defined(EIGEN_UMFPACK_SUPPORT)
+ Scalar refDet = refLu.determinant();
+ #endif
+ x.setZero();
+ // // SparseLU<SparseMatrix<Scalar> > (m2).solve(b,&x);
+ // // VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: default");
+ #ifdef EIGEN_SUPERLU_SUPPORT
+ {
+ x.setZero();
+ SparseLU<SparseMatrix<Scalar>,SuperLU> slu(m2);
+ if (slu.succeeded())
+ {
+ if (slu.solve(b,&x)) {
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: SuperLU");
+ }
+ // std::cerr << refDet << " == " << slu.determinant() << "\n";
+ if (count==0) {
+ VERIFY_IS_APPROX(refDet,slu.determinant()); // FIXME det is not very stable for complex
+ }
+ }
+ }
+ #endif
+ #ifdef EIGEN_UMFPACK_SUPPORT
+ {
+ // check solve
+ x.setZero();
+ SparseLU<SparseMatrix<Scalar>,UmfPack> slu(m2);
+ if (slu.succeeded()) {
+ if (slu.solve(b,&x)) {
+ if (count==0) {
+ VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LU: umfpack"); // FIXME solve is not very stable for complex
+ }
+ }
+ VERIFY_IS_APPROX(refDet,slu.determinant());
+ // TODO check the extracted data
+ //std::cerr << slu.matrixL() << "\n";
+ }
+ }
+ #endif
+ count++;
+ }
+
+}
+
+void test_eigen2_sparse_solvers()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_solvers<double>(8, 8) );
+ CALL_SUBTEST_2( sparse_solvers<std::complex<double> >(16, 16) );
+ CALL_SUBTEST_1( sparse_solvers<double>(101, 101) );
+ }
+}
diff --git a/test/eigen2/eigen2_sparse_vector.cpp b/test/eigen2/eigen2_sparse_vector.cpp
new file mode 100644
index 000000000..e6d2d77a1
--- /dev/null
+++ b/test/eigen2/eigen2_sparse_vector.cpp
@@ -0,0 +1,84 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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/.
+
+#include "sparse.h"
+
+template<typename Scalar> void sparse_vector(int rows, int cols)
+{
+ double densityMat = std::max(8./(rows*cols), 0.01);
+ double densityVec = std::max(8./float(rows), 0.1);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ typedef SparseVector<Scalar> SparseVectorType;
+ typedef SparseMatrix<Scalar> SparseMatrixType;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m1(rows,cols);
+ SparseVectorType v1(rows), v2(rows), v3(rows);
+ DenseMatrix refM1 = DenseMatrix::Zero(rows, cols);
+ DenseVector refV1 = DenseVector::Random(rows),
+ refV2 = DenseVector::Random(rows),
+ refV3 = DenseVector::Random(rows);
+
+ std::vector<int> zerocoords, nonzerocoords;
+ initSparse<Scalar>(densityVec, refV1, v1, &zerocoords, &nonzerocoords);
+ initSparse<Scalar>(densityMat, refM1, m1);
+
+ initSparse<Scalar>(densityVec, refV2, v2);
+ initSparse<Scalar>(densityVec, refV3, v3);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ // test coeff and coeffRef
+ for (unsigned int i=0; i<zerocoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( v1.coeff(zerocoords[i]), eps );
+ //VERIFY_RAISES_ASSERT( v1.coeffRef(zerocoords[i]) = 5 );
+ }
+ {
+ VERIFY(int(nonzerocoords.size()) == v1.nonZeros());
+ int j=0;
+ for (typename SparseVectorType::InnerIterator it(v1); it; ++it,++j)
+ {
+ VERIFY(nonzerocoords[j]==it.index());
+ VERIFY(it.value()==v1.coeff(it.index()));
+ VERIFY(it.value()==refV1.coeff(it.index()));
+ }
+ }
+ VERIFY_IS_APPROX(v1, refV1);
+
+ v1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ refV1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ VERIFY_IS_APPROX(v1, refV1);
+
+ VERIFY_IS_APPROX(v1+v2, refV1+refV2);
+ VERIFY_IS_APPROX(v1+v2+v3, refV1+refV2+refV3);
+
+ VERIFY_IS_APPROX(v1*s1-v2, refV1*s1-refV2);
+
+ VERIFY_IS_APPROX(v1*=s1, refV1*=s1);
+ VERIFY_IS_APPROX(v1/=s1, refV1/=s1);
+
+ VERIFY_IS_APPROX(v1+=v2, refV1+=refV2);
+ VERIFY_IS_APPROX(v1-=v2, refV1-=refV2);
+
+ VERIFY_IS_APPROX(v1.eigen2_dot(v2), refV1.eigen2_dot(refV2));
+ VERIFY_IS_APPROX(v1.eigen2_dot(refV2), refV1.eigen2_dot(refV2));
+
+}
+
+void test_eigen2_sparse_vector()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_vector<double>(8, 8) );
+ CALL_SUBTEST_2( sparse_vector<std::complex<double> >(16, 16) );
+ CALL_SUBTEST_1( sparse_vector<double>(299, 535) );
+ }
+}
+
diff --git a/test/eigen2/eigen2_stdvector.cpp b/test/eigen2/eigen2_stdvector.cpp
new file mode 100644
index 000000000..6ab05c20a
--- /dev/null
+++ b/test/eigen2/eigen2_stdvector.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 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/.
+
+#include <Eigen/StdVector>
+#include "main.h"
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ int rows = m.rows();
+ int cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType, aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType, aligned_allocator<TransformType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType, aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_eigen2_stdvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Transform2f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Transform3d()));
+ //CALL_SUBTEST_4(check_stdvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+}
diff --git a/test/eigen2/eigen2_submatrices.cpp b/test/eigen2/eigen2_submatrices.cpp
new file mode 100644
index 000000000..c5d3f243d
--- /dev/null
+++ b/test/eigen2/eigen2_submatrices.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+// check minor separately in order to avoid the possible creation of a zero-sized
+// array. Comes from a compilation error with gcc-3.4 or gcc-4 with -ansi -pedantic.
+// Another solution would be to declare the array like this: T m_data[Size==0?1:Size]; in ei_matrix_storage
+// but this is probably not bad to raise such an error at compile time...
+template<typename Scalar, int _Rows, int _Cols> struct CheckMinor
+{
+ typedef Matrix<Scalar, _Rows, _Cols> MatrixType;
+ CheckMinor(MatrixType& m1, int r1, int c1)
+ {
+ int rows = m1.rows();
+ int cols = m1.cols();
+
+ Matrix<Scalar, Dynamic, Dynamic> mi = m1.minor(0,0).eval();
+ VERIFY_IS_APPROX(mi, m1.block(1,1,rows-1,cols-1));
+ mi = m1.minor(r1,c1);
+ VERIFY_IS_APPROX(mi.transpose(), m1.transpose().minor(c1,r1));
+ //check operator(), both constant and non-constant, on minor()
+ m1.minor(r1,c1)(0,0) = m1.minor(0,0)(0,0);
+ }
+};
+
+template<typename Scalar> struct CheckMinor<Scalar,1,1>
+{
+ typedef Matrix<Scalar, 1, 1> MatrixType;
+ CheckMinor(MatrixType&, int, int) {}
+};
+
+template<typename MatrixType> void submatrices(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Row.h Column.h Block.h Minor.h DiagonalCoeffs.h
+ */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ ones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ Scalar s1 = ei_random<Scalar>();
+
+ int r1 = ei_random<int>(0,rows-1);
+ int r2 = ei_random<int>(r1,rows-1);
+ int c1 = ei_random<int>(0,cols-1);
+ int c2 = ei_random<int>(c1,cols-1);
+
+ //check row() and col()
+ VERIFY_IS_APPROX(m1.col(c1).transpose(), m1.transpose().row(c1));
+ VERIFY_IS_APPROX(square.row(r1).eigen2_dot(m1.col(c1)), (square.lazy() * m1.conjugate())(r1,c1));
+ //check operator(), both constant and non-constant, on row() and col()
+ m1.row(r1) += s1 * m1.row(r2);
+ m1.col(c1) += s1 * m1.col(c2);
+
+ //check block()
+ Matrix<Scalar,Dynamic,Dynamic> b1(1,1); b1(0,0) = m1(r1,c1);
+ RowVectorType br1(m1.block(r1,0,1,cols));
+ VectorType bc1(m1.block(0,c1,rows,1));
+ VERIFY_IS_APPROX(b1, m1.block(r1,c1,1,1));
+ VERIFY_IS_APPROX(m1.row(r1), br1);
+ VERIFY_IS_APPROX(m1.col(c1), bc1);
+ //check operator(), both constant and non-constant, on block()
+ m1.block(r1,c1,r2-r1+1,c2-c1+1) = s1 * m2.block(0, 0, r2-r1+1,c2-c1+1);
+ m1.block(r1,c1,r2-r1+1,c2-c1+1)(r2-r1,c2-c1) = m2.block(0, 0, r2-r1+1,c2-c1+1)(0,0);
+
+ //check minor()
+ CheckMinor<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> checkminor(m1,r1,c1);
+
+ //check diagonal()
+ VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal());
+ m2.diagonal() = 2 * m1.diagonal();
+ m2.diagonal()[0] *= 3;
+ VERIFY_IS_APPROX(m2.diagonal()[0], static_cast<Scalar>(6) * m1.diagonal()[0]);
+
+ enum {
+ BlockRows = EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::RowsAtCompileTime,2),
+ BlockCols = EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::ColsAtCompileTime,5)
+ };
+ if (rows>=5 && cols>=8)
+ {
+ // test fixed block() as lvalue
+ m1.template block<BlockRows,BlockCols>(1,1) *= s1;
+ // test operator() on fixed block() both as constant and non-constant
+ m1.template block<BlockRows,BlockCols>(1,1)(0, 3) = m1.template block<2,5>(1,1)(1,2);
+ // check that fixed block() and block() agree
+ Matrix<Scalar,Dynamic,Dynamic> b = m1.template block<BlockRows,BlockCols>(3,3);
+ VERIFY_IS_APPROX(b, m1.block(3,3,BlockRows,BlockCols));
+ }
+
+ if (rows>2)
+ {
+ // test sub vectors
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.block(0,0,2,1));
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.start(2));
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.segment(0,2));
+ VERIFY_IS_APPROX(v1.template start<2>(), v1.template segment<2>(0));
+ int i = rows-2;
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.block(i,0,2,1));
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.end(2));
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.segment(i,2));
+ VERIFY_IS_APPROX(v1.template end<2>(), v1.template segment<2>(i));
+ i = ei_random(0,rows-2);
+ VERIFY_IS_APPROX(v1.segment(i,2), v1.template segment<2>(i));
+ }
+
+ // stress some basic stuffs with block matrices
+ VERIFY(ei_real(ones.col(c1).sum()) == RealScalar(rows));
+ VERIFY(ei_real(ones.row(r1).sum()) == RealScalar(cols));
+
+ VERIFY(ei_real(ones.col(c1).eigen2_dot(ones.col(c2))) == RealScalar(rows));
+ VERIFY(ei_real(ones.row(r1).eigen2_dot(ones.row(r2))) == RealScalar(cols));
+}
+
+void test_eigen2_submatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( submatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( submatrices(Matrix4d()) );
+ CALL_SUBTEST_3( submatrices(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( submatrices(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( submatrices(MatrixXcd(20, 20)) );
+ CALL_SUBTEST_6( submatrices(MatrixXf(20, 20)) );
+ }
+}
diff --git a/test/eigen2/eigen2_sum.cpp b/test/eigen2/eigen2_sum.cpp
new file mode 100644
index 000000000..b47057caa
--- /dev/null
+++ b/test/eigen2/eigen2_sum.cpp
@@ -0,0 +1,71 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void matrixSum(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
+ VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
+ Scalar x = Scalar(0);
+ for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) x += m1(i,j);
+ VERIFY_IS_APPROX(m1.sum(), x);
+}
+
+template<typename VectorType> void vectorSum(const VectorType& w)
+{
+ typedef typename VectorType::Scalar Scalar;
+ int size = w.size();
+
+ VectorType v = VectorType::Random(size);
+ for(int i = 1; i < size; i++)
+ {
+ Scalar s = Scalar(0);
+ for(int j = 0; j < i; j++) s += v[j];
+ VERIFY_IS_APPROX(s, v.start(i).sum());
+ }
+
+ for(int i = 0; i < size-1; i++)
+ {
+ Scalar s = Scalar(0);
+ for(int j = i; j < size; j++) s += v[j];
+ VERIFY_IS_APPROX(s, v.end(size-i).sum());
+ }
+
+ for(int i = 0; i < size/2; i++)
+ {
+ Scalar s = Scalar(0);
+ for(int j = i; j < size-i; j++) s += v[j];
+ VERIFY_IS_APPROX(s, v.segment(i, size-2*i).sum());
+ }
+}
+
+void test_eigen2_sum()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixSum(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixSum(Matrix2f()) );
+ CALL_SUBTEST_3( matrixSum(Matrix4d()) );
+ CALL_SUBTEST_4( matrixSum(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_5( matrixSum(MatrixXf(8, 12)) );
+ CALL_SUBTEST_6( matrixSum(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_5( vectorSum(VectorXf(5)) );
+ CALL_SUBTEST_7( vectorSum(VectorXd(10)) );
+ CALL_SUBTEST_5( vectorSum(VectorXf(33)) );
+ }
+}
diff --git a/test/eigen2/eigen2_svd.cpp b/test/eigen2/eigen2_svd.cpp
new file mode 100644
index 000000000..d4689a56f
--- /dev/null
+++ b/test/eigen2/eigen2_svd.cpp
@@ -0,0 +1,87 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType> void svd(const MatrixType& m)
+{
+ /* this test covers the following files:
+ SVD.h
+ */
+ int rows = m.rows();
+ int cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ MatrixType a = MatrixType::Random(rows,cols);
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> b =
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, 1>::Random(rows,1);
+ Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> x(cols,1), x2(cols,1);
+
+ RealScalar largerEps = test_precision<RealScalar>();
+ if (ei_is_same_type<RealScalar,float>::ret)
+ largerEps = 1e-3f;
+
+ {
+ SVD<MatrixType> svd(a);
+ MatrixType sigma = MatrixType::Zero(rows,cols);
+ MatrixType matU = MatrixType::Zero(rows,rows);
+ sigma.block(0,0,cols,cols) = svd.singularValues().asDiagonal();
+ matU.block(0,0,rows,cols) = svd.matrixU();
+ VERIFY_IS_APPROX(a, matU * sigma * svd.matrixV().transpose());
+ }
+
+
+ if (rows==cols)
+ {
+ if (ei_is_same_type<RealScalar,float>::ret)
+ {
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ a += a * a.adjoint() + a1 * a1.adjoint();
+ }
+ SVD<MatrixType> svd(a);
+ svd.solve(b, &x);
+ VERIFY_IS_APPROX(a * x,b);
+ }
+
+
+ if(rows==cols)
+ {
+ SVD<MatrixType> svd(a);
+ MatrixType unitary, positive;
+ svd.computeUnitaryPositive(&unitary, &positive);
+ VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows()));
+ VERIFY_IS_APPROX(positive, positive.adjoint());
+ for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity
+ VERIFY_IS_APPROX(unitary*positive, a);
+
+ svd.computePositiveUnitary(&positive, &unitary);
+ VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows()));
+ VERIFY_IS_APPROX(positive, positive.adjoint());
+ for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity
+ VERIFY_IS_APPROX(positive*unitary, a);
+ }
+}
+
+void test_eigen2_svd()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( svd(Matrix3f()) );
+ CALL_SUBTEST_2( svd(Matrix4d()) );
+ CALL_SUBTEST_3( svd(MatrixXf(7,7)) );
+ CALL_SUBTEST_4( svd(MatrixXd(14,7)) );
+ // complex are not implemented yet
+// CALL_SUBTEST( svd(MatrixXcd(6,6)) );
+// CALL_SUBTEST( svd(MatrixXcf(3,3)) );
+ SVD<MatrixXf> s;
+ MatrixXf m = MatrixXf::Random(10,1);
+ s.compute(m);
+ }
+}
diff --git a/test/eigen2/eigen2_swap.cpp b/test/eigen2/eigen2_swap.cpp
new file mode 100644
index 000000000..f3a8846d9
--- /dev/null
+++ b/test/eigen2/eigen2_swap.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+
+template<typename T>
+struct other_matrix_type
+{
+ typedef int type;
+};
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct other_matrix_type<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ typedef Matrix<_Scalar, _Rows, _Cols, _Options^RowMajor, _MaxRows, _MaxCols> type;
+};
+
+template<typename MatrixType> void swap(const MatrixType& m)
+{
+ typedef typename other_matrix_type<MatrixType>::type OtherMatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+
+ ei_assert((!ei_is_same_type<MatrixType,OtherMatrixType>::ret));
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // construct 3 matrix guaranteed to be distinct
+ MatrixType m1 = MatrixType::Random(rows,cols);
+ MatrixType m2 = MatrixType::Random(rows,cols) + Scalar(100) * MatrixType::Identity(rows,cols);
+ OtherMatrixType m3 = OtherMatrixType::Random(rows,cols) + Scalar(200) * OtherMatrixType::Identity(rows,cols);
+
+ MatrixType m1_copy = m1;
+ MatrixType m2_copy = m2;
+ OtherMatrixType m3_copy = m3;
+
+ // test swapping 2 matrices of same type
+ m1.swap(m2);
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping 2 matrices of different types
+ m1.swap(m3);
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test swapping matrix with expression
+ m1.swap(m2.block(0,0,rows,cols));
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping two expressions of different types
+ m1.transpose().swap(m3.transpose());
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test assertion on mismatching size -- matrix case
+ VERIFY_RAISES_ASSERT(m1.swap(m1.row(0)));
+ // test assertion on mismatching size -- xpr case
+ VERIFY_RAISES_ASSERT(m1.row(0).swap(m1));
+}
+
+void test_eigen2_swap()
+{
+ CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization
+ CALL_SUBTEST_1( swap(Matrix4d()) ); // fixed size, possible vectorization
+ CALL_SUBTEST_1( swap(MatrixXd(3,3)) ); // dyn size, no vectorization
+ CALL_SUBTEST_1( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization
+}
diff --git a/test/eigen2/eigen2_triangular.cpp b/test/eigen2/eigen2_triangular.cpp
new file mode 100644
index 000000000..3748c7d71
--- /dev/null
+++ b/test/eigen2/eigen2_triangular.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@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/.
+
+#include "main.h"
+
+template<typename MatrixType> void triangular(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ r1(rows, cols),
+ r2(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ mones = MatrixType::Ones(rows, cols),
+ identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Identity(rows, rows),
+ square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ ::Random(rows, rows);
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ MatrixType m1up = m1.template part<Eigen::UpperTriangular>();
+ MatrixType m2up = m2.template part<Eigen::UpperTriangular>();
+
+ if (rows*cols>1)
+ {
+ VERIFY(m1up.isUpperTriangular());
+ VERIFY(m2up.transpose().isLowerTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ }
+
+// VERIFY_IS_APPROX(m1up.transpose() * m2, m1.upper().transpose().lower() * m2);
+
+ // test overloaded operator+=
+ r1.setZero();
+ r2.setZero();
+ r1.template part<Eigen::UpperTriangular>() += m1;
+ r2 += m1up;
+ VERIFY_IS_APPROX(r1,r2);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template part<Eigen::UpperTriangular>() = (m2.transpose() * m2).lazy();
+ m3 = m2.transpose() * m2;
+ VERIFY_IS_APPROX(m3.template part<Eigen::LowerTriangular>().transpose(), m1);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template part<Eigen::LowerTriangular>() = (m2.transpose() * m2).lazy();
+ VERIFY_IS_APPROX(m3.template part<Eigen::LowerTriangular>(), m1);
+
+ VERIFY_IS_APPROX(m3.template part<Diagonal>(), m3.diagonal().asDiagonal());
+
+ m1 = MatrixType::Random(rows, cols);
+ for (int i=0; i<rows; ++i)
+ while (ei_abs2(m1(i,i))<1e-3) m1(i,i) = ei_random<Scalar>();
+
+ Transpose<MatrixType> trm4(m4);
+ // test back and forward subsitution
+ m3 = m1.template part<Eigen::LowerTriangular>();
+ VERIFY(m3.template marked<Eigen::LowerTriangular>().solveTriangular(m3).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ VERIFY(m3.transpose().template marked<Eigen::UpperTriangular>()
+ .solveTriangular(m3.transpose()).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ // check M * inv(L) using in place API
+ m4 = m3;
+ m3.transpose().template marked<Eigen::UpperTriangular>().solveTriangularInPlace(trm4);
+ VERIFY(m4.cwise().abs().isIdentity(test_precision<RealScalar>()));
+
+ m3 = m1.template part<Eigen::UpperTriangular>();
+ VERIFY(m3.template marked<Eigen::UpperTriangular>().solveTriangular(m3).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ VERIFY(m3.transpose().template marked<Eigen::LowerTriangular>()
+ .solveTriangular(m3.transpose()).cwise().abs().isIdentity(test_precision<RealScalar>()));
+ // check M * inv(U) using in place API
+ m4 = m3;
+ m3.transpose().template marked<Eigen::LowerTriangular>().solveTriangularInPlace(trm4);
+ VERIFY(m4.cwise().abs().isIdentity(test_precision<RealScalar>()));
+
+ m3 = m1.template part<Eigen::UpperTriangular>();
+ VERIFY(m2.isApprox(m3 * (m3.template marked<Eigen::UpperTriangular>().solveTriangular(m2)), largerEps));
+ m3 = m1.template part<Eigen::LowerTriangular>();
+ VERIFY(m2.isApprox(m3 * (m3.template marked<Eigen::LowerTriangular>().solveTriangular(m2)), largerEps));
+
+ VERIFY((m1.template part<Eigen::UpperTriangular>() * m2.template part<Eigen::UpperTriangular>()).isUpperTriangular());
+
+ // test swap
+ m1.setOnes();
+ m2.setZero();
+ m2.template part<Eigen::UpperTriangular>().swap(m1);
+ m3.setZero();
+ m3.template part<Eigen::UpperTriangular>().setOnes();
+ VERIFY_IS_APPROX(m2,m3);
+
+}
+
+void selfadjoint()
+{
+ Matrix2i m;
+ m << 1, 2,
+ 3, 4;
+
+ Matrix2i m1 = Matrix2i::Zero();
+ m1.part<SelfAdjoint>() = m;
+ Matrix2i ref1;
+ ref1 << 1, 2,
+ 2, 4;
+ VERIFY(m1 == ref1);
+
+ Matrix2i m2 = Matrix2i::Zero();
+ m2.part<SelfAdjoint>() = m.part<UpperTriangular>();
+ Matrix2i ref2;
+ ref2 << 1, 2,
+ 2, 4;
+ VERIFY(m2 == ref2);
+
+ Matrix2i m3 = Matrix2i::Zero();
+ m3.part<SelfAdjoint>() = m.part<LowerTriangular>();
+ Matrix2i ref3;
+ ref3 << 1, 0,
+ 0, 4;
+ VERIFY(m3 == ref3);
+
+ // example inspired from bug 159
+ int array[] = {1, 2, 3, 4};
+ Matrix2i::Map(array).part<SelfAdjoint>() = Matrix2i::Random().part<LowerTriangular>();
+
+ std::cout << "hello\n" << array << std::endl;
+}
+
+void test_eigen2_triangular()
+{
+ CALL_SUBTEST_8( selfadjoint() );
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( triangular(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( triangular(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( triangular(Matrix3d()) );
+ CALL_SUBTEST_4( triangular(MatrixXcf(4, 4)) );
+ CALL_SUBTEST_5( triangular(Matrix<std::complex<float>,8, 8>()) );
+ CALL_SUBTEST_6( triangular(MatrixXd(17,17)) );
+ CALL_SUBTEST_7( triangular(Matrix<float,Dynamic,Dynamic,RowMajor>(5, 5)) );
+ }
+}
diff --git a/test/eigen2/eigen2_unalignedassert.cpp b/test/eigen2/eigen2_unalignedassert.cpp
new file mode 100644
index 000000000..d10b6f538
--- /dev/null
+++ b/test/eigen2/eigen2_unalignedassert.cpp
@@ -0,0 +1,116 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+struct Good1
+{
+ MatrixXd m; // good: m will allocate its own array, taking care of alignment.
+ Good1() : m(20,20) {}
+};
+
+struct Good2
+{
+ Matrix3d m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be aligned
+};
+
+struct Good3
+{
+ Vector2f m; // good: same reason
+};
+
+struct Bad4
+{
+ Vector2d m; // bad: sizeof(m)%16==0 so alignment is required
+};
+
+struct Bad5
+{
+ Matrix<float, 2, 6> m; // bad: same reason
+};
+
+struct Bad6
+{
+ Matrix<double, 3, 4> m; // bad: same reason
+};
+
+struct Good7
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ Vector2d m;
+ float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects
+};
+
+struct Good8
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ float f; // try the f at first -- the EIGEN_ALIGN_128 attribute of m should make that still work
+ Matrix4f m;
+};
+
+struct Good9
+{
+ Matrix<float,2,2,DontAlign> m; // good: no alignment requested
+ float f;
+};
+
+template<bool Align> struct Depends
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align)
+ Vector2d m;
+ float f;
+};
+
+template<typename T>
+void check_unalignedassert_good()
+{
+ T *x, *y;
+ x = new T;
+ delete x;
+ y = new T[2];
+ delete[] y;
+}
+
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+template<typename T>
+void check_unalignedassert_bad()
+{
+ float buf[sizeof(T)+16];
+ float *unaligned = buf;
+ while((reinterpret_cast<std::size_t>(unaligned)&0xf)==0) ++unaligned; // make sure unaligned is really unaligned
+ T *x = ::new(static_cast<void*>(unaligned)) T;
+ x->~T();
+}
+#endif
+
+void unalignedassert()
+{
+ check_unalignedassert_good<Good1>();
+ check_unalignedassert_good<Good2>();
+ check_unalignedassert_good<Good3>();
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Bad4>());
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Bad5>());
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Bad6>());
+#endif
+
+ check_unalignedassert_good<Good7>();
+ check_unalignedassert_good<Good8>();
+ check_unalignedassert_good<Good9>();
+ check_unalignedassert_good<Depends<true> >();
+
+#if EIGEN_ARCH_WANTS_ALIGNMENT
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Depends<false> >());
+#endif
+}
+
+void test_eigen2_unalignedassert()
+{
+ CALL_SUBTEST(unalignedassert());
+}
diff --git a/test/eigen2/eigen2_visitor.cpp b/test/eigen2/eigen2_visitor.cpp
new file mode 100644
index 000000000..4781991de
--- /dev/null
+++ b/test/eigen2/eigen2_visitor.cpp
@@ -0,0 +1,116 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void matrixVisitor(const MatrixType& p)
+{
+ typedef typename MatrixType::Scalar Scalar;
+
+ int rows = p.rows();
+ int cols = p.cols();
+
+ // construct a random matrix where all coefficients are different
+ MatrixType m;
+ m = MatrixType::Random(rows, cols);
+ for(int i = 0; i < m.size(); i++)
+ for(int i2 = 0; i2 < i; i2++)
+ while(m(i) == m(i2)) // yes, ==
+ m(i) = ei_random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ int minrow=0,mincol=0,maxrow=0,maxcol=0;
+ for(int j = 0; j < cols; j++)
+ for(int i = 0; i < rows; i++)
+ {
+ if(m(i,j) < minc)
+ {
+ minc = m(i,j);
+ minrow = i;
+ mincol = j;
+ }
+ if(m(i,j) > maxc)
+ {
+ maxc = m(i,j);
+ maxrow = i;
+ maxcol = j;
+ }
+ }
+ int eigen_minrow, eigen_mincol, eigen_maxrow, eigen_maxcol;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = m.minCoeff(&eigen_minrow,&eigen_mincol);
+ eigen_maxc = m.maxCoeff(&eigen_maxrow,&eigen_maxcol);
+ VERIFY(minrow == eigen_minrow);
+ VERIFY(maxrow == eigen_maxrow);
+ VERIFY(mincol == eigen_mincol);
+ VERIFY(maxcol == eigen_maxcol);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, m.minCoeff());
+ VERIFY_IS_APPROX(maxc, m.maxCoeff());
+}
+
+template<typename VectorType> void vectorVisitor(const VectorType& w)
+{
+ typedef typename VectorType::Scalar Scalar;
+
+ int size = w.size();
+
+ // construct a random vector where all coefficients are different
+ VectorType v;
+ v = VectorType::Random(size);
+ for(int i = 0; i < size; i++)
+ for(int i2 = 0; i2 < i; i2++)
+ while(v(i) == v(i2)) // yes, ==
+ v(i) = ei_random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ int minidx=0,maxidx=0;
+ for(int i = 0; i < size; i++)
+ {
+ if(v(i) < minc)
+ {
+ minc = v(i);
+ minidx = i;
+ }
+ if(v(i) > maxc)
+ {
+ maxc = v(i);
+ maxidx = i;
+ }
+ }
+ int eigen_minidx, eigen_maxidx;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = v.minCoeff(&eigen_minidx);
+ eigen_maxc = v.maxCoeff(&eigen_maxidx);
+ VERIFY(minidx == eigen_minidx);
+ VERIFY(maxidx == eigen_maxidx);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, v.minCoeff());
+ VERIFY_IS_APPROX(maxc, v.maxCoeff());
+}
+
+void test_eigen2_visitor()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixVisitor(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixVisitor(Matrix2f()) );
+ CALL_SUBTEST_3( matrixVisitor(Matrix4d()) );
+ CALL_SUBTEST_4( matrixVisitor(MatrixXd(8, 12)) );
+ CALL_SUBTEST_5( matrixVisitor(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 20)) );
+ CALL_SUBTEST_6( matrixVisitor(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_7( vectorVisitor(Vector4f()) );
+ CALL_SUBTEST_4( vectorVisitor(VectorXd(10)) );
+ CALL_SUBTEST_4( vectorVisitor(RowVectorXd(10)) );
+ CALL_SUBTEST_8( vectorVisitor(VectorXf(33)) );
+ }
+}
diff --git a/test/eigen2/gsl_helper.h b/test/eigen2/gsl_helper.h
new file mode 100644
index 000000000..d1d854533
--- /dev/null
+++ b/test/eigen2/gsl_helper.h
@@ -0,0 +1,175 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#ifndef EIGEN_GSL_HELPER
+#define EIGEN_GSL_HELPER
+
+#include <Eigen/Core>
+
+#include <gsl/gsl_blas.h>
+#include <gsl/gsl_multifit.h>
+#include <gsl/gsl_eigen.h>
+#include <gsl/gsl_linalg.h>
+#include <gsl/gsl_complex.h>
+#include <gsl/gsl_complex_math.h>
+
+namespace Eigen {
+
+template<typename Scalar, bool IsComplex = NumTraits<Scalar>::IsComplex> struct GslTraits
+{
+ typedef gsl_matrix* Matrix;
+ typedef gsl_vector* Vector;
+ static Matrix createMatrix(int rows, int cols) { return gsl_matrix_alloc(rows,cols); }
+ static Vector createVector(int size) { return gsl_vector_alloc(size); }
+ static void free(Matrix& m) { gsl_matrix_free(m); m=0; }
+ static void free(Vector& m) { gsl_vector_free(m); m=0; }
+ static void prod(const Matrix& m, const Vector& v, Vector& x) { gsl_blas_dgemv(CblasNoTrans,1,m,v,0,x); }
+ static void cholesky(Matrix& m) { gsl_linalg_cholesky_decomp(m); }
+ static void cholesky_solve(const Matrix& m, const Vector& b, Vector& x) { gsl_linalg_cholesky_solve(m,b,x); }
+ static void eigen_symm(const Matrix& m, Vector& eval, Matrix& evec)
+ {
+ gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ gsl_matrix_memcpy(a, m);
+ gsl_eigen_symmv(a,eval,evec,w);
+ gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_symmv_free(w);
+ free(a);
+ }
+ static void eigen_symm_gen(const Matrix& m, const Matrix& _b, Vector& eval, Matrix& evec)
+ {
+ gsl_eigen_gensymmv_workspace * w = gsl_eigen_gensymmv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ Matrix b = createMatrix(_b->size1, _b->size2);
+ gsl_matrix_memcpy(a, m);
+ gsl_matrix_memcpy(b, _b);
+ gsl_eigen_gensymmv(a,b,eval,evec,w);
+ gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_gensymmv_free(w);
+ free(a);
+ }
+};
+
+template<typename Scalar> struct GslTraits<Scalar,true>
+{
+ typedef gsl_matrix_complex* Matrix;
+ typedef gsl_vector_complex* Vector;
+ static Matrix createMatrix(int rows, int cols) { return gsl_matrix_complex_alloc(rows,cols); }
+ static Vector createVector(int size) { return gsl_vector_complex_alloc(size); }
+ static void free(Matrix& m) { gsl_matrix_complex_free(m); m=0; }
+ static void free(Vector& m) { gsl_vector_complex_free(m); m=0; }
+ static void cholesky(Matrix& m) { gsl_linalg_complex_cholesky_decomp(m); }
+ static void cholesky_solve(const Matrix& m, const Vector& b, Vector& x) { gsl_linalg_complex_cholesky_solve(m,b,x); }
+ static void prod(const Matrix& m, const Vector& v, Vector& x)
+ { gsl_blas_zgemv(CblasNoTrans,gsl_complex_rect(1,0),m,v,gsl_complex_rect(0,0),x); }
+ static void eigen_symm(const Matrix& m, gsl_vector* &eval, Matrix& evec)
+ {
+ gsl_eigen_hermv_workspace * w = gsl_eigen_hermv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ gsl_matrix_complex_memcpy(a, m);
+ gsl_eigen_hermv(a,eval,evec,w);
+ gsl_eigen_hermv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_hermv_free(w);
+ free(a);
+ }
+ static void eigen_symm_gen(const Matrix& m, const Matrix& _b, gsl_vector* &eval, Matrix& evec)
+ {
+ gsl_eigen_genhermv_workspace * w = gsl_eigen_genhermv_alloc(m->size1);
+ Matrix a = createMatrix(m->size1, m->size2);
+ Matrix b = createMatrix(_b->size1, _b->size2);
+ gsl_matrix_complex_memcpy(a, m);
+ gsl_matrix_complex_memcpy(b, _b);
+ gsl_eigen_genhermv(a,b,eval,evec,w);
+ gsl_eigen_hermv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC);
+ gsl_eigen_genhermv_free(w);
+ free(a);
+ }
+};
+
+template<typename MatrixType>
+void convert(const MatrixType& m, gsl_matrix* &res)
+{
+// if (res)
+// gsl_matrix_free(res);
+ res = gsl_matrix_alloc(m.rows(), m.cols());
+ for (int i=0 ; i<m.rows() ; ++i)
+ for (int j=0 ; j<m.cols(); ++j)
+ gsl_matrix_set(res, i, j, m(i,j));
+}
+
+template<typename MatrixType>
+void convert(const gsl_matrix* m, MatrixType& res)
+{
+ res.resize(int(m->size1), int(m->size2));
+ for (int i=0 ; i<res.rows() ; ++i)
+ for (int j=0 ; j<res.cols(); ++j)
+ res(i,j) = gsl_matrix_get(m,i,j);
+}
+
+template<typename VectorType>
+void convert(const VectorType& m, gsl_vector* &res)
+{
+ if (res) gsl_vector_free(res);
+ res = gsl_vector_alloc(m.size());
+ for (int i=0 ; i<m.size() ; ++i)
+ gsl_vector_set(res, i, m[i]);
+}
+
+template<typename VectorType>
+void convert(const gsl_vector* m, VectorType& res)
+{
+ res.resize (m->size);
+ for (int i=0 ; i<res.rows() ; ++i)
+ res[i] = gsl_vector_get(m, i);
+}
+
+template<typename MatrixType>
+void convert(const MatrixType& m, gsl_matrix_complex* &res)
+{
+ res = gsl_matrix_complex_alloc(m.rows(), m.cols());
+ for (int i=0 ; i<m.rows() ; ++i)
+ for (int j=0 ; j<m.cols(); ++j)
+ {
+ gsl_matrix_complex_set(res, i, j,
+ gsl_complex_rect(m(i,j).real(), m(i,j).imag()));
+ }
+}
+
+template<typename MatrixType>
+void convert(const gsl_matrix_complex* m, MatrixType& res)
+{
+ res.resize(int(m->size1), int(m->size2));
+ for (int i=0 ; i<res.rows() ; ++i)
+ for (int j=0 ; j<res.cols(); ++j)
+ res(i,j) = typename MatrixType::Scalar(
+ GSL_REAL(gsl_matrix_complex_get(m,i,j)),
+ GSL_IMAG(gsl_matrix_complex_get(m,i,j)));
+}
+
+template<typename VectorType>
+void convert(const VectorType& m, gsl_vector_complex* &res)
+{
+ res = gsl_vector_complex_alloc(m.size());
+ for (int i=0 ; i<m.size() ; ++i)
+ gsl_vector_complex_set(res, i, gsl_complex_rect(m[i].real(), m[i].imag()));
+}
+
+template<typename VectorType>
+void convert(const gsl_vector_complex* m, VectorType& res)
+{
+ res.resize(m->size);
+ for (int i=0 ; i<res.rows() ; ++i)
+ res[i] = typename VectorType::Scalar(
+ GSL_REAL(gsl_vector_complex_get(m, i)),
+ GSL_IMAG(gsl_vector_complex_get(m, i)));
+}
+
+}
+
+#endif // EIGEN_GSL_HELPER
diff --git a/test/eigen2/main.h b/test/eigen2/main.h
new file mode 100644
index 000000000..ad2ba1994
--- /dev/null
+++ b/test/eigen2/main.h
@@ -0,0 +1,399 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 Gael Guennebaud <g.gael@free.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/.
+
+#include <cstdlib>
+#include <ctime>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#ifndef EIGEN_TEST_FUNC
+#error EIGEN_TEST_FUNC must be defined
+#endif
+
+#define DEFAULT_REPEAT 10
+
+namespace Eigen
+{
+ static std::vector<std::string> g_test_stack;
+ static int g_repeat;
+}
+
+#define EI_PP_MAKE_STRING2(S) #S
+#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
+
+#define EI_PP_CAT2(a,b) a ## b
+#define EI_PP_CAT(a,b) EI_PP_CAT2(a,b)
+
+#ifndef EIGEN_NO_ASSERTION_CHECKING
+
+ namespace Eigen
+ {
+ static const bool should_raise_an_assert = false;
+
+ // Used to avoid to raise two exceptions at a time in which
+ // case the exception is not properly caught.
+ // This may happen when a second exceptions is raise in a destructor.
+ static bool no_more_assert = false;
+
+ struct eigen_assert_exception
+ {
+ eigen_assert_exception(void) {}
+ ~eigen_assert_exception() { Eigen::no_more_assert = false; }
+ };
+ }
+
+ // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is raised while
+ // one should have been, then the list of excecuted assertions is printed out.
+ //
+ // EIGEN_DEBUG_ASSERTS is not enabled by default as it
+ // significantly increases the compilation time
+ // and might even introduce side effects that would hide
+ // some memory errors.
+ #ifdef EIGEN_DEBUG_ASSERTS
+
+ namespace Eigen
+ {
+ static bool ei_push_assert = false;
+ static std::vector<std::string> eigen_assert_list;
+ }
+
+ #define eigen_assert(a) \
+ if( (!(a)) && (!no_more_assert) ) \
+ { \
+ Eigen::no_more_assert = true; \
+ throw Eigen::eigen_assert_exception(); \
+ } \
+ else if (Eigen::ei_push_assert) \
+ { \
+ eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__)" ("EI_PP_MAKE_STRING(__LINE__)") : "#a) ); \
+ }
+
+ #define VERIFY_RAISES_ASSERT(a) \
+ { \
+ Eigen::no_more_assert = false; \
+ try { \
+ Eigen::eigen_assert_list.clear(); \
+ Eigen::ei_push_assert = true; \
+ a; \
+ Eigen::ei_push_assert = false; \
+ std::cerr << "One of the following asserts should have been raised:\n"; \
+ for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \
+ std::cerr << " " << eigen_assert_list[ai] << "\n"; \
+ VERIFY(Eigen::should_raise_an_assert && # a); \
+ } catch (Eigen::eigen_assert_exception e) { \
+ Eigen::ei_push_assert = false; VERIFY(true); \
+ } \
+ }
+
+ #else // EIGEN_DEBUG_ASSERTS
+
+ #undef eigen_assert
+
+ // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3
+ #define eigen_assert(a) \
+ if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) ) \
+ { \
+ Eigen::no_more_assert = true; \
+ throw Eigen::eigen_assert_exception(); \
+ }
+
+ #define VERIFY_RAISES_ASSERT(a) { \
+ Eigen::no_more_assert = false; \
+ try { a; VERIFY(Eigen::should_raise_an_assert && # a); } \
+ catch (Eigen::eigen_assert_exception e) { VERIFY(true); } \
+ }
+
+ #endif // EIGEN_DEBUG_ASSERTS
+
+ #define EIGEN_USE_CUSTOM_ASSERT
+
+#else // EIGEN_NO_ASSERTION_CHECKING
+
+ #define VERIFY_RAISES_ASSERT(a) {}
+
+#endif // EIGEN_NO_ASSERTION_CHECKING
+
+
+#define EIGEN_INTERNAL_DEBUGGING
+#define EIGEN_NICE_RANDOM
+#include <Eigen/Array>
+
+
+#define VERIFY(a) do { if (!(a)) { \
+ std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__) << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" \
+ << std::endl << " " << EI_PP_MAKE_STRING(a) << std::endl << std::endl; \
+ abort(); \
+ } } while (0)
+
+#define VERIFY_IS_APPROX(a, b) VERIFY(test_ei_isApprox(a, b))
+#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_ei_isApprox(a, b))
+#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_ei_isMuchSmallerThan(a, b))
+#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_ei_isMuchSmallerThan(a, b))
+#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_ei_isApproxOrLessThan(a, b))
+#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_ei_isApproxOrLessThan(a, b))
+
+#define CALL_SUBTEST(FUNC) do { \
+ g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \
+ FUNC; \
+ g_test_stack.pop_back(); \
+ } while (0)
+
+namespace Eigen {
+
+template<typename T> inline typename NumTraits<T>::Real test_precision();
+template<> inline int test_precision<int>() { return 0; }
+template<> inline float test_precision<float>() { return 1e-3f; }
+template<> inline double test_precision<double>() { return 1e-6; }
+template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
+template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
+template<> inline long double test_precision<long double>() { return 1e-6; }
+
+inline bool test_ei_isApprox(const int& a, const int& b)
+{ return ei_isApprox(a, b, test_precision<int>()); }
+inline bool test_ei_isMuchSmallerThan(const int& a, const int& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<int>()); }
+inline bool test_ei_isApproxOrLessThan(const int& a, const int& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<int>()); }
+
+inline bool test_ei_isApprox(const float& a, const float& b)
+{ return ei_isApprox(a, b, test_precision<float>()); }
+inline bool test_ei_isMuchSmallerThan(const float& a, const float& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<float>()); }
+inline bool test_ei_isApproxOrLessThan(const float& a, const float& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<float>()); }
+
+inline bool test_ei_isApprox(const double& a, const double& b)
+{ return ei_isApprox(a, b, test_precision<double>()); }
+inline bool test_ei_isMuchSmallerThan(const double& a, const double& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<double>()); }
+inline bool test_ei_isApproxOrLessThan(const double& a, const double& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<double>()); }
+
+inline bool test_ei_isApprox(const std::complex<float>& a, const std::complex<float>& b)
+{ return ei_isApprox(a, b, test_precision<std::complex<float> >()); }
+inline bool test_ei_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); }
+
+inline bool test_ei_isApprox(const std::complex<double>& a, const std::complex<double>& b)
+{ return ei_isApprox(a, b, test_precision<std::complex<double> >()); }
+inline bool test_ei_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); }
+
+inline bool test_ei_isApprox(const long double& a, const long double& b)
+{ return ei_isApprox(a, b, test_precision<long double>()); }
+inline bool test_ei_isMuchSmallerThan(const long double& a, const long double& b)
+{ return ei_isMuchSmallerThan(a, b, test_precision<long double>()); }
+inline bool test_ei_isApproxOrLessThan(const long double& a, const long double& b)
+{ return ei_isApproxOrLessThan(a, b, test_precision<long double>()); }
+
+template<typename Type1, typename Type2>
+inline bool test_ei_isApprox(const Type1& a, const Type2& b)
+{
+ return a.isApprox(b, test_precision<typename Type1::Scalar>());
+}
+
+template<typename Derived1, typename Derived2>
+inline bool test_ei_isMuchSmallerThan(const MatrixBase<Derived1>& m1,
+ const MatrixBase<Derived2>& m2)
+{
+ return m1.isMuchSmallerThan(m2, test_precision<typename ei_traits<Derived1>::Scalar>());
+}
+
+template<typename Derived>
+inline bool test_ei_isMuchSmallerThan(const MatrixBase<Derived>& m,
+ const typename NumTraits<typename ei_traits<Derived>::Scalar>::Real& s)
+{
+ return m.isMuchSmallerThan(s, test_precision<typename ei_traits<Derived>::Scalar>());
+}
+
+} // end namespace Eigen
+
+template<typename T> struct GetDifferentType;
+
+template<> struct GetDifferentType<float> { typedef double type; };
+template<> struct GetDifferentType<double> { typedef float type; };
+template<typename T> struct GetDifferentType<std::complex<T> >
+{ typedef std::complex<typename GetDifferentType<T>::type> type; };
+
+// forward declaration of the main test function
+void EI_PP_CAT(test_,EIGEN_TEST_FUNC)();
+
+using namespace Eigen;
+
+#ifdef EIGEN_TEST_PART_1
+#define CALL_SUBTEST_1(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_1(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_2
+#define CALL_SUBTEST_2(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_2(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_3
+#define CALL_SUBTEST_3(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_3(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_4
+#define CALL_SUBTEST_4(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_4(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_5
+#define CALL_SUBTEST_5(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_5(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_6
+#define CALL_SUBTEST_6(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_6(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_7
+#define CALL_SUBTEST_7(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_7(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_8
+#define CALL_SUBTEST_8(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_8(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_9
+#define CALL_SUBTEST_9(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_9(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_10
+#define CALL_SUBTEST_10(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_10(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_11
+#define CALL_SUBTEST_11(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_11(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_12
+#define CALL_SUBTEST_12(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_12(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_13
+#define CALL_SUBTEST_13(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_13(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_14
+#define CALL_SUBTEST_14(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_14(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_15
+#define CALL_SUBTEST_15(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_15(FUNC)
+#endif
+
+#ifdef EIGEN_TEST_PART_16
+#define CALL_SUBTEST_16(FUNC) CALL_SUBTEST(FUNC)
+#else
+#define CALL_SUBTEST_16(FUNC)
+#endif
+
+
+
+int main(int argc, char *argv[])
+{
+ bool has_set_repeat = false;
+ bool has_set_seed = false;
+ bool need_help = false;
+ unsigned int seed = 0;
+ int repeat = DEFAULT_REPEAT;
+
+ for(int i = 1; i < argc; i++)
+ {
+ if(argv[i][0] == 'r')
+ {
+ if(has_set_repeat)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ repeat = std::atoi(argv[i]+1);
+ has_set_repeat = true;
+ if(repeat <= 0)
+ {
+ std::cout << "Invalid \'repeat\' value " << argv[i]+1 << std::endl;
+ return 1;
+ }
+ }
+ else if(argv[i][0] == 's')
+ {
+ if(has_set_seed)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ seed = int(std::strtoul(argv[i]+1, 0, 10));
+ has_set_seed = true;
+ bool ok = seed!=0;
+ if(!ok)
+ {
+ std::cout << "Invalid \'seed\' value " << argv[i]+1 << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ need_help = true;
+ }
+ }
+
+ if(need_help)
+ {
+ std::cout << "This test application takes the following optional arguments:" << std::endl;
+ std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
+ std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl;
+ return 1;
+ }
+
+ if(!has_set_seed) seed = (unsigned int) std::time(NULL);
+ if(!has_set_repeat) repeat = DEFAULT_REPEAT;
+
+ std::cout << "Initializing random number generator with seed " << seed << std::endl;
+ std::srand(seed);
+ std::cout << "Repeating each test " << repeat << " times" << std::endl;
+
+ Eigen::g_repeat = repeat;
+ Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC));
+
+ EI_PP_CAT(test_,EIGEN_TEST_FUNC)();
+ return 0;
+}
+
+
+
diff --git a/test/eigen2/product.h b/test/eigen2/product.h
new file mode 100644
index 000000000..2c9604d9a
--- /dev/null
+++ b/test/eigen2/product.h
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+#include <Eigen/Array>
+#include <Eigen/QR>
+
+template<typename Derived1, typename Derived2>
+bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2, typename Derived1::RealScalar epsilon = precision<typename Derived1::RealScalar>())
+{
+ return !((m1-m2).cwise().abs2().maxCoeff() < epsilon * epsilon
+ * std::max(m1.cwise().abs2().maxCoeff(), m2.cwise().abs2().maxCoeff()));
+}
+
+template<typename MatrixType> void product(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Identity.h Product.h
+ */
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::FloatingPoint FloatingPoint;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RowVectorType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RowSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> ColSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime,
+ MatrixType::Options^RowMajor> OtherMajorMatrixType;
+
+ int rows = m.rows();
+ int cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+ RowSquareMatrixType
+ identity = RowSquareMatrixType::Identity(rows, rows),
+ square = RowSquareMatrixType::Random(rows, rows),
+ res = RowSquareMatrixType::Random(rows, rows);
+ ColSquareMatrixType
+ square2 = ColSquareMatrixType::Random(cols, cols),
+ res2 = ColSquareMatrixType::Random(cols, cols);
+ RowVectorType v1 = RowVectorType::Random(rows),
+ v2 = RowVectorType::Random(rows),
+ vzero = RowVectorType::Zero(rows);
+ ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
+ OtherMajorMatrixType tm1 = m1;
+
+ Scalar s1 = ei_random<Scalar>();
+
+ int r = ei_random<int>(0, rows-1),
+ c = ei_random<int>(0, cols-1);
+
+ // begin testing Product.h: only associativity for now
+ // (we use Transpose.h but this doesn't count as a test for it)
+
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+ m3 = m1;
+ m3 *= m1.transpose() * m2;
+ VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2));
+ VERIFY_IS_APPROX(m3, m1.lazy() * (m1.transpose()*m2));
+
+ // continue testing Product.h: distributivity
+ VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2);
+ VERIFY_IS_APPROX(square*(m1 - m2), square*m1-square*m2);
+
+ // continue testing Product.h: compatibility with ScalarMultiple.h
+ VERIFY_IS_APPROX(s1*(square*m1), (s1*square)*m1);
+ VERIFY_IS_APPROX(s1*(square*m1), square*(m1*s1));
+
+ // again, test operator() to check const-qualification
+ s1 += (square.lazy() * m1)(r,c);
+
+ // test Product.h together with Identity.h
+ VERIFY_IS_APPROX(v1, identity*v1);
+ VERIFY_IS_APPROX(v1.transpose(), v1.transpose() * identity);
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast<Scalar>(r==c));
+
+ if (rows!=cols)
+ VERIFY_RAISES_ASSERT(m3 = m1*m1);
+
+ // test the previous tests were not screwed up because operator* returns 0
+ // (we use the more accurate default epsilon)
+ if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1));
+ }
+
+ // test optimized operator+= path
+ res = square;
+ res += (m1 * m2.transpose()).lazy();
+ VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
+ if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res,square + m2 * m1.transpose()));
+ }
+ vcres = vc2;
+ vcres += (m1.transpose() * v1).lazy();
+ VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1);
+ tm1 = m1;
+ VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1);
+ VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1);
+
+ // test submatrix and matrix/vector product
+ for (int i=0; i<rows; ++i)
+ res.row(i) = m1.row(i) * m2.transpose();
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+ // the other way round:
+ for (int i=0; i<rows; ++i)
+ res.col(i) = m1 * m2.transpose().col(i);
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+
+ res2 = square2;
+ res2 += (m1.transpose() * m2).lazy();
+ VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
+
+ if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1));
+ }
+}
+
diff --git a/test/eigen2/runtest.sh b/test/eigen2/runtest.sh
new file mode 100755
index 000000000..bc693af13
--- /dev/null
+++ b/test/eigen2/runtest.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+black='\E[30m'
+red='\E[31m'
+green='\E[32m'
+yellow='\E[33m'
+blue='\E[34m'
+magenta='\E[35m'
+cyan='\E[36m'
+white='\E[37m'
+
+if make test_$1 > /dev/null 2> .runtest.log ; then
+ if ! ./test_$1 r20 > /dev/null 2> .runtest.log ; then
+ echo -e $red Test $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+ else
+ echo -e $green Test $1 passed$black
+ fi
+else
+ echo -e $red Build of target $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+fi
diff --git a/test/eigen2/sparse.h b/test/eigen2/sparse.h
new file mode 100644
index 000000000..e12f89990
--- /dev/null
+++ b/test/eigen2/sparse.h
@@ -0,0 +1,154 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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 EIGEN_TESTSPARSE_H
+
+#include "main.h"
+
+#if EIGEN_GNUC_AT_LEAST(4,0) && !defined __ICC
+#include <tr1/unordered_map>
+#define EIGEN_UNORDERED_MAP_SUPPORT
+namespace std {
+ using std::tr1::unordered_map;
+}
+#endif
+
+#ifdef EIGEN_GOOGLEHASH_SUPPORT
+ #include <google/sparse_hash_map>
+#endif
+
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+#include <Eigen/Sparse>
+
+enum {
+ ForceNonZeroDiag = 1,
+ MakeLowerTriangular = 2,
+ MakeUpperTriangular = 4,
+ ForceRealDiag = 8
+};
+
+/* Initializes both a sparse and dense matrix with same random values,
+ * and a ratio of \a density non zero entries.
+ * \param flags is a union of ForceNonZeroDiag, MakeLowerTriangular and MakeUpperTriangular
+ * allowing to control the shape of the matrix.
+ * \param zeroCoords and nonzeroCoords allows to get the coordinate lists of the non zero,
+ * and zero coefficients respectively.
+ */
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ SparseMatrix<Scalar>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ sparseMat.startFill(int(refMat.rows()*refMat.cols()*density));
+ for(int j=0; j<refMat.cols(); j++)
+ {
+ for(int i=0; i<refMat.rows(); i++)
+ {
+ Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = ei_random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && j>i)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && j<i)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = ei_real(v);
+
+ if (v!=Scalar(0))
+ {
+ sparseMat.fill(i,j) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(i,j));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(i,j));
+ }
+ refMat(i,j) = v;
+ }
+ }
+ sparseMat.endFill();
+}
+
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ DynamicSparseMatrix<Scalar>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ sparseMat.startFill(int(refMat.rows()*refMat.cols()*density));
+ for(int j=0; j<refMat.cols(); j++)
+ {
+ for(int i=0; i<refMat.rows(); i++)
+ {
+ Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = ei_random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && j>i)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && j<i)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = ei_real(v);
+
+ if (v!=Scalar(0))
+ {
+ sparseMat.fill(i,j) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(i,j));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(i,j));
+ }
+ refMat(i,j) = v;
+ }
+ }
+ sparseMat.endFill();
+}
+
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,1>& refVec,
+ SparseVector<Scalar>& sparseVec,
+ std::vector<int>* zeroCoords = 0,
+ std::vector<int>* nonzeroCoords = 0)
+{
+ sparseVec.reserve(int(refVec.size()*density));
+ sparseVec.setZero();
+ for(int i=0; i<refVec.size(); i++)
+ {
+ Scalar v = (ei_random<double>(0,1) < density) ? ei_random<Scalar>() : Scalar(0);
+ if (v!=Scalar(0))
+ {
+ sparseVec.fill(i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(i);
+ }
+ else if (zeroCoords)
+ zeroCoords->push_back(i);
+ refVec[i] = v;
+ }
+}
+
+#endif // EIGEN_TESTSPARSE_H
diff --git a/test/eigen2/testsuite.cmake b/test/eigen2/testsuite.cmake
new file mode 100644
index 000000000..12b6bfa2e
--- /dev/null
+++ b/test/eigen2/testsuite.cmake
@@ -0,0 +1,197 @@
+
+####################################################################
+#
+# Usage:
+# - create a new folder, let's call it cdash
+# - in that folder, do:
+# ctest -S path/to/eigen2/test/testsuite.cmake[,option1=value1[,option2=value2]]
+#
+# Options:
+# - EIGEN_CXX: compiler, eg.: g++-4.2
+# default: default c++ compiler
+# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc.
+# default: hostname
+# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that:
+# <OS_name>-<OS_version>-<arch>-<compiler-version>
+# with:
+# <OS_name> = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc.
+# <OS_version> = 11.1, XP, vista, leopard, etc.
+# <arch> = i386, x86_64, ia64, powerpc, etc.
+# <compiler-version> = gcc-4.3.2, icc-11.0, MSVC-2008, etc.
+# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec
+# default: SSE2 for x86_64 systems, novec otherwise
+# Its value is automatically appended to EIGEN_BUILD_STRING
+# - EIGEN_CMAKE_DIR: path to cmake executable
+# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous
+# default: Nightly
+# - EIGEN_WORK_DIR: directory used to download the source files and make the builds
+# default: folder which contains this script
+# - EIGEN_CMAKE_ARGS: additional arguments passed to cmake
+# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on)
+# default: <EIGEN_WORK_DIR>/src
+# - CTEST_BINARY_DIRECTORY: build directory
+# default: <EIGEN_WORK_DIR>/nightly-<EIGEN_CXX>
+#
+# Here is an example running several compilers on a linux system:
+# #!/bin/bash
+# ARCH=`uname -m`
+# SITE=`hostname`
+# VERSION=opensuse-11.1
+# WORK_DIR=/home/gael/Coding/eigen2/cdash
+# # get the last version of the script
+# wget http://bitbucket.org/eigen/eigen/raw/tip/test/testsuite.cmake -o $WORK_DIR/testsuite.cmake
+# COMMON="ctest -S $WORK_DIR/testsuite.cmake,EIGEN_WORK_DIR=$WORK_DIR,EIGEN_SITE=$SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$OS_VERSION-$ARCH"
+# $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4
+# $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=novec
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=SSE2
+# $COMMON-icc-11.0,EIGEN_CXX=icpc
+#
+####################################################################
+
+# process the arguments
+
+set(ARGLIST ${CTEST_SCRIPT_ARG})
+while(${ARGLIST} MATCHES ".+.*")
+
+ # pick first
+ string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST})
+ SET(TOP ${CMAKE_MATCH_1})
+
+ # remove first
+ string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST})
+ SET(ARGLIST ${CMAKE_MATCH_1})
+
+ # decompose as a pair key=value
+ string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP})
+ SET(KEY ${CMAKE_MATCH_1})
+
+ string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP})
+ SET(VALUE ${CMAKE_MATCH_1})
+
+ # set the variable to the specified value
+ if(VALUE)
+ SET(${KEY} ${VALUE})
+ else(VALUE)
+ SET(${KEY} ON)
+ endif(VALUE)
+
+endwhile(${ARGLIST} MATCHES ".+.*")
+
+####################################################################
+# Automatically set some user variables if they have not been defined manually
+####################################################################
+cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
+
+if(NOT EIGEN_SITE)
+ site_name(EIGEN_SITE)
+endif(NOT EIGEN_SITE)
+
+if(NOT EIGEN_CMAKE_DIR)
+ SET(EIGEN_CMAKE_DIR "")
+endif(NOT EIGEN_CMAKE_DIR)
+
+if(NOT EIGEN_BUILD_STRING)
+
+ # let's try to find all information we need to make the build string ourself
+
+ # OS
+ build_name(EIGEN_OS_VERSION)
+
+ # arch
+ set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR})
+ if(WIN32)
+ set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE})
+ else(WIN32)
+ execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif(WIN32)
+
+ set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX})
+
+endif(NOT EIGEN_BUILD_STRING)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION})
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(NOT EIGEN_WORK_DIR)
+ set(EIGEN_WORK_DIR ${CTEST_SCRIPT_DIRECTORY})
+endif(NOT EIGEN_WORK_DIR)
+
+if(NOT CTEST_SOURCE_DIRECTORY)
+ SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIR}/src")
+endif(NOT CTEST_SOURCE_DIRECTORY)
+
+if(NOT CTEST_BINARY_DIRECTORY)
+ SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIR}/nightly_${EIGEN_CXX}")
+endif(NOT CTEST_BINARY_DIRECTORY)
+
+if(NOT EIGEN_MODE)
+ set(EIGEN_MODE Nightly)
+endif(NOT EIGEN_MODE)
+
+## mandatory variables (the default should be ok in most cases):
+
+SET (CTEST_CVS_COMMAND "hg")
+SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone -r 2.0 http://bitbucket.org/eigen/eigen \"${CTEST_SOURCE_DIRECTORY}\"")
+
+# which ctest command to use for running the dashboard
+SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}")
+
+# what cmake command to use for configuring this dashboard
+SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_BUILD_TESTS=on ")
+
+####################################################################
+# The values in this section are optional you can either
+# have them or leave them commented out
+####################################################################
+
+# this make sure we get consistent outputs
+SET($ENV{LC_MESSAGES} "en_EN")
+
+# should ctest wipe the binary tree before running
+SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE)
+SET(CTEST_BACKUP_AND_RESTORE TRUE)
+
+# this is the initial cache to use for the binary tree, be careful to escape
+# any quotes inside of this string if you use it
+if(WIN32 AND NOT UNIX)
+ #message(SEND_ERROR "win32")
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake")
+ SET (CTEST_INITIAL_CACHE "
+ MAKECOMMAND:STRING=nmake -i
+ CMAKE_MAKE_PROGRAM:FILEPATH=nmake
+ CMAKE_GENERATOR:INTERNAL=NMake Makefiles
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+else(WIN32 AND NOT UNIX)
+ SET (CTEST_INITIAL_CACHE "
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+endif(WIN32 AND NOT UNIX)
+
+# set any extra environment variables to use during the execution of the script here:
+
+if(EIGEN_CXX)
+ set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}")
+endif(EIGEN_CXX)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON")
+ else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec")
+ endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(DEFINED EIGEN_CMAKE_ARGS)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} ${EIGEN_CMAKE_ARGS}")
+endif(DEFINED EIGEN_CMAKE_ARGS)
diff --git a/test/eigen2support.cpp b/test/eigen2support.cpp
new file mode 100644
index 000000000..7e02bdf5b
--- /dev/null
+++ b/test/eigen2support.cpp
@@ -0,0 +1,64 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 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/.
+
+#define EIGEN2_SUPPORT
+
+#include "main.h"
+
+template<typename MatrixType> void eigen2support(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ // scalar addition
+ VERIFY_IS_APPROX(m1.cwise() + s1, s1 + m1.cwise());
+ VERIFY_IS_APPROX(m1.cwise() + s1, MatrixType::Constant(rows,cols,s1) + m1);
+ VERIFY_IS_APPROX((m1*Scalar(2)).cwise() - s2, (m1+m1) - MatrixType::Constant(rows,cols,s2) );
+ m3 = m1;
+ m3.cwise() += s2;
+ VERIFY_IS_APPROX(m3, m1.cwise() + s2);
+ m3 = m1;
+ m3.cwise() -= s1;
+ VERIFY_IS_APPROX(m3, m1.cwise() - s1);
+
+ VERIFY_IS_EQUAL((m1.corner(TopLeft,1,1)), (m1.block(0,0,1,1)));
+ VERIFY_IS_EQUAL((m1.template corner<1,1>(TopLeft)), (m1.template block<1,1>(0,0)));
+ VERIFY_IS_EQUAL((m1.col(0).start(1)), (m1.col(0).segment(0,1)));
+ VERIFY_IS_EQUAL((m1.col(0).template start<1>()), (m1.col(0).segment(0,1)));
+ VERIFY_IS_EQUAL((m1.col(0).end(1)), (m1.col(0).segment(rows-1,1)));
+ VERIFY_IS_EQUAL((m1.col(0).template end<1>()), (m1.col(0).segment(rows-1,1)));
+
+ using namespace internal;
+ VERIFY_IS_EQUAL(ei_cos(s1), cos(s1));
+ VERIFY_IS_EQUAL(ei_real(s1), real(s1));
+ VERIFY_IS_EQUAL(ei_abs2(s1), abs2(s1));
+
+ m1.minor(0,0);
+}
+
+void test_eigen2support()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eigen2support(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( eigen2support(MatrixXd(1,1)) );
+ CALL_SUBTEST_4( eigen2support(Matrix3f()) );
+ CALL_SUBTEST_5( eigen2support(Matrix4d()) );
+ CALL_SUBTEST_2( eigen2support(MatrixXf(200,200)) );
+ CALL_SUBTEST_6( eigen2support(MatrixXcd(100,100)) );
+ }
+}
diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp
new file mode 100644
index 000000000..0c2059512
--- /dev/null
+++ b/test/eigensolver_complex.cpp
@@ -0,0 +1,115 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+#include <Eigen/LU>
+
+/* Check that two column vectors are approximately equal upto permutations,
+ by checking that the k-th power sums are equal for k = 1, ..., vec1.rows() */
+template<typename VectorType>
+void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2)
+{
+ typedef typename NumTraits<typename VectorType::Scalar>::Real RealScalar;
+
+ VERIFY(vec1.cols() == 1);
+ VERIFY(vec2.cols() == 1);
+ VERIFY(vec1.rows() == vec2.rows());
+ for (int k = 1; k <= vec1.rows(); ++k)
+ {
+ VERIFY_IS_APPROX(vec1.array().pow(RealScalar(k)).sum(), vec2.array().pow(RealScalar(k)).sum());
+ }
+}
+
+
+template<typename MatrixType> void eigensolver(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ ComplexEigenSolver.h, and indirectly ComplexSchur.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a;
+
+ ComplexEigenSolver<MatrixType> ei0(symmA);
+ VERIFY_IS_EQUAL(ei0.info(), Success);
+ VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());
+
+ ComplexEigenSolver<MatrixType> ei1(a);
+ VERIFY_IS_EQUAL(ei1.info(), Success);
+ VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
+ // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus
+ // another algorithm so results may differ slightly
+ verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues());
+
+ ComplexEigenSolver<MatrixType> eiNoEivecs(a, false);
+ VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
+ VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());
+
+ // Regression test for issue #66
+ MatrixType z = MatrixType::Zero(rows,cols);
+ ComplexEigenSolver<MatrixType> eiz(z);
+ VERIFY((eiz.eigenvalues().cwiseEqual(0)).all());
+
+ MatrixType id = MatrixType::Identity(rows, cols);
+ VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
+
+ if (rows > 1)
+ {
+ // Test matrix with NaN
+ a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ ComplexEigenSolver<MatrixType> eiNaN(a);
+ VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence);
+ }
+}
+
+template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m)
+{
+ ComplexEigenSolver<MatrixType> eig;
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+ VERIFY_RAISES_ASSERT(eig.eigenvalues());
+
+ MatrixType a = MatrixType::Random(m.rows(),m.cols());
+ eig.compute(a, false);
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+}
+
+void test_eigensolver_complex()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eigensolver(Matrix4cf()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver(MatrixXcd(s,s)) );
+ CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) );
+ CALL_SUBTEST_4( eigensolver(Matrix3f()) );
+ }
+
+ CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(s,s)) );
+ CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<std::complex<float>, 1, 1>()) );
+ CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) );
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf>(s));
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp
new file mode 100644
index 000000000..0b55ccd93
--- /dev/null
+++ b/test/eigensolver_generic.cpp
@@ -0,0 +1,115 @@
+// 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) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void eigensolver(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ EigenSolver.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+
+ EigenSolver<MatrixType> ei0(symmA);
+ VERIFY_IS_EQUAL(ei0.info(), Success);
+ VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX((symmA.template cast<Complex>()) * (ei0.pseudoEigenvectors().template cast<Complex>()),
+ (ei0.pseudoEigenvectors().template cast<Complex>()) * (ei0.eigenvalues().asDiagonal()));
+
+ EigenSolver<MatrixType> ei1(a);
+ VERIFY_IS_EQUAL(ei1.info(), Success);
+ VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix());
+ VERIFY_IS_APPROX(a.template cast<Complex>() * ei1.eigenvectors(),
+ ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
+ VERIFY_IS_APPROX(ei1.eigenvectors().colwise().norm(), RealVectorType::Ones(rows).transpose());
+ VERIFY_IS_APPROX(a.eigenvalues(), ei1.eigenvalues());
+
+ EigenSolver<MatrixType> eiNoEivecs(a, false);
+ VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
+ VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());
+ VERIFY_IS_APPROX(ei1.pseudoEigenvalueMatrix(), eiNoEivecs.pseudoEigenvalueMatrix());
+
+ MatrixType id = MatrixType::Identity(rows, cols);
+ VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
+
+ if (rows > 2)
+ {
+ // Test matrix with NaN
+ a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ EigenSolver<MatrixType> eiNaN(a);
+ VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence);
+ }
+}
+
+template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m)
+{
+ EigenSolver<MatrixType> eig;
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+ VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors());
+ VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix());
+ VERIFY_RAISES_ASSERT(eig.eigenvalues());
+
+ MatrixType a = MatrixType::Random(m.rows(),m.cols());
+ eig.compute(a, false);
+ VERIFY_RAISES_ASSERT(eig.eigenvectors());
+ VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors());
+}
+
+void test_eigensolver_generic()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eigensolver(Matrix4f()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver(MatrixXd(s,s)) );
+
+ // some trivial but implementation-wise tricky cases
+ CALL_SUBTEST_2( eigensolver(MatrixXd(1,1)) );
+ CALL_SUBTEST_2( eigensolver(MatrixXd(2,2)) );
+ CALL_SUBTEST_3( eigensolver(Matrix<double,1,1>()) );
+ CALL_SUBTEST_4( eigensolver(Matrix2d()) );
+ }
+
+ CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4f()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXd(s,s)) );
+ CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<double,1,1>()) );
+ CALL_SUBTEST_4( eigensolver_verify_assert(Matrix2d()) );
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(EigenSolver<MatrixXf>(s));
+
+ // regression test for bug 410
+ CALL_SUBTEST_2(
+ {
+ MatrixXd A(1,1);
+ A(0,0) = std::sqrt(-1.);
+ Eigen::EigenSolver<MatrixXd> solver(A);
+ MatrixXd V(1, 1);
+ V(0,0) = solver.eigenvectors()(0,0).real();
+ }
+ );
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp
new file mode 100644
index 000000000..02dbdb429
--- /dev/null
+++ b/test/eigensolver_selfadjoint.cpp
@@ -0,0 +1,146 @@
+// 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) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
+ typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ MatrixType a1 = MatrixType::Random(rows,cols);
+ MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
+ symmA.template triangularView<StrictlyUpper>().setZero();
+
+ MatrixType b = MatrixType::Random(rows,cols);
+ MatrixType b1 = MatrixType::Random(rows,cols);
+ MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
+ symmB.template triangularView<StrictlyUpper>().setZero();
+
+ SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
+ SelfAdjointEigenSolver<MatrixType> eiDirect;
+ eiDirect.computeDirect(symmA);
+ // generalized eigen pb
+ GeneralizedSelfAdjointEigenSolver<MatrixType> eiSymmGen(symmA, symmB);
+
+ VERIFY_IS_EQUAL(eiSymm.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * eiSymm.eigenvectors()).isApprox(
+ eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps));
+ VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues());
+
+ VERIFY_IS_EQUAL(eiDirect.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * eiDirect.eigenvectors()).isApprox(
+ eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal(), largerEps));
+ VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiDirect.eigenvalues());
+
+ SelfAdjointEigenSolver<MatrixType> eiSymmNoEivecs(symmA, false);
+ VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success);
+ VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues());
+
+ // generalized eigen problem Ax = lBx
+ eiSymmGen.compute(symmA, symmB,Ax_lBx);
+ VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * eiSymmGen.eigenvectors()).isApprox(
+ symmB.template selfadjointView<Lower>() * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+ // generalized eigen problem BAx = lx
+ eiSymmGen.compute(symmA, symmB,BAx_lx);
+ VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
+ VERIFY((symmB.template selfadjointView<Lower>() * (symmA.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())).isApprox(
+ (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+ // generalized eigen problem ABx = lx
+ eiSymmGen.compute(symmA, symmB,ABx_lx);
+ VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
+ VERIFY((symmA.template selfadjointView<Lower>() * (symmB.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())).isApprox(
+ (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
+
+
+ MatrixType sqrtSymmA = eiSymm.operatorSqrt();
+ VERIFY_IS_APPROX(MatrixType(symmA.template selfadjointView<Lower>()), sqrtSymmA*sqrtSymmA);
+ VERIFY_IS_APPROX(sqrtSymmA, symmA.template selfadjointView<Lower>()*eiSymm.operatorInverseSqrt());
+
+ MatrixType id = MatrixType::Identity(rows, cols);
+ VERIFY_IS_APPROX(id.template selfadjointView<Lower>().operatorNorm(), RealScalar(1));
+
+ SelfAdjointEigenSolver<MatrixType> eiSymmUninitialized;
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.info());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
+
+ eiSymmUninitialized.compute(symmA, false);
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
+ VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
+
+ // test Tridiagonalization's methods
+ Tridiagonalization<MatrixType> tridiag(symmA);
+ // FIXME tridiag.matrixQ().adjoint() does not work
+ VERIFY_IS_APPROX(MatrixType(symmA.template selfadjointView<Lower>()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint());
+
+ if (rows > 1)
+ {
+ // Test matrix with NaN
+ symmA(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ SelfAdjointEigenSolver<MatrixType> eiSymmNaN(symmA);
+ VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence);
+ }
+}
+
+void test_eigensolver_selfadjoint()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ // very important to test 3x3 and 2x2 matrices since we provide special paths for them
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) );
+ CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) );
+ CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_5( selfadjointeigensolver(MatrixXcd(s,s)) );
+
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_9( selfadjointeigensolver(Matrix<std::complex<double>,Dynamic,Dynamic,RowMajor>(s,s)) );
+
+ // some trivial but implementation-wise tricky cases
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(1,1)) );
+ CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(2,2)) );
+ CALL_SUBTEST_6( selfadjointeigensolver(Matrix<double,1,1>()) );
+ CALL_SUBTEST_7( selfadjointeigensolver(Matrix<double,2,2>()) );
+ }
+
+ // Test problem size constructors
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4);
+ CALL_SUBTEST_8(SelfAdjointEigenSolver<MatrixXf>(s));
+ CALL_SUBTEST_8(Tridiagonalization<MatrixXf>(s));
+
+ EIGEN_UNUSED_VARIABLE(s)
+}
+
diff --git a/test/exceptions.cpp b/test/exceptions.cpp
new file mode 100644
index 000000000..8c48b2f7b
--- /dev/null
+++ b/test/exceptions.cpp
@@ -0,0 +1,109 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+
+// Various sanity tests with exceptions:
+// - no memory leak when a custom scalar type trow an exceptions
+// - todo: complete the list of tests!
+
+#define EIGEN_STACK_ALLOCATION_LIMIT 100000000
+
+#include "main.h"
+
+struct my_exception
+{
+ my_exception() {}
+ ~my_exception() {}
+};
+
+class ScalarWithExceptions
+{
+ public:
+ ScalarWithExceptions() { init(); }
+ ScalarWithExceptions(const float& _v) { init(); *v = _v; }
+ ScalarWithExceptions(const ScalarWithExceptions& other) { init(); *v = *(other.v); }
+ ~ScalarWithExceptions() {
+ delete v;
+ instances--;
+ }
+
+ void init() {
+ v = new float;
+ instances++;
+ }
+
+ ScalarWithExceptions operator+(const ScalarWithExceptions& other) const
+ {
+ countdown--;
+ if(countdown<=0)
+ throw my_exception();
+ return ScalarWithExceptions(*v+*other.v);
+ }
+
+ ScalarWithExceptions operator-(const ScalarWithExceptions& other) const
+ { return ScalarWithExceptions(*v-*other.v); }
+
+ ScalarWithExceptions operator*(const ScalarWithExceptions& other) const
+ { return ScalarWithExceptions((*v)*(*other.v)); }
+
+ ScalarWithExceptions& operator+=(const ScalarWithExceptions& other)
+ { *v+=*other.v; return *this; }
+ ScalarWithExceptions& operator-=(const ScalarWithExceptions& other)
+ { *v-=*other.v; return *this; }
+ ScalarWithExceptions& operator=(const ScalarWithExceptions& other)
+ { *v = *(other.v); return *this; }
+
+ bool operator==(const ScalarWithExceptions& other) const
+ { return *v==*other.v; }
+ bool operator!=(const ScalarWithExceptions& other) const
+ { return *v!=*other.v; }
+
+ float* v;
+ static int instances;
+ static int countdown;
+};
+
+int ScalarWithExceptions::instances = 0;
+int ScalarWithExceptions::countdown = 0;
+
+
+#define CHECK_MEMLEAK(OP) { \
+ ScalarWithExceptions::countdown = 100; \
+ int before = ScalarWithExceptions::instances; \
+ bool exception_thrown = false; \
+ try { OP; } \
+ catch (my_exception) { \
+ exception_thrown = true; \
+ VERIFY(ScalarWithExceptions::instances==before && "memory leak detected in " && EIGEN_MAKESTRING(OP)); \
+ } \
+ VERIFY(exception_thrown && " no exception thrown in " && EIGEN_MAKESTRING(OP)); \
+ }
+
+void memoryleak()
+{
+ typedef Eigen::Matrix<ScalarWithExceptions,Dynamic,1> VectorType;
+ typedef Eigen::Matrix<ScalarWithExceptions,Dynamic,Dynamic> MatrixType;
+
+ {
+ int n = 50;
+ VectorType v0(n), v1(n);
+ MatrixType m0(n,n), m1(n,n), m2(n,n);
+ v0.setOnes(); v1.setOnes();
+ m0.setOnes(); m1.setOnes(); m2.setOnes();
+ CHECK_MEMLEAK(v0 = m0 * m1 * v1);
+ CHECK_MEMLEAK(m2 = m0 * m1 * m2);
+ CHECK_MEMLEAK((v0+v1).dot(v0+v1));
+ }
+ VERIFY(ScalarWithExceptions::instances==0 && "global memory leak detected in " && EIGEN_MAKESTRING(OP)); \
+}
+
+void test_exceptions()
+{
+ CALL_SUBTEST( memoryleak() );
+}
diff --git a/test/first_aligned.cpp b/test/first_aligned.cpp
new file mode 100644
index 000000000..467f94510
--- /dev/null
+++ b/test/first_aligned.cpp
@@ -0,0 +1,51 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#include "main.h"
+
+template<typename Scalar>
+void test_first_aligned_helper(Scalar *array, int size)
+{
+ const int packet_size = sizeof(Scalar) * internal::packet_traits<Scalar>::size;
+ VERIFY(((size_t(array) + sizeof(Scalar) * internal::first_aligned(array, size)) % packet_size) == 0);
+}
+
+template<typename Scalar>
+void test_none_aligned_helper(Scalar *array, int size)
+{
+ EIGEN_UNUSED_VARIABLE(array);
+ EIGEN_UNUSED_VARIABLE(size);
+ VERIFY(internal::packet_traits<Scalar>::size == 1 || internal::first_aligned(array, size) == size);
+}
+
+struct some_non_vectorizable_type { float x; };
+
+void test_first_aligned()
+{
+ EIGEN_ALIGN16 float array_float[100];
+ test_first_aligned_helper(array_float, 50);
+ test_first_aligned_helper(array_float+1, 50);
+ test_first_aligned_helper(array_float+2, 50);
+ test_first_aligned_helper(array_float+3, 50);
+ test_first_aligned_helper(array_float+4, 50);
+ test_first_aligned_helper(array_float+5, 50);
+
+ EIGEN_ALIGN16 double array_double[100];
+ test_first_aligned_helper(array_double, 50);
+ test_first_aligned_helper(array_double+1, 50);
+ test_first_aligned_helper(array_double+2, 50);
+
+ double *array_double_plus_4_bytes = (double*)(size_t(array_double)+4);
+ test_none_aligned_helper(array_double_plus_4_bytes, 50);
+ test_none_aligned_helper(array_double_plus_4_bytes+1, 50);
+
+ some_non_vectorizable_type array_nonvec[100];
+ test_first_aligned_helper(array_nonvec, 100);
+ test_none_aligned_helper(array_nonvec, 100);
+}
diff --git a/test/geo_alignedbox.cpp b/test/geo_alignedbox.cpp
new file mode 100644
index 000000000..5886f9181
--- /dev/null
+++ b/test/geo_alignedbox.cpp
@@ -0,0 +1,171 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+#include<iostream>
+using namespace std;
+
+template<typename BoxType> void alignedbox(const BoxType& _box)
+{
+ /* this test covers the following files:
+ AlignedBox.h
+ */
+ typedef typename BoxType::Index Index;
+ typedef typename BoxType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
+
+ const Index dim = _box.dim();
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+ while( p1 == p0 ){
+ p1 = VectorType::Random(dim); }
+ RealScalar s1 = internal::random<RealScalar>(0,1);
+
+ BoxType b0(dim);
+ BoxType b1(VectorType::Random(dim),VectorType::Random(dim));
+ BoxType b2;
+
+ b0.extend(p0);
+ b0.extend(p1);
+ VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));
+
+ (b2 = b0).extend(b1);
+ VERIFY(b2.contains(b0));
+ VERIFY(b2.contains(b1));
+ VERIFY_IS_APPROX(b2.clamp(b0), b0);
+
+
+ // alignment -- make sure there is no memory alignment assertion
+ BoxType *bp0 = new BoxType(dim);
+ BoxType *bp1 = new BoxType(dim);
+ bp0->extend(*bp1);
+ delete bp0;
+ delete bp1;
+
+ // sampling
+ for( int i=0; i<10; ++i )
+ {
+ VectorType r = b0.sample();
+ VERIFY(b0.contains(r));
+ }
+
+}
+
+
+
+template<typename BoxType>
+void alignedboxCastTests(const BoxType& _box)
+{
+ // casting
+ typedef typename BoxType::Index Index;
+ typedef typename BoxType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
+
+ const Index dim = _box.dim();
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ BoxType b0(dim);
+
+ b0.extend(p0);
+ b0.extend(p1);
+
+ const int Dim = BoxType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ AlignedBox<OtherScalar,Dim> hp1f = b0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),b0);
+ AlignedBox<Scalar,Dim> hp1d = b0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),b0);
+}
+
+
+void specificTest1()
+{
+ Vector2f m; m << -1.0f, -2.0f;
+ Vector2f M; M << 1.0f, 5.0f;
+
+ typedef AlignedBox2f BoxType;
+ BoxType box( m, M );
+
+ Vector2f sides = M-m;
+ VERIFY_IS_APPROX(sides, box.sizes() );
+ VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
+ VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
+ VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );
+
+ VERIFY_IS_APPROX( 14.0f, box.volume() );
+ VERIFY_IS_APPROX( 53.0f, box.diagonal().squaredNorm() );
+ VERIFY_IS_APPROX( internal::sqrt( 53.0f ), box.diagonal().norm() );
+
+ VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeft ) );
+ VERIFY_IS_APPROX( M, box.corner( BoxType::TopRight ) );
+ Vector2f bottomRight; bottomRight << M[0], m[1];
+ Vector2f topLeft; topLeft << m[0], M[1];
+ VERIFY_IS_APPROX( bottomRight, box.corner( BoxType::BottomRight ) );
+ VERIFY_IS_APPROX( topLeft, box.corner( BoxType::TopLeft ) );
+}
+
+
+void specificTest2()
+{
+ Vector3i m; m << -1, -2, 0;
+ Vector3i M; M << 1, 5, 3;
+
+ typedef AlignedBox3i BoxType;
+ BoxType box( m, M );
+
+ Vector3i sides = M-m;
+ VERIFY_IS_APPROX(sides, box.sizes() );
+ VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
+ VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
+ VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );
+
+ VERIFY_IS_APPROX( 42, box.volume() );
+ VERIFY_IS_APPROX( 62, box.diagonal().squaredNorm() );
+
+ VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeftFloor ) );
+ VERIFY_IS_APPROX( M, box.corner( BoxType::TopRightCeil ) );
+ Vector3i bottomRightFloor; bottomRightFloor << M[0], m[1], m[2];
+ Vector3i topLeftFloor; topLeftFloor << m[0], M[1], m[2];
+ VERIFY_IS_APPROX( bottomRightFloor, box.corner( BoxType::BottomRightFloor ) );
+ VERIFY_IS_APPROX( topLeftFloor, box.corner( BoxType::TopLeftFloor ) );
+}
+
+
+void test_geo_alignedbox()
+{
+ for(int i = 0; i < g_repeat; i++)
+ {
+ CALL_SUBTEST_1( alignedbox(AlignedBox2f()) );
+ CALL_SUBTEST_2( alignedboxCastTests(AlignedBox2f()) );
+
+ CALL_SUBTEST_3( alignedbox(AlignedBox3f()) );
+ CALL_SUBTEST_4( alignedboxCastTests(AlignedBox3f()) );
+
+ CALL_SUBTEST_5( alignedbox(AlignedBox4d()) );
+ CALL_SUBTEST_6( alignedboxCastTests(AlignedBox4d()) );
+
+ CALL_SUBTEST_7( alignedbox(AlignedBox1d()) );
+ CALL_SUBTEST_8( alignedboxCastTests(AlignedBox1d()) );
+
+ CALL_SUBTEST_9( alignedbox(AlignedBox1i()) );
+ CALL_SUBTEST_10( alignedbox(AlignedBox2i()) );
+ CALL_SUBTEST_11( alignedbox(AlignedBox3i()) );
+ }
+ CALL_SUBTEST_12( specificTest1() );
+ CALL_SUBTEST_13( specificTest2() );
+}
diff --git a/test/geo_eulerangles.cpp b/test/geo_eulerangles.cpp
new file mode 100644
index 000000000..9bf149d2a
--- /dev/null
+++ b/test/geo_eulerangles.cpp
@@ -0,0 +1,54 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar> void eulerangles(void)
+{
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Quaternionx q1;
+ q1 = AngleAxisx(a, Vector3::Random().normalized());
+ Matrix3 m;
+ m = q1;
+
+ #define VERIFY_EULER(I,J,K, X,Y,Z) { \
+ Vector3 ea = m.eulerAngles(I,J,K); \
+ VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
+ }
+ VERIFY_EULER(0,1,2, X,Y,Z);
+ VERIFY_EULER(0,1,0, X,Y,X);
+ VERIFY_EULER(0,2,1, X,Z,Y);
+ VERIFY_EULER(0,2,0, X,Z,X);
+
+ VERIFY_EULER(1,2,0, Y,Z,X);
+ VERIFY_EULER(1,2,1, Y,Z,Y);
+ VERIFY_EULER(1,0,2, Y,X,Z);
+ VERIFY_EULER(1,0,1, Y,X,Y);
+
+ VERIFY_EULER(2,0,1, Z,X,Y);
+ VERIFY_EULER(2,0,2, Z,X,Z);
+ VERIFY_EULER(2,1,0, Z,Y,X);
+ VERIFY_EULER(2,1,2, Z,Y,Z);
+}
+
+void test_geo_eulerangles()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( eulerangles<float>() );
+ CALL_SUBTEST_2( eulerangles<double>() );
+ }
+}
diff --git a/test/geo_homogeneous.cpp b/test/geo_homogeneous.cpp
new file mode 100644
index 000000000..c91bde819
--- /dev/null
+++ b/test/geo_homogeneous.cpp
@@ -0,0 +1,103 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+
+template<typename Scalar,int Size> void homogeneous(void)
+{
+ /* this test covers the following files:
+ Homogeneous.h
+ */
+
+ typedef Matrix<Scalar,Size,Size> MatrixType;
+ typedef Matrix<Scalar,Size,1, ColMajor> VectorType;
+
+ typedef Matrix<Scalar,Size+1,Size> HMatrixType;
+ typedef Matrix<Scalar,Size+1,1> HVectorType;
+
+ typedef Matrix<Scalar,Size,Size+1> T1MatrixType;
+ typedef Matrix<Scalar,Size+1,Size+1> T2MatrixType;
+ typedef Matrix<Scalar,Size+1,Size> T3MatrixType;
+
+ VectorType v0 = VectorType::Random(),
+ ones = VectorType::Ones();
+
+ HVectorType hv0 = HVectorType::Random();
+
+ MatrixType m0 = MatrixType::Random();
+
+ HMatrixType hm0 = HMatrixType::Random();
+
+ hv0 << v0, 1;
+ VERIFY_IS_APPROX(v0.homogeneous(), hv0);
+ VERIFY_IS_APPROX(v0, hv0.hnormalized());
+
+ hm0 << m0, ones.transpose();
+ VERIFY_IS_APPROX(m0.colwise().homogeneous(), hm0);
+ VERIFY_IS_APPROX(m0, hm0.colwise().hnormalized());
+ hm0.row(Size-1).setRandom();
+ for(int j=0; j<Size; ++j)
+ m0.col(j) = hm0.col(j).head(Size) / hm0(Size,j);
+ VERIFY_IS_APPROX(m0, hm0.colwise().hnormalized());
+
+ T1MatrixType t1 = T1MatrixType::Random();
+ VERIFY_IS_APPROX(t1 * (v0.homogeneous().eval()), t1 * v0.homogeneous());
+ VERIFY_IS_APPROX(t1 * (m0.colwise().homogeneous().eval()), t1 * m0.colwise().homogeneous());
+
+ T2MatrixType t2 = T2MatrixType::Random();
+ VERIFY_IS_APPROX(t2 * (v0.homogeneous().eval()), t2 * v0.homogeneous());
+ VERIFY_IS_APPROX(t2 * (m0.colwise().homogeneous().eval()), t2 * m0.colwise().homogeneous());
+
+ 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);
+
+ T3MatrixType t3 = T3MatrixType::Random();
+ VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t3,
+ v0.transpose().rowwise().homogeneous() * t3);
+ VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t3,
+ m0.transpose().rowwise().homogeneous() * t3);
+
+ // test product with a Transform object
+ Transform<Scalar, Size, Affine> aff;
+ Transform<Scalar, Size, AffineCompact> caff;
+ Transform<Scalar, Size, Projective> proj;
+ Matrix<Scalar, Size, Dynamic> pts;
+ Matrix<Scalar, Size+1, Dynamic> pts1, pts2;
+
+ aff.affine().setRandom();
+ proj = caff = aff;
+ pts.setRandom(Size,internal::random<int>(1,20));
+
+ pts1 = pts.colwise().homogeneous();
+ 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);
+
+ pts2 = pts1;
+ pts2.row(Size).setRandom();
+ VERIFY_IS_APPROX((aff * pts2).colwise().hnormalized(), aff * pts2.colwise().hnormalized());
+ VERIFY_IS_APPROX((caff * pts2).colwise().hnormalized(), caff * pts2.colwise().hnormalized());
+ VERIFY_IS_APPROX((proj * pts2).colwise().hnormalized(), (proj * pts2.colwise().hnormalized().colwise().homogeneous()).colwise().hnormalized());
+}
+
+void test_geo_homogeneous()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( homogeneous<float,1>() ));
+ CALL_SUBTEST_2(( homogeneous<double,3>() ));
+ CALL_SUBTEST_3(( homogeneous<double,8>() ));
+ }
+}
diff --git a/test/geo_hyperplane.cpp b/test/geo_hyperplane.cpp
new file mode 100644
index 000000000..3fc80c4c7
--- /dev/null
+++ b/test/geo_hyperplane.cpp
@@ -0,0 +1,157 @@
+// 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 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
+{
+ /* this test covers the following files:
+ Hyperplane.h
+ */
+ typedef typename HyperplaneType::Index Index;
+ const Index dim = _plane.dim();
+ enum { Options = HyperplaneType::Options };
+ typedef typename HyperplaneType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime,
+ HyperplaneType::AmbientDimAtCompileTime> MatrixType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType n0 = VectorType::Random(dim).normalized();
+ VectorType n1 = VectorType::Random(dim).normalized();
+
+ HyperplaneType pl0(n0, p0);
+ HyperplaneType pl1(n1, p1);
+ HyperplaneType pl2 = pl1;
+
+ Scalar s0 = internal::random<Scalar>();
+ Scalar s1 = internal::random<Scalar>();
+
+ VERIFY_IS_APPROX( n1.dot(n1), Scalar(1) );
+
+ VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) );
+ VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1) );
+
+ // transform
+ if (!NumTraits<Scalar>::IsComplex)
+ {
+ MatrixType rot = MatrixType::Random(dim,dim).householderQr().householderQ();
+ DiagonalMatrix<Scalar,HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
+ Translation<Scalar,HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());
+
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
+ .absDistance((rot*scaling*translation) * p1), Scalar(1) );
+ pl2 = pl1;
+ VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
+ .absDistance((rot*translation) * p1), Scalar(1) );
+ }
+
+ // casting
+ const int Dim = HyperplaneType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ Hyperplane<OtherScalar,Dim,Options> hp1f = pl1.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),pl1);
+ Hyperplane<Scalar,Dim,Options> hp1d = pl1.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),pl1);
+}
+
+template<typename Scalar> void lines()
+{
+ typedef Hyperplane<Scalar, 2> HLine;
+ typedef ParametrizedLine<Scalar, 2> PLine;
+ typedef Matrix<Scalar,2,1> Vector;
+ typedef Matrix<Scalar,3,1> CoeffsType;
+
+ for(int i = 0; i < 10; i++)
+ {
+ Vector center = Vector::Random();
+ Vector u = Vector::Random();
+ Vector v = Vector::Random();
+ Scalar a = internal::random<Scalar>();
+ while (internal::abs(a-1) < 1e-4) a = internal::random<Scalar>();
+ while (u.norm() < 1e-4) u = Vector::Random();
+ while (v.norm() < 1e-4) v = Vector::Random();
+
+ HLine line_u = HLine::Through(center + u, center + a*u);
+ HLine line_v = HLine::Through(center + v, center + a*v);
+
+ // the line equations should be normalized so that a^2+b^2=1
+ VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
+ VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));
+
+ Vector result = line_u.intersection(line_v);
+
+ // the lines should intersect at the point we called "center"
+ VERIFY_IS_APPROX(result, center);
+
+ // check conversions between two types of lines
+ PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable
+ CoeffsType converted_coeffs = HLine(pl).coeffs();
+ converted_coeffs *= (line_u.coeffs()[0])/(converted_coeffs[0]);
+ VERIFY(line_u.coeffs().isApprox(converted_coeffs));
+ }
+}
+
+template<typename Scalar> void hyperplane_alignment()
+{
+ typedef Hyperplane<Scalar,3,AutoAlign> Plane3a;
+ typedef Hyperplane<Scalar,3,DontAlign> Plane3u;
+
+ EIGEN_ALIGN16 Scalar array1[4];
+ EIGEN_ALIGN16 Scalar array2[4];
+ EIGEN_ALIGN16 Scalar array3[4+1];
+ Scalar* array3u = array3+1;
+
+ Plane3a *p1 = ::new(reinterpret_cast<void*>(array1)) Plane3a;
+ Plane3u *p2 = ::new(reinterpret_cast<void*>(array2)) Plane3u;
+ Plane3u *p3 = ::new(reinterpret_cast<void*>(array3u)) Plane3u;
+
+ p1->coeffs().setRandom();
+ *p2 = *p1;
+ *p3 = *p1;
+
+ VERIFY_IS_APPROX(p1->coeffs(), p2->coeffs());
+ VERIFY_IS_APPROX(p1->coeffs(), p3->coeffs());
+
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Plane3a));
+ #endif
+}
+
+
+void test_geo_hyperplane()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( hyperplane(Hyperplane<float,2>()) );
+ CALL_SUBTEST_2( hyperplane(Hyperplane<float,3>()) );
+ CALL_SUBTEST_2( hyperplane(Hyperplane<float,3,DontAlign>()) );
+ CALL_SUBTEST_2( hyperplane_alignment<float>() );
+ CALL_SUBTEST_3( hyperplane(Hyperplane<double,4>()) );
+ CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
+ CALL_SUBTEST_1( lines<float>() );
+ CALL_SUBTEST_3( lines<double>() );
+ }
+}
diff --git a/test/geo_orthomethods.cpp b/test/geo_orthomethods.cpp
new file mode 100644
index 000000000..c836dae40
--- /dev/null
+++ b/test/geo_orthomethods.cpp
@@ -0,0 +1,121 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+/* this test covers the following files:
+ Geometry/OrthoMethods.h
+*/
+
+template<typename Scalar> void orthomethods_3()
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+
+ typedef Matrix<Scalar,4,1> Vector4;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random();
+
+ // cross product
+ VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v1), Scalar(1));
+ 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));
+ Matrix3 mat3;
+ mat3 << v0.normalized(),
+ (v0.cross(v1)).normalized(),
+ (v0.cross(v1).cross(v0)).normalized();
+ VERIFY(mat3.isUnitary());
+
+
+ // colwise/rowwise cross product
+ mat3.setRandom();
+ Vector3 vec3 = Vector3::Random();
+ Matrix3 mcross;
+ int i = internal::random<int>(0,2);
+ mcross = mat3.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
+ mcross = mat3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
+
+ // cross3
+ Vector4 v40 = Vector4::Random(),
+ v41 = Vector4::Random(),
+ v42 = Vector4::Random();
+ 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);
+
+ // check mixed product
+ typedef Matrix<RealScalar, 3, 1> RealVector3;
+ RealVector3 rv1 = RealVector3::Random();
+ VERIFY_IS_APPROX(v1.cross(rv1.template cast<Scalar>()), v1.cross(rv1));
+ VERIFY_IS_APPROX(rv1.template cast<Scalar>().cross(v1), rv1.cross(v1));
+}
+
+template<typename Scalar, int Size> void orthomethods(int size=Size)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar,Size,1> VectorType;
+ typedef Matrix<Scalar,3,Size> Matrix3N;
+ typedef Matrix<Scalar,Size,3> MatrixN3;
+ typedef Matrix<Scalar,3,1> Vector3;
+
+ VectorType v0 = VectorType::Random(size);
+
+ // unitOrthogonal
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
+
+ if (size>=3)
+ {
+ v0.template head<2>().setZero();
+ v0.tail(size-2).setRandom();
+
+ VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
+ VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
+ }
+
+ // colwise/rowwise cross product
+ Vector3 vec3 = Vector3::Random();
+ int i = internal::random<int>(0,size-1);
+
+ Matrix3N mat3N(3,size), mcross3N(3,size);
+ mat3N.setRandom();
+ mcross3N = mat3N.colwise().cross(vec3);
+ VERIFY_IS_APPROX(mcross3N.col(i), mat3N.col(i).cross(vec3));
+
+ MatrixN3 matN3(size,3), mcrossN3(size,3);
+ matN3.setRandom();
+ mcrossN3 = matN3.rowwise().cross(vec3);
+ VERIFY_IS_APPROX(mcrossN3.row(i), matN3.row(i).cross(vec3));
+}
+
+void test_geo_orthomethods()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( orthomethods_3<float>() );
+ CALL_SUBTEST_2( orthomethods_3<double>() );
+ CALL_SUBTEST_4( orthomethods_3<std::complex<double> >() );
+ CALL_SUBTEST_1( (orthomethods<float,2>()) );
+ CALL_SUBTEST_2( (orthomethods<double,2>()) );
+ CALL_SUBTEST_1( (orthomethods<float,3>()) );
+ CALL_SUBTEST_2( (orthomethods<double,3>()) );
+ CALL_SUBTEST_3( (orthomethods<float,7>()) );
+ CALL_SUBTEST_4( (orthomethods<std::complex<double>,8>()) );
+ CALL_SUBTEST_5( (orthomethods<float,Dynamic>(36)) );
+ CALL_SUBTEST_6( (orthomethods<double,Dynamic>(35)) );
+ }
+}
diff --git a/test/geo_parametrizedline.cpp b/test/geo_parametrizedline.cpp
new file mode 100644
index 000000000..4e1f845dd
--- /dev/null
+++ b/test/geo_parametrizedline.cpp
@@ -0,0 +1,105 @@
+// 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 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+
+template<typename LineType> void parametrizedline(const LineType& _line)
+{
+ /* this test covers the following files:
+ ParametrizedLine.h
+ */
+ typedef typename LineType::Index Index;
+ const Index dim = _line.dim();
+ typedef typename LineType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime,
+ LineType::AmbientDimAtCompileTime> MatrixType;
+ typedef Hyperplane<Scalar,LineType::AmbientDimAtCompileTime> HyperplaneType;
+
+ VectorType p0 = VectorType::Random(dim);
+ VectorType p1 = VectorType::Random(dim);
+
+ VectorType d0 = VectorType::Random(dim).normalized();
+
+ LineType l0(p0, d0);
+
+ Scalar s0 = internal::random<Scalar>();
+ Scalar s1 = internal::abs(internal::random<Scalar>());
+
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0), RealScalar(1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0+s0*d0), RealScalar(1) );
+ VERIFY_IS_APPROX( (l0.projection(p1)-p1).norm(), l0.distance(p1) );
+ VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(l0.projection(p1)), RealScalar(1) );
+ VERIFY_IS_APPROX( Scalar(l0.distance((p0+s0*d0) + d0.unitOrthogonal() * s1)), s1 );
+
+ // casting
+ const int Dim = LineType::AmbientDimAtCompileTime;
+ typedef typename GetDifferentType<Scalar>::type OtherScalar;
+ ParametrizedLine<OtherScalar,Dim> hp1f = l0.template cast<OtherScalar>();
+ VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),l0);
+ ParametrizedLine<Scalar,Dim> hp1d = l0.template cast<Scalar>();
+ VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),l0);
+
+ // intersections
+ VectorType p2 = VectorType::Random(dim);
+ VectorType n2 = VectorType::Random(dim).normalized();
+ HyperplaneType hp(p2,n2);
+ Scalar t = l0.intersectionParameter(hp);
+ VectorType pi = l0.pointAt(t);
+ VERIFY_IS_MUCH_SMALLER_THAN(hp.signedDistance(pi), RealScalar(1));
+ VERIFY_IS_MUCH_SMALLER_THAN(l0.distance(pi), RealScalar(1));
+ VERIFY_IS_APPROX(l0.intersectionPoint(hp), pi);
+}
+
+template<typename Scalar> void parametrizedline_alignment()
+{
+ typedef ParametrizedLine<Scalar,4,AutoAlign> Line4a;
+ typedef ParametrizedLine<Scalar,4,DontAlign> Line4u;
+
+ EIGEN_ALIGN16 Scalar array1[8];
+ EIGEN_ALIGN16 Scalar array2[8];
+ EIGEN_ALIGN16 Scalar array3[8+1];
+ Scalar* array3u = array3+1;
+
+ Line4a *p1 = ::new(reinterpret_cast<void*>(array1)) Line4a;
+ Line4u *p2 = ::new(reinterpret_cast<void*>(array2)) Line4u;
+ Line4u *p3 = ::new(reinterpret_cast<void*>(array3u)) Line4u;
+
+ p1->origin().setRandom();
+ p1->direction().setRandom();
+ *p2 = *p1;
+ *p3 = *p1;
+
+ VERIFY_IS_APPROX(p1->origin(), p2->origin());
+ VERIFY_IS_APPROX(p1->origin(), p3->origin());
+ VERIFY_IS_APPROX(p1->direction(), p2->direction());
+ VERIFY_IS_APPROX(p1->direction(), p3->direction());
+
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Line4a));
+ #endif
+}
+
+void test_geo_parametrizedline()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( parametrizedline(ParametrizedLine<float,2>()) );
+ CALL_SUBTEST_2( parametrizedline(ParametrizedLine<float,3>()) );
+ CALL_SUBTEST_2( parametrizedline_alignment<float>() );
+ CALL_SUBTEST_3( parametrizedline(ParametrizedLine<double,4>()) );
+ CALL_SUBTEST_3( parametrizedline_alignment<double>() );
+ CALL_SUBTEST_4( parametrizedline(ParametrizedLine<std::complex<double>,5>()) );
+ }
+}
diff --git a/test/geo_quaternion.cpp b/test/geo_quaternion.cpp
new file mode 100644
index 000000000..6e6922864
--- /dev/null
+++ b/test/geo_quaternion.cpp
@@ -0,0 +1,255 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2009 Mathieu Gautier <mathieu.gautier@cea.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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename T> T bounded_acos(T v)
+{
+ using std::acos;
+ using std::min;
+ using std::max;
+ return acos((max)(T(-1),(min)(v,T(1))));
+}
+
+template<typename QuatType> void check_slerp(const QuatType& q0, const QuatType& q1)
+{
+ typedef typename QuatType::Scalar Scalar;
+ typedef Matrix<Scalar,3,1> VectorType;
+ typedef AngleAxis<Scalar> AA;
+
+ Scalar largeEps = test_precision<Scalar>();
+
+ Scalar theta_tot = AA(q1*q0.inverse()).angle();
+ if(theta_tot>M_PI)
+ theta_tot = 2.*M_PI-theta_tot;
+ for(Scalar t=0; t<=1.001; t+=0.1)
+ {
+ QuatType q = q0.slerp(t,q1);
+ Scalar theta = AA(q*q0.inverse()).angle();
+ VERIFY(internal::abs(q.norm() - 1) < largeEps);
+ if(theta_tot==0) VERIFY(theta_tot==0);
+ else VERIFY(internal::abs(theta/theta_tot - t) < largeEps);
+ }
+}
+
+template<typename Scalar, int Options> void quaternion(void)
+{
+ /* this test covers the following files:
+ Quaternion.h
+ */
+
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar,Options> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+
+ Scalar largeEps = test_precision<Scalar>();
+ if (internal::is_same<Scalar,float>::value)
+ largeEps = 1e-3f;
+
+ Scalar eps = internal::random<Scalar>() * Scalar(1e-2);
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random(),
+ v2 = Vector3::Random(),
+ v3 = Vector3::Random();
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI)),
+ b = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ // Quaternion: Identity(), setIdentity();
+ Quaternionx q1, q2;
+ q2.setIdentity();
+ VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
+ q1.coeffs().setRandom();
+ VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
+
+ // concatenation
+ q1 *= q2;
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // angular distance
+ Scalar refangle = internal::abs(AngleAxisx(q1.inverse()*q2).angle());
+ if (refangle>Scalar(M_PI))
+ refangle = Scalar(2)*Scalar(M_PI) - refangle;
+
+ if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(q1.angularDistance(q2) - refangle), Scalar(1));
+ }
+
+ // rotation matrix conversion
+ VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
+ VERIFY_IS_APPROX(q1 * q2 * v2,
+ q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
+
+ VERIFY( (q2*q1).isApprox(q1*q2, largeEps)
+ || !(q2 * q1 * v2).isApprox(q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
+
+ q2 = q1.toRotationMatrix();
+ VERIFY_IS_APPROX(q1*v1,q2*v1);
+
+
+ // angle-axis conversion
+ AngleAxisx aa = AngleAxisx(q1);
+ VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
+
+ // Do not execute the test if the rotation angle is almost zero, or
+ // the rotation axis and v1 are almost parallel.
+ if (internal::abs(aa.angle()) > 5*test_precision<Scalar>()
+ && (aa.axis() - v1.normalized()).norm() < 1.99
+ && (aa.axis() + v1.normalized()).norm() < 1.99)
+ {
+ VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
+ }
+
+ // from two vector creation
+ VERIFY_IS_APPROX( v2.normalized(),(q2.setFromTwoVectors(v1, v2)*v1).normalized());
+ VERIFY_IS_APPROX( v1.normalized(),(q2.setFromTwoVectors(v1, v1)*v1).normalized());
+ VERIFY_IS_APPROX(-v1.normalized(),(q2.setFromTwoVectors(v1,-v1)*v1).normalized());
+ if (internal::is_same<Scalar,double>::value)
+ {
+ v3 = (v1.array()+eps).matrix();
+ VERIFY_IS_APPROX( v3.normalized(),(q2.setFromTwoVectors(v1, v3)*v1).normalized());
+ VERIFY_IS_APPROX(-v3.normalized(),(q2.setFromTwoVectors(v1,-v3)*v1).normalized());
+ }
+
+ // from two vector creation static function
+ VERIFY_IS_APPROX( v2.normalized(),(Quaternionx::FromTwoVectors(v1, v2)*v1).normalized());
+ VERIFY_IS_APPROX( v1.normalized(),(Quaternionx::FromTwoVectors(v1, v1)*v1).normalized());
+ VERIFY_IS_APPROX(-v1.normalized(),(Quaternionx::FromTwoVectors(v1,-v1)*v1).normalized());
+ if (internal::is_same<Scalar,double>::value)
+ {
+ v3 = (v1.array()+eps).matrix();
+ VERIFY_IS_APPROX( v3.normalized(),(Quaternionx::FromTwoVectors(v1, v3)*v1).normalized());
+ VERIFY_IS_APPROX(-v3.normalized(),(Quaternionx::FromTwoVectors(v1,-v3)*v1).normalized());
+ }
+
+ // inverse and conjugate
+ VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
+ VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
+
+ // test casting
+ Quaternion<float> q1f = q1.template cast<float>();
+ VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
+ Quaternion<double> q1d = q1.template cast<double>();
+ VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
+
+ // test bug 369 - improper alignment.
+ Quaternionx *q = new Quaternionx;
+ delete q;
+
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(b, v1.normalized());
+ check_slerp(q1,q2);
+
+ q1 = AngleAxisx(b, v1.normalized());
+ q2 = AngleAxisx(b+M_PI, v1.normalized());
+ check_slerp(q1,q2);
+
+ q1 = AngleAxisx(b, v1.normalized());
+ q2 = AngleAxisx(-b, -v1.normalized());
+ check_slerp(q1,q2);
+
+ q1.coeffs() = Vector4::Random().normalized();
+ q2.coeffs() = -q1.coeffs();
+ check_slerp(q1,q2);
+}
+
+template<typename Scalar> void mapQuaternion(void){
+ typedef Map<Quaternion<Scalar>, Aligned> MQuaternionA;
+ typedef Map<Quaternion<Scalar> > MQuaternionUA;
+ typedef Map<const Quaternion<Scalar> > MCQuaternionUA;
+ typedef Quaternion<Scalar> Quaternionx;
+
+ EIGEN_ALIGN16 Scalar array1[4];
+ EIGEN_ALIGN16 Scalar array2[4];
+ EIGEN_ALIGN16 Scalar array3[4+1];
+ Scalar* array3unaligned = array3+1;
+
+// std::cerr << array1 << " " << array2 << " " << array3 << "\n";
+ MQuaternionA(array1).coeffs().setRandom();
+ (MQuaternionA(array2)) = MQuaternionA(array1);
+ (MQuaternionUA(array3unaligned)) = MQuaternionA(array1);
+
+ Quaternionx q1 = MQuaternionA(array1);
+ Quaternionx q2 = MQuaternionA(array2);
+ Quaternionx q3 = MQuaternionUA(array3unaligned);
+ Quaternionx q4 = MCQuaternionUA(array3unaligned);
+
+ VERIFY_IS_APPROX(q1.coeffs(), q2.coeffs());
+ VERIFY_IS_APPROX(q1.coeffs(), q3.coeffs());
+ VERIFY_IS_APPROX(q4.coeffs(), q3.coeffs());
+ #ifdef EIGEN_VECTORIZE
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((MQuaternionA(array3unaligned)));
+ #endif
+}
+
+template<typename Scalar> void quaternionAlignment(void){
+ typedef Quaternion<Scalar,AutoAlign> QuaternionA;
+ typedef Quaternion<Scalar,DontAlign> QuaternionUA;
+
+ EIGEN_ALIGN16 Scalar array1[4];
+ EIGEN_ALIGN16 Scalar array2[4];
+ EIGEN_ALIGN16 Scalar array3[4+1];
+ Scalar* arrayunaligned = array3+1;
+
+ QuaternionA *q1 = ::new(reinterpret_cast<void*>(array1)) QuaternionA;
+ QuaternionUA *q2 = ::new(reinterpret_cast<void*>(array2)) QuaternionUA;
+ QuaternionUA *q3 = ::new(reinterpret_cast<void*>(arrayunaligned)) QuaternionUA;
+
+ q1->coeffs().setRandom();
+ *q2 = *q1;
+ *q3 = *q1;
+
+ VERIFY_IS_APPROX(q1->coeffs(), q2->coeffs());
+ VERIFY_IS_APPROX(q1->coeffs(), q3->coeffs());
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(arrayunaligned)) QuaternionA));
+ #endif
+}
+
+template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
+{
+ // there's a lot that we can't test here while still having this test compile!
+ // the only possible approach would be to run a script trying to compile stuff and checking that it fails.
+ // CMake can help with that.
+
+ // verify that map-to-const don't have LvalueBit
+ typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType> >::Flags & LvalueBit) );
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType>::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType, Aligned>::Flags & LvalueBit) );
+}
+
+void test_geo_quaternion()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( quaternion<float,AutoAlign>() ));
+ CALL_SUBTEST_1( check_const_correctness(Quaternionf()) );
+ CALL_SUBTEST_2(( quaternion<double,AutoAlign>() ));
+ CALL_SUBTEST_2( check_const_correctness(Quaterniond()) );
+ CALL_SUBTEST_3(( quaternion<float,DontAlign>() ));
+ CALL_SUBTEST_4(( quaternion<double,DontAlign>() ));
+ CALL_SUBTEST_5(( quaternionAlignment<float>() ));
+ CALL_SUBTEST_6(( quaternionAlignment<double>() ));
+ CALL_SUBTEST_1( mapQuaternion<float>() );
+ CALL_SUBTEST_2( mapQuaternion<double>() );
+ }
+}
diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp
new file mode 100644
index 000000000..f4d65aabc
--- /dev/null
+++ b/test/geo_transformations.cpp
@@ -0,0 +1,487 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/SVD>
+
+template<typename Scalar, int Mode, int Options> void non_projective_only()
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+ typedef Transform<Scalar,2,Mode,Options> Transform2;
+ typedef Transform<Scalar,3,Mode,Options> Transform3;
+ typedef Transform<Scalar,2,Isometry,Options> Isometry2;
+ typedef Transform<Scalar,3,Isometry,Options> Isometry3;
+ typedef typename Transform3::MatrixType MatrixType;
+ typedef DiagonalMatrix<Scalar,2> AlignedScaling2;
+ typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
+ typedef Translation<Scalar,2> Translation2;
+ typedef Translation<Scalar,3> Translation3;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random();
+
+ Transform3 t0, t1, t2;
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+
+ Quaternionx q1, q2;
+
+ q1 = AngleAxisx(a, v0.normalized());
+
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.linear() = q1.toRotationMatrix();
+
+ v0 << 50, 2, 1;
+ t0.scale(v0);
+
+ VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).template head<3>().norm(), v0.x());
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwiseInverse());
+ t1.translate(-v0);
+
+ VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+ VERIFY_IS_APPROX(t1*v1, t0*v1);
+
+ // translation * vector
+ t0.setIdentity();
+ t0.translate(v0);
+ VERIFY_IS_APPROX((t0 * v1).template head<3>(), Translation3(v0) * v1);
+
+ // AlignedScaling * vector
+ t0.setIdentity();
+ t0.scale(v0);
+ VERIFY_IS_APPROX((t0 * v1).template head<3>(), AlignedScaling3(v0) * v1);
+}
+
+template<typename Scalar, int Mode, int Options> void transformations()
+{
+ /* this test covers the following files:
+ Cross.h Quaternion.h, Transform.cpp
+ */
+ typedef Matrix<Scalar,2,2> Matrix2;
+ typedef Matrix<Scalar,3,3> Matrix3;
+ typedef Matrix<Scalar,4,4> Matrix4;
+ typedef Matrix<Scalar,2,1> Vector2;
+ typedef Matrix<Scalar,3,1> Vector3;
+ typedef Matrix<Scalar,4,1> Vector4;
+ typedef Quaternion<Scalar> Quaternionx;
+ typedef AngleAxis<Scalar> AngleAxisx;
+ typedef Transform<Scalar,2,Mode,Options> Transform2;
+ typedef Transform<Scalar,3,Mode,Options> Transform3;
+ typedef Transform<Scalar,2,Isometry,Options> Isometry2;
+ typedef Transform<Scalar,3,Isometry,Options> Isometry3;
+ typedef typename Transform3::MatrixType MatrixType;
+ typedef DiagonalMatrix<Scalar,2> AlignedScaling2;
+ typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
+ typedef Translation<Scalar,2> Translation2;
+ typedef Translation<Scalar,3> Translation3;
+
+ Vector3 v0 = Vector3::Random(),
+ v1 = Vector3::Random();
+ Matrix3 matrot1, m;
+
+ Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Scalar s0 = internal::random<Scalar>();
+
+ VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
+ VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
+ VERIFY_IS_APPROX(internal::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);
+
+ Quaternionx q1, q2;
+ q1 = AngleAxisx(a, v0.normalized());
+ q2 = AngleAxisx(a, v1.normalized());
+
+ // rotation matrix conversion
+ matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
+ * AngleAxisx(Scalar(0.2), Vector3::UnitY())
+ * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
+ VERIFY_IS_APPROX(matrot1 * v1,
+ AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
+ * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
+
+ // 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);
+
+ 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);
+
+ // AngleAxis
+ VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
+ Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
+
+ AngleAxisx aa1;
+ m = q1.toRotationMatrix();
+ aa1 = m;
+ VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
+ Quaternionx(m).toRotationMatrix());
+
+ // Transform
+ // TODO complete the tests !
+ a = 0;
+ while (internal::abs(a)<Scalar(0.1))
+ a = internal::random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
+ q1 = AngleAxisx(a, v0.normalized());
+ Transform3 t0, t1, t2;
+
+ // first test setIdentity() and Identity()
+ t0.setIdentity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+ t0.matrix().setZero();
+ t0 = Transform3::Identity();
+ VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
+
+ t0.setIdentity();
+ t1.setIdentity();
+ v1 << 1, 2, 3;
+ t0.linear() = q1.toRotationMatrix();
+ t0.pretranslate(v0);
+ t0.scale(v1);
+ t1.linear() = q1.conjugate().toRotationMatrix();
+ t1.prescale(v1.cwiseInverse());
+ t1.translate(-v0);
+
+ VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
+
+ t1.fromPositionOrientationScale(v0, q1, v1);
+ VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
+ t1.setIdentity(); t1.scale(v0).rotate(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
+ VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
+
+ // More transform constructors, operator=, operator*=
+
+ Matrix3 mat3 = Matrix3::Random();
+ Matrix4 mat4;
+ mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
+ Transform3 tmat3(mat3), tmat4(mat4);
+ if(Mode!=int(AffineCompact))
+ tmat4.matrix()(3,3) = Scalar(1);
+ VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
+
+ Scalar a3 = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
+ Vector3 v3 = Vector3::Random().normalized();
+ AngleAxisx aa3(a3, v3);
+ Transform3 t3(aa3);
+ Transform3 t4;
+ t4 = aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+ t4.rotate(AngleAxisx(-a3,v3));
+ VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
+ t4 *= aa3;
+ VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
+
+ v3 = Vector3::Random();
+ Translation3 tv3(v3);
+ Transform3 t5(tv3);
+ t4 = tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+ t4.translate(-v3);
+ VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
+ t4 *= tv3;
+ VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
+
+ AlignedScaling3 sv3(v3);
+ Transform3 t6(sv3);
+ t4 = sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+ t4.scale(v3.cwiseInverse());
+ VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
+ t4 *= sv3;
+ VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
+
+ // matrix * transform
+ VERIFY_IS_APPROX((t3.matrix()*t4).matrix(), (t3*t4).matrix());
+
+ // chained Transform product
+ VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
+
+ // check that Transform product doesn't have aliasing problems
+ t5 = t4;
+ t5 = t5*t5;
+ VERIFY_IS_APPROX(t5, t4*t4);
+
+ // 2D transformation
+ Transform2 t20, t21;
+ Vector2 v20 = Vector2::Random();
+ Vector2 v21 = Vector2::Random();
+ for (int k=0; k<2; ++k)
+ if (internal::abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
+ VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
+ t21.pretranslate(v20).scale(v21).matrix());
+
+ t21.setIdentity();
+ t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
+ VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
+ * (t21.prescale(v21.cwiseInverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
+
+ // Transform - new API
+ // 3D
+ t0.setIdentity();
+ t0.rotate(q1).scale(v0).translate(v0);
+ // mat * aligned scaling and mat * translation
+ t1 = (Matrix3(q1) * AlignedScaling3(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t1 = (Matrix3(q1) * Eigen::Scaling(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t1 = (q1 * Eigen::Scaling(v0)) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // mat * transformation and aligned scaling * translation
+ t1 = Matrix3(q1) * (AlignedScaling3(v0) * Translation3(v0));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+
+ t0.setIdentity();
+ t0.scale(s0).translate(v0);
+ t1 = Eigen::Scaling(s0) * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t0.prescale(s0);
+ t1 = Eigen::Scaling(s0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0 = t3;
+ t0.scale(s0);
+ t1 = t3 * Eigen::Scaling(s0,s0,s0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ t0.prescale(s0);
+ t1 = Eigen::Scaling(s0,s0,s0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+
+ t0.setIdentity();
+ t0.prerotate(q1).prescale(v0).pretranslate(v0);
+ // translation * aligned scaling and transformation * mat
+ t1 = (Translation3(v0) * AlignedScaling3(v0)) * Transform3(q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // scaling * mat and translation * mat
+ t1 = Translation3(v0) * (AlignedScaling3(v0) * Transform3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ t0.setIdentity();
+ t0.scale(v0).translate(v0).rotate(q1);
+ // translation * mat and aligned scaling * transformation
+ t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * aligned scaling
+ t0.scale(v0);
+ t1 *= AlignedScaling3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // transformation * translation
+ t0.translate(v0);
+ t1 = t1 * Translation3(v0);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+ // translation * transformation
+ t0.pretranslate(v0);
+ t1 = Translation3(v0) * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // transform * quaternion
+ t0.rotate(q1);
+ t1 = t1 * q1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // translation * quaternion
+ t0.translate(v1).rotate(q1);
+ t1 = t1 * (Translation3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // aligned scaling * quaternion
+ t0.scale(v1).rotate(q1);
+ t1 = t1 * (AlignedScaling3(v1) * q1);
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * transform
+ t0.prerotate(q1);
+ t1 = q1 * t1;
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * translation
+ t0.rotate(q1).translate(v1);
+ t1 = t1 * (q1 * Translation3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // quaternion * aligned scaling
+ t0.rotate(q1).scale(v1);
+ t1 = t1 * (q1 * AlignedScaling3(v1));
+ VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
+
+ // test transform inversion
+ t0.setIdentity();
+ t0.translate(v0);
+ t0.linear().setRandom();
+ Matrix4 t044 = Matrix4::Zero();
+ t044(3,3) = 1;
+ t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
+ VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1);
+ t044 = Matrix4::Zero();
+ t044(3,3) = 1;
+ t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
+ VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
+
+ Matrix3 mat_rotation, mat_scaling;
+ t0.setIdentity();
+ t0.translate(v0).rotate(q1).scale(v1);
+ t0.computeRotationScaling(&mat_rotation, &mat_scaling);
+ VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+ t0.computeScalingRotation(&mat_scaling, &mat_rotation);
+ VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
+ VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
+ VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
+
+ // test casting
+ Transform<float,3,Mode> t1f = t1.template cast<float>();
+ VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
+ Transform<double,3,Mode> t1d = t1.template cast<double>();
+ VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
+
+ Translation3 tr1(v0);
+ Translation<float,3> tr1f = tr1.template cast<float>();
+ VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
+ Translation<double,3> tr1d = tr1.template cast<double>();
+ VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
+
+ AngleAxis<float> aa1f = aa1.template cast<float>();
+ VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
+ AngleAxis<double> aa1d = aa1.template cast<double>();
+ VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
+
+ Rotation2D<Scalar> r2d1(internal::random<Scalar>());
+ Rotation2D<float> r2d1f = r2d1.template cast<float>();
+ VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
+ Rotation2D<double> r2d1d = r2d1.template cast<double>();
+ VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
+
+ t20 = Translation2(v20) * (Rotation2D<Scalar>(s0) * Scaling(s0));
+ t21 = Translation2(v20) * Rotation2D<Scalar>(s0) * Scaling(s0);
+ VERIFY_IS_APPROX(t20,t21);
+}
+
+template<typename Scalar> void transform_alignment()
+{
+ typedef Transform<Scalar,3,Projective,AutoAlign> Projective3a;
+ typedef Transform<Scalar,3,Projective,DontAlign> Projective3u;
+
+ EIGEN_ALIGN16 Scalar array1[16];
+ EIGEN_ALIGN16 Scalar array2[16];
+ EIGEN_ALIGN16 Scalar array3[16+1];
+ Scalar* array3u = array3+1;
+
+ Projective3a *p1 = ::new(reinterpret_cast<void*>(array1)) Projective3a;
+ Projective3u *p2 = ::new(reinterpret_cast<void*>(array2)) Projective3u;
+ Projective3u *p3 = ::new(reinterpret_cast<void*>(array3u)) Projective3u;
+
+ p1->matrix().setRandom();
+ *p2 = *p1;
+ *p3 = *p1;
+
+ VERIFY_IS_APPROX(p1->matrix(), p2->matrix());
+ VERIFY_IS_APPROX(p1->matrix(), p3->matrix());
+
+ VERIFY_IS_APPROX( (*p1) * (*p1), (*p2)*(*p3));
+
+ #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Projective3a));
+ #endif
+}
+
+template<typename Scalar, int Dim, int Options> void transform_products()
+{
+ typedef Matrix<Scalar,Dim+1,Dim+1> Mat;
+ typedef Transform<Scalar,Dim,Projective,Options> Proj;
+ typedef Transform<Scalar,Dim,Affine,Options> Aff;
+ typedef Transform<Scalar,Dim,AffineCompact,Options> AffC;
+
+ Proj p; p.matrix().setRandom();
+ Aff a; a.linear().setRandom(); a.translation().setRandom();
+ AffC ac = a;
+
+ Mat p_m(p.matrix()), a_m(a.matrix());
+
+ VERIFY_IS_APPROX((p*p).matrix(), p_m*p_m);
+ VERIFY_IS_APPROX((a*a).matrix(), a_m*a_m);
+ VERIFY_IS_APPROX((p*a).matrix(), p_m*a_m);
+ VERIFY_IS_APPROX((a*p).matrix(), a_m*p_m);
+ VERIFY_IS_APPROX((ac*a).matrix(), a_m*a_m);
+ VERIFY_IS_APPROX((a*ac).matrix(), a_m*a_m);
+ VERIFY_IS_APPROX((p*ac).matrix(), p_m*a_m);
+ VERIFY_IS_APPROX((ac*p).matrix(), a_m*p_m);
+}
+
+void test_geo_transformations()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( transformations<double,Affine,AutoAlign>() ));
+ CALL_SUBTEST_1(( non_projective_only<double,Affine,AutoAlign>() ));
+
+ CALL_SUBTEST_2(( transformations<float,AffineCompact,AutoAlign>() ));
+ CALL_SUBTEST_2(( non_projective_only<float,AffineCompact,AutoAlign>() ));
+ CALL_SUBTEST_2(( transform_alignment<float>() ));
+
+ CALL_SUBTEST_3(( transformations<double,Projective,AutoAlign>() ));
+ CALL_SUBTEST_3(( transformations<double,Projective,DontAlign>() ));
+ CALL_SUBTEST_3(( transform_alignment<double>() ));
+
+ CALL_SUBTEST_4(( transformations<float,Affine,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_4(( non_projective_only<float,Affine,RowMajor>() ));
+
+ CALL_SUBTEST_5(( transformations<double,AffineCompact,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_5(( non_projective_only<double,AffineCompact,RowMajor>() ));
+
+ CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|DontAlign>() ));
+
+
+ CALL_SUBTEST_7(( transform_products<double,3,RowMajor|AutoAlign>() ));
+ CALL_SUBTEST_7(( transform_products<float,2,AutoAlign>() ));
+ }
+}
diff --git a/test/hessenberg.cpp b/test/hessenberg.cpp
new file mode 100644
index 000000000..96bc19e2e
--- /dev/null
+++ b/test/hessenberg.cpp
@@ -0,0 +1,62 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+#include <Eigen/Eigenvalues>
+
+template<typename Scalar,int Size> void hessenberg(int size = Size)
+{
+ typedef Matrix<Scalar,Size,Size> MatrixType;
+
+ // Test basic functionality: A = U H U* and H is Hessenberg
+ for(int counter = 0; counter < g_repeat; ++counter) {
+ MatrixType m = MatrixType::Random(size,size);
+ HessenbergDecomposition<MatrixType> hess(m);
+ MatrixType Q = hess.matrixQ();
+ MatrixType H = hess.matrixH();
+ VERIFY_IS_APPROX(m, Q * H * Q.adjoint());
+ for(int row = 2; row < size; ++row) {
+ for(int col = 0; col < row-1; ++col) {
+ VERIFY(H(row,col) == (typename MatrixType::Scalar)0);
+ }
+ }
+ }
+
+ // Test whether compute() and constructor returns same result
+ MatrixType A = MatrixType::Random(size, size);
+ HessenbergDecomposition<MatrixType> cs1;
+ cs1.compute(A);
+ HessenbergDecomposition<MatrixType> cs2(A);
+ VERIFY_IS_EQUAL(cs1.matrixH().eval(), cs2.matrixH().eval());
+ MatrixType cs1Q = cs1.matrixQ();
+ MatrixType cs2Q = cs2.matrixQ();
+ VERIFY_IS_EQUAL(cs1Q, cs2Q);
+
+ // Test assertions for when used uninitialized
+ HessenbergDecomposition<MatrixType> hessUninitialized;
+ VERIFY_RAISES_ASSERT( hessUninitialized.matrixH() );
+ VERIFY_RAISES_ASSERT( hessUninitialized.matrixQ() );
+ VERIFY_RAISES_ASSERT( hessUninitialized.householderCoefficients() );
+ VERIFY_RAISES_ASSERT( hessUninitialized.packedMatrix() );
+
+ // TODO: Add tests for packedMatrix() and householderCoefficients()
+}
+
+void test_hessenberg()
+{
+ CALL_SUBTEST_1(( hessenberg<std::complex<double>,1>() ));
+ CALL_SUBTEST_2(( hessenberg<std::complex<double>,2>() ));
+ CALL_SUBTEST_3(( hessenberg<std::complex<float>,4>() ));
+ CALL_SUBTEST_4(( hessenberg<float,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_5(( hessenberg<std::complex<double>,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_6(HessenbergDecomposition<MatrixXf>(10));
+}
diff --git a/test/householder.cpp b/test/householder.cpp
new file mode 100644
index 000000000..203dce46c
--- /dev/null
+++ b/test/householder.cpp
@@ -0,0 +1,123 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void householder(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ static bool even = true;
+ even = !even;
+ /* this test covers the following files:
+ Householder.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, internal::decrement_size<MatrixType::RowsAtCompileTime>::ret, 1> EssentialVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ typedef Matrix<Scalar, Dynamic, MatrixType::ColsAtCompileTime> HBlockMatrixType;
+ typedef Matrix<Scalar, Dynamic, 1> HCoeffsVectorType;
+
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> RightSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, Dynamic> VBlockMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime> TMatrixType;
+
+ Matrix<Scalar, EIGEN_SIZE_MAX(MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime), 1> _tmp((std::max)(rows,cols));
+ Scalar* tmp = &_tmp.coeffRef(0,0);
+
+ Scalar beta;
+ RealScalar alpha;
+ EssentialVectorType essential;
+
+ VectorType v1 = VectorType::Random(rows), v2;
+ v2 = v1;
+ v1.makeHouseholder(essential, beta, alpha);
+ v1.applyHouseholderOnTheLeft(essential,beta,tmp);
+ VERIFY_IS_APPROX(v1.norm(), v2.norm());
+ if(rows>=2) VERIFY_IS_MUCH_SMALLER_THAN(v1.tail(rows-1).norm(), v1.norm());
+ v1 = VectorType::Random(rows);
+ v2 = v1;
+ v1.applyHouseholderOnTheLeft(essential,beta,tmp);
+ VERIFY_IS_APPROX(v1.norm(), v2.norm());
+
+ MatrixType m1(rows, cols),
+ m2(rows, cols);
+
+ v1 = VectorType::Random(rows);
+ if(even) v1.tail(rows-1).setZero();
+ m1.colwise() = v1;
+ m2 = m1;
+ m1.col(0).makeHouseholder(essential, beta, alpha);
+ m1.applyHouseholderOnTheLeft(essential,beta,tmp);
+ VERIFY_IS_APPROX(m1.norm(), m2.norm());
+ if(rows>=2) VERIFY_IS_MUCH_SMALLER_THAN(m1.block(1,0,rows-1,cols).norm(), m1.norm());
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::imag(m1(0,0)), internal::real(m1(0,0)));
+ VERIFY_IS_APPROX(internal::real(m1(0,0)), alpha);
+
+ v1 = VectorType::Random(rows);
+ if(even) v1.tail(rows-1).setZero();
+ SquareMatrixType m3(rows,rows), m4(rows,rows);
+ m3.rowwise() = v1.transpose();
+ m4 = m3;
+ m3.row(0).makeHouseholder(essential, beta, alpha);
+ m3.applyHouseholderOnTheRight(essential,beta,tmp);
+ VERIFY_IS_APPROX(m3.norm(), m4.norm());
+ if(rows>=2) VERIFY_IS_MUCH_SMALLER_THAN(m3.block(0,1,rows,rows-1).norm(), m3.norm());
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::imag(m3(0,0)), internal::real(m3(0,0)));
+ VERIFY_IS_APPROX(internal::real(m3(0,0)), alpha);
+
+ // test householder sequence on the left with a shift
+
+ Index shift = internal::random<Index>(0, std::max<Index>(rows-2,0));
+ Index brows = rows - shift;
+ m1.setRandom(rows, cols);
+ HBlockMatrixType hbm = m1.block(shift,0,brows,cols);
+ HouseholderQR<HBlockMatrixType> qr(hbm);
+ m2 = m1;
+ m2.block(shift,0,brows,cols) = qr.matrixQR();
+ HCoeffsVectorType hc = qr.hCoeffs().conjugate();
+ HouseholderSequence<MatrixType, HCoeffsVectorType> hseq(m2, hc);
+ hseq.setLength(hc.size()).setShift(shift);
+ VERIFY(hseq.length() == hc.size());
+ VERIFY(hseq.shift() == shift);
+
+ MatrixType m5 = m2;
+ m5.block(shift,0,brows,cols).template triangularView<StrictlyLower>().setZero();
+ VERIFY_IS_APPROX(hseq * m5, m1); // test applying hseq directly
+ m3 = hseq;
+ VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating hseq to a dense matrix, then applying
+
+ // test householder sequence on the right with a shift
+
+ TMatrixType tm2 = m2.transpose();
+ HouseholderSequence<TMatrixType, HCoeffsVectorType, OnTheRight> rhseq(tm2, hc);
+ rhseq.setLength(hc.size()).setShift(shift);
+ VERIFY_IS_APPROX(rhseq * m5, m1); // test applying rhseq directly
+ m3 = rhseq;
+ VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating rhseq to a dense matrix, then applying
+}
+
+void test_householder()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( householder(Matrix<double,2,2>()) );
+ CALL_SUBTEST_2( householder(Matrix<float,2,3>()) );
+ CALL_SUBTEST_3( householder(Matrix<double,3,5>()) );
+ CALL_SUBTEST_4( householder(Matrix<float,4,4>()) );
+ CALL_SUBTEST_5( householder(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_6( householder(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_7( householder(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( householder(Matrix<double,1,1>()) );
+ }
+}
diff --git a/test/integer_types.cpp b/test/integer_types.cpp
new file mode 100644
index 000000000..950f8e9be
--- /dev/null
+++ b/test/integer_types.cpp
@@ -0,0 +1,161 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+#undef VERIFY_IS_APPROX
+#define VERIFY_IS_APPROX(a, b) VERIFY((a)==(b));
+#undef VERIFY_IS_NOT_APPROX
+#define VERIFY_IS_NOT_APPROX(a, b) VERIFY((a)!=(b));
+
+template<typename MatrixType> void signed_integer_type_tests(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 };
+ VERIFY(is_signed == 1);
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+
+ do {
+ m1 = MatrixType::Random(rows, cols);
+ } while(m1 == mzero || m1 == m2);
+
+ // check linear structure
+
+ Scalar s1;
+ do {
+ s1 = internal::random<Scalar>();
+ } while(s1 == 0);
+
+ VERIFY_IS_EQUAL(-(-m1), m1);
+ VERIFY_IS_EQUAL(-m2+m1+m2, m1);
+ VERIFY_IS_EQUAL((-m1+m2)*s1, -s1*m1+s1*m2);
+}
+
+template<typename MatrixType> void integer_type_tests(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ VERIFY(NumTraits<Scalar>::IsInteger);
+ enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 };
+ VERIFY(int(NumTraits<Scalar>::IsSigned) == is_signed);
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols);
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
+ SquareMatrixType identity = SquareMatrixType::Identity(rows, rows),
+ square = SquareMatrixType::Random(rows, rows);
+ VectorType v1(rows),
+ v2 = VectorType::Random(rows),
+ vzero = VectorType::Zero(rows);
+
+ do {
+ m1 = MatrixType::Random(rows, cols);
+ } while(m1 == mzero || m1 == m2);
+
+ do {
+ v1 = VectorType::Random(rows);
+ } while(v1 == vzero || v1 == v2);
+
+ VERIFY_IS_APPROX( v1, v1);
+ VERIFY_IS_NOT_APPROX( v1, 2*v1);
+ VERIFY_IS_APPROX( vzero, v1-v1);
+ VERIFY_IS_APPROX( m1, m1);
+ VERIFY_IS_NOT_APPROX( m1, 2*m1);
+ VERIFY_IS_APPROX( mzero, m1-m1);
+
+ VERIFY_IS_APPROX(m3 = m1,m1);
+ MatrixType m4;
+ VERIFY_IS_APPROX(m4 = m1,m1);
+
+ m3.real() = m1.real();
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real());
+ VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real());
+
+ // check == / != operators
+ VERIFY(m1==m1);
+ VERIFY(m1!=m2);
+ VERIFY(!(m1==m2));
+ VERIFY(!(m1!=m1));
+ m1 = m2;
+ VERIFY(m1==m2);
+ VERIFY(!(m1!=m2));
+
+ // check linear structure
+
+ Scalar s1;
+ do {
+ s1 = internal::random<Scalar>();
+ } while(s1 == 0);
+
+ VERIFY_IS_EQUAL(m1+m1, 2*m1);
+ VERIFY_IS_EQUAL(m1+m2-m1, m2);
+ VERIFY_IS_EQUAL(m1*s1, s1*m1);
+ VERIFY_IS_EQUAL((m1+m2)*s1, s1*m1+s1*m2);
+ m3 = m2; m3 += m1;
+ VERIFY_IS_EQUAL(m3, m1+m2);
+ m3 = m2; m3 -= m1;
+ VERIFY_IS_EQUAL(m3, m2-m1);
+ m3 = m2; m3 *= s1;
+ VERIFY_IS_EQUAL(m3, s1*m2);
+
+ // check matrix product.
+
+ VERIFY_IS_APPROX(identity * m1, m1);
+ VERIFY_IS_APPROX(square * (m1 + m2), square * m1 + square * m2);
+ VERIFY_IS_APPROX((m1 + m2).transpose() * square, m1.transpose() * square + m2.transpose() * square);
+ VERIFY_IS_APPROX((m1 * m2.transpose()) * m1, m1 * (m2.transpose() * m1));
+}
+
+void test_integer_types()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( integer_type_tests(Matrix<unsigned int, 1, 1>()) );
+ CALL_SUBTEST_1( integer_type_tests(Matrix<unsigned long, 3, 4>()) );
+
+ CALL_SUBTEST_2( integer_type_tests(Matrix<long, 2, 2>()) );
+ CALL_SUBTEST_2( signed_integer_type_tests(Matrix<long, 2, 2>()) );
+
+ CALL_SUBTEST_3( integer_type_tests(Matrix<char, 2, Dynamic>(2, 10)) );
+ CALL_SUBTEST_3( signed_integer_type_tests(Matrix<signed char, 2, Dynamic>(2, 10)) );
+
+ CALL_SUBTEST_4( integer_type_tests(Matrix<unsigned char, 3, 3>()) );
+ CALL_SUBTEST_4( integer_type_tests(Matrix<unsigned char, Dynamic, Dynamic>(20, 20)) );
+
+ CALL_SUBTEST_5( integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)) );
+ CALL_SUBTEST_5( signed_integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)) );
+
+ CALL_SUBTEST_6( integer_type_tests(Matrix<unsigned short, 4, 4>()) );
+
+ CALL_SUBTEST_7( integer_type_tests(Matrix<long long, 11, 13>()) );
+ CALL_SUBTEST_7( signed_integer_type_tests(Matrix<long long, 11, 13>()) );
+
+ CALL_SUBTEST_8( integer_type_tests(Matrix<unsigned long long, Dynamic, 5>(1, 5)) );
+ }
+}
diff --git a/test/inverse.cpp b/test/inverse.cpp
new file mode 100644
index 000000000..cff42dd8d
--- /dev/null
+++ b/test/inverse.cpp
@@ -0,0 +1,102 @@
+// 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 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/.
+
+#include "main.h"
+#include <Eigen/LU>
+
+template<typename MatrixType> void inverse(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ /* this test covers the following files:
+ Inverse.h
+ */
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType m1(rows, cols),
+ m2(rows, cols),
+ identity = MatrixType::Identity(rows, rows);
+ createRandomPIMatrixOfRank(rows,rows,rows,m1);
+ m2 = m1.inverse();
+ VERIFY_IS_APPROX(m1, m2.inverse() );
+
+ VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));
+
+ VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
+ VERIFY_IS_APPROX(identity, m1 * m1.inverse() );
+
+ VERIFY_IS_APPROX(m1, m1.inverse().inverse() );
+
+ // since for the general case we implement separately row-major and col-major, test that
+ VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));
+
+#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
+ //computeInverseAndDetWithCheck tests
+ //First: an invertible matrix
+ bool invertible;
+ RealScalar det;
+
+ m2.setZero();
+ m1.computeInverseAndDetWithCheck(m2, det, invertible);
+ VERIFY(invertible);
+ VERIFY_IS_APPROX(identity, m1*m2);
+ VERIFY_IS_APPROX(det, m1.determinant());
+
+ m2.setZero();
+ m1.computeInverseWithCheck(m2, invertible);
+ VERIFY(invertible);
+ VERIFY_IS_APPROX(identity, m1*m2);
+
+ //Second: a rank one matrix (not invertible, except for 1x1 matrices)
+ VectorType v3 = VectorType::Random(rows);
+ MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
+ m3.computeInverseAndDetWithCheck(m4, det, invertible);
+ VERIFY( rows==1 ? invertible : !invertible );
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(det-m3.determinant()), RealScalar(1));
+ m3.computeInverseWithCheck(m4, invertible);
+ VERIFY( rows==1 ? invertible : !invertible );
+#endif
+
+ // check in-place inversion
+ if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
+ {
+ // in-place is forbidden
+ VERIFY_RAISES_ASSERT(m1 = m1.inverse());
+ }
+ else
+ {
+ m2 = m1.inverse();
+ m1 = m1.inverse();
+ VERIFY_IS_APPROX(m1,m2);
+ }
+}
+
+void test_inverse()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
+ CALL_SUBTEST_2( inverse(Matrix2d()) );
+ CALL_SUBTEST_3( inverse(Matrix3f()) );
+ CALL_SUBTEST_4( inverse(Matrix4f()) );
+ CALL_SUBTEST_4( inverse(Matrix<float,4,4,DontAlign>()) );
+ s = internal::random<int>(50,320);
+ CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
+ s = internal::random<int>(25,100);
+ CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
+ CALL_SUBTEST_7( inverse(Matrix4d()) );
+ CALL_SUBTEST_7( inverse(Matrix<double,4,4,DontAlign>()) );
+ }
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/jacobi.cpp b/test/jacobi.cpp
new file mode 100644
index 000000000..f64f5d08f
--- /dev/null
+++ b/test/jacobi.cpp
@@ -0,0 +1,81 @@
+// 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) 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/.
+
+#include "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType, typename JacobiScalar>
+void jacobi(const MatrixType& m = MatrixType())
+{
+ 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<JacobiScalar, 2, 1> JacobiVector;
+
+ const MatrixType a(MatrixType::Random(rows, cols));
+
+ JacobiVector v = JacobiVector::Random().normalized();
+ JacobiScalar c = v.x(), s = v.y();
+ JacobiRotation<JacobiScalar> rot(c, s);
+
+ {
+ Index p = internal::random<Index>(0, rows-1);
+ Index q;
+ do {
+ q = internal::random<Index>(0, rows-1);
+ } while (q == p);
+
+ MatrixType b = a;
+ b.applyOnTheLeft(p, q, rot);
+ VERIFY_IS_APPROX(b.row(p), c * a.row(p) + internal::conj(s) * a.row(q));
+ VERIFY_IS_APPROX(b.row(q), -s * a.row(p) + internal::conj(c) * a.row(q));
+ }
+
+ {
+ Index p = internal::random<Index>(0, cols-1);
+ Index q;
+ do {
+ q = internal::random<Index>(0, cols-1);
+ } while (q == p);
+
+ MatrixType b = a;
+ b.applyOnTheRight(p, q, rot);
+ VERIFY_IS_APPROX(b.col(p), c * a.col(p) - s * a.col(q));
+ VERIFY_IS_APPROX(b.col(q), internal::conj(s) * a.col(p) + internal::conj(c) * a.col(q));
+ }
+}
+
+void test_jacobi()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(( jacobi<Matrix3f, float>() ));
+ CALL_SUBTEST_2(( jacobi<Matrix4d, double>() ));
+ CALL_SUBTEST_3(( jacobi<Matrix4cf, float>() ));
+ CALL_SUBTEST_3(( jacobi<Matrix4cf, std::complex<float> >() ));
+
+ int r = internal::random<int>(2, internal::random<int>(1,EIGEN_TEST_MAX_SIZE)/2),
+ c = internal::random<int>(2, internal::random<int>(1,EIGEN_TEST_MAX_SIZE)/2);
+ CALL_SUBTEST_4(( jacobi<MatrixXf, float>(MatrixXf(r,c)) ));
+ CALL_SUBTEST_5(( jacobi<MatrixXcd, double>(MatrixXcd(r,c)) ));
+ CALL_SUBTEST_5(( jacobi<MatrixXcd, std::complex<double> >(MatrixXcd(r,c)) ));
+ // complex<float> is really important to test as it is the only way to cover conjugation issues in certain unaligned paths
+ CALL_SUBTEST_6(( jacobi<MatrixXcf, float>(MatrixXcf(r,c)) ));
+ CALL_SUBTEST_6(( jacobi<MatrixXcf, std::complex<float> >(MatrixXcf(r,c)) ));
+ (void) r;
+ (void) c;
+ }
+}
diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp
new file mode 100644
index 000000000..f6c567829
--- /dev/null
+++ b/test/jacobisvd.cpp
@@ -0,0 +1,350 @@
+// 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) 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/.
+
+// 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>
+
+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 typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime> MatrixUType;
+ typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime> MatrixVType;
+ typedef Matrix<Scalar, RowsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, ColsAtCompileTime, 1> InputVectorType;
+
+ 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::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);
+ SolutionType x = svd.solve(rhs);
+ // evaluate normal equation which works also for least-squares solutions
+ VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs);
+}
+
+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);
+
+ jacobisvd_check_full(m, fullSvd);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeFullU | ComputeFullV);
+
+ if(QRPreconditioner == FullPivHouseholderQRPreconditioner)
+ return;
+
+ jacobisvd_compare_to_full(m, ComputeFullU, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeFullV, fullSvd);
+ jacobisvd_compare_to_full(m, 0, fullSvd);
+
+ if (MatrixType::ColsAtCompileTime == Dynamic) {
+ // thin U/V are only available with dynamic number of columns
+ jacobisvd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinV, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinU , fullSvd);
+ jacobisvd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeFullU | ComputeThinV);
+ jacobisvd_solve<MatrixType, QRPreconditioner>(m, ComputeThinU | ComputeFullV);
+ 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());
+ }
+}
+
+template<typename MatrixType>
+void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
+{
+ MatrixType m = pickrandom ? MatrixType::Random(a.rows(), a.cols()) : a;
+
+ jacobisvd_test_all_computation_options<MatrixType, FullPivHouseholderQRPreconditioner>(m);
+ jacobisvd_test_all_computation_options<MatrixType, ColPivHouseholderQRPreconditioner>(m);
+ jacobisvd_test_all_computation_options<MatrixType, HouseholderQRPreconditioner>(m);
+ jacobisvd_test_all_computation_options<MatrixType, NoQRPreconditioner>(m);
+}
+
+template<typename MatrixType> void jacobisvd_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);
+
+ 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>
+void jacobisvd_method()
+{
+ enum { Size = MatrixType::RowsAtCompileTime };
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<RealScalar, Size, 1> RealVecType;
+ MatrixType m = MatrixType::Identity();
+ VERIFY_IS_APPROX(m.jacobiSvd().singularValues(), RealVecType::Ones());
+ VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU());
+ VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV());
+ 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 some_nan = zero<Scalar>() / zero<Scalar>();
+ VERIFY(some_nan != some_nan);
+ svd.compute(MatrixType::Constant(10,10,some_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)) = some_nan;
+ svd.compute(m, ComputeFullU | ComputeFullV);
+}
+
+// Regression test for bug 286: JacobiSVD loops indefinitely with some
+// matrices containing denormal numbers.
+void jacobisvd_bug286()
+{
+#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;
+#if defined __INTEL_COMPILER
+#pragma warning pop
+#endif
+ JacobiSVD<Matrix2d> svd;
+ svd.compute(M); // just check we don't loop indefinitely
+}
+
+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 v(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)) ));
+
+ 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> >() ));
+ CALL_SUBTEST_6(( jacobisvd<Matrix<double,Dynamic,2> >(Matrix<double,Dynamic,2>(10,2)) ));
+
+ int r = internal::random<int>(1, 30),
+ c = internal::random<int>(1, 30);
+ CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(r,c)) ));
+ CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(r,c)) ));
+ (void) r;
+ (void) c;
+
+ // Test on inf/nan matrix
+ CALL_SUBTEST_7( jacobisvd_inf_nan<MatrixXf>() );
+ }
+
+ 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))) ));
+ CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/3))) ));
+
+ // test matrixbase method
+ CALL_SUBTEST_1(( jacobisvd_method<Matrix2cd>() ));
+ CALL_SUBTEST_3(( jacobisvd_method<Matrix3f>() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_7( JacobiSVD<MatrixXf>(10,10) );
+
+ // Check that preallocation avoids subsequent mallocs
+ CALL_SUBTEST_9( jacobisvd_preallocate() );
+
+ // Regression check for bug 286
+ CALL_SUBTEST_2( jacobisvd_bug286() );
+}
diff --git a/test/linearstructure.cpp b/test/linearstructure.cpp
new file mode 100644
index 000000000..fd071c995
--- /dev/null
+++ b/test/linearstructure.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void linearStructure(const MatrixType& m)
+{
+ /* this test covers the following files:
+ CwiseUnaryOp.h, CwiseBinaryOp.h, SelfCwiseBinaryOp.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>();
+ while (internal::abs(s1)<1e-3) s1 = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ VERIFY_IS_APPROX(-(-m1), m1);
+ VERIFY_IS_APPROX(m1+m1, 2*m1);
+ VERIFY_IS_APPROX(m1+m2-m1, m2);
+ VERIFY_IS_APPROX(-m2+m1+m2, m1);
+ VERIFY_IS_APPROX(m1*s1, s1*m1);
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2);
+ m3 = m2; m3 += m1;
+ VERIFY_IS_APPROX(m3, m1+m2);
+ m3 = m2; m3 -= m1;
+ VERIFY_IS_APPROX(m3, m2-m1);
+ m3 = m2; m3 *= s1;
+ VERIFY_IS_APPROX(m3, s1*m2);
+ if(!NumTraits<Scalar>::IsInteger)
+ {
+ m3 = m2; m3 /= s1;
+ VERIFY_IS_APPROX(m3, m2/s1);
+ }
+
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c)));
+ VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c)));
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c)));
+ VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1);
+ if(!NumTraits<Scalar>::IsInteger)
+ VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1);
+
+ // use .block to disable vectorization and compare to the vectorized version
+ VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1);
+ VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), m1.cwiseProduct(m1));
+ VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1);
+ VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1);
+}
+
+void test_linearstructure()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( linearStructure(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( linearStructure(Matrix2f()) );
+ CALL_SUBTEST_3( linearStructure(Vector3d()) );
+ CALL_SUBTEST_4( linearStructure(Matrix4d()) );
+ CALL_SUBTEST_5( linearStructure(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_6( linearStructure(MatrixXf (internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_7( linearStructure(MatrixXi (internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( linearStructure(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_9( linearStructure(ArrayXXf (internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+}
diff --git a/test/lu.cpp b/test/lu.cpp
new file mode 100644
index 000000000..6cbcb0a95
--- /dev/null
+++ b/test/lu.cpp
@@ -0,0 +1,207 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-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/.
+
+#include "main.h"
+#include <Eigen/LU>
+using namespace std;
+
+template<typename MatrixType> void lu_non_invertible()
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ /* this test covers the following files:
+ LU.h
+ */
+ Index rows, cols, cols2;
+ if(MatrixType::RowsAtCompileTime==Dynamic)
+ {
+ rows = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
+ }
+ else
+ {
+ rows = MatrixType::RowsAtCompileTime;
+ }
+ if(MatrixType::ColsAtCompileTime==Dynamic)
+ {
+ cols = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
+ cols2 = internal::random<int>(2,EIGEN_TEST_MAX_SIZE);
+ }
+ else
+ {
+ cols2 = cols = MatrixType::ColsAtCompileTime;
+ }
+
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime
+ };
+ typedef typename internal::kernel_retval_base<FullPivLU<MatrixType> >::ReturnType KernelMatrixType;
+ typedef typename internal::image_retval_base<FullPivLU<MatrixType> >::ReturnType ImageMatrixType;
+ typedef Matrix<typename MatrixType::Scalar, ColsAtCompileTime, ColsAtCompileTime>
+ CMatrixType;
+ typedef Matrix<typename MatrixType::Scalar, RowsAtCompileTime, RowsAtCompileTime>
+ RMatrixType;
+
+ Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
+
+ // The image of the zero matrix should consist of a single (zero) column vector
+ VERIFY((MatrixType::Zero(rows,cols).fullPivLu().image(MatrixType::Zero(rows,cols)).cols() == 1));
+
+ MatrixType m1(rows, cols), m3(rows, cols2);
+ CMatrixType m2(cols, cols2);
+ createRandomPIMatrixOfRank(rank, rows, cols, m1);
+
+ FullPivLU<MatrixType> lu;
+
+ // The special value 0.01 below works well in tests. Keep in mind that we're only computing the rank
+ // of singular values are either 0 or 1.
+ // So it's not clear at all that the epsilon should play any role there.
+ lu.setThreshold(RealScalar(0.01));
+ lu.compute(m1);
+
+ MatrixType u(rows,cols);
+ u = lu.matrixLU().template triangularView<Upper>();
+ RMatrixType l = RMatrixType::Identity(rows,rows);
+ l.block(0,0,rows,(std::min)(rows,cols)).template triangularView<StrictlyLower>()
+ = lu.matrixLU().block(0,0,rows,(std::min)(rows,cols));
+
+ VERIFY_IS_APPROX(lu.permutationP() * m1 * lu.permutationQ(), l*u);
+
+ KernelMatrixType m1kernel = lu.kernel();
+ ImageMatrixType m1image = lu.image(m1);
+
+ VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
+ VERIFY(rank == lu.rank());
+ VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
+ VERIFY(!lu.isInjective());
+ VERIFY(!lu.isInvertible());
+ VERIFY(!lu.isSurjective());
+ VERIFY((m1 * m1kernel).isMuchSmallerThan(m1));
+ VERIFY(m1image.fullPivLu().rank() == rank);
+ VERIFY_IS_APPROX(m1 * m1.adjoint() * m1image, m1image);
+
+ m2 = CMatrixType::Random(cols,cols2);
+ m3 = m1*m2;
+ m2 = CMatrixType::Random(cols,cols2);
+ // test that the code, which does resize(), may be applied to an xpr
+ m2.block(0,0,m2.rows(),m2.cols()) = lu.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void lu_invertible()
+{
+ /* this test covers the following files:
+ LU.h
+ */
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ int size = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ FullPivLU<MatrixType> lu;
+ lu.setThreshold(RealScalar(0.01));
+ do {
+ m1 = MatrixType::Random(size,size);
+ lu.compute(m1);
+ } while(!lu.isInvertible());
+
+ VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
+ VERIFY(0 == lu.dimensionOfKernel());
+ VERIFY(lu.kernel().cols() == 1); // the kernel() should consist of a single (zero) column vector
+ VERIFY(size == lu.rank());
+ VERIFY(lu.isInjective());
+ VERIFY(lu.isSurjective());
+ VERIFY(lu.isInvertible());
+ VERIFY(lu.image(m1).fullPivLu().isInvertible());
+ m3 = MatrixType::Random(size,size);
+ m2 = lu.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+ VERIFY_IS_APPROX(m2, lu.inverse()*m3);
+}
+
+template<typename MatrixType> void lu_partial_piv()
+{
+ /* this test covers the following files:
+ PartialPivLU.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ Index rows = internal::random<Index>(1,4);
+ Index cols = rows;
+
+ MatrixType m1(cols, rows);
+ m1.setRandom();
+ PartialPivLU<MatrixType> plu(m1);
+
+ VERIFY_IS_APPROX(m1, plu.reconstructedMatrix());
+}
+
+template<typename MatrixType> void lu_verify_assert()
+{
+ MatrixType tmp;
+
+ FullPivLU<MatrixType> lu;
+ VERIFY_RAISES_ASSERT(lu.matrixLU())
+ VERIFY_RAISES_ASSERT(lu.permutationP())
+ VERIFY_RAISES_ASSERT(lu.permutationQ())
+ VERIFY_RAISES_ASSERT(lu.kernel())
+ VERIFY_RAISES_ASSERT(lu.image(tmp))
+ VERIFY_RAISES_ASSERT(lu.solve(tmp))
+ VERIFY_RAISES_ASSERT(lu.determinant())
+ VERIFY_RAISES_ASSERT(lu.rank())
+ VERIFY_RAISES_ASSERT(lu.dimensionOfKernel())
+ VERIFY_RAISES_ASSERT(lu.isInjective())
+ VERIFY_RAISES_ASSERT(lu.isSurjective())
+ VERIFY_RAISES_ASSERT(lu.isInvertible())
+ VERIFY_RAISES_ASSERT(lu.inverse())
+
+ PartialPivLU<MatrixType> plu;
+ VERIFY_RAISES_ASSERT(plu.matrixLU())
+ VERIFY_RAISES_ASSERT(plu.permutationP())
+ VERIFY_RAISES_ASSERT(plu.solve(tmp))
+ VERIFY_RAISES_ASSERT(plu.determinant())
+ VERIFY_RAISES_ASSERT(plu.inverse())
+}
+
+void test_lu()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( lu_non_invertible<Matrix3f>() );
+ CALL_SUBTEST_1( lu_verify_assert<Matrix3f>() );
+
+ CALL_SUBTEST_2( (lu_non_invertible<Matrix<double, 4, 6> >()) );
+ CALL_SUBTEST_2( (lu_verify_assert<Matrix<double, 4, 6> >()) );
+
+ CALL_SUBTEST_3( lu_non_invertible<MatrixXf>() );
+ CALL_SUBTEST_3( lu_invertible<MatrixXf>() );
+ CALL_SUBTEST_3( lu_verify_assert<MatrixXf>() );
+
+ CALL_SUBTEST_4( lu_non_invertible<MatrixXd>() );
+ CALL_SUBTEST_4( lu_invertible<MatrixXd>() );
+ CALL_SUBTEST_4( lu_partial_piv<MatrixXd>() );
+ CALL_SUBTEST_4( lu_verify_assert<MatrixXd>() );
+
+ CALL_SUBTEST_5( lu_non_invertible<MatrixXcf>() );
+ CALL_SUBTEST_5( lu_invertible<MatrixXcf>() );
+ CALL_SUBTEST_5( lu_verify_assert<MatrixXcf>() );
+
+ CALL_SUBTEST_6( lu_non_invertible<MatrixXcd>() );
+ CALL_SUBTEST_6( lu_invertible<MatrixXcd>() );
+ CALL_SUBTEST_6( lu_partial_piv<MatrixXcd>() );
+ CALL_SUBTEST_6( lu_verify_assert<MatrixXcd>() );
+
+ CALL_SUBTEST_7(( lu_non_invertible<Matrix<float,Dynamic,16> >() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_9( PartialPivLU<MatrixXf>(10) );
+ CALL_SUBTEST_9( FullPivLU<MatrixXf>(10, 20); );
+ }
+}
diff --git a/test/main.h b/test/main.h
new file mode 100644
index 000000000..2da327c17
--- /dev/null
+++ b/test/main.h
@@ -0,0 +1,472 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2008 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/.
+
+#include <cstdlib>
+#include <cerrno>
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <typeinfo>
+#include <limits>
+#include <algorithm>
+#include <sstream>
+#include <complex>
+#include <deque>
+#include <queue>
+
+#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
+#define B0 FORBIDDEN_IDENTIFIER
+
+// the following file is automatically generated by cmake
+#include "split_test_helper.h"
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+// bounds integer values for AltiVec
+#ifdef __ALTIVEC__
+#define EIGEN_MAKING_DOCS
+#endif
+
+#ifndef EIGEN_TEST_FUNC
+#error EIGEN_TEST_FUNC must be defined
+#endif
+
+#define DEFAULT_REPEAT 10
+
+#ifdef __ICC
+// disable warning #279: controlling expression is constant
+#pragma warning disable 279
+#endif
+
+namespace Eigen
+{
+ static std::vector<std::string> g_test_stack;
+ static int g_repeat;
+ static unsigned int g_seed;
+ static bool g_has_set_repeat, g_has_set_seed;
+}
+
+#define EI_PP_MAKE_STRING2(S) #S
+#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
+
+#define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, " ", "\n", "", "", "", "")
+
+#ifndef EIGEN_NO_ASSERTION_CHECKING
+
+ namespace Eigen
+ {
+ static const bool should_raise_an_assert = false;
+
+ // Used to avoid to raise two exceptions at a time in which
+ // case the exception is not properly caught.
+ // This may happen when a second exceptions is triggered in a destructor.
+ static bool no_more_assert = false;
+ static bool report_on_cerr_on_assert_failure = true;
+
+ struct eigen_assert_exception
+ {
+ eigen_assert_exception(void) {}
+ ~eigen_assert_exception() { Eigen::no_more_assert = false; }
+ };
+ }
+ // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is triggered while
+ // one should have been, then the list of excecuted assertions is printed out.
+ //
+ // EIGEN_DEBUG_ASSERTS is not enabled by default as it
+ // significantly increases the compilation time
+ // and might even introduce side effects that would hide
+ // some memory errors.
+ #ifdef EIGEN_DEBUG_ASSERTS
+
+ namespace Eigen
+ {
+ namespace internal
+ {
+ static bool push_assert = false;
+ }
+ static std::vector<std::string> eigen_assert_list;
+ }
+ #define eigen_assert(a) \
+ if( (!(a)) && (!no_more_assert) ) \
+ { \
+ if(report_on_cerr_on_assert_failure) \
+ std::cerr << #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \
+ Eigen::no_more_assert = true; \
+ throw Eigen::eigen_assert_exception(); \
+ } \
+ else if (Eigen::internal::push_assert) \
+ { \
+ eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__) " (" EI_PP_MAKE_STRING(__LINE__) ") : " #a) ); \
+ }
+
+ #define VERIFY_RAISES_ASSERT(a) \
+ { \
+ Eigen::no_more_assert = false; \
+ Eigen::eigen_assert_list.clear(); \
+ Eigen::internal::push_assert = true; \
+ Eigen::report_on_cerr_on_assert_failure = false; \
+ try { \
+ a; \
+ std::cerr << "One of the following asserts should have been triggered:\n"; \
+ for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai) \
+ std::cerr << " " << eigen_assert_list[ai] << "\n"; \
+ VERIFY(Eigen::should_raise_an_assert && # a); \
+ } catch (Eigen::eigen_assert_exception) { \
+ Eigen::internal::push_assert = false; VERIFY(true); \
+ } \
+ Eigen::report_on_cerr_on_assert_failure = true; \
+ Eigen::internal::push_assert = false; \
+ }
+
+ #else // EIGEN_DEBUG_ASSERTS
+ // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3
+ #define eigen_assert(a) \
+ if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) )\
+ { \
+ Eigen::no_more_assert = true; \
+ if(report_on_cerr_on_assert_failure) \
+ eigen_plain_assert(a); \
+ else \
+ throw Eigen::eigen_assert_exception(); \
+ }
+ #define VERIFY_RAISES_ASSERT(a) { \
+ Eigen::no_more_assert = false; \
+ Eigen::report_on_cerr_on_assert_failure = false; \
+ try { \
+ a; \
+ VERIFY(Eigen::should_raise_an_assert && # a); \
+ } \
+ catch (Eigen::eigen_assert_exception&) { VERIFY(true); } \
+ Eigen::report_on_cerr_on_assert_failure = true; \
+ }
+
+ #endif // EIGEN_DEBUG_ASSERTS
+
+ #define EIGEN_USE_CUSTOM_ASSERT
+
+#else // EIGEN_NO_ASSERTION_CHECKING
+
+ #define VERIFY_RAISES_ASSERT(a) {}
+
+#endif // EIGEN_NO_ASSERTION_CHECKING
+
+
+#define EIGEN_INTERNAL_DEBUGGING
+#include <Eigen/QR> // required for createRandomPIMatrixOfRank
+
+static void verify_impl(bool condition, const char *testname, const char *file, int line, const char *condition_as_string)
+{
+ if (!condition)
+ {
+ std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" \
+ << std::endl << " " << condition_as_string << std::endl << std::endl; \
+ abort();
+ }
+}
+
+#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_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))
+#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b))
+#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_isApproxOrLessThan(a, b))
+#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_isApproxOrLessThan(a, b))
+
+#define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a))
+
+#define CALL_SUBTEST(FUNC) do { \
+ g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \
+ FUNC; \
+ g_test_stack.pop_back(); \
+ } while (0)
+
+
+namespace Eigen {
+
+template<typename T> inline typename NumTraits<T>::Real test_precision() { return NumTraits<T>::dummy_precision(); }
+template<> inline float test_precision<float>() { return 1e-3f; }
+template<> inline double test_precision<double>() { return 1e-6; }
+template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
+template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
+template<> inline long double test_precision<long double>() { return 1e-6; }
+
+inline bool test_isApprox(const int& a, const int& b)
+{ return internal::isApprox(a, b, test_precision<int>()); }
+inline bool test_isMuchSmallerThan(const int& a, const int& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<int>()); }
+inline bool test_isApproxOrLessThan(const int& a, const int& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<int>()); }
+
+inline bool test_isApprox(const float& a, const float& b)
+{ return internal::isApprox(a, b, test_precision<float>()); }
+inline bool test_isMuchSmallerThan(const float& a, const float& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<float>()); }
+inline bool test_isApproxOrLessThan(const float& a, const float& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<float>()); }
+inline bool test_isApprox(const double& a, const double& b)
+{ return internal::isApprox(a, b, test_precision<double>()); }
+
+inline bool test_isMuchSmallerThan(const double& a, const double& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<double>()); }
+inline bool test_isApproxOrLessThan(const double& a, const double& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<double>()); }
+
+inline bool test_isApprox(const std::complex<float>& a, const std::complex<float>& b)
+{ return internal::isApprox(a, b, test_precision<std::complex<float> >()); }
+inline bool test_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); }
+
+inline bool test_isApprox(const std::complex<double>& a, const std::complex<double>& b)
+{ return internal::isApprox(a, b, test_precision<std::complex<double> >()); }
+inline bool test_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); }
+
+inline bool test_isApprox(const long double& a, const long double& b)
+{
+ bool ret = internal::isApprox(a, b, test_precision<long double>());
+ if (!ret) std::cerr
+ << std::endl << " actual = " << a
+ << std::endl << " expected = " << b << std::endl << std::endl;
+ return ret;
+}
+
+inline bool test_isMuchSmallerThan(const long double& a, const long double& b)
+{ return internal::isMuchSmallerThan(a, b, test_precision<long double>()); }
+inline bool test_isApproxOrLessThan(const long double& a, const long double& b)
+{ return internal::isApproxOrLessThan(a, b, test_precision<long double>()); }
+
+template<typename Type1, typename Type2>
+inline bool test_isApprox(const Type1& a, const Type2& b)
+{
+ return a.isApprox(b, test_precision<typename Type1::Scalar>());
+}
+
+// The idea behind this function is to compare the two scalars a and b where
+// the scalar ref is a hint about the expected order of magnitude of a and b.
+// Therefore, if for some reason a and b are very small compared to ref,
+// we won't issue a false negative.
+// This test could be: abs(a-b) <= eps * ref
+// However, it seems that simply comparing a+ref and b+ref is more sensitive to true error.
+template<typename Scalar,typename ScalarRef>
+inline bool test_isApproxWithRef(const Scalar& a, const Scalar& b, const ScalarRef& ref)
+{
+ return test_isApprox(a+ref, b+ref);
+}
+
+template<typename Derived1, typename Derived2>
+inline bool test_isMuchSmallerThan(const MatrixBase<Derived1>& m1,
+ const MatrixBase<Derived2>& m2)
+{
+ return m1.isMuchSmallerThan(m2, test_precision<typename internal::traits<Derived1>::Scalar>());
+}
+
+template<typename Derived>
+inline bool test_isMuchSmallerThan(const MatrixBase<Derived>& m,
+ const typename NumTraits<typename internal::traits<Derived>::Scalar>::Real& s)
+{
+ return m.isMuchSmallerThan(s, test_precision<typename internal::traits<Derived>::Scalar>());
+}
+
+template<typename Derived>
+inline bool test_isUnitary(const MatrixBase<Derived>& m)
+{
+ return m.isUnitary(test_precision<typename internal::traits<Derived>::Scalar>());
+}
+
+template<typename T, typename U>
+bool test_is_equal(const T& actual, const U& expected)
+{
+ if (actual==expected)
+ return true;
+ // false:
+ std::cerr
+ << std::endl << " actual = " << actual
+ << std::endl << " expected = " << expected << std::endl << std::endl;
+ return false;
+}
+
+/** Creates a random Partial Isometry matrix of given rank.
+ *
+ * A partial isometry is a matrix all of whose singular values are either 0 or 1.
+ * This is very useful to test rank-revealing algorithms.
+ */
+template<typename MatrixType>
+void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m)
+{
+ typedef typename internal::traits<MatrixType>::Index Index;
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+
+ typedef Matrix<Scalar, Dynamic, 1> VectorType;
+ typedef Matrix<Scalar, Rows, Rows> MatrixAType;
+ typedef Matrix<Scalar, Cols, Cols> MatrixBType;
+
+ if(desired_rank == 0)
+ {
+ m.setZero(rows,cols);
+ return;
+ }
+
+ if(desired_rank == 1)
+ {
+ // here we normalize the vectors to get a partial isometry
+ m = VectorType::Random(rows).normalized() * VectorType::Random(cols).normalized().transpose();
+ return;
+ }
+
+ MatrixAType a = MatrixAType::Random(rows,rows);
+ MatrixType d = MatrixType::Identity(rows,cols);
+ MatrixBType b = MatrixBType::Random(cols,cols);
+
+ // set the diagonal such that only desired_rank non-zero entries reamain
+ const Index diag_size = (std::min)(d.rows(),d.cols());
+ if(diag_size != desired_rank)
+ d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank);
+
+ HouseholderQR<MatrixAType> qra(a);
+ HouseholderQR<MatrixBType> qrb(b);
+ m = qra.householderQ() * d * qrb.householderQ();
+}
+
+template<typename PermutationVectorType>
+void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size)
+{
+ typedef typename PermutationVectorType::Index Index;
+ typedef typename PermutationVectorType::Scalar Scalar;
+ v.resize(size);
+ for(Index i = 0; i < size; ++i) v(i) = Scalar(i);
+ if(size == 1) return;
+ for(Index n = 0; n < 3 * size; ++n)
+ {
+ Index i = internal::random<Index>(0, size-1);
+ Index j;
+ do j = internal::random<Index>(0, size-1); while(j==i);
+ std::swap(v(i), v(j));
+ }
+}
+
+} // end namespace Eigen
+
+template<typename T> struct GetDifferentType;
+
+template<> struct GetDifferentType<float> { typedef double type; };
+template<> struct GetDifferentType<double> { typedef float type; };
+template<typename T> struct GetDifferentType<std::complex<T> >
+{ typedef std::complex<typename GetDifferentType<T>::type> type; };
+
+template<typename T> std::string type_name() { return "other"; }
+template<> std::string type_name<float>() { return "float"; }
+template<> std::string type_name<double>() { return "double"; }
+template<> std::string type_name<int>() { return "int"; }
+template<> std::string type_name<std::complex<float> >() { return "complex<float>"; }
+template<> std::string type_name<std::complex<double> >() { return "complex<double>"; }
+template<> std::string type_name<std::complex<int> >() { return "complex<int>"; }
+
+// forward declaration of the main test function
+void EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
+
+using namespace Eigen;
+
+void set_repeat_from_string(const char *str)
+{
+ errno = 0;
+ g_repeat = int(strtoul(str, 0, 10));
+ if(errno || g_repeat <= 0)
+ {
+ std::cout << "Invalid repeat value " << str << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ g_has_set_repeat = true;
+}
+
+void set_seed_from_string(const char *str)
+{
+ errno = 0;
+ g_seed = strtoul(str, 0, 10);
+ if(errno || g_seed == 0)
+ {
+ std::cout << "Invalid seed value " << str << std::endl;
+ exit(EXIT_FAILURE);
+ }
+ g_has_set_seed = true;
+}
+
+int main(int argc, char *argv[])
+{
+ g_has_set_repeat = false;
+ g_has_set_seed = false;
+ bool need_help = false;
+
+ for(int i = 1; i < argc; i++)
+ {
+ if(argv[i][0] == 'r')
+ {
+ if(g_has_set_repeat)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ set_repeat_from_string(argv[i]+1);
+ }
+ else if(argv[i][0] == 's')
+ {
+ if(g_has_set_seed)
+ {
+ std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
+ return 1;
+ }
+ set_seed_from_string(argv[i]+1);
+ }
+ else
+ {
+ need_help = true;
+ }
+ }
+
+ if(need_help)
+ {
+ std::cout << "This test application takes the following optional arguments:" << std::endl;
+ std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
+ std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl;
+ std::cout << std::endl;
+ std::cout << "If defined, the environment variables EIGEN_REPEAT and EIGEN_SEED" << std::endl;
+ std::cout << "will be used as default values for these parameters." << std::endl;
+ return 1;
+ }
+
+ char *env_EIGEN_REPEAT = getenv("EIGEN_REPEAT");
+ if(!g_has_set_repeat && env_EIGEN_REPEAT)
+ set_repeat_from_string(env_EIGEN_REPEAT);
+ char *env_EIGEN_SEED = getenv("EIGEN_SEED");
+ if(!g_has_set_seed && env_EIGEN_SEED)
+ set_seed_from_string(env_EIGEN_SEED);
+
+ if(!g_has_set_seed) g_seed = (unsigned int) time(NULL);
+ if(!g_has_set_repeat) g_repeat = DEFAULT_REPEAT;
+
+ std::cout << "Initializing random number generator with seed " << g_seed << std::endl;
+ srand(g_seed);
+ std::cout << "Repeating each test " << g_repeat << " times" << std::endl;
+
+ Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC));
+
+ EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
+ return 0;
+}
diff --git a/test/map.cpp b/test/map.cpp
new file mode 100644
index 000000000..fe983e802
--- /dev/null
+++ b/test/map.cpp
@@ -0,0 +1,144 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2010 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 EIGEN_NO_STATIC_ASSERT
+#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
+#endif
+
+#include "main.h"
+
+template<typename VectorType> void map_class_vector(const VectorType& m)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+
+ Index size = m.size();
+
+ // test Map.h
+ Scalar* array1 = internal::aligned_new<Scalar>(size);
+ Scalar* array2 = internal::aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ Map<VectorType, Aligned>(array1, size) = VectorType::Random(size);
+ Map<VectorType, Aligned>(array2, size) = Map<VectorType,Aligned>(array1, size);
+ Map<VectorType>(array3unaligned, size) = Map<VectorType>(array1, size);
+ VectorType ma1 = Map<VectorType, Aligned>(array1, size);
+ VectorType ma2 = Map<VectorType, Aligned>(array2, size);
+ VectorType ma3 = Map<VectorType>(array3unaligned, size);
+ VERIFY_IS_EQUAL(ma1, ma2);
+ VERIFY_IS_EQUAL(ma1, ma3);
+ #ifdef EIGEN_VECTORIZE
+ if(internal::packet_traits<Scalar>::Vectorizable)
+ VERIFY_RAISES_ASSERT((Map<VectorType,Aligned>(array3unaligned, size)))
+ #endif
+
+ internal::aligned_delete(array1, size);
+ internal::aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename MatrixType> void map_class_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = m.rows(), cols = m.cols(), size = rows*cols;
+
+ // test Map.h
+ Scalar* array1 = internal::aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array1[i] = Scalar(1);
+ Scalar* array2 = internal::aligned_new<Scalar>(size);
+ for(int i = 0; i < size; i++) array2[i] = Scalar(1);
+ Scalar* array3 = new Scalar[size+1];
+ for(int i = 0; i < size+1; i++) array3[i] = Scalar(1);
+ Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
+ Map<MatrixType, Aligned>(array1, rows, cols) = MatrixType::Ones(rows,cols);
+ Map<MatrixType>(array2, rows, cols) = Map<MatrixType>(array1, rows, cols);
+ Map<MatrixType>(array3unaligned, rows, cols) = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma1 = Map<MatrixType>(array1, rows, cols);
+ MatrixType ma2 = Map<MatrixType, Aligned>(array2, rows, cols);
+ VERIFY_IS_EQUAL(ma1, ma2);
+ MatrixType ma3 = Map<MatrixType>(array3unaligned, rows, cols);
+ VERIFY_IS_EQUAL(ma1, ma3);
+
+ internal::aligned_delete(array1, size);
+ internal::aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename VectorType> void map_static_methods(const VectorType& m)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+
+ Index size = m.size();
+
+ // test Map.h
+ Scalar* array1 = internal::aligned_new<Scalar>(size);
+ Scalar* array2 = internal::aligned_new<Scalar>(size);
+ Scalar* array3 = new Scalar[size+1];
+ Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3;
+
+ VectorType::MapAligned(array1, size) = VectorType::Random(size);
+ VectorType::Map(array2, size) = VectorType::Map(array1, size);
+ VectorType::Map(array3unaligned, size) = VectorType::Map(array1, size);
+ VectorType ma1 = VectorType::Map(array1, size);
+ VectorType ma2 = VectorType::MapAligned(array2, size);
+ VectorType ma3 = VectorType::Map(array3unaligned, size);
+ VERIFY_IS_EQUAL(ma1, ma2);
+ VERIFY_IS_EQUAL(ma1, ma3);
+
+ internal::aligned_delete(array1, size);
+ internal::aligned_delete(array2, size);
+ delete[] array3;
+}
+
+template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
+{
+ typedef typename PlainObjectType::Index Index;
+ typedef typename PlainObjectType::Scalar Scalar;
+
+ // there's a lot that we can't test here while still having this test compile!
+ // the only possible approach would be to run a script trying to compile stuff and checking that it fails.
+ // CMake can help with that.
+
+ // verify that map-to-const don't have LvalueBit
+ typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType> >::Flags & LvalueBit) );
+ VERIFY( !(internal::traits<Map<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType>::Flags & LvalueBit) );
+ VERIFY( !(Map<ConstPlainObjectType, Aligned>::Flags & LvalueBit) );
+}
+
+void test_map()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( map_class_vector(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( check_const_correctness(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_vector(Vector4d()) );
+ CALL_SUBTEST_2( check_const_correctness(Matrix4d()) );
+ CALL_SUBTEST_3( map_class_vector(RowVector4f()) );
+ CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) );
+ CALL_SUBTEST_5( map_class_vector(VectorXi(12)) );
+ CALL_SUBTEST_5( check_const_correctness(VectorXi(12)) );
+
+ CALL_SUBTEST_1( map_class_matrix(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_matrix(Matrix4d()) );
+ CALL_SUBTEST_11( map_class_matrix(Matrix<float,3,5>()) );
+ CALL_SUBTEST_4( map_class_matrix(MatrixXcf(internal::random<int>(1,10),internal::random<int>(1,10))) );
+ CALL_SUBTEST_5( map_class_matrix(MatrixXi(internal::random<int>(1,10),internal::random<int>(1,10))) );
+
+ CALL_SUBTEST_6( map_static_methods(Matrix<double, 1, 1>()) );
+ CALL_SUBTEST_7( map_static_methods(Vector3f()) );
+ CALL_SUBTEST_8( map_static_methods(RowVector3d()) );
+ CALL_SUBTEST_9( map_static_methods(VectorXcd(8)) );
+ CALL_SUBTEST_10( map_static_methods(VectorXf(12)) );
+ }
+}
diff --git a/test/mapstaticmethods.cpp b/test/mapstaticmethods.cpp
new file mode 100644
index 000000000..5b512bde4
--- /dev/null
+++ b/test/mapstaticmethods.cpp
@@ -0,0 +1,173 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+#include "main.h"
+
+float *ptr;
+const float *const_ptr;
+
+template<typename PlainObjectType,
+ bool IsDynamicSize = PlainObjectType::SizeAtCompileTime == Dynamic,
+ bool IsVector = PlainObjectType::IsVectorAtCompileTime
+>
+struct mapstaticmethods_impl {};
+
+template<typename PlainObjectType, bool IsVector>
+struct mapstaticmethods_impl<PlainObjectType, false, IsVector>
+{
+ static void run(const PlainObjectType& m)
+ {
+ mapstaticmethods_impl<PlainObjectType, true, IsVector>::run(m);
+
+ int i = internal::random<int>(2,5), j = internal::random<int>(2,5);
+
+ PlainObjectType::Map(ptr).setZero();
+ PlainObjectType::MapAligned(ptr).setZero();
+ PlainObjectType::Map(const_ptr).sum();
+ PlainObjectType::MapAligned(const_ptr).sum();
+
+ PlainObjectType::Map(ptr, InnerStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, InnerStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, InnerStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, InnerStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, InnerStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, InnerStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, InnerStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, InnerStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, OuterStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, OuterStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, OuterStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, OuterStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, OuterStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, OuterStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, OuterStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, OuterStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, Stride<Dynamic, Dynamic>(i,j)).setZero();
+ PlainObjectType::MapAligned(ptr, Stride<2,Dynamic>(2,i)).setZero();
+ PlainObjectType::Map(const_ptr, Stride<Dynamic,3>(i,3)).sum();
+ PlainObjectType::MapAligned(const_ptr, Stride<Dynamic, Dynamic>(i,j)).sum();
+
+ PlainObjectType::Map(ptr, Stride<2,3>()).setZero();
+ PlainObjectType::MapAligned(ptr, Stride<3,4>()).setZero();
+ PlainObjectType::Map(const_ptr, Stride<2,4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, Stride<5,3>()).sum();
+ }
+};
+
+template<typename PlainObjectType>
+struct mapstaticmethods_impl<PlainObjectType, true, false>
+{
+ static void run(const PlainObjectType& m)
+ {
+ int rows = m.rows(), cols = m.cols();
+
+ int i = internal::random<int>(2,5), j = internal::random<int>(2,5);
+
+ PlainObjectType::Map(ptr, rows, cols).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, InnerStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, InnerStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, InnerStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, InnerStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, InnerStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, InnerStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, InnerStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, InnerStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, OuterStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, OuterStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, OuterStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, OuterStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, OuterStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, OuterStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, OuterStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, OuterStride<5>()).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, Stride<Dynamic, Dynamic>(i,j)).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, Stride<2,Dynamic>(2,i)).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, Stride<Dynamic,3>(i,3)).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, Stride<Dynamic, Dynamic>(i,j)).sum();
+
+ PlainObjectType::Map(ptr, rows, cols, Stride<2,3>()).setZero();
+ PlainObjectType::MapAligned(ptr, rows, cols, Stride<3,4>()).setZero();
+ PlainObjectType::Map(const_ptr, rows, cols, Stride<2,4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, rows, cols, Stride<5,3>()).sum();
+ }
+};
+
+template<typename PlainObjectType>
+struct mapstaticmethods_impl<PlainObjectType, true, true>
+{
+ static void run(const PlainObjectType& v)
+ {
+ int size = v.size();
+
+ int i = internal::random<int>(2,5);
+
+ PlainObjectType::Map(ptr, size).setZero();
+ PlainObjectType::MapAligned(ptr, size).setZero();
+ PlainObjectType::Map(const_ptr, size).sum();
+ PlainObjectType::MapAligned(const_ptr, size).sum();
+
+ PlainObjectType::Map(ptr, size, InnerStride<>(i)).setZero();
+ PlainObjectType::MapAligned(ptr, size, InnerStride<>(i)).setZero();
+ PlainObjectType::Map(const_ptr, size, InnerStride<>(i)).sum();
+ PlainObjectType::MapAligned(const_ptr, size, InnerStride<>(i)).sum();
+
+ PlainObjectType::Map(ptr, size, InnerStride<2>()).setZero();
+ PlainObjectType::MapAligned(ptr, size, InnerStride<3>()).setZero();
+ PlainObjectType::Map(const_ptr, size, InnerStride<4>()).sum();
+ PlainObjectType::MapAligned(const_ptr, size, InnerStride<5>()).sum();
+ }
+};
+
+template<typename PlainObjectType>
+void mapstaticmethods(const PlainObjectType& m)
+{
+ mapstaticmethods_impl<PlainObjectType>::run(m);
+ VERIFY(true); // just to avoid 'unused function' warning
+}
+
+void test_mapstaticmethods()
+{
+ ptr = internal::aligned_new<float>(1000);
+ for(int i = 0; i < 1000; i++) ptr[i] = float(i);
+
+ const_ptr = ptr;
+
+ CALL_SUBTEST_1(( mapstaticmethods(Matrix<float, 1, 1>()) ));
+ CALL_SUBTEST_1(( mapstaticmethods(Vector2f()) ));
+ CALL_SUBTEST_2(( mapstaticmethods(Vector3f()) ));
+ CALL_SUBTEST_2(( mapstaticmethods(Matrix2f()) ));
+ CALL_SUBTEST_3(( mapstaticmethods(Matrix4f()) ));
+ CALL_SUBTEST_3(( mapstaticmethods(Array4f()) ));
+ CALL_SUBTEST_4(( mapstaticmethods(Array3f()) ));
+ CALL_SUBTEST_4(( mapstaticmethods(Array33f()) ));
+ CALL_SUBTEST_5(( mapstaticmethods(Array44f()) ));
+ CALL_SUBTEST_5(( mapstaticmethods(VectorXf(1)) ));
+ CALL_SUBTEST_5(( mapstaticmethods(VectorXf(8)) ));
+ CALL_SUBTEST_6(( mapstaticmethods(MatrixXf(1,1)) ));
+ CALL_SUBTEST_6(( mapstaticmethods(MatrixXf(5,7)) ));
+ CALL_SUBTEST_7(( mapstaticmethods(ArrayXf(1)) ));
+ CALL_SUBTEST_7(( mapstaticmethods(ArrayXf(5)) ));
+ CALL_SUBTEST_8(( mapstaticmethods(ArrayXXf(1,1)) ));
+ CALL_SUBTEST_8(( mapstaticmethods(ArrayXXf(8,6)) ));
+
+ internal::aligned_delete(ptr, 1000);
+}
+
diff --git a/test/mapstride.cpp b/test/mapstride.cpp
new file mode 100644
index 000000000..fe35b9d23
--- /dev/null
+++ b/test/mapstride.cpp
@@ -0,0 +1,146 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 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/.
+
+#include "main.h"
+
+template<int Alignment,typename VectorType> void map_class_vector(const VectorType& m)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+
+ Index size = m.size();
+
+ VectorType v = VectorType::Random(size);
+
+ Index arraysize = 3*size;
+
+ Scalar* a_array = internal::aligned_new<Scalar>(arraysize+1);
+ Scalar* array = a_array;
+ if(Alignment!=Aligned)
+ array = (Scalar*)(ptrdiff_t(a_array) + (internal::packet_traits<Scalar>::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits<Scalar>::Real)));
+
+ {
+ Map<VectorType, Alignment, InnerStride<3> > map(array, size);
+ map = v;
+ for(int i = 0; i < size; ++i)
+ {
+ VERIFY(array[3*i] == v[i]);
+ VERIFY(map[i] == v[i]);
+ }
+ }
+
+ {
+ Map<VectorType, Unaligned, InnerStride<Dynamic> > map(array, size, InnerStride<Dynamic>(2));
+ map = v;
+ for(int i = 0; i < size; ++i)
+ {
+ VERIFY(array[2*i] == v[i]);
+ VERIFY(map[i] == v[i]);
+ }
+ }
+
+ internal::aligned_delete(a_array, arraysize+1);
+}
+
+template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixType& _m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+
+ Index rows = _m.rows(), cols = _m.cols();
+
+ MatrixType m = MatrixType::Random(rows,cols);
+
+ Index arraysize = 2*(rows+4)*(cols+4);
+
+ Scalar* a_array = internal::aligned_new<Scalar>(arraysize+1);
+ Scalar* array = a_array;
+ if(Alignment!=Aligned)
+ array = (Scalar*)(ptrdiff_t(a_array) + (internal::packet_traits<Scalar>::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits<Scalar>::Real)));
+
+ // test no inner stride and some dynamic outer stride
+ {
+ Map<MatrixType, Alignment, OuterStride<Dynamic> > map(array, rows, cols, OuterStride<Dynamic>(m.innerSize()+1));
+ map = m;
+ VERIFY(map.outerStride() == map.innerSize()+1);
+ for(int i = 0; i < m.outerSize(); ++i)
+ for(int j = 0; j < m.innerSize(); ++j)
+ {
+ VERIFY(array[map.outerStride()*i+j] == m.coeffByOuterInner(i,j));
+ VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
+ }
+ }
+
+ // test no inner stride and an outer stride of +4. This is quite important as for fixed-size matrices,
+ // this allows to hit the special case where it's vectorizable.
+ {
+ enum {
+ InnerSize = MatrixType::InnerSizeAtCompileTime,
+ OuterStrideAtCompileTime = InnerSize==Dynamic ? Dynamic : InnerSize+4
+ };
+ Map<MatrixType, Alignment, OuterStride<OuterStrideAtCompileTime> >
+ map(array, rows, cols, OuterStride<OuterStrideAtCompileTime>(m.innerSize()+4));
+ map = m;
+ VERIFY(map.outerStride() == map.innerSize()+4);
+ for(int i = 0; i < m.outerSize(); ++i)
+ for(int j = 0; j < m.innerSize(); ++j)
+ {
+ VERIFY(array[map.outerStride()*i+j] == m.coeffByOuterInner(i,j));
+ VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
+ }
+ }
+
+ // test both inner stride and outer stride
+ {
+ Map<MatrixType, Alignment, Stride<Dynamic,Dynamic> > map(array, rows, cols, Stride<Dynamic,Dynamic>(2*m.innerSize()+1, 2));
+ map = m;
+ VERIFY(map.outerStride() == 2*map.innerSize()+1);
+ VERIFY(map.innerStride() == 2);
+ for(int i = 0; i < m.outerSize(); ++i)
+ for(int j = 0; j < m.innerSize(); ++j)
+ {
+ VERIFY(array[map.outerStride()*i+map.innerStride()*j] == m.coeffByOuterInner(i,j));
+ VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
+ }
+ }
+
+ internal::aligned_delete(a_array, arraysize+1);
+}
+
+void test_mapstride()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ EIGEN_UNUSED int maxn = 30;
+ CALL_SUBTEST_1( map_class_vector<Aligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( map_class_vector<Unaligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_vector<Aligned>(Vector4d()) );
+ CALL_SUBTEST_2( map_class_vector<Unaligned>(Vector4d()) );
+ CALL_SUBTEST_3( map_class_vector<Aligned>(RowVector4f()) );
+ CALL_SUBTEST_3( map_class_vector<Unaligned>(RowVector4f()) );
+ CALL_SUBTEST_4( map_class_vector<Aligned>(VectorXcf(internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_4( map_class_vector<Unaligned>(VectorXcf(internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_vector<Aligned>(VectorXi(internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_vector<Unaligned>(VectorXi(internal::random<int>(1,maxn))) );
+
+ CALL_SUBTEST_1( map_class_matrix<Aligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( map_class_matrix<Unaligned>(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( map_class_matrix<Aligned>(Matrix4d()) );
+ CALL_SUBTEST_2( map_class_matrix<Unaligned>(Matrix4d()) );
+ CALL_SUBTEST_3( map_class_matrix<Aligned>(Matrix<float,3,5>()) );
+ CALL_SUBTEST_3( map_class_matrix<Unaligned>(Matrix<float,3,5>()) );
+ CALL_SUBTEST_3( map_class_matrix<Aligned>(Matrix<float,4,8>()) );
+ CALL_SUBTEST_3( map_class_matrix<Unaligned>(Matrix<float,4,8>()) );
+ CALL_SUBTEST_4( map_class_matrix<Aligned>(MatrixXcf(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_4( map_class_matrix<Unaligned>(MatrixXcf(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_matrix<Aligned>(MatrixXi(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_5( map_class_matrix<Unaligned>(MatrixXi(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_6( map_class_matrix<Aligned>(MatrixXcd(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ CALL_SUBTEST_6( map_class_matrix<Unaligned>(MatrixXcd(internal::random<int>(1,maxn),internal::random<int>(1,maxn))) );
+ }
+}
diff --git a/test/meta.cpp b/test/meta.cpp
new file mode 100644
index 000000000..dc1d128d5
--- /dev/null
+++ b/test/meta.cpp
@@ -0,0 +1,76 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+void test_meta()
+{
+ typedef float & FloatRef;
+ typedef const float & ConstFloatRef;
+
+ VERIFY((internal::conditional<(3<4),internal::true_type, internal::false_type>::type::value));
+ VERIFY(( internal::is_same<float,float>::value));
+ VERIFY((!internal::is_same<float,double>::value));
+ VERIFY((!internal::is_same<float,float&>::value));
+ VERIFY((!internal::is_same<float,const float&>::value));
+
+ VERIFY(( internal::is_same<float,internal::remove_all<const float&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<const float*>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<const float*&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float**>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float**&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float* const *&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_all<float* const>::type >::value));
+
+ // test add_const
+ VERIFY(( internal::is_same< internal::add_const<float>::type, const float >::value));
+ VERIFY(( internal::is_same< internal::add_const<float*>::type, float* const>::value));
+ VERIFY(( internal::is_same< internal::add_const<float const*>::type, float const* const>::value));
+ VERIFY(( internal::is_same< internal::add_const<float&>::type, float& >::value));
+
+ // test remove_const
+ VERIFY(( internal::is_same< internal::remove_const<float const* const>::type, float const* >::value));
+ VERIFY(( internal::is_same< internal::remove_const<float const*>::type, float const* >::value));
+ VERIFY(( internal::is_same< internal::remove_const<float* const>::type, float* >::value));
+
+ // test add_const_on_value_type
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float&>::type, float const& >::value));
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float*>::type, float const* >::value));
+
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float>::type, const float >::value));
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<const float>::type, const float >::value));
+
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<const float* const>::type, const float* const>::value));
+ VERIFY(( internal::is_same< internal::add_const_on_value_type<float* const>::type, const float* const>::value));
+
+ VERIFY(( internal::is_same<float,internal::remove_reference<float&>::type >::value));
+ VERIFY(( internal::is_same<const float,internal::remove_reference<const float&>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_pointer<float*>::type >::value));
+ VERIFY(( internal::is_same<const float,internal::remove_pointer<const float*>::type >::value));
+ VERIFY(( internal::is_same<float,internal::remove_pointer<float* const >::type >::value));
+
+ VERIFY(internal::meta_sqrt<1>::ret == 1);
+ #define VERIFY_META_SQRT(X) VERIFY(internal::meta_sqrt<X>::ret == int(internal::sqrt(double(X))))
+ VERIFY_META_SQRT(2);
+ VERIFY_META_SQRT(3);
+ VERIFY_META_SQRT(4);
+ VERIFY_META_SQRT(5);
+ VERIFY_META_SQRT(6);
+ VERIFY_META_SQRT(8);
+ VERIFY_META_SQRT(9);
+ VERIFY_META_SQRT(15);
+ VERIFY_META_SQRT(16);
+ VERIFY_META_SQRT(17);
+ VERIFY_META_SQRT(255);
+ VERIFY_META_SQRT(256);
+ VERIFY_META_SQRT(257);
+ VERIFY_META_SQRT(1023);
+ VERIFY_META_SQRT(1024);
+ VERIFY_META_SQRT(1025);
+}
diff --git a/test/miscmatrices.cpp b/test/miscmatrices.cpp
new file mode 100644
index 000000000..af0481cfe
--- /dev/null
+++ b/test/miscmatrices.cpp
@@ -0,0 +1,48 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void miscMatrices(const MatrixType& m)
+{
+ /* this test covers the following files:
+ DiagonalMatrix.h Ones.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Index r = internal::random<Index>(0, rows-1), r2 = internal::random<Index>(0, rows-1), c = internal::random<Index>(0, cols-1);
+ VERIFY_IS_APPROX(MatrixType::Ones(rows,cols)(r,c), static_cast<Scalar>(1));
+ MatrixType m1 = MatrixType::Ones(rows,cols);
+ VERIFY_IS_APPROX(m1(r,c), static_cast<Scalar>(1));
+ VectorType v1 = VectorType::Random(rows);
+ v1[0];
+ Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
+ square(v1.asDiagonal());
+ if(r==r2) VERIFY_IS_APPROX(square(r,r2), v1[r]);
+ else VERIFY_IS_MUCH_SMALLER_THAN(square(r,r2), static_cast<Scalar>(1));
+ square = MatrixType::Zero(rows, rows);
+ square.diagonal() = VectorType::Ones(rows);
+ VERIFY_IS_APPROX(square, MatrixType::Identity(rows, rows));
+}
+
+void test_miscmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( miscMatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( miscMatrices(Matrix4d()) );
+ CALL_SUBTEST_3( miscMatrices(MatrixXcf(3, 3)) );
+ CALL_SUBTEST_4( miscMatrices(MatrixXi(8, 12)) );
+ CALL_SUBTEST_5( miscMatrices(MatrixXcd(20, 20)) );
+ }
+}
diff --git a/test/mixingtypes.cpp b/test/mixingtypes.cpp
new file mode 100644
index 000000000..6c2f74875
--- /dev/null
+++ b/test/mixingtypes.cpp
@@ -0,0 +1,132 @@
+// 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 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/.
+
+// work around "uninitialized" warnings and give that option some testing
+#define EIGEN_INITIALIZE_MATRICES_BY_ZERO
+
+#ifndef EIGEN_NO_STATIC_ASSERT
+#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
+#endif
+
+// #ifndef EIGEN_DONT_VECTORIZE
+// #define EIGEN_DONT_VECTORIZE // SSE intrinsics aren't designed to allow mixing types
+// #endif
+
+#include "main.h"
+
+using namespace std;
+
+template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
+{
+ typedef std::complex<float> CF;
+ typedef std::complex<double> CD;
+ typedef Matrix<float, SizeAtCompileType, SizeAtCompileType> Mat_f;
+ typedef Matrix<double, SizeAtCompileType, SizeAtCompileType> Mat_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, SizeAtCompileType> Mat_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, SizeAtCompileType> Mat_cd;
+ typedef Matrix<float, SizeAtCompileType, 1> Vec_f;
+ typedef Matrix<double, SizeAtCompileType, 1> Vec_d;
+ typedef Matrix<std::complex<float>, SizeAtCompileType, 1> Vec_cf;
+ typedef Matrix<std::complex<double>, SizeAtCompileType, 1> Vec_cd;
+
+ Mat_f mf = Mat_f::Random(size,size);
+ Mat_d md = mf.template cast<double>();
+ Mat_cf mcf = Mat_cf::Random(size,size);
+ Mat_cd mcd = mcf.template cast<complex<double> >();
+ Vec_f vf = Vec_f::Random(size,1);
+ Vec_d vd = vf.template cast<double>();
+ Vec_cf vcf = Vec_cf::Random(size,1);
+ Vec_cd vcd = vcf.template cast<complex<double> >();
+ float sf = internal::random<float>();
+ double sd = internal::random<double>();
+ complex<float> scf = internal::random<complex<float> >();
+ complex<double> scd = internal::random<complex<double> >();
+
+
+ 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);
+
+ // check scalar products
+ VERIFY_IS_APPROX(vcf * sf , vcf * complex<float>(sf));
+ VERIFY_IS_APPROX(sd * vcd, complex<double>(sd) * vcd);
+ VERIFY_IS_APPROX(vf * scf , vf.template cast<complex<float> >() * scf);
+ VERIFY_IS_APPROX(scd * vd, scd * vd.template cast<complex<double> >());
+
+ // check dot product
+ vf.dot(vf);
+#if 0 // we get other compilation errors here than just static asserts
+ VERIFY_RAISES_ASSERT(vd.dot(vf));
+#endif
+ VERIFY_IS_APPROX(vcf.dot(vf), vcf.dot(vf.template cast<complex<float> >()));
+
+ // check diagonal product
+ VERIFY_IS_APPROX(vf.asDiagonal() * mcf, vf.template cast<complex<float> >().asDiagonal() * mcf);
+ VERIFY_IS_APPROX(vcd.asDiagonal() * md, vcd.asDiagonal() * md.template cast<complex<double> >());
+ VERIFY_IS_APPROX(mcf * vf.asDiagonal(), mcf * vf.template cast<complex<float> >().asDiagonal());
+ VERIFY_IS_APPROX(md * vcd.asDiagonal(), md.template cast<complex<double> >() * vcd.asDiagonal());
+// vd.asDiagonal() * mf; // does not even compile
+// vcd.asDiagonal() * mf; // does not even compile
+
+ // check inner product
+ VERIFY_IS_APPROX((vf.transpose() * vcf).value(), (vf.template cast<complex<float> >().transpose() * vcf).value());
+
+ // check outer product
+ VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast<complex<float> >() * vcf.transpose()).eval());
+
+ // coeff wise product
+
+ VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast<complex<float> >() * vcf.transpose()).eval());
+
+ Mat_cd mcd2 = mcd;
+ VERIFY_IS_APPROX(mcd.array() *= md.array(), mcd2.array() *= md.array().template cast<std::complex<double> >());
+
+ // check matrix-matrix products
+
+ VERIFY_IS_APPROX(sd*md*mcd, (sd*md).template cast<CD>().eval()*mcd);
+ VERIFY_IS_APPROX(sd*mcd*md, sd*mcd*md.template cast<CD>());
+ VERIFY_IS_APPROX(scd*md*mcd, scd*md.template cast<CD>().eval()*mcd);
+ VERIFY_IS_APPROX(scd*mcd*md, scd*mcd*md.template cast<CD>());
+
+ VERIFY_IS_APPROX(sf*mf*mcf, sf*mf.template cast<CF>()*mcf);
+ VERIFY_IS_APPROX(sf*mcf*mf, sf*mcf*mf.template cast<CF>());
+ VERIFY_IS_APPROX(scf*mf*mcf, scf*mf.template cast<CF>()*mcf);
+ VERIFY_IS_APPROX(scf*mcf*mf, scf*mcf*mf.template cast<CF>());
+
+ VERIFY_IS_APPROX(sf*mf*vcf, (sf*mf).template cast<CF>().eval()*vcf);
+ VERIFY_IS_APPROX(scf*mf*vcf,(scf*mf.template cast<CF>()).eval()*vcf);
+ VERIFY_IS_APPROX(sf*mcf*vf, sf*mcf*vf.template cast<CF>());
+ VERIFY_IS_APPROX(scf*mcf*vf,scf*mcf*vf.template cast<CF>());
+
+ VERIFY_IS_APPROX(sf*vcf.adjoint()*mf, sf*vcf.adjoint()*mf.template cast<CF>().eval());
+ VERIFY_IS_APPROX(scf*vcf.adjoint()*mf, scf*vcf.adjoint()*mf.template cast<CF>().eval());
+ VERIFY_IS_APPROX(sf*vf.adjoint()*mcf, sf*vf.adjoint().template cast<CF>().eval()*mcf);
+ VERIFY_IS_APPROX(scf*vf.adjoint()*mcf, scf*vf.adjoint().template cast<CF>().eval()*mcf);
+
+ VERIFY_IS_APPROX(sd*md*vcd, (sd*md).template cast<CD>().eval()*vcd);
+ VERIFY_IS_APPROX(scd*md*vcd,(scd*md.template cast<CD>()).eval()*vcd);
+ VERIFY_IS_APPROX(sd*mcd*vd, sd*mcd*vd.template cast<CD>().eval());
+ VERIFY_IS_APPROX(scd*mcd*vd,scd*mcd*vd.template cast<CD>().eval());
+
+ VERIFY_IS_APPROX(sd*vcd.adjoint()*md, sd*vcd.adjoint()*md.template cast<CD>().eval());
+ VERIFY_IS_APPROX(scd*vcd.adjoint()*md, scd*vcd.adjoint()*md.template cast<CD>().eval());
+ VERIFY_IS_APPROX(sd*vd.adjoint()*mcd, sd*vd.adjoint().template cast<CD>().eval()*mcd);
+ VERIFY_IS_APPROX(scd*vd.adjoint()*mcd, scd*vd.adjoint().template cast<CD>().eval()*mcd);
+}
+
+void test_mixingtypes()
+{
+ CALL_SUBTEST_1(mixingtypes<3>());
+ CALL_SUBTEST_2(mixingtypes<4>());
+ CALL_SUBTEST_3(mixingtypes<Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)));
+}
diff --git a/test/nesting_ops.cpp b/test/nesting_ops.cpp
new file mode 100644
index 000000000..938ebcb7a
--- /dev/null
+++ b/test/nesting_ops.cpp
@@ -0,0 +1,41 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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/.
+
+#include "main.h"
+
+template <typename MatrixType> void run_nesting_ops(const MatrixType& _m)
+{
+ typename MatrixType::Nested m(_m);
+ typedef typename MatrixType::Scalar Scalar;
+
+#ifdef NDEBUG
+ const bool is_debug = false;
+#else
+ const bool is_debug = true;
+#endif
+
+ // Make really sure that we are in debug mode! We don't want any type of
+ // inlining for these tests to pass.
+ VERIFY(is_debug);
+
+ // The only intention of these tests is to ensure that this code does
+ // not trigger any asserts or segmentation faults... more to come.
+ VERIFY_IS_APPROX( (m.transpose() * m).diagonal().sum(), (m.transpose() * m).diagonal().sum() );
+ VERIFY_IS_APPROX( (m.transpose() * m).diagonal().array().abs().sum(), (m.transpose() * m).diagonal().array().abs().sum() );
+
+ VERIFY_IS_APPROX( (m.transpose() * m).array().abs().sum(), (m.transpose() * m).array().abs().sum() );
+}
+
+void test_nesting_ops()
+{
+ CALL_SUBTEST_1(run_nesting_ops(MatrixXf::Random(25,25)));
+ CALL_SUBTEST_2(run_nesting_ops(MatrixXd::Random(25,25)));
+ CALL_SUBTEST_3(run_nesting_ops(Matrix4f::Random()));
+ CALL_SUBTEST_4(run_nesting_ops(Matrix4d::Random()));
+}
diff --git a/test/nomalloc.cpp b/test/nomalloc.cpp
new file mode 100644
index 000000000..d4ffcefcb
--- /dev/null
+++ b/test/nomalloc.cpp
@@ -0,0 +1,174 @@
+// 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) 2006-2008 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/.
+
+// this hack is needed to make this file compiles with -pedantic (gcc)
+#ifdef __GNUC__
+#define throw(X)
+#endif
+// 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
+
+#include "main.h"
+#include <Eigen/Cholesky>
+#include <Eigen/Eigenvalues>
+#include <Eigen/LU>
+#include <Eigen/QR>
+#include <Eigen/SVD>
+
+template<typename MatrixType> void nomalloc(const MatrixType& m)
+{
+ /* this test check no dynamic memory allocation are issued with fixed-size matrices
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
+ VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
+ VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), (m1.array()*m1.array()).matrix());
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+
+ m2.col(0).noalias() = m1 * m1.col(0);
+ m2.col(0).noalias() -= m1.adjoint() * m1.col(0);
+ m2.col(0).noalias() -= m1 * m1.row(0).adjoint();
+ m2.col(0).noalias() -= m1.adjoint() * m1.row(0).adjoint();
+
+ m2.row(0).noalias() = m1.row(0) * m1;
+ m2.row(0).noalias() -= m1.row(0) * m1.adjoint();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1;
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint();
+ VERIFY_IS_APPROX(m2,m2);
+
+ m2.col(0).noalias() = m1.template triangularView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.template triangularView<Upper>() * m1.row(0).adjoint();
+ m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.row(0).adjoint();
+
+ m2.row(0).noalias() = m1.row(0) * m1.template triangularView<Upper>();
+ m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template triangularView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template triangularView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template triangularView<Upper>();
+ VERIFY_IS_APPROX(m2,m2);
+
+ m2.col(0).noalias() = m1.template selfadjointView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.col(0);
+ m2.col(0).noalias() -= m1.template selfadjointView<Upper>() * m1.row(0).adjoint();
+ m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.row(0).adjoint();
+
+ m2.row(0).noalias() = m1.row(0) * m1.template selfadjointView<Upper>();
+ m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template selfadjointView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template selfadjointView<Upper>();
+ m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template selfadjointView<Upper>();
+ VERIFY_IS_APPROX(m2,m2);
+
+ m2.template selfadjointView<Lower>().rankUpdate(m1.col(0),-1);
+ m2.template selfadjointView<Lower>().rankUpdate(m1.row(0),-1);
+
+ // The following fancy matrix-matrix products are not safe yet regarding static allocation
+// m1 += m1.template triangularView<Upper>() * m2.col(;
+// m1.template selfadjointView<Lower>().rankUpdate(m2);
+// m1 += m1.template triangularView<Upper>() * m2;
+// m1 += m1.template selfadjointView<Lower>() * m2;
+// VERIFY_IS_APPROX(m1,m1);
+}
+
+template<typename Scalar>
+void ctms_decompositions()
+{
+ const int maxSize = 16;
+ const int size = 12;
+
+ typedef Eigen::Matrix<Scalar,
+ Eigen::Dynamic, Eigen::Dynamic,
+ 0,
+ maxSize, maxSize> Matrix;
+
+ typedef Eigen::Matrix<Scalar,
+ Eigen::Dynamic, 1,
+ 0,
+ maxSize, 1> Vector;
+
+ typedef Eigen::Matrix<std::complex<Scalar>,
+ Eigen::Dynamic, Eigen::Dynamic,
+ 0,
+ maxSize, maxSize> ComplexMatrix;
+
+ const Matrix A(Matrix::Random(size, size)), B(Matrix::Random(size, size));
+ Matrix X(size,size);
+ const ComplexMatrix complexA(ComplexMatrix::Random(size, size));
+ const Matrix saA = A.adjoint() * A;
+ const Vector b(Vector::Random(size));
+ Vector x(size);
+
+ // Cholesky module
+ Eigen::LLT<Matrix> LLT; LLT.compute(A);
+ X = LLT.solve(B);
+ x = LLT.solve(b);
+ Eigen::LDLT<Matrix> LDLT; LDLT.compute(A);
+ X = LDLT.solve(B);
+ x = LDLT.solve(b);
+
+ // Eigenvalues module
+ Eigen::HessenbergDecomposition<ComplexMatrix> hessDecomp; hessDecomp.compute(complexA);
+ Eigen::ComplexSchur<ComplexMatrix> cSchur(size); cSchur.compute(complexA);
+ Eigen::ComplexEigenSolver<ComplexMatrix> cEigSolver; cEigSolver.compute(complexA);
+ Eigen::EigenSolver<Matrix> eigSolver; eigSolver.compute(A);
+ Eigen::SelfAdjointEigenSolver<Matrix> saEigSolver(size); saEigSolver.compute(saA);
+ Eigen::Tridiagonalization<Matrix> tridiag; tridiag.compute(saA);
+
+ // LU module
+ Eigen::PartialPivLU<Matrix> ppLU; ppLU.compute(A);
+ X = ppLU.solve(B);
+ x = ppLU.solve(b);
+ Eigen::FullPivLU<Matrix> fpLU; fpLU.compute(A);
+ X = fpLU.solve(B);
+ x = fpLU.solve(b);
+
+ // QR module
+ Eigen::HouseholderQR<Matrix> hQR; hQR.compute(A);
+ X = hQR.solve(B);
+ x = hQR.solve(b);
+ Eigen::ColPivHouseholderQR<Matrix> cpQR; cpQR.compute(A);
+ X = cpQR.solve(B);
+ x = cpQR.solve(b);
+ Eigen::FullPivHouseholderQR<Matrix> fpQR; fpQR.compute(A);
+ // FIXME X = fpQR.solve(B);
+ x = fpQR.solve(b);
+
+ // SVD module
+ Eigen::JacobiSVD<Matrix> jSVD; jSVD.compute(A, ComputeFullU | ComputeFullV);
+}
+
+void test_nomalloc()
+{
+ // 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>()) );
+ CALL_SUBTEST_2(nomalloc(Matrix4d()) );
+ CALL_SUBTEST_3(nomalloc(Matrix<float,32,32>()) );
+
+ // Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms)
+ CALL_SUBTEST_4(ctms_decompositions<float>());
+
+}
diff --git a/test/nullary.cpp b/test/nullary.cpp
new file mode 100644
index 000000000..1220e3f97
--- /dev/null
+++ b/test/nullary.cpp
@@ -0,0 +1,123 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010-2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+
+template<typename MatrixType>
+bool equalsIdentity(const MatrixType& A)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ Scalar zero = static_cast<Scalar>(0);
+
+ bool offDiagOK = true;
+ for (Index i = 0; i < A.rows(); ++i) {
+ for (Index j = i+1; j < A.cols(); ++j) {
+ offDiagOK = offDiagOK && (A(i,j) == zero);
+ }
+ }
+ for (Index i = 0; i < A.rows(); ++i) {
+ for (Index j = 0; j < (std::min)(i, A.cols()); ++j) {
+ offDiagOK = offDiagOK && (A(i,j) == zero);
+ }
+ }
+
+ bool diagOK = (A.diagonal().array() == 1).all();
+ return offDiagOK && diagOK;
+}
+
+template<typename VectorType>
+void testVectorType(const VectorType& base)
+{
+ typedef typename internal::traits<VectorType>::Index Index;
+ typedef typename internal::traits<VectorType>::Scalar Scalar;
+
+ const Index size = base.size();
+
+ Scalar high = internal::random<Scalar>(-500,500);
+ Scalar low = (size == 1 ? high : internal::random<Scalar>(-500,500));
+ if (low>high) std::swap(low,high);
+
+ const Scalar step = ((size == 1) ? 1 : (high-low)/(size-1));
+
+ // check whether the result yields what we expect it to do
+ VectorType m(base);
+ m.setLinSpaced(size,low,high);
+
+ VectorType n(size);
+ for (int i=0; i<size; ++i)
+ n(i) = low+i*step;
+
+ VERIFY_IS_APPROX(m,n);
+
+ // random access version
+ m = VectorType::LinSpaced(size,low,high);
+ VERIFY_IS_APPROX(m,n);
+
+ // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79).
+ VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits<Scalar>::epsilon() );
+
+ // These guys sometimes fail! This is not good. Any ideas how to fix them!?
+ //VERIFY( m(m.size()-1) == high );
+ //VERIFY( m(0) == low );
+
+ // sequential access version
+ m = VectorType::LinSpaced(Sequential,size,low,high);
+ VERIFY_IS_APPROX(m,n);
+
+ // These guys sometimes fail! This is not good. Any ideas how to fix them!?
+ //VERIFY( m(m.size()-1) == high );
+ //VERIFY( m(0) == low );
+
+ // check whether everything works with row and col major vectors
+ Matrix<Scalar,Dynamic,1> row_vector(size);
+ 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()));
+
+ Matrix<Scalar,Dynamic,1> size_changer(size+50);
+ size_changer.setLinSpaced(size,low,high);
+ VERIFY( size_changer.size() == size );
+
+ typedef Matrix<Scalar,1,1> ScalarMatrix;
+ ScalarMatrix scalar;
+ scalar.setLinSpaced(1,low,high);
+ VERIFY_IS_APPROX( scalar, ScalarMatrix::Constant(high) );
+ VERIFY_IS_APPROX( ScalarMatrix::LinSpaced(1,low,high), ScalarMatrix::Constant(high) );
+}
+
+template<typename MatrixType>
+void testMatrixType(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ const Index rows = m.rows();
+ const Index cols = m.cols();
+
+ MatrixType A;
+ A.setIdentity(rows, cols);
+ VERIFY(equalsIdentity(A));
+ VERIFY(equalsIdentity(MatrixType::Identity(rows, cols)));
+}
+
+void test_nullary()
+{
+ CALL_SUBTEST_1( testMatrixType(Matrix2d()) );
+ CALL_SUBTEST_2( testMatrixType(MatrixXcf(internal::random<int>(1,300),internal::random<int>(1,300))) );
+ CALL_SUBTEST_3( testMatrixType(MatrixXf(internal::random<int>(1,300),internal::random<int>(1,300))) );
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_4( testVectorType(VectorXd(internal::random<int>(1,300))) );
+ CALL_SUBTEST_5( testVectorType(Vector4d()) ); // regression test for bug 232
+ CALL_SUBTEST_6( testVectorType(Vector3d()) );
+ CALL_SUBTEST_7( testVectorType(VectorXf(internal::random<int>(1,300))) );
+ CALL_SUBTEST_8( testVectorType(Vector3f()) );
+ CALL_SUBTEST_8( testVectorType(Matrix<float,1,1>()) );
+ }
+}
diff --git a/test/packetmath.cpp b/test/packetmath.cpp
new file mode 100644
index 000000000..c1464e994
--- /dev/null
+++ b/test/packetmath.cpp
@@ -0,0 +1,345 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+// using namespace Eigen;
+
+namespace Eigen {
+namespace internal {
+template<typename T> T negate(const T& x) { return -x; }
+}
+}
+
+template<typename Scalar> bool isApproxAbs(const Scalar& a, const Scalar& b, const typename NumTraits<Scalar>::Real& refvalue)
+{
+ return internal::isMuchSmallerThan(a-b, refvalue);
+}
+
+template<typename Scalar> bool areApproxAbs(const Scalar* a, const Scalar* b, int size, const typename NumTraits<Scalar>::Real& refvalue)
+{
+ for (int i=0; i<size; ++i)
+ {
+ if (!isApproxAbs(a[i],b[i],refvalue))
+ {
+ std::cout << "[" << Map<const Matrix<Scalar,1,Dynamic> >(a,size) << "]" << " != " << Map<const Matrix<Scalar,1,Dynamic> >(b,size) << "\n";
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename Scalar> bool areApprox(const Scalar* a, const Scalar* b, int size)
+{
+ for (int i=0; i<size; ++i)
+ {
+ if (!internal::isApprox(a[i],b[i]))
+ {
+ std::cout << "[" << Map<const Matrix<Scalar,1,Dynamic> >(a,size) << "]" << " != " << Map<const Matrix<Scalar,1,Dynamic> >(b,size) << "\n";
+ return false;
+ }
+ }
+ return true;
+}
+
+
+#define CHECK_CWISE2(REFOP, POP) { \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i], data1[i+PacketSize]); \
+ internal::pstore(data2, POP(internal::pload<Packet>(data1), internal::pload<Packet>(data1+PacketSize))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+#define CHECK_CWISE1(REFOP, POP) { \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i]); \
+ internal::pstore(data2, POP(internal::pload<Packet>(data1))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+template<bool Cond,typename Packet>
+struct packet_helper
+{
+ template<typename T>
+ inline Packet load(const T* from) const { return internal::pload<Packet>(from); }
+
+ template<typename T>
+ inline void store(T* to, const Packet& x) const { internal::pstore(to,x); }
+};
+
+template<typename Packet>
+struct packet_helper<false,Packet>
+{
+ template<typename T>
+ inline T load(const T* from) const { return *from; }
+
+ template<typename T>
+ inline void store(T* to, const T& x) const { *to = x; }
+};
+
+#define CHECK_CWISE1_IF(COND, REFOP, POP) if(COND) { \
+ packet_helper<COND,Packet> h; \
+ for (int i=0; i<PacketSize; ++i) \
+ ref[i] = REFOP(data1[i]); \
+ h.store(data2, POP(h.load(data1))); \
+ VERIFY(areApprox(ref, data2, PacketSize) && #POP); \
+}
+
+#define REF_ADD(a,b) ((a)+(b))
+#define REF_SUB(a,b) ((a)-(b))
+#define REF_MUL(a,b) ((a)*(b))
+#define REF_DIV(a,b) ((a)/(b))
+
+template<typename Scalar> void packetmath()
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN16 Scalar data1[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Scalar data2[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Packet packets[PacketSize*2];
+ EIGEN_ALIGN16 Scalar ref[internal::packet_traits<Scalar>::size*4];
+ RealScalar refvalue = 0;
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>()/RealScalar(PacketSize);
+ data2[i] = internal::random<Scalar>()/RealScalar(PacketSize);
+ refvalue = (std::max)(refvalue,internal::abs(data1[i]));
+ }
+
+ internal::pstore(data2, internal::pload<Packet>(data1));
+ VERIFY(areApprox(data1, data2, PacketSize) && "aligned load/store");
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ internal::pstore(data2, internal::ploadu<Packet>(data1+offset));
+ VERIFY(areApprox(data1+offset, data2, PacketSize) && "internal::ploadu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ internal::pstoreu(data2+offset, internal::pload<Packet>(data1));
+ VERIFY(areApprox(data1, data2+offset, PacketSize) && "internal::pstoreu");
+ }
+
+ for (int offset=0; offset<PacketSize; ++offset)
+ {
+ packets[0] = internal::pload<Packet>(data1);
+ packets[1] = internal::pload<Packet>(data1+PacketSize);
+ if (offset==0) internal::palign<0>(packets[0], packets[1]);
+ else if (offset==1) internal::palign<1>(packets[0], packets[1]);
+ else if (offset==2) internal::palign<2>(packets[0], packets[1]);
+ else if (offset==3) internal::palign<3>(packets[0], packets[1]);
+ internal::pstore(data2, packets[0]);
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[i+offset];
+
+ typedef Matrix<Scalar, PacketSize, 1> Vector;
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::palign");
+ }
+
+ CHECK_CWISE2(REF_ADD, internal::padd);
+ CHECK_CWISE2(REF_SUB, internal::psub);
+ CHECK_CWISE2(REF_MUL, internal::pmul);
+ #ifndef EIGEN_VECTORIZE_ALTIVEC
+ if (!internal::is_same<Scalar,int>::value)
+ CHECK_CWISE2(REF_DIV, internal::pdiv);
+ #endif
+ CHECK_CWISE1(internal::negate, internal::pnegate);
+ CHECK_CWISE1(internal::conj, internal::pconj);
+
+ for(int offset=0;offset<3;++offset)
+ {
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[offset];
+ internal::pstore(data2, internal::pset1<Packet>(data1[offset]));
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::pset1");
+ }
+
+ VERIFY(internal::isApprox(data1[0], internal::pfirst(internal::pload<Packet>(data1))) && "internal::pfirst");
+
+ if(PacketSize>1)
+ {
+ for(int offset=0;offset<4;++offset)
+ {
+ for(int i=0;i<PacketSize/2;++i)
+ ref[2*i+0] = ref[2*i+1] = data1[offset+i];
+ internal::pstore(data2,internal::ploaddup<Packet>(data1+offset));
+ VERIFY(areApprox(ref, data2, PacketSize) && "ploaddup");
+ }
+ }
+
+ ref[0] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] += data1[i];
+ VERIFY(isApproxAbs(ref[0], internal::predux(internal::pload<Packet>(data1)), refvalue) && "internal::predux");
+
+ ref[0] = 1;
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] *= data1[i];
+ VERIFY(internal::isApprox(ref[0], internal::predux_mul(internal::pload<Packet>(data1))) && "internal::predux_mul");
+
+ for (int j=0; j<PacketSize; ++j)
+ {
+ ref[j] = 0;
+ for (int i=0; i<PacketSize; ++i)
+ ref[j] += data1[i+j*PacketSize];
+ packets[j] = internal::pload<Packet>(data1+j*PacketSize);
+ }
+ internal::pstore(data2, internal::preduxp(packets));
+ VERIFY(areApproxAbs(ref, data2, PacketSize, refvalue) && "internal::preduxp");
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[PacketSize-i-1];
+ internal::pstore(data2, internal::preverse(internal::pload<Packet>(data1)));
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::preverse");
+}
+
+template<typename Scalar> void packetmath_real()
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN16 Scalar data1[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Scalar data2[internal::packet_traits<Scalar>::size*4];
+ EIGEN_ALIGN16 Scalar ref[internal::packet_traits<Scalar>::size*4];
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(-1e3,1e3);
+ data2[i] = internal::random<Scalar>(-1e3,1e3);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasSin, internal::sin, internal::psin);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasCos, internal::cos, internal::pcos);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasTan, internal::tan, internal::ptan);
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(-1,1);
+ data2[i] = internal::random<Scalar>(-1,1);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasASin, internal::asin, internal::pasin);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasACos, internal::acos, internal::pacos);
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(-87,88);
+ data2[i] = internal::random<Scalar>(-87,88);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasExp, internal::exp, internal::pexp);
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>(0,1e6);
+ data2[i] = internal::random<Scalar>(0,1e6);
+ }
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasLog, internal::log, internal::plog);
+ CHECK_CWISE1_IF(internal::packet_traits<Scalar>::HasSqrt, internal::sqrt, internal::psqrt);
+
+ ref[0] = data1[0];
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] = (std::min)(ref[0],data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_min(internal::pload<Packet>(data1))) && "internal::predux_min");
+
+ CHECK_CWISE2((std::min), internal::pmin);
+ CHECK_CWISE2((std::max), internal::pmax);
+ CHECK_CWISE1(internal::abs, internal::pabs);
+
+ ref[0] = data1[0];
+ for (int i=0; i<PacketSize; ++i)
+ ref[0] = (std::max)(ref[0],data1[i]);
+ VERIFY(internal::isApprox(ref[0], internal::predux_max(internal::pload<Packet>(data1))) && "internal::predux_max");
+
+ for (int i=0; i<PacketSize; ++i)
+ ref[i] = data1[0]+Scalar(i);
+ internal::pstore(data2, internal::plset(data1[0]));
+ VERIFY(areApprox(ref, data2, PacketSize) && "internal::plset");
+}
+
+template<typename Scalar,bool ConjLhs,bool ConjRhs> void test_conj_helper(Scalar* data1, Scalar* data2, Scalar* ref, Scalar* pval)
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+
+ internal::conj_if<ConjLhs> cj0;
+ internal::conj_if<ConjRhs> cj1;
+ internal::conj_helper<Scalar,Scalar,ConjLhs,ConjRhs> cj;
+ internal::conj_helper<Packet,Packet,ConjLhs,ConjRhs> pcj;
+
+ for(int i=0;i<PacketSize;++i)
+ {
+ ref[i] = cj0(data1[i]) * cj1(data2[i]);
+ VERIFY(internal::isApprox(ref[i], cj.pmul(data1[i],data2[i])) && "conj_helper pmul");
+ }
+ internal::pstore(pval,pcj.pmul(internal::pload<Packet>(data1),internal::pload<Packet>(data2)));
+ VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmul");
+
+ for(int i=0;i<PacketSize;++i)
+ {
+ Scalar tmp = ref[i];
+ ref[i] += cj0(data1[i]) * cj1(data2[i]);
+ VERIFY(internal::isApprox(ref[i], cj.pmadd(data1[i],data2[i],tmp)) && "conj_helper pmadd");
+ }
+ internal::pstore(pval,pcj.pmadd(internal::pload<Packet>(data1),internal::pload<Packet>(data2),internal::pload<Packet>(pval)));
+ VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmadd");
+}
+
+template<typename Scalar> void packetmath_complex()
+{
+ typedef typename internal::packet_traits<Scalar>::type Packet;
+ const int PacketSize = internal::packet_traits<Scalar>::size;
+
+ const int size = PacketSize*4;
+ EIGEN_ALIGN16 Scalar data1[PacketSize*4];
+ EIGEN_ALIGN16 Scalar data2[PacketSize*4];
+ EIGEN_ALIGN16 Scalar ref[PacketSize*4];
+ EIGEN_ALIGN16 Scalar pval[PacketSize*4];
+
+ for (int i=0; i<size; ++i)
+ {
+ data1[i] = internal::random<Scalar>() * Scalar(1e2);
+ data2[i] = internal::random<Scalar>() * Scalar(1e2);
+ }
+
+ test_conj_helper<Scalar,false,false> (data1,data2,ref,pval);
+ test_conj_helper<Scalar,false,true> (data1,data2,ref,pval);
+ test_conj_helper<Scalar,true,false> (data1,data2,ref,pval);
+ test_conj_helper<Scalar,true,true> (data1,data2,ref,pval);
+
+ {
+ for(int i=0;i<PacketSize;++i)
+ ref[i] = Scalar(std::imag(data1[i]),std::real(data1[i]));
+ internal::pstore(pval,internal::pcplxflip(internal::pload<Packet>(data1)));
+ VERIFY(areApprox(ref, pval, PacketSize) && "pcplxflip");
+ }
+
+
+}
+
+void test_packetmath()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( packetmath<float>() );
+ CALL_SUBTEST_2( packetmath<double>() );
+ CALL_SUBTEST_3( packetmath<int>() );
+ CALL_SUBTEST_1( packetmath<std::complex<float> >() );
+ CALL_SUBTEST_2( packetmath<std::complex<double> >() );
+
+ CALL_SUBTEST_1( packetmath_real<float>() );
+ CALL_SUBTEST_2( packetmath_real<double>() );
+
+ CALL_SUBTEST_1( packetmath_complex<std::complex<float> >() );
+ CALL_SUBTEST_2( packetmath_complex<std::complex<double> >() );
+ }
+}
diff --git a/test/pardiso_support.cpp b/test/pardiso_support.cpp
new file mode 100644
index 000000000..67efad6d8
--- /dev/null
+++ b/test/pardiso_support.cpp
@@ -0,0 +1,29 @@
+/*
+ Intel Copyright (C) ....
+*/
+
+#include "sparse_solver.h"
+#include <Eigen/PardisoSupport>
+
+template<typename T> void test_pardiso_T()
+{
+ PardisoLLT < SparseMatrix<T, RowMajor>, Lower> pardiso_llt_lower;
+ PardisoLLT < SparseMatrix<T, RowMajor>, Upper> pardiso_llt_upper;
+ PardisoLDLT < SparseMatrix<T, RowMajor>, Lower> pardiso_ldlt_lower;
+ PardisoLDLT < SparseMatrix<T, RowMajor>, Upper> pardiso_ldlt_upper;
+ PardisoLU < SparseMatrix<T, RowMajor> > pardiso_lu;
+
+ check_sparse_spd_solving(pardiso_llt_lower);
+ check_sparse_spd_solving(pardiso_llt_upper);
+ check_sparse_spd_solving(pardiso_ldlt_lower);
+ check_sparse_spd_solving(pardiso_ldlt_upper);
+ check_sparse_square_solving(pardiso_lu);
+}
+
+void test_pardiso_support()
+{
+ CALL_SUBTEST_1(test_pardiso_T<float>());
+ CALL_SUBTEST_2(test_pardiso_T<double>());
+ CALL_SUBTEST_3(test_pardiso_T< std::complex<float> >());
+ CALL_SUBTEST_4(test_pardiso_T< std::complex<double> >());
+}
diff --git a/test/pastix_support.cpp b/test/pastix_support.cpp
new file mode 100644
index 000000000..0e57227f9
--- /dev/null
+++ b/test/pastix_support.cpp
@@ -0,0 +1,44 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2012 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@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/.
+#include "sparse_solver.h"
+#include <Eigen/PaStiXSupport>
+#include <unsupported/Eigen/SparseExtra>
+
+
+template<typename T> void test_pastix_T()
+{
+ PastixLLT< SparseMatrix<T, ColMajor>, Eigen::Lower > pastix_llt_lower;
+ PastixLDLT< SparseMatrix<T, ColMajor>, Eigen::Lower > pastix_ldlt_lower;
+ PastixLLT< SparseMatrix<T, ColMajor>, Eigen::Upper > pastix_llt_upper;
+ PastixLDLT< SparseMatrix<T, ColMajor>, Eigen::Upper > pastix_ldlt_upper;
+ PastixLU< SparseMatrix<T, ColMajor> > pastix_lu;
+
+ check_sparse_spd_solving(pastix_llt_lower);
+ check_sparse_spd_solving(pastix_ldlt_lower);
+ check_sparse_spd_solving(pastix_llt_upper);
+ check_sparse_spd_solving(pastix_ldlt_upper);
+ check_sparse_square_solving(pastix_lu);
+}
+
+// There is no support for selfadjoint matrices with PaStiX.
+// Complex symmetric matrices should pass though
+template<typename T> void test_pastix_T_LU()
+{
+ PastixLU< SparseMatrix<T, ColMajor> > pastix_lu;
+ check_sparse_square_solving(pastix_lu);
+}
+
+void test_pastix_support()
+{
+ CALL_SUBTEST_1(test_pastix_T<float>());
+ CALL_SUBTEST_2(test_pastix_T<double>());
+ CALL_SUBTEST_3( (test_pastix_T_LU<std::complex<float> >()) );
+ CALL_SUBTEST_4(test_pastix_T_LU<std::complex<double> >());
+} \ No newline at end of file
diff --git a/test/permutationmatrices.cpp b/test/permutationmatrices.cpp
new file mode 100644
index 000000000..00f666ccd
--- /dev/null
+++ b/test/permutationmatrices.cpp
@@ -0,0 +1,117 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#include "main.h"
+
+using namespace std;
+template<typename MatrixType> void permutationmatrices(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime,
+ Options = MatrixType::Options };
+ typedef PermutationMatrix<Rows> LeftPermutationType;
+ typedef Matrix<int, Rows, 1> LeftPermutationVectorType;
+ typedef Map<LeftPermutationType> MapLeftPerm;
+ typedef PermutationMatrix<Cols> RightPermutationType;
+ typedef Matrix<int, Cols, 1> RightPermutationVectorType;
+ typedef Map<RightPermutationType> MapRightPerm;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m_original = MatrixType::Random(rows,cols);
+ LeftPermutationVectorType lv;
+ randomPermutationVector(lv, rows);
+ LeftPermutationType lp(lv);
+ RightPermutationVectorType rv;
+ randomPermutationVector(rv, cols);
+ RightPermutationType rp(rv);
+ MatrixType m_permuted = lp * m_original * rp;
+
+ for (int i=0; i<rows; i++)
+ for (int j=0; j<cols; j++)
+ VERIFY_IS_APPROX(m_permuted(lv(i),j), m_original(i,rv(j)));
+
+ Matrix<Scalar,Rows,Rows> lm(lp);
+ Matrix<Scalar,Cols,Cols> rm(rp);
+
+ VERIFY_IS_APPROX(m_permuted, lm*m_original*rm);
+
+ VERIFY_IS_APPROX(lp.inverse()*m_permuted*rp.inverse(), m_original);
+ VERIFY_IS_APPROX(lv.asPermutation().inverse()*m_permuted*rv.asPermutation().inverse(), m_original);
+ VERIFY_IS_APPROX(MapLeftPerm(lv.data(),lv.size()).inverse()*m_permuted*MapRightPerm(rv.data(),rv.size()).inverse(), m_original);
+
+ VERIFY((lp*lp.inverse()).toDenseMatrix().isIdentity());
+ VERIFY((lv.asPermutation()*lv.asPermutation().inverse()).toDenseMatrix().isIdentity());
+ VERIFY((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv.data(),lv.size()).inverse()).toDenseMatrix().isIdentity());
+
+ LeftPermutationVectorType lv2;
+ randomPermutationVector(lv2, rows);
+ LeftPermutationType lp2(lv2);
+ Matrix<Scalar,Rows,Rows> lm2(lp2);
+ VERIFY_IS_APPROX((lp*lp2).toDenseMatrix().template cast<Scalar>(), lm*lm2);
+ VERIFY_IS_APPROX((lv.asPermutation()*lv2.asPermutation()).toDenseMatrix().template cast<Scalar>(), lm*lm2);
+ VERIFY_IS_APPROX((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv2.data(),lv2.size())).toDenseMatrix().template cast<Scalar>(), lm*lm2);
+
+ LeftPermutationType identityp;
+ identityp.setIdentity(rows);
+ VERIFY_IS_APPROX(m_original, identityp*m_original);
+
+ // check inplace permutations
+ m_permuted = m_original;
+ m_permuted = lp.inverse() * m_permuted;
+ VERIFY_IS_APPROX(m_permuted, lp.inverse()*m_original);
+
+ m_permuted = m_original;
+ m_permuted = m_permuted * rp.inverse();
+ VERIFY_IS_APPROX(m_permuted, m_original*rp.inverse());
+
+ m_permuted = m_original;
+ m_permuted = lp * m_permuted;
+ VERIFY_IS_APPROX(m_permuted, lp*m_original);
+
+ m_permuted = m_original;
+ m_permuted = m_permuted * rp;
+ VERIFY_IS_APPROX(m_permuted, m_original*rp);
+
+ if(rows>1 && cols>1)
+ {
+ lp2 = lp;
+ Index i = internal::random<Index>(0, rows-1);
+ Index j;
+ do j = internal::random<Index>(0, rows-1); while(j==i);
+ lp2.applyTranspositionOnTheLeft(i, j);
+ lm = lp;
+ lm.row(i).swap(lm.row(j));
+ VERIFY_IS_APPROX(lm, lp2.toDenseMatrix().template cast<Scalar>());
+
+ RightPermutationType rp2 = rp;
+ i = internal::random<Index>(0, cols-1);
+ do j = internal::random<Index>(0, cols-1); while(j==i);
+ rp2.applyTranspositionOnTheRight(i, j);
+ rm = rp;
+ rm.col(i).swap(rm.col(j));
+ VERIFY_IS_APPROX(rm, rp2.toDenseMatrix().template cast<Scalar>());
+ }
+}
+
+void test_permutationmatrices()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( permutationmatrices(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( permutationmatrices(Matrix3f()) );
+ CALL_SUBTEST_3( permutationmatrices(Matrix<double,3,3,RowMajor>()) );
+ CALL_SUBTEST_4( permutationmatrices(Matrix4d()) );
+ CALL_SUBTEST_5( permutationmatrices(Matrix<double,40,60>()) );
+ CALL_SUBTEST_6( permutationmatrices(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 30)) );
+ CALL_SUBTEST_7( permutationmatrices(MatrixXcf(15, 10)) );
+ }
+}
diff --git a/test/prec_inverse_4x4.cpp b/test/prec_inverse_4x4.cpp
new file mode 100644
index 000000000..f7d0aff70
--- /dev/null
+++ b/test/prec_inverse_4x4.cpp
@@ -0,0 +1,68 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#include "main.h"
+#include <Eigen/LU>
+#include <algorithm>
+
+template<typename MatrixType> void inverse_permutation_4x4()
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ Vector4i indices(0,1,2,3);
+ for(int i = 0; i < 24; ++i)
+ {
+ MatrixType m = PermutationMatrix<4>(indices);
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() / NumTraits<Scalar>::epsilon() );
+ EIGEN_DEBUG_VAR(error)
+ VERIFY(error == 0.0);
+ std::next_permutation(indices.data(),indices.data()+4);
+ }
+}
+
+template<typename MatrixType> void inverse_general_4x4(int repeat)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ double error_sum = 0., error_max = 0.;
+ for(int i = 0; i < repeat; ++i)
+ {
+ MatrixType m;
+ RealScalar absdet;
+ do {
+ m = MatrixType::Random();
+ absdet = internal::abs(m.determinant());
+ } while(absdet < NumTraits<Scalar>::epsilon());
+ MatrixType inv = m.inverse();
+ double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / NumTraits<Scalar>::epsilon() );
+ error_sum += error;
+ error_max = (std::max)(error_max, error);
+ }
+ std::cerr << "inverse_general_4x4, Scalar = " << type_name<Scalar>() << std::endl;
+ double error_avg = error_sum / repeat;
+ EIGEN_DEBUG_VAR(error_avg);
+ EIGEN_DEBUG_VAR(error_max);
+ // FIXME that 1.25 used to be a 1.0 until the NumTraits changes on 28 April 2010, what's going wrong??
+ // FIXME that 1.25 used to be 1.2 until we tested gcc 4.1 on 30 June 2010 and got 1.21.
+ VERIFY(error_avg < (NumTraits<Scalar>::IsComplex ? 8.0 : 1.25));
+ VERIFY(error_max < (NumTraits<Scalar>::IsComplex ? 64.0 : 20.0));
+}
+
+void test_prec_inverse_4x4()
+{
+ CALL_SUBTEST_1((inverse_permutation_4x4<Matrix4f>()));
+ CALL_SUBTEST_1(( inverse_general_4x4<Matrix4f>(200000 * g_repeat) ));
+
+ CALL_SUBTEST_2((inverse_permutation_4x4<Matrix<double,4,4,RowMajor> >()));
+ CALL_SUBTEST_2(( inverse_general_4x4<Matrix<double,4,4,RowMajor> >(200000 * g_repeat) ));
+
+ CALL_SUBTEST_3((inverse_permutation_4x4<Matrix4cf>()));
+ CALL_SUBTEST_3((inverse_general_4x4<Matrix4cf>(50000 * g_repeat)));
+}
diff --git a/test/product.h b/test/product.h
new file mode 100644
index 000000000..4aa9fd56d
--- /dev/null
+++ b/test/product.h
@@ -0,0 +1,143 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+template<typename Derived1, typename Derived2>
+bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2, typename Derived1::RealScalar epsilon = NumTraits<typename Derived1::RealScalar>::dummy_precision())
+{
+ return !((m1-m2).cwiseAbs2().maxCoeff() < epsilon * epsilon
+ * (std::max)(m1.cwiseAbs2().maxCoeff(), m2.cwiseAbs2().maxCoeff()));
+}
+
+template<typename MatrixType> void product(const MatrixType& m)
+{
+ /* this test covers the following files:
+ Identity.h Product.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::NonInteger NonInteger;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RowVectorType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RowSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> ColSquareMatrixType;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime,
+ MatrixType::Flags&RowMajorBit?ColMajor:RowMajor> OtherMajorMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ // this test relies a lot on Random.h, and there's not much more that we can do
+ // to test it, hence I consider that we will have tested Random.h
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+ RowSquareMatrixType
+ identity = RowSquareMatrixType::Identity(rows, rows),
+ square = RowSquareMatrixType::Random(rows, rows),
+ res = RowSquareMatrixType::Random(rows, rows);
+ ColSquareMatrixType
+ square2 = ColSquareMatrixType::Random(cols, cols),
+ res2 = ColSquareMatrixType::Random(cols, cols);
+ RowVectorType v1 = RowVectorType::Random(rows);
+ ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
+ OtherMajorMatrixType tm1 = m1;
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1),
+ c2 = internal::random<Index>(0, cols-1);
+
+ // begin testing Product.h: only associativity for now
+ // (we use Transpose.h but this doesn't count as a test for it)
+ VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
+ m3 = m1;
+ m3 *= m1.transpose() * m2;
+ VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2));
+ VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2));
+
+ // continue testing Product.h: distributivity
+ VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2);
+ VERIFY_IS_APPROX(square*(m1 - m2), square*m1-square*m2);
+
+ // continue testing Product.h: compatibility with ScalarMultiple.h
+ VERIFY_IS_APPROX(s1*(square*m1), (s1*square)*m1);
+ VERIFY_IS_APPROX(s1*(square*m1), square*(m1*s1));
+
+ // test Product.h together with Identity.h
+ VERIFY_IS_APPROX(v1, identity*v1);
+ VERIFY_IS_APPROX(v1.transpose(), v1.transpose() * identity);
+ // again, test operator() to check const-qualification
+ VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast<Scalar>(r==c));
+
+ if (rows!=cols)
+ VERIFY_RAISES_ASSERT(m3 = m1*m1);
+
+ // test the previous tests were not screwed up because operator* returns 0
+ // (we use the more accurate default epsilon)
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1));
+ }
+
+ // test optimized operator+= path
+ res = square;
+ res.noalias() += m1 * m2.transpose();
+ VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res,square + m2 * m1.transpose()));
+ }
+ vcres = vc2;
+ vcres.noalias() += m1.transpose() * v1;
+ VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1);
+
+ // test optimized operator-= path
+ res = square;
+ res.noalias() -= m1 * m2.transpose();
+ VERIFY_IS_APPROX(res, square - (m1 * m2.transpose()));
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res,square - m2 * m1.transpose()));
+ }
+ vcres = vc2;
+ vcres.noalias() -= m1.transpose() * v1;
+ VERIFY_IS_APPROX(vcres, vc2 - m1.transpose() * v1);
+
+ tm1 = m1;
+ VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1);
+ VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1);
+
+ // test submatrix and matrix/vector product
+ for (int i=0; i<rows; ++i)
+ res.row(i) = m1.row(i) * m2.transpose();
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+ // the other way round:
+ for (int i=0; i<rows; ++i)
+ res.col(i) = m1 * m2.transpose().col(i);
+ VERIFY_IS_APPROX(res, m1 * m2.transpose());
+
+ res2 = square2;
+ res2.noalias() += m1.transpose() * m2;
+ VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
+ if (!NumTraits<Scalar>::IsInteger && (std::min)(rows,cols)>1)
+ {
+ VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1));
+ }
+
+ VERIFY_IS_APPROX(res.col(r).noalias() = square.adjoint() * square.col(r), (square.adjoint() * square.col(r)).eval());
+ VERIFY_IS_APPROX(res.col(r).noalias() = square * square.col(r), (square * square.col(r)).eval());
+
+ // inner product
+ Scalar x = square2.row(c) * square2.col(c2);
+ VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum());
+}
diff --git a/test/product_extra.cpp b/test/product_extra.cpp
new file mode 100644
index 000000000..9a6bf0792
--- /dev/null
+++ b/test/product_extra.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void product_extra(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::NonInteger NonInteger;
+ typedef Matrix<Scalar, 1, Dynamic> RowVectorType;
+ typedef Matrix<Scalar, Dynamic, 1> ColVectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic,
+ MatrixType::Flags&RowMajorBit> OtherMajorMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ mzero = MatrixType::Zero(rows, cols),
+ identity = MatrixType::Identity(rows, rows),
+ square = MatrixType::Random(rows, rows),
+ res = MatrixType::Random(rows, rows),
+ square2 = MatrixType::Random(cols, cols),
+ res2 = MatrixType::Random(cols, cols);
+ RowVectorType v1 = RowVectorType::Random(rows), vrres(rows);
+ ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
+ OtherMajorMatrixType tm1 = m1;
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>(),
+ s3 = internal::random<Scalar>();
+
+ VERIFY_IS_APPROX(m3.noalias() = m1 * m2.adjoint(), m1 * m2.adjoint().eval());
+ VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * square.adjoint(), m1.adjoint().eval() * square.adjoint().eval());
+ VERIFY_IS_APPROX(m3.noalias() = m1.adjoint() * m2, m1.adjoint().eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = (s1 * m1.adjoint()) * m2, (s1 * m1.adjoint()).eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = ((s1 * m1).adjoint()) * m2, (internal::conj(s1) * m1.adjoint()).eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = (- m1.adjoint() * s1) * (s3 * m2), (- m1.adjoint() * s1).eval() * (s3 * m2).eval());
+ VERIFY_IS_APPROX(m3.noalias() = (s2 * m1.adjoint() * s1) * m2, (s2 * m1.adjoint() * s1).eval() * m2);
+ VERIFY_IS_APPROX(m3.noalias() = (-m1*s2) * s1*m2.adjoint(), (-m1*s2).eval() * (s1*m2.adjoint()).eval());
+
+ // a very tricky case where a scale factor has to be automatically conjugated:
+ VERIFY_IS_APPROX( m1.adjoint() * (s1*m2).conjugate(), (m1.adjoint()).eval() * ((s1*m2).conjugate()).eval());
+
+
+ // test all possible conjugate combinations for the four matrix-vector product cases:
+
+ VERIFY_IS_APPROX((-m1.conjugate() * s2) * (s1 * vc2),
+ (-m1.conjugate()*s2).eval() * (s1 * vc2).eval());
+ VERIFY_IS_APPROX((-m1 * s2) * (s1 * vc2.conjugate()),
+ (-m1*s2).eval() * (s1 * vc2.conjugate()).eval());
+ VERIFY_IS_APPROX((-m1.conjugate() * s2) * (s1 * vc2.conjugate()),
+ (-m1.conjugate()*s2).eval() * (s1 * vc2.conjugate()).eval());
+
+ VERIFY_IS_APPROX((s1 * vc2.transpose()) * (-m1.adjoint() * s2),
+ (s1 * vc2.transpose()).eval() * (-m1.adjoint()*s2).eval());
+ VERIFY_IS_APPROX((s1 * vc2.adjoint()) * (-m1.transpose() * s2),
+ (s1 * vc2.adjoint()).eval() * (-m1.transpose()*s2).eval());
+ VERIFY_IS_APPROX((s1 * vc2.adjoint()) * (-m1.adjoint() * s2),
+ (s1 * vc2.adjoint()).eval() * (-m1.adjoint()*s2).eval());
+
+ VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.transpose()),
+ (-m1.adjoint()*s2).eval() * (s1 * v1.transpose()).eval());
+ VERIFY_IS_APPROX((-m1.transpose() * s2) * (s1 * v1.adjoint()),
+ (-m1.transpose()*s2).eval() * (s1 * v1.adjoint()).eval());
+ VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.adjoint()),
+ (-m1.adjoint()*s2).eval() * (s1 * v1.adjoint()).eval());
+
+ VERIFY_IS_APPROX((s1 * v1) * (-m1.conjugate() * s2),
+ (s1 * v1).eval() * (-m1.conjugate()*s2).eval());
+ VERIFY_IS_APPROX((s1 * v1.conjugate()) * (-m1 * s2),
+ (s1 * v1.conjugate()).eval() * (-m1*s2).eval());
+ VERIFY_IS_APPROX((s1 * v1.conjugate()) * (-m1.conjugate() * s2),
+ (s1 * v1.conjugate()).eval() * (-m1.conjugate()*s2).eval());
+
+ VERIFY_IS_APPROX((-m1.adjoint() * s2) * (s1 * v1.adjoint()),
+ (-m1.adjoint()*s2).eval() * (s1 * v1.adjoint()).eval());
+
+ // test the vector-matrix product with non aligned starts
+ Index i = internal::random<Index>(0,m1.rows()-2);
+ Index j = internal::random<Index>(0,m1.cols()-2);
+ Index r = internal::random<Index>(1,m1.rows()-i);
+ Index c = internal::random<Index>(1,m1.cols()-j);
+ Index i2 = internal::random<Index>(0,m1.rows()-1);
+ Index j2 = internal::random<Index>(0,m1.cols()-1);
+
+ VERIFY_IS_APPROX(m1.col(j2).adjoint() * m1.block(0,j,m1.rows(),c), m1.col(j2).adjoint().eval() * m1.block(0,j,m1.rows(),c).eval());
+ VERIFY_IS_APPROX(m1.block(i,0,r,m1.cols()) * m1.row(i2).adjoint(), m1.block(i,0,r,m1.cols()).eval() * m1.row(i2).adjoint().eval());
+
+ // regression test
+ MatrixType tmp = m1 * m1.adjoint() * s1;
+ VERIFY_IS_APPROX(tmp, m1 * m1.adjoint() * s1);
+}
+
+// Regression test for bug reported at http://forum.kde.org/viewtopic.php?f=74&t=96947
+void mat_mat_scalar_scalar_product()
+{
+ Eigen::Matrix2Xd dNdxy(2, 3);
+ dNdxy << -0.5, 0.5, 0,
+ -0.3, 0, 0.3;
+ double det = 6.0, wt = 0.5;
+ VERIFY_IS_APPROX(dNdxy.transpose()*dNdxy*det*wt, det*wt*dNdxy.transpose()*dNdxy);
+}
+
+void zero_sized_objects()
+{
+ // Bug 127
+ //
+ // a product of the form lhs*rhs with
+ //
+ // lhs:
+ // rows = 1, cols = 4
+ // RowsAtCompileTime = 1, ColsAtCompileTime = -1
+ // MaxRowsAtCompileTime = 1, MaxColsAtCompileTime = 5
+ //
+ // rhs:
+ // rows = 4, cols = 0
+ // RowsAtCompileTime = -1, ColsAtCompileTime = -1
+ // MaxRowsAtCompileTime = 5, MaxColsAtCompileTime = 1
+ //
+ // was failing on a runtime assertion, because it had been mis-compiled as a dot product because Product.h was using the
+ // max-sizes to detect size 1 indicating vectors, and that didn't account for 0-sized object with max-size 1.
+
+ Matrix<float,1,Dynamic,RowMajor,1,5> a(1,4);
+ Matrix<float,Dynamic,Dynamic,ColMajor,5,1> b(4,0);
+ a*b;
+}
+
+void test_product_extra()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product_extra(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( product_extra(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( mat_mat_scalar_scalar_product() );
+ CALL_SUBTEST_3( product_extra(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_4( product_extra(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_5( zero_sized_objects() );
+ }
+}
diff --git a/test/product_large.cpp b/test/product_large.cpp
new file mode 100644
index 000000000..03d7bd8ed
--- /dev/null
+++ b/test/product_large.cpp
@@ -0,0 +1,64 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#include "product.h"
+
+void test_product_large()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( product(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_3( product(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_4( product(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2), internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_5( product(Matrix<float,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ }
+
+#if defined EIGEN_TEST_PART_6
+ {
+ // test a specific issue in DiagonalProduct
+ int N = 1000000;
+ VectorXf v = VectorXf::Ones(N);
+ MatrixXf m = MatrixXf::Ones(N,3);
+ m = (v+v).asDiagonal() * m;
+ VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2));
+ }
+
+ {
+ // test deferred resizing in Matrix::operator=
+ MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a;
+ VERIFY_IS_APPROX((a = a * b), (c * b).eval());
+ }
+
+ {
+ // 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);
+ 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);
+ }
+
+ {
+ // test regression in row-vector by matrix (bad Map type)
+ MatrixXf mat1(10,32); mat1.setRandom();
+ MatrixXf mat2(32,32); mat2.setRandom();
+ MatrixXf r1 = mat1.row(2)*mat2.transpose();
+ VERIFY_IS_APPROX(r1, (mat1.row(2)*mat2.transpose()).eval());
+
+ MatrixXf r2 = mat1.row(2)*mat2;
+ VERIFY_IS_APPROX(r2, (mat1.row(2)*mat2).eval());
+ }
+#endif
+}
diff --git a/test/product_mmtr.cpp b/test/product_mmtr.cpp
new file mode 100644
index 000000000..879cfe16a
--- /dev/null
+++ b/test/product_mmtr.cpp
@@ -0,0 +1,65 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 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/.
+
+#include "main.h"
+
+#define CHECK_MMTR(DEST, TRI, OP) { \
+ ref2 = ref1 = DEST; \
+ DEST.template triangularView<TRI>() OP; \
+ ref1 OP; \
+ ref2.template triangularView<TRI>() = ref1; \
+ VERIFY_IS_APPROX(DEST,ref2); \
+ }
+
+template<typename Scalar> void mmtr(int size)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> MatrixColMaj;
+ typedef Matrix<Scalar,Dynamic,Dynamic,RowMajor> MatrixRowMaj;
+
+ DenseIndex othersize = internal::random<DenseIndex>(1,200);
+
+ MatrixColMaj matc(size, size);
+ MatrixRowMaj matr(size, size);
+ MatrixColMaj ref1(size, size), ref2(size, size);
+
+ MatrixColMaj soc(size,othersize); soc.setRandom();
+ MatrixColMaj osc(othersize,size); osc.setRandom();
+ MatrixRowMaj sor(size,othersize); sor.setRandom();
+ MatrixRowMaj osr(othersize,size); osr.setRandom();
+
+ Scalar s = internal::random<Scalar>();
+
+ CHECK_MMTR(matc, Lower, = s*soc*sor.adjoint());
+ CHECK_MMTR(matc, Upper, = s*(soc*soc.adjoint()));
+ CHECK_MMTR(matr, Lower, = s*soc*soc.adjoint());
+ CHECK_MMTR(matr, Upper, = soc*(s*sor.adjoint()));
+
+ CHECK_MMTR(matc, Lower, += s*soc*soc.adjoint());
+ CHECK_MMTR(matc, Upper, += s*(soc*sor.transpose()));
+ CHECK_MMTR(matr, Lower, += s*sor*soc.adjoint());
+ CHECK_MMTR(matr, Upper, += soc*(s*soc.adjoint()));
+
+ CHECK_MMTR(matc, Lower, -= s*soc*soc.adjoint());
+ CHECK_MMTR(matc, Upper, -= s*(osc.transpose()*osc.conjugate()));
+ CHECK_MMTR(matr, Lower, -= s*soc*soc.adjoint());
+ CHECK_MMTR(matr, Upper, -= soc*(s*soc.adjoint()));
+}
+
+void test_product_mmtr()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ CALL_SUBTEST_1((mmtr<float>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_2((mmtr<double>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_3((mmtr<std::complex<float> >(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+ CALL_SUBTEST_4((mmtr<std::complex<double> >(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+ }
+}
diff --git a/test/product_notemporary.cpp b/test/product_notemporary.cpp
new file mode 100644
index 000000000..cf9dbdd03
--- /dev/null
+++ b/test/product_notemporary.cpp
@@ -0,0 +1,138 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+static int nb_temporaries;
+
+void on_temporary_creation(int size) {
+ // here's a great place to set a breakpoint when debugging failures in this test!
+ if(size!=0) nb_temporaries++;
+}
+
+
+#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); }
+
+#include "main.h"
+
+#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 MatrixType> void product_notemporary(const MatrixType& m)
+{
+ /* This test checks the number of temporaries created
+ * during the evaluation of a complex expression */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, 1, Dynamic> RowVectorType;
+ typedef Matrix<Scalar, Dynamic, 1> ColVectorType;
+ typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> ColMajorMatrixType;
+ typedef Matrix<Scalar, Dynamic, Dynamic, RowMajor> RowMajorMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ ColMajorMatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+ RowVectorType rv1 = RowVectorType::Random(rows), rvres(rows);
+ ColVectorType cv1 = ColVectorType::Random(cols), cvres(cols);
+ RowMajorMatrixType rm3(rows, cols);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>(),
+ s3 = internal::random<Scalar>();
+
+ Index c0 = internal::random<Index>(4,cols-8),
+ c1 = internal::random<Index>(8,cols-c0),
+ r0 = internal::random<Index>(4,cols-8),
+ r1 = internal::random<Index>(8,rows-r0);
+
+ VERIFY_EVALUATION_COUNT( m3 = (m1 * m2.adjoint()), 1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * (m1*s3+m2*s2).adjoint(), 1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = (s1 * m1).adjoint() * s2 * m2, 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() += s1 * (-m1*s3).adjoint() * (s2 * m2 * s3), 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() -= s1 * (m1.transpose() * m2), 0);
+
+ VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() += -m1.block(r0,c0,r1,c1) * (s2*m2.block(r0,c0,r1,c1)).adjoint() ), 0);
+ VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() -= s1 * m1.block(r0,c0,r1,c1) * m2.block(c0,r0,c1,r1) ), 0);
+
+ // NOTE this is because the Block expression is not handled yet by our expression analyser
+ VERIFY_EVALUATION_COUNT(( m3.block(r0,r0,r1,r1).noalias() = s1 * m1.block(r0,c0,r1,c1) * (s1*m2).block(c0,r0,c1,r1) ), 1);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).template triangularView<Lower>() * m2, 0);
+ VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView<Upper>() * (m2+m2), 1);
+ VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView<UnitUpper>() * m2.adjoint(), 0);
+
+ // NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be actually needed for the triangular products
+ VERIFY_EVALUATION_COUNT( rm3.col(c0).noalias() = (s1 * m1.adjoint()).template triangularView<UnitUpper>() * (s2*m2.row(c0)).adjoint(), 1);
+
+ VERIFY_EVALUATION_COUNT( m1.template triangularView<Lower>().solveInPlace(m3), 0);
+ VERIFY_EVALUATION_COUNT( m1.adjoint().template triangularView<Lower>().solveInPlace(m3.transpose()), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).adjoint().template selfadjointView<Lower>() * (-m2*s3).adjoint(), 0);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = s2 * m2.adjoint() * (s1 * m1.adjoint()).template selfadjointView<Upper>(), 0);
+ VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template selfadjointView<Lower>() * m2.adjoint(), 0);
+
+ // NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be actually needed for the triangular products
+ VERIFY_EVALUATION_COUNT( m3.col(c0).noalias() = (s1 * m1).adjoint().template selfadjointView<Lower>() * (-m2.row(c0)*s3).adjoint(), 1);
+ VERIFY_EVALUATION_COUNT( m3.col(c0).noalias() -= (s1 * m1).adjoint().template selfadjointView<Upper>() * (-m2.row(c0)*s3).adjoint(), 1);
+
+ VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1).noalias() += m1.block(r0,r0,r1,r1).template selfadjointView<Upper>() * (s1*m2.block(r0,c0,r1,c1)), 0);
+ VERIFY_EVALUATION_COUNT( m3.block(r0,c0,r1,c1).noalias() = m1.block(r0,r0,r1,r1).template selfadjointView<Upper>() * m2.block(r0,c0,r1,c1), 0);
+
+ VERIFY_EVALUATION_COUNT( m3.template selfadjointView<Lower>().rankUpdate(m2.adjoint()), 0);
+
+ // Here we will get 1 temporary for each resize operation of the lhs operator; resize(r1,c1) would lead to zero temporaries
+ m3.resize(1,1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template selfadjointView<Lower>() * m2.block(r0,c0,r1,c1), 1);
+ m3.resize(1,1);
+ VERIFY_EVALUATION_COUNT( m3.noalias() = m1.block(r0,r0,r1,r1).template triangularView<UnitUpper>() * m2.block(r0,c0,r1,c1), 1);
+
+ // Zero temporaries for lazy products ...
+ VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0 );
+
+ // ... and even no temporary for even deeply (>=2) nested products
+ VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 0 );
+ 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 );
+
+ // Check matrix * vectors
+ VERIFY_EVALUATION_COUNT( cvres.noalias() = m1 * cv1, 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * cv1, 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * m2.col(0), 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * rv1.adjoint(), 0 );
+ VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * m2.row(0).transpose(), 0 );
+}
+
+void test_product_notemporary()
+{
+ int s;
+ for(int i = 0; i < g_repeat; i++) {
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_1( product_notemporary(MatrixXf(s, s)) );
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_2( product_notemporary(MatrixXd(s, s)) );
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_3( product_notemporary(MatrixXcf(s,s)) );
+ s = internal::random<int>(16,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( product_notemporary(MatrixXcd(s,s)) );
+ }
+}
diff --git a/test/product_selfadjoint.cpp b/test/product_selfadjoint.cpp
new file mode 100644
index 000000000..95693b155
--- /dev/null
+++ b/test/product_selfadjoint.cpp
@@ -0,0 +1,81 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void product_selfadjoint(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+ typedef Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> RowVectorType;
+
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, Dynamic, RowMajor> RhsMatrixType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3;
+ VectorType v1 = VectorType::Random(rows),
+ v2 = VectorType::Random(rows),
+ v3(rows);
+ RowVectorType r1 = RowVectorType::Random(rows),
+ r2 = RowVectorType::Random(rows);
+ RhsMatrixType m4 = RhsMatrixType::Random(rows,10);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>(),
+ s3 = internal::random<Scalar>();
+
+ m1 = (m1.adjoint() + m1).eval();
+
+ // rank2 update
+ m2 = m1.template triangularView<Lower>();
+ m2.template selfadjointView<Lower>().rankUpdate(v1,v2);
+ VERIFY_IS_APPROX(m2, (m1 + v1 * v2.adjoint()+ v2 * v1.adjoint()).template triangularView<Lower>().toDenseMatrix());
+
+ m2 = m1.template triangularView<Upper>();
+ m2.template selfadjointView<Upper>().rankUpdate(-v1,s2*v2,s3);
+ VERIFY_IS_APPROX(m2, (m1 + (s3*(-v1)*(s2*v2).adjoint()+internal::conj(s3)*(s2*v2)*(-v1).adjoint())).template triangularView<Upper>().toDenseMatrix());
+
+ m2 = m1.template triangularView<Upper>();
+ m2.template selfadjointView<Upper>().rankUpdate(-s2*r1.adjoint(),r2.adjoint()*s3,s1);
+ VERIFY_IS_APPROX(m2, (m1 + s1*(-s2*r1.adjoint())*(r2.adjoint()*s3).adjoint() + internal::conj(s1)*(r2.adjoint()*s3) * (-s2*r1.adjoint()).adjoint()).template triangularView<Upper>().toDenseMatrix());
+
+ if (rows>1)
+ {
+ m2 = m1.template triangularView<Lower>();
+ m2.block(1,1,rows-1,cols-1).template selfadjointView<Lower>().rankUpdate(v1.tail(rows-1),v2.head(cols-1));
+ m3 = m1;
+ m3.block(1,1,rows-1,cols-1) += v1.tail(rows-1) * v2.head(cols-1).adjoint()+ v2.head(cols-1) * v1.tail(rows-1).adjoint();
+ VERIFY_IS_APPROX(m2, m3.template triangularView<Lower>().toDenseMatrix());
+ }
+}
+
+void test_product_selfadjoint()
+{
+ int s;
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( product_selfadjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( product_selfadjoint(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( product_selfadjoint(Matrix3d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( product_selfadjoint(MatrixXcf(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_5( product_selfadjoint(MatrixXcd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_6( product_selfadjoint(MatrixXd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_7( product_selfadjoint(Matrix<float,Dynamic,Dynamic,RowMajor>(s,s)) );
+ }
+ EIGEN_UNUSED_VARIABLE(s)
+}
diff --git a/test/product_small.cpp b/test/product_small.cpp
new file mode 100644
index 000000000..8b132abb6
--- /dev/null
+++ b/test/product_small.cpp
@@ -0,0 +1,50 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "product.h"
+
+// regression test for bug 447
+void product1x1()
+{
+ Matrix<float,1,3> matAstatic;
+ Matrix<float,3,1> matBstatic;
+ matAstatic.setRandom();
+ matBstatic.setRandom();
+ VERIFY_IS_APPROX( (matAstatic * matBstatic).coeff(0,0),
+ matAstatic.cwiseProduct(matBstatic.transpose()).sum() );
+
+ MatrixXf matAdynamic(1,3);
+ MatrixXf matBdynamic(3,1);
+ matAdynamic.setRandom();
+ matBdynamic.setRandom();
+ VERIFY_IS_APPROX( (matAdynamic * matBdynamic).coeff(0,0),
+ matAdynamic.cwiseProduct(matBdynamic.transpose()).sum() );
+}
+
+
+void test_product_small()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( product(Matrix<float, 3, 2>()) );
+ CALL_SUBTEST_2( product(Matrix<int, 3, 5>()) );
+ CALL_SUBTEST_3( product(Matrix3d()) );
+ CALL_SUBTEST_4( product(Matrix4d()) );
+ CALL_SUBTEST_5( product(Matrix4f()) );
+ CALL_SUBTEST_6( product1x1() );
+ }
+
+#ifdef EIGEN_TEST_PART_6
+ {
+ // test compilation of (outer_product) * vector
+ Vector3f v = Vector3f::Random();
+ VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v);
+ }
+#endif
+}
diff --git a/test/product_symm.cpp b/test/product_symm.cpp
new file mode 100644
index 000000000..2f7a0d231
--- /dev/null
+++ b/test/product_symm.cpp
@@ -0,0 +1,96 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename Scalar, int Size, int OtherSize> void symm(int size = Size, int othersize = OtherSize)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Matrix<Scalar, Size, Size> MatrixType;
+ typedef Matrix<Scalar, Size, OtherSize> Rhs1;
+ typedef Matrix<Scalar, OtherSize, Size> Rhs2;
+ enum { order = OtherSize==1 ? 0 : RowMajor };
+ typedef Matrix<Scalar, Size, OtherSize,order> Rhs3;
+ typedef typename MatrixType::Index Index;
+
+ Index rows = size;
+ Index cols = size;
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols), m3;
+
+ m1 = (m1+m1.adjoint()).eval();
+
+ Rhs1 rhs1 = Rhs1::Random(cols, othersize), rhs12(cols, othersize), rhs13(cols, othersize);
+ Rhs2 rhs2 = Rhs2::Random(othersize, rows), rhs22(othersize, rows), rhs23(othersize, rows);
+ Rhs3 rhs3 = Rhs3::Random(cols, othersize), rhs32(cols, othersize), rhs33(cols, othersize);
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ m2 = m1.template triangularView<Lower>();
+ m3 = m2.template selfadjointView<Lower>();
+ VERIFY_IS_EQUAL(m1, m3);
+ VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView<Lower>() * (s2*rhs1),
+ rhs13 = (s1*m1) * (s2*rhs1));
+
+ m2 = m1.template triangularView<Upper>(); rhs12.setRandom(); rhs13 = rhs12;
+ m3 = m2.template selfadjointView<Upper>();
+ VERIFY_IS_EQUAL(m1, m3);
+ VERIFY_IS_APPROX(rhs12 += (s1*m2).template selfadjointView<Upper>() * (s2*rhs1),
+ rhs13 += (s1*m1) * (s2*rhs1));
+
+ m2 = m1.template triangularView<Lower>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView<Lower>() * (s2*rhs2.adjoint()),
+ rhs13 = (s1*m1) * (s2*rhs2.adjoint()));
+
+ m2 = m1.template triangularView<Upper>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView<Upper>() * (s2*rhs2.adjoint()),
+ rhs13 = (s1*m1) * (s2*rhs2.adjoint()));
+
+ m2 = m1.template triangularView<Upper>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2.adjoint()).template selfadjointView<Lower>() * (s2*rhs2.adjoint()),
+ rhs13 = (s1*m1.adjoint()) * (s2*rhs2.adjoint()));
+
+ // test row major = <...>
+ m2 = m1.template triangularView<Lower>(); rhs12.setRandom(); rhs13 = rhs12;
+ VERIFY_IS_APPROX(rhs12 -= (s1*m2).template selfadjointView<Lower>() * (s2*rhs3),
+ rhs13 -= (s1*m1) * (s2 * rhs3));
+
+ m2 = m1.template triangularView<Upper>();
+ VERIFY_IS_APPROX(rhs12 = (s1*m2.adjoint()).template selfadjointView<Lower>() * (s2*rhs3).conjugate(),
+ rhs13 = (s1*m1.adjoint()) * (s2*rhs3).conjugate());
+
+
+ m2 = m1.template triangularView<Upper>(); rhs13 = rhs12;
+ VERIFY_IS_APPROX(rhs12.noalias() += s1 * ((m2.adjoint()).template selfadjointView<Lower>() * (s2*rhs3).conjugate()),
+ rhs13 += (s1*m1.adjoint()) * (s2*rhs3).conjugate());
+
+ m2 = m1.template triangularView<Lower>();
+ VERIFY_IS_APPROX(rhs22 = (rhs2) * (m2).template selfadjointView<Lower>(), rhs23 = (rhs2) * (m1));
+ VERIFY_IS_APPROX(rhs22 = (s2*rhs2) * (s1*m2).template selfadjointView<Lower>(), rhs23 = (s2*rhs2) * (s1*m1));
+
+}
+
+void test_product_symm()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ CALL_SUBTEST_1(( symm<float,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_2(( symm<double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_3(( symm<std::complex<float>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2)) ));
+ CALL_SUBTEST_4(( symm<std::complex<double>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2)) ));
+
+ CALL_SUBTEST_5(( symm<float,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_6(( symm<double,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_7(( symm<std::complex<float>,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ CALL_SUBTEST_8(( symm<std::complex<double>,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)) ));
+ }
+}
diff --git a/test/product_syrk.cpp b/test/product_syrk.cpp
new file mode 100644
index 000000000..5855c2181
--- /dev/null
+++ b/test/product_syrk.cpp
@@ -0,0 +1,98 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void syrk(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, Dynamic> Rhs1;
+ typedef Matrix<Scalar, Dynamic, MatrixType::RowsAtCompileTime> Rhs2;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, Dynamic,RowMajor> Rhs3;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols);
+
+ Rhs1 rhs1 = Rhs1::Random(internal::random<int>(1,320), cols);
+ Rhs2 rhs2 = Rhs2::Random(rows, internal::random<int>(1,320));
+ Rhs3 rhs3 = Rhs3::Random(internal::random<int>(1,320), rows);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ Index c = internal::random<Index>(0,cols-1);
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(rhs2,s1)._expression()),
+ ((s1 * rhs2 * rhs2.adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Upper>().rankUpdate(rhs2,s1)._expression(),
+ (s1 * rhs2 * rhs2.adjoint()).eval().template triangularView<Upper>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Lower>().rankUpdate(rhs1.adjoint(),s1)._expression(),
+ (s1 * rhs1.adjoint() * rhs1).eval().template triangularView<Lower>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Upper>().rankUpdate(rhs1.adjoint(),s1)._expression(),
+ (s1 * rhs1.adjoint() * rhs1).eval().template triangularView<Upper>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Lower>().rankUpdate(rhs3.adjoint(),s1)._expression(),
+ (s1 * rhs3.adjoint() * rhs3).eval().template triangularView<Lower>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX(m2.template selfadjointView<Upper>().rankUpdate(rhs3.adjoint(),s1)._expression(),
+ (s1 * rhs3.adjoint() * rhs3).eval().template triangularView<Upper>().toDenseMatrix());
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(m1.col(c),s1)._expression()),
+ ((s1 * m1.col(c) * m1.col(c).adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Upper>().rankUpdate(m1.col(c),s1)._expression()),
+ ((s1 * m1.col(c) * m1.col(c).adjoint()).eval().template triangularView<Upper>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(m1.col(c).conjugate(),s1)._expression()),
+ ((s1 * m1.col(c).conjugate() * m1.col(c).conjugate().adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Upper>().rankUpdate(m1.col(c).conjugate(),s1)._expression()),
+ ((s1 * m1.col(c).conjugate() * m1.col(c).conjugate().adjoint()).eval().template triangularView<Upper>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Lower>().rankUpdate(m1.row(c),s1)._expression()),
+ ((s1 * m1.row(c).transpose() * m1.row(c).transpose().adjoint()).eval().template triangularView<Lower>().toDenseMatrix()));
+
+ m2.setZero();
+ VERIFY_IS_APPROX((m2.template selfadjointView<Upper>().rankUpdate(m1.row(c).adjoint(),s1)._expression()),
+ ((s1 * m1.row(c).adjoint() * m1.row(c).adjoint().adjoint()).eval().template triangularView<Upper>().toDenseMatrix()));
+}
+
+void test_product_syrk()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ int s;
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_1( syrk(MatrixXf(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_2( syrk(MatrixXd(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_3( syrk(MatrixXcf(s, s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( syrk(MatrixXcd(s, s)) );
+ }
+}
diff --git a/test/product_trmm.cpp b/test/product_trmm.cpp
new file mode 100644
index 000000000..64244c18f
--- /dev/null
+++ b/test/product_trmm.cpp
@@ -0,0 +1,108 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename Scalar, int Mode, int TriOrder, int OtherOrder, int ResOrder, int OtherCols>
+void trmm(int rows=internal::random<int>(1,EIGEN_TEST_MAX_SIZE),
+ int cols=internal::random<int>(1,EIGEN_TEST_MAX_SIZE),
+ int otherCols = OtherCols==Dynamic?internal::random<int>(1,EIGEN_TEST_MAX_SIZE):OtherCols)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Matrix<Scalar,Dynamic,Dynamic,TriOrder> TriMatrix;
+ typedef Matrix<Scalar,Dynamic,OtherCols,OtherCols==1?ColMajor:OtherOrder> OnTheRight;
+ typedef Matrix<Scalar,OtherCols,Dynamic,OtherCols==1?RowMajor:OtherOrder> OnTheLeft;
+
+ typedef Matrix<Scalar,Dynamic,OtherCols,OtherCols==1?ColMajor:ResOrder> ResXS;
+ typedef Matrix<Scalar,OtherCols,Dynamic,OtherCols==1?RowMajor:ResOrder> ResSX;
+
+ TriMatrix mat(rows,cols), tri(rows,cols), triTr(cols,rows);
+
+ OnTheRight ge_right(cols,otherCols);
+ OnTheLeft ge_left(otherCols,rows);
+ ResSX ge_sx, ge_sx_save;
+ ResXS ge_xs, ge_xs_save;
+
+ Scalar s1 = internal::random<Scalar>(),
+ s2 = internal::random<Scalar>();
+
+ mat.setRandom();
+ tri = mat.template triangularView<Mode>();
+ triTr = mat.transpose().template triangularView<Mode>();
+ ge_right.setRandom();
+ ge_left.setRandom();
+
+ VERIFY_IS_APPROX( ge_xs = mat.template triangularView<Mode>() * ge_right, tri * ge_right);
+ VERIFY_IS_APPROX( ge_sx = ge_left * mat.template triangularView<Mode>(), ge_left * tri);
+
+ VERIFY_IS_APPROX( ge_xs.noalias() = mat.template triangularView<Mode>() * ge_right, tri * ge_right);
+ VERIFY_IS_APPROX( ge_sx.noalias() = ge_left * mat.template triangularView<Mode>(), ge_left * tri);
+
+ VERIFY_IS_APPROX( ge_xs.noalias() = (s1*mat.adjoint()).template triangularView<Mode>() * (s2*ge_left.transpose()), s1*triTr.conjugate() * (s2*ge_left.transpose()));
+ VERIFY_IS_APPROX( ge_sx.noalias() = ge_right.transpose() * mat.adjoint().template triangularView<Mode>(), ge_right.transpose() * triTr.conjugate());
+
+ VERIFY_IS_APPROX( ge_xs.noalias() = (s1*mat.adjoint()).template triangularView<Mode>() * (s2*ge_left.adjoint()), s1*triTr.conjugate() * (s2*ge_left.adjoint()));
+ VERIFY_IS_APPROX( ge_sx.noalias() = ge_right.adjoint() * mat.adjoint().template triangularView<Mode>(), ge_right.adjoint() * triTr.conjugate());
+
+ ge_xs_save = ge_xs;
+ VERIFY_IS_APPROX( (ge_xs_save + s1*triTr.conjugate() * (s2*ge_left.adjoint())).eval(), ge_xs.noalias() += (s1*mat.adjoint()).template triangularView<Mode>() * (s2*ge_left.adjoint()) );
+ ge_sx_save = ge_sx;
+ VERIFY_IS_APPROX( ge_sx_save - (ge_right.adjoint() * (-s1 * triTr).conjugate()).eval(), ge_sx.noalias() -= (ge_right.adjoint() * (-s1 * mat).adjoint().template triangularView<Mode>()).eval());
+
+ VERIFY_IS_APPROX( ge_xs = (s1*mat).adjoint().template triangularView<Mode>() * ge_left.adjoint(), internal::conj(s1) * triTr.conjugate() * ge_left.adjoint());
+
+ // TODO check with sub-matrix expressions ?
+}
+
+template<typename Scalar, int Mode, int TriOrder>
+void trmv(int rows=internal::random<int>(1,EIGEN_TEST_MAX_SIZE), int cols=internal::random<int>(1,EIGEN_TEST_MAX_SIZE))
+{
+ trmm<Scalar,Mode,TriOrder,ColMajor,ColMajor,1>(rows,cols,1);
+}
+
+template<typename Scalar, int Mode, int TriOrder, int OtherOrder, int ResOrder>
+void trmm(int rows=internal::random<int>(1,EIGEN_TEST_MAX_SIZE), int cols=internal::random<int>(1,EIGEN_TEST_MAX_SIZE), int otherCols = internal::random<int>(1,EIGEN_TEST_MAX_SIZE))
+{
+ trmm<Scalar,Mode,TriOrder,OtherOrder,ResOrder,Dynamic>(rows,cols,otherCols);
+}
+
+#define CALL_ALL_ORDERS(NB,SCALAR,MODE) \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,ColMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,ColMajor,RowMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,RowMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, ColMajor,RowMajor,RowMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,ColMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,ColMajor,RowMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,RowMajor,ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_,NB)((trmm<SCALAR, MODE, RowMajor,RowMajor,RowMajor>())); \
+ \
+ EIGEN_CAT(CALL_SUBTEST_1,NB)((trmv<SCALAR, MODE, ColMajor>())); \
+ EIGEN_CAT(CALL_SUBTEST_1,NB)((trmv<SCALAR, MODE, RowMajor>()));
+
+
+#define CALL_ALL(NB,SCALAR) \
+ CALL_ALL_ORDERS(EIGEN_CAT(1,NB),SCALAR,Upper) \
+ CALL_ALL_ORDERS(EIGEN_CAT(2,NB),SCALAR,UnitUpper) \
+ CALL_ALL_ORDERS(EIGEN_CAT(3,NB),SCALAR,StrictlyUpper) \
+ CALL_ALL_ORDERS(EIGEN_CAT(1,NB),SCALAR,Lower) \
+ CALL_ALL_ORDERS(EIGEN_CAT(2,NB),SCALAR,UnitLower) \
+ CALL_ALL_ORDERS(EIGEN_CAT(3,NB),SCALAR,StrictlyLower)
+
+
+void test_product_trmm()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ CALL_ALL(1,float); // EIGEN_SUFFIXES;11;111;21;121;31;131
+ CALL_ALL(2,double); // EIGEN_SUFFIXES;12;112;22;122;32;132
+ CALL_ALL(3,std::complex<float>); // EIGEN_SUFFIXES;13;113;23;123;33;133
+ CALL_ALL(4,std::complex<double>); // EIGEN_SUFFIXES;14;114;24;124;34;134
+ }
+}
diff --git a/test/product_trmv.cpp b/test/product_trmv.cpp
new file mode 100644
index 000000000..435018e8e
--- /dev/null
+++ b/test/product_trmv.cpp
@@ -0,0 +1,89 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void trmv(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+ VectorType v1 = VectorType::Random(rows);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ m1 = MatrixType::Random(rows, cols);
+
+ // check with a column-major matrix
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::Upper>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitLower>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::UnitLower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitUpper>();
+ VERIFY((m3 * v1).isApprox(m1.template triangularView<Eigen::UnitUpper>() * v1, largerEps));
+
+ // check conjugated and scalar multiple expressions (col-major)
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY(((s1*m3).conjugate() * v1).isApprox((s1*m1).conjugate().template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3.conjugate() * v1.conjugate()).isApprox(m1.conjugate().template triangularView<Eigen::Upper>() * v1.conjugate(), largerEps));
+
+ // check with a row-major matrix
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::Upper>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitUpper>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::UnitLower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::UnitLower>();
+ VERIFY((m3.transpose() * v1).isApprox(m1.transpose().template triangularView<Eigen::UnitUpper>() * v1, largerEps));
+
+ // check conjugated and scalar multiple expressions (row-major)
+ m3 = m1.template triangularView<Eigen::Upper>();
+ VERIFY((m3.adjoint() * v1).isApprox(m1.adjoint().template triangularView<Eigen::Lower>() * v1, largerEps));
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((m3.adjoint() * (s1*v1.conjugate())).isApprox(m1.adjoint().template triangularView<Eigen::Upper>() * (s1*v1.conjugate()), largerEps));
+ m3 = m1.template triangularView<Eigen::UnitUpper>();
+
+ // check transposed cases:
+ m3 = m1.template triangularView<Eigen::Lower>();
+ VERIFY((v1.transpose() * m3).isApprox(v1.transpose() * m1.template triangularView<Eigen::Lower>(), largerEps));
+ VERIFY((v1.adjoint() * m3).isApprox(v1.adjoint() * m1.template triangularView<Eigen::Lower>(), largerEps));
+ VERIFY((v1.adjoint() * m3.adjoint()).isApprox(v1.adjoint() * m1.template triangularView<Eigen::Lower>().adjoint(), largerEps));
+
+ // TODO check with sub-matrices
+}
+
+void test_product_trmv()
+{
+ int s;
+ for(int i = 0; i < g_repeat ; i++) {
+ CALL_SUBTEST_1( trmv(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( trmv(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( trmv(Matrix3d()) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_4( trmv(MatrixXcf(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
+ CALL_SUBTEST_5( trmv(MatrixXcd(s,s)) );
+ s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE);
+ CALL_SUBTEST_6( trmv(Matrix<float,Dynamic,Dynamic,RowMajor>(s, s)) );
+ }
+ EIGEN_UNUSED_VARIABLE(s);
+}
diff --git a/test/product_trsolve.cpp b/test/product_trsolve.cpp
new file mode 100644
index 000000000..69892b3a8
--- /dev/null
+++ b/test/product_trsolve.cpp
@@ -0,0 +1,93 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+#define VERIFY_TRSM(TRI,XB) { \
+ (XB).setRandom(); ref = (XB); \
+ (TRI).solveInPlace(XB); \
+ VERIFY_IS_APPROX((TRI).toDenseMatrix() * (XB), ref); \
+ (XB).setRandom(); ref = (XB); \
+ (XB) = (TRI).solve(XB); \
+ VERIFY_IS_APPROX((TRI).toDenseMatrix() * (XB), ref); \
+ }
+
+#define VERIFY_TRSM_ONTHERIGHT(TRI,XB) { \
+ (XB).setRandom(); ref = (XB); \
+ (TRI).transpose().template solveInPlace<OnTheRight>(XB.transpose()); \
+ VERIFY_IS_APPROX((XB).transpose() * (TRI).transpose().toDenseMatrix(), ref.transpose()); \
+ (XB).setRandom(); ref = (XB); \
+ (XB).transpose() = (TRI).transpose().template solve<OnTheRight>(XB.transpose()); \
+ VERIFY_IS_APPROX((XB).transpose() * (TRI).transpose().toDenseMatrix(), ref.transpose()); \
+ }
+
+template<typename Scalar,int Size, int Cols> void trsolve(int size=Size,int cols=Cols)
+{
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ Matrix<Scalar,Size,Size,ColMajor> cmLhs(size,size);
+ Matrix<Scalar,Size,Size,RowMajor> rmLhs(size,size);
+
+ enum { colmajor = Size==1 ? RowMajor : ColMajor,
+ rowmajor = Cols==1 ? ColMajor : RowMajor };
+ Matrix<Scalar,Size,Cols,colmajor> cmRhs(size,cols);
+ Matrix<Scalar,Size,Cols,rowmajor> rmRhs(size,cols);
+ Matrix<Scalar,Dynamic,Dynamic,colmajor> ref(size,cols);
+
+ cmLhs.setRandom(); cmLhs *= static_cast<RealScalar>(0.1); cmLhs.diagonal().array() += static_cast<RealScalar>(1);
+ rmLhs.setRandom(); rmLhs *= static_cast<RealScalar>(0.1); rmLhs.diagonal().array() += static_cast<RealScalar>(1);
+
+ VERIFY_TRSM(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM(cmLhs.adjoint() .template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM(cmLhs .template triangularView<Upper>(), cmRhs);
+ VERIFY_TRSM(cmLhs .template triangularView<Lower>(), rmRhs);
+ VERIFY_TRSM(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);
+ VERIFY_TRSM(cmLhs.adjoint() .template triangularView<Upper>(), rmRhs);
+
+ VERIFY_TRSM(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
+ VERIFY_TRSM(cmLhs .template triangularView<UnitUpper>(), rmRhs);
+
+ VERIFY_TRSM(rmLhs .template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);
+
+
+ VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs .template triangularView<Upper>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs .template triangularView<Lower>(), rmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);
+
+ VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(cmLhs .template triangularView<UnitUpper>(), rmRhs);
+
+ VERIFY_TRSM_ONTHERIGHT(rmLhs .template triangularView<Lower>(), cmRhs);
+ VERIFY_TRSM_ONTHERIGHT(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);
+
+ int c = internal::random<int>(0,cols-1);
+ VERIFY_TRSM(rmLhs.template triangularView<Lower>(), rmRhs.col(c));
+ VERIFY_TRSM(cmLhs.template triangularView<Lower>(), rmRhs.col(c));
+}
+
+void test_product_trsolve()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ // matrices
+ CALL_SUBTEST_1((trsolve<float,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_2((trsolve<double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_3((trsolve<std::complex<float>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+ CALL_SUBTEST_4((trsolve<std::complex<double>,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))));
+
+ // vectors
+ CALL_SUBTEST_1((trsolve<float,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_5((trsolve<std::complex<double>,Dynamic,1>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
+ CALL_SUBTEST_6((trsolve<float,1,1>()));
+ CALL_SUBTEST_7((trsolve<float,1,2>()));
+ CALL_SUBTEST_8((trsolve<std::complex<float>,4,1>()));
+ }
+}
diff --git a/test/qr.cpp b/test/qr.cpp
new file mode 100644
index 000000000..37fb7aa4d
--- /dev/null
+++ b/test/qr.cpp
@@ -0,0 +1,126 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> MatrixQType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ HouseholderQR<MatrixType> qrOfA(a);
+
+ MatrixQType q = qrOfA.householderQ();
+ VERIFY_IS_UNITARY(q);
+
+ MatrixType r = qrOfA.matrixQR().template triangularView<Upper>();
+ VERIFY_IS_APPROX(a, qrOfA.householderQ() * r);
+}
+
+template<typename MatrixType, int Cols2> void qr_fixedsize()
+{
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef typename MatrixType::Scalar Scalar;
+ Matrix<Scalar,Rows,Cols> m1 = Matrix<Scalar,Rows,Cols>::Random();
+ HouseholderQR<Matrix<Scalar,Rows,Cols> > qr(m1);
+
+ Matrix<Scalar,Rows,Cols> r = qr.matrixQR();
+ // FIXME need better way to construct trapezoid
+ for(int i = 0; i < Rows; i++) for(int j = 0; j < Cols; j++) if(i>j) r(i,j) = Scalar(0);
+
+ VERIFY_IS_APPROX(m1, qr.householderQ() * r);
+
+ Matrix<Scalar,Cols,Cols2> m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ Matrix<Scalar,Rows,Cols2> m3 = m1*m2;
+ m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void qr_invertible()
+{
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Scalar Scalar;
+
+ int size = internal::random<int>(10,50);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (internal::is_same<RealScalar,float>::value)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ HouseholderQR<MatrixType> qr(m1);
+ m3 = MatrixType::Random(size,size);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+
+ // now construct a matrix with prescribed determinant
+ m1.setZero();
+ for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
+ RealScalar absdet = internal::abs(m1.diagonal().prod());
+ m3 = qr.householderQ(); // get a unitary
+ m1 = m3 * m1 * m3;
+ qr.compute(m1);
+ VERIFY_IS_APPROX(absdet, qr.absDeterminant());
+ VERIFY_IS_APPROX(internal::log(absdet), qr.logAbsDeterminant());
+}
+
+template<typename MatrixType> void qr_verify_assert()
+{
+ MatrixType tmp;
+
+ HouseholderQR<MatrixType> qr;
+ VERIFY_RAISES_ASSERT(qr.matrixQR())
+ VERIFY_RAISES_ASSERT(qr.solve(tmp))
+ VERIFY_RAISES_ASSERT(qr.householderQ())
+ VERIFY_RAISES_ASSERT(qr.absDeterminant())
+ VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
+}
+
+void test_qr()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_2( qr(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2),internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2))) );
+ CALL_SUBTEST_3(( qr_fixedsize<Matrix<float,3,4>, 2 >() ));
+ CALL_SUBTEST_4(( qr_fixedsize<Matrix<double,6,2>, 4 >() ));
+ CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,2,5>, 7 >() ));
+ CALL_SUBTEST_11( qr(Matrix<float,1,1>()) );
+ }
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
+ CALL_SUBTEST_6( qr_invertible<MatrixXd>() );
+ CALL_SUBTEST_7( qr_invertible<MatrixXcf>() );
+ CALL_SUBTEST_8( qr_invertible<MatrixXcd>() );
+ }
+
+ CALL_SUBTEST_9(qr_verify_assert<Matrix3f>());
+ CALL_SUBTEST_10(qr_verify_assert<Matrix3d>());
+ CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
+ CALL_SUBTEST_6(qr_verify_assert<MatrixXd>());
+ CALL_SUBTEST_7(qr_verify_assert<MatrixXcf>());
+ CALL_SUBTEST_8(qr_verify_assert<MatrixXcd>());
+
+ // Test problem size constructors
+ CALL_SUBTEST_12(HouseholderQR<MatrixXf>(10, 20));
+}
diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp
new file mode 100644
index 000000000..dd0812819
--- /dev/null
+++ b/test/qr_colpivoting.cpp
@@ -0,0 +1,150 @@
+// 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) 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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr()
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE), cols = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE), cols2 = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
+ Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> MatrixQType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+ MatrixType m1;
+ createRandomPIMatrixOfRank(rank,rows,cols,m1);
+ ColPivHouseholderQR<MatrixType> qr(m1);
+ VERIFY(rank == qr.rank());
+ VERIFY(cols - qr.rank() == qr.dimensionOfKernel());
+ VERIFY(!qr.isInjective());
+ VERIFY(!qr.isInvertible());
+ VERIFY(!qr.isSurjective());
+
+ MatrixQType q = qr.householderQ();
+ VERIFY_IS_UNITARY(q);
+
+ MatrixType r = qr.matrixQR().template triangularView<Upper>();
+ MatrixType c = q * r * qr.colsPermutation().inverse();
+ VERIFY_IS_APPROX(m1, c);
+
+ MatrixType m2 = MatrixType::Random(cols,cols2);
+ MatrixType m3 = m1*m2;
+ m2 = MatrixType::Random(cols,cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType, int Cols2> void qr_fixedsize()
+{
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef typename MatrixType::Scalar Scalar;
+ int rank = internal::random<int>(1, (std::min)(int(Rows), int(Cols))-1);
+ Matrix<Scalar,Rows,Cols> m1;
+ createRandomPIMatrixOfRank(rank,Rows,Cols,m1);
+ ColPivHouseholderQR<Matrix<Scalar,Rows,Cols> > qr(m1);
+ VERIFY(rank == qr.rank());
+ VERIFY(Cols - qr.rank() == qr.dimensionOfKernel());
+ VERIFY(qr.isInjective() == (rank == Rows));
+ VERIFY(qr.isSurjective() == (rank == Cols));
+ VERIFY(qr.isInvertible() == (qr.isInjective() && qr.isSurjective()));
+
+ Matrix<Scalar,Rows,Cols> r = qr.matrixQR().template triangularView<Upper>();
+ Matrix<Scalar,Rows,Cols> c = qr.householderQ() * r * qr.colsPermutation().inverse();
+ VERIFY_IS_APPROX(m1, c);
+
+ Matrix<Scalar,Cols,Cols2> m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ Matrix<Scalar,Rows,Cols2> m3 = m1*m2;
+ m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void qr_invertible()
+{
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Scalar Scalar;
+
+ int size = internal::random<int>(10,50);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (internal::is_same<RealScalar,float>::value)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ ColPivHouseholderQR<MatrixType> qr(m1);
+ m3 = MatrixType::Random(size,size);
+ m2 = qr.solve(m3);
+ //VERIFY_IS_APPROX(m3, m1*m2);
+
+ // now construct a matrix with prescribed determinant
+ m1.setZero();
+ for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
+ RealScalar absdet = internal::abs(m1.diagonal().prod());
+ m3 = qr.householderQ(); // get a unitary
+ m1 = m3 * m1 * m3;
+ qr.compute(m1);
+ VERIFY_IS_APPROX(absdet, qr.absDeterminant());
+ VERIFY_IS_APPROX(internal::log(absdet), qr.logAbsDeterminant());
+}
+
+template<typename MatrixType> void qr_verify_assert()
+{
+ MatrixType tmp;
+
+ ColPivHouseholderQR<MatrixType> qr;
+ VERIFY_RAISES_ASSERT(qr.matrixQR())
+ VERIFY_RAISES_ASSERT(qr.solve(tmp))
+ VERIFY_RAISES_ASSERT(qr.householderQ())
+ VERIFY_RAISES_ASSERT(qr.dimensionOfKernel())
+ VERIFY_RAISES_ASSERT(qr.isInjective())
+ VERIFY_RAISES_ASSERT(qr.isSurjective())
+ VERIFY_RAISES_ASSERT(qr.isInvertible())
+ VERIFY_RAISES_ASSERT(qr.inverse())
+ VERIFY_RAISES_ASSERT(qr.absDeterminant())
+ VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
+}
+
+void test_qr_colpivoting()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr<MatrixXf>() );
+ CALL_SUBTEST_2( qr<MatrixXd>() );
+ CALL_SUBTEST_3( qr<MatrixXcd>() );
+ CALL_SUBTEST_4(( qr_fixedsize<Matrix<float,3,5>, 4 >() ));
+ CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,6,2>, 3 >() ));
+ CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,1,1>, 1 >() ));
+ }
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( qr_invertible<MatrixXd>() );
+ CALL_SUBTEST_6( qr_invertible<MatrixXcf>() );
+ CALL_SUBTEST_3( qr_invertible<MatrixXcd>() );
+ }
+
+ CALL_SUBTEST_7(qr_verify_assert<Matrix3f>());
+ CALL_SUBTEST_8(qr_verify_assert<Matrix3d>());
+ CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
+ CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
+ CALL_SUBTEST_6(qr_verify_assert<MatrixXcf>());
+ CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
+
+ // Test problem size constructors
+ CALL_SUBTEST_9(ColPivHouseholderQR<MatrixXf>(10, 20));
+}
diff --git a/test/qr_fullpivoting.cpp b/test/qr_fullpivoting.cpp
new file mode 100644
index 000000000..e5c9790c8
--- /dev/null
+++ b/test/qr_fullpivoting.cpp
@@ -0,0 +1,132 @@
+// 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) 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/.
+
+#include "main.h"
+#include <Eigen/QR>
+
+template<typename MatrixType> void qr()
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = internal::random<Index>(20,200), cols = internal::random<int>(20,200), cols2 = internal::random<int>(20,200);
+ Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> MatrixQType;
+ typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
+ MatrixType m1;
+ createRandomPIMatrixOfRank(rank,rows,cols,m1);
+ FullPivHouseholderQR<MatrixType> qr(m1);
+ VERIFY(rank == qr.rank());
+ VERIFY(cols - qr.rank() == qr.dimensionOfKernel());
+ VERIFY(!qr.isInjective());
+ VERIFY(!qr.isInvertible());
+ VERIFY(!qr.isSurjective());
+
+ MatrixType r = qr.matrixQR();
+
+ MatrixQType q = qr.matrixQ();
+ VERIFY_IS_UNITARY(q);
+
+ // FIXME need better way to construct trapezoid
+ for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) if(i>j) r(i,j) = Scalar(0);
+
+ MatrixType c = qr.matrixQ() * r * qr.colsPermutation().inverse();
+
+ VERIFY_IS_APPROX(m1, c);
+
+ MatrixType m2 = MatrixType::Random(cols,cols2);
+ MatrixType m3 = m1*m2;
+ m2 = MatrixType::Random(cols,cols2);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+}
+
+template<typename MatrixType> void qr_invertible()
+{
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Scalar Scalar;
+
+ int size = internal::random<int>(10,50);
+
+ MatrixType m1(size, size), m2(size, size), m3(size, size);
+ m1 = MatrixType::Random(size,size);
+
+ if (internal::is_same<RealScalar,float>::value)
+ {
+ // let's build a matrix more stable to inverse
+ MatrixType a = MatrixType::Random(size,size*2);
+ m1 += a * a.adjoint();
+ }
+
+ FullPivHouseholderQR<MatrixType> qr(m1);
+ VERIFY(qr.isInjective());
+ VERIFY(qr.isInvertible());
+ VERIFY(qr.isSurjective());
+
+ m3 = MatrixType::Random(size,size);
+ m2 = qr.solve(m3);
+ VERIFY_IS_APPROX(m3, m1*m2);
+
+ // now construct a matrix with prescribed determinant
+ m1.setZero();
+ for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
+ RealScalar absdet = internal::abs(m1.diagonal().prod());
+ m3 = qr.matrixQ(); // get a unitary
+ m1 = m3 * m1 * m3;
+ qr.compute(m1);
+ VERIFY_IS_APPROX(absdet, qr.absDeterminant());
+ VERIFY_IS_APPROX(internal::log(absdet), qr.logAbsDeterminant());
+}
+
+template<typename MatrixType> void qr_verify_assert()
+{
+ MatrixType tmp;
+
+ FullPivHouseholderQR<MatrixType> qr;
+ VERIFY_RAISES_ASSERT(qr.matrixQR())
+ VERIFY_RAISES_ASSERT(qr.solve(tmp))
+ VERIFY_RAISES_ASSERT(qr.matrixQ())
+ VERIFY_RAISES_ASSERT(qr.dimensionOfKernel())
+ VERIFY_RAISES_ASSERT(qr.isInjective())
+ VERIFY_RAISES_ASSERT(qr.isSurjective())
+ VERIFY_RAISES_ASSERT(qr.isInvertible())
+ VERIFY_RAISES_ASSERT(qr.inverse())
+ VERIFY_RAISES_ASSERT(qr.absDeterminant())
+ VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
+}
+
+void test_qr_fullpivoting()
+{
+ for(int i = 0; i < 1; i++) {
+ // FIXME : very weird bug here
+// CALL_SUBTEST(qr(Matrix2f()) );
+ CALL_SUBTEST_1( qr<MatrixXf>() );
+ CALL_SUBTEST_2( qr<MatrixXd>() );
+ CALL_SUBTEST_3( qr<MatrixXcd>() );
+ }
+
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
+ CALL_SUBTEST_2( qr_invertible<MatrixXd>() );
+ CALL_SUBTEST_4( qr_invertible<MatrixXcf>() );
+ CALL_SUBTEST_3( qr_invertible<MatrixXcd>() );
+ }
+
+ CALL_SUBTEST_5(qr_verify_assert<Matrix3f>());
+ CALL_SUBTEST_6(qr_verify_assert<Matrix3d>());
+ CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
+ CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
+ CALL_SUBTEST_4(qr_verify_assert<MatrixXcf>());
+ CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
+
+ // Test problem size constructors
+ CALL_SUBTEST_7(FullPivHouseholderQR<MatrixXf>(10, 20));
+}
diff --git a/test/qtvector.cpp b/test/qtvector.cpp
new file mode 100644
index 000000000..2be885e48
--- /dev/null
+++ b/test/qtvector.cpp
@@ -0,0 +1,158 @@
+// 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 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/.
+
+#define EIGEN_WORK_AROUND_QT_BUG_CALLING_WRONG_OPERATOR_NEW_FIXED_IN_QT_4_5
+
+#include "main.h"
+#include <QtCore/QVector>
+#include <Eigen/Geometry>
+#include <Eigen/QtAlignedMalloc>
+
+template<typename MatrixType>
+void check_qtvector_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ QVector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], y);
+ }
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_qtvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ QVector<TransformType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_qtvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ QVector<QuaternionType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.fill(y,22);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; int(i)<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_qtvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST(check_qtvector_matrix(Vector2f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix3f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST(check_qtvector_matrix(Matrix2f()));
+ CALL_SUBTEST(check_qtvector_matrix(Vector4f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix4f()));
+ CALL_SUBTEST(check_qtvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST(check_qtvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST(check_qtvector_matrix(VectorXd(20)));
+ CALL_SUBTEST(check_qtvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST(check_qtvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST(check_qtvector_transform(Affine2f()));
+ CALL_SUBTEST(check_qtvector_transform(Affine3f()));
+ CALL_SUBTEST(check_qtvector_transform(Affine3d()));
+ //CALL_SUBTEST(check_qtvector_transform(Transform4d()));
+
+ // some Quaternion
+ CALL_SUBTEST(check_qtvector_quaternion(Quaternionf()));
+ CALL_SUBTEST(check_qtvector_quaternion(Quaternionf()));
+}
diff --git a/test/redux.cpp b/test/redux.cpp
new file mode 100644
index 000000000..e07d4b1e4
--- /dev/null
+++ b/test/redux.cpp
@@ -0,0 +1,158 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void matrixRedux(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::RealScalar RealScalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols);
+
+ // The entries of m1 are uniformly distributed in [0,1], so m1.prod() is very small. This may lead to test
+ // failures if we underflow into denormals. Thus, we scale so that entires are close to 1.
+ MatrixType m1_for_prod = MatrixType::Ones(rows, cols) + Scalar(0.2) * m1;
+
+ VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
+ VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
+ Scalar s(0), p(1), minc(internal::real(m1.coeff(0))), maxc(internal::real(m1.coeff(0)));
+ for(int j = 0; j < cols; j++)
+ for(int i = 0; i < rows; i++)
+ {
+ s += m1(i,j);
+ p *= m1_for_prod(i,j);
+ minc = (std::min)(internal::real(minc), internal::real(m1(i,j)));
+ maxc = (std::max)(internal::real(maxc), internal::real(m1(i,j)));
+ }
+ const Scalar mean = s/Scalar(RealScalar(rows*cols));
+
+ VERIFY_IS_APPROX(m1.sum(), s);
+ VERIFY_IS_APPROX(m1.mean(), mean);
+ VERIFY_IS_APPROX(m1_for_prod.prod(), p);
+ VERIFY_IS_APPROX(m1.real().minCoeff(), internal::real(minc));
+ VERIFY_IS_APPROX(m1.real().maxCoeff(), internal::real(maxc));
+
+ // test slice vectorization assuming assign is ok
+ Index r0 = internal::random<Index>(0,rows-1);
+ Index c0 = internal::random<Index>(0,cols-1);
+ Index r1 = internal::random<Index>(r0+1,rows)-r0;
+ Index c1 = internal::random<Index>(c0+1,cols)-c0;
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).sum(), m1.block(r0,c0,r1,c1).eval().sum());
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).mean(), m1.block(r0,c0,r1,c1).eval().mean());
+ VERIFY_IS_APPROX(m1_for_prod.block(r0,c0,r1,c1).prod(), m1_for_prod.block(r0,c0,r1,c1).eval().prod());
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
+ VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());
+
+ // test empty objects
+ VERIFY_IS_APPROX(m1.block(r0,c0,0,0).sum(), Scalar(0));
+ VERIFY_IS_APPROX(m1.block(r0,c0,0,0).prod(), Scalar(1));
+}
+
+template<typename VectorType> void vectorRedux(const VectorType& w)
+{
+ typedef typename VectorType::Index Index;
+ typedef typename VectorType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ Index size = w.size();
+
+ VectorType v = VectorType::Random(size);
+ VectorType v_for_prod = VectorType::Ones(size) + Scalar(0.2) * v; // see comment above declaration of m1_for_prod
+
+ for(int i = 1; i < size; i++)
+ {
+ Scalar s(0), p(1);
+ RealScalar minc(internal::real(v.coeff(0))), maxc(internal::real(v.coeff(0)));
+ for(int j = 0; j < i; j++)
+ {
+ s += v[j];
+ p *= v_for_prod[j];
+ minc = (std::min)(minc, internal::real(v[j]));
+ maxc = (std::max)(maxc, internal::real(v[j]));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.head(i).sum()), Scalar(1));
+ VERIFY_IS_APPROX(p, v_for_prod.head(i).prod());
+ VERIFY_IS_APPROX(minc, v.real().head(i).minCoeff());
+ VERIFY_IS_APPROX(maxc, v.real().head(i).maxCoeff());
+ }
+
+ for(int i = 0; i < size-1; i++)
+ {
+ Scalar s(0), p(1);
+ RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
+ for(int j = i; j < size; j++)
+ {
+ s += v[j];
+ p *= v_for_prod[j];
+ minc = (std::min)(minc, internal::real(v[j]));
+ maxc = (std::max)(maxc, internal::real(v[j]));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.tail(size-i).sum()), Scalar(1));
+ VERIFY_IS_APPROX(p, v_for_prod.tail(size-i).prod());
+ VERIFY_IS_APPROX(minc, v.real().tail(size-i).minCoeff());
+ VERIFY_IS_APPROX(maxc, v.real().tail(size-i).maxCoeff());
+ }
+
+ for(int i = 0; i < size/2; i++)
+ {
+ Scalar s(0), p(1);
+ RealScalar minc(internal::real(v.coeff(i))), maxc(internal::real(v.coeff(i)));
+ for(int j = i; j < size-i; j++)
+ {
+ s += v[j];
+ p *= v_for_prod[j];
+ minc = (std::min)(minc, internal::real(v[j]));
+ maxc = (std::max)(maxc, internal::real(v[j]));
+ }
+ VERIFY_IS_MUCH_SMALLER_THAN(internal::abs(s - v.segment(i, size-2*i).sum()), Scalar(1));
+ VERIFY_IS_APPROX(p, v_for_prod.segment(i, size-2*i).prod());
+ VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
+ VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
+ }
+
+ // test empty objects
+ VERIFY_IS_APPROX(v.head(0).sum(), Scalar(0));
+ VERIFY_IS_APPROX(v.tail(0).prod(), Scalar(1));
+ VERIFY_RAISES_ASSERT(v.head(0).mean());
+ VERIFY_RAISES_ASSERT(v.head(0).minCoeff());
+ VERIFY_RAISES_ASSERT(v.head(0).maxCoeff());
+}
+
+void test_redux()
+{
+ // the max size cannot be too large, otherwise reduxion operations obviously generate large errors.
+ int maxsize = (std::min)(100,EIGEN_TEST_MAX_SIZE);
+ EIGEN_UNUSED_VARIABLE(maxsize);
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixRedux(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_1( matrixRedux(Array<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixRedux(Matrix2f()) );
+ CALL_SUBTEST_2( matrixRedux(Array2f()) );
+ CALL_SUBTEST_3( matrixRedux(Matrix4d()) );
+ CALL_SUBTEST_3( matrixRedux(Array4d()) );
+ CALL_SUBTEST_4( matrixRedux(MatrixXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_4( matrixRedux(ArrayXXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_5( matrixRedux(MatrixXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_5( matrixRedux(ArrayXXd (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_6( matrixRedux(MatrixXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_6( matrixRedux(ArrayXXi (internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_7( vectorRedux(Vector4f()) );
+ CALL_SUBTEST_7( vectorRedux(Array4f()) );
+ CALL_SUBTEST_5( vectorRedux(VectorXd(internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_5( vectorRedux(ArrayXd(internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_8( vectorRedux(VectorXf(internal::random<int>(1,maxsize))) );
+ CALL_SUBTEST_8( vectorRedux(ArrayXf(internal::random<int>(1,maxsize))) );
+ }
+}
diff --git a/test/resize.cpp b/test/resize.cpp
new file mode 100644
index 000000000..4adaafe56
--- /dev/null
+++ b/test/resize.cpp
@@ -0,0 +1,41 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Keir Mierle <mierle@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/.
+
+#include "main.h"
+
+template<DenseIndex rows, DenseIndex cols>
+void resizeLikeTest()
+{
+ MatrixXf A(rows, cols);
+ MatrixXf B;
+ Matrix<double, rows, cols> C;
+ B.resizeLike(A);
+ C.resizeLike(B); // Shouldn't crash.
+ VERIFY(B.rows() == rows && B.cols() == cols);
+
+ VectorXf x(rows);
+ RowVectorXf y;
+ y.resizeLike(x);
+ VERIFY(y.rows() == 1 && y.cols() == rows);
+
+ y.resize(cols);
+ x.resizeLike(y);
+ VERIFY(x.rows() == cols && x.cols() == 1);
+}
+
+void resizeLikeTest12() { resizeLikeTest<1,2>(); }
+void resizeLikeTest1020() { resizeLikeTest<10,20>(); }
+void resizeLikeTest31() { resizeLikeTest<3,1>(); }
+
+void test_resize()
+{
+ CALL_SUBTEST(resizeLikeTest12() );
+ CALL_SUBTEST(resizeLikeTest1020() );
+ CALL_SUBTEST(resizeLikeTest31() );
+}
diff --git a/test/runtest.sh b/test/runtest.sh
new file mode 100755
index 000000000..2be250819
--- /dev/null
+++ b/test/runtest.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+black='\E[30m'
+red='\E[31m'
+green='\E[32m'
+yellow='\E[33m'
+blue='\E[34m'
+magenta='\E[35m'
+cyan='\E[36m'
+white='\E[37m'
+
+if ! ./$1 > /dev/null 2> .runtest.log ; then
+ echo -e $red Test $1 failed: $black
+ echo -e $blue
+ cat .runtest.log
+ echo -e $black
+ exit 1
+else
+echo -e $green Test $1 passed$black
+fi
diff --git a/test/schur_complex.cpp b/test/schur_complex.cpp
new file mode 100644
index 000000000..a6f66ab02
--- /dev/null
+++ b/test/schur_complex.cpp
@@ -0,0 +1,74 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime)
+{
+ typedef typename ComplexSchur<MatrixType>::ComplexScalar ComplexScalar;
+ typedef typename ComplexSchur<MatrixType>::ComplexMatrixType ComplexMatrixType;
+
+ // Test basic functionality: T is triangular and A = U T U*
+ for(int counter = 0; counter < g_repeat; ++counter) {
+ MatrixType A = MatrixType::Random(size, size);
+ ComplexSchur<MatrixType> schurOfA(A);
+ VERIFY_IS_EQUAL(schurOfA.info(), Success);
+ ComplexMatrixType U = schurOfA.matrixU();
+ ComplexMatrixType T = schurOfA.matrixT();
+ for(int row = 1; row < size; ++row) {
+ for(int col = 0; col < row; ++col) {
+ VERIFY(T(row,col) == (typename MatrixType::Scalar)0);
+ }
+ }
+ VERIFY_IS_APPROX(A.template cast<ComplexScalar>(), U * T * U.adjoint());
+ }
+
+ // Test asserts when not initialized
+ ComplexSchur<MatrixType> csUninitialized;
+ VERIFY_RAISES_ASSERT(csUninitialized.matrixT());
+ VERIFY_RAISES_ASSERT(csUninitialized.matrixU());
+ VERIFY_RAISES_ASSERT(csUninitialized.info());
+
+ // Test whether compute() and constructor returns same result
+ MatrixType A = MatrixType::Random(size, size);
+ ComplexSchur<MatrixType> cs1;
+ cs1.compute(A);
+ ComplexSchur<MatrixType> cs2(A);
+ VERIFY_IS_EQUAL(cs1.info(), Success);
+ VERIFY_IS_EQUAL(cs2.info(), Success);
+ VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT());
+ VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU());
+
+ // Test computation of only T, not U
+ ComplexSchur<MatrixType> csOnlyT(A, false);
+ VERIFY_IS_EQUAL(csOnlyT.info(), Success);
+ VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT());
+ VERIFY_RAISES_ASSERT(csOnlyT.matrixU());
+
+ if (size > 1)
+ {
+ // Test matrix with NaN
+ A(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
+ ComplexSchur<MatrixType> csNaN(A);
+ VERIFY_IS_EQUAL(csNaN.info(), NoConvergence);
+ }
+}
+
+void test_schur_complex()
+{
+ CALL_SUBTEST_1(( schur<Matrix4cd>() ));
+ CALL_SUBTEST_2(( schur<MatrixXcf>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4)) ));
+ CALL_SUBTEST_3(( schur<Matrix<std::complex<float>, 1, 1> >() ));
+ CALL_SUBTEST_4(( schur<Matrix<float, 3, 3, Eigen::RowMajor> >() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(ComplexSchur<MatrixXf>(10));
+}
diff --git a/test/schur_real.cpp b/test/schur_real.cpp
new file mode 100644
index 000000000..e6351d94a
--- /dev/null
+++ b/test/schur_real.cpp
@@ -0,0 +1,93 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
+//
+// 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/.
+
+#include "main.h"
+#include <limits>
+#include <Eigen/Eigenvalues>
+
+template<typename MatrixType> void verifyIsQuasiTriangular(const MatrixType& T)
+{
+ typedef typename MatrixType::Index Index;
+
+ const Index size = T.cols();
+ typedef typename MatrixType::Scalar Scalar;
+
+ // Check T is lower Hessenberg
+ for(int row = 2; row < size; ++row) {
+ for(int col = 0; col < row - 1; ++col) {
+ VERIFY(T(row,col) == Scalar(0));
+ }
+ }
+
+ // Check that any non-zero on the subdiagonal is followed by a zero and is
+ // part of a 2x2 diagonal block with imaginary eigenvalues.
+ for(int row = 1; row < size; ++row) {
+ if (T(row,row-1) != Scalar(0)) {
+ VERIFY(row == size-1 || T(row+1,row) == 0);
+ Scalar tr = T(row-1,row-1) + T(row,row);
+ Scalar det = T(row-1,row-1) * T(row,row) - T(row-1,row) * T(row,row-1);
+ VERIFY(4 * det > tr * tr);
+ }
+ }
+}
+
+template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime)
+{
+ // Test basic functionality: T is quasi-triangular and A = U T U*
+ for(int counter = 0; counter < g_repeat; ++counter) {
+ MatrixType A = MatrixType::Random(size, size);
+ RealSchur<MatrixType> schurOfA(A);
+ VERIFY_IS_EQUAL(schurOfA.info(), Success);
+ MatrixType U = schurOfA.matrixU();
+ MatrixType T = schurOfA.matrixT();
+ verifyIsQuasiTriangular(T);
+ VERIFY_IS_APPROX(A, U * T * U.transpose());
+ }
+
+ // Test asserts when not initialized
+ RealSchur<MatrixType> rsUninitialized;
+ VERIFY_RAISES_ASSERT(rsUninitialized.matrixT());
+ VERIFY_RAISES_ASSERT(rsUninitialized.matrixU());
+ VERIFY_RAISES_ASSERT(rsUninitialized.info());
+
+ // Test whether compute() and constructor returns same result
+ MatrixType A = MatrixType::Random(size, size);
+ RealSchur<MatrixType> rs1;
+ rs1.compute(A);
+ RealSchur<MatrixType> rs2(A);
+ VERIFY_IS_EQUAL(rs1.info(), Success);
+ VERIFY_IS_EQUAL(rs2.info(), Success);
+ VERIFY_IS_EQUAL(rs1.matrixT(), rs2.matrixT());
+ VERIFY_IS_EQUAL(rs1.matrixU(), rs2.matrixU());
+
+ // Test computation of only T, not U
+ RealSchur<MatrixType> rsOnlyT(A, false);
+ VERIFY_IS_EQUAL(rsOnlyT.info(), Success);
+ VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT());
+ VERIFY_RAISES_ASSERT(rsOnlyT.matrixU());
+
+ if (size > 2)
+ {
+ // Test matrix with NaN
+ A(0,0) = std::numeric_limits<typename MatrixType::Scalar>::quiet_NaN();
+ RealSchur<MatrixType> rsNaN(A);
+ VERIFY_IS_EQUAL(rsNaN.info(), NoConvergence);
+ }
+}
+
+void test_schur_real()
+{
+ CALL_SUBTEST_1(( schur<Matrix4f>() ));
+ CALL_SUBTEST_2(( schur<MatrixXd>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE/4)) ));
+ CALL_SUBTEST_3(( schur<Matrix<float, 1, 1> >() ));
+ CALL_SUBTEST_4(( schur<Matrix<double, 3, 3, Eigen::RowMajor> >() ));
+
+ // Test problem size constructors
+ CALL_SUBTEST_5(RealSchur<MatrixXf>(10));
+}
diff --git a/test/selfadjoint.cpp b/test/selfadjoint.cpp
new file mode 100644
index 000000000..6d3ec6536
--- /dev/null
+++ b/test/selfadjoint.cpp
@@ -0,0 +1,62 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 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/.
+
+#include "main.h"
+
+// This file tests the basic selfadjointView API,
+// the related products and decompositions are tested in specific files.
+
+template<typename MatrixType> void selfadjoint(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m3(rows, cols);
+
+ m1.diagonal() = m1.diagonal().real().template cast<Scalar>();
+
+ // check selfadjoint to dense
+ m3 = m1.template selfadjointView<Upper>();
+ VERIFY_IS_APPROX(MatrixType(m3.template triangularView<Upper>()), MatrixType(m1.template triangularView<Upper>()));
+ VERIFY_IS_APPROX(m3, m3.adjoint());
+
+
+ m3 = m1.template selfadjointView<Lower>();
+ VERIFY_IS_APPROX(MatrixType(m3.template triangularView<Lower>()), MatrixType(m1.template triangularView<Lower>()));
+ VERIFY_IS_APPROX(m3, m3.adjoint());
+}
+
+void bug_159()
+{
+ Matrix3d m = Matrix3d::Random().selfadjointView<Lower>();
+ EIGEN_UNUSED_VARIABLE(m)
+}
+
+void test_selfadjoint()
+{
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ int s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE); EIGEN_UNUSED_VARIABLE(s);
+
+ CALL_SUBTEST_1( selfadjoint(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( selfadjoint(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( selfadjoint(Matrix3cf()) );
+ CALL_SUBTEST_4( selfadjoint(MatrixXcd(s,s)) );
+ CALL_SUBTEST_5( selfadjoint(Matrix<float,Dynamic,Dynamic,RowMajor>(s, s)) );
+
+ EIGEN_UNUSED_VARIABLE(s)
+ }
+
+ CALL_SUBTEST_1( bug_159() );
+}
diff --git a/test/simplicial_cholesky.cpp b/test/simplicial_cholesky.cpp
new file mode 100644
index 000000000..e93a52e9c
--- /dev/null
+++ b/test/simplicial_cholesky.cpp
@@ -0,0 +1,40 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse_solver.h"
+
+template<typename T> void test_simplicial_cholesky_T()
+{
+ SimplicialCholesky<SparseMatrix<T>, Lower> chol_colmajor_lower;
+ SimplicialCholesky<SparseMatrix<T>, Upper> chol_colmajor_upper;
+ SimplicialLLT<SparseMatrix<T>, Lower> llt_colmajor_lower;
+ SimplicialLDLT<SparseMatrix<T>, Upper> llt_colmajor_upper;
+ SimplicialLDLT<SparseMatrix<T>, Lower> ldlt_colmajor_lower;
+ SimplicialLDLT<SparseMatrix<T>, Upper> ldlt_colmajor_upper;
+
+ check_sparse_spd_solving(chol_colmajor_lower);
+ check_sparse_spd_solving(chol_colmajor_upper);
+ check_sparse_spd_solving(llt_colmajor_lower);
+ check_sparse_spd_solving(llt_colmajor_upper);
+ check_sparse_spd_solving(ldlt_colmajor_lower);
+ check_sparse_spd_solving(ldlt_colmajor_upper);
+
+ check_sparse_spd_determinant(chol_colmajor_lower);
+ check_sparse_spd_determinant(chol_colmajor_upper);
+ check_sparse_spd_determinant(llt_colmajor_lower);
+ check_sparse_spd_determinant(llt_colmajor_upper);
+ check_sparse_spd_determinant(ldlt_colmajor_lower);
+ check_sparse_spd_determinant(ldlt_colmajor_upper);
+}
+
+void test_simplicial_cholesky()
+{
+ CALL_SUBTEST_1(test_simplicial_cholesky_T<double>());
+ CALL_SUBTEST_2(test_simplicial_cholesky_T<std::complex<double> >());
+}
diff --git a/test/sizeof.cpp b/test/sizeof.cpp
new file mode 100644
index 000000000..68463c9b6
--- /dev/null
+++ b/test/sizeof.cpp
@@ -0,0 +1,34 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void verifySizeOf(const MatrixType&)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ if (MatrixType::RowsAtCompileTime!=Dynamic && MatrixType::ColsAtCompileTime!=Dynamic)
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar)*size_t(MatrixType::SizeAtCompileTime));
+ else
+ VERIFY(sizeof(MatrixType)==sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index));
+}
+
+void test_sizeof()
+{
+ CALL_SUBTEST(verifySizeOf(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST(verifySizeOf(Matrix4d()) );
+ CALL_SUBTEST(verifySizeOf(Matrix<double, 4, 2>()) );
+ CALL_SUBTEST(verifySizeOf(Matrix<bool, 7, 5>()) );
+ CALL_SUBTEST(verifySizeOf(MatrixXcf(3, 3)) );
+ CALL_SUBTEST(verifySizeOf(MatrixXi(8, 12)) );
+ CALL_SUBTEST(verifySizeOf(MatrixXcd(20, 20)) );
+ CALL_SUBTEST(verifySizeOf(Matrix<float, 100, 100>()) );
+
+ VERIFY(sizeof(std::complex<float>) == 2*sizeof(float));
+ VERIFY(sizeof(std::complex<double>) == 2*sizeof(double));
+}
diff --git a/test/sizeoverflow.cpp b/test/sizeoverflow.cpp
new file mode 100644
index 000000000..16d6f8d04
--- /dev/null
+++ b/test/sizeoverflow.cpp
@@ -0,0 +1,66 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+#include "main.h"
+
+#define VERIFY_THROWS_BADALLOC(a) { \
+ bool threw = false; \
+ try { \
+ a; \
+ } \
+ catch (std::bad_alloc&) { threw = true; } \
+ VERIFY(threw && "should have thrown bad_alloc: " #a); \
+ }
+
+typedef DenseIndex Index;
+
+template<typename MatrixType>
+void triggerMatrixBadAlloc(Index rows, Index cols)
+{
+ VERIFY_THROWS_BADALLOC( MatrixType m(rows, cols) );
+ VERIFY_THROWS_BADALLOC( MatrixType m; m.resize(rows, cols) );
+ VERIFY_THROWS_BADALLOC( MatrixType m; m.conservativeResize(rows, cols) );
+}
+
+template<typename VectorType>
+void triggerVectorBadAlloc(Index size)
+{
+ VERIFY_THROWS_BADALLOC( VectorType v(size) );
+ VERIFY_THROWS_BADALLOC( VectorType v; v.resize(size) );
+ VERIFY_THROWS_BADALLOC( VectorType v; v.conservativeResize(size) );
+}
+
+void test_sizeoverflow()
+{
+ // there are 2 levels of overflow checking. first in PlainObjectBase.h we check for overflow in rows*cols computations.
+ // this is tested in tests of the form times_itself_gives_0 * times_itself_gives_0
+ // Then in Memory.h we check for overflow in size * sizeof(T) computations.
+ // this is tested in tests of the form times_4_gives_0 * sizeof(float)
+
+ size_t times_itself_gives_0 = size_t(1) << (8 * sizeof(Index) / 2);
+ VERIFY(times_itself_gives_0 * times_itself_gives_0 == 0);
+
+ size_t times_4_gives_0 = size_t(1) << (8 * sizeof(Index) - 2);
+ VERIFY(times_4_gives_0 * 4 == 0);
+
+ size_t times_8_gives_0 = size_t(1) << (8 * sizeof(Index) - 3);
+ VERIFY(times_8_gives_0 * 8 == 0);
+
+ triggerMatrixBadAlloc<MatrixXf>(times_itself_gives_0, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXf>(times_itself_gives_0 / 4, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXf>(times_4_gives_0, 1);
+
+ triggerMatrixBadAlloc<MatrixXd>(times_itself_gives_0, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXd>(times_itself_gives_0 / 8, times_itself_gives_0);
+ triggerMatrixBadAlloc<MatrixXd>(times_8_gives_0, 1);
+
+ triggerVectorBadAlloc<VectorXf>(times_4_gives_0);
+
+ triggerVectorBadAlloc<VectorXd>(times_8_gives_0);
+}
diff --git a/test/smallvectors.cpp b/test/smallvectors.cpp
new file mode 100644
index 000000000..781511397
--- /dev/null
+++ b/test/smallvectors.cpp
@@ -0,0 +1,67 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2006-2008 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+
+template<typename Scalar> void smallVectors()
+{
+ typedef Matrix<Scalar, 1, 2> V2;
+ typedef Matrix<Scalar, 3, 1> V3;
+ typedef Matrix<Scalar, 1, 4> V4;
+ typedef Matrix<Scalar, Dynamic, 1> VX;
+ Scalar x1 = internal::random<Scalar>(),
+ x2 = internal::random<Scalar>(),
+ x3 = internal::random<Scalar>(),
+ x4 = internal::random<Scalar>();
+ V2 v2(x1, x2);
+ V3 v3(x1, x2, x3);
+ V4 v4(x1, x2, x3, x4);
+ VERIFY_IS_APPROX(x1, v2.x());
+ VERIFY_IS_APPROX(x1, v3.x());
+ VERIFY_IS_APPROX(x1, v4.x());
+ VERIFY_IS_APPROX(x2, v2.y());
+ VERIFY_IS_APPROX(x2, v3.y());
+ VERIFY_IS_APPROX(x2, v4.y());
+ VERIFY_IS_APPROX(x3, v3.z());
+ VERIFY_IS_APPROX(x3, v4.z());
+ VERIFY_IS_APPROX(x4, v4.w());
+
+ if (!NumTraits<Scalar>::IsInteger)
+ {
+ VERIFY_RAISES_ASSERT(V3(2, 1))
+ VERIFY_RAISES_ASSERT(V3(3, 2))
+ VERIFY_RAISES_ASSERT(V3(Scalar(3), 1))
+ VERIFY_RAISES_ASSERT(V3(3, Scalar(1)))
+ VERIFY_RAISES_ASSERT(V3(Scalar(3), Scalar(1)))
+ VERIFY_RAISES_ASSERT(V3(Scalar(123), Scalar(123)))
+
+ VERIFY_RAISES_ASSERT(V4(1, 3))
+ VERIFY_RAISES_ASSERT(V4(2, 4))
+ VERIFY_RAISES_ASSERT(V4(1, Scalar(4)))
+ VERIFY_RAISES_ASSERT(V4(Scalar(1), 4))
+ VERIFY_RAISES_ASSERT(V4(Scalar(1), Scalar(4)))
+ VERIFY_RAISES_ASSERT(V4(Scalar(123), Scalar(123)))
+
+ VERIFY_RAISES_ASSERT(VX(3, 2))
+ VERIFY_RAISES_ASSERT(VX(Scalar(3), 1))
+ VERIFY_RAISES_ASSERT(VX(3, Scalar(1)))
+ VERIFY_RAISES_ASSERT(VX(Scalar(3), Scalar(1)))
+ VERIFY_RAISES_ASSERT(VX(Scalar(123), Scalar(123)))
+ }
+}
+
+void test_smallvectors()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST(smallVectors<int>() );
+ CALL_SUBTEST(smallVectors<float>() );
+ CALL_SUBTEST(smallVectors<double>() );
+ }
+}
diff --git a/test/sparse.h b/test/sparse.h
new file mode 100644
index 000000000..4db0004aa
--- /dev/null
+++ b/test/sparse.h
@@ -0,0 +1,182 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 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/.
+
+#ifndef EIGEN_TESTSPARSE_H
+#define EIGEN_TESTSPARSE_H
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+
+#include "main.h"
+
+#if EIGEN_GNUC_AT_LEAST(4,0) && !defined __ICC && !defined(__clang__)
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef max
+#undef max
+#endif
+
+#include <tr1/unordered_map>
+#define EIGEN_UNORDERED_MAP_SUPPORT
+namespace std {
+ using std::tr1::unordered_map;
+}
+#endif
+
+#ifdef EIGEN_GOOGLEHASH_SUPPORT
+ #include <google/sparse_hash_map>
+#endif
+
+#include <Eigen/Cholesky>
+#include <Eigen/LU>
+#include <Eigen/Sparse>
+
+enum {
+ ForceNonZeroDiag = 1,
+ MakeLowerTriangular = 2,
+ MakeUpperTriangular = 4,
+ ForceRealDiag = 8
+};
+
+/* Initializes both a sparse and dense matrix with same random values,
+ * and a ratio of \a density non zero entries.
+ * \param flags is a union of ForceNonZeroDiag, MakeLowerTriangular and MakeUpperTriangular
+ * allowing to control the shape of the matrix.
+ * \param zeroCoords and nonzeroCoords allows to get the coordinate lists of the non zero,
+ * and zero coefficients respectively.
+ */
+template<typename Scalar,int Opt1,int Opt2,typename Index> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic,Opt1>& refMat,
+ SparseMatrix<Scalar,Opt2,Index>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ enum { IsRowMajor = SparseMatrix<Scalar,Opt2,Index>::IsRowMajor };
+ sparseMat.setZero();
+ //sparseMat.reserve(int(refMat.rows()*refMat.cols()*density));
+ sparseMat.reserve(VectorXi::Constant(IsRowMajor ? refMat.rows() : refMat.cols(), int((1.5*density)*(IsRowMajor?refMat.cols():refMat.rows()))));
+
+ for(int j=0; j<sparseMat.outerSize(); j++)
+ {
+ //sparseMat.startVec(j);
+ for(int i=0; i<sparseMat.innerSize(); i++)
+ {
+ int ai(i), aj(j);
+ if(IsRowMajor)
+ std::swap(ai,aj);
+ Scalar v = (internal::random<double>(0,1) < density) ? internal::random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = internal::random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && aj>ai)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && aj<ai)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = internal::real(v);
+
+ if (v!=Scalar(0))
+ {
+ //sparseMat.insertBackByOuterInner(j,i) = v;
+ sparseMat.insertByOuterInner(j,i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(ai,aj));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(ai,aj));
+ }
+ refMat(ai,aj) = v;
+ }
+ }
+ //sparseMat.finalize();
+}
+
+template<typename Scalar,int Opt1,int Opt2,typename Index> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,Dynamic, Opt1>& refMat,
+ DynamicSparseMatrix<Scalar, Opt2, Index>& sparseMat,
+ int flags = 0,
+ std::vector<Vector2i>* zeroCoords = 0,
+ std::vector<Vector2i>* nonzeroCoords = 0)
+{
+ enum { IsRowMajor = DynamicSparseMatrix<Scalar,Opt2,Index>::IsRowMajor };
+ sparseMat.setZero();
+ sparseMat.reserve(int(refMat.rows()*refMat.cols()*density));
+ for(int j=0; j<sparseMat.outerSize(); j++)
+ {
+ sparseMat.startVec(j); // not needed for DynamicSparseMatrix
+ for(int i=0; i<sparseMat.innerSize(); i++)
+ {
+ int ai(i), aj(j);
+ if(IsRowMajor)
+ std::swap(ai,aj);
+ Scalar v = (internal::random<double>(0,1) < density) ? internal::random<Scalar>() : Scalar(0);
+ if ((flags&ForceNonZeroDiag) && (i==j))
+ {
+ v = internal::random<Scalar>()*Scalar(3.);
+ v = v*v + Scalar(5.);
+ }
+ if ((flags & MakeLowerTriangular) && aj>ai)
+ v = Scalar(0);
+ else if ((flags & MakeUpperTriangular) && aj<ai)
+ v = Scalar(0);
+
+ if ((flags&ForceRealDiag) && (i==j))
+ v = internal::real(v);
+
+ if (v!=Scalar(0))
+ {
+ sparseMat.insertBackByOuterInner(j,i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(Vector2i(ai,aj));
+ }
+ else if (zeroCoords)
+ {
+ zeroCoords->push_back(Vector2i(ai,aj));
+ }
+ refMat(ai,aj) = v;
+ }
+ }
+ sparseMat.finalize();
+}
+
+template<typename Scalar> void
+initSparse(double density,
+ Matrix<Scalar,Dynamic,1>& refVec,
+ SparseVector<Scalar>& sparseVec,
+ std::vector<int>* zeroCoords = 0,
+ std::vector<int>* nonzeroCoords = 0)
+{
+ sparseVec.reserve(int(refVec.size()*density));
+ sparseVec.setZero();
+ for(int i=0; i<refVec.size(); i++)
+ {
+ Scalar v = (internal::random<double>(0,1) < density) ? internal::random<Scalar>() : Scalar(0);
+ if (v!=Scalar(0))
+ {
+ sparseVec.insertBack(i) = v;
+ if (nonzeroCoords)
+ nonzeroCoords->push_back(i);
+ }
+ else if (zeroCoords)
+ zeroCoords->push_back(i);
+ refVec[i] = v;
+ }
+}
+
+#include <unsupported/Eigen/SparseExtra>
+#endif // EIGEN_TESTSPARSE_H
diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp
new file mode 100644
index 000000000..8897a9dca
--- /dev/null
+++ b/test/sparse_basic.cpp
@@ -0,0 +1,395 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@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/.
+
+#include "sparse.h"
+
+template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
+{
+ typedef typename SparseMatrixType::Index Index;
+
+ const Index rows = ref.rows();
+ const Index cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m(rows, cols);
+ DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
+ DenseVector vec1 = DenseVector::Random(rows);
+ Scalar s1 = internal::random<Scalar>();
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> 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)
+ {
+ 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_IS_APPROX(m, refMat);
+
+ 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)
+ {
+ int j = internal::random<int>(0,cols-1);
+ int i = internal::random<int>(0,rows-1);
+ 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));
+ 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));
+ }
+ }
+// 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 c=0; c<cols; c++)
+ {
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
+ VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
+ }
+
+ for(int r=0; r<rows; r++)
+ {
+ 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 insert (inner random)
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ if(internal::random<int>()%2)
+ m2.reserve(VectorXi::Constant(m2.outerSize(), 2));
+ for (int j=0; j<cols; ++j)
+ {
+ for (int k=0; k<rows/2; ++k)
+ {
+ int i = internal::random<int>(0,rows-1);
+ if (m1.coeff(i,j)==Scalar(0))
+ m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
+ }
+ }
+ m2.finalize();
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test insert (fully random)
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ if(internal::random<int>()%2)
+ m2.reserve(VectorXi::Constant(m2.outerSize(), 2));
+ for (int k=0; k<rows*cols; ++k)
+ {
+ int i = internal::random<int>(0,rows-1);
+ int j = internal::random<int>(0,cols-1);
+ if ((m1.coeff(i,j)==Scalar(0)) && (internal::random<int>()%2))
+ m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
+ else
+ {
+ Scalar v = internal::random<Scalar>();
+ m2.coeffRef(i,j) += v;
+ m1(i,j) += v;
+ }
+ }
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // test insert (un-compressed)
+ for(int mode=0;mode<4;++mode)
+ {
+ DenseMatrix m1(rows,cols);
+ m1.setZero();
+ SparseMatrixType m2(rows,cols);
+ VectorXi r(VectorXi::Constant(m2.outerSize(), ((mode%2)==0) ? m2.innerSize() : std::max<int>(1,m2.innerSize()/8)));
+ m2.reserve(r);
+ for (int k=0; k<rows*cols; ++k)
+ {
+ int i = internal::random<int>(0,rows-1);
+ int j = internal::random<int>(0,cols-1);
+ if (m1.coeff(i,j)==Scalar(0))
+ m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
+ if(mode==3)
+ m2.reserve(r);
+ }
+ if(internal::random<int>()%2)
+ m2.makeCompressed();
+ VERIFY_IS_APPROX(m2,m1);
+ }
+
+ // 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);
+ initSparse<Scalar>(density, refM1, m1);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ initSparse<Scalar>(density, refM4, m4);
+
+ 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));
+ VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);
+
+ VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
+ VERIFY_IS_APPROX(m1/=s1, refM1/=s1);
+
+ VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
+ VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
+
+ 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.conjugate(), refM1.conjugate());
+ VERIFY_IS_APPROX(m1.real(), refM1.real());
+
+ refM4.setRandom();
+ // sparse cwise* dense
+ VERIFY_IS_APPROX(m3.cwiseProduct(refM4), refM3.cwiseProduct(refM4));
+// VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
+ }
+
+ // test transpose
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ 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());
+ }
+
+ // test innerVector()
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = internal::random<int>(0,rows-1);
+ int j1 = internal::random<int>(0,rows-1);
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.row(j0));
+ else
+ VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
+
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.row(j0)+refMat2.row(j1));
+ 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,rows/2));
+ for(int j=0; j<rows; ++j)
+ for(int k=0; k<j; ++k)
+ m3.insertByOuterInner(j,k) = k+1;
+ for(int j=0; j<rows; ++j)
+ {
+ VERIFY(j==internal::real(m3.innerVector(j).nonZeros()));
+ if(j>0)
+ VERIFY(j==internal::real(m3.innerVector(j).lastCoeff()));
+ }
+ m3.makeCompressed();
+ for(int j=0; j<rows; ++j)
+ {
+ VERIFY(j==internal::real(m3.innerVector(j).nonZeros()));
+ if(j>0)
+ VERIFY(j==internal::real(m3.innerVector(j).lastCoeff()));
+ }
+
+ //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);
+ initSparse<Scalar>(density, refMat2, m2);
+ int j0 = internal::random<int>(0,rows-2);
+ int j1 = internal::random<int>(0,rows-2);
+ int n0 = internal::random<int>(1,rows-(std::max)(j0,j1));
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(j0,0,n0,cols));
+ else
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
+ if(SparseMatrixType::IsRowMajor)
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
+ refMat2.block(j0,0,n0,cols)+refMat2.block(j1,0,n0,cols));
+ else
+ VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
+ refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
+ //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
+ //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
+ }
+
+ // test prune
+ {
+ SparseMatrixType m2(rows, rows);
+ DenseMatrix refM2(rows, rows);
+ refM2.setZero();
+ int countFalseNonZero = 0;
+ int countTrueNonZero = 0;
+ for (int j=0; j<m2.outerSize(); ++j)
+ {
+ m2.startVec(j);
+ for (int i=0; i<m2.innerSize(); ++i)
+ {
+ float x = internal::random<float>(0,1);
+ if (x<0.1)
+ {
+ // do nothing
+ }
+ else if (x<0.5)
+ {
+ countFalseNonZero++;
+ m2.insertBackByOuterInner(j,i) = Scalar(0);
+ }
+ else
+ {
+ countTrueNonZero++;
+ m2.insertBackByOuterInner(j,i) = Scalar(1);
+ if(SparseMatrixType::IsRowMajor)
+ refM2(j,i) = Scalar(1);
+ else
+ refM2(i,j) = Scalar(1);
+ }
+ }
+ }
+ m2.finalize();
+ VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ m2.prune(Scalar(1));
+ VERIFY(countTrueNonZero==m2.nonZeros());
+ VERIFY_IS_APPROX(m2, refM2);
+ }
+
+ // test setFromTriplets
+ {
+ typedef Triplet<Scalar,Index> TripletType;
+ std::vector<TripletType> triplets;
+ int ntriplets = rows*cols;
+ triplets.reserve(ntriplets);
+ DenseMatrix refMat(rows,cols);
+ refMat.setZero();
+ for(int i=0;i<ntriplets;++i)
+ {
+ int r = internal::random<int>(0,rows-1);
+ int c = internal::random<int>(0,cols-1);
+ Scalar v = internal::random<Scalar>();
+ triplets.push_back(TripletType(r,c,v));
+ refMat(r,c) += v;
+ }
+ SparseMatrixType m(rows,cols);
+ m.setFromTriplets(triplets.begin(), triplets.end());
+ VERIFY_IS_APPROX(m, refMat);
+ }
+
+ // test triangularView
+ {
+ DenseMatrix refMat2(rows, rows), refMat3(rows, rows);
+ SparseMatrixType m2(rows, rows), m3(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ refMat3 = refMat2.template triangularView<Lower>();
+ m3 = m2.template triangularView<Lower>();
+ VERIFY_IS_APPROX(m3, refMat3);
+
+ refMat3 = refMat2.template triangularView<Upper>();
+ 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);
+
+ refMat3 = refMat2.template triangularView<UnitLower>();
+ m3 = m2.template triangularView<UnitLower>();
+ VERIFY_IS_APPROX(m3, refMat3);
+ }
+
+ // test selfadjointView
+ if(!SparseMatrixType::IsRowMajor)
+ {
+ DenseMatrix refMat2(rows, rows), refMat3(rows, rows);
+ SparseMatrixType m2(rows, rows), m3(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ refMat3 = refMat2.template selfadjointView<Lower>();
+ m3 = m2.template selfadjointView<Lower>();
+ VERIFY_IS_APPROX(m3, refMat3);
+ }
+
+ // test sparseView
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.eval(), refMat2.sparseView().eval());
+ }
+
+ // test diagonal
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType m2(rows, rows);
+ initSparse<Scalar>(density, refMat2, m2);
+ VERIFY_IS_APPROX(m2.diagonal(), refMat2.diagonal().eval());
+ }
+}
+
+void test_sparse_basic()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ int s = Eigen::internal::random<int>(1,50);
+ 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)) ));
+ }
+}
diff --git a/test/sparse_permutations.cpp b/test/sparse_permutations.cpp
new file mode 100644
index 000000000..e4ce1d679
--- /dev/null
+++ b/test/sparse_permutations.cpp
@@ -0,0 +1,187 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+#include "sparse.h"
+
+template<int OtherStorage, typename SparseMatrixType> void sparse_permutations(const SparseMatrixType& ref)
+{
+ typedef typename SparseMatrixType::Index Index;
+
+ const Index rows = ref.rows();
+ const Index cols = ref.cols();
+ typedef typename SparseMatrixType::Scalar Scalar;
+ typedef typename SparseMatrixType::Index Index;
+ typedef SparseMatrix<Scalar, OtherStorage, Index> OtherSparseMatrixType;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Index,Dynamic,1> VectorI;
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+
+ SparseMatrixType mat(rows, cols), up(rows,cols), lo(rows,cols);
+ OtherSparseMatrixType res;
+ DenseMatrix mat_d = DenseMatrix::Zero(rows, cols), up_sym_d, lo_sym_d, res_d;
+
+ initSparse<Scalar>(density, mat_d, mat, 0);
+
+ up = mat.template triangularView<Upper>();
+ lo = mat.template triangularView<Lower>();
+
+ up_sym_d = mat_d.template selfadjointView<Upper>();
+ lo_sym_d = mat_d.template selfadjointView<Lower>();
+
+ VERIFY_IS_APPROX(mat, mat_d);
+ VERIFY_IS_APPROX(up, DenseMatrix(mat_d.template triangularView<Upper>()));
+ VERIFY_IS_APPROX(lo, DenseMatrix(mat_d.template triangularView<Lower>()));
+
+ PermutationMatrix<Dynamic> p, p_null;
+ VectorI pi;
+ randomPermutationVector(pi, cols);
+ p.indices() = pi;
+
+ res = mat*p;
+ res_d = mat_d*p;
+ VERIFY(res.isApprox(res_d) && "mat*p");
+
+ res = p*mat;
+ res_d = p*mat_d;
+ VERIFY(res.isApprox(res_d) && "p*mat");
+
+ res = mat*p.inverse();
+ res_d = mat*p.inverse();
+ VERIFY(res.isApprox(res_d) && "mat*inv(p)");
+
+ res = p.inverse()*mat;
+ res_d = p.inverse()*mat_d;
+ VERIFY(res.isApprox(res_d) && "inv(p)*mat");
+
+ res = mat.twistedBy(p);
+ res_d = (p * mat_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "p*mat*inv(p)");
+
+
+ res = mat.template selfadjointView<Upper>().twistedBy(p_null);
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to full");
+
+ res = mat.template selfadjointView<Lower>().twistedBy(p_null);
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to full");
+
+
+ res = up.template selfadjointView<Upper>().twistedBy(p_null);
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint to full");
+
+ res = lo.template selfadjointView<Lower>().twistedBy(p_null);
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint full");
+
+
+ res = mat.template selfadjointView<Upper>();
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to full");
+
+ res = mat.template selfadjointView<Lower>();
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to full");
+
+ res = up.template selfadjointView<Upper>();
+ res_d = up_sym_d;
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint to full");
+
+ res = lo.template selfadjointView<Lower>();
+ res_d = lo_sym_d;
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint full");
+
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Upper>();
+ res_d = up_sym_d.template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to upper");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Upper>();
+ res_d = up_sym_d.template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper to lower");
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Lower>();
+ res_d = lo_sym_d.template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to upper");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Lower>();
+ res_d = lo_sym_d.template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower to lower");
+
+
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to upper");
+
+ res.template selfadjointView<Upper>() = mat.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to upper");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to lower");
+
+ res.template selfadjointView<Lower>() = mat.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to lower");
+
+
+ res.template selfadjointView<Upper>() = up.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to upper");
+
+ res.template selfadjointView<Upper>() = lo.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Upper>();
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to upper");
+
+ res.template selfadjointView<Lower>() = lo.template selfadjointView<Lower>().twistedBy(p);
+ res_d = ((p * lo_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to lower");
+
+ res.template selfadjointView<Lower>() = up.template selfadjointView<Upper>().twistedBy(p);
+ res_d = ((p * up_sym_d) * p.inverse()).eval().template triangularView<Lower>();
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to lower");
+
+
+ res = mat.template selfadjointView<Upper>().twistedBy(p);
+ res_d = (p * up_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to full");
+
+ res = mat.template selfadjointView<Lower>().twistedBy(p);
+ res_d = (p * lo_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to full");
+
+ res = up.template selfadjointView<Upper>().twistedBy(p);
+ res_d = (p * up_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to full");
+
+ res = lo.template selfadjointView<Lower>().twistedBy(p);
+ res_d = (p * lo_sym_d) * p.inverse();
+ VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to full");
+}
+
+template<typename Scalar> void sparse_permutations_all(int size)
+{
+ CALL_SUBTEST(( sparse_permutations<ColMajor>(SparseMatrix<Scalar, ColMajor>(size,size)) ));
+ CALL_SUBTEST(( sparse_permutations<ColMajor>(SparseMatrix<Scalar, RowMajor>(size,size)) ));
+ CALL_SUBTEST(( sparse_permutations<RowMajor>(SparseMatrix<Scalar, ColMajor>(size,size)) ));
+ CALL_SUBTEST(( sparse_permutations<RowMajor>(SparseMatrix<Scalar, RowMajor>(size,size)) ));
+}
+
+void test_sparse_permutations()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ int s = Eigen::internal::random<int>(1,50);
+ CALL_SUBTEST_1(( sparse_permutations_all<double>(s) ));
+ CALL_SUBTEST_2(( sparse_permutations_all<std::complex<double> >(s) ));
+ }
+}
diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp
new file mode 100644
index 000000000..17a955c9d
--- /dev/null
+++ b/test/sparse_product.cpp
@@ -0,0 +1,204 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 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/.
+
+#include "sparse.h"
+
+template<typename SparseMatrixType, typename DenseMatrix, bool IsRowMajor=SparseMatrixType::IsRowMajor> struct test_outer;
+
+template<typename SparseMatrixType, typename DenseMatrix> struct test_outer<SparseMatrixType,DenseMatrix,false> {
+ static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) {
+ int c = internal::random(0,m2.cols()-1);
+ int c1 = internal::random(0,m2.cols()-1);
+ VERIFY_IS_APPROX(m4=m2.col(c)*refMat2.col(c1).transpose(), refMat4=refMat2.col(c)*refMat2.col(c1).transpose());
+ VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.col(c).transpose(), refMat4=refMat2.col(c1)*refMat2.col(c).transpose());
+ }
+};
+
+template<typename SparseMatrixType, typename DenseMatrix> struct test_outer<SparseMatrixType,DenseMatrix,true> {
+ static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) {
+ int r = internal::random(0,m2.rows()-1);
+ int c1 = internal::random(0,m2.cols()-1);
+ VERIFY_IS_APPROX(m4=m2.row(r).transpose()*refMat2.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*refMat2.col(c1).transpose());
+ VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.row(r), refMat4=refMat2.col(c1)*refMat2.row(r));
+ }
+};
+
+// (m2,m4,refMat2,refMat4,dv1);
+// VERIFY_IS_APPROX(m4=m2.innerVector(c)*dv1.transpose(), refMat4=refMat2.colVector(c)*dv1.transpose());
+// VERIFY_IS_APPROX(m4=dv1*mcm.col(c).transpose(), refMat4=dv1*refMat2.col(c).transpose());
+
+template<typename SparseMatrixType> void sparse_product()
+{
+ typedef typename SparseMatrixType::Index Index;
+ Index n = 100;
+ const Index rows = internal::random<int>(1,n);
+ const Index cols = internal::random<int>(1,n);
+ const Index depth = internal::random<int>(1,n);
+ typedef typename SparseMatrixType::Scalar Scalar;
+ enum { Flags = SparseMatrixType::Flags };
+
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ Scalar s1 = internal::random<Scalar>();
+ Scalar s2 = internal::random<Scalar>();
+
+ // test matrix-matrix product
+ {
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, depth);
+ DenseMatrix refMat2t = DenseMatrix::Zero(depth, rows);
+ DenseMatrix refMat3 = DenseMatrix::Zero(depth, cols);
+ DenseMatrix refMat3t = DenseMatrix::Zero(cols, depth);
+ DenseMatrix refMat4 = DenseMatrix::Zero(rows, cols);
+ DenseMatrix refMat4t = DenseMatrix::Zero(cols, rows);
+ DenseMatrix refMat5 = DenseMatrix::Random(depth, cols);
+ DenseMatrix refMat6 = DenseMatrix::Random(rows, rows);
+ DenseMatrix dm4 = DenseMatrix::Zero(rows, rows);
+// DenseVector dv1 = DenseVector::Random(rows);
+ SparseMatrixType m2 (rows, depth);
+ SparseMatrixType m2t(depth, rows);
+ SparseMatrixType m3 (depth, cols);
+ SparseMatrixType m3t(cols, depth);
+ SparseMatrixType m4 (rows, cols);
+ SparseMatrixType m4t(cols, rows);
+ SparseMatrixType m6(rows, rows);
+ initSparse(density, refMat2, m2);
+ initSparse(density, refMat2t, m2t);
+ initSparse(density, refMat3, m3);
+ initSparse(density, refMat3t, m3t);
+ initSparse(density, refMat4, m4);
+ initSparse(density, refMat4t, m4t);
+ initSparse(density, refMat6, m6);
+
+// int c = internal::random<int>(0,depth-1);
+
+ // sparse * sparse
+ VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(m4=m2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3);
+ VERIFY_IS_APPROX(m4=m2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose());
+ VERIFY_IS_APPROX(m4=m2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose());
+
+ VERIFY_IS_APPROX(m4 = m2*m3/s1, refMat4 = refMat2*refMat3/s1);
+ VERIFY_IS_APPROX(m4 = m2*m3*s1, refMat4 = refMat2*refMat3*s1);
+ VERIFY_IS_APPROX(m4 = s2*m2*m3*s1, refMat4 = s2*refMat2*refMat3*s1);
+
+ VERIFY_IS_APPROX(m4=(m2*m3).pruned(0), refMat4=refMat2*refMat3);
+ VERIFY_IS_APPROX(m4=(m2t.transpose()*m3).pruned(0), refMat4=refMat2t.transpose()*refMat3);
+ VERIFY_IS_APPROX(m4=(m2t.transpose()*m3t.transpose()).pruned(0), refMat4=refMat2t.transpose()*refMat3t.transpose());
+ VERIFY_IS_APPROX(m4=(m2*m3t.transpose()).pruned(0), refMat4=refMat2*refMat3t.transpose());
+
+ // test aliasing
+ m4 = m2; refMat4 = refMat2;
+ VERIFY_IS_APPROX(m4=m4*m3, refMat4=refMat4*refMat3);
+
+ // sparse * dense
+ 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+refMat3), refMat4=refMat2*(refMat3+refMat3));
+ VERIFY_IS_APPROX(dm4=m2t.transpose()*(refMat3+refMat5)*0.5, refMat4=refMat2t.transpose()*(refMat3+refMat5)*0.5);
+
+ // dense * sparse
+ 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());
+
+ // sparse * dense and dense * sparse outer product
+ test_outer<SparseMatrixType,DenseMatrix>::run(m2,m4,refMat2,refMat4);
+
+ VERIFY_IS_APPROX(m6=m6*m6, refMat6=refMat6*refMat6);
+ }
+
+ // test matrix - diagonal product
+ {
+ DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
+ DiagonalMatrix<Scalar,Dynamic> d1(DenseVector::Random(rows));
+ SparseMatrixType m2(rows, rows);
+ SparseMatrixType m3(rows, rows);
+ initSparse<Scalar>(density, refM2, m2);
+ initSparse<Scalar>(density, refM3, m3);
+ VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1);
+ VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1);
+ VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2);
+ VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose());
+ }
+
+ // test self adjoint products
+ {
+ DenseMatrix b = DenseMatrix::Random(rows, rows);
+ DenseMatrix x = DenseMatrix::Random(rows, rows);
+ DenseMatrix refX = DenseMatrix::Random(rows, rows);
+ DenseMatrix refUp = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refLo = DenseMatrix::Zero(rows, rows);
+ DenseMatrix refS = DenseMatrix::Zero(rows, rows);
+ SparseMatrixType mUp(rows, rows);
+ SparseMatrixType mLo(rows, rows);
+ SparseMatrixType mS(rows, rows);
+ do {
+ initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular);
+ } while (refUp.isZero());
+ refLo = refUp.adjoint();
+ mLo = mUp.adjoint();
+ refS = refUp + refLo;
+ refS.diagonal() *= 0.5;
+ mS = mUp + mLo;
+ // TODO be able to address the diagonal....
+ for (int k=0; k<mS.outerSize(); ++k)
+ for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it)
+ if (it.index() == k)
+ it.valueRef() *= 0.5;
+
+ VERIFY_IS_APPROX(refS.adjoint(), refS);
+ VERIFY_IS_APPROX(mS.adjoint(), mS);
+ VERIFY_IS_APPROX(mS, refS);
+ VERIFY_IS_APPROX(x=mS*b, refX=refS*b);
+
+ 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);
+ }
+}
+
+// New test for Bug in SparseTimeDenseProduct
+template<typename SparseMatrixType, typename DenseMatrixType> void sparse_product_regression_test()
+{
+ // This code does not compile with afflicted versions of the bug
+ SparseMatrixType sm1(3,2);
+ DenseMatrixType m2(2,2);
+ sm1.setZero();
+ m2.setZero();
+
+ DenseMatrixType m3 = sm1*m2;
+
+
+ // This code produces a segfault with afflicted versions of another SparseTimeDenseProduct
+ // bug
+
+ SparseMatrixType sm2(20000,2);
+ sm2.setZero();
+ DenseMatrixType m4(sm2*m2);
+
+ VERIFY_IS_APPROX( m4(0,0), 0.0 );
+}
+
+void test_sparse_product()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( (sparse_product<SparseMatrix<double,ColMajor> >()) );
+ CALL_SUBTEST_1( (sparse_product<SparseMatrix<double,RowMajor> >()) );
+ CALL_SUBTEST_2( (sparse_product<SparseMatrix<std::complex<double>, ColMajor > >()) );
+ CALL_SUBTEST_2( (sparse_product<SparseMatrix<std::complex<double>, RowMajor > >()) );
+ CALL_SUBTEST_4( (sparse_product_regression_test<SparseMatrix<double,RowMajor>, Matrix<double, Dynamic, Dynamic, RowMajor> >()) );
+ }
+}
diff --git a/test/sparse_solver.h b/test/sparse_solver.h
new file mode 100644
index 000000000..75fa85082
--- /dev/null
+++ b/test/sparse_solver.h
@@ -0,0 +1,309 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse.h"
+#include <Eigen/SparseCore>
+
+template<typename Solver, typename Rhs, typename DenseMat, typename DenseRhs>
+void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const DenseMat& dA, const DenseRhs& db)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+
+ DenseRhs refX = dA.lu().solve(db);
+
+ Rhs x(b.rows(), b.cols());
+ Rhs oldb = b;
+
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n";
+ exit(0);
+ return;
+ }
+ x = solver.solve(b);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: solving failed\n";
+ 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);
+ solver.factorize(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n";
+ exit(0);
+ return;
+ }
+ x = solver.solve(b);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: solving failed\n";
+ return;
+ }
+ VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
+
+ VERIFY(x.isApprox(refX,test_precision<Scalar>()));
+
+ // test Block as the result and rhs:
+ {
+ DenseRhs x(db.rows(), db.cols());
+ DenseRhs b(db), oldb(db);
+ x.setZero();
+ x.block(0,0,x.rows(),x.cols()) = solver.solve(b.block(0,0,b.rows(),b.cols()));
+ VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!");
+ VERIFY(x.isApprox(refX,test_precision<Scalar>()));
+ }
+}
+
+template<typename Solver, typename Rhs>
+void check_sparse_solving_real_cases(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const Rhs& refX)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef typename Mat::RealScalar RealScalar;
+
+ Rhs x(b.rows(), b.cols());
+
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_solving_real_cases)\n";
+ exit(0);
+ return;
+ }
+ x = solver.solve(b);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: solving failed\n";
+ return;
+ }
+
+ RealScalar res_error;
+ // Compute the norm of the relative error
+ if(refX.size() != 0)
+ res_error = (refX - x).norm()/refX.norm();
+ else
+ {
+ // Compute the relative residual norm
+ res_error = (b - A * x).norm()/b.norm();
+ }
+ if (res_error > test_precision<Scalar>() ){
+ std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__)
+ << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" << std::endl << std::endl;
+ abort();
+ }
+
+}
+template<typename Solver, typename DenseMat>
+void check_sparse_determinant(Solver& solver, const typename Solver::MatrixType& A, const DenseMat& dA)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef typename Mat::RealScalar RealScalar;
+
+ solver.compute(A);
+ if (solver.info() != Success)
+ {
+ std::cerr << "sparse solver testing: factorization failed (check_sparse_determinant)\n";
+ return;
+ }
+
+ Scalar refDet = dA.determinant();
+ VERIFY_IS_APPROX(refDet,solver.determinant());
+}
+
+
+template<typename Solver, typename DenseMat>
+int generate_sparse_spd_problem(Solver& , typename Solver::MatrixType& A, typename Solver::MatrixType& halfA, DenseMat& dA, int maxSize = 300)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ int size = internal::random<int>(1,maxSize);
+ double density = (std::max)(8./(size*size), 0.01);
+
+ Mat M(size, size);
+ DenseMatrix dM(size, size);
+
+ initSparse<Scalar>(density, dM, M, ForceNonZeroDiag);
+
+ A = M * M.adjoint();
+ dA = dM * dM.adjoint();
+
+ halfA.resize(size,size);
+ halfA.template selfadjointView<Solver::UpLo>().rankUpdate(M);
+
+ return size;
+}
+
+
+#ifdef TEST_REAL_CASES
+template<typename Scalar>
+inline std::string get_matrixfolder()
+{
+ std::string mat_folder = TEST_REAL_CASES;
+ if( internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value )
+ mat_folder = mat_folder + static_cast<string>("/complex/");
+ else
+ mat_folder = mat_folder + static_cast<string>("/real/");
+ return mat_folder;
+}
+#endif
+
+template<typename Solver> void check_sparse_spd_solving(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef typename Mat::Index Index;
+ typedef SparseMatrix<Scalar,ColMajor> SpMat;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ // generate the problem
+ Mat A, halfA;
+ DenseMatrix dA;
+ int size = generate_sparse_spd_problem(solver, A, halfA, dA);
+
+ // generate the right hand sides
+ int rhsCols = internal::random<int>(1,16);
+ double density = (std::max)(8./(size*rhsCols), 0.1);
+ SpMat B(size,rhsCols);
+ DenseVector b = DenseVector::Random(size);
+ DenseMatrix dB(size,rhsCols);
+ initSparse<Scalar>(density, dB, B, ForceNonZeroDiag);
+
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_solving(solver, A, b, dA, b);
+ check_sparse_solving(solver, halfA, b, dA, b);
+ check_sparse_solving(solver, A, dB, dA, dB);
+ check_sparse_solving(solver, halfA, dB, dA, dB);
+ check_sparse_solving(solver, A, B, dA, dB);
+ check_sparse_solving(solver, halfA, B, dA, dB);
+ }
+
+ // First, get the folder
+#ifdef TEST_REAL_CASES
+ if (internal::is_same<Scalar, float>::value
+ || internal::is_same<Scalar, std::complex<float> >::value)
+ return ;
+
+ std::string mat_folder = get_matrixfolder<Scalar>();
+ MatrixMarketIterator<Scalar> it(mat_folder);
+ for (; it; ++it)
+ {
+ if (it.sym() == SPD){
+ Mat halfA;
+ PermutationMatrix<Dynamic, Dynamic, Index> pnull;
+ halfA.template selfadjointView<Solver::UpLo>() = it.matrix().template triangularView<Eigen::Lower>().twistedBy(pnull);
+
+ std::cout<< " ==== SOLVING WITH MATRIX " << it.matname() << " ==== \n";
+ check_sparse_solving_real_cases(solver, it.matrix(), it.rhs(), it.refX());
+ check_sparse_solving_real_cases(solver, halfA, it.rhs(), it.refX());
+ }
+ }
+#endif
+}
+
+template<typename Solver> void check_sparse_spd_determinant(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ // generate the problem
+ Mat A, halfA;
+ DenseMatrix dA;
+ generate_sparse_spd_problem(solver, A, halfA, dA, 30);
+
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_determinant(solver, A, dA);
+ check_sparse_determinant(solver, halfA, dA );
+ }
+}
+
+template<typename Solver, typename DenseMat>
+int generate_sparse_square_problem(Solver&, typename Solver::MatrixType& A, DenseMat& dA, int maxSize = 300)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+
+ int size = internal::random<int>(1,maxSize);
+ double density = (std::max)(8./(size*size), 0.01);
+
+ A.resize(size,size);
+ dA.resize(size,size);
+
+ initSparse<Scalar>(density, dA, A, ForceNonZeroDiag);
+
+ return size;
+}
+
+template<typename Solver> void check_sparse_square_solving(Solver& solver)
+{
+ typedef typename Solver::MatrixType Mat;
+ typedef typename Mat::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+
+ int rhsCols = internal::random<int>(1,16);
+
+ Mat A;
+ DenseMatrix dA;
+ int size = generate_sparse_square_problem(solver, A, dA);
+
+ DenseVector b = DenseVector::Random(size);
+ DenseMatrix dB = DenseMatrix::Random(size,rhsCols);
+ A.makeCompressed();
+ for (int i = 0; i < g_repeat; i++) {
+ check_sparse_solving(solver, A, b, dA, b);
+ check_sparse_solving(solver, A, dB, dA, dB);
+ }
+
+ // First, get the folder
+#ifdef TEST_REAL_CASES
+ if (internal::is_same<Scalar, float>::value
+ || internal::is_same<Scalar, std::complex<float> >::value)
+ return ;
+
+ std::string mat_folder = get_matrixfolder<Scalar>();
+ MatrixMarketIterator<Scalar> it(mat_folder);
+ for (; it; ++it)
+ {
+ std::cout<< " ==== SOLVING WITH MATRIX " << it.matname() << " ==== \n";
+ check_sparse_solving_real_cases(solver, it.matrix(), it.rhs(), it.refX());
+ }
+#endif
+
+}
+
+template<typename Solver> void check_sparse_square_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_determinant(solver, A, dA);
+ }
+}
diff --git a/test/sparse_solvers.cpp b/test/sparse_solvers.cpp
new file mode 100644
index 000000000..3a8873d43
--- /dev/null
+++ b/test/sparse_solvers.cpp
@@ -0,0 +1,112 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2010 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/.
+
+#include "sparse.h"
+
+template<typename Scalar> void
+initSPD(double density,
+ Matrix<Scalar,Dynamic,Dynamic>& refMat,
+ SparseMatrix<Scalar>& sparseMat)
+{
+ Matrix<Scalar,Dynamic,Dynamic> aux(refMat.rows(),refMat.cols());
+ initSparse(density,refMat,sparseMat);
+ refMat = refMat * refMat.adjoint();
+ for (int k=0; k<2; ++k)
+ {
+ initSparse(density,aux,sparseMat,ForceNonZeroDiag);
+ refMat += aux * aux.adjoint();
+ }
+ sparseMat.setZero();
+ for (int j=0 ; j<sparseMat.cols(); ++j)
+ for (int i=j ; i<sparseMat.rows(); ++i)
+ if (refMat(i,j)!=Scalar(0))
+ sparseMat.insert(i,j) = refMat(i,j);
+ sparseMat.finalize();
+}
+
+template<typename Scalar> void sparse_solvers(int rows, int cols)
+{
+ double density = (std::max)(8./(rows*cols), 0.01);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ // Scalar eps = 1e-6;
+
+ DenseVector vec1 = DenseVector::Random(rows);
+
+ std::vector<Vector2i> zeroCoords;
+ std::vector<Vector2i> nonzeroCoords;
+
+ // test triangular solver
+ {
+ DenseVector vec2 = vec1, vec3 = vec1;
+ SparseMatrix<Scalar> m2(rows, cols);
+ DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
+
+ // lower - dense
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template triangularView<Lower>().solve(vec2),
+ m2.template triangularView<Lower>().solve(vec3));
+
+ // upper - dense
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template triangularView<Upper>().solve(vec2),
+ m2.template triangularView<Upper>().solve(vec3));
+ VERIFY_IS_APPROX(refMat2.conjugate().template triangularView<Upper>().solve(vec2),
+ m2.conjugate().template triangularView<Upper>().solve(vec3));
+ {
+ SparseMatrix<Scalar> cm2(m2);
+ //Index rows, Index cols, Index nnz, Index* outerIndexPtr, Index* innerIndexPtr, Scalar* valuePtr
+ MappedSparseMatrix<Scalar> mm2(rows, cols, cm2.nonZeros(), cm2.outerIndexPtr(), cm2.innerIndexPtr(), cm2.valuePtr());
+ VERIFY_IS_APPROX(refMat2.conjugate().template triangularView<Upper>().solve(vec2),
+ mm2.conjugate().template triangularView<Upper>().solve(vec3));
+ }
+
+ // lower - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.transpose().template triangularView<Upper>().solve(vec2),
+ m2.transpose().template triangularView<Upper>().solve(vec3));
+
+ // upper - transpose
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.transpose().template triangularView<Lower>().solve(vec2),
+ m2.transpose().template triangularView<Lower>().solve(vec3));
+
+ SparseMatrix<Scalar> matB(rows, rows);
+ DenseMatrix refMatB = DenseMatrix::Zero(rows, rows);
+
+ // lower - sparse
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular);
+ initSparse<Scalar>(density, refMatB, matB);
+ refMat2.template triangularView<Lower>().solveInPlace(refMatB);
+ m2.template triangularView<Lower>().solveInPlace(matB);
+ VERIFY_IS_APPROX(matB.toDense(), refMatB);
+
+ // upper - sparse
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular);
+ initSparse<Scalar>(density, refMatB, matB);
+ refMat2.template triangularView<Upper>().solveInPlace(refMatB);
+ m2.template triangularView<Upper>().solveInPlace(matB);
+ VERIFY_IS_APPROX(matB, refMatB);
+
+ // test deprecated API
+ initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords);
+ VERIFY_IS_APPROX(refMat2.template triangularView<Lower>().solve(vec2),
+ m2.template triangularView<Lower>().solve(vec3));
+ }
+}
+
+void test_sparse_solvers()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1(sparse_solvers<double>(8, 8) );
+ int s = internal::random<int>(1,300);
+ CALL_SUBTEST_2(sparse_solvers<std::complex<double> >(s,s) );
+ CALL_SUBTEST_1(sparse_solvers<double>(s,s) );
+ }
+}
diff --git a/test/sparse_vector.cpp b/test/sparse_vector.cpp
new file mode 100644
index 000000000..7201afe5b
--- /dev/null
+++ b/test/sparse_vector.cpp
@@ -0,0 +1,91 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2011 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/.
+
+#include "sparse.h"
+
+template<typename Scalar> void sparse_vector(int rows, int cols)
+{
+ double densityMat = (std::max)(8./(rows*cols), 0.01);
+ double densityVec = (std::max)(8./float(rows), 0.1);
+ typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
+ typedef Matrix<Scalar,Dynamic,1> DenseVector;
+ typedef SparseVector<Scalar> SparseVectorType;
+ typedef SparseMatrix<Scalar> SparseMatrixType;
+ Scalar eps = 1e-6;
+
+ SparseMatrixType m1(rows,rows);
+ 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);
+
+ std::vector<int> zerocoords, nonzerocoords;
+ initSparse<Scalar>(densityVec, refV1, v1, &zerocoords, &nonzerocoords);
+ initSparse<Scalar>(densityMat, refM1, m1);
+
+ initSparse<Scalar>(densityVec, refV2, v2);
+ initSparse<Scalar>(densityVec, refV3, v3);
+
+ Scalar s1 = internal::random<Scalar>();
+
+ // test coeff and coeffRef
+ for (unsigned int i=0; i<zerocoords.size(); ++i)
+ {
+ VERIFY_IS_MUCH_SMALLER_THAN( v1.coeff(zerocoords[i]), eps );
+ //VERIFY_RAISES_ASSERT( v1.coeffRef(zerocoords[i]) = 5 );
+ }
+ {
+ VERIFY(int(nonzerocoords.size()) == v1.nonZeros());
+ int j=0;
+ for (typename SparseVectorType::InnerIterator it(v1); it; ++it,++j)
+ {
+ VERIFY(nonzerocoords[j]==it.index());
+ VERIFY(it.value()==v1.coeff(it.index()));
+ VERIFY(it.value()==refV1.coeff(it.index()));
+ }
+ }
+ VERIFY_IS_APPROX(v1, refV1);
+
+ v1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ refV1.coeffRef(nonzerocoords[0]) = Scalar(5);
+ VERIFY_IS_APPROX(v1, refV1);
+
+ VERIFY_IS_APPROX(v1+v2, refV1+refV2);
+ VERIFY_IS_APPROX(v1+v2+v3, refV1+refV2+refV3);
+
+ VERIFY_IS_APPROX(v1*s1-v2, refV1*s1-refV2);
+
+ VERIFY_IS_APPROX(v1*=s1, refV1*=s1);
+ VERIFY_IS_APPROX(v1/=s1, refV1/=s1);
+
+ VERIFY_IS_APPROX(v1+=v2, refV1+=refV2);
+ VERIFY_IS_APPROX(v1-=v2, refV1-=refV2);
+
+ VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2));
+ VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(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)));
+
+
+ VERIFY_IS_APPROX(v1.squaredNorm(), refV1.squaredNorm());
+
+}
+
+void test_sparse_vector()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( sparse_vector<double>(8, 8) );
+ CALL_SUBTEST_2( sparse_vector<std::complex<double> >(16, 16) );
+ CALL_SUBTEST_1( sparse_vector<double>(299, 535) );
+ }
+}
+
diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp
new file mode 100644
index 000000000..a25dbf51c
--- /dev/null
+++ b/test/stable_norm.cpp
@@ -0,0 +1,110 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 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/.
+
+#include "main.h"
+
+template<typename T> bool isNotNaN(const T& x)
+{
+ return x==x;
+}
+
+// workaround aggressive optimization in ICC
+template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
+
+template<typename T> bool isFinite(const T& x)
+{
+ return isNotNaN(sub(x,x));
+}
+
+template<typename T> EIGEN_DONT_INLINE T copy(const T& x)
+{
+ return x;
+}
+
+template<typename MatrixType> void stable_norm(const MatrixType& m)
+{
+ /* this test covers the following files:
+ StableNorm.h
+ */
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ // Check the basic machine-dependent constants.
+ {
+ int ibeta, it, iemin, iemax;
+
+ ibeta = std::numeric_limits<RealScalar>::radix; // base for floating-point numbers
+ it = std::numeric_limits<RealScalar>::digits; // number of base-beta digits in mantissa
+ iemin = std::numeric_limits<RealScalar>::min_exponent; // minimum exponent
+ iemax = std::numeric_limits<RealScalar>::max_exponent; // maximum exponent
+
+ VERIFY( (!(iemin > 1 - 2*it || 1+it>iemax || (it==2 && ibeta<5) || (it<=4 && ibeta <= 3 ) || it<2))
+ && "the stable norm algorithm cannot be guaranteed on this computer");
+ }
+
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ Scalar big = internal::random<Scalar>() * ((std::numeric_limits<RealScalar>::max)() * RealScalar(1e-4));
+ Scalar small = internal::random<Scalar>() * ((std::numeric_limits<RealScalar>::min)() * RealScalar(1e4));
+
+ MatrixType vzero = MatrixType::Zero(rows, cols),
+ vrand = MatrixType::Random(rows, cols),
+ vbig(rows, cols),
+ vsmall(rows,cols);
+
+ vbig.fill(big);
+ vsmall.fill(small);
+
+ VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast<RealScalar>(1));
+ VERIFY_IS_APPROX(vrand.stableNorm(), vrand.norm());
+ VERIFY_IS_APPROX(vrand.blueNorm(), vrand.norm());
+ VERIFY_IS_APPROX(vrand.hypotNorm(), vrand.norm());
+
+ RealScalar size = static_cast<RealScalar>(m.size());
+
+ // test isFinite
+ VERIFY(!isFinite( std::numeric_limits<RealScalar>::infinity()));
+ VERIFY(!isFinite(internal::sqrt(-internal::abs(big))));
+
+ // test overflow
+ VERIFY(isFinite(internal::sqrt(size)*internal::abs(big)));
+ VERIFY_IS_NOT_APPROX(internal::sqrt(copy(vbig.squaredNorm())), internal::abs(internal::sqrt(size)*big)); // here the default norm must fail
+ VERIFY_IS_APPROX(vbig.stableNorm(), internal::sqrt(size)*internal::abs(big));
+ VERIFY_IS_APPROX(vbig.blueNorm(), internal::sqrt(size)*internal::abs(big));
+ VERIFY_IS_APPROX(vbig.hypotNorm(), internal::sqrt(size)*internal::abs(big));
+
+ // test underflow
+ VERIFY(isFinite(internal::sqrt(size)*internal::abs(small)));
+ VERIFY_IS_NOT_APPROX(internal::sqrt(copy(vsmall.squaredNorm())), internal::abs(internal::sqrt(size)*small)); // here the default norm must fail
+ VERIFY_IS_APPROX(vsmall.stableNorm(), internal::sqrt(size)*internal::abs(small));
+ VERIFY_IS_APPROX(vsmall.blueNorm(), internal::sqrt(size)*internal::abs(small));
+ VERIFY_IS_APPROX(vsmall.hypotNorm(), internal::sqrt(size)*internal::abs(small));
+
+// Test compilation of cwise() version
+ VERIFY_IS_APPROX(vrand.colwise().stableNorm(), vrand.colwise().norm());
+ VERIFY_IS_APPROX(vrand.colwise().blueNorm(), vrand.colwise().norm());
+ VERIFY_IS_APPROX(vrand.colwise().hypotNorm(), vrand.colwise().norm());
+ VERIFY_IS_APPROX(vrand.rowwise().stableNorm(), vrand.rowwise().norm());
+ VERIFY_IS_APPROX(vrand.rowwise().blueNorm(), vrand.rowwise().norm());
+ VERIFY_IS_APPROX(vrand.rowwise().hypotNorm(), vrand.rowwise().norm());
+}
+
+void test_stable_norm()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( stable_norm(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( stable_norm(Vector4d()) );
+ CALL_SUBTEST_3( stable_norm(VectorXd(internal::random<int>(10,2000))) );
+ CALL_SUBTEST_4( stable_norm(VectorXf(internal::random<int>(10,2000))) );
+ CALL_SUBTEST_5( stable_norm(VectorXcd(internal::random<int>(10,2000))) );
+ }
+}
diff --git a/test/stddeque.cpp b/test/stddeque.cpp
new file mode 100644
index 000000000..bb4b476f3
--- /dev/null
+++ b/test/stddeque.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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/.
+
+#include "main.h"
+#include <Eigen/StdDeque>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stddeque_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::deque<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::deque<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator vi = v.begin();
+ typename std::deque<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename TransformType>
+void check_stddeque_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::deque<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::deque<TransformType,Eigen::aligned_allocator<TransformType> >::iterator vi = v.begin();
+ typename std::deque<TransformType,Eigen::aligned_allocator<TransformType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename QuaternionType>
+void check_stddeque_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::deque<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::deque<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator vi = v.begin();
+ typename std::deque<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+void test_stddeque()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stddeque_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stddeque_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stddeque_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stddeque_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stddeque_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stddeque_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stddeque_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stddeque_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stddeque_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stddeque_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stddeque_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stddeque_transform(Affine2f()));
+ CALL_SUBTEST_4(check_stddeque_transform(Affine3f()));
+ CALL_SUBTEST_4(check_stddeque_transform(Affine3d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stddeque_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stddeque_quaternion(Quaterniond()));
+}
diff --git a/test/stdlist.cpp b/test/stdlist.cpp
new file mode 100644
index 000000000..17cce779a
--- /dev/null
+++ b/test/stdlist.cpp
@@ -0,0 +1,132 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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/.
+
+#include "main.h"
+#include <Eigen/StdList>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdlist_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::list<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::list<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator vi = v.begin();
+ typename std::list<MatrixType,Eigen::aligned_allocator<MatrixType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename TransformType>
+void check_stdlist_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::list<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::list<TransformType,Eigen::aligned_allocator<TransformType> >::iterator vi = v.begin();
+ typename std::list<TransformType,Eigen::aligned_allocator<TransformType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+template<typename QuaternionType>
+void check_stdlist_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::list<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v.front() = x;
+ w.front() = w.back();
+ VERIFY_IS_APPROX(w.front(), w.back());
+ v = w;
+
+ typename std::list<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator vi = v.begin();
+ typename std::list<QuaternionType,Eigen::aligned_allocator<QuaternionType> >::iterator wi = w.begin();
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(*vi, *wi);
+ ++vi;
+ ++wi;
+ }
+
+ v.resize(21);
+ v.back() = x;
+ VERIFY_IS_APPROX(v.back(), x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v.back(), y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v.back(), x);
+}
+
+void test_stdlist()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdlist_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdlist_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stdlist_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdlist_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stdlist_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stdlist_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdlist_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdlist_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdlist_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdlist_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdlist_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdlist_transform(Affine2f()));
+ CALL_SUBTEST_4(check_stdlist_transform(Affine3f()));
+ CALL_SUBTEST_4(check_stdlist_transform(Affine3d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdlist_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdlist_quaternion(Quaterniond()));
+}
diff --git a/test/stdvector.cpp b/test/stdvector.cpp
new file mode 100644
index 000000000..6e173c678
--- /dev/null
+++ b/test/stdvector.cpp
@@ -0,0 +1,148 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_stdvector()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Projective2f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Projective3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Projective3d()));
+ //CALL_SUBTEST(heck_stdvector_transform(Projective4d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
+}
diff --git a/test/stdvector_overload.cpp b/test/stdvector_overload.cpp
new file mode 100644
index 000000000..736ff0ee7
--- /dev/null
+++ b/test/stdvector_overload.cpp
@@ -0,0 +1,161 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2010 Hauke Heibel <hauke.heibel@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/.
+
+#include "main.h"
+
+#include <Eigen/StdVector>
+#include <Eigen/Geometry>
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Vector4f)
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix2f)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix4f)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Matrix4d)
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Affine3f)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Affine3d)
+
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaternionf)
+EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Quaterniond)
+
+template<typename MatrixType>
+void check_stdvector_matrix(const MatrixType& m)
+{
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+ MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
+ std::vector<MatrixType> v(10, MatrixType(rows,cols)), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ MatrixType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i]==w[(i-23)%w.size()]);
+ }
+}
+
+template<typename TransformType>
+void check_stdvector_transform(const TransformType&)
+{
+ typedef typename TransformType::MatrixType MatrixType;
+ TransformType x(MatrixType::Random()), y(MatrixType::Random());
+ std::vector<TransformType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ TransformType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
+ }
+}
+
+template<typename QuaternionType>
+void check_stdvector_quaternion(const QuaternionType&)
+{
+ typedef typename QuaternionType::Coefficients Coefficients;
+ QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
+ std::vector<QuaternionType> v(10), w(20, y);
+ v[5] = x;
+ w[6] = v[5];
+ VERIFY_IS_APPROX(w[6], v[5]);
+ v = w;
+ for(int i = 0; i < 20; i++)
+ {
+ VERIFY_IS_APPROX(w[i], v[i]);
+ }
+
+ v.resize(21);
+ v[20] = x;
+ VERIFY_IS_APPROX(v[20], x);
+ v.resize(22,y);
+ VERIFY_IS_APPROX(v[21], y);
+ v.push_back(x);
+ VERIFY_IS_APPROX(v[22], x);
+ VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));
+
+ // do a lot of push_back such that the vector gets internally resized
+ // (with memory reallocation)
+ QuaternionType* ref = &w[0];
+ for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
+ v.push_back(w[i%w.size()]);
+ for(unsigned int i=23; i<v.size(); ++i)
+ {
+ VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
+ }
+}
+
+void test_stdvector_overload()
+{
+ // some non vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix3d()));
+
+ // some vectorizable fixed sizes
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix2f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Vector4f()));
+ CALL_SUBTEST_1(check_stdvector_matrix(Matrix4f()));
+ CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));
+
+ // some dynamic sizes
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
+ CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
+ CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));
+
+ // some Transform
+ CALL_SUBTEST_4(check_stdvector_transform(Affine2f())); // does not need the specialization (2+1)^2 = 9
+ CALL_SUBTEST_4(check_stdvector_transform(Affine3f()));
+ CALL_SUBTEST_4(check_stdvector_transform(Affine3d()));
+
+ // some Quaternion
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
+ CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
+}
diff --git a/test/superlu_support.cpp b/test/superlu_support.cpp
new file mode 100644
index 000000000..3b16135bc
--- /dev/null
+++ b/test/superlu_support.cpp
@@ -0,0 +1,22 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse_solver.h"
+
+#include <Eigen/SuperLUSupport>
+
+void test_superlu_support()
+{
+ SuperLU<SparseMatrix<double> > superlu_double_colmajor;
+ SuperLU<SparseMatrix<std::complex<double> > > superlu_cplxdouble_colmajor;
+ CALL_SUBTEST_1( check_sparse_square_solving(superlu_double_colmajor) );
+ CALL_SUBTEST_2( check_sparse_square_solving(superlu_cplxdouble_colmajor) );
+ CALL_SUBTEST_1( check_sparse_square_determinant(superlu_double_colmajor) );
+ CALL_SUBTEST_2( check_sparse_square_determinant(superlu_cplxdouble_colmajor) );
+}
diff --git a/test/swap.cpp b/test/swap.cpp
new file mode 100644
index 000000000..36b353148
--- /dev/null
+++ b/test/swap.cpp
@@ -0,0 +1,83 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+#include "main.h"
+
+template<typename T>
+struct other_matrix_type
+{
+ typedef int type;
+};
+
+template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
+struct other_matrix_type<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
+{
+ typedef Matrix<_Scalar, _Rows, _Cols, _Options^RowMajor, _MaxRows, _MaxCols> type;
+};
+
+template<typename MatrixType> void swap(const MatrixType& m)
+{
+ typedef typename other_matrix_type<MatrixType>::type OtherMatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+
+ eigen_assert((!internal::is_same<MatrixType,OtherMatrixType>::value));
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+
+ // construct 3 matrix guaranteed to be distinct
+ MatrixType m1 = MatrixType::Random(rows,cols);
+ MatrixType m2 = MatrixType::Random(rows,cols) + Scalar(100) * MatrixType::Identity(rows,cols);
+ OtherMatrixType m3 = OtherMatrixType::Random(rows,cols) + Scalar(200) * OtherMatrixType::Identity(rows,cols);
+
+ MatrixType m1_copy = m1;
+ MatrixType m2_copy = m2;
+ OtherMatrixType m3_copy = m3;
+
+ // test swapping 2 matrices of same type
+ m1.swap(m2);
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping 2 matrices of different types
+ m1.swap(m3);
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test swapping matrix with expression
+ m1.swap(m2.block(0,0,rows,cols));
+ VERIFY_IS_APPROX(m1,m2_copy);
+ VERIFY_IS_APPROX(m2,m1_copy);
+ m1 = m1_copy;
+ m2 = m2_copy;
+
+ // test swapping two expressions of different types
+ m1.transpose().swap(m3.transpose());
+ VERIFY_IS_APPROX(m1,m3_copy);
+ VERIFY_IS_APPROX(m3,m1_copy);
+ m1 = m1_copy;
+ m3 = m3_copy;
+
+ // test assertion on mismatching size -- matrix case
+ VERIFY_RAISES_ASSERT(m1.swap(m1.row(0)));
+ // test assertion on mismatching size -- xpr case
+ VERIFY_RAISES_ASSERT(m1.row(0).swap(m1));
+}
+
+void test_swap()
+{
+ CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization
+ CALL_SUBTEST_2( swap(Matrix4d()) ); // fixed size, possible vectorization
+ CALL_SUBTEST_3( swap(MatrixXd(3,3)) ); // dyn size, no vectorization
+ CALL_SUBTEST_4( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization
+}
diff --git a/test/testsuite.cmake b/test/testsuite.cmake
new file mode 100644
index 000000000..3bec56b3f
--- /dev/null
+++ b/test/testsuite.cmake
@@ -0,0 +1,229 @@
+
+####################################################################
+#
+# Usage:
+# - create a new folder, let's call it cdash
+# - in that folder, do:
+# ctest -S path/to/eigen/test/testsuite.cmake[,option1=value1[,option2=value2]]
+#
+# Options:
+# - EIGEN_CXX: compiler, eg.: g++-4.2
+# default: default c++ compiler
+# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc.
+# default: hostname
+# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that:
+# <OS_name>-<OS_version>-<arch>-<compiler-version>
+# with:
+# <OS_name> = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc.
+# <OS_version> = 11.1, XP, vista, leopard, etc.
+# <arch> = i386, x86_64, ia64, powerpc, etc.
+# <compiler-version> = gcc-4.3.2, icc-11.0, MSVC-2008, etc.
+# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec
+# default: SSE2 for x86_64 systems, novec otherwise
+# Its value is automatically appended to EIGEN_BUILD_STRING
+# - EIGEN_CMAKE_DIR: path to cmake executable
+# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous
+# default: Nightly
+# - EIGEN_WORK_DIR: directory used to download the source files and make the builds
+# default: folder which contains this script
+# - EIGEN_CMAKE_ARGS: additional arguments passed to cmake
+# - EIGEN_GENERATOR_TYPE: allows to overwrite the generator type
+# default: nmake (windows
+# See http://www.cmake.org/cmake/help/cmake2.6docs.html#section_Generators for a complete
+# list of supported generators.
+# - EIGEN_NO_UPDATE: allows to submit dash boards from local repositories
+# This might be interesting in case you want to submit dashboards
+# including local changes.
+# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on)
+# default: <EIGEN_WORK_DIR>/src
+# - CTEST_BINARY_DIRECTORY: build directory
+# default: <EIGEN_WORK_DIR>/nightly-<EIGEN_CXX>
+#
+# Here is an example running several compilers on a linux system:
+# #!/bin/bash
+# ARCH=`uname -m`
+# SITE=`hostname`
+# VERSION=opensuse-11.1
+# WORK_DIR=/home/gael/Coding/eigen/cdash
+# # get the last version of the script
+# wget http://bitbucket.org/eigen/eigen/raw/tip/test/testsuite.cmake -o $WORK_DIR/testsuite.cmake
+# COMMON="ctest -S $WORK_DIR/testsuite.cmake,EIGEN_WORK_DIR=$WORK_DIR,EIGEN_SITE=$SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$OS_VERSION-$ARCH"
+# $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4
+# $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=novec
+# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=SSE2
+# $COMMON-icc-11.0,EIGEN_CXX=icpc
+#
+####################################################################
+
+# process the arguments
+
+set(ARGLIST ${CTEST_SCRIPT_ARG})
+while(${ARGLIST} MATCHES ".+.*")
+
+ # pick first
+ string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST})
+ SET(TOP ${CMAKE_MATCH_1})
+
+ # remove first
+ string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST})
+ SET(ARGLIST ${CMAKE_MATCH_1})
+
+ # decompose as a pair key=value
+ string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP})
+ SET(KEY ${CMAKE_MATCH_1})
+
+ string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP})
+ SET(VALUE ${CMAKE_MATCH_1})
+
+ # set the variable to the specified value
+ if(VALUE)
+ SET(${KEY} ${VALUE})
+ else(VALUE)
+ SET(${KEY} ON)
+ endif(VALUE)
+
+endwhile(${ARGLIST} MATCHES ".+.*")
+
+####################################################################
+# Automatically set some user variables if they have not been defined manually
+####################################################################
+cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
+
+if(NOT EIGEN_SITE)
+ site_name(EIGEN_SITE)
+endif(NOT EIGEN_SITE)
+
+if(NOT EIGEN_CMAKE_DIR)
+ SET(EIGEN_CMAKE_DIR "")
+endif(NOT EIGEN_CMAKE_DIR)
+
+if(NOT EIGEN_BUILD_STRING)
+
+ # let's try to find all information we need to make the build string ourself
+
+ # OS
+ build_name(EIGEN_OS_VERSION)
+
+ # arch
+ set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR})
+ if(WIN32)
+ set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE})
+ else(WIN32)
+ execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif(WIN32)
+
+ set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX})
+
+endif(NOT EIGEN_BUILD_STRING)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION})
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(NOT EIGEN_WORK_DIR)
+ set(EIGEN_WORK_DIR ${CTEST_SCRIPT_DIRECTORY})
+endif(NOT EIGEN_WORK_DIR)
+
+if(NOT CTEST_SOURCE_DIRECTORY)
+ SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIR}/src")
+endif(NOT CTEST_SOURCE_DIRECTORY)
+
+if(NOT CTEST_BINARY_DIRECTORY)
+ SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIR}/nightly_${EIGEN_CXX}")
+endif(NOT CTEST_BINARY_DIRECTORY)
+
+if(NOT EIGEN_MODE)
+ set(EIGEN_MODE Nightly)
+endif(NOT EIGEN_MODE)
+
+## mandatory variables (the default should be ok in most cases):
+
+if(NOT EIGEN_NO_UPDATE)
+ SET (CTEST_CVS_COMMAND "hg")
+ SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone http://bitbucket.org/eigen/eigen \"${CTEST_SOURCE_DIRECTORY}\"")
+ SET(CTEST_BACKUP_AND_RESTORE TRUE) # the backup is CVS related ...
+endif(NOT EIGEN_NO_UPDATE)
+
+# which ctest command to use for running the dashboard
+SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE} --no-compress-output")
+if($ENV{EIGEN_CTEST_ARGS})
+SET (CTEST_COMMAND "${CTEST_COMMAND} $ENV{EIGEN_CTEST_ARGS}")
+endif($ENV{EIGEN_CTEST_ARGS})
+# what cmake command to use for configuring this dashboard
+SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_LEAVE_TEST_IN_ALL_TARGET=ON")
+
+####################################################################
+# The values in this section are optional you can either
+# have them or leave them commented out
+####################################################################
+
+# this make sure we get consistent outputs
+SET($ENV{LC_MESSAGES} "en_EN")
+
+# should ctest wipe the binary tree before running
+SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE)
+
+# raise the warning/error limit
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "33331")
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "33331")
+
+# this is the initial cache to use for the binary tree, be careful to escape
+# any quotes inside of this string if you use it
+if(WIN32 AND NOT UNIX)
+ #message(SEND_ERROR "win32")
+ if(EIGEN_GENERATOR_TYPE)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"${EIGEN_GENERATOR_TYPE}\"")
+ SET (CTEST_INITIAL_CACHE "
+ CMAKE_BUILD_TYPE:STRING=Release
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+ else(EIGEN_GENERATOR_TYPE)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake")
+ SET (CTEST_INITIAL_CACHE "
+ MAKECOMMAND:STRING=nmake /i
+ CMAKE_MAKE_PROGRAM:FILEPATH=nmake
+ CMAKE_GENERATOR:INTERNAL=NMake Makefiles
+ CMAKE_BUILD_TYPE:STRING=Release
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+ endif(EIGEN_GENERATOR_TYPE)
+else(WIN32 AND NOT UNIX)
+ SET (CTEST_INITIAL_CACHE "
+ BUILDNAME:STRING=${EIGEN_BUILD_STRING}
+ SITE:STRING=${EIGEN_SITE}
+ ")
+endif(WIN32 AND NOT UNIX)
+
+# set any extra environment variables to use during the execution of the script here:
+# setting this variable on windows machines causes trouble ...
+
+if(EIGEN_CXX AND NOT WIN32)
+ set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}")
+endif(EIGEN_CXX AND NOT WIN32)
+
+if(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+ if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSSE3)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE4_1)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON -DEIGEN_TEST_SSE4_1=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE4_2)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON -DEIGEN_TEST_SSE4_1=ON -DEIGEN_TEST_SSE4_2=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON")
+ elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON")
+ else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+ message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec")
+ endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2)
+endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION)
+
+if(DEFINED EIGEN_CMAKE_ARGS)
+ set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} ${EIGEN_CMAKE_ARGS}")
+endif(DEFINED EIGEN_CMAKE_ARGS)
diff --git a/test/triangular.cpp b/test/triangular.cpp
new file mode 100644
index 000000000..0e8ee5487
--- /dev/null
+++ b/test/triangular.cpp
@@ -0,0 +1,235 @@
+// This file is triangularView of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008-2009 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/.
+
+#include "main.h"
+
+
+
+template<typename MatrixType> void triangular_square(const MatrixType& m)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+ RealScalar largerEps = 10*test_precision<RealScalar>();
+
+ typename MatrixType::Index rows = m.rows();
+ typename MatrixType::Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ r1(rows, cols),
+ r2(rows, cols);
+ VectorType v2 = VectorType::Random(rows);
+
+ MatrixType m1up = m1.template triangularView<Upper>();
+ MatrixType m2up = m2.template triangularView<Upper>();
+
+ if (rows*cols>1)
+ {
+ VERIFY(m1up.isUpperTriangular());
+ VERIFY(m2up.transpose().isLowerTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ }
+
+// VERIFY_IS_APPROX(m1up.transpose() * m2, m1.upper().transpose().lower() * m2);
+
+ // test overloaded operator+=
+ r1.setZero();
+ r2.setZero();
+ r1.template triangularView<Upper>() += m1;
+ r2 += m1up;
+ VERIFY_IS_APPROX(r1,r2);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template triangularView<Upper>() = m2.transpose() + m2;
+ m3 = m2.transpose() + m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().transpose().toDenseMatrix(), m1);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template triangularView<Lower>() = m2.transpose() + m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().toDenseMatrix(), m1);
+
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().conjugate().toDenseMatrix(),
+ m3.conjugate().template triangularView<Lower>().toDenseMatrix());
+
+ m1 = MatrixType::Random(rows, cols);
+ for (int i=0; i<rows; ++i)
+ while (internal::abs2(m1(i,i))<1e-1) m1(i,i) = internal::random<Scalar>();
+
+ Transpose<MatrixType> trm4(m4);
+ // test back and forward subsitution with a vector as the rhs
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(v2.isApprox(m3.adjoint() * (m1.adjoint().template triangularView<Lower>().solve(v2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(v2.isApprox(m3.transpose() * (m1.transpose().template triangularView<Upper>().solve(v2)), largerEps));
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(v2.isApprox(m3 * (m1.template triangularView<Upper>().solve(v2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(v2.isApprox(m3.conjugate() * (m1.conjugate().template triangularView<Lower>().solve(v2)), largerEps));
+
+ // test back and forward subsitution with a matrix as the rhs
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(m2.isApprox(m3.adjoint() * (m1.adjoint().template triangularView<Lower>().solve(m2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(m2.isApprox(m3.transpose() * (m1.transpose().template triangularView<Upper>().solve(m2)), largerEps));
+ m3 = m1.template triangularView<Upper>();
+ VERIFY(m2.isApprox(m3 * (m1.template triangularView<Upper>().solve(m2)), largerEps));
+ m3 = m1.template triangularView<Lower>();
+ VERIFY(m2.isApprox(m3.conjugate() * (m1.conjugate().template triangularView<Lower>().solve(m2)), largerEps));
+
+ // check M * inv(L) using in place API
+ m4 = m3;
+ m1.transpose().template triangularView<Eigen::Upper>().solveInPlace(trm4);
+ VERIFY_IS_APPROX(m4 * m1.template triangularView<Eigen::Lower>(), m3);
+
+ // check M * inv(U) using in place API
+ m3 = m1.template triangularView<Upper>();
+ m4 = m3;
+ m3.transpose().template triangularView<Eigen::Lower>().solveInPlace(trm4);
+ VERIFY_IS_APPROX(m4 * m1.template triangularView<Eigen::Upper>(), m3);
+
+ // check solve with unit diagonal
+ m3 = m1.template triangularView<UnitUpper>();
+ VERIFY(m2.isApprox(m3 * (m1.template triangularView<UnitUpper>().solve(m2)), largerEps));
+
+// VERIFY(( m1.template triangularView<Upper>()
+// * m2.template triangularView<Upper>()).isUpperTriangular());
+
+ // test swap
+ m1.setOnes();
+ m2.setZero();
+ m2.template triangularView<Upper>().swap(m1);
+ m3.setZero();
+ m3.template triangularView<Upper>().setOnes();
+ VERIFY_IS_APPROX(m2,m3);
+
+}
+
+
+template<typename MatrixType> void triangular_rect(const MatrixType& m)
+{
+ typedef const typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
+ typedef Matrix<Scalar, Rows, 1> VectorType;
+ typedef Matrix<Scalar, Rows, Rows> RMatrixType;
+
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2 = MatrixType::Random(rows, cols),
+ m3(rows, cols),
+ m4(rows, cols),
+ r1(rows, cols),
+ r2(rows, cols);
+
+ MatrixType m1up = m1.template triangularView<Upper>();
+ MatrixType m2up = m2.template triangularView<Upper>();
+
+ if (rows>1 && cols>1)
+ {
+ VERIFY(m1up.isUpperTriangular());
+ VERIFY(m2up.transpose().isLowerTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ }
+
+ // test overloaded operator+=
+ r1.setZero();
+ r2.setZero();
+ r1.template triangularView<Upper>() += m1;
+ r2 += m1up;
+ VERIFY_IS_APPROX(r1,r2);
+
+ // test overloaded operator=
+ m1.setZero();
+ m1.template triangularView<Upper>() = 3 * m2;
+ m3 = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Upper>().toDenseMatrix(), m1);
+
+
+ m1.setZero();
+ m1.template triangularView<Lower>() = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<Lower>().toDenseMatrix(), m1);
+
+ m1.setZero();
+ m1.template triangularView<StrictlyUpper>() = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<StrictlyUpper>().toDenseMatrix(), m1);
+
+
+ m1.setZero();
+ m1.template triangularView<StrictlyLower>() = 3 * m2;
+ VERIFY_IS_APPROX(m3.template triangularView<StrictlyLower>().toDenseMatrix(), m1);
+ m1.setRandom();
+ m2 = m1.template triangularView<Upper>();
+ VERIFY(m2.isUpperTriangular());
+ VERIFY(!m2.isLowerTriangular());
+ m2 = m1.template triangularView<StrictlyUpper>();
+ VERIFY(m2.isUpperTriangular());
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ m2 = m1.template triangularView<UnitUpper>();
+ VERIFY(m2.isUpperTriangular());
+ m2.diagonal().array() -= Scalar(1);
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ m2 = m1.template triangularView<Lower>();
+ VERIFY(m2.isLowerTriangular());
+ VERIFY(!m2.isUpperTriangular());
+ m2 = m1.template triangularView<StrictlyLower>();
+ VERIFY(m2.isLowerTriangular());
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ m2 = m1.template triangularView<UnitLower>();
+ VERIFY(m2.isLowerTriangular());
+ m2.diagonal().array() -= Scalar(1);
+ VERIFY(m2.diagonal().isMuchSmallerThan(RealScalar(1)));
+ // test swap
+ m1.setOnes();
+ m2.setZero();
+ m2.template triangularView<Upper>().swap(m1);
+ m3.setZero();
+ m3.template triangularView<Upper>().setOnes();
+ VERIFY_IS_APPROX(m2,m3);
+}
+
+void bug_159()
+{
+ Matrix3d m = Matrix3d::Random().triangularView<Lower>();
+ EIGEN_UNUSED_VARIABLE(m)
+}
+
+void test_triangular()
+{
+ int maxsize = (std::min)(EIGEN_TEST_MAX_SIZE,20);
+ for(int i = 0; i < g_repeat ; i++)
+ {
+ int r = internal::random<int>(2,maxsize); EIGEN_UNUSED_VARIABLE(r);
+ int c = internal::random<int>(2,maxsize); EIGEN_UNUSED_VARIABLE(c);
+
+ CALL_SUBTEST_1( triangular_square(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( triangular_square(Matrix<float, 2, 2>()) );
+ CALL_SUBTEST_3( triangular_square(Matrix3d()) );
+ CALL_SUBTEST_4( triangular_square(Matrix<std::complex<float>,8, 8>()) );
+ CALL_SUBTEST_5( triangular_square(MatrixXcd(r,r)) );
+ CALL_SUBTEST_6( triangular_square(Matrix<float,Dynamic,Dynamic,RowMajor>(r, r)) );
+
+ CALL_SUBTEST_7( triangular_rect(Matrix<float, 4, 5>()) );
+ CALL_SUBTEST_8( triangular_rect(Matrix<double, 6, 2>()) );
+ CALL_SUBTEST_9( triangular_rect(MatrixXcf(r, c)) );
+ CALL_SUBTEST_5( triangular_rect(MatrixXcd(r, c)) );
+ CALL_SUBTEST_6( triangular_rect(Matrix<float,Dynamic,Dynamic,RowMajor>(r, c)) );
+ }
+
+ CALL_SUBTEST_1( bug_159() );
+}
diff --git a/test/umeyama.cpp b/test/umeyama.cpp
new file mode 100644
index 000000000..b6c9be3a5
--- /dev/null
+++ b/test/umeyama.cpp
@@ -0,0 +1,183 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 Hauke Heibel <hauke.heibel@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/.
+
+#include "main.h"
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <Eigen/LU> // required for MatrixBase::determinant
+#include <Eigen/SVD> // required for SVD
+
+using namespace Eigen;
+
+// Constructs a random matrix from the unitary group U(size).
+template <typename T>
+Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> randMatrixUnitary(int size)
+{
+ typedef T Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
+
+ MatrixType Q;
+
+ int max_tries = 40;
+ double is_unitary = false;
+
+ while (!is_unitary && max_tries > 0)
+ {
+ // initialize random matrix
+ Q = MatrixType::Random(size, size);
+
+ // orthogonalize columns using the Gram-Schmidt algorithm
+ for (int col = 0; col < size; ++col)
+ {
+ typename MatrixType::ColXpr colVec = Q.col(col);
+ for (int prevCol = 0; prevCol < col; ++prevCol)
+ {
+ typename MatrixType::ColXpr prevColVec = Q.col(prevCol);
+ colVec -= colVec.dot(prevColVec)*prevColVec;
+ }
+ Q.col(col) = colVec.normalized();
+ }
+
+ // this additional orthogonalization is not necessary in theory but should enhance
+ // the numerical orthogonality of the matrix
+ for (int row = 0; row < size; ++row)
+ {
+ typename MatrixType::RowXpr rowVec = Q.row(row);
+ for (int prevRow = 0; prevRow < row; ++prevRow)
+ {
+ typename MatrixType::RowXpr prevRowVec = Q.row(prevRow);
+ rowVec -= rowVec.dot(prevRowVec)*prevRowVec;
+ }
+ Q.row(row) = rowVec.normalized();
+ }
+
+ // final check
+ is_unitary = Q.isUnitary();
+ --max_tries;
+ }
+
+ if (max_tries == 0)
+ eigen_assert(false && "randMatrixUnitary: Could not construct unitary matrix!");
+
+ return Q;
+}
+
+// Constructs a random matrix from the special unitary group SU(size).
+template <typename T>
+Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> randMatrixSpecialUnitary(int size)
+{
+ typedef T Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+
+ typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
+
+ // initialize unitary matrix
+ MatrixType Q = randMatrixUnitary<Scalar>(size);
+
+ // tweak the first column to make the determinant be 1
+ Q.col(0) *= internal::conj(Q.determinant());
+
+ return Q;
+}
+
+template <typename MatrixType>
+void run_test(int dim, int num_elements)
+{
+ typedef typename internal::traits<MatrixType>::Scalar Scalar;
+ typedef Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixX;
+ typedef Matrix<Scalar, Eigen::Dynamic, 1> VectorX;
+
+ // MUST be positive because in any other case det(cR_t) may become negative for
+ // odd dimensions!
+ const Scalar c = internal::abs(internal::random<Scalar>());
+
+ MatrixX R = randMatrixSpecialUnitary<Scalar>(dim);
+ VectorX t = Scalar(50)*VectorX::Random(dim,1);
+
+ MatrixX cR_t = MatrixX::Identity(dim+1,dim+1);
+ cR_t.block(0,0,dim,dim) = c*R;
+ cR_t.block(0,dim,dim,1) = t;
+
+ MatrixX src = MatrixX::Random(dim+1, num_elements);
+ src.row(dim) = Matrix<Scalar, 1, Dynamic>::Constant(num_elements, Scalar(1));
+
+ MatrixX dst = cR_t*src;
+
+ MatrixX cR_t_umeyama = umeyama(src.block(0,0,dim,num_elements), dst.block(0,0,dim,num_elements));
+
+ const Scalar error = ( cR_t_umeyama*src - dst ).norm() / dst.norm();
+ VERIFY(error < Scalar(40)*std::numeric_limits<Scalar>::epsilon());
+}
+
+template<typename Scalar, int Dimension>
+void run_fixed_size_test(int num_elements)
+{
+ typedef Matrix<Scalar, Dimension+1, Dynamic> MatrixX;
+ typedef Matrix<Scalar, Dimension+1, Dimension+1> HomMatrix;
+ typedef Matrix<Scalar, Dimension, Dimension> FixedMatrix;
+ typedef Matrix<Scalar, Dimension, 1> FixedVector;
+
+ const int dim = Dimension;
+
+ // MUST be positive because in any other case det(cR_t) may become negative for
+ // odd dimensions!
+ const Scalar c = internal::abs(internal::random<Scalar>());
+
+ FixedMatrix R = randMatrixSpecialUnitary<Scalar>(dim);
+ FixedVector t = Scalar(50)*FixedVector::Random(dim,1);
+
+ HomMatrix cR_t = HomMatrix::Identity(dim+1,dim+1);
+ cR_t.block(0,0,dim,dim) = c*R;
+ cR_t.block(0,dim,dim,1) = t;
+
+ MatrixX src = MatrixX::Random(dim+1, num_elements);
+ src.row(dim) = Matrix<Scalar, 1, Dynamic>::Constant(num_elements, Scalar(1));
+
+ MatrixX dst = cR_t*src;
+
+ Block<MatrixX, Dimension, Dynamic> src_block(src,0,0,dim,num_elements);
+ Block<MatrixX, Dimension, Dynamic> dst_block(dst,0,0,dim,num_elements);
+
+ HomMatrix cR_t_umeyama = umeyama(src_block, dst_block);
+
+ const Scalar error = ( cR_t_umeyama*src - dst ).array().square().sum();
+
+ VERIFY(error < Scalar(10)*std::numeric_limits<Scalar>::epsilon());
+}
+
+void test_umeyama()
+{
+ for (int i=0; i<g_repeat; ++i)
+ {
+ const int num_elements = internal::random<int>(40,500);
+
+ // works also for dimensions bigger than 3...
+ for (int dim=2; dim<8; ++dim)
+ {
+ CALL_SUBTEST_1(run_test<MatrixXd>(dim, num_elements));
+ CALL_SUBTEST_2(run_test<MatrixXf>(dim, num_elements));
+ }
+
+ CALL_SUBTEST_3((run_fixed_size_test<float, 2>(num_elements)));
+ CALL_SUBTEST_4((run_fixed_size_test<float, 3>(num_elements)));
+ CALL_SUBTEST_5((run_fixed_size_test<float, 4>(num_elements)));
+
+ CALL_SUBTEST_6((run_fixed_size_test<double, 2>(num_elements)));
+ CALL_SUBTEST_7((run_fixed_size_test<double, 3>(num_elements)));
+ CALL_SUBTEST_8((run_fixed_size_test<double, 4>(num_elements)));
+ }
+
+ // Those two calls don't compile and result in meaningful error messages!
+ // umeyama(MatrixXcf(),MatrixXcf());
+ // umeyama(MatrixXcd(),MatrixXcd());
+}
diff --git a/test/umfpack_support.cpp b/test/umfpack_support.cpp
new file mode 100644
index 000000000..9eb84c14b
--- /dev/null
+++ b/test/umfpack_support.cpp
@@ -0,0 +1,31 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 Gael Guennebaud <g.gael@free.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/.
+
+#include "sparse_solver.h"
+
+#include <Eigen/UmfPackSupport>
+
+template<typename T> void test_umfpack_support_T()
+{
+ UmfPackLU<SparseMatrix<T, ColMajor> > umfpack_colmajor;
+ UmfPackLU<SparseMatrix<T, RowMajor> > umfpack_rowmajor;
+
+ check_sparse_square_solving(umfpack_colmajor);
+ check_sparse_square_solving(umfpack_rowmajor);
+
+ check_sparse_square_determinant(umfpack_colmajor);
+ check_sparse_square_determinant(umfpack_rowmajor);
+}
+
+void test_umfpack_support()
+{
+ CALL_SUBTEST_1(test_umfpack_support_T<double>());
+ CALL_SUBTEST_2(test_umfpack_support_T<std::complex<double> >());
+}
+
diff --git a/test/unalignedassert.cpp b/test/unalignedassert.cpp
new file mode 100644
index 000000000..601dbf214
--- /dev/null
+++ b/test/unalignedassert.cpp
@@ -0,0 +1,127 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+struct TestNew1
+{
+ MatrixXd m; // good: m will allocate its own array, taking care of alignment.
+ TestNew1() : m(20,20) {}
+};
+
+struct TestNew2
+{
+ Matrix3d m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be 16-byte aligned,
+ // 8-byte alignment is good enough here, which we'll get automatically
+};
+
+struct TestNew3
+{
+ Vector2f m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be 16-byte aligned
+};
+
+struct TestNew4
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ Vector2d m;
+ float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects
+};
+
+struct TestNew5
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ float f; // try the f at first -- the EIGEN_ALIGN16 attribute of m should make that still work
+ Matrix4f m;
+};
+
+struct TestNew6
+{
+ Matrix<float,2,2,DontAlign> m; // good: no alignment requested
+ float f;
+};
+
+template<bool Align> struct Depends
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align)
+ Vector2d m;
+ float f;
+};
+
+template<typename T>
+void check_unalignedassert_good()
+{
+ T *x, *y;
+ x = new T;
+ delete x;
+ y = new T[2];
+ delete[] y;
+}
+
+#if EIGEN_ALIGN_STATICALLY
+template<typename T>
+void construct_at_boundary(int boundary)
+{
+ char buf[sizeof(T)+256];
+ size_t _buf = reinterpret_cast<size_t>(buf);
+ _buf += (16 - (_buf % 16)); // make 16-byte aligned
+ _buf += boundary; // make exact boundary-aligned
+ T *x = ::new(reinterpret_cast<void*>(_buf)) T;
+ x[0].setZero(); // just in order to silence warnings
+ x->~T();
+}
+#endif
+
+void unalignedassert()
+{
+ #if EIGEN_ALIGN_STATICALLY
+ construct_at_boundary<Vector2f>(4);
+ construct_at_boundary<Vector3f>(4);
+ construct_at_boundary<Vector4f>(16);
+ construct_at_boundary<Matrix2f>(16);
+ construct_at_boundary<Matrix3f>(4);
+ construct_at_boundary<Matrix4f>(16);
+
+ construct_at_boundary<Vector2d>(16);
+ construct_at_boundary<Vector3d>(4);
+ construct_at_boundary<Vector4d>(16);
+ construct_at_boundary<Matrix2d>(16);
+ construct_at_boundary<Matrix3d>(4);
+ construct_at_boundary<Matrix4d>(16);
+
+ construct_at_boundary<Vector2cf>(16);
+ construct_at_boundary<Vector3cf>(4);
+ construct_at_boundary<Vector2cd>(16);
+ construct_at_boundary<Vector3cd>(16);
+ #endif
+
+ check_unalignedassert_good<TestNew1>();
+ check_unalignedassert_good<TestNew2>();
+ check_unalignedassert_good<TestNew3>();
+
+ check_unalignedassert_good<TestNew4>();
+ check_unalignedassert_good<TestNew5>();
+ check_unalignedassert_good<TestNew6>();
+ check_unalignedassert_good<Depends<true> >();
+
+#if EIGEN_ALIGN_STATICALLY
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector4f>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Matrix4f>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector2d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector4d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Matrix2d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Matrix4d>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector2cf>(8));
+ VERIFY_RAISES_ASSERT(construct_at_boundary<Vector2cd>(8));
+#endif
+}
+
+void test_unalignedassert()
+{
+ CALL_SUBTEST(unalignedassert());
+}
diff --git a/test/unalignedcount.cpp b/test/unalignedcount.cpp
new file mode 100644
index 000000000..5451159e6
--- /dev/null
+++ b/test/unalignedcount.cpp
@@ -0,0 +1,44 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009 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/.
+
+static int nb_load;
+static int nb_loadu;
+static int nb_store;
+static int nb_storeu;
+
+#define EIGEN_DEBUG_ALIGNED_LOAD { nb_load++; }
+#define EIGEN_DEBUG_UNALIGNED_LOAD { nb_loadu++; }
+#define EIGEN_DEBUG_ALIGNED_STORE { nb_store++; }
+#define EIGEN_DEBUG_UNALIGNED_STORE { nb_storeu++; }
+
+#define VERIFY_ALIGNED_UNALIGNED_COUNT(XPR,AL,UL,AS,US) {\
+ nb_load = nb_loadu = nb_store = nb_storeu = 0; \
+ XPR; \
+ if(!(nb_load==AL && nb_loadu==UL && nb_store==AS && nb_storeu==US)) \
+ std::cerr << " >> " << nb_load << ", " << nb_loadu << ", " << nb_store << ", " << nb_storeu << "\n"; \
+ VERIFY( (#XPR) && nb_load==AL && nb_loadu==UL && nb_store==AS && nb_storeu==US ); \
+ }
+
+
+#include "main.h"
+
+void test_unalignedcount()
+{
+ #ifdef EIGEN_VECTORIZE_SSE
+ VectorXf a(40), b(40);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a += b, 20, 0, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) += b.segment(0,40), 10, 10, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) -= b.segment(0,40), 10, 10, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) *= 3.5, 10, 0, 10, 0);
+ VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) /= 3.5, 10, 0, 10, 0);
+ #else
+ // The following line is to eliminate "variable not used" warnings
+ nb_load = nb_loadu = nb_store = nb_storeu = 0;
+ #endif
+}
diff --git a/test/upperbidiagonalization.cpp b/test/upperbidiagonalization.cpp
new file mode 100644
index 000000000..db6ce383e
--- /dev/null
+++ b/test/upperbidiagonalization.cpp
@@ -0,0 +1,41 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 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/.
+
+#include "main.h"
+#include <Eigen/SVD>
+
+template<typename MatrixType> void upperbidiag(const MatrixType& m)
+{
+ const typename MatrixType::Index rows = m.rows();
+ const typename MatrixType::Index cols = m.cols();
+
+ typedef typename MatrixType::Scalar Scalar;
+ typedef Matrix<typename MatrixType::RealScalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> RealMatrixType;
+
+ MatrixType a = MatrixType::Random(rows,cols);
+ internal::UpperBidiagonalization<MatrixType> ubd(a);
+ RealMatrixType b(rows, cols);
+ b.setZero();
+ b.block(0,0,cols,cols) = ubd.bidiagonal();
+ MatrixType c = ubd.householderU() * b * ubd.householderV().adjoint();
+ VERIFY_IS_APPROX(a,c);
+}
+
+void test_upperbidiagonalization()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( upperbidiag(MatrixXf(3,3)) );
+ CALL_SUBTEST_2( upperbidiag(MatrixXd(17,12)) );
+ CALL_SUBTEST_3( upperbidiag(MatrixXcf(20,20)) );
+ CALL_SUBTEST_4( upperbidiag(MatrixXcd(16,15)) );
+ CALL_SUBTEST_5( upperbidiag(Matrix<float,6,4>()) );
+ CALL_SUBTEST_6( upperbidiag(Matrix<float,5,5>()) );
+ CALL_SUBTEST_7( upperbidiag(Matrix<double,4,3>()) );
+ }
+}
diff --git a/test/vectorization_logic.cpp b/test/vectorization_logic.cpp
new file mode 100644
index 000000000..aee68a87f
--- /dev/null
+++ b/test/vectorization_logic.cpp
@@ -0,0 +1,235 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#define EIGEN_DEBUG_ASSIGN
+#include "main.h"
+#include <typeinfo>
+
+std::string demangle_traversal(int t)
+{
+ if(t==DefaultTraversal) return "DefaultTraversal";
+ if(t==LinearTraversal) return "LinearTraversal";
+ if(t==InnerVectorizedTraversal) return "InnerVectorizedTraversal";
+ if(t==LinearVectorizedTraversal) return "LinearVectorizedTraversal";
+ if(t==SliceVectorizedTraversal) return "SliceVectorizedTraversal";
+ return "?";
+}
+std::string demangle_unrolling(int t)
+{
+ if(t==NoUnrolling) return "NoUnrolling";
+ if(t==InnerUnrolling) return "InnerUnrolling";
+ if(t==CompleteUnrolling) return "CompleteUnrolling";
+ return "?";
+}
+
+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;
+ if(!res)
+ {
+ std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
+ << " got " << demangle_traversal(internal::assign_traits<Dst,Src>::Traversal) << "\n";
+ std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
+ << " got " << demangle_unrolling(internal::assign_traits<Dst,Src>::Unrolling) << "\n";
+ }
+ return res;
+}
+
+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;
+ if(!res)
+ {
+ std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
+ << " got " << demangle_traversal(internal::assign_traits<Dst,Src>::Traversal) << "\n";
+ std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
+ << " got " << demangle_unrolling(internal::assign_traits<Dst,Src>::Unrolling) << "\n";
+ }
+ return res;
+}
+
+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;
+ bool res = traits::Traversal==traversal && traits::Unrolling==unrolling;
+ if(!res)
+ {
+ std::cerr << " Expected Traversal == " << demangle_traversal(traversal)
+ << " got " << demangle_traversal(traits::Traversal) << "\n";
+ std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling)
+ << " got " << demangle_unrolling(traits::Unrolling) << "\n";
+ }
+ return res;
+}
+
+template<typename Scalar, bool Enable = internal::packet_traits<Scalar>::Vectorizable> struct vectorization_logic
+{
+ enum {
+ PacketSize = internal::packet_traits<Scalar>::size
+ };
+ static void run()
+ {
+
+ typedef Matrix<Scalar,PacketSize,1> Vector1;
+ typedef Matrix<Scalar,Dynamic,1> VectorX;
+ typedef Matrix<Scalar,Dynamic,Dynamic> MatrixXX;
+ typedef Matrix<Scalar,PacketSize,PacketSize> Matrix11;
+ typedef Matrix<Scalar,2*PacketSize,2*PacketSize> Matrix22;
+ typedef Matrix<Scalar,(Matrix11::Flags&RowMajorBit)?16:4*PacketSize,(Matrix11::Flags&RowMajorBit)?4*PacketSize:16> Matrix44;
+ typedef Matrix<Scalar,(Matrix11::Flags&RowMajorBit)?16:4*PacketSize,(Matrix11::Flags&RowMajorBit)?4*PacketSize:16,DontAlign|EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION> Matrix44u;
+ typedef Matrix<Scalar,4*PacketSize,16,ColMajor> Matrix44c;
+ typedef Matrix<Scalar,4*PacketSize,16,RowMajor> Matrix44r;
+
+ typedef Matrix<Scalar,
+ (PacketSize==8 ? 4 : PacketSize==4 ? 2 : PacketSize==2 ? 1 : /*PacketSize==1 ?*/ 1),
+ (PacketSize==8 ? 2 : PacketSize==4 ? 2 : PacketSize==2 ? 2 : /*PacketSize==1 ?*/ 1)
+ > Matrix1;
+
+ typedef Matrix<Scalar,
+ (PacketSize==8 ? 4 : PacketSize==4 ? 2 : PacketSize==2 ? 1 : /*PacketSize==1 ?*/ 1),
+ (PacketSize==8 ? 2 : PacketSize==4 ? 2 : PacketSize==2 ? 2 : /*PacketSize==1 ?*/ 1),
+ DontAlign|((Matrix1::Flags&RowMajorBit)?RowMajor:ColMajor)> Matrix1u;
+
+ // this type is made such that it can only be vectorized when viewed as a linear 1D vector
+ typedef Matrix<Scalar,
+ (PacketSize==8 ? 4 : PacketSize==4 ? 6 : PacketSize==2 ? ((Matrix11::Flags&RowMajorBit)?2:3) : /*PacketSize==1 ?*/ 1),
+ (PacketSize==8 ? 6 : PacketSize==4 ? 2 : PacketSize==2 ? ((Matrix11::Flags&RowMajorBit)?3:2) : /*PacketSize==1 ?*/ 3)
+ > Matrix3;
+
+ #if !EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT
+ VERIFY(test_assign(Vector1(),Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1()+Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1().template cast<Scalar>(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+
+ VERIFY(test_assign(Vector1(),Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1()+Vector1(),
+ InnerVectorizedTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix44(),Matrix44()+Matrix44(),
+ InnerVectorizedTraversal,InnerUnrolling));
+
+ VERIFY(test_assign(Matrix44u(),Matrix44()+Matrix44(),
+ LinearTraversal,NoUnrolling));
+
+ VERIFY(test_assign(Matrix1u(),Matrix1()+Matrix1(),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix44c().col(1),Matrix44c().col(2)+Matrix44c().col(3),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix44r().row(2),Matrix44r().row(1)+Matrix44r().row(1),
+ InnerVectorizedTraversal,CompleteUnrolling));
+
+ if(PacketSize>1)
+ {
+ typedef Matrix<Scalar,3,3,ColMajor> Matrix33c;
+ VERIFY(test_assign(Matrix33c().row(2),Matrix33c().row(1)+Matrix33c().row(1),
+ LinearTraversal,CompleteUnrolling));
+ VERIFY(test_assign(Matrix33c().col(0),Matrix33c().col(1)+Matrix33c().col(1),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix3(),Matrix3().cwiseQuotient(Matrix3()),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_assign(Matrix<Scalar,17,17>(),Matrix<Scalar,17,17>()+Matrix<Scalar,17,17>(),
+ LinearTraversal,NoUnrolling));
+
+ VERIFY(test_assign(Matrix11(),Matrix<Scalar,17,17>().template block<PacketSize,PacketSize>(2,3)+Matrix<Scalar,17,17>().template block<PacketSize,PacketSize>(10,4),
+ DefaultTraversal,CompleteUnrolling));
+ }
+
+ VERIFY(test_redux(Matrix3(),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix44(),
+ LinearVectorizedTraversal,NoUnrolling));
+
+ VERIFY(test_redux(Matrix44().template block<(Matrix1::Flags&RowMajorBit)?4:PacketSize,(Matrix1::Flags&RowMajorBit)?PacketSize:4>(1,2),
+ DefaultTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix44c().template block<2*PacketSize,1>(1,2),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix44r().template block<1,2*PacketSize>(2,1),
+ LinearVectorizedTraversal,CompleteUnrolling));
+
+ VERIFY((test_assign<
+ Map<Matrix22, Aligned, OuterStride<3*PacketSize> >,
+ Matrix22
+ >(InnerVectorizedTraversal,CompleteUnrolling)));
+
+ VERIFY((test_assign<
+ Map<Matrix22, Aligned, InnerStride<3*PacketSize> >,
+ Matrix22
+ >(DefaultTraversal,CompleteUnrolling)));
+
+ VERIFY((test_assign(Matrix11(), Matrix11()*Matrix11(), InnerVectorizedTraversal, CompleteUnrolling)));
+ #endif
+
+ VERIFY(test_assign(MatrixXX(10,10),MatrixXX(20,20).block(10,10,2,3),
+ SliceVectorizedTraversal,NoUnrolling));
+
+ VERIFY(test_redux(VectorX(10),
+ LinearVectorizedTraversal,NoUnrolling));
+
+
+ }
+};
+
+template<typename Scalar> struct vectorization_logic<Scalar,false>
+{
+ static void run() {}
+};
+
+void test_vectorization_logic()
+{
+
+#ifdef EIGEN_VECTORIZE
+
+ CALL_SUBTEST( vectorization_logic<float>::run() );
+ CALL_SUBTEST( vectorization_logic<double>::run() );
+ CALL_SUBTEST( vectorization_logic<std::complex<float> >::run() );
+ CALL_SUBTEST( vectorization_logic<std::complex<double> >::run() );
+
+ if(internal::packet_traits<float>::Vectorizable)
+ {
+ VERIFY(test_assign(Matrix<float,3,3>(),Matrix<float,3,3>()+Matrix<float,3,3>(),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix<float,5,2>(),
+ DefaultTraversal,CompleteUnrolling));
+ }
+
+ if(internal::packet_traits<double>::Vectorizable)
+ {
+ VERIFY(test_assign(Matrix<double,3,3>(),Matrix<double,3,3>()+Matrix<double,3,3>(),
+ LinearTraversal,CompleteUnrolling));
+
+ VERIFY(test_redux(Matrix<double,7,3>(),
+ DefaultTraversal,CompleteUnrolling));
+ }
+#endif // EIGEN_VECTORIZE
+
+}
diff --git a/test/vectorwiseop.cpp b/test/vectorwiseop.cpp
new file mode 100644
index 000000000..b938e3957
--- /dev/null
+++ b/test/vectorwiseop.cpp
@@ -0,0 +1,172 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+#define EIGEN_NO_STATIC_ASSERT
+
+#include "main.h"
+
+template<typename ArrayType> void vectorwiseop_array(const ArrayType& m)
+{
+ typedef typename ArrayType::Index Index;
+ typedef typename ArrayType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Array<Scalar, ArrayType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Array<Scalar, 1, ArrayType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ ArrayType m1 = ArrayType::Random(rows, cols),
+ m2(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType colvec = ColVectorType::Random(rows);
+ RowVectorType rowvec = RowVectorType::Random(cols);
+
+ // test addition
+
+ m2 = m1;
+ m2.colwise() += colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() + colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() += colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() + colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() += rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() + rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) + rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose());
+
+ // test substraction
+
+ m2 = m1;
+ m2.colwise() -= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() - colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() -= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() - colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() -= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() - rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) - rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose());
+
+ // test multiplication
+
+ m2 = m1;
+ m2.colwise() *= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() * colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) * colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() *= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() * colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() *= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() * rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) * rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() *= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() * rowvec.transpose());
+
+ // test quotient
+
+ m2 = m1;
+ m2.colwise() /= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() / colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) / colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() /= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() / colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() /= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() / rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) / rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() /= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() / rowvec.transpose());
+}
+
+template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
+{
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
+ typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
+
+ Index rows = m.rows();
+ Index cols = m.cols();
+ Index r = internal::random<Index>(0, rows-1),
+ c = internal::random<Index>(0, cols-1);
+
+ MatrixType m1 = MatrixType::Random(rows, cols),
+ m2(rows, cols),
+ m3(rows, cols);
+
+ ColVectorType colvec = ColVectorType::Random(rows);
+ RowVectorType rowvec = RowVectorType::Random(cols);
+
+ // test addition
+
+ m2 = m1;
+ m2.colwise() += colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() + colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() += colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() + colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() += rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() + rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) + rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose());
+
+ // test substraction
+
+ m2 = m1;
+ m2.colwise() -= colvec;
+ VERIFY_IS_APPROX(m2, m1.colwise() - colvec);
+ VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec);
+
+ VERIFY_RAISES_ASSERT(m2.colwise() -= colvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.colwise() - colvec.transpose());
+
+ m2 = m1;
+ m2.rowwise() -= rowvec;
+ VERIFY_IS_APPROX(m2, m1.rowwise() - rowvec);
+ VERIFY_IS_APPROX(m2.row(r), m1.row(r) - rowvec);
+
+ VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose());
+ VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose());
+}
+
+void test_vectorwiseop()
+{
+ CALL_SUBTEST_1(vectorwiseop_array(Array22cd()));
+ CALL_SUBTEST_2(vectorwiseop_array(Array<double, 3, 2>()));
+ CALL_SUBTEST_3(vectorwiseop_array(ArrayXXf(3, 4)));
+ CALL_SUBTEST_4(vectorwiseop_matrix(Matrix4cf()));
+ CALL_SUBTEST_5(vectorwiseop_matrix(Matrix<float,4,5>()));
+ CALL_SUBTEST_6(vectorwiseop_matrix(MatrixXd(7,2)));
+}
diff --git a/test/visitor.cpp b/test/visitor.cpp
new file mode 100644
index 000000000..087306258
--- /dev/null
+++ b/test/visitor.cpp
@@ -0,0 +1,118 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2008 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void matrixVisitor(const MatrixType& p)
+{
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+
+ Index rows = p.rows();
+ Index cols = p.cols();
+
+ // construct a random matrix where all coefficients are different
+ MatrixType m;
+ m = MatrixType::Random(rows, cols);
+ for(Index i = 0; i < m.size(); i++)
+ for(Index i2 = 0; i2 < i; i2++)
+ while(m(i) == m(i2)) // yes, ==
+ m(i) = internal::random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ Index minrow=0,mincol=0,maxrow=0,maxcol=0;
+ for(Index j = 0; j < cols; j++)
+ for(Index i = 0; i < rows; i++)
+ {
+ if(m(i,j) < minc)
+ {
+ minc = m(i,j);
+ minrow = i;
+ mincol = j;
+ }
+ if(m(i,j) > maxc)
+ {
+ maxc = m(i,j);
+ maxrow = i;
+ maxcol = j;
+ }
+ }
+ Index eigen_minrow, eigen_mincol, eigen_maxrow, eigen_maxcol;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = m.minCoeff(&eigen_minrow,&eigen_mincol);
+ eigen_maxc = m.maxCoeff(&eigen_maxrow,&eigen_maxcol);
+ VERIFY(minrow == eigen_minrow);
+ VERIFY(maxrow == eigen_maxrow);
+ VERIFY(mincol == eigen_mincol);
+ VERIFY(maxcol == eigen_maxcol);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, m.minCoeff());
+ VERIFY_IS_APPROX(maxc, m.maxCoeff());
+}
+
+template<typename VectorType> void vectorVisitor(const VectorType& w)
+{
+ typedef typename VectorType::Scalar Scalar;
+ typedef typename VectorType::Index Index;
+
+ Index size = w.size();
+
+ // construct a random vector where all coefficients are different
+ VectorType v;
+ v = VectorType::Random(size);
+ for(Index i = 0; i < size; i++)
+ for(Index i2 = 0; i2 < i; i2++)
+ while(v(i) == v(i2)) // yes, ==
+ v(i) = internal::random<Scalar>();
+
+ Scalar minc = Scalar(1000), maxc = Scalar(-1000);
+ Index minidx=0,maxidx=0;
+ for(Index i = 0; i < size; i++)
+ {
+ if(v(i) < minc)
+ {
+ minc = v(i);
+ minidx = i;
+ }
+ if(v(i) > maxc)
+ {
+ maxc = v(i);
+ maxidx = i;
+ }
+ }
+ Index eigen_minidx, eigen_maxidx;
+ Scalar eigen_minc, eigen_maxc;
+ eigen_minc = v.minCoeff(&eigen_minidx);
+ eigen_maxc = v.maxCoeff(&eigen_maxidx);
+ VERIFY(minidx == eigen_minidx);
+ VERIFY(maxidx == eigen_maxidx);
+ VERIFY_IS_APPROX(minc, eigen_minc);
+ VERIFY_IS_APPROX(maxc, eigen_maxc);
+ VERIFY_IS_APPROX(minc, v.minCoeff());
+ VERIFY_IS_APPROX(maxc, v.maxCoeff());
+}
+
+void test_visitor()
+{
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_1( matrixVisitor(Matrix<float, 1, 1>()) );
+ CALL_SUBTEST_2( matrixVisitor(Matrix2f()) );
+ CALL_SUBTEST_3( matrixVisitor(Matrix4d()) );
+ CALL_SUBTEST_4( matrixVisitor(MatrixXd(8, 12)) );
+ CALL_SUBTEST_5( matrixVisitor(Matrix<double,Dynamic,Dynamic,RowMajor>(20, 20)) );
+ CALL_SUBTEST_6( matrixVisitor(MatrixXi(8, 12)) );
+ }
+ for(int i = 0; i < g_repeat; i++) {
+ CALL_SUBTEST_7( vectorVisitor(Vector4f()) );
+ CALL_SUBTEST_8( vectorVisitor(VectorXd(10)) );
+ CALL_SUBTEST_9( vectorVisitor(RowVectorXd(10)) );
+ CALL_SUBTEST_10( vectorVisitor(VectorXf(33)) );
+ }
+}
diff --git a/test/zerosized.cpp b/test/zerosized.cpp
new file mode 100644
index 000000000..6905e584e
--- /dev/null
+++ b/test/zerosized.cpp
@@ -0,0 +1,59 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2011 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/.
+
+#include "main.h"
+
+template<typename MatrixType> void zeroSizedMatrix()
+{
+ MatrixType t1;
+
+ if (MatrixType::SizeAtCompileTime == Dynamic)
+ {
+ if (MatrixType::RowsAtCompileTime == Dynamic)
+ VERIFY(t1.rows() == 0);
+ if (MatrixType::ColsAtCompileTime == Dynamic)
+ VERIFY(t1.cols() == 0);
+
+ if (MatrixType::RowsAtCompileTime == Dynamic && MatrixType::ColsAtCompileTime == Dynamic)
+ {
+ MatrixType t2(0, 0);
+ VERIFY(t2.rows() == 0);
+ VERIFY(t2.cols() == 0);
+ }
+ }
+}
+
+template<typename VectorType> void zeroSizedVector()
+{
+ VectorType t1;
+
+ if (VectorType::SizeAtCompileTime == Dynamic)
+ {
+ VERIFY(t1.size() == 0);
+ VectorType t2(DenseIndex(0)); // DenseIndex disambiguates with 0-the-null-pointer (error with gcc 4.4 and MSVC8)
+ VERIFY(t2.size() == 0);
+ }
+}
+
+void test_zerosized()
+{
+ zeroSizedMatrix<Matrix2d>();
+ zeroSizedMatrix<Matrix3i>();
+ zeroSizedMatrix<Matrix<float, 2, Dynamic> >();
+ zeroSizedMatrix<MatrixXf>();
+ zeroSizedMatrix<Matrix<float, 0, 0> >();
+ zeroSizedMatrix<Matrix<float, Dynamic, 0, 0, 0, 0> >();
+ zeroSizedMatrix<Matrix<float, 0, Dynamic, 0, 0, 0> >();
+ zeroSizedMatrix<Matrix<float, Dynamic, Dynamic, 0, 0, 0> >();
+
+ zeroSizedVector<Vector2d>();
+ zeroSizedVector<Vector3i>();
+ zeroSizedVector<VectorXf>();
+ zeroSizedVector<Matrix<float, 0, 1> >();
+}