ADD: added other eigen lib
This commit is contained in:
@@ -32,14 +32,12 @@ class AnnoyingScalar
|
||||
{
|
||||
public:
|
||||
AnnoyingScalar() { init(); *v = 0; }
|
||||
AnnoyingScalar(long double _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(double _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(long double _v) { init(); *v = static_cast<float>(_v); }
|
||||
AnnoyingScalar(double _v) { init(); *v = static_cast<float>(_v); }
|
||||
AnnoyingScalar(float _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(int _v) { init(); *v = _v; }
|
||||
AnnoyingScalar(long _v) { init(); *v = _v; }
|
||||
#if EIGEN_HAS_CXX11
|
||||
AnnoyingScalar(long long _v) { init(); *v = _v; }
|
||||
#endif
|
||||
AnnoyingScalar(int _v) { init(); *v = static_cast<float>(_v); }
|
||||
AnnoyingScalar(long _v) { init(); *v = static_cast<float>(_v); }
|
||||
AnnoyingScalar(long long _v) { init(); *v = static_cast<float>(_v); }
|
||||
AnnoyingScalar(const AnnoyingScalar& other) { init(); *v = *(other.v); }
|
||||
~AnnoyingScalar() {
|
||||
if(v!=&data)
|
||||
@@ -83,8 +81,8 @@ class AnnoyingScalar
|
||||
AnnoyingScalar& operator/=(const AnnoyingScalar& other) { *v /= *other.v; return *this; }
|
||||
AnnoyingScalar& operator= (const AnnoyingScalar& other) { *v = *other.v; return *this; }
|
||||
|
||||
bool operator==(const AnnoyingScalar& other) const { return *v == *other.v; }
|
||||
bool operator!=(const AnnoyingScalar& other) const { return *v != *other.v; }
|
||||
bool operator==(const AnnoyingScalar& other) const { return numext::equal_strict(*v, *other.v); }
|
||||
bool operator!=(const AnnoyingScalar& other) const { return numext::not_equal_strict(*v, *other.v); }
|
||||
bool operator<=(const AnnoyingScalar& other) const { return *v <= *other.v; }
|
||||
bool operator< (const AnnoyingScalar& other) const { return *v < *other.v; }
|
||||
bool operator>=(const AnnoyingScalar& other) const { return *v >= *other.v; }
|
||||
|
||||
@@ -42,45 +42,53 @@ endif()
|
||||
set(SPARSE_LIBS " ")
|
||||
|
||||
find_package(CHOLMOD)
|
||||
if(CHOLMOD_FOUND)
|
||||
if(CHOLMOD_FOUND AND EIGEN_BUILD_BLAS AND EIGEN_BUILD_LAPACK)
|
||||
add_definitions("-DEIGEN_CHOLMOD_SUPPORT")
|
||||
include_directories(${CHOLMOD_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES} ${EIGEN_BLAS_LIBRARIES} ${EIGEN_LAPACK_LIBRARIES})
|
||||
set(CHOLMOD_ALL_LIBS ${CHOLMOD_LIBRARIES} ${EIGEN_BLAS_LIBRARIES} ${EIGEN_LAPACK_LIBRARIES})
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "CHOLMOD, ")
|
||||
|
||||
ei_add_test(cholmod_support "" "${CHOLMOD_ALL_LIBS}")
|
||||
else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "CHOLMOD, ")
|
||||
endif()
|
||||
|
||||
find_package(UMFPACK)
|
||||
if(UMFPACK_FOUND)
|
||||
if(UMFPACK_FOUND AND EIGEN_BUILD_BLAS)
|
||||
add_definitions("-DEIGEN_UMFPACK_SUPPORT")
|
||||
include_directories(${UMFPACK_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES} ${EIGEN_BLAS_LIBRARIES})
|
||||
set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${EIGEN_BLAS_LIBRARIES})
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "UMFPACK, ")
|
||||
|
||||
ei_add_test(umfpack_support "" "${UMFPACK_ALL_LIBS}")
|
||||
else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "UMFPACK, ")
|
||||
endif()
|
||||
|
||||
find_package(KLU)
|
||||
if(KLU_FOUND)
|
||||
if(KLU_FOUND AND EIGEN_BUILD_BLAS)
|
||||
add_definitions("-DEIGEN_KLU_SUPPORT")
|
||||
include_directories(${KLU_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${KLU_LIBRARIES} ${EIGEN_BLAS_LIBRARIES})
|
||||
set(KLU_ALL_LIBS ${KLU_LIBRARIES} ${EIGEN_BLAS_LIBRARIES})
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "KLU, ")
|
||||
|
||||
ei_add_test(klu_support "" "${KLU_ALL_LIBS}")
|
||||
else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "KLU, ")
|
||||
endif()
|
||||
|
||||
find_package(SuperLU 4.0)
|
||||
if(SuperLU_FOUND)
|
||||
if(SuperLU_FOUND AND EIGEN_BUILD_BLAS)
|
||||
add_definitions("-DEIGEN_SUPERLU_SUPPORT")
|
||||
include_directories(${SUPERLU_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES} ${EIGEN_BLAS_LIBRARIES})
|
||||
set(SUPERLU_ALL_LIBS ${SUPERLU_LIBRARIES} ${EIGEN_BLAS_LIBRARIES})
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "SuperLU, ")
|
||||
|
||||
ei_add_test(superlu_support "" "${SUPERLU_ALL_LIBS}")
|
||||
else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "SuperLU, ")
|
||||
endif()
|
||||
@@ -124,7 +132,7 @@ else()
|
||||
endif()
|
||||
|
||||
find_package(SPQR)
|
||||
if(SPQR_FOUND AND CHOLMOD_FOUND AND (EIGEN_Fortran_COMPILER_WORKS OR LAPACK_FOUND) )
|
||||
if(SPQR_FOUND AND CHOLMOD_FOUND AND EIGEN_BUILD_BLAS AND EIGEN_BUILD_LAPACK AND (EIGEN_Fortran_COMPILER_WORKS OR LAPACK_FOUND) )
|
||||
add_definitions("-DEIGEN_SPQR_SUPPORT")
|
||||
include_directories(${SPQR_INCLUDES})
|
||||
set(SPQR_ALL_LIBS ${SPQR_LIBRARIES} ${CHOLMOD_LIBRARIES} ${EIGEN_LAPACK_LIBRARIES} ${EIGEN_BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
|
||||
@@ -134,6 +142,17 @@ else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "SPQR, ")
|
||||
endif()
|
||||
|
||||
find_package(Accelerate)
|
||||
if(Accelerate_FOUND)
|
||||
add_definitions("-DEIGEN_ACCELERATE_SUPPORT")
|
||||
include_directories(${Accelerate_INCLUDES})
|
||||
set(SPARSE_LIBS ${SPARSE_LIBS} ${Accelerate_LIBRARIES})
|
||||
set(Accelerate_ALL_LIBS ${Accelerate_LIBRARIES})
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "Accelerate, ")
|
||||
else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "Accelerate, ")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_NOQT "Disable Qt support in unit tests" OFF)
|
||||
if(NOT EIGEN_TEST_NOQT)
|
||||
find_package(Qt4)
|
||||
@@ -166,6 +185,7 @@ ei_add_test(io)
|
||||
ei_add_test(packetmath "-DEIGEN_FAST_MATH=1")
|
||||
ei_add_test(vectorization_logic)
|
||||
ei_add_test(basicstuff)
|
||||
ei_add_test(constexpr)
|
||||
ei_add_test(constructor)
|
||||
ei_add_test(linearstructure)
|
||||
ei_add_test(integer_types)
|
||||
@@ -187,6 +207,7 @@ ei_add_test(product_small)
|
||||
ei_add_test(product_large)
|
||||
ei_add_test(product_extra)
|
||||
ei_add_test(diagonalmatrices)
|
||||
ei_add_test(skew_symmetric_matrix3)
|
||||
ei_add_test(adjoint)
|
||||
ei_add_test(diagonal)
|
||||
ei_add_test(miscmatrices)
|
||||
@@ -194,6 +215,7 @@ ei_add_test(commainitializer)
|
||||
ei_add_test(smallvectors)
|
||||
ei_add_test(mapped_matrix)
|
||||
ei_add_test(mapstride)
|
||||
ei_add_test(unaryviewstride)
|
||||
ei_add_test(mapstaticmethods)
|
||||
ei_add_test(array_cwise)
|
||||
ei_add_test(array_for_matrix)
|
||||
@@ -285,10 +307,11 @@ ei_add_test(array_of_string)
|
||||
ei_add_test(num_dimensions)
|
||||
ei_add_test(stl_iterators)
|
||||
ei_add_test(blasutil)
|
||||
if(EIGEN_TEST_CXX11)
|
||||
ei_add_test(initializer_list_construction)
|
||||
ei_add_test(diagonal_matrix_variadic_ctor)
|
||||
endif()
|
||||
ei_add_test(random_matrix)
|
||||
ei_add_test(initializer_list_construction)
|
||||
ei_add_test(diagonal_matrix_variadic_ctor)
|
||||
ei_add_test(serializer)
|
||||
ei_add_test(tuple_test)
|
||||
|
||||
add_executable(bug1213 bug1213.cpp bug1213_main.cpp)
|
||||
|
||||
@@ -302,7 +325,7 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ei_add_test(fastmath " ${EIGEN_FASTMATH_FLAGS} ")
|
||||
ei_add_test(fastmath "${EIGEN_FASTMATH_FLAGS}")
|
||||
|
||||
# # ei_add_test(denseLM)
|
||||
|
||||
@@ -310,22 +333,6 @@ if(QT4_FOUND)
|
||||
ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}")
|
||||
endif()
|
||||
|
||||
if(UMFPACK_FOUND)
|
||||
ei_add_test(umfpack_support "" "${UMFPACK_ALL_LIBS}")
|
||||
endif()
|
||||
|
||||
if(KLU_FOUND OR SuiteSparse_FOUND)
|
||||
ei_add_test(klu_support "" "${KLU_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()
|
||||
@@ -334,7 +341,7 @@ if(PASTIX_FOUND AND (SCOTCH_FOUND OR METIS_FOUND))
|
||||
ei_add_test(pastix_support "" "${PASTIX_ALL_LIBS}")
|
||||
endif()
|
||||
|
||||
if(SPQR_FOUND AND CHOLMOD_FOUND)
|
||||
if(SPQR_FOUND AND CHOLMOD_FOUND AND EIGEN_BUILD_BLAS AND EIGEN_BUILD_LAPACK)
|
||||
ei_add_test(spqr_support "" "${SPQR_ALL_LIBS}")
|
||||
endif()
|
||||
|
||||
@@ -342,6 +349,10 @@ if(METIS_FOUND)
|
||||
ei_add_test(metis_support "" "${METIS_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
if(Accelerate_FOUND)
|
||||
ei_add_test(accelerate_support "" "${Accelerate_ALL_LIBS}")
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${CMAKE_CXX_COMPILER}" cmake_cxx_compiler_tolower)
|
||||
if(cmake_cxx_compiler_tolower MATCHES "qcc")
|
||||
set(CXX_IS_QCC "ON")
|
||||
@@ -383,43 +394,51 @@ if(EIGEN_TEST_CUDA_CLANG AND NOT CMAKE_CXX_COMPILER MATCHES "clang")
|
||||
message(WARNING "EIGEN_TEST_CUDA_CLANG is set, but CMAKE_CXX_COMPILER does not appear to be clang.")
|
||||
endif()
|
||||
|
||||
if(EIGEN_TEST_CUDA)
|
||||
find_package(CUDA 9.0)
|
||||
if(CUDA_FOUND AND EIGEN_TEST_CUDA)
|
||||
# Make sure to compile without the -pedantic, -Wundef, -Wnon-virtual-dtor
|
||||
# and -fno-check-new flags since they trigger thousands of compilation warnings
|
||||
# in the CUDA runtime
|
||||
string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "-Wundef" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "-Wnon-virtual-dtor" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REPLACE "-fno-check-new" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
find_package(CUDA 5.0)
|
||||
if(CUDA_FOUND)
|
||||
|
||||
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
|
||||
|
||||
set(EIGEN_CUDA_RELAXED_CONSTEXPR "--expt-relaxed-constexpr")
|
||||
if (${CUDA_VERSION} STREQUAL "7.0")
|
||||
set(EIGEN_CUDA_RELAXED_CONSTEXPR "--relaxed-constexpr")
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(CUDA_NVCC_FLAGS "-ccbin ${CMAKE_C_COMPILER}" CACHE STRING "nvcc flags" FORCE)
|
||||
endif()
|
||||
if(EIGEN_TEST_CUDA_CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
string(APPEND CMAKE_CXX_FLAGS " --cuda-path=${CUDA_TOOLKIT_ROOT_DIR}")
|
||||
foreach(GPU IN LISTS EIGEN_CUDA_COMPUTE_ARCH)
|
||||
string(APPEND CMAKE_CXX_FLAGS " --cuda-gpu-arch=sm_${GPU}")
|
||||
endforeach()
|
||||
string(APPEND CMAKE_CXX_FLAGS " ${EIGEN_CUDA_CXX_FLAGS}")
|
||||
else()
|
||||
foreach(GPU IN LISTS EIGEN_CUDA_COMPUTE_ARCH)
|
||||
string(APPEND CUDA_NVCC_FLAGS " -gencode arch=compute_${GPU},code=sm_${GPU}")
|
||||
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
|
||||
set(NVCC_ARCH_FLAGS)
|
||||
# Define an -arch=sm_<arch>, otherwise if GPU does not exactly match one of
|
||||
# those in the arch list for -gencode, the kernels will fail to run with
|
||||
# cudaErrorNoKernelImageForDevice
|
||||
# This can happen with newer cards (e.g. sm_75) and compiling with older
|
||||
# versions of nvcc (e.g. 9.2) that do not support their specific arch.
|
||||
list(LENGTH EIGEN_CUDA_COMPUTE_ARCH EIGEN_CUDA_COMPUTE_ARCH_SIZE)
|
||||
if(EIGEN_CUDA_COMPUTE_ARCH_SIZE)
|
||||
list(GET EIGEN_CUDA_COMPUTE_ARCH 0 EIGEN_CUDA_COMPUTE_DEFAULT)
|
||||
set(NVCC_ARCH_FLAGS " -arch=sm_${EIGEN_CUDA_COMPUTE_DEFAULT}")
|
||||
endif()
|
||||
foreach(ARCH IN LISTS EIGEN_CUDA_COMPUTE_ARCH)
|
||||
string(APPEND NVCC_ARCH_FLAGS " -gencode arch=compute_${ARCH},code=sm_${ARCH}")
|
||||
endforeach()
|
||||
set(CUDA_NVCC_FLAGS "--expt-relaxed-constexpr -Xcudafe \"--display_error_number\" ${NVCC_ARCH_FLAGS} ${CUDA_NVCC_FLAGS} ${EIGEN_CUDA_CXX_FLAGS}")
|
||||
cuda_include_directories("${CMAKE_CURRENT_BINARY_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}/include")
|
||||
endif()
|
||||
string(APPEND CUDA_NVCC_FLAGS " ${EIGEN_CUDA_RELAXED_CONSTEXPR}")
|
||||
|
||||
set(EIGEN_ADD_TEST_FILENAME_EXTENSION "cu")
|
||||
|
||||
ei_add_test(gpu_example)
|
||||
ei_add_test(gpu_basic)
|
||||
|
||||
unset(EIGEN_ADD_TEST_FILENAME_EXTENSION)
|
||||
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
# HIP unit tests
|
||||
option(EIGEN_TEST_HIP "Add HIP support." OFF)
|
||||
@@ -442,6 +461,7 @@ if (EIGEN_TEST_HIP)
|
||||
|
||||
set(EIGEN_ADD_TEST_FILENAME_EXTENSION "cu")
|
||||
ei_add_test(gpu_basic)
|
||||
ei_add_test(gpu_example)
|
||||
unset(EIGEN_ADD_TEST_FILENAME_EXTENSION)
|
||||
|
||||
elseif ((${HIP_PLATFORM} STREQUAL "nvcc") OR (${HIP_PLATFORM} STREQUAL "nvidia"))
|
||||
|
||||
28
libs/eigen/test/OffByOneScalar.h
Normal file
28
libs/eigen/test/OffByOneScalar.h
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
// A Scalar with internal representation T+1 so that zero is internally
|
||||
// represented by T(1). This is used to test memory fill.
|
||||
//
|
||||
template<typename T>
|
||||
class OffByOneScalar {
|
||||
public:
|
||||
OffByOneScalar() : val_(1) {}
|
||||
OffByOneScalar(const OffByOneScalar& other) {
|
||||
*this = other;
|
||||
}
|
||||
OffByOneScalar& operator=(const OffByOneScalar& other) {
|
||||
val_ = other.val_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OffByOneScalar(T val) : val_(val + 1) {}
|
||||
OffByOneScalar& operator=(T val) {
|
||||
val_ = val + 1;
|
||||
}
|
||||
|
||||
operator T() const {
|
||||
return val_ - 1;
|
||||
}
|
||||
|
||||
private:
|
||||
T val_;
|
||||
};
|
||||
176
libs/eigen/test/accelerate_support.cpp
Normal file
176
libs/eigen/test/accelerate_support.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS
|
||||
#include "sparse_solver.h"
|
||||
|
||||
#if defined(DEBUG)
|
||||
#undef DEBUG
|
||||
#endif
|
||||
|
||||
#include <Eigen/AccelerateSupport>
|
||||
|
||||
template<typename MatrixType,typename DenseMat>
|
||||
int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300, int maxCols = 300)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
int rows = internal::random<int>(1, maxRows);
|
||||
int cols = internal::random<int>(1, maxCols);
|
||||
double density = (std::max)(8.0 / (rows * cols), 0.01);
|
||||
|
||||
A.resize(rows,cols);
|
||||
dA.resize(rows,cols);
|
||||
initSparse<Scalar>(density, dA, A, ForceNonZeroDiag);
|
||||
A.makeCompressed();
|
||||
return rows;
|
||||
}
|
||||
|
||||
template<typename MatrixType,typename DenseMat>
|
||||
int generate_sparse_square_symmetric_problem(MatrixType& A, DenseMat& dA, int maxSize = 300)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
int rows = internal::random<int>(1, maxSize);
|
||||
int cols = rows;
|
||||
double density = (std::max)(8.0 / (rows * cols), 0.01);
|
||||
|
||||
A.resize(rows,cols);
|
||||
dA.resize(rows,cols);
|
||||
initSparse<Scalar>(density, dA, A, ForceNonZeroDiag);
|
||||
dA = dA * dA.transpose();
|
||||
A = A * A.transpose();
|
||||
A.makeCompressed();
|
||||
return rows;
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Solver> void test_accelerate_ldlt()
|
||||
{
|
||||
typedef SparseMatrix<Scalar> MatrixType;
|
||||
typedef Matrix<Scalar,Dynamic,1> DenseVector;
|
||||
|
||||
MatrixType A;
|
||||
Matrix<Scalar,Dynamic,Dynamic> dA;
|
||||
|
||||
generate_sparse_square_symmetric_problem(A, dA);
|
||||
|
||||
DenseVector b = DenseVector::Random(A.rows());
|
||||
|
||||
Solver solver;
|
||||
solver.compute(A);
|
||||
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse LDLT factorization failed\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
DenseVector x = solver.solve(b);
|
||||
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse LDLT factorization failed\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
//Compare with a dense solver
|
||||
DenseVector refX = dA.ldlt().solve(b);
|
||||
VERIFY((A * x).isApprox(A * refX, test_precision<Scalar>()));
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Solver> void test_accelerate_llt()
|
||||
{
|
||||
typedef SparseMatrix<Scalar> MatrixType;
|
||||
typedef Matrix<Scalar,Dynamic,1> DenseVector;
|
||||
|
||||
MatrixType A;
|
||||
Matrix<Scalar,Dynamic,Dynamic> dA;
|
||||
|
||||
generate_sparse_square_symmetric_problem(A, dA);
|
||||
|
||||
DenseVector b = DenseVector::Random(A.rows());
|
||||
|
||||
Solver solver;
|
||||
solver.compute(A);
|
||||
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse LLT factorization failed\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
DenseVector x = solver.solve(b);
|
||||
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse LLT factorization failed\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
//Compare with a dense solver
|
||||
DenseVector refX = dA.llt().solve(b);
|
||||
VERIFY((A * x).isApprox(A * refX, test_precision<Scalar>()));
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Solver> void test_accelerate_qr()
|
||||
{
|
||||
typedef SparseMatrix<Scalar> MatrixType;
|
||||
typedef Matrix<Scalar,Dynamic,1> DenseVector;
|
||||
|
||||
MatrixType A;
|
||||
Matrix<Scalar,Dynamic,Dynamic> dA;
|
||||
|
||||
generate_sparse_rectangular_problem(A, dA);
|
||||
|
||||
DenseVector b = DenseVector::Random(A.rows());
|
||||
|
||||
Solver solver;
|
||||
solver.compute(A);
|
||||
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse QR factorization failed\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
DenseVector x = solver.solve(b);
|
||||
|
||||
if (solver.info() != Success)
|
||||
{
|
||||
std::cerr << "sparse QR factorization failed\n";
|
||||
exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
//Compare with a dense solver
|
||||
DenseVector refX = dA.colPivHouseholderQr().solve(b);
|
||||
VERIFY((A * x).isApprox(A * refX, test_precision<Scalar>()));
|
||||
}
|
||||
|
||||
template<typename Scalar>
|
||||
void run_tests()
|
||||
{
|
||||
typedef SparseMatrix<Scalar> MatrixType;
|
||||
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLT<MatrixType, Lower> >();
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLTUnpivoted<MatrixType, Lower> >();
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLTSBK<MatrixType, Lower> >();
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLTTPP<MatrixType, Lower> >();
|
||||
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLT<MatrixType, Upper> >();
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLTUnpivoted<MatrixType, Upper> >();
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLTSBK<MatrixType, Upper> >();
|
||||
test_accelerate_ldlt<Scalar, AccelerateLDLTTPP<MatrixType, Upper> >();
|
||||
|
||||
test_accelerate_llt<Scalar, AccelerateLLT<MatrixType, Lower> >();
|
||||
|
||||
test_accelerate_llt<Scalar, AccelerateLLT<MatrixType, Upper> >();
|
||||
|
||||
test_accelerate_qr<Scalar, AccelerateQR<MatrixType> >();
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(accelerate_support)
|
||||
{
|
||||
CALL_SUBTEST_1(run_tests<float>());
|
||||
CALL_SUBTEST_2(run_tests<double>());
|
||||
}
|
||||
@@ -7,8 +7,6 @@
|
||||
// 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<bool IsInteger> struct adjoint_specific;
|
||||
@@ -47,7 +45,7 @@ template<> struct adjoint_specific<false> {
|
||||
VERIFY_IS_APPROX((v1*0).normalized(), (v1*0));
|
||||
#if (!EIGEN_ARCH_i386) || defined(EIGEN_VECTORIZE)
|
||||
RealScalar very_small = (std::numeric_limits<RealScalar>::min)();
|
||||
VERIFY( (v1*very_small).norm() == 0 );
|
||||
VERIFY( numext::is_exactly_zero((v1*very_small).norm()) );
|
||||
VERIFY_IS_APPROX((v1*very_small).normalized(), (v1*very_small));
|
||||
v3 = v1*very_small;
|
||||
v3.normalize();
|
||||
@@ -64,6 +62,17 @@ template<> struct adjoint_specific<false> {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MatrixType, typename Scalar = typename MatrixType::Scalar>
|
||||
MatrixType RandomMatrix(Index rows, Index cols, Scalar min, Scalar max) {
|
||||
MatrixType M = MatrixType(rows, cols);
|
||||
for (Index i=0; i<rows; ++i) {
|
||||
for (Index j=0; j<cols; ++j) {
|
||||
M(i, j) = Eigen::internal::random<Scalar>(min, max);
|
||||
}
|
||||
}
|
||||
return M;
|
||||
}
|
||||
|
||||
template<typename MatrixType> void adjoint(const MatrixType& m)
|
||||
{
|
||||
/* this test covers the following files:
|
||||
@@ -79,17 +88,21 @@ template<typename MatrixType> void adjoint(const MatrixType& m)
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
MatrixType m1 = MatrixType::Random(rows, cols),
|
||||
m2 = MatrixType::Random(rows, cols),
|
||||
// Avoid integer overflow by limiting input values.
|
||||
RealScalar rmin = static_cast<RealScalar>(NumTraits<Scalar>::IsInteger ? NumTraits<Scalar>::IsSigned ? -100 : 0 : -1);
|
||||
RealScalar rmax = static_cast<RealScalar>(NumTraits<Scalar>::IsInteger ? 100 : 1);
|
||||
|
||||
MatrixType m1 = RandomMatrix<MatrixType>(rows, cols, rmin, rmax),
|
||||
m2 = RandomMatrix<MatrixType>(rows, cols, rmin, rmax),
|
||||
m3(rows, cols),
|
||||
square = SquareMatrixType::Random(rows, rows);
|
||||
VectorType v1 = VectorType::Random(rows),
|
||||
v2 = VectorType::Random(rows),
|
||||
v3 = VectorType::Random(rows),
|
||||
square = RandomMatrix<SquareMatrixType>(rows, rows, rmin, rmax);
|
||||
VectorType v1 = RandomMatrix<VectorType>(rows, 1, rmin, rmax),
|
||||
v2 = RandomMatrix<VectorType>(rows, 1, rmin, rmax),
|
||||
v3 = RandomMatrix<VectorType>(rows, 1, rmin, rmax),
|
||||
vzero = VectorType::Zero(rows);
|
||||
|
||||
Scalar s1 = internal::random<Scalar>(),
|
||||
s2 = internal::random<Scalar>();
|
||||
Scalar s1 = internal::random<Scalar>(rmin, rmax),
|
||||
s2 = internal::random<Scalar>(rmin, rmax);
|
||||
|
||||
// check basic compatibility of adjoint, transpose, conjugate
|
||||
VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1);
|
||||
@@ -140,7 +153,8 @@ template<typename MatrixType> void adjoint(const MatrixType& m)
|
||||
|
||||
// check mixed dot product
|
||||
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
|
||||
RealVectorType rv1 = RealVectorType::Random(rows);
|
||||
RealVectorType rv1 = RandomMatrix<RealVectorType>(rows, 1, rmin, rmax);
|
||||
|
||||
VERIFY_IS_APPROX(v1.dot(rv1.template cast<Scalar>()), v1.dot(rv1));
|
||||
VERIFY_IS_APPROX(rv1.template cast<Scalar>().dot(v1), rv1.dot(v1));
|
||||
|
||||
|
||||
@@ -7,12 +7,22 @@
|
||||
// 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 <vector>
|
||||
#include "main.h"
|
||||
|
||||
template <typename Scalar, std::enable_if_t<NumTraits<Scalar>::IsInteger,int> = 0>
|
||||
std::vector<Scalar> special_values() {
|
||||
const Scalar zero = Scalar(0);
|
||||
const Scalar one = Scalar(1);
|
||||
const Scalar two = Scalar(2);
|
||||
const Scalar three = Scalar(3);
|
||||
const Scalar min = (std::numeric_limits<Scalar>::min)();
|
||||
const Scalar max = (std::numeric_limits<Scalar>::max)();
|
||||
return { zero, min, one, two, three, max };
|
||||
}
|
||||
|
||||
// Test the corner cases of pow(x, y) for real types.
|
||||
template<typename Scalar>
|
||||
void pow_test() {
|
||||
template <typename Scalar, std::enable_if_t<!NumTraits<Scalar>::IsInteger, int> = 0>
|
||||
std::vector<Scalar> special_values() {
|
||||
const Scalar zero = Scalar(0);
|
||||
const Scalar eps = Eigen::NumTraits<Scalar>::epsilon();
|
||||
const Scalar one = Scalar(1);
|
||||
@@ -26,36 +36,29 @@ void pow_test() {
|
||||
const Scalar min = (std::numeric_limits<Scalar>::min)();
|
||||
const Scalar max = (std::numeric_limits<Scalar>::max)();
|
||||
const Scalar max_exp = (static_cast<Scalar>(int(Eigen::NumTraits<Scalar>::max_exponent())) * Scalar(EIGEN_LN2)) / eps;
|
||||
return { zero, denorm_min, min, eps, sqrt_half, one, sqrt2, two, three, max_exp, max, inf, nan };
|
||||
}
|
||||
|
||||
const static Scalar abs_vals[] = {zero,
|
||||
denorm_min,
|
||||
min,
|
||||
eps,
|
||||
sqrt_half,
|
||||
one,
|
||||
sqrt2,
|
||||
two,
|
||||
three,
|
||||
max_exp,
|
||||
max,
|
||||
inf,
|
||||
nan};
|
||||
const int abs_cases = 13;
|
||||
const int num_cases = 2*abs_cases * 2*abs_cases;
|
||||
// Repeat the same value to make sure we hit the vectorized path.
|
||||
const int num_repeats = 32;
|
||||
Array<Scalar, Dynamic, Dynamic> x(num_repeats, num_cases);
|
||||
Array<Scalar, Dynamic, Dynamic> y(num_repeats, num_cases);
|
||||
template<typename Scalar>
|
||||
void special_value_pairs(Array<Scalar, Dynamic, Dynamic>& x,
|
||||
Array<Scalar, Dynamic, Dynamic>& y) {
|
||||
std::vector<Scalar> abs_vals = special_values<Scalar>();
|
||||
const Index abs_cases = (Index)abs_vals.size();
|
||||
const Index num_cases = 2*abs_cases * 2*abs_cases;
|
||||
// ensure both vectorized and non-vectorized paths taken
|
||||
const Index num_repeats = 2 * (Index)internal::packet_traits<Scalar>::size + 1;
|
||||
x.resize(num_repeats, num_cases);
|
||||
y.resize(num_repeats, num_cases);
|
||||
int count = 0;
|
||||
for (int i = 0; i < abs_cases; ++i) {
|
||||
for (Index i = 0; i < abs_cases; ++i) {
|
||||
const Scalar abs_x = abs_vals[i];
|
||||
for (int sign_x = 0; sign_x < 2; ++sign_x) {
|
||||
for (Index sign_x = 0; sign_x < 2; ++sign_x) {
|
||||
Scalar x_case = sign_x == 0 ? -abs_x : abs_x;
|
||||
for (int j = 0; j < abs_cases; ++j) {
|
||||
for (Index j = 0; j < abs_cases; ++j) {
|
||||
const Scalar abs_y = abs_vals[j];
|
||||
for (int sign_y = 0; sign_y < 2; ++sign_y) {
|
||||
for (Index sign_y = 0; sign_y < 2; ++sign_y) {
|
||||
Scalar y_case = sign_y == 0 ? -abs_y : abs_y;
|
||||
for (int repeat = 0; repeat < num_repeats; ++repeat) {
|
||||
for (Index repeat = 0; repeat < num_repeats; ++repeat) {
|
||||
x(repeat, count) = x_case;
|
||||
y(repeat, count) = y_case;
|
||||
}
|
||||
@@ -64,24 +67,266 @@ void pow_test() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array<Scalar, Dynamic, Dynamic> actual = x.pow(y);
|
||||
template <typename Scalar, typename Fn, typename RefFn>
|
||||
void binary_op_test(std::string name, Fn fun, RefFn ref) {
|
||||
const Scalar tol = test_precision<Scalar>();
|
||||
Array<Scalar, Dynamic, Dynamic> x;
|
||||
Array<Scalar, Dynamic, Dynamic> y;
|
||||
special_value_pairs(x, y);
|
||||
|
||||
Array<Scalar, Dynamic, Dynamic> actual = fun(x, y);
|
||||
bool all_pass = true;
|
||||
for (int i = 0; i < 1; ++i) {
|
||||
for (int j = 0; j < num_cases; ++j) {
|
||||
Scalar e = static_cast<Scalar>(std::pow(x(i,j), y(i,j)));
|
||||
for (Index i = 0; i < x.rows(); ++i) {
|
||||
for (Index j = 0; j < x.cols(); ++j) {
|
||||
Scalar e = static_cast<Scalar>(ref(x(i,j), y(i,j)));
|
||||
Scalar a = actual(i, j);
|
||||
bool fail = !(a==e) && !internal::isApprox(a, e, tol) && !((numext::isnan)(a) && (numext::isnan)(e));
|
||||
all_pass &= !fail;
|
||||
if (fail) {
|
||||
std::cout << "pow(" << x(i,j) << "," << y(i,j) << ") = " << a << " != " << e << std::endl;
|
||||
bool success = (a==e) || ((numext::isfinite)(e) && internal::isApprox(a, e, tol)) || ((numext::isnan)(a) && (numext::isnan)(e));
|
||||
all_pass &= success;
|
||||
if (!success) {
|
||||
std::cout << name << "(" << x(i,j) << "," << y(i,j) << ") = " << a << " != " << e << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY(all_pass);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void binary_ops_test() {
|
||||
binary_op_test<Scalar>("pow",
|
||||
[](auto x, auto y) { return Eigen::pow(x, y); },
|
||||
[](auto x, auto y) { return std::pow(x, y); });
|
||||
binary_op_test<Scalar>("atan2",
|
||||
[](auto x, auto y) { return Eigen::atan2(x, y); },
|
||||
[](auto x, auto y) { return std::atan2(x, y); });
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void pow_scalar_exponent_test() {
|
||||
using Int_t = typename internal::make_integer<Scalar>::type;
|
||||
const Scalar tol = test_precision<Scalar>();
|
||||
|
||||
std::vector<Scalar> abs_vals = special_values<Scalar>();
|
||||
const Index num_vals = (Index)abs_vals.size();
|
||||
Map<Array<Scalar, Dynamic, 1>> bases(abs_vals.data(), num_vals);
|
||||
|
||||
bool all_pass = true;
|
||||
for (Scalar abs_exponent : abs_vals) {
|
||||
for (Scalar exponent : {-abs_exponent, abs_exponent}) {
|
||||
// test integer exponent code path
|
||||
bool exponent_is_integer = (numext::isfinite)(exponent) && (numext::round(exponent) == exponent) &&
|
||||
(numext::abs(exponent) < static_cast<Scalar>(NumTraits<Int_t>::highest()));
|
||||
if (exponent_is_integer) {
|
||||
Int_t exponent_as_int = static_cast<Int_t>(exponent);
|
||||
Array<Scalar, Dynamic, 1> eigenPow = bases.pow(exponent_as_int);
|
||||
for (Index j = 0; j < num_vals; j++) {
|
||||
Scalar e = static_cast<Scalar>(std::pow(bases(j), exponent));
|
||||
Scalar a = eigenPow(j);
|
||||
bool success = (a == e) || ((numext::isfinite)(e) && internal::isApprox(a, e, tol)) ||
|
||||
((numext::isnan)(a) && (numext::isnan)(e));
|
||||
all_pass &= success;
|
||||
if (!success) {
|
||||
std::cout << "pow(" << bases(j) << "," << exponent << ") = " << a << " != " << e << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// test floating point exponent code path
|
||||
Array<Scalar, Dynamic, 1> eigenPow = bases.pow(exponent);
|
||||
for (Index j = 0; j < num_vals; j++) {
|
||||
Scalar e = static_cast<Scalar>(std::pow(bases(j), exponent));
|
||||
Scalar a = eigenPow(j);
|
||||
bool success = (a == e) || ((numext::isfinite)(e) && internal::isApprox(a, e, tol)) ||
|
||||
((numext::isnan)(a) && (numext::isnan)(e));
|
||||
all_pass &= success;
|
||||
if (!success) {
|
||||
std::cout << "pow(" << bases(j) << "," << exponent << ") = " << a << " != " << e << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY(all_pass);
|
||||
}
|
||||
|
||||
template <typename Scalar, typename ScalarExponent>
|
||||
Scalar calc_overflow_threshold(const ScalarExponent exponent) {
|
||||
EIGEN_USING_STD(exp2);
|
||||
EIGEN_USING_STD(log2);
|
||||
EIGEN_STATIC_ASSERT((NumTraits<Scalar>::digits() < 2 * NumTraits<double>::digits()), BASE_TYPE_IS_TOO_BIG);
|
||||
|
||||
if (exponent < 2)
|
||||
return NumTraits<Scalar>::highest();
|
||||
else {
|
||||
// base^e <= highest ==> base <= 2^(log2(highest)/e)
|
||||
// For floating-point types, consider the bound for integer values that can be reproduced exactly = 2 ^ digits
|
||||
double highest_bits = numext::mini(static_cast<double>(NumTraits<Scalar>::digits()),
|
||||
static_cast<double>(log2(NumTraits<Scalar>::highest())));
|
||||
return static_cast<Scalar>(
|
||||
numext::floor(exp2(highest_bits / static_cast<double>(exponent))));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Base, typename Exponent, bool ExpIsInteger = NumTraits<Exponent>::IsInteger>
|
||||
struct ref_pow {
|
||||
static Base run(Base base, Exponent exponent) {
|
||||
EIGEN_USING_STD(pow);
|
||||
return pow(base, static_cast<Base>(exponent));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Base, typename Exponent>
|
||||
struct ref_pow<Base, Exponent, true> {
|
||||
static Base run(Base base, Exponent exponent) {
|
||||
EIGEN_USING_STD(pow);
|
||||
return pow(base, exponent);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Base, typename Exponent>
|
||||
void test_exponent(Exponent exponent) {
|
||||
const Base max_abs_bases = static_cast<Base>(10000);
|
||||
// avoid integer overflow in Base type
|
||||
Base threshold = calc_overflow_threshold<Base, Exponent>(numext::abs(exponent));
|
||||
// avoid numbers that can't be verified with std::pow
|
||||
double double_threshold = calc_overflow_threshold<double, Exponent>(numext::abs(exponent));
|
||||
// use the lesser of these two thresholds
|
||||
Base testing_threshold =
|
||||
static_cast<double>(threshold) < double_threshold ? threshold : static_cast<Base>(double_threshold);
|
||||
// test both vectorized and non-vectorized code paths
|
||||
const Index array_size = 2 * internal::packet_traits<Base>::size + 1;
|
||||
|
||||
Base max_base = numext::mini(testing_threshold, max_abs_bases);
|
||||
Base min_base = NumTraits<Base>::IsSigned ? -max_base : Base(0);
|
||||
|
||||
ArrayX<Base> x(array_size), y(array_size);
|
||||
bool all_pass = true;
|
||||
for (Base base = min_base; base <= max_base; base++) {
|
||||
if (exponent < 0 && base == 0) continue;
|
||||
x.setConstant(base);
|
||||
y = x.pow(exponent);
|
||||
for (Base a : y) {
|
||||
Base e = ref_pow<Base, Exponent>::run(base, exponent);
|
||||
bool pass = (a == e);
|
||||
if (!NumTraits<Base>::IsInteger) {
|
||||
pass = pass || (((numext::isfinite)(e) && internal::isApprox(a, e)) ||
|
||||
((numext::isnan)(a) && (numext::isnan)(e)));
|
||||
}
|
||||
all_pass &= pass;
|
||||
if (!pass) {
|
||||
std::cout << "pow(" << base << "," << exponent << ") = " << a << " != " << e << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY(all_pass);
|
||||
}
|
||||
|
||||
template <typename Base, typename Exponent>
|
||||
void unary_pow_test() {
|
||||
Exponent max_exponent = static_cast<Exponent>(NumTraits<Base>::digits());
|
||||
Exponent min_exponent = static_cast<Exponent>(NumTraits<Exponent>::IsSigned ? -max_exponent : 0);
|
||||
|
||||
for (Exponent exponent = min_exponent; exponent < max_exponent; ++exponent) {
|
||||
test_exponent<Base, Exponent>(exponent);
|
||||
}
|
||||
}
|
||||
|
||||
void mixed_pow_test() {
|
||||
// The following cases will test promoting a smaller exponent type
|
||||
// to a wider base type.
|
||||
unary_pow_test<double, int>();
|
||||
unary_pow_test<double, float>();
|
||||
unary_pow_test<float, half>();
|
||||
unary_pow_test<double, half>();
|
||||
unary_pow_test<float, bfloat16>();
|
||||
unary_pow_test<double, bfloat16>();
|
||||
|
||||
// Although in the following cases the exponent cannot be represented exactly
|
||||
// in the base type, we do not perform a conversion, but implement
|
||||
// the operation using repeated squaring.
|
||||
unary_pow_test<float, int>();
|
||||
unary_pow_test<double, long long>();
|
||||
|
||||
// The following cases will test promoting a wider exponent type
|
||||
// to a narrower base type. This should compile but generate a
|
||||
// deprecation warning:
|
||||
unary_pow_test<float, double>();
|
||||
}
|
||||
|
||||
void int_pow_test() {
|
||||
unary_pow_test<int, int>();
|
||||
unary_pow_test<unsigned int, unsigned int>();
|
||||
unary_pow_test<long long, long long>();
|
||||
unary_pow_test<unsigned long long, unsigned long long>();
|
||||
|
||||
// Although in the following cases the exponent cannot be represented exactly
|
||||
// in the base type, we do not perform a conversion, but implement the
|
||||
// operation using repeated squaring.
|
||||
unary_pow_test<long long, int>();
|
||||
unary_pow_test<int, unsigned int>();
|
||||
unary_pow_test<unsigned int, int>();
|
||||
unary_pow_test<long long, unsigned long long>();
|
||||
unary_pow_test<unsigned long long, long long>();
|
||||
unary_pow_test<long long, int>();
|
||||
}
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
template <typename Scalar>
|
||||
struct test_signbit_op {
|
||||
Scalar constexpr operator()(const Scalar& a) const { return numext::signbit(a); }
|
||||
template <typename Packet>
|
||||
inline Packet packetOp(const Packet& a) const {
|
||||
return psignbit(a);
|
||||
}
|
||||
};
|
||||
template <typename Scalar>
|
||||
struct functor_traits<test_signbit_op<Scalar>> {
|
||||
enum { Cost = 1, PacketAccess = true }; //todo: define HasSignbit flag
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
|
||||
template <typename Scalar>
|
||||
void signbit_test() {
|
||||
const size_t size = 100 * internal::packet_traits<Scalar>::size;
|
||||
ArrayX<Scalar> x(size), y(size);
|
||||
x.setRandom();
|
||||
std::vector<Scalar> special_vals = special_values<Scalar>();
|
||||
for (size_t i = 0; i < special_vals.size(); i++) {
|
||||
x(2 * i + 0) = special_vals[i];
|
||||
x(2 * i + 1) = -special_vals[i];
|
||||
}
|
||||
y = x.unaryExpr(internal::test_signbit_op<Scalar>());
|
||||
|
||||
bool all_pass = true;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
const Scalar ref_val = numext::signbit(x(i));
|
||||
bool not_same = internal::predux_any(internal::bitwise_helper<Scalar>::bitwise_xor(ref_val, y(i)));
|
||||
if (not_same) std::cout << "signbit(" << x(i) << ") != " << y(i) << "\n";
|
||||
all_pass = all_pass && !not_same;
|
||||
}
|
||||
|
||||
VERIFY(all_pass);
|
||||
}
|
||||
void signbit_tests() {
|
||||
signbit_test<float>();
|
||||
signbit_test<double>();
|
||||
signbit_test<Eigen::half>();
|
||||
signbit_test<Eigen::bfloat16>();
|
||||
|
||||
signbit_test<uint8_t>();
|
||||
signbit_test<uint16_t>();
|
||||
signbit_test<uint32_t>();
|
||||
signbit_test<uint64_t>();
|
||||
|
||||
signbit_test<int8_t>();
|
||||
signbit_test<int16_t>();
|
||||
signbit_test<int32_t>();
|
||||
signbit_test<int64_t>();
|
||||
}
|
||||
|
||||
template<typename ArrayType> void array(const ArrayType& m)
|
||||
{
|
||||
typedef typename ArrayType::Scalar Scalar;
|
||||
@@ -92,8 +337,20 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
ArrayType m1 = ArrayType::Random(rows, cols),
|
||||
m2 = ArrayType::Random(rows, cols),
|
||||
ArrayType m1 = ArrayType::Random(rows, cols);
|
||||
if (NumTraits<RealScalar>::IsInteger && NumTraits<RealScalar>::IsSigned
|
||||
&& !NumTraits<Scalar>::IsComplex) {
|
||||
// Here we cap the size of the values in m1 such that pow(3)/cube()
|
||||
// doesn't overflow and result in undefined behavior. Notice that because
|
||||
// pow(int, int) promotes its inputs and output to double (according to
|
||||
// the C++ standard), we have to make sure that the result fits in 53 bits
|
||||
// for int64,
|
||||
RealScalar max_val =
|
||||
numext::mini(RealScalar(std::cbrt(NumTraits<RealScalar>::highest())),
|
||||
RealScalar(std::cbrt(1LL << 53)))/2;
|
||||
m1.array() = (m1.abs().array() <= max_val).select(m1, Scalar(max_val));
|
||||
}
|
||||
ArrayType m2 = ArrayType::Random(rows, cols),
|
||||
m3(rows, cols);
|
||||
ArrayType m4 = m1; // copy constructor
|
||||
VERIFY_IS_APPROX(m1, m4);
|
||||
@@ -119,23 +376,23 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
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; m4 = m1;
|
||||
ArrayType::Map(m4.data(), m4.rows(), m4.cols()) -= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
|
||||
VERIFY_IS_APPROX(m4, 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; m4 = m1;
|
||||
ArrayType::Map(m4.data(), m4.rows(), m4.cols()) += ArrayType::Map(m2.data(), m2.rows(), m2.cols());
|
||||
VERIFY_IS_APPROX(m4, 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; m4 = m1;
|
||||
ArrayType::Map(m4.data(), m4.rows(), m4.cols()) *= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
|
||||
VERIFY_IS_APPROX(m4, m3 * m2);
|
||||
|
||||
m3 = m1;
|
||||
m3 = m1; m4 = 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);
|
||||
ArrayType::Map(m4.data(), m4.rows(), m4.cols()) /= ArrayType::Map(m2.data(), m2.rows(), m2.cols());
|
||||
VERIFY_IS_APPROX(m4, m3 / m2);
|
||||
|
||||
// reductions
|
||||
VERIFY_IS_APPROX(m1.abs().colwise().sum().sum(), m1.abs().sum());
|
||||
@@ -176,7 +433,6 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
FixedArrayType f4(f1.data());
|
||||
VERIFY_IS_APPROX(f4, f1);
|
||||
}
|
||||
#if EIGEN_HAS_CXX11
|
||||
{
|
||||
FixedArrayType f1{s1};
|
||||
VERIFY_IS_APPROX(f1, FixedArrayType::Constant(s1));
|
||||
@@ -188,7 +444,6 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
FixedArrayType f4{f1.data()};
|
||||
VERIFY_IS_APPROX(f4, f1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// pow
|
||||
VERIFY_IS_APPROX(m1.pow(2), m1.square());
|
||||
@@ -214,14 +469,12 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
OneDArrayType o2(static_cast<int>(rows));
|
||||
VERIFY(o2.size()==rows);
|
||||
}
|
||||
#if EIGEN_HAS_CXX11
|
||||
{
|
||||
OneDArrayType o1{rows};
|
||||
VERIFY(o1.size()==rows);
|
||||
OneDArrayType o4{int(rows)};
|
||||
VERIFY(o4.size()==rows);
|
||||
}
|
||||
#endif
|
||||
// Check possible conflicts with 2D ctor
|
||||
typedef Array<Scalar, Dynamic, Dynamic> TwoDArrayType;
|
||||
typedef Array<Scalar, 2, 1> ArrayType2;
|
||||
@@ -238,7 +491,6 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
ArrayType2 o4(static_cast<int>(rows),static_cast<int>(cols));
|
||||
VERIFY(o4(0)==Scalar(rows) && o4(1)==Scalar(cols));
|
||||
}
|
||||
#if EIGEN_HAS_CXX11
|
||||
{
|
||||
TwoDArrayType o1{rows,cols};
|
||||
VERIFY(o1.rows()==rows);
|
||||
@@ -252,7 +504,6 @@ template<typename ArrayType> void array(const ArrayType& m)
|
||||
ArrayType2 o4{int(rows),int(cols)};
|
||||
VERIFY(o4(0)==Scalar(rows) && o4(1)==Scalar(cols));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename ArrayType> void comparisons(const ArrayType& m)
|
||||
@@ -360,11 +611,11 @@ template<typename ArrayType> void array_real(const ArrayType& m)
|
||||
VERIFY_IS_APPROX(m1.sinh(), sinh(m1));
|
||||
VERIFY_IS_APPROX(m1.cosh(), cosh(m1));
|
||||
VERIFY_IS_APPROX(m1.tanh(), tanh(m1));
|
||||
#if EIGEN_HAS_CXX11_MATH
|
||||
VERIFY_IS_APPROX(m1.atan2(m2), atan2(m1,m2));
|
||||
|
||||
VERIFY_IS_APPROX(m1.tanh().atanh(), atanh(tanh(m1)));
|
||||
VERIFY_IS_APPROX(m1.sinh().asinh(), asinh(sinh(m1)));
|
||||
VERIFY_IS_APPROX(m1.cosh().acosh(), acosh(cosh(m1)));
|
||||
#endif
|
||||
VERIFY_IS_APPROX(m1.logistic(), logistic(m1));
|
||||
|
||||
VERIFY_IS_APPROX(m1.arg(), arg(m1));
|
||||
@@ -421,6 +672,13 @@ template<typename ArrayType> void array_real(const ArrayType& m)
|
||||
VERIFY_IS_APPROX( m1.sign(), -(-m1).sign() );
|
||||
VERIFY_IS_APPROX( m1*m1.sign(),m1.abs());
|
||||
VERIFY_IS_APPROX(m1.sign() * m1.abs(), m1);
|
||||
|
||||
ArrayType tmp = m1.atan2(m2);
|
||||
for (Index i = 0; i < tmp.size(); ++i) {
|
||||
Scalar actual = tmp.array()(i);
|
||||
Scalar expected = atan2(m1.array()(i), m2.array()(i));
|
||||
VERIFY_IS_APPROX(actual, expected);
|
||||
}
|
||||
|
||||
VERIFY_IS_APPROX(numext::abs2(numext::real(m1)) + numext::abs2(numext::imag(m1)), numext::abs2(m1));
|
||||
VERIFY_IS_APPROX(numext::abs2(Eigen::real(m1)) + numext::abs2(Eigen::imag(m1)), numext::abs2(m1));
|
||||
@@ -448,7 +706,10 @@ template<typename ArrayType> void array_real(const ArrayType& m)
|
||||
// Avoid inf and NaN.
|
||||
m3 = (m1.square()<NumTraits<Scalar>::epsilon()).select(Scalar(1),m3);
|
||||
VERIFY_IS_APPROX(m3.pow(RealScalar(-2)), m3.square().inverse());
|
||||
pow_test<Scalar>();
|
||||
|
||||
// Test pow and atan2 on special IEEE values.
|
||||
binary_ops_test<Scalar>();
|
||||
pow_scalar_exponent_test<Scalar>();
|
||||
|
||||
VERIFY_IS_APPROX(log10(m3), log(m3)/numext::log(Scalar(10)));
|
||||
VERIFY_IS_APPROX(log2(m3), log(m3)/numext::log(Scalar(2)));
|
||||
@@ -457,7 +718,7 @@ template<typename ArrayType> void array_real(const ArrayType& m)
|
||||
const RealScalar tiny = sqrt(std::numeric_limits<RealScalar>::epsilon());
|
||||
s1 += Scalar(tiny);
|
||||
m1 += ArrayType::Constant(rows,cols,Scalar(tiny));
|
||||
VERIFY_IS_APPROX(s1/m1, s1 * m1.inverse());
|
||||
VERIFY_IS_CWISE_APPROX(s1/m1, s1 * m1.inverse());
|
||||
|
||||
// check inplace transpose
|
||||
m3 = m1;
|
||||
@@ -467,6 +728,7 @@ template<typename ArrayType> void array_real(const ArrayType& m)
|
||||
VERIFY_IS_APPROX(m3, m1);
|
||||
}
|
||||
|
||||
|
||||
template<typename ArrayType> void array_complex(const ArrayType& m)
|
||||
{
|
||||
typedef typename ArrayType::Scalar Scalar;
|
||||
@@ -512,7 +774,6 @@ template<typename ArrayType> void array_complex(const ArrayType& m)
|
||||
VERIFY_IS_APPROX(cos(m1+RealScalar(3)*m2), cos((m1+RealScalar(3)*m2).eval()));
|
||||
VERIFY_IS_APPROX(m1.sign(), sign(m1));
|
||||
|
||||
|
||||
VERIFY_IS_APPROX(m1.exp() * m2.exp(), exp(m1+m2));
|
||||
VERIFY_IS_APPROX(m1.exp(), exp(m1));
|
||||
VERIFY_IS_APPROX(m1.exp() / m2.exp(),(m1-m2).exp());
|
||||
@@ -661,6 +922,35 @@ template<typename ArrayType> void array_integer(const ArrayType& m)
|
||||
VERIFY( (m2 == m1.unaryExpr(arithmetic_shift_right<9>())).all() );
|
||||
}
|
||||
|
||||
template <typename ArrayType>
|
||||
struct signed_shift_test_impl {
|
||||
typedef typename ArrayType::Scalar Scalar;
|
||||
static constexpr size_t Size = sizeof(Scalar);
|
||||
static constexpr size_t MaxShift = (CHAR_BIT * Size) - 1;
|
||||
|
||||
template <size_t N = 0>
|
||||
static inline std::enable_if_t<(N > MaxShift), void> run(const ArrayType& ) {}
|
||||
template <size_t N = 0>
|
||||
static inline std::enable_if_t<(N <= MaxShift), void> run(const ArrayType& m) {
|
||||
const Index rows = m.rows();
|
||||
const Index cols = m.cols();
|
||||
|
||||
ArrayType m1 = ArrayType::Random(rows, cols), m2(rows, cols);
|
||||
|
||||
m2 = m1.unaryExpr([](const Scalar& x) { return x >> N; });
|
||||
VERIFY((m2 == m1.unaryExpr(internal::scalar_shift_right_op<Scalar, N>())).all());
|
||||
|
||||
m2 = m1.unaryExpr([](const Scalar& x) { return x << N; });
|
||||
VERIFY((m2 == m1.unaryExpr( internal::scalar_shift_left_op<Scalar, N>())).all());
|
||||
|
||||
run<N + 1>(m);
|
||||
}
|
||||
};
|
||||
template <typename ArrayType>
|
||||
void signed_shift_test(const ArrayType& m) {
|
||||
signed_shift_test_impl<ArrayType>::run(m);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(array_cwise)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -673,6 +963,9 @@ EIGEN_DECLARE_TEST(array_cwise)
|
||||
CALL_SUBTEST_6( array(Array<Index,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_6( array_integer(ArrayXXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_6( array_integer(Array<Index,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_7( signed_shift_test(ArrayXXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_7( signed_shift_test(Array<Index, Dynamic, Dynamic>(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>()) );
|
||||
@@ -700,6 +993,12 @@ EIGEN_DECLARE_TEST(array_cwise)
|
||||
CALL_SUBTEST_4( array_complex(ArrayXXcf(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_6( int_pow_test() );
|
||||
CALL_SUBTEST_7( mixed_pow_test() );
|
||||
CALL_SUBTEST_8( signbit_tests() );
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -211,6 +211,40 @@ template<typename MatrixType> void cwise_min_max(const MatrixType& m)
|
||||
VERIFY_IS_APPROX(MatrixType::Constant(rows,cols, maxM1).array(), (m1.array().max)( maxM1));
|
||||
VERIFY_IS_APPROX(m1.array(), (m1.array().max)( minM1));
|
||||
|
||||
// Test NaN propagation for min/max.
|
||||
if (!NumTraits<Scalar>::IsInteger) {
|
||||
m1(0,0) = NumTraits<Scalar>::quiet_NaN();
|
||||
// Elementwise.
|
||||
VERIFY((numext::isnan)(m1.template cwiseMax<PropagateNaN>(MatrixType::Constant(rows,cols, Scalar(1)))(0,0)));
|
||||
VERIFY((numext::isnan)(m1.template cwiseMin<PropagateNaN>(MatrixType::Constant(rows,cols, Scalar(1)))(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.template cwiseMax<PropagateNumbers>(MatrixType::Constant(rows,cols, Scalar(1)))(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.template cwiseMin<PropagateNumbers>(MatrixType::Constant(rows,cols, Scalar(1)))(0,0)));
|
||||
VERIFY((numext::isnan)(m1.template cwiseMax<PropagateNaN>(Scalar(1))(0,0)));
|
||||
VERIFY((numext::isnan)(m1.template cwiseMin<PropagateNaN>(Scalar(1))(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.template cwiseMax<PropagateNumbers>(Scalar(1))(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.template cwiseMin<PropagateNumbers>(Scalar(1))(0,0)));
|
||||
|
||||
|
||||
VERIFY((numext::isnan)(m1.array().template max<PropagateNaN>(MatrixType::Constant(rows,cols, Scalar(1)).array())(0,0)));
|
||||
VERIFY((numext::isnan)(m1.array().template min<PropagateNaN>(MatrixType::Constant(rows,cols, Scalar(1)).array())(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.array().template max<PropagateNumbers>(MatrixType::Constant(rows,cols, Scalar(1)).array())(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.array().template min<PropagateNumbers>(MatrixType::Constant(rows,cols, Scalar(1)).array())(0,0)));
|
||||
VERIFY((numext::isnan)(m1.array().template max<PropagateNaN>(Scalar(1))(0,0)));
|
||||
VERIFY((numext::isnan)(m1.array().template min<PropagateNaN>(Scalar(1))(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.array().template max<PropagateNumbers>(Scalar(1))(0,0)));
|
||||
VERIFY(!(numext::isnan)(m1.array().template min<PropagateNumbers>(Scalar(1))(0,0)));
|
||||
|
||||
// Reductions.
|
||||
VERIFY((numext::isnan)(m1.template maxCoeff<PropagateNaN>()));
|
||||
VERIFY((numext::isnan)(m1.template minCoeff<PropagateNaN>()));
|
||||
if (m1.size() > 1) {
|
||||
VERIFY(!(numext::isnan)(m1.template maxCoeff<PropagateNumbers>()));
|
||||
VERIFY(!(numext::isnan)(m1.template minCoeff<PropagateNumbers>()));
|
||||
} else {
|
||||
VERIFY((numext::isnan)(m1.template maxCoeff<PropagateNumbers>()));
|
||||
VERIFY((numext::isnan)(m1.template minCoeff<PropagateNumbers>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixTraits> void resize(const MatrixTraits& t)
|
||||
|
||||
@@ -7,11 +7,20 @@
|
||||
// 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"
|
||||
#include "random_without_cast_overflow.h"
|
||||
|
||||
template <typename MatrixType>
|
||||
std::enable_if_t<(MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1),void>
|
||||
check_index(const MatrixType& m) {
|
||||
VERIFY_RAISES_ASSERT(m[0]);
|
||||
VERIFY_RAISES_ASSERT((m+m)[0]);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
std::enable_if_t<!(MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1),void>
|
||||
check_index(const MatrixType& /*unused*/) {}
|
||||
|
||||
template<typename MatrixType> void basicStuff(const MatrixType& m)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
@@ -60,10 +69,8 @@ template<typename MatrixType> void basicStuff(const MatrixType& m)
|
||||
x = v1(static_cast<unsigned int>(r1));
|
||||
x = v1(static_cast<signed long>(r1));
|
||||
x = v1(static_cast<unsigned long>(r1));
|
||||
#if EIGEN_HAS_CXX11
|
||||
x = v1(static_cast<long long int>(r1));
|
||||
x = v1(static_cast<unsigned long long int>(r1));
|
||||
#endif
|
||||
|
||||
VERIFY_IS_APPROX( v1, v1);
|
||||
VERIFY_IS_NOT_APPROX( v1, 2*v1);
|
||||
@@ -101,8 +108,7 @@ template<typename MatrixType> void basicStuff(const MatrixType& m)
|
||||
|
||||
if(cols!=1 && rows!=1)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT(m1[0]);
|
||||
VERIFY_RAISES_ASSERT((m1+m1)[0]);
|
||||
check_index(m1);
|
||||
}
|
||||
|
||||
VERIFY_IS_APPROX(m3 = m1,m1);
|
||||
@@ -223,10 +229,8 @@ struct casting_test_runner {
|
||||
casting_test<SrcScalar, uint16_t>::run();
|
||||
casting_test<SrcScalar, int32_t>::run();
|
||||
casting_test<SrcScalar, uint32_t>::run();
|
||||
#if EIGEN_HAS_CXX11
|
||||
casting_test<SrcScalar, int64_t>::run();
|
||||
casting_test<SrcScalar, uint64_t>::run();
|
||||
#endif
|
||||
casting_test<SrcScalar, half>::run();
|
||||
casting_test<SrcScalar, bfloat16>::run();
|
||||
casting_test<SrcScalar, float>::run();
|
||||
@@ -237,7 +241,7 @@ struct casting_test_runner {
|
||||
};
|
||||
|
||||
template<typename SrcScalar>
|
||||
struct casting_test_runner<SrcScalar, typename internal::enable_if<(NumTraits<SrcScalar>::IsComplex)>::type>
|
||||
struct casting_test_runner<SrcScalar, std::enable_if_t<(NumTraits<SrcScalar>::IsComplex)>>
|
||||
{
|
||||
static void run() {
|
||||
// Only a few casts from std::complex<T> are defined.
|
||||
@@ -256,10 +260,8 @@ void casting_all() {
|
||||
casting_test_runner<uint16_t>::run();
|
||||
casting_test_runner<int32_t>::run();
|
||||
casting_test_runner<uint32_t>::run();
|
||||
#if EIGEN_HAS_CXX11
|
||||
casting_test_runner<int64_t>::run();
|
||||
casting_test_runner<uint64_t>::run();
|
||||
#endif
|
||||
casting_test_runner<half>::run();
|
||||
casting_test_runner<bfloat16>::run();
|
||||
casting_test_runner<float>::run();
|
||||
|
||||
@@ -10,35 +10,27 @@
|
||||
// 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/
|
||||
|
||||
// We explicitly disable deprecated declarations for this set of tests
|
||||
// because we purposely verify assertions for the deprecated SVD runtime
|
||||
// option behavior.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning( disable : 4996 )
|
||||
#endif
|
||||
|
||||
// discard stack allocation as that too bypasses malloc
|
||||
#define EIGEN_STACK_ALLOCATION_LIMIT 0
|
||||
#define EIGEN_RUNTIME_NO_MALLOC
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/SVD>
|
||||
#include <iostream>
|
||||
#include <Eigen/LU>
|
||||
|
||||
|
||||
#define SVD_DEFAULT(M) BDCSVD<M>
|
||||
#define SVD_FOR_MIN_NORM(M) BDCSVD<M>
|
||||
#define SVD_STATIC_OPTIONS(M, O) BDCSVD<M, O>
|
||||
#include "svd_common.h"
|
||||
|
||||
// Check all variants of JacobiSVD
|
||||
template<typename MatrixType>
|
||||
void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
|
||||
{
|
||||
MatrixType m;
|
||||
if(pickrandom) {
|
||||
m.resizeLike(a);
|
||||
svd_fill_random(m);
|
||||
}
|
||||
else
|
||||
m = a;
|
||||
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<BDCSVD<MatrixType> >(m, false) ));
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void bdcsvd_method()
|
||||
{
|
||||
@@ -49,70 +41,141 @@ void bdcsvd_method()
|
||||
VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones());
|
||||
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU());
|
||||
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV());
|
||||
|
||||
// Deprecated behavior.
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).adjoint().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<DisableQRDecomposition>(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<DisableQRDecomposition>(ComputeFullU|ComputeFullV).transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<DisableQRDecomposition>(ComputeFullU|ComputeFullV).adjoint().solve(m), m);
|
||||
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<ComputeFullU | ComputeFullV>().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<ComputeFullU | ComputeFullV>().transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<ComputeFullU | ComputeFullV>().adjoint().solve(m), m);
|
||||
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<ComputeFullU | ComputeFullV | DisableQRDecomposition>().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<ComputeFullU | ComputeFullV | DisableQRDecomposition>().transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template bdcSvd<ComputeFullU | ComputeFullV | DisableQRDecomposition>().adjoint().solve(m), m);
|
||||
}
|
||||
|
||||
// compare the Singular values returned with Jacobi and Bdc
|
||||
template<typename MatrixType>
|
||||
void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0)
|
||||
{
|
||||
MatrixType m = MatrixType::Random(a.rows(), a.cols());
|
||||
BDCSVD<MatrixType> bdc_svd(m);
|
||||
template <typename MatrixType>
|
||||
void compare_bdc_jacobi(const MatrixType& a = MatrixType(), int algoswap = 16, bool random = true) {
|
||||
MatrixType m = random ? MatrixType::Random(a.rows(), a.cols()) : a;
|
||||
|
||||
BDCSVD<MatrixType> bdc_svd(m.rows(), m.cols());
|
||||
bdc_svd.setSwitchSize(algoswap);
|
||||
bdc_svd.compute(m);
|
||||
|
||||
JacobiSVD<MatrixType> jacobi_svd(m);
|
||||
VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues());
|
||||
if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU());
|
||||
if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU());
|
||||
if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV());
|
||||
if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV());
|
||||
}
|
||||
|
||||
// Verifies total deflation is **not** triggered.
|
||||
void compare_bdc_jacobi_instance(bool structure_as_m, int algoswap = 16)
|
||||
{
|
||||
MatrixXd m(4, 3);
|
||||
if (structure_as_m) {
|
||||
// The first 3 rows are the reduced form of Matrix 1 as shown below, and it
|
||||
// has nonzero elements in the first column and diagonals only.
|
||||
m << 1.056293, 0, 0,
|
||||
-0.336468, 0.907359, 0,
|
||||
-1.566245, 0, 0.149150,
|
||||
-0.1, 0, 0;
|
||||
} else {
|
||||
// Matrix 1.
|
||||
m << 0.882336, 18.3914, -26.7921,
|
||||
-5.58135, 17.1931, -24.0892,
|
||||
-20.794, 8.68496, -4.83103,
|
||||
-8.4981, -10.5451, 23.9072;
|
||||
}
|
||||
compare_bdc_jacobi(m, algoswap, false);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void bdcsvd_all_options(const MatrixType& input = MatrixType()) {
|
||||
MatrixType m(input.rows(), input.cols());
|
||||
svd_fill_random(m);
|
||||
svd_option_checks<MatrixType, 0>(m);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void bdcsvd_verify_assert(const MatrixType& input = MatrixType()) {
|
||||
svd_verify_assert<MatrixType>(input);
|
||||
svd_verify_constructor_options_assert<BDCSVD<MatrixType>>(input);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(bdcsvd)
|
||||
{
|
||||
CALL_SUBTEST_3(( svd_verify_assert<BDCSVD<Matrix3f> >(Matrix3f()) ));
|
||||
CALL_SUBTEST_4(( svd_verify_assert<BDCSVD<Matrix4d> >(Matrix4d()) ));
|
||||
CALL_SUBTEST_7(( svd_verify_assert<BDCSVD<MatrixXf> >(MatrixXf(10,12)) ));
|
||||
CALL_SUBTEST_8(( svd_verify_assert<BDCSVD<MatrixXcd> >(MatrixXcd(7,5)) ));
|
||||
|
||||
CALL_SUBTEST_101(( svd_all_trivial_2x2(bdcsvd<Matrix2cd>) ));
|
||||
CALL_SUBTEST_102(( svd_all_trivial_2x2(bdcsvd<Matrix2d>) ));
|
||||
CALL_SUBTEST_1((bdcsvd_verify_assert<Matrix3f>()));
|
||||
CALL_SUBTEST_1((bdcsvd_verify_assert<Matrix4d>()));
|
||||
CALL_SUBTEST_2((bdcsvd_verify_assert<Matrix<float, 10, 7>>()));
|
||||
CALL_SUBTEST_2((bdcsvd_verify_assert<Matrix<float, 7, 10>>()));
|
||||
CALL_SUBTEST_3((bdcsvd_verify_assert<Matrix<std::complex<double>, 6, 9>>()));
|
||||
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_3(( bdcsvd<Matrix3f>() ));
|
||||
CALL_SUBTEST_4(( bdcsvd<Matrix4d>() ));
|
||||
CALL_SUBTEST_5(( bdcsvd<Matrix<float,3,5> >() ));
|
||||
CALL_SUBTEST_4((svd_all_trivial_2x2(bdcsvd_all_options<Matrix2cd>)));
|
||||
CALL_SUBTEST_5((svd_all_trivial_2x2(bdcsvd_all_options<Matrix2d>)));
|
||||
|
||||
for (int i = 0; i < g_repeat; i++) {
|
||||
int r = internal::random<int>(1, EIGEN_TEST_MAX_SIZE/2),
|
||||
c = internal::random<int>(1, EIGEN_TEST_MAX_SIZE/2);
|
||||
|
||||
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(r)
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(c)
|
||||
|
||||
CALL_SUBTEST_6(( bdcsvd(Matrix<double,Dynamic,2>(r,2)) ));
|
||||
CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) ));
|
||||
CALL_SUBTEST_7(( compare_bdc_jacobi(MatrixXf(r,c)) ));
|
||||
CALL_SUBTEST_10(( bdcsvd(MatrixXd(r,c)) ));
|
||||
CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) ));
|
||||
CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) ));
|
||||
CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) ));
|
||||
|
||||
CALL_SUBTEST_6((compare_bdc_jacobi<MatrixXf>(MatrixXf(r, c))));
|
||||
CALL_SUBTEST_7((compare_bdc_jacobi<MatrixXd>(MatrixXd(r, c))));
|
||||
CALL_SUBTEST_8((compare_bdc_jacobi<MatrixXcd>(MatrixXcd(r, c))));
|
||||
// Test on inf/nan matrix
|
||||
CALL_SUBTEST_7( (svd_inf_nan<BDCSVD<MatrixXf>, MatrixXf>()) );
|
||||
CALL_SUBTEST_10( (svd_inf_nan<BDCSVD<MatrixXd>, MatrixXd>()) );
|
||||
CALL_SUBTEST_9((svd_inf_nan<MatrixXf>()));
|
||||
CALL_SUBTEST_10((svd_inf_nan<MatrixXd>()));
|
||||
|
||||
// Verify some computations using all combinations of the Options template parameter.
|
||||
CALL_SUBTEST_11((bdcsvd_all_options<Matrix3f>()));
|
||||
CALL_SUBTEST_12((bdcsvd_all_options<Matrix<float, 2, 3>>()));
|
||||
CALL_SUBTEST_13((bdcsvd_all_options<MatrixXd>(MatrixXd(20, 17))));
|
||||
CALL_SUBTEST_14((bdcsvd_all_options<MatrixXd>(MatrixXd(17, 20))));
|
||||
CALL_SUBTEST_15((bdcsvd_all_options<Matrix<double, Dynamic, 15>>(Matrix<double, Dynamic, 15>(r, 15))));
|
||||
CALL_SUBTEST_16((bdcsvd_all_options<Matrix<double, 13, Dynamic>>(Matrix<double, 13, Dynamic>(13, c))));
|
||||
CALL_SUBTEST_17((bdcsvd_all_options<MatrixXf>(MatrixXf(r, c))));
|
||||
CALL_SUBTEST_18((bdcsvd_all_options<MatrixXcd>(MatrixXcd(r, c))));
|
||||
CALL_SUBTEST_19((bdcsvd_all_options<MatrixXd>(MatrixXd(r, c))));
|
||||
CALL_SUBTEST_20((bdcsvd_all_options<Matrix<double, Dynamic, Dynamic, RowMajor>>(Matrix<double, Dynamic, Dynamic, RowMajor>(20, 27))));
|
||||
CALL_SUBTEST_21((bdcsvd_all_options<Matrix<double, Dynamic, Dynamic, RowMajor>>(Matrix<double, Dynamic, Dynamic, RowMajor>(27, 20))));
|
||||
|
||||
CALL_SUBTEST_22((
|
||||
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 20, 35>, ColPivHouseholderQRPreconditioner>(
|
||||
r, c)));
|
||||
CALL_SUBTEST_22(
|
||||
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 35, 20>, HouseholderQRPreconditioner>(r,
|
||||
c)));
|
||||
CALL_SUBTEST_22((
|
||||
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 20, 35>, ColPivHouseholderQRPreconditioner>(
|
||||
r, c)));
|
||||
CALL_SUBTEST_22(
|
||||
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 35, 20>, HouseholderQRPreconditioner>(r,
|
||||
c)));
|
||||
}
|
||||
|
||||
// test matrixbase method
|
||||
CALL_SUBTEST_1(( bdcsvd_method<Matrix2cd>() ));
|
||||
CALL_SUBTEST_3(( bdcsvd_method<Matrix3f>() ));
|
||||
CALL_SUBTEST_23(( bdcsvd_method<Matrix2cd>() ));
|
||||
CALL_SUBTEST_23(( bdcsvd_method<Matrix3f>() ));
|
||||
|
||||
// Test problem size constructors
|
||||
CALL_SUBTEST_7( BDCSVD<MatrixXf>(10,10) );
|
||||
CALL_SUBTEST_24( BDCSVD<MatrixXf>(10,10) );
|
||||
|
||||
// Check that preallocation avoids subsequent mallocs
|
||||
// Disabled because not supported by BDCSVD
|
||||
// CALL_SUBTEST_9( svd_preallocate<void>() );
|
||||
|
||||
CALL_SUBTEST_2( svd_underoverflow<void>() );
|
||||
}
|
||||
CALL_SUBTEST_25( svd_underoverflow<void>() );
|
||||
|
||||
// Without total deflation issues.
|
||||
CALL_SUBTEST_26(( compare_bdc_jacobi_instance(true) ));
|
||||
CALL_SUBTEST_26(( compare_bdc_jacobi_instance(false) ));
|
||||
|
||||
// With total deflation issues before, when it shouldn't be triggered.
|
||||
CALL_SUBTEST_27(( compare_bdc_jacobi_instance(true, 3) ));
|
||||
CALL_SUBTEST_27(( compare_bdc_jacobi_instance(false, 3) ));
|
||||
}
|
||||
|
||||
@@ -209,8 +209,8 @@ void test_numtraits()
|
||||
|
||||
void test_arithmetic()
|
||||
{
|
||||
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(2) + bfloat16(2)), 4);
|
||||
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(2) + bfloat16(-2)), 0);
|
||||
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(2) + bfloat16(2)), 4.f);
|
||||
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(2) + bfloat16(-2)), 0.f);
|
||||
VERIFY_IS_APPROX(static_cast<float>(bfloat16(0.33333f) + bfloat16(0.66667f)), 1.0f);
|
||||
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(2.0f) * bfloat16(-5.5f)), -11.0f);
|
||||
VERIFY_IS_APPROX(static_cast<float>(bfloat16(1.0f) / bfloat16(3.0f)), 0.3339f);
|
||||
|
||||
@@ -196,12 +196,7 @@ EIGEN_DECLARE_TEST(blasutil)
|
||||
|
||||
// TODO: Replace this by a call to numext::int64_t as soon as we have a way to
|
||||
// detect the typedef for int64_t on all platforms
|
||||
#if EIGEN_HAS_CXX11
|
||||
CALL_SUBTEST_4(run_test<signed long long>());
|
||||
#else
|
||||
CALL_SUBTEST_4(run_test<signed long>());
|
||||
#endif
|
||||
|
||||
CALL_SUBTEST_5(run_test<float_t>());
|
||||
CALL_SUBTEST_6(run_test<double_t>());
|
||||
CALL_SUBTEST_7(run_test<std::complex<float> >());
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
// 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, typename Index, typename Scalar>
|
||||
typename Eigen::internal::enable_if<!NumTraits<typename MatrixType::Scalar>::IsComplex,typename MatrixType::Scalar>::type
|
||||
std::enable_if_t<!NumTraits<typename MatrixType::Scalar>::IsComplex,typename MatrixType::Scalar>
|
||||
block_real_only(const MatrixType &m1, Index r1, Index r2, Index c1, Index c2, const Scalar& s1) {
|
||||
// check cwise-Functions:
|
||||
VERIFY_IS_APPROX(m1.row(r1).cwiseMax(s1), m1.cwiseMax(s1).row(r1));
|
||||
@@ -24,19 +23,33 @@ block_real_only(const MatrixType &m1, Index r1, Index r2, Index c1, Index c2, co
|
||||
}
|
||||
|
||||
template<typename MatrixType, typename Index, typename Scalar>
|
||||
typename Eigen::internal::enable_if<NumTraits<typename MatrixType::Scalar>::IsComplex,typename MatrixType::Scalar>::type
|
||||
std::enable_if_t<NumTraits<typename MatrixType::Scalar>::IsComplex,typename MatrixType::Scalar>
|
||||
block_real_only(const MatrixType &, Index, Index, Index, Index, const Scalar&) {
|
||||
return Scalar(0);
|
||||
}
|
||||
|
||||
// Check at compile-time that T1==T2, and at runtime-time that a==b
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
std::enable_if_t<internal::is_same<T1,T2>::value,bool>
|
||||
is_same_block(const T1& a, const T2& b)
|
||||
{
|
||||
return a.isApprox(b);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
std::enable_if_t<((MatrixType::Flags&RowMajorBit)==0),void>
|
||||
check_left_top(const MatrixType& m, Index r, Index c,
|
||||
Index rows, Index /*unused*/) {
|
||||
VERIFY_IS_EQUAL(m.leftCols(c).coeff(r+c*rows), m(r,c));
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
std::enable_if_t<((MatrixType::Flags&RowMajorBit)!=0),void>
|
||||
check_left_top(const MatrixType& m, Index r, Index c,
|
||||
Index /*unused*/, Index cols) {
|
||||
VERIFY_IS_EQUAL(m.topRows(r).coeff(c+r*cols), m(r,c));
|
||||
}
|
||||
|
||||
template<typename MatrixType> void block(const MatrixType& m)
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
@@ -79,7 +92,8 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
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_left_top(m1,r1,c1,rows,cols);
|
||||
|
||||
//check block()
|
||||
Matrix<Scalar,Dynamic,Dynamic> b1(1,1); b1(0,0) = m1(r1,c1);
|
||||
@@ -135,19 +149,14 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
}
|
||||
|
||||
// stress some basic stuffs with block matrices
|
||||
VERIFY(numext::real(ones.col(c1).sum()) == RealScalar(rows));
|
||||
VERIFY(numext::real(ones.row(r1).sum()) == RealScalar(cols));
|
||||
VERIFY_IS_EQUAL(numext::real(ones.col(c1).sum()), RealScalar(rows));
|
||||
VERIFY_IS_EQUAL(numext::real(ones.row(r1).sum()), RealScalar(cols));
|
||||
|
||||
VERIFY(numext::real(ones.col(c1).dot(ones.col(c2))) == RealScalar(rows));
|
||||
VERIFY(numext::real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols));
|
||||
VERIFY_IS_EQUAL(numext::real(ones.col(c1).dot(ones.col(c2))), RealScalar(rows));
|
||||
VERIFY_IS_EQUAL(numext::real(ones.row(r1).dot(ones.row(r2))), RealScalar(cols));
|
||||
|
||||
// check that linear acccessors works on blocks
|
||||
m1 = m1_copy;
|
||||
if((MatrixType::Flags&RowMajorBit)==0)
|
||||
VERIFY_IS_EQUAL(m1.leftCols(c1).coeff(r1+c1*rows), m1(r1,c1));
|
||||
else
|
||||
VERIFY_IS_EQUAL(m1.topRows(r1).coeff(c1+r1*cols), m1(r1,c1));
|
||||
|
||||
|
||||
// now test some block-inside-of-block.
|
||||
|
||||
@@ -213,14 +222,6 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
VERIFY_IS_EQUAL( ((m1*1).template block<Dynamic,1>(1,0,0,1)), m1.block(1,0,0,1));
|
||||
VERIFY_IS_EQUAL( ((m1*1).template block<1,Dynamic>(0,1,1,0)), m1.block(0,1,1,0));
|
||||
|
||||
if (rows>=2 && cols>=2)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT( m1 += m1.col(0) );
|
||||
VERIFY_RAISES_ASSERT( m1 -= m1.col(0) );
|
||||
VERIFY_RAISES_ASSERT( m1.array() *= m1.col(0).array() );
|
||||
VERIFY_RAISES_ASSERT( m1.array() /= m1.col(0).array() );
|
||||
}
|
||||
|
||||
VERIFY_IS_EQUAL( m1.template subVector<Horizontal>(r1), m1.row(r1) );
|
||||
VERIFY_IS_APPROX( (m1+m1).template subVector<Horizontal>(r1), (m1+m1).row(r1) );
|
||||
VERIFY_IS_EQUAL( m1.template subVector<Vertical>(c1), m1.col(c1) );
|
||||
@@ -240,13 +241,35 @@ template<typename MatrixType> void block(const MatrixType& m)
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename MatrixType>
|
||||
void compare_using_data_and_stride(const MatrixType& m)
|
||||
std::enable_if_t<MatrixType::IsVectorAtCompileTime,void>
|
||||
compare_using_data_and_stride(const MatrixType& m)
|
||||
{
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
Index size = m.size();
|
||||
Index innerStride = m.innerStride();
|
||||
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]);
|
||||
|
||||
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>
|
||||
std::enable_if_t<!MatrixType::IsVectorAtCompileTime,void>
|
||||
compare_using_data_and_stride(const MatrixType& m)
|
||||
{
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
Index innerStride = m.innerStride();
|
||||
Index outerStride = m.outerStride();
|
||||
Index rowStride = m.rowStride();
|
||||
Index colStride = m.colStride();
|
||||
@@ -256,21 +279,11 @@ void compare_using_data_and_stride(const MatrixType& m)
|
||||
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]);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
|
||||
@@ -74,8 +74,7 @@
|
||||
#include <boost/math/special_functions.hpp>
|
||||
#include <boost/math/complex.hpp>
|
||||
|
||||
namespace mp = boost::multiprecision;
|
||||
typedef mp::number<mp::cpp_dec_float<100>, mp::et_on> Real;
|
||||
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100>, boost::multiprecision::et_on> Real;
|
||||
|
||||
namespace Eigen {
|
||||
template<> struct NumTraits<Real> : GenericNumTraits<Real> {
|
||||
@@ -201,8 +200,8 @@ EIGEN_DECLARE_TEST(boostmultiprec)
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(s)
|
||||
}
|
||||
|
||||
CALL_SUBTEST_9(( jacobisvd(Mat(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) ));
|
||||
CALL_SUBTEST_10(( bdcsvd(Mat(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) ));
|
||||
CALL_SUBTEST_9(( jacobisvd_all_options(Mat(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) ));
|
||||
CALL_SUBTEST_10(( bdcsvd_all_options(Mat(internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE), internal::random<int>(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) ));
|
||||
|
||||
CALL_SUBTEST_11(( test_simplicial_cholesky_T<Real,int,ColMajor>() ));
|
||||
}
|
||||
|
||||
52
libs/eigen/test/constexpr.cpp
Normal file
52
libs/eigen/test/constexpr.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2022 Alex Richardson <alexrichardson@google.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"
|
||||
|
||||
EIGEN_DECLARE_TEST(constexpr) {
|
||||
// Clang accepts (some of) this code when using C++14/C++17, but GCC does not like
|
||||
// the fact that `T array[Size]` inside Eigen::internal::plain_array is not initialized
|
||||
// until after the constructor returns:
|
||||
// error: member ‘Eigen::internal::plain_array<int, 9, 0, 0>::array’ must be initialized by mem-initializer in
|
||||
// ‘constexpr’ constructor
|
||||
#if EIGEN_COMP_CXXVER >= 20
|
||||
constexpr Matrix3i mat({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
|
||||
VERIFY_IS_EQUAL(mat.size(), 9);
|
||||
VERIFY_IS_EQUAL(mat(0, 0), 1);
|
||||
static_assert(mat.coeff(0,1) == 2);
|
||||
constexpr Array33i arr({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
|
||||
VERIFY_IS_EQUAL(arr(0, 0), 1);
|
||||
VERIFY_IS_EQUAL(arr.size(), 9);
|
||||
static_assert(arr.coeff(0,1) == 2);
|
||||
// Also check dynamic size arrays/matrices with fixed-size storage (currently
|
||||
// only works if all elements are initialized, since otherwise the compiler
|
||||
// complains about uninitialized trailing elements.
|
||||
constexpr Matrix<int, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> dyn_mat({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
|
||||
VERIFY_IS_EQUAL(dyn_mat.size(), 9);
|
||||
VERIFY_IS_EQUAL(dyn_mat(0, 0), 1);
|
||||
static_assert(dyn_mat.coeff(0,1) == 2);
|
||||
constexpr Array<int, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> dyn_arr({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
|
||||
VERIFY_IS_EQUAL(dyn_arr(0, 0), 1);
|
||||
VERIFY_IS_EQUAL(dyn_arr.size(), 9);
|
||||
static_assert(dyn_arr.coeff(0,1) == 2);
|
||||
#endif // EIGEN_COMP_CXXVER >= 20
|
||||
}
|
||||
|
||||
// Check that we can use the std::initializer_list constructor for constexpr variables.
|
||||
#if EIGEN_COMP_CXXVER >= 20
|
||||
// EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT() will fail constexpr evaluation unless
|
||||
// we have std::is_constant_evaluated().
|
||||
constexpr Matrix<int, 2, 2> global_mat({{1, 2}, {3, 4}});
|
||||
|
||||
EIGEN_DECLARE_TEST(constexpr_global) {
|
||||
VERIFY_IS_EQUAL(global_mat.size(), 4);
|
||||
VERIFY_IS_EQUAL(global_mat(0, 0), 1);
|
||||
static_assert(global_mat.coeff(0,0) == 1);
|
||||
}
|
||||
#endif // EIGEN_COMP_CXXVER >= 20
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
#if EIGEN_HAS_TYPE_TRAITS && EIGEN_HAS_CXX11
|
||||
using DenseStorageD3x3 = Eigen::DenseStorage<double, 3, 3, 3, 3>;
|
||||
static_assert(std::is_trivially_move_constructible<DenseStorageD3x3>::value, "DenseStorage not trivially_move_constructible");
|
||||
static_assert(std::is_trivially_move_assignable<DenseStorageD3x3>::value, "DenseStorage not trivially_move_assignable");
|
||||
@@ -22,7 +21,6 @@ static_assert(std::is_trivially_copy_constructible<DenseStorageD3x3>::value, "De
|
||||
static_assert(std::is_trivially_copy_assignable<DenseStorageD3x3>::value, "DenseStorage not trivially_copy_assignable");
|
||||
static_assert(std::is_trivially_copyable<DenseStorageD3x3>::value, "DenseStorage not trivially_copyable");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename T, int Size, int Rows, int Cols>
|
||||
void dense_storage_copy(int rows, int cols)
|
||||
@@ -90,8 +88,6 @@ void dense_storage_swap(int rows0, int cols0, int rows1, int cols1)
|
||||
template<typename T, int Size, std::size_t Alignment>
|
||||
void dense_storage_alignment()
|
||||
{
|
||||
#if EIGEN_HAS_ALIGNAS
|
||||
|
||||
struct alignas(Alignment) Empty1 {};
|
||||
VERIFY_IS_EQUAL(std::alignment_of<Empty1>::value, Alignment);
|
||||
|
||||
@@ -104,13 +100,12 @@ void dense_storage_alignment()
|
||||
VERIFY_IS_EQUAL( (std::alignment_of<internal::plain_array<T,Size,AutoAlign,Alignment> >::value), Alignment);
|
||||
|
||||
const std::size_t default_alignment = internal::compute_default_alignment<T,Size>::value;
|
||||
|
||||
VERIFY_IS_EQUAL( (std::alignment_of<DenseStorage<T,Size,1,1,AutoAlign> >::value), default_alignment);
|
||||
VERIFY_IS_EQUAL( (std::alignment_of<Matrix<T,Size,1,AutoAlign> >::value), default_alignment);
|
||||
struct Nested2 { Matrix<T,Size,1,AutoAlign> mat; };
|
||||
VERIFY_IS_EQUAL(std::alignment_of<Nested2>::value, default_alignment);
|
||||
|
||||
#endif
|
||||
if (default_alignment > 0) {
|
||||
VERIFY_IS_EQUAL( (std::alignment_of<DenseStorage<T,Size,1,1,AutoAlign> >::value), default_alignment);
|
||||
VERIFY_IS_EQUAL( (std::alignment_of<Matrix<T,Size,1,AutoAlign> >::value), default_alignment);
|
||||
struct Nested2 { Matrix<T,Size,1,AutoAlign> mat; };
|
||||
VERIFY_IS_EQUAL(std::alignment_of<Nested2>::value, default_alignment);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -7,32 +7,8 @@
|
||||
// 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 assertionTest()
|
||||
{
|
||||
typedef DiagonalMatrix<Scalar, 5> DiagMatrix5;
|
||||
typedef DiagonalMatrix<Scalar, 7> DiagMatrix7;
|
||||
typedef DiagonalMatrix<Scalar, Dynamic> DiagMatrixX;
|
||||
|
||||
Scalar raw[6];
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
raw[i] = internal::random<Scalar>();
|
||||
}
|
||||
|
||||
VERIFY_RAISES_ASSERT((DiagMatrix5{raw[0], raw[1], raw[2], raw[3]}));
|
||||
VERIFY_RAISES_ASSERT((DiagMatrix5{raw[0], raw[1], raw[3]}));
|
||||
VERIFY_RAISES_ASSERT((DiagMatrix7{raw[0], raw[1], raw[2], raw[3]}));
|
||||
|
||||
VERIFY_RAISES_ASSERT((DiagMatrixX {
|
||||
{raw[0], raw[1], raw[2]},
|
||||
{raw[3], raw[4], raw[5]}
|
||||
}));
|
||||
}
|
||||
|
||||
#define VERIFY_IMPLICIT_CONVERSION_3(DIAGTYPE, V0, V1, V2) \
|
||||
DIAGTYPE d(V0, V1, V2); \
|
||||
DIAGTYPE::DenseMatrixType Dense = d.toDenseMatrix(); \
|
||||
@@ -167,14 +143,6 @@ void constructorTest<float>()
|
||||
|
||||
EIGEN_DECLARE_TEST(diagonal_matrix_variadic_ctor)
|
||||
{
|
||||
CALL_SUBTEST_1(assertionTest<unsigned char>());
|
||||
CALL_SUBTEST_1(assertionTest<float>());
|
||||
CALL_SUBTEST_1(assertionTest<Index>());
|
||||
CALL_SUBTEST_1(assertionTest<int>());
|
||||
CALL_SUBTEST_1(assertionTest<long int>());
|
||||
CALL_SUBTEST_1(assertionTest<std::ptrdiff_t>());
|
||||
CALL_SUBTEST_1(assertionTest<std::complex<double>>());
|
||||
|
||||
CALL_SUBTEST_2(constructorTest<unsigned char>());
|
||||
CALL_SUBTEST_2(constructorTest<float>());
|
||||
CALL_SUBTEST_2(constructorTest<Index>());
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
// 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
|
||||
// heap allocation will raise an assert if enabled at runtime
|
||||
#define EIGEN_RUNTIME_NO_MALLOC
|
||||
|
||||
#include "main.h"
|
||||
using namespace std;
|
||||
template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
@@ -56,6 +62,7 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
Index i = internal::random<Index>(0, rows-1);
|
||||
Index j = internal::random<Index>(0, cols-1);
|
||||
|
||||
internal::set_is_malloc_allowed(false);
|
||||
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) );
|
||||
@@ -65,6 +72,10 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
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) );
|
||||
VERIFY_IS_APPROX( (ldm1 * ldm1).diagonal()(i), ldm1.diagonal()(i) * ldm1.diagonal()(i) );
|
||||
VERIFY_IS_APPROX( (ldm1 * ldm1 * m1)(i, j), ldm1.diagonal()(i) * ldm1.diagonal()(i) * m1(i, j) );
|
||||
VERIFY_IS_APPROX( ((v1.asDiagonal() * v1.asDiagonal()).diagonal()(i)), v1(i) * v1(i) );
|
||||
internal::set_is_malloc_allowed(true);
|
||||
|
||||
if(rows>1)
|
||||
{
|
||||
@@ -84,7 +95,15 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
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() );
|
||||
|
||||
|
||||
// products do not allocate memory
|
||||
MatrixType res(rows, cols);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
res.noalias() = ldm1 * m1;
|
||||
res.noalias() = m1 * rdm1;
|
||||
res.noalias() = ldm1 * m1 * rdm1;
|
||||
res.noalias() = LeftDiagonalMatrix::Identity(rows) * m1 * RightDiagonalMatrix::Zero(cols);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
|
||||
// scalar multiple
|
||||
VERIFY_IS_APPROX(LeftDiagonalMatrix(ldm1*s1).diagonal(), ldm1.diagonal() * s1);
|
||||
@@ -112,6 +131,13 @@ template<typename MatrixType> void diagonalmatrices(const MatrixType& m)
|
||||
VERIFY_IS_APPROX( sq_m3 = v1.asDiagonal() + v2.asDiagonal(), sq_m1 + sq_m2);
|
||||
VERIFY_IS_APPROX( sq_m3 = v1.asDiagonal() - v2.asDiagonal(), sq_m1 - sq_m2);
|
||||
VERIFY_IS_APPROX( sq_m3 = v1.asDiagonal() - 2*v2.asDiagonal() + v1.asDiagonal(), sq_m1 - 2*sq_m2 + sq_m1);
|
||||
|
||||
// Zero and Identity
|
||||
LeftDiagonalMatrix zero = LeftDiagonalMatrix::Zero(rows);
|
||||
LeftDiagonalMatrix identity = LeftDiagonalMatrix::Identity(rows);
|
||||
VERIFY_IS_APPROX(identity.diagonal().sum(), Scalar(rows));
|
||||
VERIFY_IS_APPROX(zero.diagonal().sum(), Scalar(0));
|
||||
VERIFY_IS_APPROX((zero + 2 * LeftDiagonalMatrix::Identity(rows)).diagonal().sum(), Scalar(2 * rows));
|
||||
}
|
||||
|
||||
template<typename MatrixType> void as_scalar_product(const MatrixType& m)
|
||||
|
||||
@@ -20,9 +20,12 @@ typedef Matrix<float,8,1> Vector8f;
|
||||
|
||||
void check_handmade_aligned_malloc()
|
||||
{
|
||||
// Hand-make alignment needs at least sizeof(void*) to store the offset.
|
||||
constexpr int alignment = (std::max<int>)(EIGEN_DEFAULT_ALIGN_BYTES, sizeof(void*));
|
||||
|
||||
for(int i = 1; i < 1000; i++)
|
||||
{
|
||||
char *p = (char*)internal::handmade_aligned_malloc(i);
|
||||
char *p = (char*)internal::handmade_aligned_malloc(i, alignment);
|
||||
VERIFY(internal::UIntPtr(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;
|
||||
|
||||
@@ -85,6 +85,42 @@ template<typename MatrixType> void generalized_eigensolver_real(const MatrixType
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void generalized_eigensolver_assert() {
|
||||
GeneralizedEigenSolver<MatrixType> eig;
|
||||
// all raise assert if uninitialized
|
||||
VERIFY_RAISES_ASSERT(eig.info());
|
||||
VERIFY_RAISES_ASSERT(eig.eigenvectors());
|
||||
VERIFY_RAISES_ASSERT(eig.eigenvalues());
|
||||
VERIFY_RAISES_ASSERT(eig.alphas());
|
||||
VERIFY_RAISES_ASSERT(eig.betas());
|
||||
|
||||
// none raise assert after compute called
|
||||
eig.compute(MatrixType::Random(20, 20), MatrixType::Random(20, 20));
|
||||
VERIFY(eig.info() == Success);
|
||||
eig.eigenvectors();
|
||||
eig.eigenvalues();
|
||||
eig.alphas();
|
||||
eig.betas();
|
||||
|
||||
// eigenvectors() raises assert, if eigenvectors were not requested
|
||||
eig.compute(MatrixType::Random(20, 20), MatrixType::Random(20, 20), false);
|
||||
VERIFY(eig.info() == Success);
|
||||
VERIFY_RAISES_ASSERT(eig.eigenvectors());
|
||||
eig.eigenvalues();
|
||||
eig.alphas();
|
||||
eig.betas();
|
||||
|
||||
// all except info raise assert if realQZ did not converge
|
||||
eig.setMaxIterations(0); // force real QZ to fail.
|
||||
eig.compute(MatrixType::Random(20, 20), MatrixType::Random(20, 20));
|
||||
VERIFY(eig.info() == NoConvergence);
|
||||
VERIFY_RAISES_ASSERT(eig.eigenvectors());
|
||||
VERIFY_RAISES_ASSERT(eig.eigenvalues());
|
||||
VERIFY_RAISES_ASSERT(eig.alphas());
|
||||
VERIFY_RAISES_ASSERT(eig.betas());
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(eigensolver_generalized_real)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -98,6 +134,7 @@ EIGEN_DECLARE_TEST(eigensolver_generalized_real)
|
||||
CALL_SUBTEST_2( generalized_eigensolver_real(MatrixXd(2,2)) );
|
||||
CALL_SUBTEST_3( generalized_eigensolver_real(Matrix<double,1,1>()) );
|
||||
CALL_SUBTEST_4( generalized_eigensolver_real(Matrix2d()) );
|
||||
CALL_SUBTEST_5( generalized_eigensolver_assert<MatrixXd>() );
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +510,9 @@ EIGEN_DECLARE_TEST(evaluators)
|
||||
const size_t K = 2;
|
||||
const size_t N = 5;
|
||||
float *destMem = new float[(M*N) + 1];
|
||||
float *dest = (internal::UIntPtr(destMem)%EIGEN_MAX_ALIGN_BYTES) == 0 ? destMem+1 : destMem;
|
||||
// In case of no alignment, avoid division by zero.
|
||||
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
|
||||
float *dest = (internal::UIntPtr(destMem)%alignment) == 0 ? destMem+1 : destMem;
|
||||
|
||||
const Matrix<float, Dynamic, Dynamic, RowMajor> a = Matrix<float, Dynamic, Dynamic, RowMajor>::Random(M, K);
|
||||
const Matrix<float, Dynamic, Dynamic, RowMajor> b = Matrix<float, Dynamic, Dynamic, RowMajor>::Random(K, N);
|
||||
|
||||
@@ -211,7 +211,7 @@ MatrixType randomRotationMatrix()
|
||||
// https://www.isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/III-7/103/2016/isprs-annals-III-7-103-2016.pdf
|
||||
const MatrixType rand = MatrixType::Random();
|
||||
const MatrixType q = rand.householderQr().householderQ();
|
||||
const JacobiSVD<MatrixType> svd = q.jacobiSvd(ComputeFullU | ComputeFullV);
|
||||
const JacobiSVD<MatrixType, ComputeFullU | ComputeFullV> svd(q);
|
||||
const typename MatrixType::Scalar det = (svd.matrixU() * svd.matrixV().transpose()).determinant();
|
||||
MatrixType diag = rand.Identity();
|
||||
diag(MatrixType::RowsAtCompileTime - 1, MatrixType::ColsAtCompileTime - 1) = det;
|
||||
|
||||
@@ -26,7 +26,7 @@ void verify_euler(const Matrix<Scalar,3,1>& ea, int i, int j, int k)
|
||||
VERIFY_IS_APPROX(m, mbis);
|
||||
/* If I==K, and ea[1]==0, then there no unique solution. */
|
||||
/* The remark apply in the case where I!=K, and |ea[1]| is close to pi/2. */
|
||||
if( (i!=k || ea[1]!=0) && (i==k || !internal::isApprox(abs(ea[1]),Scalar(EIGEN_PI/2),test_precision<Scalar>())) )
|
||||
if((i!=k || !numext::is_exactly_zero(ea[1])) && (i == k || !internal::isApprox(abs(ea[1]), Scalar(EIGEN_PI / 2), test_precision<Scalar>())) )
|
||||
VERIFY((ea-eabis).norm() <= test_precision<Scalar>());
|
||||
|
||||
// approx_or_less_than does not work for 0
|
||||
|
||||
@@ -73,8 +73,39 @@ template<typename Scalar> void orthomethods_3()
|
||||
// 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));
|
||||
v2 = rv1.template cast<Scalar>();
|
||||
VERIFY_IS_APPROX(v1.cross(v2), v1.cross(rv1));
|
||||
VERIFY_IS_APPROX(v2.cross(v1), rv1.cross(v1));
|
||||
}
|
||||
|
||||
template<typename Scalar> void orthomethods_2()
|
||||
{
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar,2,1> Vector2;
|
||||
typedef Matrix<Scalar,3,1> Vector3;
|
||||
|
||||
Vector3 v30 = Vector3::Random(),
|
||||
v31 = Vector3::Random();
|
||||
Vector2 v20 = v30.template head<2>();
|
||||
Vector2 v21 = v31.template head<2>();
|
||||
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v20.cross(v20), Scalar(1));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(v21.cross(v21), Scalar(1));
|
||||
VERIFY_IS_APPROX(v20.cross(v21), v30.cross(v31).z());
|
||||
|
||||
Vector2 v20Rot90(numext::conj(-v20.y()), numext::conj(v20.x()));
|
||||
VERIFY_IS_APPROX(v20.cross( v20Rot90), v20.squaredNorm());
|
||||
VERIFY_IS_APPROX(v20.cross(-v20Rot90), -v20.squaredNorm());
|
||||
Vector2 v21Rot90(numext::conj(-v21.y()), numext::conj(v21.x()));
|
||||
VERIFY_IS_APPROX(v21.cross( v21Rot90), v21.squaredNorm());
|
||||
VERIFY_IS_APPROX(v21.cross(-v21Rot90), -v21.squaredNorm());
|
||||
|
||||
// check mixed product
|
||||
typedef Matrix<RealScalar, 2, 1> RealVector2;
|
||||
RealVector2 rv21 = RealVector2::Random();
|
||||
v21 = rv21.template cast<Scalar>();
|
||||
VERIFY_IS_APPROX(v20.cross(v21), v20.cross(rv21));
|
||||
VERIFY_IS_APPROX(v21.cross(v20), rv21.cross(v20));
|
||||
}
|
||||
|
||||
template<typename Scalar, int Size> void orthomethods(int size=Size)
|
||||
@@ -118,6 +149,9 @@ template<typename Scalar, int Size> void orthomethods(int size=Size)
|
||||
EIGEN_DECLARE_TEST(geo_orthomethods)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1( orthomethods_2<float>() );
|
||||
CALL_SUBTEST_2( orthomethods_2<double>() );
|
||||
CALL_SUBTEST_4( orthomethods_2<std::complex<double> >() );
|
||||
CALL_SUBTEST_1( orthomethods_3<float>() );
|
||||
CALL_SUBTEST_2( orthomethods_3<double>() );
|
||||
CALL_SUBTEST_4( orthomethods_3<std::complex<double> >() );
|
||||
|
||||
@@ -286,15 +286,13 @@ template<typename PlainObjectType> void check_const_correctness(const PlainObjec
|
||||
// CMake can help with that.
|
||||
|
||||
// verify that map-to-const don't have LvalueBit
|
||||
typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
|
||||
typedef std::add_const_t<PlainObjectType> 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) );
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_RVALUE_REFERENCES
|
||||
|
||||
// Regression for bug 1573
|
||||
struct MovableClass {
|
||||
// The following line is a workaround for gcc 4.7 and 4.8 (see bug 1573 comments).
|
||||
@@ -307,8 +305,6 @@ struct MovableClass {
|
||||
Quaternionf m_quat;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
EIGEN_DECLARE_TEST(geo_quaternion)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
|
||||
@@ -138,10 +138,12 @@ struct complex_operators {
|
||||
out[out_idx++] = a / numext::real(b);
|
||||
out[out_idx++] = numext::real(a) / b;
|
||||
|
||||
#if !defined(EIGEN_COMP_MSVC)
|
||||
out[out_idx] = a; out[out_idx++] += b;
|
||||
out[out_idx] = a; out[out_idx++] -= b;
|
||||
out[out_idx] = a; out[out_idx++] *= b;
|
||||
out[out_idx] = a; out[out_idx++] /= b;
|
||||
#endif
|
||||
|
||||
const ComplexType true_value = ComplexType(ValueType(1), ValueType(0));
|
||||
const ComplexType false_value = ComplexType(ValueType(0), ValueType(0));
|
||||
@@ -188,6 +190,7 @@ struct complex_operators {
|
||||
res.segment(block_idx, size) = x1.real().array() / x2.array();
|
||||
block_idx += size;
|
||||
|
||||
#if !defined(EIGEN_COMP_MSVC)
|
||||
res.segment(block_idx, size) = x1; res.segment(block_idx, size) += x2;
|
||||
block_idx += size;
|
||||
res.segment(block_idx, size) = x1; res.segment(block_idx, size) -= x2;
|
||||
@@ -196,6 +199,7 @@ struct complex_operators {
|
||||
block_idx += size;
|
||||
res.segment(block_idx, size) = x1; res.segment(block_idx, size).array() /= x2.array();
|
||||
block_idx += size;
|
||||
#endif
|
||||
|
||||
const T true_vector = T::Constant(true_value);
|
||||
const T false_vector = T::Constant(false_value);
|
||||
|
||||
129
libs/eigen/test/gpu_example.cu
Normal file
129
libs/eigen/test/gpu_example.cu
Normal file
@@ -0,0 +1,129 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 The Eigen Team.
|
||||
//
|
||||
// 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/.
|
||||
|
||||
// The following is an example GPU test.
|
||||
|
||||
#include "main.h" // Include the main test utilities.
|
||||
|
||||
// Define a kernel functor.
|
||||
//
|
||||
// The kernel must be a POD type and implement operator().
|
||||
struct AddKernel {
|
||||
// Parameters must be POD or serializable Eigen types (e.g. Matrix,
|
||||
// Array). The return value must be a POD or serializable value type.
|
||||
template<typename Type1, typename Type2, typename Type3>
|
||||
EIGEN_DEVICE_FUNC
|
||||
Type3 operator()(const Type1& A, const Type2& B, Type3& C) const {
|
||||
C = A + B; // Populate output parameter.
|
||||
Type3 D = A + B; // Populate return value.
|
||||
return D;
|
||||
}
|
||||
};
|
||||
|
||||
// Define a sub-test that uses the kernel.
|
||||
template <typename T>
|
||||
void test_add(const T& type) {
|
||||
const Index rows = type.rows();
|
||||
const Index cols = type.cols();
|
||||
|
||||
// Create random inputs.
|
||||
const T A = T::Random(rows, cols);
|
||||
const T B = T::Random(rows, cols);
|
||||
T C; // Output parameter.
|
||||
|
||||
// Create kernel.
|
||||
AddKernel add_kernel;
|
||||
|
||||
// Run add_kernel(A, B, C) via run(...).
|
||||
// This will run on the GPU if using a GPU compiler, or CPU otherwise,
|
||||
// facilitating generic tests that can run on either.
|
||||
T D = run(add_kernel, A, B, C);
|
||||
|
||||
// Check that both output parameter and return value are correctly populated.
|
||||
const T expected = A + B;
|
||||
VERIFY_IS_CWISE_EQUAL(C, expected);
|
||||
VERIFY_IS_CWISE_EQUAL(D, expected);
|
||||
|
||||
// In a GPU-only test, we can verify that the CPU and GPU produce the
|
||||
// same results.
|
||||
T C_cpu, C_gpu;
|
||||
T D_cpu = run_on_cpu(add_kernel, A, B, C_cpu); // Runs on CPU.
|
||||
T D_gpu = run_on_gpu(add_kernel, A, B, C_gpu); // Runs on GPU.
|
||||
VERIFY_IS_CWISE_EQUAL(C_cpu, C_gpu);
|
||||
VERIFY_IS_CWISE_EQUAL(D_cpu, D_gpu);
|
||||
};
|
||||
|
||||
struct MultiplyKernel {
|
||||
template<typename Type1, typename Type2, typename Type3>
|
||||
EIGEN_DEVICE_FUNC
|
||||
Type3 operator()(const Type1& A, const Type2& B, Type3& C) const {
|
||||
C = A * B;
|
||||
return A * B;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void test_multiply(const T1& type1, const T2& type2, const T3& type3) {
|
||||
const T1 A = T1::Random(type1.rows(), type1.cols());
|
||||
const T2 B = T2::Random(type2.rows(), type2.cols());
|
||||
T3 C;
|
||||
|
||||
MultiplyKernel multiply_kernel;
|
||||
|
||||
// The run(...) family of functions uses a memory buffer to transfer data back
|
||||
// and forth to and from the device. The size of this buffer is estimated
|
||||
// from the size of all input parameters. If the estimated buffer size is
|
||||
// not sufficient for transferring outputs from device-to-host, then an
|
||||
// explicit buffer size needs to be specified.
|
||||
|
||||
// 2 outputs of size (A * B). For each matrix output, the buffer will store
|
||||
// the number of rows, columns, and the data.
|
||||
size_t buffer_capacity_hint = 2 * ( // 2 output parameters
|
||||
2 * sizeof(typename T3::Index) // # Rows, # Cols
|
||||
+ A.rows() * B.cols() * sizeof(typename T3::Scalar)); // Output data
|
||||
|
||||
T3 D = run_with_hint(buffer_capacity_hint, multiply_kernel, A, B, C);
|
||||
|
||||
const T3 expected = A * B;
|
||||
VERIFY_IS_CWISE_APPROX(C, expected);
|
||||
VERIFY_IS_CWISE_APPROX(D, expected);
|
||||
|
||||
T3 C_cpu, C_gpu;
|
||||
T3 D_cpu = run_on_cpu(multiply_kernel, A, B, C_cpu);
|
||||
T3 D_gpu = run_on_gpu_with_hint(buffer_capacity_hint,
|
||||
multiply_kernel, A, B, C_gpu);
|
||||
VERIFY_IS_CWISE_APPROX(C_cpu, C_gpu);
|
||||
VERIFY_IS_CWISE_APPROX(D_cpu, D_gpu);
|
||||
}
|
||||
|
||||
// Declare the test fixture.
|
||||
EIGEN_DECLARE_TEST(gpu_example)
|
||||
{
|
||||
// For the number of repeats, call the desired subtests.
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
// Call subtests with different sized/typed inputs.
|
||||
CALL_SUBTEST( test_add(Eigen::Vector3f()) );
|
||||
CALL_SUBTEST( test_add(Eigen::Matrix3d()) );
|
||||
CALL_SUBTEST( test_add(Eigen::MatrixX<int>(10, 10)) );
|
||||
|
||||
CALL_SUBTEST( test_add(Eigen::Array44f()) );
|
||||
CALL_SUBTEST( test_add(Eigen::ArrayXd(20)) );
|
||||
CALL_SUBTEST( test_add(Eigen::ArrayXXi(13, 17)) );
|
||||
|
||||
CALL_SUBTEST( test_multiply(Eigen::Matrix3d(),
|
||||
Eigen::Matrix3d(),
|
||||
Eigen::Matrix3d()) );
|
||||
CALL_SUBTEST( test_multiply(Eigen::MatrixX<int>(10, 10),
|
||||
Eigen::MatrixX<int>(10, 10),
|
||||
Eigen::MatrixX<int>()) );
|
||||
CALL_SUBTEST( test_multiply(Eigen::MatrixXf(12, 1),
|
||||
Eigen::MatrixXf(1, 32),
|
||||
Eigen::MatrixXf()) );
|
||||
}
|
||||
}
|
||||
476
libs/eigen/test/gpu_test_helper.h
Normal file
476
libs/eigen/test/gpu_test_helper.h
Normal file
@@ -0,0 +1,476 @@
|
||||
#ifndef GPU_TEST_HELPER_H
|
||||
#define GPU_TEST_HELPER_H
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
#ifdef EIGEN_GPUCC
|
||||
#define EIGEN_USE_GPU
|
||||
#include "../unsupported/Eigen/CXX11/src/Tensor/TensorGpuHipCudaDefines.h"
|
||||
#endif // EIGEN_GPUCC
|
||||
|
||||
// std::tuple cannot be used on device, and there is a bug in cuda < 9.2 that
|
||||
// doesn't allow std::tuple to compile for host code either. In these cases,
|
||||
// use our custom implementation.
|
||||
#if defined(EIGEN_GPU_COMPILE_PHASE) || (defined(EIGEN_CUDACC) && EIGEN_CUDA_SDK_VER < 92000)
|
||||
#define EIGEN_USE_CUSTOM_TUPLE 1
|
||||
#else
|
||||
#define EIGEN_USE_CUSTOM_TUPLE 0
|
||||
#endif
|
||||
|
||||
#if EIGEN_USE_CUSTOM_TUPLE
|
||||
#include "../Eigen/src/Core/arch/GPU/Tuple.h"
|
||||
#else
|
||||
#include <tuple>
|
||||
#endif
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Note: cannot re-use tuple_impl, since that will cause havoc for
|
||||
// tuple_test.
|
||||
namespace test_detail {
|
||||
// Use std::tuple on CPU, otherwise use the GPU-specific versions.
|
||||
#if !EIGEN_USE_CUSTOM_TUPLE
|
||||
using std::tuple;
|
||||
using std::get;
|
||||
using std::make_tuple;
|
||||
using std::tie;
|
||||
#else
|
||||
using tuple_impl::tuple;
|
||||
using tuple_impl::get;
|
||||
using tuple_impl::make_tuple;
|
||||
using tuple_impl::tie;
|
||||
#endif
|
||||
#undef EIGEN_USE_CUSTOM_TUPLE
|
||||
} // namespace test_detail
|
||||
|
||||
template<size_t N, size_t Idx, typename OutputIndexSequence, typename... Ts>
|
||||
struct extract_output_indices_helper;
|
||||
|
||||
/**
|
||||
* Extracts a set of indices corresponding to non-const l-value reference
|
||||
* output types.
|
||||
*
|
||||
* \internal
|
||||
* \tparam N the number of types {T1, Ts...}.
|
||||
* \tparam Idx the "index" to append if T1 is an output type.
|
||||
* \tparam OutputIndices the current set of output indices.
|
||||
* \tparam T1 the next type to consider, with index Idx.
|
||||
* \tparam Ts the remaining types.
|
||||
*/
|
||||
template<size_t N, size_t Idx, size_t... OutputIndices, typename T1, typename... Ts>
|
||||
struct extract_output_indices_helper<N, Idx, std::index_sequence<OutputIndices...>, T1, Ts...> {
|
||||
using type = typename
|
||||
extract_output_indices_helper<
|
||||
N - 1, Idx + 1,
|
||||
typename std::conditional<
|
||||
// If is a non-const l-value reference, append index.
|
||||
std::is_lvalue_reference<T1>::value
|
||||
&& !std::is_const<std::remove_reference_t<T1>>::value,
|
||||
std::index_sequence<OutputIndices..., Idx>,
|
||||
std::index_sequence<OutputIndices...> >::type,
|
||||
Ts...>::type;
|
||||
};
|
||||
|
||||
// Base case.
|
||||
template<size_t Idx, size_t... OutputIndices>
|
||||
struct extract_output_indices_helper<0, Idx, std::index_sequence<OutputIndices...> > {
|
||||
using type = std::index_sequence<OutputIndices...>;
|
||||
};
|
||||
|
||||
// Extracts a set of indices into Types... that correspond to non-const
|
||||
// l-value references.
|
||||
template<typename... Types>
|
||||
using extract_output_indices = typename extract_output_indices_helper<sizeof...(Types), 0, std::index_sequence<>, Types...>::type;
|
||||
|
||||
// Helper struct for dealing with Generic functors that may return void.
|
||||
struct void_helper {
|
||||
struct Void {};
|
||||
|
||||
// Converts void -> Void, T otherwise.
|
||||
template<typename T>
|
||||
using ReturnType = typename std::conditional<std::is_same<T, void>::value, Void, T>::type;
|
||||
|
||||
// Non-void return value.
|
||||
template<typename Func, typename... Args>
|
||||
static EIGEN_ALWAYS_INLINE EIGEN_DEVICE_FUNC
|
||||
auto call(Func&& func, Args&&... args) ->
|
||||
std::enable_if_t<!std::is_same<decltype(func(args...)), void>::value,
|
||||
decltype(func(args...))> {
|
||||
return func(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Void return value.
|
||||
template<typename Func, typename... Args>
|
||||
static EIGEN_ALWAYS_INLINE EIGEN_DEVICE_FUNC
|
||||
auto call(Func&& func, Args&&... args) ->
|
||||
std::enable_if_t<std::is_same<decltype(func(args...)), void>::value,
|
||||
Void> {
|
||||
func(std::forward<Args>(args)...);
|
||||
return Void{};
|
||||
}
|
||||
|
||||
// Restores the original return type, Void -> void, T otherwise.
|
||||
template<typename T>
|
||||
static EIGEN_ALWAYS_INLINE EIGEN_DEVICE_FUNC
|
||||
std::enable_if_t<!std::is_same<typename std::decay<T>::type, Void>::value, T>
|
||||
restore(T&& val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// Void case.
|
||||
template<typename T = void>
|
||||
static EIGEN_ALWAYS_INLINE EIGEN_DEVICE_FUNC
|
||||
void restore(const Void&) {}
|
||||
};
|
||||
|
||||
// Runs a kernel via serialized buffer. Does this by deserializing the buffer
|
||||
// to construct the arguments, calling the kernel, then re-serialing the outputs.
|
||||
// The buffer contains
|
||||
// [ input_buffer_size, args ]
|
||||
// After the kernel call, it is then populated with
|
||||
// [ output_buffer_size, output_parameters, return_value ]
|
||||
// If the output_buffer_size exceeds the buffer's capacity, then only the
|
||||
// output_buffer_size is populated.
|
||||
template<typename Kernel, typename... Args, size_t... Indices, size_t... OutputIndices>
|
||||
EIGEN_DEVICE_FUNC
|
||||
void run_serialized(std::index_sequence<Indices...>, std::index_sequence<OutputIndices...>,
|
||||
Kernel kernel, uint8_t* buffer, size_t capacity) {
|
||||
using test_detail::get;
|
||||
using test_detail::make_tuple;
|
||||
using test_detail::tuple;
|
||||
// Deserialize input size and inputs.
|
||||
size_t input_size;
|
||||
const uint8_t* read_ptr = buffer;
|
||||
const uint8_t* read_end = buffer + capacity;
|
||||
read_ptr = Eigen::deserialize(read_ptr, read_end, input_size);
|
||||
// Create value-type instances to populate.
|
||||
auto args = make_tuple(typename std::decay<Args>::type{}...);
|
||||
EIGEN_UNUSED_VARIABLE(args) // Avoid NVCC compile warning.
|
||||
// NVCC 9.1 requires us to spell out the template parameters explicitly.
|
||||
read_ptr = Eigen::deserialize(read_ptr, read_end, get<Indices, typename std::decay<Args>::type...>(args)...);
|
||||
|
||||
// Call function, with void->Void conversion so we are guaranteed a complete
|
||||
// output type.
|
||||
auto result = void_helper::call(kernel, get<Indices, typename std::decay<Args>::type...>(args)...);
|
||||
|
||||
// Determine required output size.
|
||||
size_t output_size = Eigen::serialize_size(capacity);
|
||||
output_size += Eigen::serialize_size(get<OutputIndices, typename std::decay<Args>::type...>(args)...);
|
||||
output_size += Eigen::serialize_size(result);
|
||||
|
||||
// Always serialize required buffer size.
|
||||
uint8_t* write_ptr = buffer;
|
||||
uint8_t* write_end = buffer + capacity;
|
||||
write_ptr = Eigen::serialize(write_ptr, write_end, output_size);
|
||||
// Null `write_ptr` can be safely passed along.
|
||||
// Serialize outputs if they fit in the buffer.
|
||||
if (output_size <= capacity) {
|
||||
// Collect outputs and result.
|
||||
write_ptr = Eigen::serialize(write_ptr, write_end, get<OutputIndices, typename std::decay<Args>::type...>(args)...);
|
||||
write_ptr = Eigen::serialize(write_ptr, write_end, result);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Kernel, typename... Args>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
void run_serialized(Kernel kernel, uint8_t* buffer, size_t capacity) {
|
||||
run_serialized<Kernel, Args...> (std::make_index_sequence<sizeof...(Args)>{},
|
||||
extract_output_indices<Args...>{},
|
||||
kernel, buffer, capacity);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_GPUCC
|
||||
|
||||
// Checks for GPU errors and asserts / prints the error message.
|
||||
#define GPU_CHECK(expr) \
|
||||
do { \
|
||||
gpuError_t err = expr; \
|
||||
if (err != gpuSuccess) { \
|
||||
printf("%s: %s\n", gpuGetErrorName(err), gpuGetErrorString(err)); \
|
||||
gpu_assert(false); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
// Calls run_serialized on the GPU.
|
||||
template<typename Kernel, typename... Args>
|
||||
__global__
|
||||
EIGEN_HIP_LAUNCH_BOUNDS_1024
|
||||
void run_serialized_on_gpu_meta_kernel(const Kernel kernel, uint8_t* buffer, size_t capacity) {
|
||||
run_serialized<Kernel, Args...>(kernel, buffer, capacity);
|
||||
}
|
||||
|
||||
// Runs kernel(args...) on the GPU via the serialization mechanism.
|
||||
//
|
||||
// Note: this may end up calling the kernel multiple times if the initial output
|
||||
// buffer is not large enough to hold the outputs.
|
||||
template<typename Kernel, typename... Args, size_t... Indices, size_t... OutputIndices>
|
||||
auto run_serialized_on_gpu(size_t buffer_capacity_hint,
|
||||
std::index_sequence<Indices...>,
|
||||
std::index_sequence<OutputIndices...>,
|
||||
Kernel kernel, Args&&... args) -> decltype(kernel(args...)) {
|
||||
// Compute the required serialization buffer capacity.
|
||||
// Round up input size to next power of two to give a little extra room
|
||||
// for outputs.
|
||||
size_t input_data_size = sizeof(size_t) + Eigen::serialize_size(args...);
|
||||
|
||||
size_t capacity;
|
||||
if (buffer_capacity_hint == 0) {
|
||||
// Estimate as the power of two larger than the total input size.
|
||||
capacity = sizeof(size_t);
|
||||
while (capacity <= input_data_size) {
|
||||
capacity *= 2;
|
||||
}
|
||||
} else {
|
||||
// Use the larger of the hint and the total input size.
|
||||
// Add sizeof(size_t) to the hint to account for storing the buffer capacity
|
||||
// itself so the user doesn't need to think about this.
|
||||
capacity = std::max<size_t>(buffer_capacity_hint + sizeof(size_t),
|
||||
input_data_size);
|
||||
}
|
||||
std::vector<uint8_t> buffer(capacity);
|
||||
|
||||
uint8_t* host_data = nullptr;
|
||||
uint8_t* host_data_end = nullptr;
|
||||
uint8_t* host_ptr = nullptr;
|
||||
uint8_t* device_data = nullptr;
|
||||
size_t output_data_size = 0;
|
||||
|
||||
// Allocate buffers and copy input data.
|
||||
capacity = std::max<size_t>(capacity, output_data_size);
|
||||
buffer.resize(capacity);
|
||||
host_data = buffer.data();
|
||||
host_data_end = buffer.data() + capacity;
|
||||
host_ptr = Eigen::serialize(host_data, host_data_end, input_data_size);
|
||||
host_ptr = Eigen::serialize(host_ptr, host_data_end, args...);
|
||||
|
||||
// Copy inputs to host.
|
||||
gpuMalloc((void**)(&device_data), capacity);
|
||||
gpuMemcpy(device_data, buffer.data(), input_data_size, gpuMemcpyHostToDevice);
|
||||
GPU_CHECK(gpuDeviceSynchronize());
|
||||
|
||||
// Run kernel.
|
||||
#ifdef EIGEN_USE_HIP
|
||||
hipLaunchKernelGGL(
|
||||
HIP_KERNEL_NAME(run_serialized_on_gpu_meta_kernel<Kernel, Args...>),
|
||||
1, 1, 0, 0, kernel, device_data, capacity);
|
||||
#else
|
||||
run_serialized_on_gpu_meta_kernel<Kernel, Args...><<<1,1>>>(
|
||||
kernel, device_data, capacity);
|
||||
#endif
|
||||
// Check pre-launch and kernel execution errors.
|
||||
GPU_CHECK(gpuGetLastError());
|
||||
GPU_CHECK(gpuDeviceSynchronize());
|
||||
// Copy back new output to host.
|
||||
gpuMemcpy(host_data, device_data, capacity, gpuMemcpyDeviceToHost);
|
||||
gpuFree(device_data);
|
||||
GPU_CHECK(gpuDeviceSynchronize());
|
||||
|
||||
// Determine output buffer size.
|
||||
const uint8_t* c_host_ptr = Eigen::deserialize(host_data, host_data_end, output_data_size);
|
||||
// If the output doesn't fit in the buffer, spit out warning and fail.
|
||||
if (output_data_size > capacity) {
|
||||
std::cerr << "The serialized output does not fit in the output buffer, "
|
||||
<< output_data_size << " vs capacity " << capacity << "."
|
||||
<< std::endl
|
||||
<< "Try specifying a minimum buffer capacity: " << std::endl
|
||||
<< " run_with_hint(" << output_data_size << ", ...)"
|
||||
<< std::endl;
|
||||
VERIFY(false);
|
||||
}
|
||||
|
||||
// Deserialize outputs.
|
||||
auto args_tuple = test_detail::tie(args...);
|
||||
EIGEN_UNUSED_VARIABLE(args_tuple) // Avoid NVCC compile warning.
|
||||
c_host_ptr = Eigen::deserialize(c_host_ptr, host_data_end, test_detail::get<OutputIndices, Args&...>(args_tuple)...);
|
||||
|
||||
// Maybe deserialize return value, properly handling void.
|
||||
typename void_helper::ReturnType<decltype(kernel(args...))> result;
|
||||
c_host_ptr = Eigen::deserialize(c_host_ptr, host_data_end, result);
|
||||
return void_helper::restore(result);
|
||||
}
|
||||
|
||||
#endif // EIGEN_GPUCC
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Runs a kernel on the CPU, returning the results.
|
||||
* \param kernel kernel to run.
|
||||
* \param args ... input arguments.
|
||||
* \return kernel(args...).
|
||||
*/
|
||||
template<typename Kernel, typename... Args>
|
||||
auto run_on_cpu(Kernel kernel, Args&&... args) -> decltype(kernel(args...)){
|
||||
return kernel(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_GPUCC
|
||||
|
||||
/**
|
||||
* Runs a kernel on the GPU, returning the results.
|
||||
*
|
||||
* The kernel must be able to be passed directly as an input to a global
|
||||
* function (i.e. empty or POD). Its inputs must be "Serializable" so we
|
||||
* can transfer them to the device, and the output must be a Serializable value
|
||||
* type so it can be transferred back from the device.
|
||||
*
|
||||
* \param kernel kernel to run.
|
||||
* \param args ... input arguments, must be "Serializable".
|
||||
* \return kernel(args...).
|
||||
*/
|
||||
template<typename Kernel, typename... Args>
|
||||
auto run_on_gpu(Kernel kernel, Args&&... args) -> decltype(kernel(args...)){
|
||||
return internal::run_serialized_on_gpu<Kernel, Args...>(
|
||||
/*buffer_capacity_hint=*/ 0,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
internal::extract_output_indices<Args...>{},
|
||||
kernel, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a kernel on the GPU, returning the results.
|
||||
*
|
||||
* This version allows specifying a minimum buffer capacity size required for
|
||||
* serializing the puts to transfer results from device to host. Use this when
|
||||
* `run_on_gpu(...)` fails to determine an appropriate capacity by default.
|
||||
*
|
||||
* \param buffer_capacity_hint minimum required buffer size for serializing
|
||||
* outputs.
|
||||
* \param kernel kernel to run.
|
||||
* \param args ... input arguments, must be "Serializable".
|
||||
* \return kernel(args...).
|
||||
* \sa run_on_gpu
|
||||
*/
|
||||
template<typename Kernel, typename... Args>
|
||||
auto run_on_gpu_with_hint(size_t buffer_capacity_hint,
|
||||
Kernel kernel, Args&&... args) -> decltype(kernel(args...)){
|
||||
return internal::run_serialized_on_gpu<Kernel, Args...>(
|
||||
buffer_capacity_hint,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
internal::extract_output_indices<Args...>{},
|
||||
kernel, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kernel for determining basic Eigen compile-time information
|
||||
* (i.e. the cuda/hip arch)
|
||||
*/
|
||||
struct CompileTimeDeviceInfoKernel {
|
||||
struct Info {
|
||||
int cuda;
|
||||
int hip;
|
||||
};
|
||||
|
||||
EIGEN_DEVICE_FUNC
|
||||
Info operator()() const
|
||||
{
|
||||
Info info = {-1, -1};
|
||||
#if defined(__CUDA_ARCH__)
|
||||
info.cuda = static_cast<int>(__CUDA_ARCH__ +0);
|
||||
#endif
|
||||
#if defined(EIGEN_HIP_DEVICE_COMPILE)
|
||||
info.hip = static_cast<int>(EIGEN_HIP_DEVICE_COMPILE +0);
|
||||
#endif
|
||||
return info;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Queries and prints the compile-time and runtime GPU info.
|
||||
*/
|
||||
void print_gpu_device_info()
|
||||
{
|
||||
int device = 0;
|
||||
gpuDeviceProp_t deviceProp;
|
||||
gpuGetDeviceProperties(&deviceProp, device);
|
||||
|
||||
auto info = run_on_gpu(CompileTimeDeviceInfoKernel());
|
||||
|
||||
std::cout << "GPU compile-time info:\n";
|
||||
|
||||
#ifdef EIGEN_CUDACC
|
||||
std::cout << " EIGEN_CUDACC: " << int(EIGEN_CUDACC) << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_CUDA_SDK_VER
|
||||
std::cout << " EIGEN_CUDA_SDK_VER: " << int(EIGEN_CUDA_SDK_VER) << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_COMP_NVCC
|
||||
std::cout << " EIGEN_COMP_NVCC: " << int(EIGEN_COMP_NVCC) << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_HIPCC
|
||||
std::cout << " EIGEN_HIPCC: " << int(EIGEN_HIPCC) << std::endl;
|
||||
#endif
|
||||
|
||||
std::cout << " EIGEN_CUDA_ARCH: " << info.cuda << std::endl;
|
||||
std::cout << " EIGEN_HIP_DEVICE_COMPILE: " << info.hip << std::endl;
|
||||
|
||||
std::cout << "GPU device info:\n";
|
||||
std::cout << " name: " << deviceProp.name << std::endl;
|
||||
std::cout << " capability: " << deviceProp.major << "." << deviceProp.minor << std::endl;
|
||||
std::cout << " multiProcessorCount: " << deviceProp.multiProcessorCount << std::endl;
|
||||
std::cout << " maxThreadsPerMultiProcessor: " << deviceProp.maxThreadsPerMultiProcessor << std::endl;
|
||||
std::cout << " warpSize: " << deviceProp.warpSize << std::endl;
|
||||
std::cout << " regsPerBlock: " << deviceProp.regsPerBlock << std::endl;
|
||||
std::cout << " concurrentKernels: " << deviceProp.concurrentKernels << std::endl;
|
||||
std::cout << " clockRate: " << deviceProp.clockRate << std::endl;
|
||||
std::cout << " canMapHostMemory: " << deviceProp.canMapHostMemory << std::endl;
|
||||
std::cout << " computeMode: " << deviceProp.computeMode << std::endl;
|
||||
}
|
||||
|
||||
#endif // EIGEN_GPUCC
|
||||
|
||||
/**
|
||||
* Runs a kernel on the GPU (if EIGEN_GPUCC), or CPU otherwise.
|
||||
*
|
||||
* This is to better support creating generic tests.
|
||||
*
|
||||
* The kernel must be able to be passed directly as an input to a global
|
||||
* function (i.e. empty or POD). Its inputs must be "Serializable" so we
|
||||
* can transfer them to the device, and the output must be a Serializable value
|
||||
* type so it can be transferred back from the device.
|
||||
*
|
||||
* \param kernel kernel to run.
|
||||
* \param args ... input arguments, must be "Serializable".
|
||||
* \return kernel(args...).
|
||||
*/
|
||||
template<typename Kernel, typename... Args>
|
||||
auto run(Kernel kernel, Args&&... args) -> decltype(kernel(args...)){
|
||||
#ifdef EIGEN_GPUCC
|
||||
return run_on_gpu(kernel, std::forward<Args>(args)...);
|
||||
#else
|
||||
return run_on_cpu(kernel, std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a kernel on the GPU (if EIGEN_GPUCC), or CPU otherwise.
|
||||
*
|
||||
* This version allows specifying a minimum buffer capacity size required for
|
||||
* serializing the puts to transfer results from device to host. Use this when
|
||||
* `run(...)` fails to determine an appropriate capacity by default.
|
||||
*
|
||||
* \param buffer_capacity_hint minimum required buffer size for serializing
|
||||
* outputs.
|
||||
* \param kernel kernel to run.
|
||||
* \param args ... input arguments, must be "Serializable".
|
||||
* \return kernel(args...).
|
||||
* \sa run
|
||||
*/
|
||||
template<typename Kernel, typename... Args>
|
||||
auto run_with_hint(size_t buffer_capacity_hint,
|
||||
Kernel kernel, Args&&... args) -> decltype(kernel(args...)){
|
||||
#ifdef EIGEN_GPUCC
|
||||
return run_on_gpu_with_hint(buffer_capacity_hint, kernel, std::forward<Args>(args)...);
|
||||
#else
|
||||
EIGEN_UNUSED_VARIABLE(buffer_capacity_hint)
|
||||
return run_on_cpu(kernel, std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // GPU_TEST_HELPER_H
|
||||
@@ -157,6 +157,12 @@ void test_numtraits()
|
||||
VERIFY( (std::numeric_limits<half>::denorm_min)() > half(0.f) );
|
||||
VERIFY( (std::numeric_limits<half>::min)()/half(2) > half(0.f) );
|
||||
VERIFY_IS_EQUAL( (std::numeric_limits<half>::denorm_min)()/half(2), half(0.f) );
|
||||
|
||||
// Test to see that we are able to link against the symbols for digits and
|
||||
// digits10.
|
||||
volatile const int& digits10 = std::numeric_limits<half>::digits10;
|
||||
volatile const int& digits = std::numeric_limits<half>::digits;
|
||||
VERIFY( (digits10) != (digits) );
|
||||
}
|
||||
|
||||
void test_arithmetic()
|
||||
@@ -224,6 +230,8 @@ void test_comparison()
|
||||
|
||||
void test_basic_functions()
|
||||
{
|
||||
constexpr float PI = static_cast<float>(EIGEN_PI);
|
||||
|
||||
VERIFY_IS_EQUAL(float(numext::abs(half(3.5f))), 3.5f);
|
||||
VERIFY_IS_EQUAL(float(abs(half(3.5f))), 3.5f);
|
||||
VERIFY_IS_EQUAL(float(numext::abs(half(-3.5f))), 3.5f);
|
||||
@@ -251,8 +259,8 @@ void test_basic_functions()
|
||||
|
||||
VERIFY_IS_EQUAL(float(numext::exp(half(0.0f))), 1.0f);
|
||||
VERIFY_IS_EQUAL(float(exp(half(0.0f))), 1.0f);
|
||||
VERIFY_IS_APPROX(float(numext::exp(half(EIGEN_PI))), 20.f + float(EIGEN_PI));
|
||||
VERIFY_IS_APPROX(float(exp(half(EIGEN_PI))), 20.f + float(EIGEN_PI));
|
||||
VERIFY_IS_APPROX(float(numext::exp(half(PI))), 20.f + PI);
|
||||
VERIFY_IS_APPROX(float(exp(half(PI))), 20.f + PI);
|
||||
|
||||
VERIFY_IS_EQUAL(float(numext::expm1(half(0.0f))), 0.0f);
|
||||
VERIFY_IS_EQUAL(float(expm1(half(0.0f))), 0.0f);
|
||||
@@ -277,25 +285,26 @@ void test_basic_functions()
|
||||
|
||||
void test_trigonometric_functions()
|
||||
{
|
||||
constexpr float PI = static_cast<float>(EIGEN_PI);
|
||||
VERIFY_IS_APPROX(numext::cos(half(0.0f)), half(cosf(0.0f)));
|
||||
VERIFY_IS_APPROX(cos(half(0.0f)), half(cosf(0.0f)));
|
||||
VERIFY_IS_APPROX(numext::cos(half(EIGEN_PI)), half(cosf(EIGEN_PI)));
|
||||
// VERIFY_IS_APPROX(numext::cos(half(EIGEN_PI/2)), half(cosf(EIGEN_PI/2)));
|
||||
// VERIFY_IS_APPROX(numext::cos(half(3*EIGEN_PI/2)), half(cosf(3*EIGEN_PI/2)));
|
||||
VERIFY_IS_APPROX(numext::cos(half(PI)), half(cosf(PI)));
|
||||
// VERIFY_IS_APPROX(numext::cos(half(PI/2)), half(cosf(PI/2)));
|
||||
// VERIFY_IS_APPROX(numext::cos(half(3*PI/2)), half(cosf(3*PI/2)));
|
||||
VERIFY_IS_APPROX(numext::cos(half(3.5f)), half(cosf(3.5f)));
|
||||
|
||||
VERIFY_IS_APPROX(numext::sin(half(0.0f)), half(sinf(0.0f)));
|
||||
VERIFY_IS_APPROX(sin(half(0.0f)), half(sinf(0.0f)));
|
||||
// VERIFY_IS_APPROX(numext::sin(half(EIGEN_PI)), half(sinf(EIGEN_PI)));
|
||||
VERIFY_IS_APPROX(numext::sin(half(EIGEN_PI/2)), half(sinf(EIGEN_PI/2)));
|
||||
VERIFY_IS_APPROX(numext::sin(half(3*EIGEN_PI/2)), half(sinf(3*EIGEN_PI/2)));
|
||||
// VERIFY_IS_APPROX(numext::sin(half(PI)), half(sinf(PI)));
|
||||
VERIFY_IS_APPROX(numext::sin(half(PI/2)), half(sinf(PI/2)));
|
||||
VERIFY_IS_APPROX(numext::sin(half(3*PI/2)), half(sinf(3*PI/2)));
|
||||
VERIFY_IS_APPROX(numext::sin(half(3.5f)), half(sinf(3.5f)));
|
||||
|
||||
VERIFY_IS_APPROX(numext::tan(half(0.0f)), half(tanf(0.0f)));
|
||||
VERIFY_IS_APPROX(tan(half(0.0f)), half(tanf(0.0f)));
|
||||
// VERIFY_IS_APPROX(numext::tan(half(EIGEN_PI)), half(tanf(EIGEN_PI)));
|
||||
// VERIFY_IS_APPROX(numext::tan(half(EIGEN_PI/2)), half(tanf(EIGEN_PI/2)));
|
||||
//VERIFY_IS_APPROX(numext::tan(half(3*EIGEN_PI/2)), half(tanf(3*EIGEN_PI/2)));
|
||||
// VERIFY_IS_APPROX(numext::tan(half(PI)), half(tanf(PI)));
|
||||
// VERIFY_IS_APPROX(numext::tan(half(PI/2)), half(tanf(PI/2)));
|
||||
//VERIFY_IS_APPROX(numext::tan(half(3*PI/2)), half(tanf(3*PI/2)));
|
||||
VERIFY_IS_APPROX(numext::tan(half(3.5f)), half(tanf(3.5f)));
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ template<typename MatrixType> void householder(const MatrixType& m)
|
||||
|
||||
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime> TMatrixType;
|
||||
|
||||
Matrix<Scalar, EIGEN_SIZE_MAX(MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime), 1> _tmp((std::max)(rows,cols));
|
||||
Matrix<Scalar, internal::max_size_prefer_dynamic(MatrixType::RowsAtCompileTime,MatrixType::ColsAtCompileTime), 1> _tmp((std::max)(rows,cols));
|
||||
Scalar* tmp = &_tmp.coeffRef(0,0);
|
||||
|
||||
Scalar beta;
|
||||
@@ -133,6 +133,89 @@ template<typename MatrixType> void householder(const MatrixType& m)
|
||||
VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating rhseq to a dense matrix, then applying
|
||||
}
|
||||
|
||||
|
||||
template <typename MatrixType>
|
||||
void householder_update(const MatrixType& m) {
|
||||
// This test is covering the internal::householder_qr_inplace_update function.
|
||||
// At time of writing, there is not public API that exposes this update behavior directly,
|
||||
// so we are testing the internal implementation.
|
||||
|
||||
const Index rows = m.rows();
|
||||
const Index cols = m.cols();
|
||||
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
|
||||
typedef Matrix<Scalar, Dynamic, 1> HCoeffsVectorType;
|
||||
typedef Matrix<Scalar, Dynamic, Dynamic> MatrixX;
|
||||
typedef Matrix<Scalar, Dynamic, 1> VectorX;
|
||||
|
||||
VectorX tmpOwner(cols);
|
||||
Scalar* tmp = tmpOwner.data();
|
||||
|
||||
// The matrix to factorize.
|
||||
const MatrixType A = MatrixType::Random(rows, cols);
|
||||
|
||||
// matQR and hCoeffs will hold the factorization of A,
|
||||
// built by a sequence of calls to `update`.
|
||||
MatrixType matQR(rows, cols);
|
||||
HCoeffsVectorType hCoeffs(cols);
|
||||
|
||||
// householder_qr_inplace_update should be able to build a QR factorization one column at a time.
|
||||
// We verify this by starting with an empty factorization and 'updating' one column at a time.
|
||||
// After each call to update, we should have a QR factorization of the columns presented so far.
|
||||
|
||||
const Index size = (std::min)(rows, cols); // QR can only go up to 'size' b/c that's full rank.
|
||||
for (Index k = 0; k != size; ++k)
|
||||
{
|
||||
// Make a copy of the column to prevent any possibility of 'leaking' other parts of A.
|
||||
const VectorType newColumn = A.col(k);
|
||||
internal::householder_qr_inplace_update(matQR, hCoeffs, newColumn, k, tmp);
|
||||
|
||||
// Verify Property:
|
||||
// matQR.leftCols(k+1) and hCoeffs.head(k+1) hold
|
||||
// a QR factorization of A.leftCols(k+1).
|
||||
// This is the fundamental guarantee of householder_qr_inplace_update.
|
||||
{
|
||||
const MatrixX matQR_k = matQR.leftCols(k + 1);
|
||||
const VectorX hCoeffs_k = hCoeffs.head(k + 1);
|
||||
MatrixX R = matQR_k.template triangularView<Upper>();
|
||||
MatrixX QxR = householderSequence(matQR_k, hCoeffs_k.conjugate()) * R;
|
||||
VERIFY_IS_APPROX(QxR, A.leftCols(k + 1));
|
||||
}
|
||||
|
||||
// Verify Property:
|
||||
// A sequence of calls to 'householder_qr_inplace_update'
|
||||
// should produce the same result as 'householder_qr_inplace_unblocked'.
|
||||
// This is a property of the current implementation.
|
||||
// If these implementations diverge in the future,
|
||||
// then simply delete the test of this property.
|
||||
{
|
||||
MatrixX QR_at_once = A.leftCols(k + 1);
|
||||
VectorX hCoeffs_at_once(k + 1);
|
||||
internal::householder_qr_inplace_unblocked(QR_at_once, hCoeffs_at_once, tmp);
|
||||
VERIFY_IS_APPROX(QR_at_once, matQR.leftCols(k + 1));
|
||||
VERIFY_IS_APPROX(hCoeffs_at_once, hCoeffs.head(k + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Verify Property:
|
||||
// We can go back and update any column to have a new value,
|
||||
// and get a QR factorization of the columns up to that one.
|
||||
{
|
||||
const Index k = internal::random<Index>(0, size - 1);
|
||||
VectorType newColumn = VectorType::Random(rows);
|
||||
internal::householder_qr_inplace_update(matQR, hCoeffs, newColumn, k, tmp);
|
||||
|
||||
const MatrixX matQR_k = matQR.leftCols(k + 1);
|
||||
const VectorX hCoeffs_k = hCoeffs.head(k + 1);
|
||||
MatrixX R = matQR_k.template triangularView<Upper>();
|
||||
MatrixX QxR = householderSequence(matQR_k, hCoeffs_k.conjugate()) * R;
|
||||
VERIFY_IS_APPROX(QxR.leftCols(k), A.leftCols(k));
|
||||
VERIFY_IS_APPROX(QxR.col(k), newColumn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EIGEN_DECLARE_TEST(householder)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -144,5 +227,9 @@ EIGEN_DECLARE_TEST(householder)
|
||||
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>()) );
|
||||
|
||||
CALL_SUBTEST_9( householder_update(Matrix<double, 3, 5>()) );
|
||||
CALL_SUBTEST_9( householder_update(Matrix<float, 4, 2>()) );
|
||||
CALL_SUBTEST_9( householder_update(MatrixXcf(internal::random<Index>(1,EIGEN_TEST_MAX_SIZE), internal::random<Index>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,38 +7,15 @@
|
||||
// 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/.
|
||||
|
||||
#ifdef EIGEN_TEST_PART_2
|
||||
// Make sure we also check c++11 max implementation
|
||||
#define EIGEN_MAX_CPP_VER 11
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_TEST_PART_3
|
||||
// Make sure we also check c++98 max implementation
|
||||
#define EIGEN_MAX_CPP_VER 03
|
||||
|
||||
// We need to disable this warning when compiling with c++11 while limiting Eigen to c++98
|
||||
// Ideally we would rather configure the compiler to build in c++98 mode but this needs
|
||||
// to be done at the CMakeLists.txt level.
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >=9)
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-copy"
|
||||
#endif
|
||||
#if defined(__clang__) && (__clang_major__ >= 10)
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-copy"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
#include "main.h"
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
using Eigen::placeholders::all;
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::lastp1;
|
||||
using Eigen::placeholders::lastN;
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
typedef std::pair<Index,Index> IndexPair;
|
||||
|
||||
@@ -63,7 +40,7 @@ bool match(const T& xpr, std::string ref, std::string str_xpr = "") {
|
||||
#define MATCH(X,R) match(X, R, #X)
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
std::enable_if_t<internal::is_same<T1,T2>::value,bool>
|
||||
is_same_eq(const T1& a, const T2& b)
|
||||
{
|
||||
return (a == b).all();
|
||||
@@ -82,7 +59,7 @@ bool is_same_seq(const T1& a, const T2& b)
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
std::enable_if_t<internal::is_same<T1,T2>::value,bool>
|
||||
is_same_seq_type(const T1& a, const T2& b)
|
||||
{
|
||||
return is_same_seq(a,b);
|
||||
@@ -102,11 +79,7 @@ void check_indexed_view()
|
||||
ArrayXd a = ArrayXd::LinSpaced(n,0,n-1);
|
||||
Array<double,1,Dynamic> b = a.transpose();
|
||||
|
||||
#if EIGEN_COMP_CXXVER>=14
|
||||
ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ref(encode));
|
||||
#else
|
||||
ArrayXXi A = ArrayXXi::NullaryExpr(n,n, std::ptr_fun(&encode));
|
||||
#endif
|
||||
|
||||
for(Index i=0; i<n; ++i)
|
||||
for(Index j=0; j<n; ++j)
|
||||
@@ -220,7 +193,6 @@ void check_indexed_view()
|
||||
VERIFY( is_same_seq_type( seqN(2,fix<5>(5),fix<-2>), seqN(2,fix<5>,fix<-2>()) ) );
|
||||
|
||||
VERIFY( is_same_seq_type( seq(2,fix<5>), seqN(2,4) ) );
|
||||
#if EIGEN_HAS_CXX11
|
||||
VERIFY( is_same_seq_type( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) );
|
||||
VERIFY( is_same_seq( seqN(2,std::integral_constant<int,5>(),std::integral_constant<int,-2>()), seqN(2,fix<5>,fix<-2>()) ) );
|
||||
VERIFY( is_same_seq( seq(std::integral_constant<int,1>(),std::integral_constant<int,5>(),std::integral_constant<int,2>()),
|
||||
@@ -231,10 +203,6 @@ void check_indexed_view()
|
||||
|
||||
VERIFY( is_same_seq_type( seqN(2,std::integral_constant<int,5>()), seqN(2,fix<5>) ) );
|
||||
VERIFY( is_same_seq_type( seq(std::integral_constant<int,1>(),std::integral_constant<int,5>()), seq(fix<1>,fix<5>) ) );
|
||||
#else
|
||||
// sorry, no compile-time size recovery in c++98/03
|
||||
VERIFY( is_same_seq( seq(fix<2>,fix<5>), seqN(fix<2>,fix<4>) ) );
|
||||
#endif
|
||||
|
||||
VERIFY( (A(seqN(2,fix<5>), 5)).RowsAtCompileTime == 5);
|
||||
VERIFY( (A(4, all)).ColsAtCompileTime == Dynamic);
|
||||
@@ -310,7 +278,6 @@ void check_indexed_view()
|
||||
A(seq(last-5,last-1,2), seqN(last-3,3,fix<-2>)).reverse() );
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
// check lastN
|
||||
VERIFY_IS_APPROX( a(lastN(3)), a.tail(3) );
|
||||
VERIFY( MATCH( a(lastN(3)), "7\n8\n9" ) );
|
||||
@@ -323,7 +290,6 @@ void check_indexed_view()
|
||||
|
||||
VERIFY_IS_APPROX( (A(std::array<int,3>{{1,3,5}}, std::array<int,4>{{9,6,3,0}})), A(seqN(1,3,2), seqN(9,4,-3)) );
|
||||
|
||||
#if EIGEN_HAS_STATIC_ARRAY_TEMPLATE
|
||||
VERIFY_IS_APPROX( A({3, 1, 6, 5}, all), A(std::array<int,4>{{3, 1, 6, 5}}, all) );
|
||||
VERIFY_IS_APPROX( A(all,{3, 1, 6, 5}), A(all,std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
VERIFY_IS_APPROX( A({1,3,5},{3, 1, 6, 5}), A(std::array<int,3>{{1,3,5}},std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
@@ -336,9 +302,6 @@ void check_indexed_view()
|
||||
|
||||
VERIFY_IS_APPROX( b({3, 1, 6, 5}), b(std::array<int,4>{{3, 1, 6, 5}}) );
|
||||
VERIFY_IS_EQUAL( b({1,3,5}).SizeAtCompileTime, 3 );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// check mat(i,j) with weird types for i and j
|
||||
{
|
||||
@@ -396,13 +359,11 @@ void check_indexed_view()
|
||||
a(XX) = 1;
|
||||
A(XX,YY) = 1;
|
||||
// Anonymous enums only work with C++11
|
||||
#if EIGEN_HAS_CXX11
|
||||
enum { X=0, Y=1 };
|
||||
a(X) = 1;
|
||||
A(X,Y) = 1;
|
||||
A(XX,Y) = 1;
|
||||
A(X,YY) = 1;
|
||||
#endif
|
||||
|
||||
// Check compilation of varying integer types as index types:
|
||||
Index i = n/2;
|
||||
@@ -442,13 +403,21 @@ void check_indexed_view()
|
||||
VERIFY( MATCH( A(all,1)(1), "101"));
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
// bug #2375: indexing over matrices of dim >128 should compile on gcc
|
||||
{
|
||||
Matrix<double, 513, 3> large_mat = Matrix<double, 513, 3>::Random();
|
||||
std::array<int, 2> test_indices = {0, 1};
|
||||
Matrix<double, 513, 2> thin_slice = large_mat(all, test_indices);
|
||||
for(int col = 0; col < int(test_indices.size()); ++col)
|
||||
for(int row = 0; row < large_mat.rows(); ++row)
|
||||
VERIFY_IS_EQUAL( thin_slice(row, col), large_mat(row, col) );
|
||||
}
|
||||
|
||||
//Bug IndexView with a single static row should be RowMajor:
|
||||
{
|
||||
// A(1, seq(0,2,1)).cwiseAbs().colwise().replicate(2).eval();
|
||||
STATIC_CHECK(( (internal::evaluator<decltype( A(1,seq(0,2,1)) )>::Flags & RowMajorBit) == RowMajorBit ));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -456,8 +425,6 @@ EIGEN_DECLARE_TEST(indexed_view)
|
||||
{
|
||||
// for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1( check_indexed_view() );
|
||||
CALL_SUBTEST_2( check_indexed_view() );
|
||||
CALL_SUBTEST_3( check_indexed_view() );
|
||||
// }
|
||||
|
||||
// static checks of some internals:
|
||||
|
||||
@@ -7,7 +7,12 @@
|
||||
// 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
|
||||
#if defined(__GNUC__) && __GNUC__ >= 10
|
||||
// GCC 10+ has a bug for unsigned char that thinks we're writing past the
|
||||
// end of an array when compiled with -O3. This warning is not triggered for
|
||||
// any other types, nor for other compilers, nor for other optimization levels.
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
|
||||
@@ -320,16 +325,6 @@ template<typename Scalar> void dynamicVectorConstruction()
|
||||
VERIFY(v.cols() == 1);
|
||||
VERIFY_IS_EQUAL(v, (VectorX {{raw[0], raw[1], raw[2], raw[3]}}));
|
||||
}
|
||||
|
||||
{
|
||||
VERIFY_RAISES_ASSERT((VectorX {raw[0], raw[1], raw[2], raw[3]}));
|
||||
}
|
||||
{
|
||||
VERIFY_RAISES_ASSERT((VectorX {
|
||||
{raw[0], raw[1], raw[2], raw[3]},
|
||||
{raw[0], raw[1], raw[2], raw[3]},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(initializer_list_construction)
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
// 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
|
||||
@@ -162,12 +160,10 @@ EIGEN_DECLARE_TEST(integer_types)
|
||||
|
||||
CALL_SUBTEST_6( integer_type_tests(Matrix<unsigned short, 4, 4>()) );
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
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)) );
|
||||
#endif
|
||||
}
|
||||
CALL_SUBTEST_9( integer_types_extra<0>() );
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
#include <Eigen/LU>
|
||||
|
||||
template<typename MatrixType>
|
||||
void inverse_for_fixed_size(const MatrixType&, typename internal::enable_if<MatrixType::SizeAtCompileTime==Dynamic>::type* = 0)
|
||||
void inverse_for_fixed_size(const MatrixType&, std::enable_if_t<MatrixType::SizeAtCompileTime==Dynamic>* = 0)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void inverse_for_fixed_size(const MatrixType& m1, typename internal::enable_if<MatrixType::SizeAtCompileTime!=Dynamic>::type* = 0)
|
||||
void inverse_for_fixed_size(const MatrixType& m1, std::enable_if_t<MatrixType::SizeAtCompileTime!=Dynamic>* = 0)
|
||||
{
|
||||
using std::abs;
|
||||
|
||||
|
||||
@@ -65,6 +65,11 @@ EIGEN_DECLARE_TEST(jacobi)
|
||||
CALL_SUBTEST_3(( jacobi<Matrix4cf, float>() ));
|
||||
CALL_SUBTEST_3(( jacobi<Matrix4cf, std::complex<float> >() ));
|
||||
|
||||
CALL_SUBTEST_1(( jacobi<Matrix<float, 3, 3, RowMajor>, float>() ));
|
||||
CALL_SUBTEST_2(( jacobi<Matrix<double, 4, 4, RowMajor>, double>() ));
|
||||
CALL_SUBTEST_3(( jacobi<Matrix<std::complex<float>, 4, 4, RowMajor>, float>() ));
|
||||
CALL_SUBTEST_3(( jacobi<Matrix<std::complex<float>, 4, 4, RowMajor>, 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)) ));
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
// 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/.
|
||||
|
||||
// We explicitly disable deprecated declarations for this set of tests
|
||||
// because we purposely verify assertions for the deprecated SVD runtime
|
||||
// option behavior.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning( disable : 4996 )
|
||||
#endif
|
||||
|
||||
// discard stack allocation as that too bypasses malloc
|
||||
#define EIGEN_STACK_ALLOCATION_LIMIT 0
|
||||
#define EIGEN_RUNTIME_NO_MALLOC
|
||||
@@ -16,49 +25,9 @@
|
||||
|
||||
#define SVD_DEFAULT(M) JacobiSVD<M>
|
||||
#define SVD_FOR_MIN_NORM(M) JacobiSVD<M,ColPivHouseholderQRPreconditioner>
|
||||
#define SVD_STATIC_OPTIONS(M, O) JacobiSVD<M, O>
|
||||
#include "svd_common.h"
|
||||
|
||||
// Check all variants of JacobiSVD
|
||||
template<typename MatrixType>
|
||||
void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
|
||||
{
|
||||
MatrixType m = a;
|
||||
if(pickrandom)
|
||||
svd_fill_random(m);
|
||||
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner> >(m, true) )); // check full only
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner> >(m, false) ));
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, HouseholderQRPreconditioner> >(m, false) ));
|
||||
if(m.rows()==m.cols())
|
||||
CALL_SUBTEST(( svd_test_all_computation_options<JacobiSVD<MatrixType, NoQRPreconditioner> >(m, false) ));
|
||||
}
|
||||
|
||||
template<typename MatrixType> void jacobisvd_verify_assert(const MatrixType& m)
|
||||
{
|
||||
svd_verify_assert<JacobiSVD<MatrixType> >(m);
|
||||
svd_verify_assert<JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner> >(m, true);
|
||||
svd_verify_assert<JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner> >(m);
|
||||
svd_verify_assert<JacobiSVD<MatrixType, HouseholderQRPreconditioner> >(m);
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
|
||||
enum {
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
|
||||
MatrixType a = MatrixType::Zero(rows, cols);
|
||||
a.setZero();
|
||||
|
||||
if (ColsAtCompileTime == Dynamic)
|
||||
{
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void jacobisvd_method()
|
||||
{
|
||||
@@ -69,11 +38,62 @@ void jacobisvd_method()
|
||||
VERIFY_IS_APPROX(m.jacobiSvd().singularValues(), RealVecType::Ones());
|
||||
VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU());
|
||||
VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV());
|
||||
VERIFY_IS_APPROX(m.template jacobiSvd<ComputeFullU | ComputeFullV>().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template jacobiSvd<ComputeFullU | ComputeFullV>().transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.template jacobiSvd<ComputeFullU | ComputeFullV>().adjoint().solve(m), m);
|
||||
|
||||
// Deprecated behavior.
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).adjoint().solve(m), m);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void jacobisvd_all_options(const MatrixType& input = MatrixType()) {
|
||||
MatrixType m(input.rows(), input.cols());
|
||||
svd_fill_random(m);
|
||||
svd_option_checks<MatrixType, 0>(m);
|
||||
svd_option_checks<MatrixType, ColPivHouseholderQRPreconditioner>(m);
|
||||
svd_option_checks<MatrixType, HouseholderQRPreconditioner>(m);
|
||||
svd_option_checks_full_only<MatrixType, FullPivHouseholderQRPreconditioner>(
|
||||
m); // FullPiv only used when computing full unitaries
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void jacobisvd_verify_assert(const MatrixType& m = MatrixType()) {
|
||||
svd_verify_assert<MatrixType, 0>(m);
|
||||
svd_verify_assert<MatrixType, ColPivHouseholderQRPreconditioner>(m);
|
||||
svd_verify_assert<MatrixType, HouseholderQRPreconditioner>(m);
|
||||
svd_verify_assert_full_only<MatrixType, FullPivHouseholderQRPreconditioner>(m);
|
||||
|
||||
svd_verify_constructor_options_assert<JacobiSVD<MatrixType>>(m);
|
||||
svd_verify_constructor_options_assert<JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>>(m);
|
||||
svd_verify_constructor_options_assert<JacobiSVD<MatrixType, HouseholderQRPreconditioner>>(m);
|
||||
svd_verify_constructor_options_assert<JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>>(m, true);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void jacobisvd_verify_inputs(const MatrixType& m = MatrixType()) {
|
||||
// check defaults
|
||||
typedef JacobiSVD<MatrixType> DefaultSVD;
|
||||
DefaultSVD defaultSvd(m);
|
||||
VERIFY((int)DefaultSVD::QRPreconditioner == (int)ColPivHouseholderQRPreconditioner);
|
||||
VERIFY(!defaultSvd.computeU());
|
||||
VERIFY(!defaultSvd.computeV());
|
||||
|
||||
// ColPivHouseholderQR is always default in presence of other options.
|
||||
VERIFY(((int)JacobiSVD<MatrixType, ComputeThinU>::QRPreconditioner == (int)ColPivHouseholderQRPreconditioner));
|
||||
VERIFY(((int)JacobiSVD<MatrixType, ComputeThinV>::QRPreconditioner == (int)ColPivHouseholderQRPreconditioner));
|
||||
VERIFY(((int)JacobiSVD<MatrixType, ComputeThinU | ComputeThinV>::QRPreconditioner ==
|
||||
(int)ColPivHouseholderQRPreconditioner));
|
||||
VERIFY(((int)JacobiSVD<MatrixType, ComputeFullU | ComputeFullV>::QRPreconditioner ==
|
||||
(int)ColPivHouseholderQRPreconditioner));
|
||||
VERIFY(((int)JacobiSVD<MatrixType, ComputeThinU | ComputeFullV>::QRPreconditioner ==
|
||||
(int)ColPivHouseholderQRPreconditioner));
|
||||
VERIFY(((int)JacobiSVD<MatrixType, ComputeFullU | ComputeThinV>::QRPreconditioner ==
|
||||
(int)ColPivHouseholderQRPreconditioner));
|
||||
}
|
||||
|
||||
namespace Foo {
|
||||
// older compiler require a default constructor for Bar
|
||||
// cf: https://stackoverflow.com/questions/7411515/
|
||||
@@ -86,62 +106,91 @@ void msvc_workaround()
|
||||
{
|
||||
const Foo::Bar a;
|
||||
const Foo::Bar b;
|
||||
std::max EIGEN_NOT_A_MACRO (a,b);
|
||||
const Foo::Bar c = std::max EIGEN_NOT_A_MACRO (a,b);
|
||||
EIGEN_UNUSED_VARIABLE(c)
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(jacobisvd)
|
||||
{
|
||||
CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) ));
|
||||
CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) ));
|
||||
CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) ));
|
||||
CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) ));
|
||||
|
||||
CALL_SUBTEST_11(svd_all_trivial_2x2(jacobisvd<Matrix2cd>));
|
||||
CALL_SUBTEST_12(svd_all_trivial_2x2(jacobisvd<Matrix2d>));
|
||||
CALL_SUBTEST_1((jacobisvd_verify_inputs<Matrix4d>()));
|
||||
CALL_SUBTEST_1((jacobisvd_verify_inputs(Matrix<float, 5, Dynamic>(5, 6))));
|
||||
CALL_SUBTEST_1((jacobisvd_verify_inputs<Matrix<std::complex<double>, 7, 5>>()));
|
||||
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
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)) ));
|
||||
CALL_SUBTEST_2((jacobisvd_verify_assert<Matrix3f>()));
|
||||
CALL_SUBTEST_2((jacobisvd_verify_assert<Matrix4d>()));
|
||||
CALL_SUBTEST_2((jacobisvd_verify_assert<Matrix<float, 10, 12>>()));
|
||||
CALL_SUBTEST_2((jacobisvd_verify_assert<Matrix<float, 12, 10>>()));
|
||||
CALL_SUBTEST_2((jacobisvd_verify_assert<MatrixXf>(MatrixXf(10, 12))));
|
||||
CALL_SUBTEST_2((jacobisvd_verify_assert<MatrixXcd>(MatrixXcd(7, 5))));
|
||||
|
||||
CALL_SUBTEST_3(svd_all_trivial_2x2(jacobisvd_all_options<Matrix2cd>));
|
||||
CALL_SUBTEST_4(svd_all_trivial_2x2(jacobisvd_all_options<Matrix2d>));
|
||||
|
||||
for (int i = 0; i < g_repeat; i++) {
|
||||
int r = internal::random<int>(1, 30),
|
||||
c = internal::random<int>(1, 30);
|
||||
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(r)
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(c)
|
||||
|
||||
CALL_SUBTEST_10(( jacobisvd<MatrixXd>(MatrixXd(r,c)) ));
|
||||
CALL_SUBTEST_7(( jacobisvd<MatrixXf>(MatrixXf(r,c)) ));
|
||||
CALL_SUBTEST_8(( jacobisvd<MatrixXcd>(MatrixXcd(r,c)) ));
|
||||
(void) r;
|
||||
(void) c;
|
||||
CALL_SUBTEST_5((jacobisvd_all_options<Matrix3f>()));
|
||||
CALL_SUBTEST_6((jacobisvd_all_options<Matrix4d>()));
|
||||
CALL_SUBTEST_7((jacobisvd_all_options<Matrix<float, 2, 3>>()));
|
||||
CALL_SUBTEST_8((jacobisvd_all_options<Matrix<double, 4, 7>>()));
|
||||
CALL_SUBTEST_9((jacobisvd_all_options<Matrix<double, 7, 4>>()));
|
||||
CALL_SUBTEST_10((jacobisvd_all_options<Matrix<double, Dynamic, 5>>(Matrix<double, Dynamic, 5>(r, 5))));
|
||||
CALL_SUBTEST_11((jacobisvd_all_options<Matrix<double, 5, Dynamic>>(Matrix<double, 5, Dynamic>(5, c))));
|
||||
CALL_SUBTEST_12((jacobisvd_all_options<MatrixXf>(MatrixXf(r, c))));
|
||||
CALL_SUBTEST_13((jacobisvd_all_options<MatrixXcd>(MatrixXcd(r, c))));
|
||||
CALL_SUBTEST_14((jacobisvd_all_options<MatrixXd>(MatrixXd(r, c))));
|
||||
CALL_SUBTEST_15((jacobisvd_all_options<Matrix<double, 5, 7, RowMajor>>()));
|
||||
CALL_SUBTEST_16((jacobisvd_all_options<Matrix<double, 7, 5, RowMajor>>()));
|
||||
|
||||
MatrixXcd noQRTest = MatrixXcd(r, r);
|
||||
svd_fill_random(noQRTest);
|
||||
CALL_SUBTEST_17((svd_option_checks<MatrixXcd, NoQRPreconditioner>(noQRTest)));
|
||||
|
||||
CALL_SUBTEST_18((
|
||||
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 13, 15>, ColPivHouseholderQRPreconditioner>(
|
||||
r, c)));
|
||||
CALL_SUBTEST_18(
|
||||
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 15, 13>, HouseholderQRPreconditioner>(r,
|
||||
c)));
|
||||
CALL_SUBTEST_18((
|
||||
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 13, 15>, ColPivHouseholderQRPreconditioner>(
|
||||
r, c)));
|
||||
CALL_SUBTEST_18(
|
||||
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 15, 13>, HouseholderQRPreconditioner>(r,
|
||||
c)));
|
||||
|
||||
// Test on inf/nan matrix
|
||||
CALL_SUBTEST_7( (svd_inf_nan<JacobiSVD<MatrixXf>, MatrixXf>()) );
|
||||
CALL_SUBTEST_10( (svd_inf_nan<JacobiSVD<MatrixXd>, MatrixXd>()) );
|
||||
CALL_SUBTEST_19((svd_inf_nan<MatrixXf>()));
|
||||
CALL_SUBTEST_19((svd_inf_nan<MatrixXd>()));
|
||||
|
||||
// bug1395 test compile-time vectors as input
|
||||
CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix<double,6,1>()) ));
|
||||
CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix<double,1,6>()) ));
|
||||
CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix<double,Dynamic,1>(r)) ));
|
||||
CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix<double,1,Dynamic>(c)) ));
|
||||
CALL_SUBTEST_20((jacobisvd_verify_assert<Matrix<double, 6, 1>>()));
|
||||
CALL_SUBTEST_20((jacobisvd_verify_assert<Matrix<double, 1, 6>>()));
|
||||
CALL_SUBTEST_20((jacobisvd_verify_assert<Matrix<double, Dynamic, 1>>(Matrix<double, Dynamic, 1>(r))));
|
||||
CALL_SUBTEST_20((jacobisvd_verify_assert<Matrix<double, 1, Dynamic>>(Matrix<double, 1, Dynamic>(c))));
|
||||
}
|
||||
|
||||
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))) ));
|
||||
CALL_SUBTEST_21((jacobisvd_all_options<MatrixXd>(
|
||||
MatrixXd(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_22((jacobisvd_all_options<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>() ));
|
||||
CALL_SUBTEST_23(( jacobisvd_method<Matrix2cd>() ));
|
||||
CALL_SUBTEST_23(( jacobisvd_method<Matrix3f>() ));
|
||||
|
||||
// Test problem size constructors
|
||||
CALL_SUBTEST_7( JacobiSVD<MatrixXf>(10,10) );
|
||||
CALL_SUBTEST_24( JacobiSVD<MatrixXf>(10,10) );
|
||||
|
||||
// Check that preallocation avoids subsequent mallocs
|
||||
CALL_SUBTEST_9( svd_preallocate<void>() );
|
||||
CALL_SUBTEST_25( svd_preallocate<void>() );
|
||||
|
||||
CALL_SUBTEST_2( svd_underoverflow<void>() );
|
||||
CALL_SUBTEST_26( svd_underoverflow<void>() );
|
||||
|
||||
msvc_workaround();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
@@ -23,7 +22,7 @@
|
||||
// The following includes of STL headers have to be done _before_ the
|
||||
// definition of macros min() and max(). The reason is that many STL
|
||||
// implementations will not work properly as the min and max symbols collide
|
||||
// with the STL functions std:min() and std::max(). The STL headers may check
|
||||
// with the STL functions std::min() and std::max(). The STL headers may check
|
||||
// for the macro definition of min/max and issue a warning or undefine the
|
||||
// macros.
|
||||
//
|
||||
@@ -54,27 +53,41 @@
|
||||
#include <future>
|
||||
#endif
|
||||
#endif
|
||||
#if __cplusplus > 201703L
|
||||
// libstdc++ 9's <memory> indirectly uses max() via <bit>.
|
||||
// libstdc++ 10's <memory> indirectly uses max() via ranges headers.
|
||||
#include <memory>
|
||||
// libstdc++ 11's <thread> indirectly uses max() via semaphore headers.
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
// Same for cuda_fp16.h
|
||||
#if defined(__CUDACC__) && !defined(EIGEN_NO_CUDA)
|
||||
// Means the compiler is either nvcc or clang with CUDA enabled
|
||||
// Configure GPU.
|
||||
#if defined(EIGEN_USE_HIP)
|
||||
#if defined(__HIPCC__) && !defined(EIGEN_NO_HIP)
|
||||
#define EIGEN_HIPCC __HIPCC__
|
||||
#include <hip/hip_runtime.h>
|
||||
#include <hip/hip_runtime_api.h>
|
||||
#endif
|
||||
#elif defined(__CUDACC__) && !defined(EIGEN_NO_CUDA)
|
||||
#define EIGEN_CUDACC __CUDACC__
|
||||
#include <cuda.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda_runtime_api.h>
|
||||
#if CUDA_VERSION >= 7050
|
||||
#include <cuda_fp16.h>
|
||||
#endif
|
||||
#endif
|
||||
#if defined(EIGEN_CUDACC)
|
||||
#include <cuda.h>
|
||||
#define EIGEN_CUDA_SDK_VER (CUDA_VERSION * 10)
|
||||
#else
|
||||
#define EIGEN_CUDA_SDK_VER 0
|
||||
#endif
|
||||
#if EIGEN_CUDA_SDK_VER >= 70500
|
||||
#include <cuda_fp16.h>
|
||||
|
||||
#if defined(EIGEN_CUDACC) || defined(EIGEN_HIPCC)
|
||||
#define EIGEN_TEST_NO_LONGDOUBLE
|
||||
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
|
||||
#endif
|
||||
|
||||
// To test that all calls from Eigen code to std::min() and std::max() are
|
||||
// protected by parenthesis against macro expansion, the min()/max() macros
|
||||
// are defined here and any not-parenthesized min/max call will cause a
|
||||
// compiler error.
|
||||
#if !defined(__HIPCC__) && !defined(EIGEN_USE_SYCL)
|
||||
#if !defined(__HIPCC__) && !defined(EIGEN_USE_SYCL) && !defined(EIGEN_POCKETFFT_DEFAULT)
|
||||
//
|
||||
// HIP header files include the following files
|
||||
// <thread>
|
||||
@@ -289,9 +302,8 @@ namespace Eigen
|
||||
#endif //EIGEN_EXCEPTIONS
|
||||
|
||||
#elif !defined(__CUDACC__) && !defined(__HIPCC__) && !defined(SYCL_DEVICE_ONLY) // 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) )\
|
||||
if( (!(a)) && (!no_more_assert) ) \
|
||||
{ \
|
||||
Eigen::no_more_assert = true; \
|
||||
if(report_on_cerr_on_assert_failure) \
|
||||
@@ -314,36 +326,10 @@ namespace Eigen
|
||||
#endif // EIGEN_EXCEPTIONS
|
||||
#endif // EIGEN_DEBUG_ASSERTS
|
||||
|
||||
#if defined(TEST_CHECK_STATIC_ASSERTIONS) && defined(EIGEN_EXCEPTIONS)
|
||||
#define EIGEN_STATIC_ASSERT(a,MSG) \
|
||||
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) && #MSG); \
|
||||
else \
|
||||
EIGEN_THROW_X(Eigen::eigen_static_assert_exception()); \
|
||||
}
|
||||
#define VERIFY_RAISES_STATIC_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_static_assert_exception&) { VERIFY(true); } \
|
||||
Eigen::report_on_cerr_on_assert_failure = true; \
|
||||
}
|
||||
#endif // TEST_CHECK_STATIC_ASSERTIONS
|
||||
|
||||
#ifndef VERIFY_RAISES_ASSERT
|
||||
#define VERIFY_RAISES_ASSERT(a) \
|
||||
std::cout << "Can't VERIFY_RAISES_ASSERT( " #a " ) with exceptions disabled\n";
|
||||
#endif
|
||||
#ifndef VERIFY_RAISES_STATIC_ASSERT
|
||||
#define VERIFY_RAISES_STATIC_ASSERT(a) \
|
||||
std::cout << "Can't VERIFY_RAISES_STATIC_ASSERT( " #a " ) with exceptions disabled\n";
|
||||
#endif
|
||||
|
||||
#if !defined(__CUDACC__) && !defined(__HIPCC__) && !defined(SYCL_DEVICE_ONLY)
|
||||
#define EIGEN_USE_CUSTOM_ASSERT
|
||||
@@ -352,12 +338,11 @@ namespace Eigen
|
||||
#else // EIGEN_NO_ASSERTION_CHECKING
|
||||
|
||||
#define VERIFY_RAISES_ASSERT(a) {}
|
||||
#define VERIFY_RAISES_STATIC_ASSERT(a) {}
|
||||
|
||||
#endif // EIGEN_NO_ASSERTION_CHECKING
|
||||
|
||||
#define EIGEN_INTERNAL_DEBUGGING
|
||||
#include <Eigen/QR> // required for createRandomPIMatrixOfRank
|
||||
#include <Eigen/QR> // required for createRandomPIMatrixOfRank and generateRandomMatrixSvs
|
||||
|
||||
inline void verify_impl(bool condition, const char *testname, const char *file, int line, const char *condition_as_string)
|
||||
{
|
||||
@@ -391,6 +376,8 @@ inline void verify_impl(bool condition, const char *testname, const char *file,
|
||||
#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_CWISE_EQUAL(a, b) VERIFY(verifyIsCwiseApprox(a, b, true))
|
||||
#define VERIFY_IS_CWISE_APPROX(a, b) VERIFY(verifyIsCwiseApprox(a, b, false))
|
||||
|
||||
#define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a))
|
||||
|
||||
@@ -403,10 +390,25 @@ inline void verify_impl(bool condition, const char *testname, const char *file,
|
||||
} while (0)
|
||||
|
||||
|
||||
// Forward declarations to avoid ICC warnings
|
||||
#if EIGEN_COMP_ICC
|
||||
|
||||
template<typename T> std::string type_name();
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template<typename T, typename U>
|
||||
bool test_is_equal(const T& actual, const U& expected, bool expect_equal=true);
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_COMP_ICC
|
||||
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
std::enable_if_t<internal::is_same<T1,T2>::value,bool>
|
||||
is_same_type(const T1&, const T2&)
|
||||
{
|
||||
return true;
|
||||
@@ -422,7 +424,13 @@ template<> inline long double test_precision<std::complex<long double> >() { ret
|
||||
|
||||
#define EIGEN_TEST_SCALAR_TEST_OVERLOAD(TYPE) \
|
||||
inline bool test_isApprox(TYPE a, TYPE b) \
|
||||
{ return internal::isApprox(a, b, test_precision<TYPE>()); } \
|
||||
{ return numext::equal_strict(a, b) || \
|
||||
((numext::isnan)(a) && (numext::isnan)(b)) || \
|
||||
(internal::isApprox(a, b, test_precision<TYPE>())); } \
|
||||
inline bool test_isCwiseApprox(TYPE a, TYPE b, bool exact) \
|
||||
{ return numext::equal_strict(a, b) || \
|
||||
((numext::isnan)(a) && (numext::isnan)(b)) || \
|
||||
(!exact && internal::isApprox(a, b, test_precision<TYPE>())); } \
|
||||
inline bool test_isMuchSmallerThan(TYPE a, TYPE b) \
|
||||
{ return internal::isMuchSmallerThan(a, b, test_precision<TYPE>()); } \
|
||||
inline bool test_isApproxOrLessThan(TYPE a, TYPE b) \
|
||||
@@ -434,10 +442,8 @@ EIGEN_TEST_SCALAR_TEST_OVERLOAD(int)
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(unsigned int)
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(long)
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(unsigned long)
|
||||
#if EIGEN_HAS_CXX11
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(long long)
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(unsigned long long)
|
||||
#endif
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(float)
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(double)
|
||||
EIGEN_TEST_SCALAR_TEST_OVERLOAD(half)
|
||||
@@ -543,7 +549,7 @@ typename T1::RealScalar test_relative_error(const SparseMatrixBase<T1> &a, const
|
||||
}
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename NumTraits<typename NumTraits<T1>::Real>::NonInteger test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if<internal::is_arithmetic<typename NumTraits<T1>::Real>::value, T1>::type* = 0)
|
||||
typename NumTraits<typename NumTraits<T1>::Real>::NonInteger test_relative_error(const T1 &a, const T2 &b, std::enable_if_t<internal::is_arithmetic<typename NumTraits<T1>::Real>::value, T1>* = 0)
|
||||
{
|
||||
typedef typename NumTraits<typename NumTraits<T1>::Real>::NonInteger RealScalar;
|
||||
return numext::sqrt(RealScalar(numext::abs2(a-b))/(numext::mini)(RealScalar(numext::abs2(a)),RealScalar(numext::abs2(b))));
|
||||
@@ -575,7 +581,7 @@ typename NumTraits<typename T::Scalar>::Real get_test_precision(const T&, const
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename NumTraits<T>::Real get_test_precision(const T&,typename internal::enable_if<internal::is_arithmetic<typename NumTraits<T>::Real>::value, T>::type* = 0)
|
||||
typename NumTraits<T>::Real get_test_precision(const T&,std::enable_if_t<internal::is_arithmetic<typename NumTraits<T>::Real>::value, T>* = 0)
|
||||
{
|
||||
return test_precision<typename NumTraits<T>::Real>();
|
||||
}
|
||||
@@ -592,6 +598,22 @@ inline bool verifyIsApprox(const Type1& a, const Type2& b)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// verifyIsCwiseApprox is a wrapper to test_isCwiseApprox that outputs the relative difference magnitude if the test fails.
|
||||
template<typename Type1, typename Type2>
|
||||
inline bool verifyIsCwiseApprox(const Type1& a, const Type2& b, bool exact)
|
||||
{
|
||||
bool ret = test_isCwiseApprox(a,b,exact);
|
||||
if(!ret) {
|
||||
if (exact) {
|
||||
std::cerr << "Values are not an exact match";
|
||||
} else {
|
||||
std::cerr << "Difference too large wrt tolerance " << get_test_precision(a);
|
||||
}
|
||||
std::cerr << ", relative error is: " << test_relative_error(a,b) << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// WARNING: the scalar a and b must be positive
|
||||
@@ -625,14 +647,39 @@ inline bool test_isUnitary(const MatrixBase<Derived>& m)
|
||||
return m.isUnitary(test_precision<typename internal::traits<Derived>::Scalar>());
|
||||
}
|
||||
|
||||
// Forward declaration to avoid ICC warning
|
||||
template<typename T, typename U>
|
||||
bool test_is_equal(const T& actual, const U& expected, bool expect_equal=true);
|
||||
// Checks component-wise, works with infs and nans.
|
||||
template<typename Derived1, typename Derived2>
|
||||
bool test_isCwiseApprox(const DenseBase<Derived1>& m1,
|
||||
const DenseBase<Derived2>& m2,
|
||||
bool exact) {
|
||||
if (m1.rows() != m2.rows()) {
|
||||
return false;
|
||||
}
|
||||
if (m1.cols() != m2.cols()) {
|
||||
return false;
|
||||
}
|
||||
for (Index r = 0; r < m1.rows(); ++r) {
|
||||
for (Index c = 0; c < m1.cols(); ++c) {
|
||||
if (m1(r, c) != m2(r, c)
|
||||
&& !((numext::isnan)(m1(r, c)) && (numext::isnan)(m2(r, c)))
|
||||
&& (exact || !test_isApprox(m1(r, c), m2(r, c)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived1, typename Derived2>
|
||||
bool test_isCwiseApprox(const SparseMatrixBase<Derived1>& m1,
|
||||
const SparseMatrixBase<Derived2>& m2, bool exact) {
|
||||
return test_isCwiseApprox(m1.toDense(), m2.toDense(), exact);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
bool test_is_equal(const T& actual, const U& expected, bool expect_equal)
|
||||
{
|
||||
if ((actual==expected) == expect_equal)
|
||||
if (numext::equal_strict(actual, expected) == expect_equal)
|
||||
return true;
|
||||
// false:
|
||||
std::cerr
|
||||
@@ -641,80 +688,39 @@ bool test_is_equal(const T& actual, const U& expected, bool expect_equal)
|
||||
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.
|
||||
*/
|
||||
// Forward declaration to avoid ICC warning
|
||||
template<typename MatrixType>
|
||||
void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m);
|
||||
template<typename MatrixType>
|
||||
void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// Forward declaration to avoid ICC warning
|
||||
template<typename PermutationVectorType>
|
||||
void randomPermutationVector(PermutationVectorType& v, Index size);
|
||||
template<typename PermutationVectorType>
|
||||
void randomPermutationVector(PermutationVectorType& v, Index size)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if number is "not a number" (NaN).
|
||||
*
|
||||
* @tparam T input type
|
||||
* @param x input value
|
||||
* @return true, if input value is "not a number" (NaN)
|
||||
*/
|
||||
template<typename T> bool isNotNaN(const T& x)
|
||||
{
|
||||
return x==x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if number is plus infinity.
|
||||
*
|
||||
* @tparam T input type
|
||||
* @param x input value
|
||||
* @return true, if input value is plus infinity
|
||||
*/
|
||||
template<typename T> bool isPlusInf(const T& x)
|
||||
{
|
||||
return x > NumTraits<T>::highest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if number is minus infinity.
|
||||
*
|
||||
* @tparam T input type
|
||||
* @param x input value
|
||||
* @return true, if input value is minus infinity
|
||||
*/
|
||||
template<typename T> bool isMinusInf(const T& x)
|
||||
{
|
||||
return x < NumTraits<T>::lowest();
|
||||
@@ -722,6 +728,10 @@ template<typename T> bool isMinusInf(const T& x)
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
|
||||
#include "random_matrix_helper.h"
|
||||
|
||||
|
||||
template<typename T> struct GetDifferentType;
|
||||
|
||||
template<> struct GetDifferentType<float> { typedef double type; };
|
||||
@@ -729,8 +739,6 @@ 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 to avoid ICC warning
|
||||
template<typename T> std::string type_name();
|
||||
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"; }
|
||||
@@ -743,6 +751,11 @@ template<> std::string type_name<std::complex<int> >() { return "comple
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
/**
|
||||
* Set number of repetitions for unit test from input string.
|
||||
*
|
||||
* @param str input string
|
||||
*/
|
||||
inline void set_repeat_from_string(const char *str)
|
||||
{
|
||||
errno = 0;
|
||||
@@ -755,6 +768,11 @@ inline void set_repeat_from_string(const char *str)
|
||||
g_has_set_repeat = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set seed for randomized unit tests from input string.
|
||||
*
|
||||
* @param str input string
|
||||
*/
|
||||
inline void set_seed_from_string(const char *str)
|
||||
{
|
||||
errno = 0;
|
||||
@@ -855,3 +873,5 @@ int main(int argc, char *argv[])
|
||||
// 4503 - decorated name length exceeded, name was truncated
|
||||
#pragma warning( disable : 4503)
|
||||
#endif
|
||||
|
||||
#include "gpu_test_helper.h"
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
// 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"
|
||||
|
||||
#define EIGEN_TESTMAP_MAX_SIZE 256
|
||||
@@ -24,7 +20,9 @@ template<typename VectorType> void map_class_vector(const VectorType& m)
|
||||
Scalar* array1 = internal::aligned_new<Scalar>(size);
|
||||
Scalar* array2 = internal::aligned_new<Scalar>(size);
|
||||
Scalar* array3 = new Scalar[size+1];
|
||||
Scalar* array3unaligned = (internal::UIntPtr(array3)%EIGEN_MAX_ALIGN_BYTES) == 0 ? array3+1 : array3;
|
||||
// In case of no alignment, avoid division by zero.
|
||||
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
|
||||
Scalar* array3unaligned = (internal::UIntPtr(array3)%alignment) == 0 ? array3+1 : array3;
|
||||
Scalar array4[EIGEN_TESTMAP_MAX_SIZE];
|
||||
|
||||
Map<VectorType, AlignedMax>(array1, size) = VectorType::Random(size);
|
||||
@@ -64,7 +62,9 @@ template<typename MatrixType> void map_class_matrix(const MatrixType& m)
|
||||
Scalar* array3 = new Scalar[size+1];
|
||||
Index sizep1 = size + 1; // <- without this temporary MSVC 2103 generates bad code
|
||||
for(Index i = 0; i < sizep1; i++) array3[i] = Scalar(1);
|
||||
Scalar* array3unaligned = (internal::UIntPtr(array3)%EIGEN_MAX_ALIGN_BYTES) == 0 ? array3+1 : array3;
|
||||
// In case of no alignment, avoid division by zero.
|
||||
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
|
||||
Scalar* array3unaligned = (internal::UIntPtr(array3)%alignment) == 0 ? array3+1 : array3;
|
||||
Scalar array4[256];
|
||||
if(size<=256)
|
||||
for(int i = 0; i < size; i++) array4[i] = Scalar(1);
|
||||
@@ -127,7 +127,9 @@ template<typename VectorType> void map_static_methods(const VectorType& m)
|
||||
Scalar* array1 = internal::aligned_new<Scalar>(size);
|
||||
Scalar* array2 = internal::aligned_new<Scalar>(size);
|
||||
Scalar* array3 = new Scalar[size+1];
|
||||
Scalar* array3unaligned = internal::UIntPtr(array3)%EIGEN_MAX_ALIGN_BYTES == 0 ? array3+1 : array3;
|
||||
// In case of no alignment, avoid division by zero.
|
||||
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
|
||||
Scalar* array3unaligned = (internal::UIntPtr(array3)%alignment) == 0 ? array3+1 : array3;
|
||||
|
||||
VectorType::MapAligned(array1, size) = VectorType::Random(size);
|
||||
VectorType::Map(array2, size) = VectorType::Map(array1, size);
|
||||
@@ -150,7 +152,7 @@ template<typename PlainObjectType> void check_const_correctness(const PlainObjec
|
||||
// CMake can help with that.
|
||||
|
||||
// verify that map-to-const don't have LvalueBit
|
||||
typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
|
||||
typedef std::add_const_t<PlainObjectType> ConstPlainObjectType;
|
||||
VERIFY( !(internal::traits<Map<ConstPlainObjectType> >::Flags & LvalueBit) );
|
||||
VERIFY( !(internal::traits<Map<ConstPlainObjectType, AlignedMax> >::Flags & LvalueBit) );
|
||||
VERIFY( !(Map<ConstPlainObjectType>::Flags & LvalueBit) );
|
||||
|
||||
@@ -29,8 +29,8 @@ template<int Alignment,typename VectorType> void map_class_vector(const VectorTy
|
||||
map = v;
|
||||
for(int i = 0; i < size; ++i)
|
||||
{
|
||||
VERIFY(array[3*i] == v[i]);
|
||||
VERIFY(map[i] == v[i]);
|
||||
VERIFY_IS_EQUAL(array[3*i], v[i]);
|
||||
VERIFY_IS_EQUAL(map[i], v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ template<int Alignment,typename VectorType> void map_class_vector(const VectorTy
|
||||
map = v;
|
||||
for(int i = 0; i < size; ++i)
|
||||
{
|
||||
VERIFY(array[2*i] == v[i]);
|
||||
VERIFY(map[i] == v[i]);
|
||||
VERIFY_IS_EQUAL(array[2*i], v[i]);
|
||||
VERIFY_IS_EQUAL(map[i], v[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +65,13 @@ template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixTy
|
||||
|
||||
Scalar a_array2[256];
|
||||
Scalar* array2 = a_array2;
|
||||
if(Alignment!=Aligned)
|
||||
if(Alignment!=Aligned) {
|
||||
array2 = (Scalar*)(internal::IntPtr(a_array2) + (internal::packet_traits<Scalar>::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits<Scalar>::Real)));
|
||||
else
|
||||
array2 = (Scalar*)(((internal::UIntPtr(a_array2)+EIGEN_MAX_ALIGN_BYTES-1)/EIGEN_MAX_ALIGN_BYTES)*EIGEN_MAX_ALIGN_BYTES);
|
||||
} else {
|
||||
// In case there is no alignment, default to pointing to the start.
|
||||
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
|
||||
array2 = (Scalar*)(((internal::UIntPtr(a_array2)+alignment-1)/alignment)*alignment);
|
||||
}
|
||||
Index maxsize2 = a_array2 - array2 + 256;
|
||||
|
||||
// test no inner stride and some dynamic outer stride
|
||||
@@ -84,8 +87,8 @@ template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixTy
|
||||
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));
|
||||
VERIFY_IS_EQUAL(array[map.outerStride()*i+j], m.coeffByOuterInner(i,j));
|
||||
VERIFY_IS_EQUAL(map.coeffByOuterInner(i,j), m.coeffByOuterInner(i,j));
|
||||
}
|
||||
VERIFY_IS_APPROX(s1*map,s1*m);
|
||||
map *= s1;
|
||||
@@ -111,8 +114,8 @@ template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixTy
|
||||
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));
|
||||
VERIFY_IS_EQUAL(array[map.outerStride()*i+j], m.coeffByOuterInner(i,j));
|
||||
VERIFY_IS_EQUAL(map.coeffByOuterInner(i,j), m.coeffByOuterInner(i,j));
|
||||
}
|
||||
VERIFY_IS_APPROX(s1*map,s1*m);
|
||||
map *= s1;
|
||||
@@ -133,8 +136,8 @@ template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixTy
|
||||
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));
|
||||
VERIFY_IS_EQUAL(array[map.outerStride()*i+map.innerStride()*j], m.coeffByOuterInner(i,j));
|
||||
VERIFY_IS_EQUAL(map.coeffByOuterInner(i,j), m.coeffByOuterInner(i,j));
|
||||
}
|
||||
VERIFY_IS_APPROX(s1*map,s1*m);
|
||||
map *= s1;
|
||||
@@ -154,8 +157,8 @@ template<int Alignment,typename MatrixType> void map_class_matrix(const MatrixTy
|
||||
for(int i = 0; i < m.outerSize(); ++i)
|
||||
for(int j = 0; j < m.innerSize(); ++j)
|
||||
{
|
||||
VERIFY(array[map.innerSize()*i*2+j*2] == m.coeffByOuterInner(i,j));
|
||||
VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j));
|
||||
VERIFY_IS_EQUAL(array[map.innerSize()*i*2+j*2], m.coeffByOuterInner(i,j));
|
||||
VERIFY_IS_EQUAL(map.coeffByOuterInner(i,j), m.coeffByOuterInner(i,j));
|
||||
}
|
||||
VERIFY_IS_APPROX(s1*map,s1*m);
|
||||
map *= s1;
|
||||
|
||||
@@ -29,47 +29,28 @@ struct MyImpl : public MyInterface {
|
||||
|
||||
EIGEN_DECLARE_TEST(meta)
|
||||
{
|
||||
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));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<const float&> >::value));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<const float*> >::value));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<const float*&> >::value));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<float**> >::value));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<float**&> >::value));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<float* const *&> >::value));
|
||||
VERIFY(( internal::is_same<float,internal::remove_all_t<float* const> >::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_t<float&>, float const& >::value));
|
||||
VERIFY(( internal::is_same< internal::add_const_on_value_type_t<float*>, 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::is_same< internal::add_const_on_value_type_t<float>, const float >::value));
|
||||
VERIFY(( internal::is_same< internal::add_const_on_value_type_t<const float>, const float >::value));
|
||||
|
||||
VERIFY(( internal::is_same< internal::add_const_on_value_type_t<const float* const>, const float* const>::value));
|
||||
VERIFY(( internal::is_same< internal::add_const_on_value_type_t<float* const>, const float* const>::value));
|
||||
|
||||
// is_convertible
|
||||
STATIC_CHECK(( internal::is_convertible<float,double>::value ));
|
||||
@@ -114,13 +95,7 @@ EIGEN_DECLARE_TEST(meta)
|
||||
// So the following tests are expected to fail with recent compilers.
|
||||
|
||||
STATIC_CHECK(( !internal::is_convertible<MyInterface, MyImpl>::value ));
|
||||
#if (!EIGEN_COMP_GNUC_STRICT) || (EIGEN_GNUC_AT_LEAST(4,8))
|
||||
// GCC prior to 4.8 fails to compile this test:
|
||||
// error: cannot allocate an object of abstract type 'MyInterface'
|
||||
// In other word, it does not obey SFINAE.
|
||||
// Nevertheless, we don't really care about supporting abstract type as scalar type!
|
||||
STATIC_CHECK(( !internal::is_convertible<MyImpl, MyInterface>::value ));
|
||||
#endif
|
||||
STATIC_CHECK(( internal::is_convertible<MyImpl, const MyInterface&>::value ));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
|
||||
#if defined(EIGEN_TEST_PART_7)
|
||||
|
||||
#ifndef EIGEN_NO_STATIC_ASSERT
|
||||
#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them
|
||||
#endif
|
||||
|
||||
// ignore double-promotion diagnostic for clang and gcc, if we check for static assertion anyway:
|
||||
// TODO do the same for MSVC?
|
||||
#if defined(__clang__)
|
||||
@@ -49,28 +45,6 @@ using namespace std;
|
||||
VERIFY_IS_APPROX(XPR,REF); \
|
||||
VERIFY( g_called && #XPR" not properly optimized");
|
||||
|
||||
template<int SizeAtCompileType>
|
||||
void raise_assertion(Index size = SizeAtCompileType)
|
||||
{
|
||||
// VERIFY_RAISES_ASSERT(mf+md); // does not even compile
|
||||
Matrix<float, SizeAtCompileType, 1> vf; vf.setRandom(size);
|
||||
Matrix<double, SizeAtCompileType, 1> vd; vd.setRandom(size);
|
||||
VERIFY_RAISES_ASSERT(vf=vd);
|
||||
VERIFY_RAISES_ASSERT(vf+=vd);
|
||||
VERIFY_RAISES_ASSERT(vf-=vd);
|
||||
VERIFY_RAISES_ASSERT(vd=vf);
|
||||
VERIFY_RAISES_ASSERT(vd+=vf);
|
||||
VERIFY_RAISES_ASSERT(vd-=vf);
|
||||
|
||||
// vd.asDiagonal() * mf; // does not even compile
|
||||
// vcd.asDiagonal() * mf; // does not even compile
|
||||
|
||||
#if 0 // we get other compilation errors here than just static asserts
|
||||
VERIFY_RAISES_ASSERT(vd.dot(vf));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
|
||||
{
|
||||
typedef std::complex<float> CF;
|
||||
@@ -139,11 +113,12 @@ template<int SizeAtCompileType> void mixingtypes(int size = SizeAtCompileType)
|
||||
VERIFY_MIX_SCALAR(scd - vd.array() , scd - vd.template cast<complex<double> >().array());
|
||||
|
||||
// check scalar powers
|
||||
VERIFY_MIX_SCALAR( pow(vcf.array(), sf), Eigen::pow(vcf.array(), complex<float>(sf)) );
|
||||
VERIFY_MIX_SCALAR( vcf.array().pow(sf) , Eigen::pow(vcf.array(), complex<float>(sf)) );
|
||||
// NOTE: scalar exponents use a unary op.
|
||||
VERIFY_IS_APPROX( pow(vcf.array(), sf), Eigen::pow(vcf.array(), complex<float>(sf)) );
|
||||
VERIFY_IS_APPROX( vcf.array().pow(sf) , Eigen::pow(vcf.array(), complex<float>(sf)) );
|
||||
VERIFY_MIX_SCALAR( pow(sd, vcd.array()), Eigen::pow(complex<double>(sd), vcd.array()) );
|
||||
VERIFY_MIX_SCALAR( Eigen::pow(vf.array(), scf), Eigen::pow(vf.template cast<complex<float> >().array(), scf) );
|
||||
VERIFY_MIX_SCALAR( vf.array().pow(scf) , Eigen::pow(vf.template cast<complex<float> >().array(), scf) );
|
||||
VERIFY_IS_APPROX( Eigen::pow(vf.array(), scf), Eigen::pow(vf.template cast<complex<float> >().array(), scf) );
|
||||
VERIFY_IS_APPROX( vf.array().pow(scf) , Eigen::pow(vf.template cast<complex<float> >().array(), scf) );
|
||||
VERIFY_MIX_SCALAR( Eigen::pow(scd, vd.array()), Eigen::pow(scd, vd.template cast<complex<double> >().array()) );
|
||||
|
||||
// check dot product
|
||||
@@ -320,10 +295,5 @@ EIGEN_DECLARE_TEST(mixingtypes)
|
||||
CALL_SUBTEST_4(mixingtypes<3>());
|
||||
CALL_SUBTEST_5(mixingtypes<4>());
|
||||
CALL_SUBTEST_6(mixingtypes<Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)));
|
||||
CALL_SUBTEST_7(raise_assertion<Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE)));
|
||||
}
|
||||
CALL_SUBTEST_7(raise_assertion<0>());
|
||||
CALL_SUBTEST_7(raise_assertion<3>());
|
||||
CALL_SUBTEST_7(raise_assertion<4>());
|
||||
CALL_SUBTEST_7(raise_assertion<Dynamic>(0));
|
||||
}
|
||||
|
||||
@@ -26,12 +26,14 @@ EIGEN_DECLARE_TEST(nestbyvalue)
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
Index rows = internal::random<Index>(1,EIGEN_TEST_MAX_SIZE);
|
||||
Index cols = internal::random<Index>(1,EIGEN_TEST_MAX_SIZE);
|
||||
MatrixXd a = MatrixXd(rows,cols);
|
||||
MatrixXd a = MatrixXd::Random(rows,cols);
|
||||
nb_temporaries = 0;
|
||||
XprType x = get_xpr_with_temps(a);
|
||||
VERIFY_IS_EQUAL(nb_temporaries,6);
|
||||
MatrixXd b = x;
|
||||
VERIFY_IS_EQUAL(nb_temporaries,6+1);
|
||||
VERIFY_IS_APPROX(b, a.rowwise().reverse().eval() + (a+a).eval());
|
||||
// Block expressions work with dense NestByValue.
|
||||
VERIFY_IS_APPROX(b, a.nestByValue().rowwise().reverse().eval() + (a.nestByValue()+a.nestByValue()).eval());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ template <int N, typename ReferenceType, typename XprType>
|
||||
bool verify_eval_type(const XprType &, const ReferenceType&)
|
||||
{
|
||||
typedef typename internal::nested_eval<XprType,N>::type EvalType;
|
||||
return internal::is_same<typename internal::remove_all<EvalType>::type, typename internal::remove_all<ReferenceType>::type>::value;
|
||||
return internal::is_same<internal::remove_all_t<EvalType>, internal::remove_all_t<ReferenceType>>::value;
|
||||
}
|
||||
|
||||
template <typename MatrixType> void run_nesting_ops_1(const MatrixType& _m)
|
||||
|
||||
@@ -152,7 +152,7 @@ void ctms_decompositions()
|
||||
x = fpQR.solve(b);
|
||||
|
||||
// SVD module
|
||||
Eigen::JacobiSVD<Matrix> jSVD; jSVD.compute(A, ComputeFullU | ComputeFullV);
|
||||
Eigen::JacobiSVD<Matrix, ComputeFullU | ComputeFullV> jSVD; jSVD.compute(A);
|
||||
}
|
||||
|
||||
void test_zerosized() {
|
||||
|
||||
@@ -13,24 +13,20 @@
|
||||
template<typename MatrixType>
|
||||
bool equalsIdentity(const MatrixType& A)
|
||||
{
|
||||
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);
|
||||
offDiagOK = offDiagOK && numext::is_exactly_zero(A(i, j));
|
||||
}
|
||||
}
|
||||
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);
|
||||
offDiagOK = offDiagOK && numext::is_exactly_zero(A(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
bool diagOK = (A.diagonal().array() == 1).all();
|
||||
return offDiagOK && diagOK;
|
||||
|
||||
}
|
||||
|
||||
template<typename VectorType>
|
||||
@@ -82,8 +78,9 @@ void testVectorType(const VectorType& base)
|
||||
const Scalar step = ((size == 1) ? 1 : (high-low)/RealScalar(size-1));
|
||||
|
||||
// check whether the result yields what we expect it to do
|
||||
VectorType m(base);
|
||||
VectorType m(base), o(base);
|
||||
m.setLinSpaced(size,low,high);
|
||||
o.setEqualSpaced(size, low, step);
|
||||
|
||||
if(!NumTraits<Scalar>::IsInteger)
|
||||
{
|
||||
@@ -91,6 +88,7 @@ void testVectorType(const VectorType& base)
|
||||
for (int i=0; i<size; ++i)
|
||||
n(i) = low+RealScalar(i)*step;
|
||||
VERIFY_IS_APPROX(m,n);
|
||||
VERIFY_IS_APPROX(n,o);
|
||||
|
||||
CALL_SUBTEST( check_extremity_accuracy(m, low, high) );
|
||||
}
|
||||
@@ -260,11 +258,12 @@ void nullary_overflow()
|
||||
{
|
||||
// Check possible overflow issue
|
||||
int n = 60000;
|
||||
ArrayXi a1(n), a2(n);
|
||||
a1.setLinSpaced(n, 0, n-1);
|
||||
for(int i=0; i<n; ++i)
|
||||
a2(i) = i;
|
||||
VERIFY_IS_APPROX(a1,a2);
|
||||
ArrayXi a1(n), a2(n), a_ref(n);
|
||||
a1.setLinSpaced(n, 0, n - 1);
|
||||
a2.setEqualSpaced(n, 0, 1);
|
||||
for (int i = 0; i < n; ++i) a_ref(i) = i;
|
||||
VERIFY_IS_APPROX(a1, a_ref);
|
||||
VERIFY_IS_APPROX(a2, a_ref);
|
||||
}
|
||||
|
||||
template<int>
|
||||
|
||||
@@ -15,7 +15,6 @@ void check_dim(const Xpr& ) {
|
||||
STATIC_CHECK( Xpr::NumDimensions == ExpectedDim );
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
template<template <typename,int,int> class Object>
|
||||
void map_num_dimensions()
|
||||
{
|
||||
@@ -58,8 +57,6 @@ using TArray = Array<Scalar,Rows,Cols>;
|
||||
template<typename Scalar, int Rows, int Cols>
|
||||
using TMatrix = Matrix<Scalar,Rows,Cols>;
|
||||
|
||||
#endif
|
||||
|
||||
EIGEN_DECLARE_TEST(num_dimensions)
|
||||
{
|
||||
int n = 10;
|
||||
@@ -81,10 +78,7 @@ EIGEN_DECLARE_TEST(num_dimensions)
|
||||
SparseVector<double> s(n);
|
||||
CALL_SUBTEST( check_dim<1>(s) );
|
||||
CALL_SUBTEST( check_dim<1>(s.head(2)) );
|
||||
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
CALL_SUBTEST( map_num_dimensions<TArray>() );
|
||||
CALL_SUBTEST( map_num_dimensions<TMatrix>() );
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
template<typename T, typename U>
|
||||
bool check_if_equal_or_nans(const T& actual, const U& expected) {
|
||||
return ((actual == expected) || ((numext::isnan)(actual) && (numext::isnan)(expected)));
|
||||
return (numext::equal_strict(actual, expected) || ((numext::isnan)(actual) && (numext::isnan)(expected)));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
@@ -239,6 +239,63 @@ void check_rsqrt() {
|
||||
check_rsqrt_impl<T>::run();
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct check_signbit_impl {
|
||||
static void run() {
|
||||
T true_mask;
|
||||
std::memset(static_cast<void*>(&true_mask), 0xff, sizeof(T));
|
||||
T false_mask;
|
||||
std::memset(static_cast<void*>(&false_mask), 0x00, sizeof(T));
|
||||
|
||||
std::vector<T> negative_values;
|
||||
std::vector<T> non_negative_values;
|
||||
|
||||
if (NumTraits<T>::IsInteger) {
|
||||
negative_values = {static_cast<T>(-1),
|
||||
static_cast<T>(NumTraits<T>::lowest())};
|
||||
non_negative_values = {static_cast<T>(0), static_cast<T>(1),
|
||||
static_cast<T>(NumTraits<T>::highest())};
|
||||
} else {
|
||||
// has sign bit
|
||||
const T neg_zero = static_cast<T>(-0.0);
|
||||
const T neg_one = static_cast<T>(-1.0);
|
||||
const T neg_inf = -std::numeric_limits<T>::infinity();
|
||||
const T neg_nan = -std::numeric_limits<T>::quiet_NaN();
|
||||
// does not have sign bit
|
||||
const T pos_zero = static_cast<T>(0.0);
|
||||
const T pos_one = static_cast<T>(1.0);
|
||||
const T pos_inf = std::numeric_limits<T>::infinity();
|
||||
const T pos_nan = std::numeric_limits<T>::quiet_NaN();
|
||||
negative_values = {neg_zero, neg_one, neg_inf, neg_nan};
|
||||
non_negative_values = {pos_zero, pos_one, pos_inf, pos_nan};
|
||||
}
|
||||
|
||||
|
||||
auto check_all = [](auto values, auto expected) {
|
||||
bool all_pass = true;
|
||||
for (T val : values) {
|
||||
const T numext_val = numext::signbit(val);
|
||||
bool not_same = internal::predux_any(
|
||||
internal::bitwise_helper<T>::bitwise_xor(expected, numext_val));
|
||||
all_pass = all_pass && !not_same;
|
||||
if (not_same)
|
||||
std::cout << "signbit(" << val << ") = " << numext_val
|
||||
<< " != " << expected << std::endl;
|
||||
}
|
||||
return all_pass;
|
||||
};
|
||||
|
||||
bool all_pass = check_all(non_negative_values, false_mask);
|
||||
all_pass = all_pass && check_all(negative_values, (NumTraits<T>::IsSigned ? true_mask : false_mask));
|
||||
VERIFY(all_pass);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
void check_signbit() {
|
||||
check_signbit_impl<T>::run();
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(numext) {
|
||||
for(int k=0; k<g_repeat; ++k)
|
||||
{
|
||||
@@ -266,10 +323,25 @@ EIGEN_DECLARE_TEST(numext) {
|
||||
CALL_SUBTEST( check_sqrt<double>() );
|
||||
CALL_SUBTEST( check_sqrt<std::complex<float> >() );
|
||||
CALL_SUBTEST( check_sqrt<std::complex<double> >() );
|
||||
|
||||
|
||||
CALL_SUBTEST( check_rsqrt<float>() );
|
||||
CALL_SUBTEST( check_rsqrt<double>() );
|
||||
CALL_SUBTEST( check_rsqrt<std::complex<float> >() );
|
||||
CALL_SUBTEST( check_rsqrt<std::complex<double> >() );
|
||||
|
||||
CALL_SUBTEST( check_signbit<half>());
|
||||
CALL_SUBTEST( check_signbit<bfloat16>());
|
||||
CALL_SUBTEST( check_signbit<float>());
|
||||
CALL_SUBTEST( check_signbit<double>());
|
||||
|
||||
CALL_SUBTEST( check_signbit<uint8_t>());
|
||||
CALL_SUBTEST( check_signbit<uint16_t>());
|
||||
CALL_SUBTEST( check_signbit<uint32_t>());
|
||||
CALL_SUBTEST( check_signbit<uint64_t>());
|
||||
|
||||
CALL_SUBTEST( check_signbit<int8_t>());
|
||||
CALL_SUBTEST( check_signbit<int16_t>());
|
||||
CALL_SUBTEST( check_signbit<int32_t>());
|
||||
CALL_SUBTEST( check_signbit<int64_t>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,30 @@ inline T REF_MUL(const T& a, const T& b) {
|
||||
return a * b;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_MADD(const T& a, const T& b, const T& c) {
|
||||
return a * b + c;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_MSUB(const T& a, const T& b, const T& c) {
|
||||
return a * b - c;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_NMADD(const T& a, const T& b, const T& c) {
|
||||
return (-a * b) + c;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_NMSUB(const T& a, const T& b, const T& c) {
|
||||
return (-a * b) - c;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_DIV(const T& a, const T& b) {
|
||||
return a / b;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_RECIPROCAL(const T& a) {
|
||||
return T(1) / a;
|
||||
}
|
||||
template <typename T>
|
||||
inline T REF_ABS_DIFF(const T& a, const T& b) {
|
||||
return a > b ? a - b : b - a;
|
||||
}
|
||||
@@ -45,13 +65,23 @@ template <>
|
||||
inline bool REF_MUL(const bool& a, const bool& b) {
|
||||
return a && b;
|
||||
}
|
||||
template <>
|
||||
inline bool REF_MADD(const bool& a, const bool& b, const bool& c) {
|
||||
return (a && b) || c;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T REF_FREXP(const T& x, T& exp) {
|
||||
int iexp;
|
||||
int iexp = 0;
|
||||
EIGEN_USING_STD(frexp)
|
||||
const T out = static_cast<T>(frexp(x, &iexp));
|
||||
exp = static_cast<T>(iexp);
|
||||
|
||||
// The exponent value is unspecified if the input is inf or NaN, but MSVC
|
||||
// seems to set it to 1. We need to set it back to zero for consistency.
|
||||
if (!(numext::isfinite)(x)) {
|
||||
exp = T(0);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -235,7 +265,7 @@ struct packetmath_pcast_ops_runner {
|
||||
|
||||
// Only some types support cast from std::complex<>.
|
||||
template <typename Scalar, typename Packet>
|
||||
struct packetmath_pcast_ops_runner<Scalar, Packet, typename internal::enable_if<NumTraits<Scalar>::IsComplex>::type> {
|
||||
struct packetmath_pcast_ops_runner<Scalar, Packet, std::enable_if_t<NumTraits<Scalar>::IsComplex>> {
|
||||
static void run() {
|
||||
test_cast_runner<Packet, std::complex<float> >::run();
|
||||
test_cast_runner<Packet, std::complex<double> >::run();
|
||||
@@ -353,10 +383,10 @@ template <typename Scalar, typename Packet>
|
||||
void packetmath_minus_zero_add() {
|
||||
const int PacketSize = internal::unpacket_traits<Packet>::size;
|
||||
const int size = 2 * PacketSize;
|
||||
EIGEN_ALIGN_MAX Scalar data1[size];
|
||||
EIGEN_ALIGN_MAX Scalar data2[size];
|
||||
EIGEN_ALIGN_MAX Scalar ref[size];
|
||||
|
||||
EIGEN_ALIGN_MAX Scalar data1[size] = {};
|
||||
EIGEN_ALIGN_MAX Scalar data2[size] = {};
|
||||
EIGEN_ALIGN_MAX Scalar ref[size] = {};
|
||||
|
||||
for (int i = 0; i < PacketSize; ++i) {
|
||||
data1[i] = Scalar(-0.0);
|
||||
data1[i + PacketSize] = Scalar(-0.0);
|
||||
@@ -374,11 +404,11 @@ struct eigen_optimization_barrier_test {
|
||||
};
|
||||
|
||||
template<typename Packet>
|
||||
struct eigen_optimization_barrier_test<Packet, typename internal::enable_if<
|
||||
struct eigen_optimization_barrier_test<Packet, std::enable_if_t<
|
||||
!NumTraits<Packet>::IsComplex &&
|
||||
!internal::is_same<Packet, Eigen::half>::value &&
|
||||
!internal::is_same<Packet, Eigen::bfloat16>::value
|
||||
>::type> {
|
||||
>> {
|
||||
static void run() {
|
||||
typedef typename internal::unpacket_traits<Packet>::type Scalar;
|
||||
Scalar s = internal::random<Scalar>();
|
||||
@@ -428,6 +458,36 @@ void packetmath() {
|
||||
VERIFY(test::areApprox(data1, data2 + offset, PacketSize) && "internal::pstoreu");
|
||||
}
|
||||
|
||||
for (int M = 0; M < PacketSize; ++M) {
|
||||
for (int N = 0; N <= PacketSize; ++N) {
|
||||
for (int j = 0; j < size; ++j) {
|
||||
data1[j] = internal::random<Scalar>() / RealScalar(PacketSize);
|
||||
data2[j] = internal::random<Scalar>() / RealScalar(PacketSize);
|
||||
refvalue = (std::max)(refvalue, numext::abs(data1[j]));
|
||||
}
|
||||
|
||||
if (M == 0) {
|
||||
internal::pstore_partial(data2, internal::pload_partial<Packet>(data1, N), N);
|
||||
VERIFY(test::areApprox(data1, data2, N) && "aligned loadN/storeN");
|
||||
|
||||
for (int offset = 0; offset < PacketSize; ++offset) {
|
||||
internal::pstore_partial(data2, internal::ploadu_partial<Packet>(data1 + offset, N), N);
|
||||
VERIFY(test::areApprox(data1 + offset, data2, N) && "internal::ploadu_partial");
|
||||
}
|
||||
|
||||
for (int offset = 0; offset < PacketSize; ++offset) {
|
||||
internal::pstoreu_partial(data2 + offset, internal::pload_partial<Packet>(data1, N), N);
|
||||
VERIFY(test::areApprox(data1, data2 + offset, N) && "internal::pstoreu_partial");
|
||||
}
|
||||
}
|
||||
|
||||
if (N + M > PacketSize) continue; // Don't read or write past end of Packet
|
||||
|
||||
internal::pstore_partial(data2, internal::pload_partial<Packet>(data1, N, M), N, M);
|
||||
VERIFY(test::areApprox(data1, data2, N) && "aligned offset loadN/storeN");
|
||||
}
|
||||
}
|
||||
|
||||
if (internal::unpacket_traits<Packet>::masked_load_available) {
|
||||
test::packet_helper<internal::unpacket_traits<Packet>::masked_load_available, Packet> h;
|
||||
unsigned long long max_umask = (0x1ull << PacketSize);
|
||||
@@ -464,8 +524,11 @@ void packetmath() {
|
||||
CHECK_CWISE2_IF(PacketTraits::HasMul, REF_MUL, internal::pmul);
|
||||
CHECK_CWISE2_IF(PacketTraits::HasDiv, REF_DIV, internal::pdiv);
|
||||
|
||||
if (PacketTraits::HasNegate) CHECK_CWISE1(internal::negate, internal::pnegate);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasNegate, internal::negate, internal::pnegate);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasReciprocal, REF_RECIPROCAL, internal::preciprocal);
|
||||
CHECK_CWISE1(numext::conj, internal::pconj);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasSign, numext::sign, internal::psign);
|
||||
|
||||
|
||||
for (int offset = 0; offset < 3; ++offset) {
|
||||
for (int i = 0; i < PacketSize; ++i) ref[i] = data1[offset];
|
||||
@@ -616,6 +679,23 @@ void packetmath() {
|
||||
}
|
||||
CHECK_CWISE1_IF(PacketTraits::HasSqrt, numext::sqrt, internal::psqrt);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasRsqrt, numext::rsqrt, internal::prsqrt);
|
||||
CHECK_CWISE3_IF(true, REF_MADD, internal::pmadd);
|
||||
if (!std::is_same<Scalar, bool>::value && NumTraits<Scalar>::IsSigned) {
|
||||
CHECK_CWISE3_IF(true, REF_NMSUB, internal::pnmsub);
|
||||
}
|
||||
|
||||
// For pmsub, pnmadd, the values can cancel each other to become near zero,
|
||||
// which can lead to very flaky tests. Here we ensure the signs are such that
|
||||
// they do not cancel.
|
||||
for (int i = 0; i < PacketSize; ++i) {
|
||||
data1[i] = numext::abs(internal::random<Scalar>());
|
||||
data1[i + PacketSize] = numext::abs(internal::random<Scalar>());
|
||||
data1[i + 2 * PacketSize] = -numext::abs(internal::random<Scalar>());
|
||||
}
|
||||
if (!std::is_same<Scalar, bool>::value && NumTraits<Scalar>::IsSigned) {
|
||||
CHECK_CWISE3_IF(true, REF_MSUB, internal::pmsub);
|
||||
CHECK_CWISE3_IF(true, REF_NMADD, internal::pnmadd);
|
||||
}
|
||||
}
|
||||
|
||||
// Notice that this definition works for complex types as well.
|
||||
@@ -625,15 +705,104 @@ Scalar log2(Scalar x) {
|
||||
return Scalar(EIGEN_LOG2E) * std::log(x);
|
||||
}
|
||||
|
||||
// Create a functor out of a function so it can be passed (with overloads)
|
||||
// to another function as an input argument.
|
||||
#define CREATE_FUNCTOR(Name, Func) \
|
||||
struct Name { \
|
||||
template<typename T> \
|
||||
T operator()(const T& val) const { \
|
||||
return Func(val); \
|
||||
} \
|
||||
}
|
||||
|
||||
CREATE_FUNCTOR(psqrt_functor, internal::psqrt);
|
||||
CREATE_FUNCTOR(prsqrt_functor, internal::prsqrt);
|
||||
|
||||
// TODO(rmlarsen): Run this test for more functions.
|
||||
template <bool Cond, typename Scalar, typename Packet, typename RefFunctorT, typename FunctorT>
|
||||
void packetmath_test_IEEE_corner_cases(const RefFunctorT& ref_fun,
|
||||
const FunctorT& fun) {
|
||||
const int PacketSize = internal::unpacket_traits<Packet>::size;
|
||||
const Scalar norm_min = (std::numeric_limits<Scalar>::min)();
|
||||
const Scalar norm_max = (std::numeric_limits<Scalar>::max)();
|
||||
|
||||
constexpr int size = PacketSize * 2;
|
||||
EIGEN_ALIGN_MAX Scalar data1[size];
|
||||
EIGEN_ALIGN_MAX Scalar data2[size];
|
||||
EIGEN_ALIGN_MAX Scalar ref[size];
|
||||
for (int i = 0; i < size; ++i) {
|
||||
data1[i] = data2[i] = ref[i] = Scalar(0);
|
||||
}
|
||||
|
||||
// Test for subnormals.
|
||||
if (Cond && std::numeric_limits<Scalar>::has_denorm == std::denorm_present) {
|
||||
|
||||
for (int scale = 1; scale < 5; ++scale) {
|
||||
// When EIGEN_FAST_MATH is 1 we relax the conditions slightly, and allow the function
|
||||
// to return the same value for subnormals as the reference would return for zero with
|
||||
// the same sign as the input.
|
||||
#if EIGEN_FAST_MATH
|
||||
data1[0] = Scalar(scale) * std::numeric_limits<Scalar>::denorm_min();
|
||||
data1[1] = -data1[0];
|
||||
test::packet_helper<Cond, Packet> h;
|
||||
h.store(data2, fun(h.load(data1)));
|
||||
for (int i=0; i < PacketSize; ++i) {
|
||||
const Scalar ref_zero = ref_fun(data1[i] < 0 ? -Scalar(0) : Scalar(0));
|
||||
const Scalar ref_val = ref_fun(data1[i]);
|
||||
VERIFY(((std::isnan)(data2[i]) && (std::isnan)(ref_val)) || data2[i] == ref_zero ||
|
||||
verifyIsApprox(data2[i], ref_val));
|
||||
}
|
||||
#else
|
||||
CHECK_CWISE1_IF(Cond, ref_fun, fun);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Test for smallest normalized floats.
|
||||
data1[0] = norm_min;
|
||||
data1[1] = -data1[0];
|
||||
CHECK_CWISE1_IF(Cond, ref_fun, fun);
|
||||
|
||||
// Test for largest floats.
|
||||
data1[0] = norm_max;
|
||||
data1[1] = -data1[0];
|
||||
CHECK_CWISE1_IF(Cond, ref_fun, fun);
|
||||
|
||||
// Test for zeros.
|
||||
data1[0] = Scalar(0.0);
|
||||
data1[1] = -data1[0];
|
||||
CHECK_CWISE1_IF(Cond, ref_fun, fun);
|
||||
|
||||
// Test for infinities.
|
||||
data1[0] = NumTraits<Scalar>::infinity();
|
||||
data1[1] = -data1[0];
|
||||
CHECK_CWISE1_IF(Cond, ref_fun, fun);
|
||||
|
||||
// Test for quiet NaNs.
|
||||
data1[0] = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
data1[1] = -std::numeric_limits<Scalar>::quiet_NaN();
|
||||
CHECK_CWISE1_IF(Cond, ref_fun, fun);
|
||||
}
|
||||
|
||||
template <typename Scalar, typename Packet>
|
||||
void packetmath_real() {
|
||||
typedef internal::packet_traits<Scalar> PacketTraits;
|
||||
const int PacketSize = internal::unpacket_traits<Packet>::size;
|
||||
|
||||
const int size = PacketSize * 4;
|
||||
EIGEN_ALIGN_MAX Scalar data1[PacketSize * 4];
|
||||
EIGEN_ALIGN_MAX Scalar data2[PacketSize * 4];
|
||||
EIGEN_ALIGN_MAX Scalar ref[PacketSize * 4];
|
||||
EIGEN_ALIGN_MAX Scalar data1[PacketSize * 4] = {};
|
||||
EIGEN_ALIGN_MAX Scalar data2[PacketSize * 4] = {};
|
||||
EIGEN_ALIGN_MAX Scalar ref[PacketSize * 4] = {};
|
||||
|
||||
// Negate with -0.
|
||||
if (PacketTraits::HasNegate) {
|
||||
test::packet_helper<PacketTraits::HasNegate,Packet> h;
|
||||
data1[0] = Scalar{-0};
|
||||
h.store(data2, internal::pnegate(h.load(data1)));
|
||||
typedef typename internal::make_unsigned<typename internal::make_integer<Scalar>::type>::type Bits;
|
||||
Bits bits = numext::bit_cast<Bits>(data2[0]);
|
||||
VERIFY_IS_EQUAL(bits, static_cast<Bits>(Bits(1)<<(sizeof(Scalar)*CHAR_BIT - 1)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
data1[i] = Scalar(internal::random<double>(0, 1) * std::pow(10., internal::random<double>(-6, 6)));
|
||||
@@ -658,6 +827,7 @@ void packetmath_real() {
|
||||
CHECK_CWISE1_EXACT_IF(PacketTraits::HasCeil, numext::ceil, internal::pceil);
|
||||
CHECK_CWISE1_EXACT_IF(PacketTraits::HasFloor, numext::floor, internal::pfloor);
|
||||
CHECK_CWISE1_EXACT_IF(PacketTraits::HasRint, numext::rint, internal::print);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasSign, numext::sign, internal::psign);
|
||||
|
||||
packetmath_boolean_mask_ops_real<Scalar,Packet>();
|
||||
|
||||
@@ -713,6 +883,7 @@ void packetmath_real() {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
data1[i] = Scalar(internal::random<double>(-87, 88));
|
||||
data2[i] = Scalar(internal::random<double>(-87, 88));
|
||||
data1[0] = -NumTraits<Scalar>::infinity();
|
||||
}
|
||||
CHECK_CWISE1_IF(PacketTraits::HasExp, std::exp, internal::pexp);
|
||||
|
||||
@@ -847,7 +1018,7 @@ void packetmath_real() {
|
||||
}
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_C99_MATH && (EIGEN_COMP_CXXVER >= 11)
|
||||
#if EIGEN_HAS_C99_MATH
|
||||
data1[0] = NumTraits<Scalar>::infinity();
|
||||
data1[1] = Scalar(-1);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasLog1p, std::log1p, internal::plog1p);
|
||||
@@ -889,8 +1060,10 @@ void packetmath_real() {
|
||||
data1[0] = std::numeric_limits<Scalar>::denorm_min();
|
||||
data1[1] = -std::numeric_limits<Scalar>::denorm_min();
|
||||
h.store(data2, internal::plog(h.load(data1)));
|
||||
// TODO(rmlarsen): Reenable.
|
||||
// VERIFY_IS_EQUAL(std::log(std::numeric_limits<Scalar>::denorm_min()), data2[0]);
|
||||
// TODO(rmlarsen): Re-enable for bfloat16.
|
||||
if (!internal::is_same<Scalar, bfloat16>::value) {
|
||||
VERIFY_IS_APPROX(std::log(std::numeric_limits<Scalar>::denorm_min()), data2[0]);
|
||||
}
|
||||
VERIFY((numext::isnan)(data2[1]));
|
||||
}
|
||||
#endif
|
||||
@@ -911,18 +1084,10 @@ void packetmath_real() {
|
||||
VERIFY((numext::isnan)(data2[0]));
|
||||
VERIFY((numext::isnan)(data2[1]));
|
||||
}
|
||||
if (PacketTraits::HasSqrt) {
|
||||
test::packet_helper<PacketTraits::HasSqrt, Packet> h;
|
||||
data1[0] = Scalar(-1.0f);
|
||||
if (std::numeric_limits<Scalar>::has_denorm == std::denorm_present) {
|
||||
data1[1] = -std::numeric_limits<Scalar>::denorm_min();
|
||||
} else {
|
||||
data1[1] = -NumTraits<Scalar>::epsilon();
|
||||
}
|
||||
h.store(data2, internal::psqrt(h.load(data1)));
|
||||
VERIFY((numext::isnan)(data2[0]));
|
||||
VERIFY((numext::isnan)(data2[1]));
|
||||
}
|
||||
|
||||
packetmath_test_IEEE_corner_cases<PacketTraits::HasSqrt, Scalar, Packet>(numext::sqrt<Scalar>, psqrt_functor());
|
||||
packetmath_test_IEEE_corner_cases<PacketTraits::HasRsqrt, Scalar, Packet>(numext::rsqrt<Scalar>, prsqrt_functor());
|
||||
|
||||
// TODO(rmlarsen): Re-enable for half and bfloat16.
|
||||
if (PacketTraits::HasCos
|
||||
&& !internal::is_same<Scalar, half>::value
|
||||
@@ -972,6 +1137,23 @@ void packetmath_real() {
|
||||
VERIFY_IS_EQUAL(data2[0], Scalar(1));
|
||||
}
|
||||
}
|
||||
if (PacketTraits::HasReciprocal && PacketSize >= 2) {
|
||||
test::packet_helper<PacketTraits::HasReciprocal, Packet> h;
|
||||
const Scalar inf = NumTraits<Scalar>::infinity();
|
||||
const Scalar zero = Scalar(0);
|
||||
data1[0] = zero;
|
||||
data1[1] = -zero;
|
||||
h.store(data2, internal::preciprocal(h.load(data1)));
|
||||
VERIFY_IS_EQUAL(data2[0], inf);
|
||||
VERIFY_IS_EQUAL(data2[1], -inf);
|
||||
|
||||
data1[0] = inf;
|
||||
data1[1] = -inf;
|
||||
h.store(data2, internal::preciprocal(h.load(data1)));
|
||||
VERIFY_IS_EQUAL(data2[0], zero);
|
||||
VERIFY_IS_EQUAL(data2[1], -zero);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define CAST_CHECK_CWISE1_IF(COND, REFOP, POP, SCALAR, REFTYPE) if(COND) { \
|
||||
@@ -1170,6 +1352,7 @@ void packetmath_complex() {
|
||||
data1[i] = Scalar(internal::random<RealScalar>(), internal::random<RealScalar>());
|
||||
}
|
||||
CHECK_CWISE1_N(numext::sqrt, internal::psqrt, size);
|
||||
CHECK_CWISE1_IF(PacketTraits::HasSign, numext::sign, internal::psign);
|
||||
|
||||
// Test misc. corner cases.
|
||||
const RealScalar zero = RealScalar(0);
|
||||
@@ -1243,6 +1426,36 @@ void packetmath_scatter_gather() {
|
||||
for (int i = 0; i < PacketSize; ++i) {
|
||||
VERIFY(test::isApproxAbs(data1[i], buffer[i * 7], refvalue) && "pgather");
|
||||
}
|
||||
|
||||
for (Index N = 0; N <= PacketSize; ++N) {
|
||||
for (Index i = 0; i < N; ++i) {
|
||||
data1[i] = internal::random<Scalar>() / RealScalar(PacketSize);
|
||||
}
|
||||
|
||||
for (Index i = 0; i < N * 20; ++i) {
|
||||
buffer[i] = Scalar(0);
|
||||
}
|
||||
|
||||
packet = internal::pload_partial<Packet>(data1, N);
|
||||
internal::pscatter_partial<Scalar, Packet>(buffer, packet, stride, N);
|
||||
|
||||
for (Index i = 0; i < N * 20; ++i) {
|
||||
if ((i % stride) == 0 && i < stride * N) {
|
||||
VERIFY(test::isApproxAbs(buffer[i], data1[i / stride], refvalue) && "pscatter_partial");
|
||||
} else {
|
||||
VERIFY(test::isApproxAbs(buffer[i], Scalar(0), refvalue) && "pscatter_partial");
|
||||
}
|
||||
}
|
||||
|
||||
for (Index i = 0; i < N * 7; ++i) {
|
||||
buffer[i] = internal::random<Scalar>() / RealScalar(PacketSize);
|
||||
}
|
||||
packet = internal::pgather_partial<Scalar, Packet>(buffer, 7, N);
|
||||
internal::pstore_partial(data1, packet, N);
|
||||
for (Index i = 0; i < N; ++i) {
|
||||
VERIFY(test::isApproxAbs(data1[i], buffer[i * 7], refvalue) && "pgather_partial");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
@@ -90,6 +90,7 @@ template<typename Scalar> bool areApproxAbs(const Scalar* a, const Scalar* b, in
|
||||
if (!isApproxAbs(a[i],b[i],refvalue))
|
||||
{
|
||||
print_mismatch(a, b, size);
|
||||
std::cout << "Values differ in position " << i << ": " << a[i] << " vs " << b[i] << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -100,10 +101,11 @@ template<typename Scalar> bool areApprox(const Scalar* a, const Scalar* b, int s
|
||||
{
|
||||
for (int i=0; i<size; ++i)
|
||||
{
|
||||
if ( a[i]!=b[i] && !internal::isApprox(a[i],b[i])
|
||||
if ( numext::not_equal_strict(a[i], b[i]) && !internal::isApprox(a[i],b[i])
|
||||
&& !((numext::isnan)(a[i]) && (numext::isnan)(b[i])) )
|
||||
{
|
||||
print_mismatch(a, b, size);
|
||||
std::cout << "Values differ in position " << i << ": " << a[i] << " vs " << b[i] << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -114,9 +116,10 @@ template<typename Scalar> bool areEqual(const Scalar* a, const Scalar* b, int si
|
||||
{
|
||||
for (int i=0; i<size; ++i)
|
||||
{
|
||||
if ( (a[i] != b[i]) && !((numext::isnan)(a[i]) && (numext::isnan)(b[i])) )
|
||||
if ( numext::not_equal_strict(a[i], b[i]) && !((numext::isnan)(a[i]) && (numext::isnan)(b[i])) )
|
||||
{
|
||||
print_mismatch(a, b, size);
|
||||
std::cout << "Values differ in position " << i << ": " << a[i] << " vs " << b[i] << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,15 +13,12 @@
|
||||
|
||||
template<typename MatrixType> void inverse_permutation_4x4()
|
||||
{
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
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);
|
||||
VERIFY_IS_APPROX(m*inv, MatrixType::Identity());
|
||||
std::next_permutation(indices.data(),indices.data()+4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,17 @@ bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2
|
||||
* (std::max)(m1.cwiseAbs2().maxCoeff(), m2.cwiseAbs2().maxCoeff()));
|
||||
}
|
||||
|
||||
template <typename LhsType, typename RhsType>
|
||||
std::enable_if_t<RhsType::SizeAtCompileTime==Dynamic,void>
|
||||
check_mismatched_product(LhsType& lhs, const RhsType& rhs) {
|
||||
VERIFY_RAISES_ASSERT(lhs = rhs*rhs);
|
||||
}
|
||||
|
||||
template <typename LhsType, typename RhsType>
|
||||
std::enable_if_t<RhsType::SizeAtCompileTime!=Dynamic,void>
|
||||
check_mismatched_product(LhsType& /*unused*/, const RhsType& /*unused*/) {
|
||||
}
|
||||
|
||||
template<typename MatrixType> void product(const MatrixType& m)
|
||||
{
|
||||
/* this test covers the following files:
|
||||
@@ -77,8 +88,9 @@ template<typename MatrixType> void product(const MatrixType& m)
|
||||
// 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);
|
||||
if (rows!=cols) {
|
||||
check_mismatched_product(m3, m1);
|
||||
}
|
||||
|
||||
// test the previous tests were not screwed up because operator* returns 0
|
||||
// (we use the more accurate default epsilon)
|
||||
@@ -126,7 +138,7 @@ template<typename MatrixType> void product(const MatrixType& m)
|
||||
res.noalias() = square + m1 * m2.transpose();
|
||||
VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
|
||||
res.noalias() += square + m1 * m2.transpose();
|
||||
VERIFY_IS_APPROX(res, 2*(square + m1 * m2.transpose()));
|
||||
VERIFY_IS_APPROX(res, Scalar(2)*(square + m1 * m2.transpose()));
|
||||
res.noalias() -= square + m1 * m2.transpose();
|
||||
VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
|
||||
|
||||
@@ -134,7 +146,7 @@ template<typename MatrixType> void product(const MatrixType& m)
|
||||
res.noalias() = square - m1 * m2.transpose();
|
||||
VERIFY_IS_APPROX(res, square - m1 * m2.transpose());
|
||||
res.noalias() += square - m1 * m2.transpose();
|
||||
VERIFY_IS_APPROX(res, 2*(square - m1 * m2.transpose()));
|
||||
VERIFY_IS_APPROX(res, Scalar(2)*(square - m1 * m2.transpose()));
|
||||
res.noalias() -= square - m1 * m2.transpose();
|
||||
VERIFY_IS_APPROX(res, square - m1 * m2.transpose());
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ EIGEN_DECLARE_TEST(product_large)
|
||||
CALL_SUBTEST_8( product(Matrix<double,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_9( product(Matrix<std::complex<float>,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_10( product(Matrix<std::complex<double>,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
CALL_SUBTEST_11( product(Matrix<bfloat16,Dynamic,Dynamic,RowMajor>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
|
||||
}
|
||||
|
||||
CALL_SUBTEST_6( product_large_regressions<0>() );
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// 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"
|
||||
#include <Eigen/LU>
|
||||
|
||||
@@ -41,12 +40,12 @@ const TC& ref_prod(TC &C, const TA &A, const TB &B)
|
||||
}
|
||||
|
||||
template<typename T, int Rows, int Cols, int Depth, int OC, int OA, int OB>
|
||||
typename internal::enable_if<! ( (Rows ==1&&Depth!=1&&OA==ColMajor)
|
||||
std::enable_if_t<! ( (Rows ==1&&Depth!=1&&OA==ColMajor)
|
||||
|| (Depth==1&&Rows !=1&&OA==RowMajor)
|
||||
|| (Cols ==1&&Depth!=1&&OB==RowMajor)
|
||||
|| (Depth==1&&Cols !=1&&OB==ColMajor)
|
||||
|| (Rows ==1&&Cols !=1&&OC==ColMajor)
|
||||
|| (Cols ==1&&Rows !=1&&OC==RowMajor)),void>::type
|
||||
|| (Cols ==1&&Rows !=1&&OC==RowMajor)),void>
|
||||
test_lazy_single(int rows, int cols, int depth)
|
||||
{
|
||||
Matrix<T,Rows,Depth,OA> A(rows,depth); A.setRandom();
|
||||
@@ -81,12 +80,12 @@ void test_dynamic_bool()
|
||||
}
|
||||
|
||||
template<typename T, int Rows, int Cols, int Depth, int OC, int OA, int OB>
|
||||
typename internal::enable_if< ( (Rows ==1&&Depth!=1&&OA==ColMajor)
|
||||
std::enable_if_t< ( (Rows ==1&&Depth!=1&&OA==ColMajor)
|
||||
|| (Depth==1&&Rows !=1&&OA==RowMajor)
|
||||
|| (Cols ==1&&Depth!=1&&OB==RowMajor)
|
||||
|| (Depth==1&&Cols !=1&&OB==ColMajor)
|
||||
|| (Rows ==1&&Cols !=1&&OC==ColMajor)
|
||||
|| (Cols ==1&&Rows !=1&&OC==RowMajor)),void>::type
|
||||
|| (Cols ==1&&Rows !=1&&OC==RowMajor)),void>
|
||||
test_lazy_single(int, int, int)
|
||||
{
|
||||
}
|
||||
@@ -282,6 +281,25 @@ void product_small_regressions()
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void product_sweep(int max_m, int max_k, int max_n) {
|
||||
using Matrix = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
|
||||
for (int m = 1; m < max_m; ++m) {
|
||||
for (int n = 1; n < max_n; ++n) {
|
||||
Matrix C = Matrix::Zero(m, n);
|
||||
Matrix Cref = Matrix::Zero(m, n);
|
||||
for (int k = 1; k < max_k; ++k) {
|
||||
Matrix A = Matrix::Random(m, k);
|
||||
Matrix B = Matrix::Random(k, n);
|
||||
C = A * B;
|
||||
Cref.setZero();
|
||||
ref_prod(Cref, A, B);
|
||||
VERIFY_IS_APPROX(C, Cref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(product_small)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -291,6 +309,7 @@ EIGEN_DECLARE_TEST(product_small)
|
||||
CALL_SUBTEST_3( product(Matrix3d()) );
|
||||
CALL_SUBTEST_4( product(Matrix4d()) );
|
||||
CALL_SUBTEST_5( product(Matrix4f()) );
|
||||
CALL_SUBTEST_10( product(Matrix<bfloat16, 3, 2>()) );
|
||||
CALL_SUBTEST_6( product1x1<0>() );
|
||||
|
||||
CALL_SUBTEST_11( test_lazy_l1<float>() );
|
||||
@@ -317,6 +336,12 @@ EIGEN_DECLARE_TEST(product_small)
|
||||
CALL_SUBTEST_6( bug_1311<5>() );
|
||||
|
||||
CALL_SUBTEST_9( test_dynamic_bool() );
|
||||
|
||||
// Commonly specialized vectorized types.
|
||||
CALL_SUBTEST_50( product_sweep<float>(10, 10, 10) );
|
||||
CALL_SUBTEST_51( product_sweep<double>(10, 10, 10) );
|
||||
CALL_SUBTEST_52( product_sweep<Eigen::half>(10, 10, 10) );
|
||||
CALL_SUBTEST_53( product_sweep<Eigen::bfloat16>(10, 10, 10) );
|
||||
}
|
||||
|
||||
CALL_SUBTEST_6( product_small_regressions<0>() );
|
||||
|
||||
@@ -141,6 +141,7 @@ EIGEN_DECLARE_TEST(product_syrk)
|
||||
s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2);
|
||||
CALL_SUBTEST_3( syrk(MatrixXcf(s, s)) );
|
||||
CALL_SUBTEST_4( syrk(MatrixXcd(s, s)) );
|
||||
CALL_SUBTEST_5( syrk(Matrix<bfloat16, Dynamic, Dynamic>(s, s)) );
|
||||
TEST_SET_BUT_UNUSED_VARIABLE(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,15 +75,17 @@ template<typename MatrixType> void qr_invertible()
|
||||
// now construct a matrix with prescribed determinant
|
||||
m1.setZero();
|
||||
for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
|
||||
RealScalar absdet = abs(m1.diagonal().prod());
|
||||
Scalar det = m1.diagonal().prod();
|
||||
RealScalar absdet = abs(det);
|
||||
m3 = qr.householderQ(); // get a unitary
|
||||
m1 = m3 * m1 * m3;
|
||||
m1 = m3 * m1 * m3.adjoint();
|
||||
qr.compute(m1);
|
||||
VERIFY_IS_APPROX(log(absdet), qr.logAbsDeterminant());
|
||||
// This test is tricky if the determinant becomes too small.
|
||||
// Since we generate random numbers with magnitude range [0,1], the average determinant is 0.5^size
|
||||
VERIFY_IS_MUCH_SMALLER_THAN( abs(absdet-qr.absDeterminant()), numext::maxi(RealScalar(pow(0.5,size)),numext::maxi<RealScalar>(abs(absdet),abs(qr.absDeterminant()))) );
|
||||
|
||||
RealScalar tol = numext::maxi(RealScalar(pow(0.5,size)), numext::maxi<RealScalar>(abs(absdet), abs(qr.absDeterminant())));
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(abs(det - qr.determinant()), tol);
|
||||
VERIFY_IS_MUCH_SMALLER_THAN(abs(absdet - qr.absDeterminant()), tol);
|
||||
}
|
||||
|
||||
template<typename MatrixType> void qr_verify_assert()
|
||||
@@ -96,6 +98,7 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(qr.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.householderQ())
|
||||
VERIFY_RAISES_ASSERT(qr.determinant())
|
||||
VERIFY_RAISES_ASSERT(qr.absDeterminant())
|
||||
VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void cod() {
|
||||
MatrixType exact_solution = MatrixType::Random(cols, cols2);
|
||||
MatrixType rhs = matrix * exact_solution;
|
||||
MatrixType cod_solution = cod.solve(rhs);
|
||||
JacobiSVD<MatrixType> svd(matrix, ComputeThinU | ComputeThinV);
|
||||
JacobiSVD<MatrixType, ComputeThinU | ComputeThinV> svd(matrix);
|
||||
MatrixType svd_solution = svd.solve(rhs);
|
||||
VERIFY_IS_APPROX(cod_solution, svd_solution);
|
||||
|
||||
@@ -88,7 +88,7 @@ void cod_fixedsize() {
|
||||
exact_solution.setRandom(Cols, Cols2);
|
||||
Matrix<Scalar, Rows, Cols2> rhs = matrix * exact_solution;
|
||||
Matrix<Scalar, Cols, Cols2> cod_solution = cod.solve(rhs);
|
||||
JacobiSVD<MatrixType> svd(matrix, ComputeFullU | ComputeFullV);
|
||||
JacobiSVD<MatrixType, ComputeFullU | ComputeFullV> svd(matrix);
|
||||
Matrix<Scalar, Cols, Cols2> svd_solution = svd.solve(rhs);
|
||||
VERIFY_IS_APPROX(cod_solution, svd_solution);
|
||||
|
||||
@@ -273,10 +273,12 @@ template<typename MatrixType> void qr_invertible()
|
||||
// now construct a matrix with prescribed determinant
|
||||
m1.setZero();
|
||||
for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
|
||||
RealScalar absdet = abs(m1.diagonal().prod());
|
||||
Scalar det = m1.diagonal().prod();
|
||||
RealScalar absdet = abs(det);
|
||||
m3 = qr.householderQ(); // get a unitary
|
||||
m1 = m3 * m1 * m3;
|
||||
m1 = m3 * m1 * m3.adjoint();
|
||||
qr.compute(m1);
|
||||
VERIFY_IS_APPROX(det, qr.determinant());
|
||||
VERIFY_IS_APPROX(absdet, qr.absDeterminant());
|
||||
VERIFY_IS_APPROX(log(absdet), qr.logAbsDeterminant());
|
||||
}
|
||||
@@ -296,6 +298,7 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(qr.isSurjective())
|
||||
VERIFY_RAISES_ASSERT(qr.isInvertible())
|
||||
VERIFY_RAISES_ASSERT(qr.inverse())
|
||||
VERIFY_RAISES_ASSERT(qr.determinant())
|
||||
VERIFY_RAISES_ASSERT(qr.absDeterminant())
|
||||
VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
|
||||
}
|
||||
@@ -315,6 +318,7 @@ template<typename MatrixType> void cod_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(cod.isSurjective())
|
||||
VERIFY_RAISES_ASSERT(cod.isInvertible())
|
||||
VERIFY_RAISES_ASSERT(cod.pseudoInverse())
|
||||
VERIFY_RAISES_ASSERT(cod.determinant())
|
||||
VERIFY_RAISES_ASSERT(cod.absDeterminant())
|
||||
VERIFY_RAISES_ASSERT(cod.logAbsDeterminant())
|
||||
}
|
||||
|
||||
@@ -98,10 +98,12 @@ template<typename MatrixType> void qr_invertible()
|
||||
// now construct a matrix with prescribed determinant
|
||||
m1.setZero();
|
||||
for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
|
||||
RealScalar absdet = abs(m1.diagonal().prod());
|
||||
Scalar det = m1.diagonal().prod();
|
||||
RealScalar absdet = abs(det);
|
||||
m3 = qr.matrixQ(); // get a unitary
|
||||
m1 = m3 * m1 * m3;
|
||||
m1 = m3 * m1 * m3.adjoint();
|
||||
qr.compute(m1);
|
||||
VERIFY_IS_APPROX(det, qr.determinant());
|
||||
VERIFY_IS_APPROX(absdet, qr.absDeterminant());
|
||||
VERIFY_IS_APPROX(log(absdet), qr.logAbsDeterminant());
|
||||
}
|
||||
@@ -121,6 +123,7 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(qr.isSurjective())
|
||||
VERIFY_RAISES_ASSERT(qr.isInvertible())
|
||||
VERIFY_RAISES_ASSERT(qr.inverse())
|
||||
VERIFY_RAISES_ASSERT(qr.determinant())
|
||||
VERIFY_RAISES_ASSERT(qr.absDeterminant())
|
||||
VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
|
||||
}
|
||||
|
||||
@@ -57,14 +57,15 @@ template<typename Scalar> void check_histogram(Scalar x, Scalar y, int bins)
|
||||
EIGEN_DECLARE_TEST(rand)
|
||||
{
|
||||
long long_ref = NumTraits<long>::highest()/10;
|
||||
signed char char_offset = (std::min)(g_repeat,64);
|
||||
signed char short_offset = (std::min)(g_repeat,16000);
|
||||
// the minimum guarantees that these conversions are safe
|
||||
auto char_offset = static_cast<signed char>((std::min)(g_repeat, 64));
|
||||
auto short_offset = static_cast<signed short>((std::min)(g_repeat, 8000));
|
||||
|
||||
for(int i = 0; i < g_repeat*10000; i++) {
|
||||
CALL_SUBTEST(check_in_range<float>(10,11));
|
||||
CALL_SUBTEST(check_in_range<float>(1.24234523,1.24234523));
|
||||
CALL_SUBTEST(check_in_range<float>(1.24234523f,1.24234523f));
|
||||
CALL_SUBTEST(check_in_range<float>(-1,1));
|
||||
CALL_SUBTEST(check_in_range<float>(-1432.2352,-1432.2352));
|
||||
CALL_SUBTEST(check_in_range<float>(-1432.2352f,-1432.2352f));
|
||||
|
||||
CALL_SUBTEST(check_in_range<double>(10,11));
|
||||
CALL_SUBTEST(check_in_range<double>(1.24234523,1.24234523));
|
||||
|
||||
136
libs/eigen/test/random_matrix.cpp
Normal file
136
libs/eigen/test/random_matrix.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 Kolja Brix <kolja.brix@rwth-aachen.de>
|
||||
//
|
||||
// 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 check_generateRandomUnitaryMatrix(const Index dim)
|
||||
{
|
||||
const MatrixType Q = generateRandomUnitaryMatrix<MatrixType>(dim);
|
||||
|
||||
// validate dimensions
|
||||
VERIFY_IS_EQUAL(Q.rows(), dim);
|
||||
VERIFY_IS_EQUAL(Q.cols(), dim);
|
||||
|
||||
VERIFY_IS_UNITARY(Q);
|
||||
}
|
||||
|
||||
template<typename VectorType, typename RealScalarType>
|
||||
void check_setupRandomSvs(const Index dim, const RealScalarType max)
|
||||
{
|
||||
const VectorType v = setupRandomSvs<VectorType, RealScalarType>(dim, max);
|
||||
|
||||
// validate dimensions
|
||||
VERIFY_IS_EQUAL(v.size(), dim);
|
||||
|
||||
// check entries
|
||||
for(Index i = 0; i < v.size(); ++i)
|
||||
VERIFY_GE(v(i), 0);
|
||||
for(Index i = 0; i < v.size()-1; ++i)
|
||||
VERIFY_GE(v(i), v(i+1));
|
||||
}
|
||||
|
||||
template<typename VectorType, typename RealScalarType>
|
||||
void check_setupRangeSvs(const Index dim, const RealScalarType min, const RealScalarType max)
|
||||
{
|
||||
const VectorType v = setupRangeSvs<VectorType, RealScalarType>(dim, min, max);
|
||||
|
||||
// validate dimensions
|
||||
VERIFY_IS_EQUAL(v.size(), dim);
|
||||
|
||||
// check entries
|
||||
if(dim == 1) {
|
||||
VERIFY_IS_APPROX(v(0), min);
|
||||
} else {
|
||||
VERIFY_IS_APPROX(v(0), max);
|
||||
VERIFY_IS_APPROX(v(dim-1), min);
|
||||
}
|
||||
for(Index i = 0; i < v.size()-1; ++i)
|
||||
VERIFY_GE(v(i), v(i+1));
|
||||
}
|
||||
|
||||
template<typename MatrixType, typename RealScalar, typename RealVectorType>
|
||||
void check_generateRandomMatrixSvs(const Index rows, const Index cols, const Index diag_size,
|
||||
const RealScalar min_svs, const RealScalar max_svs)
|
||||
{
|
||||
RealVectorType svs = setupRangeSvs<RealVectorType, RealScalar>(diag_size, min_svs, max_svs);
|
||||
|
||||
MatrixType M;
|
||||
generateRandomMatrixSvs(svs, rows, cols, M);
|
||||
|
||||
// validate dimensions
|
||||
VERIFY_IS_EQUAL(M.rows(), rows);
|
||||
VERIFY_IS_EQUAL(M.cols(), cols);
|
||||
VERIFY_IS_EQUAL(svs.size(), diag_size);
|
||||
|
||||
// validate singular values
|
||||
Eigen::JacobiSVD<MatrixType> SVD(M);
|
||||
VERIFY_IS_APPROX(svs, SVD.singularValues());
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void check_random_matrix(const MatrixType &m)
|
||||
{
|
||||
enum {
|
||||
Rows = MatrixType::RowsAtCompileTime,
|
||||
Cols = MatrixType::ColsAtCompileTime,
|
||||
DiagSize = internal::min_size_prefer_dynamic(Rows, Cols)
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<RealScalar, DiagSize, 1> RealVectorType;
|
||||
|
||||
const Index rows = m.rows(), cols = m.cols();
|
||||
const Index diag_size = (std::min)(rows, cols);
|
||||
const RealScalar min_svs = 1.0, max_svs = 1000.0;
|
||||
|
||||
// check generation of unitary random matrices
|
||||
typedef Matrix<Scalar, Rows, Rows> MatrixAType;
|
||||
typedef Matrix<Scalar, Cols, Cols> MatrixBType;
|
||||
check_generateRandomUnitaryMatrix<MatrixAType>(rows);
|
||||
check_generateRandomUnitaryMatrix<MatrixBType>(cols);
|
||||
|
||||
// test generators for singular values
|
||||
check_setupRandomSvs<RealVectorType, RealScalar>(diag_size, max_svs);
|
||||
check_setupRangeSvs<RealVectorType, RealScalar>(diag_size, min_svs, max_svs);
|
||||
|
||||
// check generation of random matrices
|
||||
check_generateRandomMatrixSvs<MatrixType, RealScalar, RealVectorType>(rows, cols, diag_size, min_svs, max_svs);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(random_matrix)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1(check_random_matrix(Matrix<float, 1, 1>()));
|
||||
CALL_SUBTEST_2(check_random_matrix(Matrix<float, 4, 4>()));
|
||||
CALL_SUBTEST_3(check_random_matrix(Matrix<float, 2, 3>()));
|
||||
CALL_SUBTEST_4(check_random_matrix(Matrix<float, 7, 4>()));
|
||||
|
||||
CALL_SUBTEST_5(check_random_matrix(Matrix<double, 1, 1>()));
|
||||
CALL_SUBTEST_6(check_random_matrix(Matrix<double, 6, 6>()));
|
||||
CALL_SUBTEST_7(check_random_matrix(Matrix<double, 5, 3>()));
|
||||
CALL_SUBTEST_8(check_random_matrix(Matrix<double, 4, 9>()));
|
||||
|
||||
CALL_SUBTEST_9(check_random_matrix(Matrix<std::complex<float>, 12, 12>()));
|
||||
CALL_SUBTEST_10(check_random_matrix(Matrix<std::complex<float>, 7, 14>()));
|
||||
CALL_SUBTEST_11(check_random_matrix(Matrix<std::complex<double>, 15, 11>()));
|
||||
CALL_SUBTEST_12(check_random_matrix(Matrix<std::complex<double>, 6, 9>()));
|
||||
|
||||
CALL_SUBTEST_13(check_random_matrix(
|
||||
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_14(check_random_matrix(
|
||||
MatrixXd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_15(check_random_matrix(
|
||||
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_16(check_random_matrix(
|
||||
MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
|
||||
}
|
||||
}
|
||||
256
libs/eigen/test/random_matrix_helper.h
Normal file
256
libs/eigen/test/random_matrix_helper.h
Normal file
@@ -0,0 +1,256 @@
|
||||
// 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>
|
||||
// Copyright (C) 2021 Kolja Brix <kolja.brix@rwth-aachen.de>
|
||||
//
|
||||
// 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_RANDOM_MATRIX_HELPER
|
||||
#define EIGEN_RANDOM_MATRIX_HELPER
|
||||
|
||||
#include <typeinfo>
|
||||
#include <Eigen/QR> // required for createRandomPIMatrixOfRank and generateRandomMatrixSvs
|
||||
|
||||
|
||||
// Forward declarations to avoid ICC warnings
|
||||
#if EIGEN_COMP_ICC
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template<typename MatrixType>
|
||||
void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m);
|
||||
|
||||
template<typename PermutationVectorType>
|
||||
void randomPermutationVector(PermutationVectorType& v, Index size);
|
||||
|
||||
template<typename MatrixType>
|
||||
MatrixType generateRandomUnitaryMatrix(const Index dim);
|
||||
|
||||
template<typename MatrixType, typename RealScalarVectorType>
|
||||
void generateRandomMatrixSvs(const RealScalarVectorType &svs, const Index rows, const Index cols, MatrixType& M);
|
||||
|
||||
template<typename VectorType, typename RealScalar>
|
||||
VectorType setupRandomSvs(const Index dim, const RealScalar max);
|
||||
|
||||
template<typename VectorType, typename RealScalar>
|
||||
VectorType setupRangeSvs(const Index dim, const RealScalar min, const RealScalar max);
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_COMP_ICC
|
||||
|
||||
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @tparam MatrixType type of random partial isometry matrix
|
||||
* @param desired_rank rank requested for the random partial isometry matrix
|
||||
* @param rows row dimension of requested random partial isometry matrix
|
||||
* @param cols column dimension of requested random partial isometry matrix
|
||||
* @param m random partial isometry matrix
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m)
|
||||
{
|
||||
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 remain
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random permutation vector.
|
||||
*
|
||||
* @tparam PermutationVectorType type of vector used to store permutation
|
||||
* @param v permutation vector
|
||||
* @param size length of permutation vector
|
||||
*/
|
||||
template<typename PermutationVectorType>
|
||||
void randomPermutationVector(PermutationVectorType& v, Index size)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random unitary matrix of prescribed dimension.
|
||||
*
|
||||
* The algorithm is using a random Householder sequence to produce
|
||||
* a random unitary matrix.
|
||||
*
|
||||
* @tparam MatrixType type of matrix to generate
|
||||
* @param dim row and column dimension of the requested square matrix
|
||||
* @return random unitary matrix
|
||||
*/
|
||||
template<typename MatrixType>
|
||||
MatrixType generateRandomUnitaryMatrix(const Index dim)
|
||||
{
|
||||
typedef typename internal::traits<MatrixType>::Scalar Scalar;
|
||||
typedef Matrix<Scalar, Dynamic, 1> VectorType;
|
||||
|
||||
MatrixType v = MatrixType::Identity(dim, dim);
|
||||
VectorType h = VectorType::Zero(dim);
|
||||
for (Index i = 0; i < dim; ++i)
|
||||
{
|
||||
v.col(i).tail(dim - i - 1) = VectorType::Random(dim - i - 1);
|
||||
h(i) = 2 / v.col(i).tail(dim - i).squaredNorm();
|
||||
}
|
||||
|
||||
const Eigen::HouseholderSequence<MatrixType, VectorType> HSeq(v, h);
|
||||
return MatrixType(HSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generation of random matrix with prescribed singular values.
|
||||
*
|
||||
* We generate random matrices with given singular values by setting up
|
||||
* a singular value decomposition. By choosing the number of zeros as
|
||||
* singular values we can specify the rank of the matrix.
|
||||
* Moreover, we also control its spectral norm, which is the largest
|
||||
* singular value, as well as its condition number with respect to the
|
||||
* l2-norm, which is the quotient of the largest and smallest singular
|
||||
* value.
|
||||
*
|
||||
* Reference: For details on the method see e.g. Section 8.1 (pp. 62 f) in
|
||||
*
|
||||
* C. C. Paige, M. A. Saunders,
|
||||
* LSQR: An algorithm for sparse linear equations and sparse least squares.
|
||||
* ACM Transactions on Mathematical Software 8(1), pp. 43-71, 1982.
|
||||
* https://web.stanford.edu/group/SOL/software/lsqr/lsqr-toms82a.pdf
|
||||
*
|
||||
* and also the LSQR webpage https://web.stanford.edu/group/SOL/software/lsqr/.
|
||||
*
|
||||
* @tparam MatrixType matrix type to generate
|
||||
* @tparam RealScalarVectorType vector type with real entries used for singular values
|
||||
* @param svs vector of desired singular values
|
||||
* @param rows row dimension of requested random matrix
|
||||
* @param cols column dimension of requested random matrix
|
||||
* @param M generated matrix with prescribed singular values
|
||||
*/
|
||||
template<typename MatrixType, typename RealScalarVectorType>
|
||||
void generateRandomMatrixSvs(const RealScalarVectorType &svs, const Index rows, const Index cols, MatrixType& M)
|
||||
{
|
||||
enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
|
||||
typedef typename internal::traits<MatrixType>::Scalar Scalar;
|
||||
typedef Matrix<Scalar, Rows, Rows> MatrixAType;
|
||||
typedef Matrix<Scalar, Cols, Cols> MatrixBType;
|
||||
|
||||
const Index min_dim = (std::min)(rows, cols);
|
||||
|
||||
const MatrixAType U = generateRandomUnitaryMatrix<MatrixAType>(rows);
|
||||
const MatrixBType V = generateRandomUnitaryMatrix<MatrixBType>(cols);
|
||||
|
||||
M = U.block(0, 0, rows, min_dim) * svs.asDiagonal() * V.block(0, 0, cols, min_dim).transpose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a vector of random singular values with prescribed upper limit.
|
||||
* For use with generateRandomMatrixSvs().
|
||||
*
|
||||
* Singular values are non-negative real values. By convention (to be consistent with
|
||||
* singular value decomposition) we sort them in decreasing order.
|
||||
*
|
||||
* This strategy produces random singular values in the range [0, max], in particular
|
||||
* the singular values can be zero or arbitrarily close to zero.
|
||||
*
|
||||
* @tparam VectorType vector type with real entries used for singular values
|
||||
* @tparam RealScalar data type used for real entry
|
||||
* @param dim number of singular values to generate
|
||||
* @param max upper bound for singular values
|
||||
* @return vector of singular values
|
||||
*/
|
||||
template<typename VectorType, typename RealScalar>
|
||||
VectorType setupRandomSvs(const Index dim, const RealScalar max)
|
||||
{
|
||||
VectorType svs = max / RealScalar(2) * (VectorType::Random(dim) + VectorType::Ones(dim));
|
||||
std::sort(svs.begin(), svs.end(), std::greater<RealScalar>());
|
||||
return svs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a vector of random singular values with prescribed range.
|
||||
* For use with generateRandomMatrixSvs().
|
||||
*
|
||||
* Singular values are non-negative real values. By convention (to be consistent with
|
||||
* singular value decomposition) we sort them in decreasing order.
|
||||
*
|
||||
* For dim > 1 this strategy generates a vector with largest entry max, smallest entry
|
||||
* min, and remaining entries in the range [min, max]. For dim == 1 the only entry is
|
||||
* min.
|
||||
*
|
||||
* @tparam VectorType vector type with real entries used for singular values
|
||||
* @tparam RealScalar data type used for real entry
|
||||
* @param dim number of singular values to generate
|
||||
* @param min smallest singular value to use
|
||||
* @param max largest singular value to use
|
||||
* @return vector of singular values
|
||||
*/
|
||||
template<typename VectorType, typename RealScalar>
|
||||
VectorType setupRangeSvs(const Index dim, const RealScalar min, const RealScalar max)
|
||||
{
|
||||
VectorType svs = VectorType::Random(dim);
|
||||
if(dim == 0)
|
||||
return svs;
|
||||
if(dim == 1)
|
||||
{
|
||||
svs(0) = min;
|
||||
return svs;
|
||||
}
|
||||
std::sort(svs.begin(), svs.end(), std::greater<RealScalar>());
|
||||
|
||||
// scale to range [min, max]
|
||||
const RealScalar c_min = svs(dim - 1), c_max = svs(0);
|
||||
svs = (svs - VectorType::Constant(dim, c_min)) / (c_max - c_min);
|
||||
return min * (VectorType::Ones(dim) - svs) + max * svs;
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_RANDOM_MATRIX_HELPER
|
||||
@@ -23,11 +23,11 @@ struct random_without_cast_overflow {
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
|
||||
!NumTraits<TgtScalar>::IsSigned &&
|
||||
(std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
|
||||
(std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
|
||||
NumTraits<SrcScalar>::IsSigned))>::type> {
|
||||
std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
|
||||
!NumTraits<TgtScalar>::IsSigned &&
|
||||
(std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
|
||||
(std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
|
||||
NumTraits<SrcScalar>::IsSigned))>> {
|
||||
static SrcScalar value() {
|
||||
SrcScalar a = internal::random<SrcScalar>();
|
||||
return a < SrcScalar(0) ? -(a + 1) : a;
|
||||
@@ -38,9 +38,9 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<
|
||||
std::enable_if_t<
|
||||
NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && !NumTraits<SrcScalar>::IsSigned &&
|
||||
(std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
|
||||
(std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>> {
|
||||
static SrcScalar value() {
|
||||
TgtScalar b = internal::random<TgtScalar>();
|
||||
return static_cast<SrcScalar>(b < TgtScalar(0) ? -(b + 1) : b);
|
||||
@@ -51,9 +51,9 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<
|
||||
std::enable_if_t<
|
||||
NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && NumTraits<SrcScalar>::IsSigned &&
|
||||
(std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
|
||||
(std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>> {
|
||||
static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
|
||||
};
|
||||
|
||||
@@ -61,10 +61,10 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
|
||||
!NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
|
||||
(std::numeric_limits<SrcScalar>::digits ==
|
||||
std::numeric_limits<TgtScalar>::digits)>::type> {
|
||||
std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
|
||||
!NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
|
||||
(std::numeric_limits<SrcScalar>::digits ==
|
||||
std::numeric_limits<TgtScalar>::digits)>> {
|
||||
static SrcScalar value() { return internal::random<SrcScalar>() / 2; }
|
||||
};
|
||||
|
||||
@@ -72,9 +72,9 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<
|
||||
std::enable_if_t<
|
||||
!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
|
||||
(std::numeric_limits<TgtScalar>::digits <= std::numeric_limits<SrcScalar>::digits)>::type> {
|
||||
(std::numeric_limits<TgtScalar>::digits <= std::numeric_limits<SrcScalar>::digits)>> {
|
||||
static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
|
||||
};
|
||||
|
||||
@@ -82,9 +82,9 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<
|
||||
std::enable_if_t<
|
||||
!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
|
||||
(std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>::type> {
|
||||
(std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>> {
|
||||
static SrcScalar value() {
|
||||
// NOTE: internal::random<T>() is limited by RAND_MAX, so random<int64_t> is always within that range.
|
||||
// This prevents us from simply shifting bits, which would result in only 0 or -1.
|
||||
@@ -99,8 +99,8 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && !NumTraits<TgtScalar>::IsInteger &&
|
||||
!NumTraits<TgtScalar>::IsComplex>::type> {
|
||||
std::enable_if_t<NumTraits<SrcScalar>::IsInteger && !NumTraits<TgtScalar>::IsInteger &&
|
||||
!NumTraits<TgtScalar>::IsComplex>> {
|
||||
static SrcScalar value() {
|
||||
return static_cast<SrcScalar>(random_without_cast_overflow<TgtScalar, SrcScalar>::value());
|
||||
}
|
||||
@@ -110,10 +110,10 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
|
||||
!NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsComplex &&
|
||||
(std::numeric_limits<SrcScalar>::digits >
|
||||
std::numeric_limits<TgtScalar>::digits)>::type> {
|
||||
std::enable_if_t<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
|
||||
!NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsComplex &&
|
||||
(std::numeric_limits<SrcScalar>::digits >
|
||||
std::numeric_limits<TgtScalar>::digits)>> {
|
||||
static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
|
||||
};
|
||||
|
||||
@@ -121,7 +121,7 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && !NumTraits<TgtScalar>::IsComplex>::type> {
|
||||
std::enable_if_t<NumTraits<SrcScalar>::IsComplex && !NumTraits<TgtScalar>::IsComplex>> {
|
||||
typedef typename NumTraits<SrcScalar>::Real SrcReal;
|
||||
static SrcScalar value() { return SrcScalar(random_without_cast_overflow<SrcReal, TgtScalar>::value(), 0); }
|
||||
};
|
||||
@@ -130,7 +130,7 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<!NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
|
||||
std::enable_if_t<!NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>> {
|
||||
typedef typename NumTraits<TgtScalar>::Real TgtReal;
|
||||
static SrcScalar value() { return random_without_cast_overflow<SrcScalar, TgtReal>::value(); }
|
||||
};
|
||||
@@ -139,7 +139,7 @@ struct random_without_cast_overflow<
|
||||
template <typename SrcScalar, typename TgtScalar>
|
||||
struct random_without_cast_overflow<
|
||||
SrcScalar, TgtScalar,
|
||||
typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
|
||||
std::enable_if_t<NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>> {
|
||||
typedef typename NumTraits<SrcScalar>::Real SrcReal;
|
||||
typedef typename NumTraits<TgtScalar>::Real TgtReal;
|
||||
static SrcScalar value() {
|
||||
|
||||
@@ -18,7 +18,6 @@ template<typename MatrixType> void real_qz(const MatrixType& m)
|
||||
RealQZ.h
|
||||
*/
|
||||
using std::abs;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
|
||||
Index dim = m.cols();
|
||||
|
||||
@@ -52,17 +51,18 @@ template<typename MatrixType> void real_qz(const MatrixType& m)
|
||||
bool all_zeros = true;
|
||||
for (Index i=0; i<A.cols(); i++)
|
||||
for (Index j=0; j<i; j++) {
|
||||
if (abs(qz.matrixT()(i,j))!=Scalar(0.0))
|
||||
if (!numext::is_exactly_zero(abs(qz.matrixT()(i, j))))
|
||||
{
|
||||
std::cerr << "Error: T(" << i << "," << j << ") = " << qz.matrixT()(i,j) << std::endl;
|
||||
all_zeros = false;
|
||||
}
|
||||
if (j<i-1 && abs(qz.matrixS()(i,j))!=Scalar(0.0))
|
||||
if (j<i-1 && !numext::is_exactly_zero(abs(qz.matrixS()(i, j))))
|
||||
{
|
||||
std::cerr << "Error: S(" << i << "," << j << ") = " << qz.matrixS()(i,j) << std::endl;
|
||||
all_zeros = false;
|
||||
}
|
||||
if (j==i-1 && j>0 && abs(qz.matrixS()(i,j))!=Scalar(0.0) && abs(qz.matrixS()(i-1,j-1))!=Scalar(0.0))
|
||||
if (j==i-1 && j>0 && !numext::is_exactly_zero(abs(qz.matrixS()(i, j))) &&
|
||||
!numext::is_exactly_zero(abs(qz.matrixS()(i - 1, j - 1))))
|
||||
{
|
||||
std::cerr << "Error: S(" << i << "," << j << ") = " << qz.matrixS()(i,j) << " && S(" << i-1 << "," << j-1 << ") = " << qz.matrixS()(i-1,j-1) << std::endl;
|
||||
all_zeros = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 20013 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2013 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
|
||||
@@ -21,7 +21,7 @@
|
||||
// Deal with i387 extended precision
|
||||
#if EIGEN_ARCH_i386 && !(EIGEN_ARCH_x86_64)
|
||||
|
||||
#if EIGEN_COMP_GNUC_STRICT && EIGEN_GNUC_AT_LEAST(4,4)
|
||||
#if EIGEN_COMP_GNUC_STRICT
|
||||
#pragma GCC optimize ("-ffloat-store")
|
||||
#else
|
||||
#undef VERIFY_IS_EQUAL
|
||||
@@ -106,9 +106,6 @@ template<typename VectorType> void ref_vector(const VectorType& m)
|
||||
{ RefMat rm0 = v1.block(0,0,size,1); VERIFY_IS_EQUAL(rm0, v1); }
|
||||
{ RefDynMat rv1 = v1; VERIFY_IS_EQUAL(rv1, v1); }
|
||||
{ RefDynMat rv1 = v1.block(0,0,size,1); VERIFY_IS_EQUAL(rv1, v1); }
|
||||
{ VERIFY_RAISES_ASSERT( RefMat rm0 = v1.block(0, 0, size, 0); EIGEN_UNUSED_VARIABLE(rm0); ); }
|
||||
if(VectorType::SizeAtCompileTime!=1)
|
||||
{ VERIFY_RAISES_ASSERT( RefDynMat rv1 = v1.block(0, 0, size, 0); EIGEN_UNUSED_VARIABLE(rv1); ); }
|
||||
|
||||
RefDynMat rv2 = v1.segment(i,bsize);
|
||||
VERIFY_IS_EQUAL(rv2, v1.segment(i,bsize));
|
||||
@@ -207,7 +204,7 @@ void ref_vector_fixed_sizes()
|
||||
template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
|
||||
{
|
||||
// verify that ref-to-const don't have LvalueBit
|
||||
typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
|
||||
typedef std::add_const_t<PlainObjectType> ConstPlainObjectType;
|
||||
VERIFY( !(internal::traits<Ref<ConstPlainObjectType> >::Flags & LvalueBit) );
|
||||
VERIFY( !(internal::traits<Ref<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
|
||||
VERIFY( !(Ref<ConstPlainObjectType>::Flags & LvalueBit) );
|
||||
@@ -320,17 +317,6 @@ void test_ref_overloads()
|
||||
test_ref_ambiguous(A, B);
|
||||
}
|
||||
|
||||
void test_ref_fixed_size_assert()
|
||||
{
|
||||
Vector4f v4 = Vector4f::Random();
|
||||
VectorXf vx = VectorXf::Random(10);
|
||||
VERIFY_RAISES_STATIC_ASSERT( Ref<Vector3f> y = v4; (void)y; );
|
||||
VERIFY_RAISES_STATIC_ASSERT( Ref<Vector3f> y = vx.head<4>(); (void)y; );
|
||||
VERIFY_RAISES_STATIC_ASSERT( Ref<const Vector3f> y = v4; (void)y; );
|
||||
VERIFY_RAISES_STATIC_ASSERT( Ref<const Vector3f> y = vx.head<4>(); (void)y; );
|
||||
VERIFY_RAISES_STATIC_ASSERT( Ref<const Vector3f> y = 2*v4; (void)y; );
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(ref)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -356,5 +342,4 @@ EIGEN_DECLARE_TEST(ref)
|
||||
}
|
||||
|
||||
CALL_SUBTEST_7( test_ref_overloads() );
|
||||
CALL_SUBTEST_7( test_ref_fixed_size_assert() );
|
||||
}
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::all;
|
||||
|
||||
template<typename T1,typename T2>
|
||||
typename internal::enable_if<internal::is_same<T1,T2>::value,bool>::type
|
||||
std::enable_if_t<internal::is_same<T1,T2>::value,bool>
|
||||
is_same_eq(const T1& a, const T2& b)
|
||||
{
|
||||
return (a.array() == b.array()).all();
|
||||
@@ -193,6 +196,24 @@ void reshape4x4(MatType m)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BlockType>
|
||||
void reshape_block(const BlockType& M) {
|
||||
auto dense = M.eval();
|
||||
Index rows = M.size() / 2;
|
||||
Index cols = M.size() / rows;
|
||||
VERIFY_IS_EQUAL(dense.reshaped(rows, cols), M.reshaped(rows, cols));
|
||||
|
||||
for (Index i=0; i<rows; ++i) {
|
||||
VERIFY_IS_EQUAL(dense.reshaped(rows, cols).row(i),
|
||||
M.reshaped(rows, cols).row(i));
|
||||
}
|
||||
|
||||
for (Index j = 0; j<cols; ++j) {
|
||||
VERIFY_IS_EQUAL(dense.reshaped(rows, cols).col(j),
|
||||
M.reshaped(rows, cols).col(j));
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(reshape)
|
||||
{
|
||||
typedef Matrix<int,Dynamic,Dynamic,RowMajor> RowMatrixXi;
|
||||
@@ -213,4 +234,5 @@ EIGEN_DECLARE_TEST(reshape)
|
||||
|
||||
CALL_SUBTEST(reshape4x4(rmx));
|
||||
CALL_SUBTEST(reshape4x4(rm4));
|
||||
CALL_SUBTEST(reshape_block(rm4.col(1)));
|
||||
}
|
||||
|
||||
@@ -10,16 +10,13 @@
|
||||
#define EIGEN_RUNTIME_NO_MALLOC
|
||||
|
||||
#include "main.h"
|
||||
#if EIGEN_HAS_CXX11
|
||||
#include "MovableScalar.h"
|
||||
#endif
|
||||
#include "SafeScalar.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
using internal::UIntPtr;
|
||||
|
||||
#if EIGEN_HAS_RVALUE_REFERENCES
|
||||
template <typename MatrixType>
|
||||
void rvalue_copyassign(const MatrixType& m)
|
||||
{
|
||||
@@ -114,14 +111,6 @@ void rvalue_move(const MatrixType& m)
|
||||
g_dst = std::move(g_src);
|
||||
VERIFY_IS_EQUAL(g_dst, m);
|
||||
}
|
||||
#else
|
||||
template <typename MatrixType>
|
||||
void rvalue_copyassign(const MatrixType&) {}
|
||||
template<typename TranspositionsType>
|
||||
void rvalue_transpositions(Index) {}
|
||||
template <typename MatrixType>
|
||||
void rvalue_move(const MatrixType&) {}
|
||||
#endif
|
||||
|
||||
EIGEN_DECLARE_TEST(rvalue_types)
|
||||
{
|
||||
@@ -148,10 +137,8 @@ EIGEN_DECLARE_TEST(rvalue_types)
|
||||
CALL_SUBTEST_4((rvalue_transpositions<Transpositions<Dynamic, Dynamic, int> >(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_4((rvalue_transpositions<Transpositions<Dynamic, Dynamic, Index> >(internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
CALL_SUBTEST_5(rvalue_move(Eigen::Matrix<MovableScalar<float>,1,3>::Random().eval()));
|
||||
CALL_SUBTEST_5(rvalue_move(Eigen::Matrix<SafeScalar<float>,1,3>::Random().eval()));
|
||||
CALL_SUBTEST_5(rvalue_move(Eigen::Matrix<SafeScalar<float>,Eigen::Dynamic,Eigen::Dynamic>::Random(1,3).eval()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTim
|
||||
VERIFY_IS_EQUAL(cs3.matrixT(), cs1.matrixT());
|
||||
VERIFY_IS_EQUAL(cs3.matrixU(), cs1.matrixU());
|
||||
cs3.setMaxIterations(1).compute(A);
|
||||
VERIFY_IS_EQUAL(cs3.info(), size > 1 ? NoConvergence : Success);
|
||||
// The schur decomposition does often converge with a single iteration.
|
||||
// VERIFY_IS_EQUAL(cs3.info(), size > 1 ? NoConvergence : Success);
|
||||
VERIFY_IS_EQUAL(cs3.getMaxIterations(), 1);
|
||||
|
||||
MatrixType Atriangular = A;
|
||||
|
||||
@@ -19,15 +19,15 @@ template<typename MatrixType> void verifyIsQuasiTriangular(const MatrixType& T)
|
||||
// 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));
|
||||
VERIFY_IS_EQUAL(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);
|
||||
if (!numext::is_exactly_zero(T(row, row - 1))) {
|
||||
VERIFY(row == size-1 || numext::is_exactly_zero(T(row + 1, row)));
|
||||
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);
|
||||
|
||||
@@ -45,9 +45,6 @@ template<typename MatrixType> void selfadjoint(const MatrixType& m)
|
||||
m4 = m2;
|
||||
m4 -= m1.template selfadjointView<Lower>();
|
||||
VERIFY_IS_APPROX(m4, m2-m3);
|
||||
|
||||
VERIFY_RAISES_STATIC_ASSERT(m2.template selfadjointView<StrictlyUpper>());
|
||||
VERIFY_RAISES_STATIC_ASSERT(m2.template selfadjointView<UnitLower>());
|
||||
}
|
||||
|
||||
void bug_159()
|
||||
|
||||
233
libs/eigen/test/serializer.cpp
Normal file
233
libs/eigen/test/serializer.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 The Eigen Team
|
||||
//
|
||||
// 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/SparseCore>
|
||||
#include <vector>
|
||||
|
||||
template <typename T>
|
||||
struct RandomImpl {
|
||||
static auto Create(Eigen::Index rows, Eigen::Index cols) {
|
||||
return T::Random(rows, cols);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar, int Options, typename DenseIndex>
|
||||
struct RandomImpl<Eigen::SparseMatrix<Scalar, Options, DenseIndex>> {
|
||||
using T = Eigen::SparseMatrix<Scalar, Options, DenseIndex>;
|
||||
|
||||
static auto Create(Eigen::Index rows, Eigen::Index cols) {
|
||||
Eigen::SparseMatrix<Scalar, Options, DenseIndex> M(rows, cols);
|
||||
M.setZero();
|
||||
double density = 0.1;
|
||||
|
||||
// Reserve some space along each inner dim.
|
||||
int nnz = static_cast<int>(std::ceil(density * 1.5 * M.innerSize()));
|
||||
M.reserve(Eigen::VectorXi::Constant(M.outerSize(), nnz));
|
||||
|
||||
for (int j = 0; j < M.outerSize(); j++) {
|
||||
for (int i = 0; i < M.innerSize(); i++) {
|
||||
bool zero = (Eigen::internal::random<double>(0, 1) > density);
|
||||
if (!zero) {
|
||||
M.insertByOuterInner(j, i) = internal::random<Scalar>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 50-50 whether to compress or not.
|
||||
if (Eigen::internal::random<double>(0, 1) >= 0.5) {
|
||||
M.makeCompressed();
|
||||
}
|
||||
|
||||
return M;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar, int Options, typename DenseIndex>
|
||||
struct RandomImpl<Eigen::SparseVector<Scalar, Options, DenseIndex>> {
|
||||
using T = Eigen::SparseVector<Scalar, Options, DenseIndex>;
|
||||
|
||||
static auto Create(Eigen::Index rows, Eigen::Index cols) {
|
||||
Eigen::SparseVector<Scalar, Options, DenseIndex> M(rows, cols);
|
||||
M.setZero();
|
||||
double density = 0.1;
|
||||
|
||||
// Reserve some space along each inner dim.
|
||||
int nnz = static_cast<int>(density * 1.5 * M.innerSize());
|
||||
M.reserve(nnz);
|
||||
|
||||
for (int i = 0; i < M.innerSize(); i++) {
|
||||
bool zero = (Eigen::internal::random<double>(0, 1) > density);
|
||||
if (!zero) {
|
||||
M.insert(i) = internal::random<Scalar>();
|
||||
}
|
||||
}
|
||||
|
||||
return M;
|
||||
}
|
||||
};
|
||||
|
||||
struct MyPodType {
|
||||
double x;
|
||||
int y;
|
||||
float z;
|
||||
};
|
||||
|
||||
// Plain-old-data serialization.
|
||||
void test_pod_type() {
|
||||
MyPodType initial = {1.3, 17, 1.9f};
|
||||
MyPodType clone = {-1, -1, -1};
|
||||
|
||||
Eigen::Serializer<MyPodType> serializer;
|
||||
|
||||
// Determine required size.
|
||||
size_t buffer_size = serializer.size(initial);
|
||||
VERIFY_IS_EQUAL(buffer_size, sizeof(MyPodType));
|
||||
|
||||
// Serialize.
|
||||
std::vector<uint8_t> buffer(buffer_size);
|
||||
uint8_t* begin = buffer.data();
|
||||
uint8_t* end = buffer.data() + buffer.size();
|
||||
uint8_t* dest = serializer.serialize(begin, end, initial);
|
||||
VERIFY(dest != nullptr);
|
||||
VERIFY_IS_EQUAL(dest - begin, buffer_size);
|
||||
|
||||
// Deserialize.
|
||||
const uint8_t* src = serializer.deserialize(begin, end, clone);
|
||||
VERIFY(src != nullptr);
|
||||
VERIFY_IS_EQUAL(src - begin, buffer_size);
|
||||
VERIFY_IS_EQUAL(clone.x, initial.x);
|
||||
VERIFY_IS_EQUAL(clone.y, initial.y);
|
||||
VERIFY_IS_EQUAL(clone.z, initial.z);
|
||||
|
||||
// Serialize with bounds checking errors.
|
||||
dest = serializer.serialize(begin, end - 1, initial);
|
||||
VERIFY(dest == nullptr);
|
||||
dest = serializer.serialize(begin, begin, initial);
|
||||
VERIFY(dest == nullptr);
|
||||
dest = serializer.serialize(nullptr, nullptr, initial);
|
||||
VERIFY(dest == nullptr);
|
||||
|
||||
// Deserialize with bounds checking errors.
|
||||
src = serializer.deserialize(begin, end - 1, clone);
|
||||
VERIFY(src == nullptr);
|
||||
src = serializer.deserialize(begin, begin, clone);
|
||||
VERIFY(src == nullptr);
|
||||
src = serializer.deserialize(nullptr, nullptr, clone);
|
||||
VERIFY(src == nullptr);
|
||||
}
|
||||
|
||||
// Matrix, Vector, Array
|
||||
template<typename T>
|
||||
void test_eigen_type(const T& type) {
|
||||
const Index rows = type.rows();
|
||||
const Index cols = type.cols();
|
||||
|
||||
const T initial = RandomImpl<T>::Create(rows, cols);
|
||||
|
||||
// Serialize.
|
||||
Eigen::Serializer<T> serializer;
|
||||
size_t buffer_size = serializer.size(initial);
|
||||
std::vector<uint8_t> buffer(buffer_size);
|
||||
uint8_t* begin = buffer.data();
|
||||
uint8_t* end = buffer.data() + buffer.size();
|
||||
uint8_t* dest = serializer.serialize(begin, end, initial);
|
||||
VERIFY(dest != nullptr);
|
||||
VERIFY_IS_EQUAL(dest - begin, buffer_size);
|
||||
|
||||
// Deserialize.
|
||||
T clone;
|
||||
const uint8_t* src = serializer.deserialize(begin, end, clone);
|
||||
VERIFY(src != nullptr);
|
||||
VERIFY_IS_EQUAL(src - begin, buffer_size);
|
||||
VERIFY_IS_CWISE_EQUAL(clone, initial);
|
||||
|
||||
// Serialize with bounds checking errors.
|
||||
dest = serializer.serialize(begin, end - 1, initial);
|
||||
VERIFY(dest == nullptr);
|
||||
dest = serializer.serialize(begin, begin, initial);
|
||||
VERIFY(dest == nullptr);
|
||||
dest = serializer.serialize(nullptr, nullptr, initial);
|
||||
VERIFY(dest == nullptr);
|
||||
|
||||
// Deserialize with bounds checking errors.
|
||||
src = serializer.deserialize(begin, end - 1, clone);
|
||||
VERIFY(src == nullptr);
|
||||
src = serializer.deserialize(begin, begin, clone);
|
||||
VERIFY(src == nullptr);
|
||||
src = serializer.deserialize(nullptr, nullptr, clone);
|
||||
VERIFY(src == nullptr);
|
||||
}
|
||||
|
||||
// Test a collection of dense types.
|
||||
template<typename T1, typename T2, typename T3>
|
||||
void test_dense_types(const T1& type1, const T2& type2, const T3& type3) {
|
||||
|
||||
// Make random inputs.
|
||||
const T1 x1 = T1::Random(type1.rows(), type1.cols());
|
||||
const T2 x2 = T2::Random(type2.rows(), type2.cols());
|
||||
const T3 x3 = T3::Random(type3.rows(), type3.cols());
|
||||
|
||||
// Allocate buffer and serialize.
|
||||
size_t buffer_size = Eigen::serialize_size(x1, x2, x3);
|
||||
std::vector<uint8_t> buffer(buffer_size);
|
||||
uint8_t* begin = buffer.data();
|
||||
uint8_t* end = buffer.data() + buffer.size();
|
||||
uint8_t* dest = Eigen::serialize(begin, end, x1, x2, x3);
|
||||
VERIFY(dest != nullptr);
|
||||
|
||||
// Clone everything.
|
||||
T1 y1;
|
||||
T2 y2;
|
||||
T3 y3;
|
||||
const uint8_t* src = Eigen::deserialize(begin, end, y1, y2, y3);
|
||||
VERIFY(src != nullptr);
|
||||
|
||||
// Verify they equal.
|
||||
VERIFY_IS_CWISE_EQUAL(y1, x1);
|
||||
VERIFY_IS_CWISE_EQUAL(y2, x2);
|
||||
VERIFY_IS_CWISE_EQUAL(y3, x3);
|
||||
|
||||
// Serialize everything with bounds checking errors.
|
||||
dest = Eigen::serialize(begin, end - 1, y1, y2, y3);
|
||||
VERIFY(dest == nullptr);
|
||||
dest = Eigen::serialize(begin, begin, y1, y2, y3);
|
||||
VERIFY(dest == nullptr);
|
||||
dest = Eigen::serialize(nullptr, nullptr, y1, y2, y3);
|
||||
VERIFY(dest == nullptr);
|
||||
|
||||
// Deserialize everything with bounds checking errors.
|
||||
src = Eigen::deserialize(begin, end - 1, y1, y2, y3);
|
||||
VERIFY(src == nullptr);
|
||||
src = Eigen::deserialize(begin, begin, y1, y2, y3);
|
||||
VERIFY(src == nullptr);
|
||||
src = Eigen::deserialize(nullptr, nullptr, y1, y2, y3);
|
||||
VERIFY(src == nullptr);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(serializer)
|
||||
{
|
||||
CALL_SUBTEST( test_pod_type() );
|
||||
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST( test_eigen_type(Eigen::Array33f()) );
|
||||
CALL_SUBTEST( test_eigen_type(Eigen::ArrayXd(10)) );
|
||||
CALL_SUBTEST( test_eigen_type(Eigen::Vector3f()) );
|
||||
CALL_SUBTEST( test_eigen_type(Eigen::Matrix4d()) );
|
||||
CALL_SUBTEST( test_eigen_type(Eigen::MatrixXd(15, 17)) );
|
||||
CALL_SUBTEST(test_eigen_type(Eigen::SparseMatrix<float>(13, 12)));
|
||||
CALL_SUBTEST(test_eigen_type(Eigen::SparseVector<float>(17)));
|
||||
|
||||
CALL_SUBTEST( test_dense_types( Eigen::Array33f(),
|
||||
Eigen::ArrayXd(10),
|
||||
Eigen::MatrixXd(15, 17)) );
|
||||
}
|
||||
}
|
||||
217
libs/eigen/test/skew_symmetric_matrix3.cpp
Normal file
217
libs/eigen/test/skew_symmetric_matrix3.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// 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>
|
||||
|
||||
namespace {
|
||||
template <typename Scalar>
|
||||
void constructors() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
const Vector v = Vector::Random();
|
||||
// l-value
|
||||
const SkewSymmetricMatrix3<Scalar> s1(v);
|
||||
const Vector& v1 = s1.vector();
|
||||
VERIFY_IS_APPROX(v1, v);
|
||||
VERIFY(s1.cols() == 3);
|
||||
VERIFY(s1.rows() == 3);
|
||||
|
||||
// r-value
|
||||
const SkewSymmetricMatrix3<Scalar> s2(std::move(v));
|
||||
VERIFY_IS_APPROX(v1, s2.vector());
|
||||
VERIFY_IS_APPROX(s1.toDenseMatrix(), s2.toDenseMatrix());
|
||||
|
||||
// from scalars
|
||||
SkewSymmetricMatrix3<Scalar> s4(v1(0), v1(1), v1(2));
|
||||
VERIFY_IS_APPROX(v1, s4.vector());
|
||||
|
||||
// constructors with four vectors do not compile
|
||||
// Matrix<Scalar, 4, 1> vector4 = Matrix<Scalar, 4, 1>::Random();
|
||||
// SkewSymmetricMatrix3<Scalar> s5(vector4);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void assignments() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
typedef Matrix<Scalar, 3, 3> SquareMatrix;
|
||||
|
||||
const Vector v = Vector::Random();
|
||||
|
||||
// assign to square matrix
|
||||
SquareMatrix sq;
|
||||
sq = v.asSkewSymmetric();
|
||||
VERIFY(sq.isSkewSymmetric());
|
||||
|
||||
// assign to skew symmetric matrix
|
||||
SkewSymmetricMatrix3<Scalar> sk;
|
||||
sk = v.asSkewSymmetric();
|
||||
VERIFY_IS_APPROX(v, sk.vector());
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void plusMinus() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
typedef Matrix<Scalar, 3, 3> SquareMatrix;
|
||||
|
||||
const Vector v1 = Vector::Random();
|
||||
const Vector v2 = Vector::Random();
|
||||
|
||||
SquareMatrix sq1;
|
||||
sq1 = v1.asSkewSymmetric();
|
||||
SquareMatrix sq2;
|
||||
sq2 = v2.asSkewSymmetric();
|
||||
|
||||
SkewSymmetricMatrix3<Scalar> sk1;
|
||||
sk1 = v1.asSkewSymmetric();
|
||||
SkewSymmetricMatrix3<Scalar> sk2;
|
||||
sk2 = v2.asSkewSymmetric();
|
||||
|
||||
VERIFY_IS_APPROX((sk1 + sk2).toDenseMatrix(), sq1 + sq2);
|
||||
VERIFY_IS_APPROX((sk1 - sk2).toDenseMatrix(), sq1 - sq2);
|
||||
|
||||
SquareMatrix sq3 = v1.asSkewSymmetric();
|
||||
VERIFY_IS_APPROX( sq3 = v1.asSkewSymmetric() + v2.asSkewSymmetric(), sq1 + sq2);
|
||||
VERIFY_IS_APPROX( sq3 = v1.asSkewSymmetric() - v2.asSkewSymmetric(), sq1 - sq2);
|
||||
VERIFY_IS_APPROX( sq3 = v1.asSkewSymmetric() - 2*v2.asSkewSymmetric() + v1.asSkewSymmetric(), sq1 - 2*sq2 + sq1);
|
||||
|
||||
VERIFY_IS_APPROX((sk1 + sk1).vector(), 2*v1);
|
||||
VERIFY((sk1 - sk1).vector().isZero());
|
||||
VERIFY((sk1 - sk1).toDenseMatrix().isZero());
|
||||
}
|
||||
|
||||
|
||||
template <typename Scalar>
|
||||
void multiplyScale() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
typedef Matrix<Scalar, 3, 3> SquareMatrix;
|
||||
|
||||
const Vector v1 = Vector::Random();
|
||||
SquareMatrix sq1;
|
||||
sq1 = v1.asSkewSymmetric();
|
||||
SkewSymmetricMatrix3<Scalar> sk1;
|
||||
sk1 = v1.asSkewSymmetric();
|
||||
|
||||
const Scalar s1 = internal::random<Scalar>();
|
||||
VERIFY_IS_APPROX(SkewSymmetricMatrix3<Scalar>(sk1*s1).vector(), sk1.vector() * s1);
|
||||
VERIFY_IS_APPROX(SkewSymmetricMatrix3<Scalar>(s1*sk1).vector(), s1 * sk1.vector());
|
||||
VERIFY_IS_APPROX(sq1 * (sk1 * s1), (sq1 * sk1) * s1);
|
||||
|
||||
const Vector v2 = Vector::Random();
|
||||
SquareMatrix sq2;
|
||||
sq2 = v2.asSkewSymmetric();
|
||||
SkewSymmetricMatrix3<Scalar> sk2;
|
||||
sk2 = v2.asSkewSymmetric();
|
||||
VERIFY_IS_APPROX(sk1*sk2, sq1*sq2);
|
||||
|
||||
// null space
|
||||
VERIFY((sk1*v1).isZero());
|
||||
VERIFY((sk2*v2).isZero());
|
||||
}
|
||||
|
||||
template<typename Matrix>
|
||||
void skewSymmetricMultiplication(const Matrix& m) {
|
||||
typedef Eigen::Matrix<typename Matrix::Scalar, 3, 1> Vector;
|
||||
const Vector v = Vector::Random();
|
||||
const Matrix m1 = Matrix::Random(m.rows(), m.cols());
|
||||
const SkewSymmetricMatrix3<typename Matrix::Scalar> sk = v.asSkewSymmetric();
|
||||
VERIFY_IS_APPROX(m1.transpose() * (sk * m1), (m1.transpose() * sk) * m1);
|
||||
VERIFY((m1.transpose() * (sk * m1)).isSkewSymmetric());
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void traceAndDet() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
const Vector v = Vector::Random();
|
||||
// this does not work, values larger than 1.e-08 can be seen
|
||||
//VERIFY_IS_APPROX(sq.determinant(), static_cast<Scalar>(0));
|
||||
VERIFY_IS_APPROX(v.asSkewSymmetric().determinant(), static_cast<Scalar>(0));
|
||||
VERIFY_IS_APPROX(v.asSkewSymmetric().toDenseMatrix().trace(), static_cast<Scalar>(0));
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void transpose() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
const Vector v = Vector::Random();
|
||||
// By definition of a skew symmetric matrix: A^T = -A
|
||||
VERIFY_IS_APPROX(v.asSkewSymmetric().toDenseMatrix().transpose(), v.asSkewSymmetric().transpose().toDenseMatrix());
|
||||
VERIFY_IS_APPROX(v.asSkewSymmetric().transpose().vector(), (-v).asSkewSymmetric().vector());
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void exponentialIdentity() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
const Vector v1 = Vector::Zero();
|
||||
VERIFY(v1.asSkewSymmetric().exponential().isIdentity());
|
||||
|
||||
Vector v2 = Vector::Random();
|
||||
v2.normalize();
|
||||
VERIFY((2*EIGEN_PI*v2).asSkewSymmetric().exponential().isIdentity());
|
||||
|
||||
Vector v3;
|
||||
const auto precision = static_cast<Scalar>(1.1)*NumTraits<Scalar>::dummy_precision();
|
||||
v3 << 0, 0, precision;
|
||||
VERIFY(v3.asSkewSymmetric().exponential().isIdentity(precision));
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void exponentialOrthogonality() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
typedef Matrix<Scalar, 3, 3> SquareMatrix;
|
||||
const Vector v = Vector::Random();
|
||||
SquareMatrix sq = v.asSkewSymmetric().exponential();
|
||||
VERIFY(sq.isUnitary());
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void exponentialRotation() {
|
||||
typedef Matrix<Scalar, 3, 1> Vector;
|
||||
typedef Matrix<Scalar, 3, 3> SquareMatrix;
|
||||
|
||||
// rotation axis is invariant
|
||||
const Vector v1 = Vector::Random();
|
||||
const SquareMatrix r1 = v1.asSkewSymmetric().exponential();
|
||||
VERIFY_IS_APPROX(r1*v1, v1);
|
||||
|
||||
// rotate around z-axis
|
||||
Vector v2;
|
||||
v2 << 0, 0, EIGEN_PI;
|
||||
const SquareMatrix r2 = v2.asSkewSymmetric().exponential();
|
||||
VERIFY_IS_APPROX(r2*(Vector() << 1,0,0).finished(), (Vector() << -1,0,0).finished());
|
||||
VERIFY_IS_APPROX(r2*(Vector() << 0,1,0).finished(), (Vector() << 0,-1,0).finished());
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
EIGEN_DECLARE_TEST(skew_symmetric_matrix3)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1(constructors<float>());
|
||||
CALL_SUBTEST_1(constructors<double>());
|
||||
CALL_SUBTEST_1(assignments<float>());
|
||||
CALL_SUBTEST_1(assignments<double>());
|
||||
|
||||
CALL_SUBTEST_2(plusMinus<float>());
|
||||
CALL_SUBTEST_2(plusMinus<double>());
|
||||
CALL_SUBTEST_2(multiplyScale<float>());
|
||||
CALL_SUBTEST_2(multiplyScale<double>());
|
||||
CALL_SUBTEST_2(skewSymmetricMultiplication(MatrixXf(3,internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_2(skewSymmetricMultiplication(MatrixXd(3,internal::random<int>(1,EIGEN_TEST_MAX_SIZE))));
|
||||
CALL_SUBTEST_2(traceAndDet<float>());
|
||||
CALL_SUBTEST_2(traceAndDet<double>());
|
||||
CALL_SUBTEST_2(transpose<float>());
|
||||
CALL_SUBTEST_2(transpose<double>());
|
||||
|
||||
CALL_SUBTEST_3(exponentialIdentity<float>());
|
||||
CALL_SUBTEST_3(exponentialIdentity<double>());
|
||||
CALL_SUBTEST_3(exponentialOrthogonality<float>());
|
||||
CALL_SUBTEST_3(exponentialOrthogonality<double>());
|
||||
CALL_SUBTEST_3(exponentialRotation<float>());
|
||||
CALL_SUBTEST_3(exponentialRotation<double>());
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
// 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()
|
||||
@@ -33,28 +32,11 @@ template<typename Scalar> void smallVectors()
|
||||
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)))
|
||||
}
|
||||
VERIFY_RAISES_ASSERT(V3(2, 1))
|
||||
VERIFY_RAISES_ASSERT(V3(3, 2))
|
||||
VERIFY_RAISES_ASSERT(V4(1, 3))
|
||||
VERIFY_RAISES_ASSERT(V4(2, 4))
|
||||
VERIFY_RAISES_ASSERT(VX(3, 2))
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(smallvectors)
|
||||
|
||||
@@ -31,6 +31,10 @@ void check_solverbase(const MatrixType& matrix, const SolverType& solver, Index
|
||||
solver_solution2 = RhsType::Random(rows,cols2);
|
||||
solver_solution2 = solver.adjoint().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, matrix.adjoint()*solver_solution2);
|
||||
// test with temporary expression as rhs
|
||||
m2 = DstType::Random(cols,cols2);
|
||||
solver_solution = solver.solve(matrix*m2);
|
||||
VERIFY_IS_APPROX(matrix*m2, matrix*solver_solution);
|
||||
}
|
||||
|
||||
#endif // TEST_SOLVERBASE_H
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
@@ -27,8 +25,6 @@
|
||||
#include <unordered_map>
|
||||
#define EIGEN_UNORDERED_MAP_SUPPORT
|
||||
|
||||
#endif
|
||||
|
||||
#include <Eigen/Cholesky>
|
||||
#include <Eigen/LU>
|
||||
#include <Eigen/Sparse>
|
||||
@@ -58,8 +54,10 @@ initSparse(double density,
|
||||
enum { IsRowMajor = SparseMatrix<Scalar,Opt2,StorageIndex>::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()))));
|
||||
|
||||
int nnz = static_cast<int>((1.5 * density) * static_cast<double>(IsRowMajor ? refMat.cols() : refMat.rows()));
|
||||
sparseMat.reserve(VectorXi::Constant(IsRowMajor ? refMat.rows() : refMat.cols(), nnz));
|
||||
|
||||
Index insert_count = 0;
|
||||
for(Index j=0; j<sparseMat.outerSize(); j++)
|
||||
{
|
||||
//sparseMat.startVec(j);
|
||||
@@ -85,10 +83,11 @@ initSparse(double density,
|
||||
if ((flags&ForceRealDiag) && (i==j))
|
||||
v = numext::real(v);
|
||||
|
||||
if (v!=Scalar(0))
|
||||
if (!numext::is_exactly_zero(v))
|
||||
{
|
||||
//sparseMat.insertBackByOuterInner(j,i) = v;
|
||||
sparseMat.insertByOuterInner(j,i) = v;
|
||||
++insert_count;
|
||||
if (nonzeroCoords)
|
||||
nonzeroCoords->push_back(Matrix<StorageIndex,2,1> (ai,aj));
|
||||
}
|
||||
@@ -97,60 +96,14 @@ initSparse(double density,
|
||||
zeroCoords->push_back(Matrix<StorageIndex,2,1> (ai,aj));
|
||||
}
|
||||
refMat(ai,aj) = v;
|
||||
|
||||
// make sure we only insert as many as the sparse matrix supports
|
||||
if(insert_count == NumTraits<StorageIndex>::highest()) return;
|
||||
}
|
||||
}
|
||||
//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<Matrix<Index,2,1> >* zeroCoords = 0,
|
||||
std::vector<Matrix<Index,2,1> >* 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 = numext::real(v);
|
||||
|
||||
if (v!=Scalar(0))
|
||||
{
|
||||
sparseMat.insertBackByOuterInner(j,i) = v;
|
||||
if (nonzeroCoords)
|
||||
nonzeroCoords->push_back(Matrix<Index,2,1> (ai,aj));
|
||||
}
|
||||
else if (zeroCoords)
|
||||
{
|
||||
zeroCoords->push_back(Matrix<Index,2,1> (ai,aj));
|
||||
}
|
||||
refMat(ai,aj) = v;
|
||||
}
|
||||
}
|
||||
sparseMat.finalize();
|
||||
}
|
||||
|
||||
template<typename Scalar,int Options,typename Index> void
|
||||
initSparse(double density,
|
||||
Matrix<Scalar,Dynamic,1>& refVec,
|
||||
@@ -163,7 +116,7 @@ initSparse(double density,
|
||||
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))
|
||||
if (!numext::is_exactly_zero(v))
|
||||
{
|
||||
sparseVec.insertBack(i) = v;
|
||||
if (nonzeroCoords)
|
||||
|
||||
@@ -28,8 +28,8 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
const Index rows = ref.rows();
|
||||
const Index cols = ref.cols();
|
||||
//const Index inner = ref.innerSize();
|
||||
//const Index outer = ref.outerSize();
|
||||
const Index inner = ref.innerSize();
|
||||
const Index outer = ref.outerSize();
|
||||
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
typedef typename SparseMatrixType::RealScalar RealScalar;
|
||||
@@ -91,8 +91,12 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
for (Index k=0; k<nnz; ++k)
|
||||
{
|
||||
Index i = internal::random<Index>(0,rows-1);
|
||||
if (m1.coeff(i,j)==Scalar(0))
|
||||
m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
|
||||
if (m1.coeff(i, j) == Scalar(0)) {
|
||||
Scalar v = internal::random<Scalar>();
|
||||
if (v == Scalar(0)) v = Scalar(1);
|
||||
m1(i, j) = v;
|
||||
m2.insert(i, j) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,13 +120,18 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
{
|
||||
Index i = internal::random<Index>(0,rows-1);
|
||||
Index j = internal::random<Index>(0,cols-1);
|
||||
if ((m1.coeff(i,j)==Scalar(0)) && (internal::random<int>()%2))
|
||||
m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
|
||||
if ((m1.coeff(i, j) == Scalar(0)) && (internal::random<int>() % 2)) {
|
||||
Scalar v = internal::random<Scalar>();
|
||||
if (v == Scalar(0)) v = Scalar(1);
|
||||
m1(i, j) = v;
|
||||
m2.insert(i, j) = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
Scalar v = internal::random<Scalar>();
|
||||
m2.coeffRef(i,j) += v;
|
||||
m1(i,j) += v;
|
||||
if (v == Scalar(0)) v = Scalar(1);
|
||||
m1(i, j) = v;
|
||||
m2.coeffRef(i, j) = v;
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(m2,m1);
|
||||
@@ -140,8 +149,12 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
{
|
||||
Index i = internal::random<Index>(0,rows-1);
|
||||
Index j = internal::random<Index>(0,cols-1);
|
||||
if (m1.coeff(i,j)==Scalar(0))
|
||||
m2.insert(i,j) = m1(i,j) = internal::random<Scalar>();
|
||||
if (m1.coeff(i, j) == Scalar(0)) {
|
||||
Scalar v = internal::random<Scalar>();
|
||||
if (v == Scalar(0)) v = Scalar(1);
|
||||
m1(i, j) = v;
|
||||
m2.insert(i, j) = v;
|
||||
}
|
||||
if(mode==3)
|
||||
m2.reserve(r);
|
||||
}
|
||||
@@ -150,6 +163,63 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
VERIFY_IS_APPROX(m2,m1);
|
||||
}
|
||||
|
||||
// test sort
|
||||
if (inner > 1) {
|
||||
bool StorageOrdersMatch = DenseMatrix::IsRowMajor == SparseMatrixType::IsRowMajor;
|
||||
DenseMatrix m1(rows, cols);
|
||||
m1.setZero();
|
||||
SparseMatrixType m2(rows, cols);
|
||||
// generate random inner indices with no repeats
|
||||
Vector<Index, Dynamic> innerIndices(inner);
|
||||
innerIndices.setLinSpaced(inner, 0, inner - 1);
|
||||
for (Index j = 0; j < outer; j++) {
|
||||
std::random_shuffle(innerIndices.begin(), innerIndices.end());
|
||||
Index nzj = internal::random<Index>(2, inner / 2);
|
||||
for (Index k = 0; k < nzj; k++) {
|
||||
Index i = innerIndices[k];
|
||||
Scalar val = internal::random<Scalar>();
|
||||
m1.coeffRefByOuterInner(StorageOrdersMatch ? j : i, StorageOrdersMatch ? i : j) = val;
|
||||
m2.insertByOuterInner(j, i) = val;
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY_IS_APPROX(m2, m1);
|
||||
// sort wrt greater
|
||||
m2.template sortInnerIndices<std::greater<>>();
|
||||
// verify that all inner vectors are not sorted wrt less
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::less<>>(), 0);
|
||||
// verify that all inner vectors are sorted wrt greater
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::greater<>>(), m2.outerSize());
|
||||
// verify that sort does not change evaluation
|
||||
VERIFY_IS_APPROX(m2, m1);
|
||||
// sort wrt less
|
||||
m2.template sortInnerIndices<std::less<>>();
|
||||
// verify that all inner vectors are sorted wrt less
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::less<>>(), m2.outerSize());
|
||||
// verify that all inner vectors are not sorted wrt greater
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::greater<>>(), 0);
|
||||
// verify that sort does not change evaluation
|
||||
VERIFY_IS_APPROX(m2, m1);
|
||||
|
||||
m2.makeCompressed();
|
||||
// sort wrt greater
|
||||
m2.template sortInnerIndices<std::greater<>>();
|
||||
// verify that all inner vectors are not sorted wrt less
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::less<>>(), 0);
|
||||
// verify that all inner vectors are sorted wrt greater
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::greater<>>(), m2.outerSize());
|
||||
// verify that sort does not change evaluation
|
||||
VERIFY_IS_APPROX(m2, m1);
|
||||
// sort wrt less
|
||||
m2.template sortInnerIndices<std::less<>>();
|
||||
// verify that all inner vectors are sorted wrt less
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::less<>>(), m2.outerSize());
|
||||
// verify that all inner vectors are not sorted wrt greater
|
||||
VERIFY_IS_EQUAL(m2.template innerIndicesAreSorted<std::greater<>>(), 0);
|
||||
// verify that sort does not change evaluation
|
||||
VERIFY_IS_APPROX(m2, m1);
|
||||
}
|
||||
|
||||
// test basic computations
|
||||
{
|
||||
DenseMatrix refM1 = DenseMatrix::Zero(rows, cols);
|
||||
@@ -413,10 +483,8 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
|
||||
m.setFromTriplets(triplets.begin(), triplets.end(), std::multiplies<Scalar>());
|
||||
VERIFY_IS_APPROX(m, refMat_prod);
|
||||
#if (EIGEN_COMP_CXXVER >= 11)
|
||||
m.setFromTriplets(triplets.begin(), triplets.end(), [] (Scalar,Scalar b) { return b; });
|
||||
VERIFY_IS_APPROX(m, refMat_last);
|
||||
#endif
|
||||
}
|
||||
|
||||
// test Map
|
||||
@@ -431,12 +499,6 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re
|
||||
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
|
||||
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
|
||||
}
|
||||
{
|
||||
MappedSparseMatrix<Scalar,SparseMatrixType::Options,StorageIndex> mapMat2(m2.rows(), m2.cols(), m2.nonZeros(), m2.outerIndexPtr(), m2.innerIndexPtr(), m2.valuePtr(), m2.innerNonZeroPtr());
|
||||
MappedSparseMatrix<Scalar,SparseMatrixType::Options,StorageIndex> mapMat3(m3.rows(), m3.cols(), m3.nonZeros(), m3.outerIndexPtr(), m3.innerIndexPtr(), m3.valuePtr(), m3.innerNonZeroPtr());
|
||||
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
|
||||
VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3);
|
||||
}
|
||||
|
||||
Index i = internal::random<Index>(0,rows-1);
|
||||
Index j = internal::random<Index>(0,cols-1);
|
||||
@@ -687,7 +749,7 @@ void big_sparse_triplet(Index rows, Index cols, double density) {
|
||||
typedef typename SparseMatrixType::Scalar Scalar;
|
||||
typedef Triplet<Scalar,Index> TripletType;
|
||||
std::vector<TripletType> triplets;
|
||||
double nelements = density * rows*cols;
|
||||
double nelements = density * static_cast<double>(rows*cols);
|
||||
VERIFY(nelements>=0 && nelements < static_cast<double>(NumTraits<StorageIndex>::highest()));
|
||||
Index ntriplets = Index(nelements);
|
||||
triplets.reserve(ntriplets);
|
||||
@@ -737,9 +799,12 @@ EIGEN_DECLARE_TEST(sparse_basic)
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(8, 8)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, ColMajor>(r, c)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<std::complex<double>, RowMajor>(r, c)) ));
|
||||
CALL_SUBTEST_1(( sparse_basic(SparseMatrix<double>(r, c)) ));
|
||||
CALL_SUBTEST_5(( sparse_basic(SparseMatrix<double,ColMajor,long int>(r, c)) ));
|
||||
CALL_SUBTEST_5(( sparse_basic(SparseMatrix<double,RowMajor,long int>(r, c)) ));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<float, RowMajor>(r, c))));
|
||||
CALL_SUBTEST_2(( sparse_basic(SparseMatrix<float, ColMajor>(r, c))));
|
||||
CALL_SUBTEST_3(( sparse_basic(SparseMatrix<double, ColMajor>(r, c))));
|
||||
CALL_SUBTEST_3(( sparse_basic(SparseMatrix<double, RowMajor>(r, c))));
|
||||
CALL_SUBTEST_4(( sparse_basic(SparseMatrix<double, ColMajor,long int>(r, c)) ));
|
||||
CALL_SUBTEST_4(( sparse_basic(SparseMatrix<double, RowMajor,long int>(r, c)) ));
|
||||
|
||||
r = Eigen::internal::random<int>(1,100);
|
||||
c = Eigen::internal::random<int>(1,100);
|
||||
@@ -747,14 +812,14 @@ EIGEN_DECLARE_TEST(sparse_basic)
|
||||
r = c; // check square matrices in 25% of tries
|
||||
}
|
||||
|
||||
CALL_SUBTEST_6(( sparse_basic(SparseMatrix<double,ColMajor,short int>(short(r), short(c))) ));
|
||||
CALL_SUBTEST_6(( sparse_basic(SparseMatrix<double,RowMajor,short int>(short(r), short(c))) ));
|
||||
CALL_SUBTEST_5(( sparse_basic(SparseMatrix<double,ColMajor,short int>(short(r), short(c))) ));
|
||||
CALL_SUBTEST_5(( sparse_basic(SparseMatrix<double,RowMajor,short int>(short(r), short(c))) ));
|
||||
}
|
||||
|
||||
// Regression test for bug 900: (manually insert higher values here, if you have enough RAM):
|
||||
CALL_SUBTEST_3((big_sparse_triplet<SparseMatrix<float, RowMajor, int> >(10000, 10000, 0.125)));
|
||||
CALL_SUBTEST_4((big_sparse_triplet<SparseMatrix<double, ColMajor, long int> >(10000, 10000, 0.125)));
|
||||
CALL_SUBTEST_5(( big_sparse_triplet<SparseMatrix<float, RowMajor, int>>(10000, 10000, 0.125)));
|
||||
CALL_SUBTEST_5(( big_sparse_triplet<SparseMatrix<double, ColMajor, long int>>(10000, 10000, 0.125)));
|
||||
|
||||
CALL_SUBTEST_7( bug1105<0>() );
|
||||
CALL_SUBTEST_5(bug1105<0>());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
#include "AnnoyingScalar.h"
|
||||
|
||||
template<typename T>
|
||||
typename Eigen::internal::enable_if<(T::Flags&RowMajorBit)==RowMajorBit, typename T::RowXpr>::type
|
||||
std::enable_if_t<(T::Flags&RowMajorBit)==RowMajorBit, typename T::RowXpr>
|
||||
innervec(T& A, Index i)
|
||||
{
|
||||
return A.row(i);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename Eigen::internal::enable_if<(T::Flags&RowMajorBit)==0, typename T::ColXpr>::type
|
||||
std::enable_if_t<(T::Flags&RowMajorBit)==0, typename T::ColXpr>
|
||||
innervec(T& A, Index i)
|
||||
{
|
||||
return A.col(i);
|
||||
@@ -90,11 +90,11 @@ template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& re
|
||||
|
||||
VERIFY_IS_APPROX(m.middleCols(j,w).coeff(r,c), refMat.middleCols(j,w).coeff(r,c));
|
||||
VERIFY_IS_APPROX(m.middleRows(i,h).coeff(r,c), refMat.middleRows(i,h).coeff(r,c));
|
||||
if(m.middleCols(j,w).coeff(r,c) != Scalar(0))
|
||||
if(!numext::is_exactly_zero(m.middleCols(j, w).coeff(r, c)))
|
||||
{
|
||||
VERIFY_IS_APPROX(m.middleCols(j,w).coeffRef(r,c), refMat.middleCols(j,w).coeff(r,c));
|
||||
}
|
||||
if(m.middleRows(i,h).coeff(r,c) != Scalar(0))
|
||||
if(!numext::is_exactly_zero(m.middleRows(i, h).coeff(r, c)))
|
||||
{
|
||||
VERIFY_IS_APPROX(m.middleRows(i,h).coeff(r,c), refMat.middleRows(i,h).coeff(r,c));
|
||||
}
|
||||
@@ -166,14 +166,14 @@ template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& re
|
||||
{
|
||||
VERIFY(j==numext::real(m3.innerVector(j).nonZeros()));
|
||||
if(j>0)
|
||||
VERIFY(RealScalar(j)==numext::real(m3.innerVector(j).lastCoeff()));
|
||||
VERIFY_IS_EQUAL(RealScalar(j), numext::real(m3.innerVector(j).lastCoeff()));
|
||||
}
|
||||
m3.makeCompressed();
|
||||
for(Index j=0; j<(std::min)(outer, inner); ++j)
|
||||
{
|
||||
VERIFY(j==numext::real(m3.innerVector(j).nonZeros()));
|
||||
if(j>0)
|
||||
VERIFY(RealScalar(j)==numext::real(m3.innerVector(j).lastCoeff()));
|
||||
VERIFY_IS_EQUAL(RealScalar(j), numext::real(m3.innerVector(j).lastCoeff()));
|
||||
}
|
||||
|
||||
VERIFY(m3.innerVector(j0).nonZeros() == m3.transpose().innerVector(j0).nonZeros());
|
||||
@@ -288,6 +288,25 @@ template<typename SparseMatrixType> void sparse_block(const SparseMatrixType& re
|
||||
VERIFY_IS_APPROX(m3, refMat3);
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit inner iterator.
|
||||
{
|
||||
DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols);
|
||||
SparseMatrixType m2(rows, cols);
|
||||
initSparse<Scalar>(density, refMat2, m2);
|
||||
|
||||
Index j0 =internal::random<Index>(0, outer - 1);
|
||||
auto v = innervec(m2, j0);
|
||||
|
||||
typename decltype(v)::InnerIterator block_iterator(v);
|
||||
typename SparseMatrixType::InnerIterator matrix_iterator(m2, j0);
|
||||
while (block_iterator) {
|
||||
VERIFY_IS_EQUAL(block_iterator.index(), matrix_iterator.index());
|
||||
++block_iterator;
|
||||
++matrix_iterator;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(sparse_block)
|
||||
|
||||
@@ -53,7 +53,7 @@ template<int OtherStorage, typename SparseMatrixType> void sparse_permutations(c
|
||||
// bool IsRowMajor1 = SparseMatrixType::IsRowMajor;
|
||||
// bool IsRowMajor2 = OtherSparseMatrixType::IsRowMajor;
|
||||
|
||||
double density = (std::max)(8./(rows*cols), 0.01);
|
||||
double density = (std::max)(8./static_cast<double>(rows*cols), 0.01);
|
||||
|
||||
SparseMatrixType mat(rows, cols), up(rows,cols), lo(rows,cols);
|
||||
OtherSparseMatrixType res;
|
||||
|
||||
@@ -390,7 +390,7 @@ void test_mixing_types()
|
||||
typedef Matrix<Cplx,Dynamic,Dynamic> DenseMatCplx;
|
||||
|
||||
Index n = internal::random<Index>(1,100);
|
||||
double density = (std::max)(8./(n*n), 0.2);
|
||||
double density = (std::max)(8./static_cast<double>(n*n), 0.2);
|
||||
|
||||
SpMatReal sR1(n,n);
|
||||
SpMatCplx sC1(n,n), sC2(n,n), sC3(n,n);
|
||||
@@ -461,6 +461,58 @@ void test_mixing_types()
|
||||
VERIFY_IS_APPROX( dC2 = sC1 * dR1.col(0), dC3 = sC1 * dR1.template cast<Cplx>().col(0) );
|
||||
}
|
||||
|
||||
// Test mixed storage types
|
||||
template<int OrderA, int OrderB, int OrderC>
|
||||
void test_mixed_storage_imp() {
|
||||
typedef float Real;
|
||||
typedef Matrix<Real,Dynamic,Dynamic> DenseMat;
|
||||
|
||||
// Case: Large inputs but small result
|
||||
{
|
||||
SparseMatrix<Real, OrderA> A(8, 512);
|
||||
SparseMatrix<Real, OrderB> B(512, 8);
|
||||
DenseMat refA(8, 512);
|
||||
DenseMat refB(512, 8);
|
||||
|
||||
initSparse<Real>(0.1, refA, A);
|
||||
initSparse<Real>(0.1, refB, B);
|
||||
|
||||
SparseMatrix<Real, OrderC, std::int8_t> result;
|
||||
SparseMatrix<Real, OrderC> result_large;
|
||||
DenseMat refResult;
|
||||
|
||||
VERIFY_IS_APPROX( result = (A * B), refResult = refA * refB );
|
||||
}
|
||||
|
||||
// Case: Small input but large result
|
||||
{
|
||||
SparseMatrix<Real, OrderA, std::int8_t> A(127, 8);
|
||||
SparseMatrix<Real, OrderB, std::int8_t> B(8, 127);
|
||||
DenseMat refA(127, 8);
|
||||
DenseMat refB(8, 127);
|
||||
|
||||
initSparse<Real>(0.01, refA, A);
|
||||
initSparse<Real>(0.01, refB, B);
|
||||
|
||||
SparseMatrix<Real, OrderC> result;
|
||||
SparseMatrix<Real, OrderC> result_large;
|
||||
DenseMat refResult;
|
||||
|
||||
VERIFY_IS_APPROX( result = (A * B), refResult = refA * refB );
|
||||
}
|
||||
}
|
||||
|
||||
void test_mixed_storage() {
|
||||
test_mixed_storage_imp<RowMajor, RowMajor, RowMajor>();
|
||||
test_mixed_storage_imp<RowMajor, RowMajor, ColMajor>();
|
||||
test_mixed_storage_imp<RowMajor, ColMajor, RowMajor>();
|
||||
test_mixed_storage_imp<RowMajor, ColMajor, ColMajor>();
|
||||
test_mixed_storage_imp<ColMajor, RowMajor, RowMajor>();
|
||||
test_mixed_storage_imp<ColMajor, RowMajor, ColMajor>();
|
||||
test_mixed_storage_imp<ColMajor, ColMajor, RowMajor>();
|
||||
test_mixed_storage_imp<ColMajor, ColMajor, ColMajor>();
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(sparse_product)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -473,5 +525,6 @@ EIGEN_DECLARE_TEST(sparse_product)
|
||||
CALL_SUBTEST_4( (sparse_product_regression_test<SparseMatrix<double,RowMajor>, Matrix<double, Dynamic, Dynamic, RowMajor> >()) );
|
||||
|
||||
CALL_SUBTEST_5( (test_mixing_types<float>()) );
|
||||
CALL_SUBTEST_5( (test_mixed_storage()) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 20015 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2015 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
|
||||
@@ -34,7 +34,7 @@ inline void on_temporary_creation() {
|
||||
template<typename PlainObjectType> void check_const_correctness(const PlainObjectType&)
|
||||
{
|
||||
// verify that ref-to-const don't have LvalueBit
|
||||
typedef typename internal::add_const<PlainObjectType>::type ConstPlainObjectType;
|
||||
typedef std::add_const_t<PlainObjectType> ConstPlainObjectType;
|
||||
VERIFY( !(internal::traits<Ref<ConstPlainObjectType> >::Flags & LvalueBit) );
|
||||
VERIFY( !(internal::traits<Ref<ConstPlainObjectType, Aligned> >::Flags & LvalueBit) );
|
||||
VERIFY( !(Ref<ConstPlainObjectType>::Flags & LvalueBit) );
|
||||
|
||||
@@ -88,7 +88,7 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
|
||||
|
||||
x.setZero();
|
||||
// test with Map
|
||||
MappedSparseMatrix<Scalar,Mat::Options,StorageIndex> Am(A.rows(), A.cols(), A.nonZeros(), const_cast<StorageIndex*>(A.outerIndexPtr()), const_cast<StorageIndex*>(A.innerIndexPtr()), const_cast<Scalar*>(A.valuePtr()));
|
||||
Map<SparseMatrix<Scalar,Mat::Options,StorageIndex>> Am(A.rows(), A.cols(), A.nonZeros(), const_cast<StorageIndex*>(A.outerIndexPtr()), const_cast<StorageIndex*>(A.innerIndexPtr()), const_cast<Scalar*>(A.valuePtr()));
|
||||
solver.compute(Am);
|
||||
VERIFY(solver.info() == Success && "factorization failed when using Map");
|
||||
DenseRhs dx(refX);
|
||||
@@ -99,6 +99,13 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A,
|
||||
VERIFY(solver.info() == Success && "solving failed when using Map");
|
||||
VERIFY(oldb.isApprox(bm) && "sparse solver testing: the rhs should not be modified!");
|
||||
VERIFY(xm.isApprox(refX,test_precision<Scalar>()));
|
||||
|
||||
// Test with a Map and non-unit stride.
|
||||
Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> out(2*xm.rows(), 2*xm.cols());
|
||||
out.setZero();
|
||||
Eigen::Map<DenseRhs, 0, Stride<Eigen::Dynamic, 2>> outm(out.data(), xm.rows(), xm.cols(), Stride<Eigen::Dynamic, 2>(2 * xm.rows(), 2));
|
||||
outm = solver.solve(bm);
|
||||
VERIFY(outm.isApprox(refX,test_precision<Scalar>()));
|
||||
}
|
||||
|
||||
// if not too large, do some extra check:
|
||||
@@ -217,7 +224,7 @@ void check_sparse_solving(Eigen::SparseLU<Eigen::SparseMatrix<Scalar> >& solver,
|
||||
|
||||
x1.setZero();
|
||||
// test with Map
|
||||
MappedSparseMatrix<Scalar,Mat::Options,StorageIndex> Am(A.rows(), A.cols(), A.nonZeros(), const_cast<StorageIndex*>(A.outerIndexPtr()), const_cast<StorageIndex*>(A.innerIndexPtr()), const_cast<Scalar*>(A.valuePtr()));
|
||||
Map<SparseMatrix<Scalar,Mat::Options,StorageIndex> > Am(A.rows(), A.cols(), A.nonZeros(), const_cast<StorageIndex*>(A.outerIndexPtr()), const_cast<StorageIndex*>(A.innerIndexPtr()), const_cast<Scalar*>(A.valuePtr()));
|
||||
solver.compute(Am);
|
||||
VERIFY(solver.info() == Success && "factorization failed when using Map");
|
||||
DenseRhs dx(refX1);
|
||||
@@ -350,7 +357,7 @@ int generate_sparse_spd_problem(Solver& , typename Solver::MatrixType& A, typena
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
|
||||
|
||||
int size = internal::random<int>(1,maxSize);
|
||||
double density = (std::max)(8./(size*size), 0.01);
|
||||
double density = (std::max)(8./static_cast<double>(size*size), 0.01);
|
||||
|
||||
Mat M(size, size);
|
||||
DenseMatrix dM(size, size);
|
||||
@@ -419,7 +426,7 @@ template<typename Solver> void check_sparse_spd_solving(Solver& solver, int maxS
|
||||
|
||||
// generate the right hand sides
|
||||
int rhsCols = internal::random<int>(1,16);
|
||||
double density = (std::max)(8./(size*rhsCols), 0.1);
|
||||
double density = (std::max)(8./static_cast<double>(size*rhsCols), 0.1);
|
||||
SpMat B(size,rhsCols);
|
||||
DenseVector b = DenseVector::Random(size);
|
||||
DenseMatrix dB(size,rhsCols);
|
||||
@@ -510,7 +517,7 @@ Index generate_sparse_square_problem(Solver&, typename Solver::MatrixType& A, De
|
||||
typedef typename Mat::Scalar Scalar;
|
||||
|
||||
Index size = internal::random<int>(1,maxSize);
|
||||
double density = (std::max)(8./(size*size), 0.01);
|
||||
double density = (std::max)(8./static_cast<double>(size*size), 0.01);
|
||||
|
||||
A.resize(size,size);
|
||||
dA.resize(size,size);
|
||||
@@ -551,7 +558,7 @@ template<typename Solver> void check_sparse_square_solving(Solver& solver, int m
|
||||
DenseVector b = DenseVector::Random(size);
|
||||
DenseMatrix dB(size,rhsCols);
|
||||
SpMat B(size,rhsCols);
|
||||
double density = (std::max)(8./(size*rhsCols), 0.1);
|
||||
double density = (std::max)(8./double(size*rhsCols), 0.1);
|
||||
initSparse<Scalar>(density, dB, B, ForceNonZeroDiag);
|
||||
B.makeCompressed();
|
||||
SpVec c = B.col(0);
|
||||
|
||||
@@ -62,7 +62,7 @@ template<typename Scalar> void sparse_solvers(int rows, int cols)
|
||||
{
|
||||
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());
|
||||
Map<SparseMatrix<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));
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ template<typename Scalar,typename StorageIndex> void sparse_vector(int rows, int
|
||||
double densityVec = (std::max)(8./(rows), 0.1);
|
||||
typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
|
||||
typedef Matrix<Scalar,Dynamic,1> DenseVector;
|
||||
typedef Matrix<DenseIndex,Dynamic,1> DenseIndexVector;
|
||||
typedef SparseVector<Scalar,0,StorageIndex> SparseVectorType;
|
||||
typedef SparseMatrix<Scalar,0,StorageIndex> SparseMatrixType;
|
||||
Scalar eps = 1e-6;
|
||||
@@ -47,8 +48,8 @@ template<typename Scalar,typename StorageIndex> void sparse_vector(int rows, int
|
||||
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_EQUAL(it.value(), v1.coeff(it.index()));
|
||||
VERIFY_IS_EQUAL(it.value(), refV1.coeff(it.index()));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(v1, refV1);
|
||||
@@ -111,7 +112,7 @@ template<typename Scalar,typename StorageIndex> void sparse_vector(int rows, int
|
||||
// check copy to dense vector with transpose
|
||||
refV3.resize(0);
|
||||
VERIFY_IS_APPROX(refV3 = v1.transpose(),v1.toDense());
|
||||
VERIFY_IS_APPROX(DenseVector(v1),v1.toDense());
|
||||
VERIFY_IS_APPROX(DenseVector(v1),v1.toDense());
|
||||
|
||||
// test conservative resize
|
||||
{
|
||||
@@ -143,6 +144,58 @@ template<typename Scalar,typename StorageIndex> void sparse_vector(int rows, int
|
||||
}
|
||||
}
|
||||
|
||||
// test sort
|
||||
if(rows > 1)
|
||||
{
|
||||
SparseVectorType vec1(rows);
|
||||
DenseVector refVec1 = DenseVector::Zero(rows);
|
||||
DenseIndexVector innerIndices(rows);
|
||||
innerIndices.setLinSpaced(0, rows - 1);
|
||||
std::random_shuffle(innerIndices.begin(), innerIndices.end());
|
||||
Index nz = internal::random<Index>(2, rows / 2);
|
||||
for (Index k = 0; k < nz; k++)
|
||||
{
|
||||
Index i = innerIndices[k];
|
||||
Scalar val = internal::random<Scalar>();
|
||||
refVec1.coeffRef(i) = val;
|
||||
vec1.insert(i) = val;
|
||||
}
|
||||
|
||||
vec1.template sortInnerIndices<std::greater<>>();
|
||||
VERIFY_IS_APPROX(vec1, refVec1);
|
||||
VERIFY_IS_EQUAL(vec1.template innerIndicesAreSorted<std::greater<>>(), 1);
|
||||
VERIFY_IS_EQUAL(vec1.template innerIndicesAreSorted<std::less<>>(), 0);
|
||||
vec1.template sortInnerIndices<std::less<>>();
|
||||
VERIFY_IS_APPROX(vec1, refVec1);
|
||||
VERIFY_IS_EQUAL(vec1.template innerIndicesAreSorted<std::greater<>>(), 0);
|
||||
VERIFY_IS_EQUAL(vec1.template innerIndicesAreSorted<std::less<>>(), 1);
|
||||
}
|
||||
|
||||
}
|
||||
void test_pruning() {
|
||||
using SparseVectorType = SparseVector<double, 0, int>;
|
||||
|
||||
SparseVectorType vec;
|
||||
auto init_vec = [&](){;
|
||||
vec.resize(10);
|
||||
vec.insert(3) = 0.1;
|
||||
vec.insert(5) = 1.0;
|
||||
vec.insert(8) = -0.1;
|
||||
vec.insert(9) = -0.2;
|
||||
};
|
||||
init_vec();
|
||||
|
||||
VERIFY_IS_EQUAL(vec.nonZeros(), 4);
|
||||
VERIFY_IS_EQUAL(vec.prune(0.1, 1.0), 2);
|
||||
VERIFY_IS_EQUAL(vec.nonZeros(), 2);
|
||||
VERIFY_IS_EQUAL(vec.coeff(5), 1.0);
|
||||
VERIFY_IS_EQUAL(vec.coeff(9), -0.2);
|
||||
|
||||
init_vec();
|
||||
VERIFY_IS_EQUAL(vec.prune([](double v) { return v >= 0; }), 2);
|
||||
VERIFY_IS_EQUAL(vec.nonZeros(), 2);
|
||||
VERIFY_IS_EQUAL(vec.coeff(3), 0.1);
|
||||
VERIFY_IS_EQUAL(vec.coeff(5), 1.0);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(sparse_vector)
|
||||
@@ -159,5 +212,7 @@ EIGEN_DECLARE_TEST(sparse_vector)
|
||||
CALL_SUBTEST_1(( sparse_vector<double,long int>(r, c) ));
|
||||
CALL_SUBTEST_1(( sparse_vector<double,short>(r, c) ));
|
||||
}
|
||||
|
||||
CALL_SUBTEST_1(test_pruning());
|
||||
}
|
||||
|
||||
|
||||
@@ -18,28 +18,7 @@ make_reverse_iterator( Iterator i )
|
||||
return std::reverse_iterator<Iterator>(i);
|
||||
}
|
||||
|
||||
#if !EIGEN_HAS_CXX11
|
||||
template<class ForwardIt>
|
||||
ForwardIt is_sorted_until(ForwardIt firstIt, ForwardIt lastIt)
|
||||
{
|
||||
if (firstIt != lastIt) {
|
||||
ForwardIt next = firstIt;
|
||||
while (++next != lastIt) {
|
||||
if (*next < *firstIt)
|
||||
return next;
|
||||
firstIt = next;
|
||||
}
|
||||
}
|
||||
return lastIt;
|
||||
}
|
||||
template<class ForwardIt>
|
||||
bool is_sorted(ForwardIt firstIt, ForwardIt lastIt)
|
||||
{
|
||||
return ::is_sorted_until(firstIt, lastIt) == lastIt;
|
||||
}
|
||||
#else
|
||||
using std::is_sorted;
|
||||
#endif
|
||||
|
||||
template<typename XprType>
|
||||
bool is_pointer_based_stl_iterator(const internal::pointer_based_stl_iterator<XprType> &) { return true; }
|
||||
@@ -50,10 +29,8 @@ bool is_generic_randaccess_stl_iterator(const internal::generic_randaccess_stl_i
|
||||
template<typename Iter>
|
||||
bool is_default_constructible_and_assignable(const Iter& it)
|
||||
{
|
||||
#if EIGEN_HAS_CXX11
|
||||
VERIFY(std::is_default_constructible<Iter>::value);
|
||||
VERIFY(std::is_nothrow_default_constructible<Iter>::value);
|
||||
#endif
|
||||
Iter it2;
|
||||
it2 = it;
|
||||
return (it==it2);
|
||||
@@ -82,12 +59,10 @@ void check_begin_end_for_loop(Xpr xpr)
|
||||
typename Xpr::const_iterator cit = xpr.begin();
|
||||
cit = xpr.cbegin();
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
auto tmp1 = xpr.begin();
|
||||
VERIFY(tmp1==xpr.begin());
|
||||
auto tmp2 = xpr.cbegin();
|
||||
VERIFY(tmp2==xpr.cbegin());
|
||||
#endif
|
||||
}
|
||||
|
||||
VERIFY( xpr.end() -xpr.begin() == xpr.size() );
|
||||
@@ -123,9 +98,7 @@ template<typename Scalar, int Rows, int Cols>
|
||||
void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
{
|
||||
typedef Matrix<Scalar,Rows,1> VectorType;
|
||||
#if EIGEN_HAS_CXX11
|
||||
typedef Matrix<Scalar,1,Cols> RowVectorType;
|
||||
#endif
|
||||
typedef Matrix<Scalar,Rows,Cols,ColMajor> ColMatrixType;
|
||||
typedef Matrix<Scalar,Rows,Cols,RowMajor> RowMatrixType;
|
||||
VectorType v = VectorType::Random(rows);
|
||||
@@ -133,6 +106,7 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
ColMatrixType A = ColMatrixType::Random(rows,cols);
|
||||
const ColMatrixType& cA(A);
|
||||
RowMatrixType B = RowMatrixType::Random(rows,cols);
|
||||
using Eigen::placeholders::last;
|
||||
|
||||
Index i, j;
|
||||
|
||||
@@ -190,7 +164,6 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
check_begin_end_for_loop(v+v);
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
// check swappable
|
||||
{
|
||||
using std::swap;
|
||||
@@ -325,8 +298,6 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(rows>=3) {
|
||||
VERIFY_IS_EQUAL((v.begin()+rows/2)[1], v(rows/2+1));
|
||||
|
||||
@@ -343,11 +314,7 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
if(rows>=2)
|
||||
{
|
||||
v(1) = v(0)-Scalar(1);
|
||||
#if EIGEN_HAS_CXX11
|
||||
VERIFY(!is_sorted(std::begin(v),std::end(v)));
|
||||
#else
|
||||
VERIFY(!is_sorted(v.cbegin(),v.cend()));
|
||||
#endif
|
||||
}
|
||||
|
||||
// on a vector
|
||||
@@ -427,7 +394,6 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
VERIFY_IS_APPROX(v1(rows/4), v(rows/4));
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
// check rows/cols iterators with range-for loops
|
||||
{
|
||||
j = 0;
|
||||
@@ -472,31 +438,26 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
|
||||
i = internal::random<Index>(0,A.rows()-1);
|
||||
A.setRandom();
|
||||
A.row(i).setZero();
|
||||
VERIFY_IS_EQUAL( std::find_if(A.rowwise().begin(), A.rowwise().end(), [](typename ColMatrixType::RowXpr x) { return x.squaredNorm() == Scalar(0); })-A.rowwise().begin(), i );
|
||||
VERIFY_IS_EQUAL( std::find_if(A.rowwise().rbegin(), A.rowwise().rend(), [](typename ColMatrixType::RowXpr x) { return x.squaredNorm() == Scalar(0); })-A.rowwise().rbegin(), (A.rows()-1) - i );
|
||||
VERIFY_IS_EQUAL(std::find_if(A.rowwise().begin(), A.rowwise().end(), [](typename ColMatrixType::RowXpr x) { return numext::is_exactly_zero(x.squaredNorm()); }) - A.rowwise().begin(), i );
|
||||
VERIFY_IS_EQUAL(std::find_if(A.rowwise().rbegin(), A.rowwise().rend(), [](typename ColMatrixType::RowXpr x) { return numext::is_exactly_zero(x.squaredNorm()); }) - A.rowwise().rbegin(), (A.rows() - 1) - i );
|
||||
|
||||
j = internal::random<Index>(0,A.cols()-1);
|
||||
A.setRandom();
|
||||
A.col(j).setZero();
|
||||
VERIFY_IS_EQUAL( std::find_if(A.colwise().begin(), A.colwise().end(), [](typename ColMatrixType::ColXpr x) { return x.squaredNorm() == Scalar(0); })-A.colwise().begin(), j );
|
||||
VERIFY_IS_EQUAL( std::find_if(A.colwise().rbegin(), A.colwise().rend(), [](typename ColMatrixType::ColXpr x) { return x.squaredNorm() == Scalar(0); })-A.colwise().rbegin(), (A.cols()-1) - j );
|
||||
VERIFY_IS_EQUAL(std::find_if(A.colwise().begin(), A.colwise().end(), [](typename ColMatrixType::ColXpr x) { return numext::is_exactly_zero(x.squaredNorm()); }) - A.colwise().begin(), j );
|
||||
VERIFY_IS_EQUAL(std::find_if(A.colwise().rbegin(), A.colwise().rend(), [](typename ColMatrixType::ColXpr x) { return numext::is_exactly_zero(x.squaredNorm()); }) - A.colwise().rbegin(), (A.cols() - 1) - j );
|
||||
}
|
||||
|
||||
{
|
||||
using VecOp = VectorwiseOp<ArrayXXi, 0>;
|
||||
STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::declval<const VecOp&>().cbegin())>::value ));
|
||||
STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::declval<const VecOp&>().cend ())>::value ));
|
||||
#if EIGEN_COMP_CXXVER>=14
|
||||
STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::cbegin(std::declval<const VecOp&>()))>::value ));
|
||||
STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::cend (std::declval<const VecOp&>()))>::value ));
|
||||
#endif
|
||||
STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::cbegin(std::declval<const VecOp&>()))>::value ));
|
||||
STATIC_CHECK(( internal::is_same<VecOp::const_iterator, decltype(std::cend (std::declval<const VecOp&>()))>::value ));
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
// When the compiler sees expression IsContainerTest<C>(0), if C is an
|
||||
// STL-style container class, the first overload of IsContainerTest
|
||||
// will be viable (since both C::iterator* and C::const_iterator* are
|
||||
@@ -544,7 +505,6 @@ void test_stl_container_detection(int rows=Rows, int cols=Cols)
|
||||
VERIFY_IS_EQUAL(IsContainerType<ColMatrixType>(0), rows == 1 || cols == 1);
|
||||
VERIFY_IS_EQUAL(IsContainerType<RowMatrixType>(0), rows == 1 || cols == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
EIGEN_DECLARE_TEST(stl_iterators)
|
||||
{
|
||||
@@ -554,9 +514,7 @@ EIGEN_DECLARE_TEST(stl_iterators)
|
||||
CALL_SUBTEST_1(( test_stl_iterators<int,Dynamic,Dynamic>(internal::random<int>(5,10), internal::random<int>(5,10)) ));
|
||||
CALL_SUBTEST_1(( test_stl_iterators<int,Dynamic,Dynamic>(internal::random<int>(10,200), internal::random<int>(10,200)) ));
|
||||
}
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
|
||||
CALL_SUBTEST_1(( test_stl_container_detection<float,1,1>() ));
|
||||
CALL_SUBTEST_1(( test_stl_container_detection<float,5,5>() ));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#error a macro SVD_FOR_MIN_NORM(MatrixType) must be defined prior to including svd_common.h
|
||||
#endif
|
||||
|
||||
#ifndef SVD_STATIC_OPTIONS
|
||||
#error a macro SVD_STATIC_OPTIONS(MatrixType, Options) must be defined prior to including svd_common.h
|
||||
#endif
|
||||
|
||||
#include "svd_fill.h"
|
||||
#include "solverbase.h"
|
||||
|
||||
@@ -55,50 +59,44 @@ void svd_check_full(const MatrixType& m, const SvdType& svd)
|
||||
}
|
||||
|
||||
// Compare partial SVD defined by computationOptions to a full SVD referenceSvd
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_compare_to_full(const MatrixType& m,
|
||||
unsigned int computationOptions,
|
||||
const SvdType& referenceSvd)
|
||||
{
|
||||
template <typename MatrixType, typename SvdType, int Options>
|
||||
void svd_compare_to_full(const MatrixType& m, const SvdType& referenceSvd) {
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
Index diagSize = (std::min)(rows, cols);
|
||||
RealScalar prec = test_precision<RealScalar>();
|
||||
|
||||
SvdType svd(m, computationOptions);
|
||||
SVD_STATIC_OPTIONS(MatrixType, Options) svd(m);
|
||||
|
||||
VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues());
|
||||
|
||||
if(computationOptions & (ComputeFullV|ComputeThinV))
|
||||
{
|
||||
|
||||
if (Options & (ComputeFullV | ComputeThinV)) {
|
||||
VERIFY( (svd.matrixV().adjoint()*svd.matrixV()).isIdentity(prec) );
|
||||
VERIFY_IS_APPROX( svd.matrixV().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint(),
|
||||
referenceSvd.matrixV().leftCols(diagSize) * referenceSvd.singularValues().asDiagonal() * referenceSvd.matrixV().leftCols(diagSize).adjoint());
|
||||
}
|
||||
|
||||
if(computationOptions & (ComputeFullU|ComputeThinU))
|
||||
{
|
||||
|
||||
if (Options & (ComputeFullU | ComputeThinU)) {
|
||||
VERIFY( (svd.matrixU().adjoint()*svd.matrixU()).isIdentity(prec) );
|
||||
VERIFY_IS_APPROX( svd.matrixU().leftCols(diagSize) * svd.singularValues().cwiseAbs2().asDiagonal() * svd.matrixU().leftCols(diagSize).adjoint(),
|
||||
referenceSvd.matrixU().leftCols(diagSize) * referenceSvd.singularValues().cwiseAbs2().asDiagonal() * referenceSvd.matrixU().leftCols(diagSize).adjoint());
|
||||
}
|
||||
|
||||
|
||||
// The following checks are not critical.
|
||||
// For instance, with Dived&Conquer SVD, if only the factor 'V' is computedt then different matrix-matrix product implementation will be used
|
||||
// and the resulting 'V' factor might be significantly different when the SVD decomposition is not unique, especially with single precision float.
|
||||
// For instance, with Dived&Conquer SVD, if only the factor 'V' is computed then different matrix-matrix product
|
||||
// implementation will be used and the resulting 'V' factor might be significantly different when the SVD
|
||||
// decomposition is not unique, especially with single precision float.
|
||||
++g_test_level;
|
||||
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().cwiseAbs(), referenceSvd.matrixV().cwiseAbs());
|
||||
if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize));
|
||||
if (Options & ComputeFullU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU());
|
||||
if (Options & ComputeThinU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize));
|
||||
if (Options & ComputeFullV) VERIFY_IS_APPROX(svd.matrixV().cwiseAbs(), referenceSvd.matrixV().cwiseAbs());
|
||||
if (Options & ComputeThinV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize));
|
||||
--g_test_level;
|
||||
}
|
||||
|
||||
//
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_least_square(const MatrixType& m, unsigned int computationOptions)
|
||||
{
|
||||
template <typename SvdType, typename MatrixType>
|
||||
void svd_least_square(const MatrixType& m) {
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
Index rows = m.rows();
|
||||
@@ -113,10 +111,10 @@ void svd_least_square(const MatrixType& m, unsigned int computationOptions)
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, Dynamic> SolutionType;
|
||||
|
||||
RhsType rhs = RhsType::Random(rows, internal::random<Index>(1, cols));
|
||||
SvdType svd(m, computationOptions);
|
||||
SvdType svd(m);
|
||||
|
||||
if(internal::is_same<RealScalar,double>::value) svd.setThreshold(1e-8);
|
||||
else if(internal::is_same<RealScalar,float>::value) svd.setThreshold(2e-4);
|
||||
if (internal::is_same<RealScalar, double>::value) svd.setThreshold(RealScalar(1e-8));
|
||||
else if(internal::is_same<RealScalar,float>::value) svd.setThreshold(RealScalar(2e-4));
|
||||
|
||||
SolutionType x = svd.solve(rhs);
|
||||
|
||||
@@ -162,10 +160,9 @@ void svd_least_square(const MatrixType& m, unsigned int computationOptions)
|
||||
}
|
||||
}
|
||||
|
||||
// check minimal norm solutions, the inoput matrix m is only used to recover problem size
|
||||
template<typename MatrixType>
|
||||
void svd_min_norm(const MatrixType& m, unsigned int computationOptions)
|
||||
{
|
||||
// check minimal norm solutions, the input matrix m is only used to recover problem size
|
||||
template <typename MatrixType, int Options>
|
||||
void svd_min_norm(const MatrixType& m) {
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
Index cols = m.cols();
|
||||
|
||||
@@ -199,7 +196,7 @@ void svd_min_norm(const MatrixType& m, unsigned int computationOptions)
|
||||
tmp.tail(cols-rank).setZero();
|
||||
SolutionType x21 = qr.householderQ() * tmp;
|
||||
// now check with SVD
|
||||
SVD_FOR_MIN_NORM(MatrixType2) svd2(m2, computationOptions);
|
||||
SVD_STATIC_OPTIONS(MatrixType2, Options) svd2(m2);
|
||||
SolutionType x22 = svd2.solve(rhs2);
|
||||
VERIFY_IS_APPROX(m2*x21, rhs2);
|
||||
VERIFY_IS_APPROX(m2*x22, rhs2);
|
||||
@@ -212,7 +209,7 @@ void svd_min_norm(const MatrixType& m, unsigned int computationOptions)
|
||||
Matrix<Scalar,RowsAtCompileTime3,Dynamic> C = Matrix<Scalar,RowsAtCompileTime3,Dynamic>::Random(rows3,rank);
|
||||
MatrixType3 m3 = C * m2;
|
||||
RhsType3 rhs3 = C * rhs2;
|
||||
SVD_FOR_MIN_NORM(MatrixType3) svd3(m3, computationOptions);
|
||||
SVD_STATIC_OPTIONS(MatrixType3, Options) svd3(m3);
|
||||
SolutionType x3 = svd3.solve(rhs3);
|
||||
VERIFY_IS_APPROX(m3*x3, rhs3);
|
||||
VERIFY_IS_APPROX(m3*x21, rhs3);
|
||||
@@ -239,57 +236,6 @@ void svd_test_solvers(const MatrixType& m, const SolverType& solver) {
|
||||
check_solverbase<CMatrixType, MatrixType>(m, solver, rows, cols, cols2);
|
||||
}
|
||||
|
||||
// Check full, compare_to_full, least_square, and min_norm for all possible compute-options
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_test_all_computation_options(const MatrixType& m, bool full_only)
|
||||
{
|
||||
// if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols())
|
||||
// return;
|
||||
STATIC_CHECK(( internal::is_same<typename SvdType::StorageIndex,int>::value ));
|
||||
|
||||
SvdType fullSvd(m, ComputeFullU|ComputeFullV);
|
||||
CALL_SUBTEST(( svd_check_full(m, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeFullU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeFullV) ));
|
||||
|
||||
#if defined __INTEL_COMPILER
|
||||
// remark #111: statement is unreachable
|
||||
#pragma warning disable 111
|
||||
#endif
|
||||
|
||||
svd_test_solvers(m, fullSvd);
|
||||
|
||||
if(full_only)
|
||||
return;
|
||||
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, 0, fullSvd) ));
|
||||
|
||||
if (MatrixType::ColsAtCompileTime == Dynamic) {
|
||||
// thin U/V are only available with dynamic number of columns
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU , fullSvd) ));
|
||||
CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) ));
|
||||
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeFullU | ComputeThinV) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeThinU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeThinU | ComputeThinV) ));
|
||||
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeThinV) ));
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeFullV) ));
|
||||
CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeThinV) ));
|
||||
|
||||
// test reconstruction
|
||||
Index diagSize = (std::min)(m.rows(), m.cols());
|
||||
SvdType svd(m, ComputeThinU | ComputeThinV);
|
||||
VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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>
|
||||
@@ -300,29 +246,28 @@ template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
|
||||
|
||||
// This function verifies we don't iterate infinitely on nan/inf values,
|
||||
// and that info() returns InvalidInput.
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_inf_nan()
|
||||
{
|
||||
SvdType svd;
|
||||
template <typename MatrixType>
|
||||
void svd_inf_nan() {
|
||||
SVD_STATIC_OPTIONS(MatrixType, ComputeFullU | ComputeFullV) 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);
|
||||
svd.compute(MatrixType::Constant(10, 10, some_inf));
|
||||
VERIFY(svd.info() == InvalidInput);
|
||||
|
||||
Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
|
||||
VERIFY(nan != nan);
|
||||
svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV);
|
||||
svd.compute(MatrixType::Constant(10, 10, nan));
|
||||
VERIFY(svd.info() == InvalidInput);
|
||||
|
||||
MatrixType m = MatrixType::Zero(10,10);
|
||||
m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_inf;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
svd.compute(m);
|
||||
VERIFY(svd.info() == InvalidInput);
|
||||
|
||||
m = MatrixType::Zero(10,10);
|
||||
m(internal::random<int>(0,9), internal::random<int>(0,9)) = nan;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
svd.compute(m);
|
||||
VERIFY(svd.info() == InvalidInput);
|
||||
|
||||
// regression test for bug 791
|
||||
@@ -330,7 +275,7 @@ void svd_inf_nan()
|
||||
m << 0, 2*NumTraits<Scalar>::epsilon(), 0.5,
|
||||
0, -0.5, 0,
|
||||
nan, 0, 0;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
svd.compute(m);
|
||||
VERIFY(svd.info() == InvalidInput);
|
||||
|
||||
m.resize(4,4);
|
||||
@@ -338,7 +283,7 @@ void svd_inf_nan()
|
||||
0, 3, 1, 2e-308,
|
||||
1, 0, 1, nan,
|
||||
0, nan, nan, 0;
|
||||
svd.compute(m, ComputeFullU | ComputeFullV);
|
||||
svd.compute(m);
|
||||
VERIFY(svd.info() == InvalidInput);
|
||||
}
|
||||
|
||||
@@ -355,8 +300,8 @@ void svd_underoverflow()
|
||||
Matrix2d M;
|
||||
M << -7.90884e-313, -4.94e-324,
|
||||
0, 5.60844e-313;
|
||||
SVD_DEFAULT(Matrix2d) svd;
|
||||
svd.compute(M,ComputeFullU|ComputeFullV);
|
||||
SVD_STATIC_OPTIONS(Matrix2d, ComputeFullU | ComputeFullV) svd;
|
||||
svd.compute(M);
|
||||
CALL_SUBTEST( svd_check_full(M,svd) );
|
||||
|
||||
// Check all 2x2 matrices made with the following coefficients:
|
||||
@@ -367,7 +312,7 @@ void svd_underoverflow()
|
||||
do
|
||||
{
|
||||
M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3));
|
||||
svd.compute(M,ComputeFullU|ComputeFullV);
|
||||
svd.compute(M);
|
||||
CALL_SUBTEST( svd_check_full(M,svd) );
|
||||
|
||||
id(k)++;
|
||||
@@ -390,16 +335,13 @@ void svd_underoverflow()
|
||||
3.7841695601406358e+307, 2.4331702789740617e+306, -3.5235707140272905e+307,
|
||||
-8.7190887618028355e+307, -7.3453213709232193e+307, -2.4367363684472105e+307;
|
||||
|
||||
SVD_DEFAULT(Matrix3d) svd3;
|
||||
svd3.compute(M3,ComputeFullU|ComputeFullV); // just check we don't loop indefinitely
|
||||
SVD_STATIC_OPTIONS(Matrix3d, ComputeFullU | ComputeFullV) svd3;
|
||||
svd3.compute(M3); // just check we don't loop indefinitely
|
||||
CALL_SUBTEST( svd_check_full(M3,svd3) );
|
||||
}
|
||||
|
||||
// void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true)
|
||||
|
||||
template<typename MatrixType>
|
||||
void svd_all_trivial_2x2( void (*cb)(const MatrixType&,bool) )
|
||||
{
|
||||
template <typename MatrixType>
|
||||
void svd_all_trivial_2x2(void (*cb)(const MatrixType&)) {
|
||||
MatrixType M;
|
||||
VectorXd value_set(3);
|
||||
value_set << 0, 1, -1;
|
||||
@@ -408,9 +350,9 @@ void svd_all_trivial_2x2( void (*cb)(const MatrixType&,bool) )
|
||||
do
|
||||
{
|
||||
M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3));
|
||||
|
||||
cb(M,false);
|
||||
|
||||
|
||||
cb(M);
|
||||
|
||||
id(k)++;
|
||||
if(id(k)>=value_set.size())
|
||||
{
|
||||
@@ -434,22 +376,10 @@ void svd_preallocate()
|
||||
internal::set_is_malloc_allowed(true);
|
||||
svd.compute(m);
|
||||
VERIFY_IS_APPROX(svd.singularValues(), v);
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU());
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV());
|
||||
|
||||
SVD_DEFAULT(MatrixXf) svd2(3,3);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
VERIFY_IS_APPROX(svd2.singularValues(), v);
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixU());
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixV());
|
||||
svd2.compute(m, ComputeFullU | ComputeFullV);
|
||||
VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity());
|
||||
VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity());
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
|
||||
SVD_DEFAULT(MatrixXf) svd3(3,3,ComputeFullU|ComputeFullV);
|
||||
SVD_STATIC_OPTIONS(MatrixXf, ComputeFullU | ComputeFullV) svd2(3, 3);
|
||||
internal::set_is_malloc_allowed(false);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
@@ -457,13 +387,203 @@ void svd_preallocate()
|
||||
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);
|
||||
svd2.compute(m);
|
||||
internal::set_is_malloc_allowed(true);
|
||||
}
|
||||
|
||||
template<typename SvdType,typename MatrixType>
|
||||
void svd_verify_assert(const MatrixType& m, bool fullOnly = false)
|
||||
{
|
||||
template <typename MatrixType, int QRPreconditioner = 0>
|
||||
void svd_verify_assert_full_only(const MatrixType& m = MatrixType()) {
|
||||
enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime };
|
||||
|
||||
typedef Matrix<typename MatrixType::Scalar, RowsAtCompileTime, 1> RhsType;
|
||||
RhsType rhs = RhsType::Zero(m.rows());
|
||||
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner) svd0;
|
||||
VERIFY_RAISES_ASSERT((svd0.matrixU()));
|
||||
VERIFY_RAISES_ASSERT((svd0.singularValues()));
|
||||
VERIFY_RAISES_ASSERT((svd0.matrixV()));
|
||||
VERIFY_RAISES_ASSERT((svd0.solve(rhs)));
|
||||
VERIFY_RAISES_ASSERT((svd0.transpose().solve(rhs)));
|
||||
VERIFY_RAISES_ASSERT((svd0.adjoint().solve(rhs)));
|
||||
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner) svd1(m);
|
||||
VERIFY_RAISES_ASSERT((svd1.matrixU()));
|
||||
VERIFY_RAISES_ASSERT((svd1.matrixV()));
|
||||
VERIFY_RAISES_ASSERT((svd1.solve(rhs)));
|
||||
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeFullU) svdFullU(m);
|
||||
VERIFY_RAISES_ASSERT((svdFullU.matrixV()));
|
||||
VERIFY_RAISES_ASSERT((svdFullU.solve(rhs)));
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeFullV) svdFullV(m);
|
||||
VERIFY_RAISES_ASSERT((svdFullV.matrixU()));
|
||||
VERIFY_RAISES_ASSERT((svdFullV.solve(rhs)));
|
||||
}
|
||||
|
||||
template <typename MatrixType, int QRPreconditioner = 0>
|
||||
void svd_verify_assert(const MatrixType& m = MatrixType()) {
|
||||
enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime };
|
||||
|
||||
typedef Matrix<typename MatrixType::Scalar, RowsAtCompileTime, 1> RhsType;
|
||||
RhsType rhs = RhsType::Zero(m.rows());
|
||||
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeThinU) svdThinU(m);
|
||||
VERIFY_RAISES_ASSERT((svdThinU.matrixV()));
|
||||
VERIFY_RAISES_ASSERT((svdThinU.solve(rhs)));
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeThinV) svdThinV(m);
|
||||
VERIFY_RAISES_ASSERT((svdThinV.matrixU()));
|
||||
VERIFY_RAISES_ASSERT((svdThinV.solve(rhs)));
|
||||
|
||||
svd_verify_assert_full_only<MatrixType, QRPreconditioner>(m);
|
||||
}
|
||||
|
||||
template <typename MatrixType, int Options>
|
||||
void svd_compute_checks(const MatrixType& m) {
|
||||
typedef SVD_STATIC_OPTIONS(MatrixType, Options) SVDType;
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
DiagAtCompileTime = internal::min_size_prefer_dynamic(RowsAtCompileTime, ColsAtCompileTime),
|
||||
MatrixURowsAtCompileTime = SVDType::MatrixUType::RowsAtCompileTime,
|
||||
MatrixUColsAtCompileTime = SVDType::MatrixUType::ColsAtCompileTime,
|
||||
MatrixVRowsAtCompileTime = SVDType::MatrixVType::RowsAtCompileTime,
|
||||
MatrixVColsAtCompileTime = SVDType::MatrixVType::ColsAtCompileTime
|
||||
};
|
||||
|
||||
SVDType staticSvd(m);
|
||||
|
||||
VERIFY(MatrixURowsAtCompileTime == RowsAtCompileTime);
|
||||
VERIFY(MatrixVRowsAtCompileTime == ColsAtCompileTime);
|
||||
if (Options & ComputeThinU) VERIFY(MatrixUColsAtCompileTime == DiagAtCompileTime);
|
||||
if (Options & ComputeFullU) VERIFY(MatrixUColsAtCompileTime == RowsAtCompileTime);
|
||||
if (Options & ComputeThinV) VERIFY(MatrixVColsAtCompileTime == DiagAtCompileTime);
|
||||
if (Options & ComputeFullV) VERIFY(MatrixVColsAtCompileTime == ColsAtCompileTime);
|
||||
|
||||
if (Options & (ComputeThinU | ComputeFullU))
|
||||
VERIFY(staticSvd.computeU());
|
||||
else
|
||||
VERIFY(!staticSvd.computeU());
|
||||
if (Options & (ComputeThinV | ComputeFullV))
|
||||
VERIFY(staticSvd.computeV());
|
||||
else
|
||||
VERIFY(!staticSvd.computeV());
|
||||
|
||||
if (staticSvd.computeU()) VERIFY(staticSvd.matrixU().isUnitary());
|
||||
if (staticSvd.computeV()) VERIFY(staticSvd.matrixV().isUnitary());
|
||||
|
||||
if (staticSvd.computeU() && staticSvd.computeV()) {
|
||||
svd_test_solvers(m, staticSvd);
|
||||
svd_least_square<SVDType, MatrixType>(m);
|
||||
// svd_min_norm generates non-square matrices so it can't be used with NoQRPreconditioner
|
||||
if ((Options & internal::QRPreconditionerBits) != NoQRPreconditioner) svd_min_norm<MatrixType, Options>(m);
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated behavior.
|
||||
template <typename SvdType, typename MatrixType>
|
||||
void svd_check_runtime_options(const MatrixType& m, unsigned int computationOptions) {
|
||||
const bool fixedRowAndThinU = SvdType::RowsAtCompileTime != Dynamic && (computationOptions & ComputeThinU) != 0 && m.cols() < m.rows();
|
||||
const bool fixedColAndThinV = SvdType::ColsAtCompileTime != Dynamic && (computationOptions & ComputeThinV) != 0 && m.rows() < m.cols();
|
||||
if (fixedRowAndThinU || fixedColAndThinV) {
|
||||
VERIFY_RAISES_ASSERT(SvdType svd(m, computationOptions));
|
||||
return;
|
||||
}
|
||||
|
||||
Index diagSize = (std::min)(m.rows(), m.cols());
|
||||
|
||||
SvdType svd(m, computationOptions);
|
||||
if (svd.computeU()) {
|
||||
VERIFY(svd.matrixU().isUnitary());
|
||||
if (computationOptions & ComputeThinU) VERIFY(svd.matrixU().cols() == diagSize);
|
||||
}
|
||||
|
||||
if (svd.computeV()) {
|
||||
VERIFY(svd.matrixV().isUnitary());
|
||||
if (computationOptions & ComputeThinV) VERIFY(svd.matrixV().cols() == diagSize);
|
||||
}
|
||||
if (svd.computeU() && svd.computeV()) {
|
||||
svd_test_solvers(m, svd);
|
||||
svd.matrixU().isUnitary();
|
||||
svd.matrixV().isUnitary();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MatrixType, int QRPreconditioner = 0>
|
||||
void svd_option_checks(const MatrixType& m) {
|
||||
svd_compute_checks<MatrixType, QRPreconditioner>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeThinU>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeThinV>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeThinU | ComputeThinV>(m);
|
||||
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullU>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullV>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullU | ComputeFullV>(m);
|
||||
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeThinU | ComputeFullV>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullU | ComputeThinV>(m);
|
||||
|
||||
typedef SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeFullU | ComputeFullV) FullSvdType;
|
||||
FullSvdType fullSvd(m);
|
||||
svd_check_full(m, fullSvd);
|
||||
svd_compare_to_full<MatrixType, FullSvdType, QRPreconditioner | ComputeFullU | ComputeFullV>(m, fullSvd);
|
||||
|
||||
// Deprecated behavior.
|
||||
typedef SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner) DynamicSvd;
|
||||
svd_check_runtime_options<DynamicSvd>(m, 0);
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeThinU);
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeThinV);
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeThinU | ComputeThinV);
|
||||
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeFullU);
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeFullV);
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeFullU | ComputeFullV);
|
||||
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeThinU | ComputeFullV);
|
||||
svd_check_runtime_options<DynamicSvd>(m, ComputeFullU | ComputeThinV);
|
||||
}
|
||||
|
||||
template <typename MatrixType, int QRPreconditioner = 0>
|
||||
void svd_option_checks_full_only(const MatrixType& m) {
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullU>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullV>(m);
|
||||
svd_compute_checks<MatrixType, QRPreconditioner | ComputeFullU | ComputeFullV>(m);
|
||||
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeFullU | ComputeFullV) fullSvd(m);
|
||||
svd_check_full(m, fullSvd);
|
||||
}
|
||||
|
||||
template <typename MatrixType, int QRPreconditioner = 0>
|
||||
void svd_check_max_size_matrix(int initialRows, int initialCols) {
|
||||
enum {
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||
};
|
||||
|
||||
int rows = MaxRowsAtCompileTime == Dynamic ? initialRows : (std::min)(initialRows, (int)MaxRowsAtCompileTime);
|
||||
int cols = MaxColsAtCompileTime == Dynamic ? initialCols : (std::min)(initialCols, (int)MaxColsAtCompileTime);
|
||||
|
||||
MatrixType m(rows, cols);
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeThinU | ComputeThinV) thinSvd(m);
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeThinU | ComputeFullV) mixedSvd1(m);
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeFullU | ComputeThinV) mixedSvd2(m);
|
||||
SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner | ComputeFullU | ComputeFullV) fullSvd(m);
|
||||
|
||||
MatrixType n(MaxRowsAtCompileTime, MaxColsAtCompileTime);
|
||||
thinSvd.compute(n);
|
||||
mixedSvd1.compute(n);
|
||||
mixedSvd2.compute(n);
|
||||
fullSvd.compute(n);
|
||||
|
||||
MatrixX<typename MatrixType::Scalar> dynamicMatrix(MaxRowsAtCompileTime + 1, MaxColsAtCompileTime + 1);
|
||||
|
||||
VERIFY_RAISES_ASSERT(thinSvd.compute(dynamicMatrix));
|
||||
VERIFY_RAISES_ASSERT(mixedSvd1.compute(dynamicMatrix));
|
||||
VERIFY_RAISES_ASSERT(mixedSvd2.compute(dynamicMatrix));
|
||||
VERIFY_RAISES_ASSERT(fullSvd.compute(dynamicMatrix));
|
||||
}
|
||||
|
||||
template <typename SvdType, typename MatrixType>
|
||||
void svd_verify_constructor_options_assert(const MatrixType& m, bool fullOnly = false) {
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
@@ -482,40 +602,39 @@ void svd_verify_assert(const MatrixType& m, bool fullOnly = false)
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
VERIFY_RAISES_ASSERT(svd.transpose().solve(rhs))
|
||||
VERIFY_RAISES_ASSERT(svd.adjoint().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))
|
||||
|
||||
svd.compute(a, ComputeFullU);
|
||||
svd.matrixU();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
svd.compute(a, ComputeFullV);
|
||||
svd.matrixV();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
MatrixType a = MatrixType::Zero(rows, cols);
|
||||
SvdType svd2(a, 0);
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd2.matrixV())
|
||||
svd2.singularValues();
|
||||
VERIFY_RAISES_ASSERT(svd2.solve(rhs))
|
||||
|
||||
// Deprecated behavior.
|
||||
SvdType svd3(a, ComputeFullU);
|
||||
svd3.matrixU();
|
||||
VERIFY_RAISES_ASSERT(svd3.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd3.solve(rhs))
|
||||
|
||||
SvdType svd4(a, ComputeFullV);
|
||||
svd4.matrixV();
|
||||
VERIFY_RAISES_ASSERT(svd4.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd4.solve(rhs))
|
||||
|
||||
if (!fullOnly && ColsAtCompileTime == Dynamic)
|
||||
{
|
||||
svd.compute(a, ComputeThinU);
|
||||
svd.matrixU();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
svd.compute(a, ComputeThinV);
|
||||
svd.matrixV();
|
||||
VERIFY_RAISES_ASSERT(svd.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU))
|
||||
VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV))
|
||||
SvdType svd5(a, ComputeThinU);
|
||||
svd5.matrixU();
|
||||
VERIFY_RAISES_ASSERT(svd5.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd5.solve(rhs))
|
||||
|
||||
SvdType svd6(a, ComputeThinV);
|
||||
svd6.matrixV();
|
||||
VERIFY_RAISES_ASSERT(svd6.matrixU())
|
||||
VERIFY_RAISES_ASSERT(svd6.solve(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
#undef SVD_DEFAULT
|
||||
#undef SVD_FOR_MIN_NORM
|
||||
#undef SVD_STATIC_OPTIONS
|
||||
|
||||
@@ -64,8 +64,11 @@ void svd_fill_random(MatrixType &m, int Option = 0)
|
||||
}
|
||||
|
||||
Matrix<Scalar,Dynamic,1> samples(9);
|
||||
samples << 0, four_denorms<RealScalar>(),
|
||||
-RealScalar(1)/NumTraits<RealScalar>::highest(), RealScalar(1)/NumTraits<RealScalar>::highest(), (std::numeric_limits<RealScalar>::min)(), pow((std::numeric_limits<RealScalar>::min)(),0.8);
|
||||
samples << Scalar(0), four_denorms<RealScalar>(),
|
||||
-RealScalar(1)/NumTraits<RealScalar>::highest(),
|
||||
RealScalar(1)/NumTraits<RealScalar>::highest(),
|
||||
(std::numeric_limits<RealScalar>::min)(),
|
||||
pow((std::numeric_limits<RealScalar>::min)(), RealScalar(0.8));
|
||||
|
||||
if(Option==Symmetric)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// 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>
|
||||
@@ -16,12 +15,29 @@ 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> >
|
||||
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;
|
||||
typedef Matrix<Scalar_, Rows_, Cols_, Options_^RowMajor, MaxRows_, MaxCols_> type;
|
||||
};
|
||||
|
||||
template <typename MatrixType>
|
||||
std::enable_if_t<(MatrixType::RowsAtCompileTime==1 || MatrixType::RowsAtCompileTime==Dynamic), void>
|
||||
check_row_swap(MatrixType& m1) {
|
||||
|
||||
if (m1.rows() != 1) {
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
std::enable_if_t<!(MatrixType::RowsAtCompileTime==1 || MatrixType::RowsAtCompileTime==Dynamic), void>
|
||||
check_row_swap(MatrixType& /* unused */) {
|
||||
}
|
||||
|
||||
template<typename MatrixType> void swap(const MatrixType& m)
|
||||
{
|
||||
typedef typename other_matrix_type<MatrixType>::type OtherMatrixType;
|
||||
@@ -73,14 +89,8 @@ template<typename MatrixType> void swap(const MatrixType& m)
|
||||
VERIFY_IS_APPROX(m3,m1_copy);
|
||||
m1 = m1_copy;
|
||||
m3 = m3_copy;
|
||||
|
||||
if(m1.rows()>1)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
|
||||
check_row_swap(m1);
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(swap)
|
||||
|
||||
@@ -7,18 +7,12 @@
|
||||
// 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/.
|
||||
|
||||
#ifdef EIGEN_TEST_PART_2
|
||||
#define EIGEN_MAX_CPP_VER 03
|
||||
|
||||
// see indexed_view.cpp
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::lastp1;
|
||||
using Eigen::placeholders::all;
|
||||
|
||||
template<typename T1,typename T2>
|
||||
bool is_same_symb(const T1& a, const T2& b, Index size)
|
||||
{
|
||||
@@ -58,15 +52,14 @@ void check_symbolic_index()
|
||||
VERIFY( is_same_type( fix<9>()/2, int(9/2) ) );
|
||||
|
||||
VERIFY( is_same_symb( lastp1-1, last, size) );
|
||||
VERIFY( is_same_symb( lastp1-fix<1>, last, size) );
|
||||
VERIFY( is_same_symb( lastp1-fix<1>(), last, size) );
|
||||
|
||||
VERIFY_IS_EQUAL( ( (last*5-2)/3 ).eval(last=size-1), ((size-1)*5-2)/3 );
|
||||
VERIFY_IS_EQUAL( ( (last*fix<5>-fix<2>)/fix<3> ).eval(last=size-1), ((size-1)*5-2)/3 );
|
||||
VERIFY_IS_EQUAL( ( (last*fix<5>()-fix<2>())/fix<3>() ).eval(last=size-1), ((size-1)*5-2)/3 );
|
||||
VERIFY_IS_EQUAL( ( -last*lastp1 ).eval(last=size-1), -(size-1)*size );
|
||||
VERIFY_IS_EQUAL( ( lastp1-3*last ).eval(last=size-1), size- 3*(size-1) );
|
||||
VERIFY_IS_EQUAL( ( (lastp1-3*last)/lastp1 ).eval(last=size-1), (size- 3*(size-1))/size );
|
||||
|
||||
#if EIGEN_HAS_CXX14
|
||||
{
|
||||
struct x_tag {}; static const symbolic::SymbolExpr<x_tag> x;
|
||||
struct y_tag {}; static const symbolic::SymbolExpr<y_tag> y;
|
||||
@@ -74,11 +67,9 @@ void check_symbolic_index()
|
||||
|
||||
VERIFY_IS_APPROX( int(((x+3)/y+z).eval(x=6,y=3,z=-13)), (6+3)/3+(-13) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(symbolic_index)
|
||||
{
|
||||
CALL_SUBTEST_1( check_symbolic_index() );
|
||||
CALL_SUBTEST_2( check_symbolic_index() );
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// 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/.
|
||||
|
||||
#ifdef EIGEN_TEST_PART_100
|
||||
#if defined(EIGEN_TEST_PART_100) || defined(EIGEN_TEST_PART_ALL)
|
||||
# define EIGEN_NO_DEPRECATED_WARNING
|
||||
#endif
|
||||
|
||||
@@ -139,7 +139,6 @@ template<typename MatrixType> void triangular_square(const MatrixType& m)
|
||||
m3.setZero();
|
||||
m3.template triangularView<Upper>().setOnes();
|
||||
VERIFY_IS_APPROX(m2,m3);
|
||||
VERIFY_RAISES_STATIC_ASSERT(m1.template triangularView<Eigen::Lower>().swap(m2.template triangularView<Eigen::Upper>()));
|
||||
|
||||
m1.setRandom();
|
||||
m3 = m1.template triangularView<Upper>();
|
||||
|
||||
123
libs/eigen/test/tuple_test.cpp
Normal file
123
libs/eigen/test/tuple_test.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 The Eigen Team
|
||||
//
|
||||
// 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/src/Core/arch/GPU/Tuple.h>
|
||||
|
||||
using namespace Eigen::internal;
|
||||
using Eigen::internal::tuple_impl::tuple;
|
||||
|
||||
void basic_tuple_test() {
|
||||
// Construction.
|
||||
tuple<> tuple0 {};
|
||||
tuple<int> tuple1 {1};
|
||||
tuple<int, float> tuple2 {3, 5.0f};
|
||||
tuple<int, float, double> tuple3 {7, 11.0f, 13.0};
|
||||
// Default construction.
|
||||
tuple<> tuple0default;
|
||||
EIGEN_UNUSED_VARIABLE(tuple0default)
|
||||
tuple<int> tuple1default;
|
||||
EIGEN_UNUSED_VARIABLE(tuple1default)
|
||||
tuple<int, float> tuple2default;
|
||||
EIGEN_UNUSED_VARIABLE(tuple2default)
|
||||
tuple<int, float, double> tuple3default;
|
||||
EIGEN_UNUSED_VARIABLE(tuple3default)
|
||||
|
||||
// Assignment.
|
||||
tuple<> tuple0b = tuple0;
|
||||
EIGEN_UNUSED_VARIABLE(tuple0b)
|
||||
decltype(tuple1) tuple1b = tuple1;
|
||||
EIGEN_UNUSED_VARIABLE(tuple1b)
|
||||
decltype(tuple2) tuple2b = tuple2;
|
||||
EIGEN_UNUSED_VARIABLE(tuple2b)
|
||||
decltype(tuple3) tuple3b = tuple3;
|
||||
EIGEN_UNUSED_VARIABLE(tuple3b)
|
||||
|
||||
// get.
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<0>(tuple3), 7);
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<1>(tuple3), 11.0f);
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<2>(tuple3), 13.0);
|
||||
|
||||
// tuple_impl::tuple_size.
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple0)>::value, size_t(0));
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple1)>::value, size_t(1));
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple2)>::value, size_t(2));
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple3)>::value, size_t(3));
|
||||
|
||||
// tuple_impl::tuple_cat.
|
||||
auto tuple2cat3 = tuple_impl::tuple_cat(tuple2, tuple3);
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple2cat3)>::value, size_t(5));
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<1>(tuple2cat3), 5.0f);
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<3>(tuple2cat3), 11.0f);
|
||||
auto tuple3cat0 = tuple_impl::tuple_cat(tuple3, tuple0);
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple3cat0)>::value, size_t(3));
|
||||
auto singlecat = tuple_impl::tuple_cat(tuple3);
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(singlecat)>::value, size_t(3));
|
||||
auto emptycat = tuple_impl::tuple_cat();
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(emptycat)>::value, size_t(0));
|
||||
auto tuple0cat1cat2cat3 = tuple_impl::tuple_cat(tuple0, tuple1, tuple2, tuple3);
|
||||
VERIFY_IS_EQUAL(tuple_impl::tuple_size<decltype(tuple0cat1cat2cat3)>::value, size_t(6));
|
||||
|
||||
// make_tuple.
|
||||
// The tuple types should uses values for the second and fourth parameters.
|
||||
double tmp = 20;
|
||||
auto tuple_make = tuple_impl::make_tuple(int(10), tmp, float(20.0f), tuple0);
|
||||
VERIFY( (std::is_same<decltype(tuple_make), tuple<int, double, float, tuple<> > >::value) );
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<1>(tuple_make), tmp);
|
||||
|
||||
// forward_as_tuple.
|
||||
// The tuple types should uses references for the second and fourth parameters.
|
||||
auto tuple_forward = tuple_impl::forward_as_tuple(int(10), tmp, float(20.0f), tuple0);
|
||||
VERIFY( (std::is_same<decltype(tuple_forward), tuple<int, double&, float, tuple<>& > >::value) );
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<1>(tuple_forward), tmp);
|
||||
|
||||
// tie.
|
||||
auto tuple_tie = tuple_impl::tie(tuple0, tuple1, tuple2, tuple3);
|
||||
VERIFY( (std::is_same<decltype(tuple_tie),
|
||||
tuple<decltype(tuple0)&,
|
||||
decltype(tuple1)&,
|
||||
decltype(tuple2)&,
|
||||
decltype(tuple3)&> >::value) );
|
||||
VERIFY_IS_EQUAL( (tuple_impl::get<1>(tuple_impl::get<2>(tuple_tie))), 5.0f );
|
||||
// Modify value and ensure tuple2 is updated.
|
||||
tuple_impl::get<1>(tuple_impl::get<2>(tuple_tie)) = 10.0f;
|
||||
VERIFY_IS_EQUAL( (tuple_impl::get<1>(tuple2)), 10.0f );
|
||||
|
||||
// Assignment.
|
||||
int x = -1;
|
||||
float y = -1;
|
||||
double z = -1;
|
||||
tuple_impl::tie(x, y, z) = tuple3;
|
||||
VERIFY_IS_EQUAL(x, tuple_impl::get<0>(tuple3));
|
||||
VERIFY_IS_EQUAL(y, tuple_impl::get<1>(tuple3));
|
||||
VERIFY_IS_EQUAL(z, tuple_impl::get<2>(tuple3));
|
||||
tuple<int, float, double> tuple3c(-2, -2.0f, -2.0);
|
||||
tuple3c = std::move(tuple3b);
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<0>(tuple3c), tuple_impl::get<0>(tuple3));
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<1>(tuple3c), tuple_impl::get<1>(tuple3));
|
||||
VERIFY_IS_EQUAL(tuple_impl::get<2>(tuple3c), tuple_impl::get<2>(tuple3));
|
||||
}
|
||||
|
||||
void eigen_tuple_test() {
|
||||
tuple<Eigen::Matrix3d, Eigen::MatrixXd> tuple;
|
||||
tuple_impl::get<0>(tuple).setRandom();
|
||||
tuple_impl::get<1>(tuple).setRandom(10, 10);
|
||||
|
||||
auto tuple_tie = tuple_impl::tie(tuple_impl::get<0>(tuple), tuple_impl::get<1>(tuple));
|
||||
tuple_impl::get<1>(tuple_tie).setIdentity();
|
||||
VERIFY(tuple_impl::get<1>(tuple).isIdentity());
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(tuple)
|
||||
{
|
||||
CALL_SUBTEST(basic_tuple_test());
|
||||
CALL_SUBTEST(eigen_tuple_test());
|
||||
}
|
||||
@@ -18,8 +18,6 @@ EIGEN_DECLARE_TEST(type_alias)
|
||||
STATIC_CHECK((is_same<Matrix2f,Matrix<float,2,2> >::value));
|
||||
STATIC_CHECK((is_same<Array33i,Array<int,3,3> >::value));
|
||||
|
||||
#if EIGEN_HAS_CXX11
|
||||
|
||||
STATIC_CHECK((is_same<MatrixX<double>, MatrixXd>::value));
|
||||
STATIC_CHECK((is_same<MatrixX<int>, MatrixXi>::value));
|
||||
STATIC_CHECK((is_same<Matrix2<int>, Matrix2i>::value));
|
||||
@@ -42,7 +40,4 @@ EIGEN_DECLARE_TEST(type_alias)
|
||||
STATIC_CHECK((is_same<RowVector<float,3>, RowVector3f>::value));
|
||||
STATIC_CHECK((is_same<RowVector<int,Dynamic>, RowVectorXi>::value));
|
||||
|
||||
#else
|
||||
std::cerr << "WARNING: c++11 type aliases not tested.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
38
libs/eigen/test/unaryviewstride.cpp
Normal file
38
libs/eigen/test/unaryviewstride.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 Andrew Johnson <andrew.johnson@arjohnsonau.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 OuterStride,int InnerStride,typename VectorType> void unaryview_stride(const VectorType& m)
|
||||
{
|
||||
typedef typename VectorType::Scalar Scalar;
|
||||
Index rows = m.rows();
|
||||
Index cols = m.cols();
|
||||
VectorType vec = VectorType::Random(rows, cols);
|
||||
|
||||
struct view_op {
|
||||
EIGEN_DEVICE_FUNC
|
||||
EIGEN_STRONG_INLINE const Scalar&
|
||||
operator()(const Scalar& v) const { return v; }
|
||||
};
|
||||
|
||||
CwiseUnaryView<view_op, VectorType, Stride<OuterStride,InnerStride>> vec_view(vec);
|
||||
VERIFY(vec_view.outerStride() == (OuterStride == 0 ? 0 : OuterStride));
|
||||
VERIFY(vec_view.innerStride() == (InnerStride == 0 ? 1 : InnerStride));
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(unaryviewstride)
|
||||
{
|
||||
CALL_SUBTEST_1(( unaryview_stride<1,2>(MatrixXf()) ));
|
||||
CALL_SUBTEST_1(( unaryview_stride<0,0>(MatrixXf()) ));
|
||||
CALL_SUBTEST_2(( unaryview_stride<1,2>(VectorXf()) ));
|
||||
CALL_SUBTEST_2(( unaryview_stride<0,0>(VectorXf()) ));
|
||||
CALL_SUBTEST_3(( unaryview_stride<1,2>(RowVectorXf()) ));
|
||||
CALL_SUBTEST_3(( unaryview_stride<0,0>(RowVectorXf()) ));
|
||||
}
|
||||
@@ -39,11 +39,15 @@ bool test_assign(const Dst&, const Src&, int traversal, int unrolling)
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src);
|
||||
typedef internal::copy_using_evaluator_traits<internal::evaluator<Dst>,internal::evaluator<Src>, internal::assign_op<typename Dst::Scalar,typename Src::Scalar> > traits;
|
||||
bool res = traits::Traversal==traversal;
|
||||
if(unrolling==InnerUnrolling+CompleteUnrolling)
|
||||
res = res && (int(traits::Unrolling)==InnerUnrolling || int(traits::Unrolling)==CompleteUnrolling);
|
||||
else
|
||||
res = res && int(traits::Unrolling)==unrolling;
|
||||
// If traversal or unrolling are negative, ignore.
|
||||
bool res = traversal > -1 ? traits::Traversal==traversal : true;
|
||||
if (unrolling > -1) {
|
||||
if(unrolling==InnerUnrolling+CompleteUnrolling) {
|
||||
res = res && (int(traits::Unrolling)==InnerUnrolling || int(traits::Unrolling)==CompleteUnrolling);
|
||||
} else {
|
||||
res = res && int(traits::Unrolling)==unrolling;
|
||||
}
|
||||
}
|
||||
if(!res)
|
||||
{
|
||||
std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl;
|
||||
@@ -178,21 +182,15 @@ struct vectorization_logic
|
||||
typedef Matrix<Scalar,3,1,ColMajor> Vector3;
|
||||
VERIFY(test_assign(Matrix33c().row(2),Matrix33c().row(1)+Matrix33c().row(1),
|
||||
LinearTraversal,CompleteUnrolling));
|
||||
VERIFY(test_assign(Vector3(),Vector3()+Vector3(),
|
||||
sizeof(Scalar)==16 ? InnerVectorizedTraversal : (EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : LinearTraversal), CompleteUnrolling));
|
||||
VERIFY(test_assign(Matrix33c().col(0),Matrix33c().col(1)+Matrix33c().col(1),
|
||||
EIGEN_UNALIGNED_VECTORIZE ? (sizeof(Scalar)==16 ? InnerVectorizedTraversal : LinearVectorizedTraversal)
|
||||
: (sizeof(Scalar)==16 ? SliceVectorizedTraversal : LinearTraversal),
|
||||
((!EIGEN_UNALIGNED_VECTORIZE) && (sizeof(Scalar)==16)) ? NoUnrolling : CompleteUnrolling));
|
||||
// Vectorization depends on too many factors - ignore.
|
||||
VERIFY(test_assign(Vector3(),Vector3()+Vector3(), -1, CompleteUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix3(),Matrix3().cwiseProduct(Matrix3()),
|
||||
LinearVectorizedTraversal,CompleteUnrolling));
|
||||
|
||||
// Vectorization depends on too many factors - ignore.
|
||||
VERIFY(test_assign(Matrix<Scalar,17,17>(),Matrix<Scalar,17,17>()+Matrix<Scalar,17,17>(),
|
||||
sizeof(Scalar)==16 ? InnerVectorizedTraversal :
|
||||
EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal :
|
||||
LinearTraversal,
|
||||
NoUnrolling));
|
||||
-1, NoUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix11(), Matrix11()+Matrix11(),InnerVectorizedTraversal,CompleteUnrolling));
|
||||
|
||||
@@ -245,11 +243,11 @@ struct vectorization_logic
|
||||
>(InnerVectorizedTraversal,CompleteUnrolling)));
|
||||
|
||||
VERIFY((test_assign<
|
||||
Map<Matrix<Scalar,EIGEN_PLAIN_ENUM_MAX(2,PacketSize),EIGEN_PLAIN_ENUM_MAX(2,PacketSize)>, AlignedMax, InnerStride<3*PacketSize> >,
|
||||
Matrix<Scalar,EIGEN_PLAIN_ENUM_MAX(2,PacketSize),EIGEN_PLAIN_ENUM_MAX(2,PacketSize)>
|
||||
Map<Matrix<Scalar, internal::plain_enum_max(2,PacketSize), internal::plain_enum_max(2, PacketSize)>, AlignedMax, InnerStride<3*PacketSize> >,
|
||||
Matrix<Scalar, internal::plain_enum_max(2, PacketSize), internal::plain_enum_max(2, PacketSize)>
|
||||
>(DefaultTraversal,PacketSize>=8?InnerUnrolling:CompleteUnrolling)));
|
||||
|
||||
VERIFY((test_assign(Matrix11(), Matrix<Scalar,PacketSize,EIGEN_PLAIN_ENUM_MIN(2,PacketSize)>()*Matrix<Scalar,EIGEN_PLAIN_ENUM_MIN(2,PacketSize),PacketSize>(),
|
||||
VERIFY((test_assign(Matrix11(), Matrix<Scalar,PacketSize, internal::plain_enum_min(2, PacketSize)>()*Matrix<Scalar, internal::plain_enum_min(2, PacketSize),PacketSize>(),
|
||||
InnerVectorizedTraversal, CompleteUnrolling)));
|
||||
#endif
|
||||
|
||||
@@ -277,12 +275,20 @@ struct vectorization_logic_half
|
||||
};
|
||||
static void run()
|
||||
{
|
||||
// Some half-packets have a byte size < EIGEN_MIN_ALIGN_BYTES (e.g. Packet2f),
|
||||
// which causes many of these tests to fail since they don't vectorize if
|
||||
// EIGEN_UNALIGNED_VECTORIZE is 0 (the matrix is assumed unaligned).
|
||||
// Adjust the matrix sizes to account for these alignment issues.
|
||||
constexpr int PacketBytes = sizeof(Scalar)*PacketSize;
|
||||
constexpr int MinVSize = EIGEN_UNALIGNED_VECTORIZE ? PacketSize
|
||||
: PacketBytes >= EIGEN_MIN_ALIGN_BYTES ? PacketSize
|
||||
: (EIGEN_MIN_ALIGN_BYTES + sizeof(Scalar) - 1) / sizeof(Scalar);
|
||||
|
||||
typedef Matrix<Scalar,PacketSize,1> Vector1;
|
||||
typedef Matrix<Scalar,PacketSize,PacketSize> Matrix11;
|
||||
typedef Matrix<Scalar,5*PacketSize,7,ColMajor> Matrix57;
|
||||
typedef Matrix<Scalar,3*PacketSize,5,ColMajor> Matrix35;
|
||||
typedef Matrix<Scalar,5*PacketSize,7,DontAlign|ColMajor> Matrix57u;
|
||||
typedef Matrix<Scalar,MinVSize,1> Vector1;
|
||||
typedef Matrix<Scalar,MinVSize,MinVSize> Matrix11;
|
||||
typedef Matrix<Scalar,5*MinVSize,7,ColMajor> Matrix57;
|
||||
typedef Matrix<Scalar,3*MinVSize,5,ColMajor> Matrix35;
|
||||
typedef Matrix<Scalar,5*MinVSize,7,DontAlign|ColMajor> Matrix57u;
|
||||
|
||||
typedef Matrix<Scalar,
|
||||
(PacketSize==16 ? 8 : PacketSize==8 ? 4 : PacketSize==4 ? 2 : PacketSize==2 ? 1 : /*PacketSize==1 ?*/ 1),
|
||||
@@ -296,20 +302,20 @@ struct vectorization_logic_half
|
||||
|
||||
// this type is made such that it can only be vectorized when viewed as a linear 1D vector
|
||||
typedef Matrix<Scalar,
|
||||
(PacketSize==16 ? 4 : PacketSize==8 ? 4 : PacketSize==4 ? 6 : PacketSize==2 ? ((Matrix11::Flags&RowMajorBit)?2:3) : /*PacketSize==1 ?*/ 1),
|
||||
(PacketSize==16 ? 12 : PacketSize==8 ? 6 : PacketSize==4 ? 2 : PacketSize==2 ? ((Matrix11::Flags&RowMajorBit)?3:2) : /*PacketSize==1 ?*/ 3)
|
||||
(MinVSize==16 ? 4 : MinVSize==8 ? 4 : MinVSize==4 ? 6 : MinVSize==2 ? ((Matrix11::Flags&RowMajorBit)?2:3) : /*PacketSize==1 ?*/ 1),
|
||||
(MinVSize==16 ? 12 : MinVSize==8 ? 6 : MinVSize==4 ? 2 : MinVSize==2 ? ((Matrix11::Flags&RowMajorBit)?3:2) : /*PacketSize==1 ?*/ 3)
|
||||
> Matrix3;
|
||||
|
||||
#if !EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT
|
||||
#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().template segment<PacketSize>(0).derived(),
|
||||
VERIFY(test_assign(Vector1(),Vector1().template segment<MinVSize>(0).derived(),
|
||||
EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearVectorizedTraversal,CompleteUnrolling));
|
||||
VERIFY(test_assign(Vector1(),Scalar(2.1)*Vector1()-Vector1(),
|
||||
InnerVectorizedTraversal,CompleteUnrolling));
|
||||
VERIFY(test_assign(Vector1(),(Scalar(2.1)*Vector1().template segment<PacketSize>(0)-Vector1().template segment<PacketSize>(0)).derived(),
|
||||
VERIFY(test_assign(Vector1(),(Scalar(2.1)*Vector1().template segment<MinVSize>(0)-Vector1().template segment<MinVSize>(0)).derived(),
|
||||
EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearVectorizedTraversal,CompleteUnrolling));
|
||||
VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()),
|
||||
InnerVectorizedTraversal,CompleteUnrolling));
|
||||
@@ -331,19 +337,16 @@ struct vectorization_logic_half
|
||||
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),
|
||||
EIGEN_UNALIGNED_VECTORIZE ? (sizeof(Scalar)==16 ? InnerVectorizedTraversal : LinearVectorizedTraversal)
|
||||
: (sizeof(Scalar)==16 ? SliceVectorizedTraversal : LinearTraversal),
|
||||
((!EIGEN_UNALIGNED_VECTORIZE) && (sizeof(Scalar)==16)) ? NoUnrolling : CompleteUnrolling));
|
||||
|
||||
|
||||
// Unrolling depends on read costs and unroll limits, which vary - ignore.
|
||||
VERIFY(test_assign(Matrix3(),Matrix3().cwiseQuotient(Matrix3()),
|
||||
PacketTraits::HasDiv ? LinearVectorizedTraversal : LinearTraversal,CompleteUnrolling));
|
||||
PacketTraits::HasDiv ? LinearVectorizedTraversal : LinearTraversal, -1));
|
||||
|
||||
VERIFY(test_assign(Matrix<Scalar,17,17>(),Matrix<Scalar,17,17>()+Matrix<Scalar,17,17>(),
|
||||
sizeof(Scalar)==16 ? InnerVectorizedTraversal : (EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : LinearTraversal),
|
||||
NoUnrolling));
|
||||
|
||||
VERIFY(test_assign(Matrix11(),Matrix<Scalar,17,17>().template block<PacketSize,PacketSize>(2,3)+Matrix<Scalar,17,17>().template block<PacketSize,PacketSize>(8,4),
|
||||
VERIFY(test_assign(Matrix11(),Matrix<Scalar,17,17>().template block<MinVSize,MinVSize>(2,3)+Matrix<Scalar,17,17>().template block<MinVSize,MinVSize>(8,4),
|
||||
EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : DefaultTraversal,InnerUnrolling+CompleteUnrolling));
|
||||
|
||||
|
||||
@@ -357,7 +360,7 @@ struct vectorization_logic_half
|
||||
VERIFY(test_redux(Vector1(),
|
||||
LinearVectorizedTraversal,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_redux(Matrix<Scalar,PacketSize,3>(),
|
||||
VERIFY(test_redux(Matrix<Scalar,MinVSize,3>(),
|
||||
LinearVectorizedTraversal,CompleteUnrolling));
|
||||
|
||||
VERIFY(test_redux(Matrix3(),
|
||||
@@ -375,13 +378,14 @@ struct vectorization_logic_half
|
||||
}
|
||||
|
||||
VERIFY((test_assign<
|
||||
Map<Matrix<Scalar,EIGEN_PLAIN_ENUM_MAX(2,PacketSize),EIGEN_PLAIN_ENUM_MAX(2,PacketSize)>, AlignedMax, InnerStride<3*PacketSize> >,
|
||||
Matrix<Scalar,EIGEN_PLAIN_ENUM_MAX(2,PacketSize),EIGEN_PLAIN_ENUM_MAX(2,PacketSize)>
|
||||
>(DefaultTraversal,PacketSize>4?InnerUnrolling:CompleteUnrolling)));
|
||||
Map<Matrix<Scalar, internal::plain_enum_max(2, PacketSize), internal::plain_enum_max(2, PacketSize)>,
|
||||
AlignedMax, InnerStride<3 * PacketSize> >,
|
||||
Matrix<Scalar, internal::plain_enum_max(2, PacketSize), internal::plain_enum_max(2, PacketSize)> >(
|
||||
DefaultTraversal, PacketSize > 4 ? InnerUnrolling : CompleteUnrolling)));
|
||||
|
||||
VERIFY((test_assign(Matrix57(), Matrix<Scalar,5*PacketSize,3>()*Matrix<Scalar,3,7>(),
|
||||
InnerVectorizedTraversal, InnerUnrolling+CompleteUnrolling)));
|
||||
#endif
|
||||
VERIFY((test_assign(Matrix57(), Matrix<Scalar, 5 * MinVSize, 3>() * Matrix<Scalar, 3, 7>(),
|
||||
InnerVectorizedTraversal, InnerUnrolling + CompleteUnrolling)));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#define TEST_ENABLE_TEMPORARY_TRACKING
|
||||
#define EIGEN_NO_STATIC_ASSERT
|
||||
|
||||
#include "main.h"
|
||||
|
||||
@@ -32,77 +31,49 @@ template<typename ArrayType> void vectorwiseop_array(const ArrayType& m)
|
||||
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
|
||||
|
||||
// test subtraction
|
||||
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());
|
||||
|
||||
m2 = m1;
|
||||
// yes, there might be an aliasing issue there but ".rowwise() /="
|
||||
// is supposed to evaluate " m2.colwise().sum()" into a temporary to avoid
|
||||
@@ -158,58 +129,30 @@ template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
|
||||
m2.rowwise() = rowvec;
|
||||
for(Index i=0; i<rows; ++i)
|
||||
VERIFY_IS_APPROX(m2.row(i), rowvec);
|
||||
if(rows>1)
|
||||
VERIFY_RAISES_ASSERT(m2.colwise() = colvec.transpose());
|
||||
if(cols>1)
|
||||
VERIFY_RAISES_ASSERT(m2.rowwise() = rowvec.transpose());
|
||||
|
||||
// test addition
|
||||
|
||||
m2 = m1;
|
||||
m2.colwise() += colvec;
|
||||
VERIFY_IS_APPROX(m2, m1.colwise() + colvec);
|
||||
VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec);
|
||||
|
||||
if(rows>1)
|
||||
{
|
||||
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);
|
||||
|
||||
if(cols>1)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose());
|
||||
VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose());
|
||||
}
|
||||
|
||||
// test substraction
|
||||
|
||||
// test subtraction
|
||||
m2 = m1;
|
||||
m2.colwise() -= colvec;
|
||||
VERIFY_IS_APPROX(m2, m1.colwise() - colvec);
|
||||
VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec);
|
||||
|
||||
if(rows>1)
|
||||
{
|
||||
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);
|
||||
|
||||
if(cols>1)
|
||||
{
|
||||
VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose());
|
||||
VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose());
|
||||
}
|
||||
|
||||
// ------ partial reductions ------
|
||||
|
||||
@@ -272,11 +215,8 @@ template<typename MatrixType> void vectorwiseop_matrix(const MatrixType& m)
|
||||
VERIFY_IS_APPROX(m1.matrix().middleRows(0,0).colwise().prod().eval(), MatrixX::Ones(1,cols));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,fix<0>).rowwise().prod().eval(), MatrixX::Ones(rows,1));
|
||||
VERIFY_IS_APPROX(m1.matrix().middleRows(0,fix<0>).colwise().prod().eval(), MatrixX::Ones(1,cols));
|
||||
|
||||
VERIFY_IS_APPROX(m1.matrix().middleCols(0,0).rowwise().squaredNorm().eval(), MatrixX::Zero(rows,1));
|
||||
|
||||
VERIFY_RAISES_ASSERT(m1.real().middleCols(0,0).rowwise().minCoeff().eval());
|
||||
VERIFY_RAISES_ASSERT(m1.real().middleRows(0,0).colwise().maxCoeff().eval());
|
||||
VERIFY_IS_EQUAL(m1.real().middleRows(0,0).rowwise().maxCoeff().eval().rows(),0);
|
||||
VERIFY_IS_EQUAL(m1.real().middleCols(0,0).colwise().maxCoeff().eval().cols(),0);
|
||||
VERIFY_IS_EQUAL(m1.real().middleRows(0,fix<0>).rowwise().maxCoeff().eval().rows(),0);
|
||||
|
||||
@@ -21,7 +21,7 @@ template<typename MatrixType> void matrixVisitor(const MatrixType& p)
|
||||
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, ==
|
||||
while(numext::equal_strict(m(i), m(i2))) // yes, strict equality
|
||||
m(i) = internal::random<Scalar>();
|
||||
|
||||
Scalar minc = Scalar(1000), maxc = Scalar(-1000);
|
||||
@@ -173,6 +173,155 @@ template<typename VectorType> void vectorVisitor(const VectorType& w)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, bool Vectorizable>
|
||||
struct TrackedVisitor {
|
||||
void init(T v, Index i, Index j) { return this->operator()(v,i,j); }
|
||||
void operator()(T v, Index i, Index j) {
|
||||
EIGEN_UNUSED_VARIABLE(v)
|
||||
visited.push_back({i, j});
|
||||
vectorized = false;
|
||||
}
|
||||
|
||||
template<typename Packet>
|
||||
void packet(Packet p, Index i, Index j) {
|
||||
EIGEN_UNUSED_VARIABLE(p)
|
||||
visited.push_back({i, j});
|
||||
vectorized = true;
|
||||
}
|
||||
std::vector<std::pair<int,int>> visited;
|
||||
bool vectorized;
|
||||
};
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
|
||||
template<typename T, bool Vectorizable>
|
||||
struct functor_traits<TrackedVisitor<T, Vectorizable> > {
|
||||
enum { PacketAccess = Vectorizable, Cost = 1 };
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
void checkOptimalTraversal() {
|
||||
|
||||
// Unrolled - ColMajor.
|
||||
{
|
||||
using MatrixType = Matrix<float, 4, 4, ColMajor>;
|
||||
MatrixType X = MatrixType::Random(4, 4);
|
||||
TrackedVisitor<MatrixType::Scalar, false> visitor;
|
||||
X.visit(visitor);
|
||||
Index count = 0;
|
||||
for (Index j=0; j<X.cols(); ++j) {
|
||||
for (Index i=0; i<X.rows(); ++i) {
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].first, i);
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].second, j);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unrolled - RowMajor.
|
||||
{
|
||||
using MatrixType = Matrix<float, 4, 4, RowMajor>;
|
||||
MatrixType X = MatrixType::Random(4, 4);
|
||||
TrackedVisitor<MatrixType::Scalar, false> visitor;
|
||||
X.visit(visitor);
|
||||
Index count = 0;
|
||||
for (Index i=0; i<X.rows(); ++i) {
|
||||
for (Index j=0; j<X.cols(); ++j) {
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].first, i);
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].second, j);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not unrolled - ColMajor
|
||||
{
|
||||
using MatrixType = Matrix<float, Dynamic, Dynamic, ColMajor>;
|
||||
MatrixType X = MatrixType::Random(4, 4);
|
||||
TrackedVisitor<MatrixType::Scalar, false> visitor;
|
||||
X.visit(visitor);
|
||||
Index count = 0;
|
||||
for (Index j=0; j<X.cols(); ++j) {
|
||||
for (Index i=0; i<X.rows(); ++i) {
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].first, i);
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].second, j);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not unrolled - RowMajor.
|
||||
{
|
||||
using MatrixType = Matrix<float, Dynamic, Dynamic, RowMajor>;
|
||||
MatrixType X = MatrixType::Random(4, 4);
|
||||
TrackedVisitor<MatrixType::Scalar, false> visitor;
|
||||
X.visit(visitor);
|
||||
Index count = 0;
|
||||
for (Index i=0; i<X.rows(); ++i) {
|
||||
for (Index j=0; j<X.cols(); ++j) {
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].first, i);
|
||||
VERIFY_IS_EQUAL(visitor.visited[count].second, j);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vectorized - ColMajor
|
||||
{
|
||||
using MatrixType = Matrix<float, Dynamic, Dynamic, ColMajor>;
|
||||
// Ensure rows/cols is larger than packet size.
|
||||
constexpr int PacketSize = Eigen::internal::packet_traits<MatrixType::Scalar>::size;
|
||||
MatrixType X = MatrixType::Random(4 * PacketSize, 4 * PacketSize);
|
||||
TrackedVisitor<MatrixType::Scalar, true> visitor;
|
||||
X.visit(visitor);
|
||||
Index previ = -1;
|
||||
Index prevj = 0;
|
||||
for (const auto& p : visitor.visited) {
|
||||
Index i = p.first;
|
||||
Index j = p.second;
|
||||
VERIFY(
|
||||
(j == prevj && i == previ + 1) // Advance single element
|
||||
|| (j == prevj && i == previ + PacketSize) // Advance packet
|
||||
|| (j == prevj + 1 && i == 0) // Advance column
|
||||
);
|
||||
previ = i;
|
||||
prevj = j;
|
||||
}
|
||||
if (Eigen::internal::packet_traits<MatrixType::Scalar>::Vectorizable) {
|
||||
VERIFY(visitor.vectorized);
|
||||
}
|
||||
}
|
||||
|
||||
// Vectorized - RowMajor.
|
||||
{
|
||||
using MatrixType = Matrix<float, Dynamic, Dynamic, RowMajor>;
|
||||
// Ensure rows/cols is larger than packet size.
|
||||
constexpr int PacketSize = Eigen::internal::packet_traits<MatrixType::Scalar>::size;
|
||||
MatrixType X = MatrixType::Random(4 * PacketSize, 4 * PacketSize);
|
||||
TrackedVisitor<MatrixType::Scalar, true> visitor;
|
||||
X.visit(visitor);
|
||||
Index previ = 0;
|
||||
Index prevj = -1;
|
||||
for (const auto& p : visitor.visited) {
|
||||
Index i = p.first;
|
||||
Index j = p.second;
|
||||
VERIFY(
|
||||
(i == previ && j == prevj + 1) // Advance single element
|
||||
|| (i == previ && j == prevj + PacketSize) // Advance packet
|
||||
|| (i == previ + 1 && j == 0) // Advance row
|
||||
);
|
||||
previ = i;
|
||||
prevj = j;
|
||||
}
|
||||
if (Eigen::internal::packet_traits<MatrixType::Scalar>::Vectorizable) {
|
||||
VERIFY(visitor.vectorized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(visitor)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@@ -190,4 +339,5 @@ EIGEN_DECLARE_TEST(visitor)
|
||||
CALL_SUBTEST_9( vectorVisitor(RowVectorXd(10)) );
|
||||
CALL_SUBTEST_10( vectorVisitor(VectorXf(33)) );
|
||||
}
|
||||
CALL_SUBTEST_11(checkOptimalTraversal());
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ template<typename MatrixType> void zeroSizedMatrix()
|
||||
if (MatrixType::RowsAtCompileTime == Dynamic && MatrixType::ColsAtCompileTime == Dynamic)
|
||||
{
|
||||
|
||||
MatrixType t2(0, 0), t3(t1);
|
||||
MatrixType t2(0, 0);
|
||||
VERIFY(t2.rows() == 0);
|
||||
VERIFY(t2.cols() == 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user