initial commit

This commit is contained in:
huangweifeng
2026-10-22 09:23:54 +08:00
commit 63f557a39f
4448 changed files with 584487 additions and 0 deletions
+204
View File
@@ -0,0 +1,204 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011-2018 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_TEST_ANNOYING_SCALAR_H
#define EIGEN_TEST_ANNOYING_SCALAR_H
#include <ostream>
#if EIGEN_COMP_GNUC
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#if defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW)
struct my_exception {
my_exception() {}
~my_exception() {}
};
#endif
// An AnnoyingScalar is a pseudo scalar type that:
// - can randomly through an exception in operator +
// - randomly allocate on the heap or initialize a reference to itself making it non trivially copyable, nor movable,
// nor relocatable.
class AnnoyingScalar {
public:
AnnoyingScalar() {
init();
*v = 0;
}
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 = 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) delete v;
instances--;
}
void init() {
if (internal::random<bool>())
v = new float;
else
v = &data;
instances++;
}
AnnoyingScalar operator+(const AnnoyingScalar& other) const {
#if defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW)
countdown--;
if (countdown <= 0 && !dont_throw) throw my_exception();
#endif
return AnnoyingScalar(*v + *other.v);
}
AnnoyingScalar operator-() const { return AnnoyingScalar(-*v); }
AnnoyingScalar operator-(const AnnoyingScalar& other) const { return AnnoyingScalar(*v - *other.v); }
AnnoyingScalar operator*(const AnnoyingScalar& other) const { return AnnoyingScalar((*v) * (*other.v)); }
AnnoyingScalar operator/(const AnnoyingScalar& other) const { return AnnoyingScalar((*v) / (*other.v)); }
AnnoyingScalar& operator+=(const AnnoyingScalar& other) {
*v += *other.v;
return *this;
}
AnnoyingScalar& operator-=(const AnnoyingScalar& other) {
*v -= *other.v;
return *this;
}
AnnoyingScalar& operator*=(const AnnoyingScalar& other) {
*v *= *other.v;
return *this;
}
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 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; }
bool operator>(const AnnoyingScalar& other) const { return *v > *other.v; }
float* v;
float data;
static int instances;
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
static int countdown;
static bool dont_throw;
#endif
};
AnnoyingScalar real(const AnnoyingScalar& x) { return x; }
AnnoyingScalar imag(const AnnoyingScalar&) { return 0; }
AnnoyingScalar conj(const AnnoyingScalar& x) { return x; }
AnnoyingScalar sqrt(const AnnoyingScalar& x) { return std::sqrt(*x.v); }
AnnoyingScalar abs(const AnnoyingScalar& x) { return std::abs(*x.v); }
AnnoyingScalar cos(const AnnoyingScalar& x) { return std::cos(*x.v); }
AnnoyingScalar sin(const AnnoyingScalar& x) { return std::sin(*x.v); }
AnnoyingScalar acos(const AnnoyingScalar& x) { return std::acos(*x.v); }
AnnoyingScalar atan2(const AnnoyingScalar& y, const AnnoyingScalar& x) { return std::atan2(*y.v, *x.v); }
std::ostream& operator<<(std::ostream& stream, const AnnoyingScalar& x) {
stream << (*(x.v));
return stream;
}
int AnnoyingScalar::instances = 0;
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
int AnnoyingScalar::countdown = 0;
bool AnnoyingScalar::dont_throw = false;
#endif
namespace Eigen {
template <>
struct NumTraits<AnnoyingScalar> : NumTraits<float> {
enum {
RequireInitialization = 1,
};
typedef AnnoyingScalar Real;
typedef AnnoyingScalar Nested;
typedef AnnoyingScalar Literal;
typedef AnnoyingScalar NonInteger;
};
template <>
inline AnnoyingScalar test_precision<AnnoyingScalar>() {
return test_precision<float>();
}
namespace numext {
template <>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool(isfinite)(const AnnoyingScalar& x) {
return (numext::isfinite)(*x.v);
}
} // namespace numext
namespace internal {
template <>
EIGEN_STRONG_INLINE double cast(const AnnoyingScalar& x) {
return double(*x.v);
}
template <>
EIGEN_STRONG_INLINE float cast(const AnnoyingScalar& x) {
return *x.v;
}
} // namespace internal
} // namespace Eigen
AnnoyingScalar get_test_precision(const AnnoyingScalar&) { return Eigen::test_precision<AnnoyingScalar>(); }
AnnoyingScalar test_relative_error(const AnnoyingScalar& a, const AnnoyingScalar& b) {
return test_relative_error(*a.v, *b.v);
}
inline bool test_isApprox(const AnnoyingScalar& a, const AnnoyingScalar& b) {
return internal::isApprox(*a.v, *b.v, test_precision<float>());
}
inline bool test_isMuchSmallerThan(const AnnoyingScalar& a, const AnnoyingScalar& b) {
return test_isMuchSmallerThan(*a.v, *b.v);
}
#endif // EIGEN_TEST_ANNOYING_SCALAR_H
+504
View File
@@ -0,0 +1,504 @@
# The file split_test_helper.h was generated at first run,
# it is now included in test/
if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h)
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h)
endif()
# check if we have a Fortran compiler
include(CheckLanguage)
check_language(Fortran)
if(CMAKE_Fortran_COMPILER)
enable_language(Fortran)
set(EIGEN_Fortran_COMPILER_WORKS ON)
else()
set(EIGEN_Fortran_COMPILER_WORKS OFF)
# search for a default Lapack library to complete Eigen's one
find_package(LAPACK QUIET)
endif()
# TODO do the same for EXTERNAL_LAPACK
option(EIGEN_TEST_EXTERNAL_BLAS "Use external BLAS library for testsuite" OFF)
if(EIGEN_TEST_EXTERNAL_BLAS)
find_package(BLAS REQUIRED)
message(STATUS "BLAS_COMPILER_FLAGS: ${BLAS_COMPILER_FLAGS}")
add_definitions("-DEIGEN_USE_BLAS") # is adding ${BLAS_COMPILER_FLAGS} necessary?
list(APPEND EXTERNAL_LIBS "${BLAS_LIBRARIES}")
endif()
# configure blas/lapack (use Eigen's ones)
set(EIGEN_BLAS_LIBRARIES eigen_blas)
set(EIGEN_LAPACK_LIBRARIES eigen_lapack)
set(EIGEN_TEST_MATRIX_DIR "" CACHE STRING "Enable testing of realword sparse matrices contained in the specified path")
if(EIGEN_TEST_MATRIX_DIR)
if(NOT WIN32)
message(STATUS "Test realworld sparse matrices: ${EIGEN_TEST_MATRIX_DIR}")
add_definitions( -DTEST_REAL_CASES="${EIGEN_TEST_MATRIX_DIR}" )
else()
message(STATUS "REAL CASES CAN NOT BE CURRENTLY TESTED ON WIN32")
endif()
endif()
set(SPARSE_LIBS " ")
find_package(CHOLMOD)
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 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 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 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()
find_package(PASTIX QUIET COMPONENTS METIS SEQ)
# check that the PASTIX found is a version without MPI
find_path(PASTIX_pastix_nompi.h_INCLUDE_DIRS
NAMES pastix_nompi.h
HINTS ${PASTIX_INCLUDE_DIRS}
)
if (NOT PASTIX_pastix_nompi.h_INCLUDE_DIRS)
message(STATUS "A version of Pastix has been found but pastix_nompi.h does not exist in the include directory."
" Because Eigen tests require a version without MPI, we disable the Pastix backend.")
endif()
if(PASTIX_FOUND AND PASTIX_pastix_nompi.h_INCLUDE_DIRS)
add_definitions("-DEIGEN_PASTIX_SUPPORT")
include_directories(${PASTIX_INCLUDE_DIRS_DEP})
if(SCOTCH_FOUND)
include_directories(${SCOTCH_INCLUDE_DIRS})
set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${SCOTCH_LIBRARIES})
elseif(METIS_FOUND)
include_directories(${METIS_INCLUDE_DIRS})
set(PASTIX_LIBRARIES ${PASTIX_LIBRARIES} ${METIS_LIBRARIES})
else()
ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ")
endif()
set(SPARSE_LIBS ${SPARSE_LIBS} ${PASTIX_LIBRARIES_DEP} ${ORDERING_LIBRARIES})
set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES_DEP})
ei_add_property(EIGEN_TESTED_BACKENDS "PaStiX, ")
else()
ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ")
endif()
if(METIS_FOUND)
add_definitions("-DEIGEN_METIS_SUPPORT")
include_directories(${METIS_INCLUDE_DIRS})
ei_add_property(EIGEN_TESTED_BACKENDS "METIS, ")
else()
ei_add_property(EIGEN_MISSING_BACKENDS "METIS, ")
endif()
find_package(SPQR)
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})
set(SPARSE_LIBS ${SPARSE_LIBS} ${SPQR_ALL_LIBS})
ei_add_property(EIGEN_TESTED_BACKENDS "SPQR, ")
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)
if(QT4_FOUND)
include(${QT_USE_FILE})
ei_add_property(EIGEN_TESTED_BACKENDS "Qt4 support, ")
else()
ei_add_property(EIGEN_MISSING_BACKENDS "Qt4 support, ")
endif()
endif()
if(TEST_LIB)
add_definitions("-DEIGEN_EXTERN_INSTANTIATIONS=1")
endif()
set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Official")
add_custom_target(BuildOfficial)
ei_add_test(clz)
ei_add_test(rand)
ei_add_test(meta)
ei_add_test(maxsizevector)
ei_add_test(numext)
ei_add_test(sizeof)
ei_add_test(dynalloc)
ei_add_test(nomalloc)
ei_add_test(first_aligned)
ei_add_test(type_alias)
ei_add_test(nullary)
ei_add_test(mixingtypes)
ei_add_test(float_conversion)
ei_add_test(io)
ei_add_test(packetmath "-DEIGEN_FAST_MATH=1")
ei_add_test(packet_segment)
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)
ei_add_test(unalignedcount)
if(NOT EIGEN_TEST_NO_EXCEPTIONS AND NOT EIGEN_TEST_OPENMP)
ei_add_test(exceptions)
endif()
ei_add_test(redux)
ei_add_test(visitor)
ei_add_test(block)
ei_add_test(corners)
ei_add_test(symbolic_index)
ei_add_test(indexed_view)
ei_add_test(reshape)
ei_add_test(swap)
ei_add_test(resize)
ei_add_test(conservative_resize)
ei_add_test(product_small)
ei_add_test(product_large)
ei_add_test(product_extra)
ei_add_test(diagonalmatrices)
ei_add_test(skew_symmetric_matrix3)
ei_add_test(adjoint)
ei_add_test(diagonal)
ei_add_test(miscmatrices)
ei_add_test(commainitializer)
ei_add_test(smallvectors)
ei_add_test(mapped_matrix)
ei_add_test(mapstride)
ei_add_test(unaryview)
ei_add_test(mapstaticmethods)
ei_add_test(array_cwise)
ei_add_test(matrix_cwise)
ei_add_test(array_for_matrix)
ei_add_test(array_replicate)
ei_add_test(array_reverse)
ei_add_test(ref)
ei_add_test(is_same_dense)
ei_add_test(triangular)
ei_add_test(selfadjoint)
ei_add_test(product_selfadjoint)
ei_add_test(product_symm)
ei_add_test(product_syrk)
ei_add_test(product_trmv)
ei_add_test(product_trmm)
ei_add_test(product_trsolve)
ei_add_test(product_mmtr)
ei_add_test(product_notemporary)
ei_add_test(product_threaded "-pthread" "${CMAKE_THREAD_LIBS_INIT}")
ei_add_test(stable_norm)
ei_add_test(permutationmatrices)
ei_add_test(bandmatrix)
ei_add_test(cholesky)
ei_add_test(lu)
ei_add_test(determinant)
ei_add_test(inverse)
ei_add_test(qr)
ei_add_test(qr_colpivoting)
ei_add_test(qr_fullpivoting)
ei_add_test(upperbidiagonalization)
ei_add_test(hessenberg)
ei_add_test(schur_real)
ei_add_test(schur_complex)
ei_add_test(eigensolver_selfadjoint)
ei_add_test(eigensolver_generic)
ei_add_test(eigensolver_complex)
ei_add_test(real_qz)
ei_add_test(eigensolver_generalized_real)
ei_add_test(jacobi)
ei_add_test(jacobisvd)
ei_add_test(bdcsvd)
ei_add_test(householder)
ei_add_test(geo_orthomethods)
ei_add_test(geo_quaternion)
ei_add_test(geo_eulerangles)
ei_add_test(geo_parametrizedline)
ei_add_test(geo_alignedbox)
ei_add_test(geo_hyperplane)
ei_add_test(geo_transformations)
ei_add_test(geo_homogeneous)
ei_add_test(stdvector)
ei_add_test(stdvector_overload)
ei_add_test(stdlist)
ei_add_test(stdlist_overload)
ei_add_test(stddeque)
ei_add_test(stddeque_overload)
ei_add_test(sparse_basic)
ei_add_test(sparse_block)
ei_add_test(sparse_vector)
ei_add_test(sparse_product)
ei_add_test(sparse_ref)
ei_add_test(sparse_solvers)
ei_add_test(sparse_permutations)
ei_add_test(simplicial_cholesky)
ei_add_test(conjugate_gradient)
ei_add_test(incomplete_cholesky)
ei_add_test(incomplete_LUT)
ei_add_test(bicgstab)
ei_add_test(lscg)
ei_add_test(sparselu)
ei_add_test(sparseqr)
ei_add_test(umeyama)
ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}")
ei_add_test(nestbyvalue)
ei_add_test(zerosized)
ei_add_test(dontalign)
ei_add_test(evaluators)
if(NOT EIGEN_TEST_NO_EXCEPTIONS)
ei_add_test(sizeoverflow)
endif()
ei_add_test(prec_inverse_4x4)
ei_add_test(vectorwiseop)
ei_add_test(special_numbers)
ei_add_test(rvalue_types)
ei_add_test(dense_storage)
ei_add_test(ctorleak)
ei_add_test(inplace_decomposition)
ei_add_test(half_float)
ei_add_test(bfloat16_float)
ei_add_test(array_of_string)
ei_add_test(num_dimensions)
ei_add_test(stl_iterators)
ei_add_test(blasutil)
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)
ei_add_test(threads_eventcount "-pthread" "${CMAKE_THREAD_LIBS_INIT}")
ei_add_test(threads_runqueue "-pthread" "${CMAKE_THREAD_LIBS_INIT}")
ei_add_test(threads_non_blocking_thread_pool "-pthread" "${CMAKE_THREAD_LIBS_INIT}")
ei_add_test(threads_fork_join "-pthread" "${CMAKE_THREAD_LIBS_INIT}")
add_executable(bug1213 bug1213.cpp bug1213_main.cpp)
check_cxx_compiler_flag("-ffast-math" COMPILER_SUPPORT_FASTMATH)
if(COMPILER_SUPPORT_FASTMATH)
set(EIGEN_FASTMATH_FLAGS "-ffast-math")
else()
check_cxx_compiler_flag("/fp:fast" COMPILER_SUPPORT_FPFAST)
if(COMPILER_SUPPORT_FPFAST)
set(EIGEN_FASTMATH_FLAGS "/fp:fast")
endif()
endif()
ei_add_test(fastmath "${EIGEN_FASTMATH_FLAGS}")
# # ei_add_test(denseLM)
if(QT4_FOUND)
ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}")
endif()
if(PARDISO_FOUND)
ei_add_test(pardiso_support "" "${PARDISO_ALL_LIBS}")
endif()
if(PASTIX_FOUND AND (SCOTCH_FOUND OR METIS_FOUND))
ei_add_test(pastix_support "" "${PASTIX_ALL_LIBS}")
endif()
if(SPQR_FOUND AND CHOLMOD_FOUND AND EIGEN_BUILD_BLAS AND EIGEN_BUILD_LAPACK)
ei_add_test(spqr_support "" "${SPQR_ALL_LIBS}")
endif()
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")
endif()
ei_add_property(EIGEN_TESTING_SUMMARY "CXX: ${CMAKE_CXX_COMPILER}\n")
if(CMAKE_COMPILER_IS_GNUCXX AND NOT CXX_IS_QCC)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version COMMAND head -n 1 OUTPUT_VARIABLE EIGEN_CXX_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE)
ei_add_property(EIGEN_TESTING_SUMMARY "CXX_VERSION: ${EIGEN_CXX_VERSION_STRING}\n")
endif()
ei_add_property(EIGEN_TESTING_SUMMARY "CXX_FLAGS: ${CMAKE_CXX_FLAGS}\n")
if (EIGEN_TEST_CUSTOM_CXX_FLAGS)
ei_add_property(EIGEN_TESTING_SUMMARY "Custom CXX flags: ${EIGEN_TEST_CUSTOM_CXX_FLAGS}\n")
endif()
ei_add_property(EIGEN_TESTING_SUMMARY "Sparse lib flags: ${SPARSE_LIBS}\n")
option(EIGEN_TEST_EIGEN2 "Run whole Eigen2 test suite against EIGEN2_SUPPORT" OFF)
mark_as_advanced(EIGEN_TEST_EIGEN2)
if(EIGEN_TEST_EIGEN2)
message(WARNING "The Eigen2 test suite has been removed")
endif()
# boost MP unit test
find_package(Boost 1.53.0 CONFIG)
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
ei_add_test(boostmultiprec "" "${Boost_LIBRARIES}")
ei_add_property(EIGEN_TESTED_BACKENDS "Boost.Multiprecision, ")
else()
ei_add_property(EIGEN_MISSING_BACKENDS "Boost.Multiprecision, ")
endif()
# CUDA unit tests
option(EIGEN_TEST_CUDA "Enable CUDA support in unit tests" OFF)
option(EIGEN_TEST_CUDA_CLANG "Use clang instead of nvcc to compile the CUDA tests" OFF)
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()
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}")
if(EIGEN_TEST_CUDA_CLANG)
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()
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()
set(EIGEN_ADD_TEST_FILENAME_EXTENSION "cu")
ei_add_test(gpu_example)
ei_add_test(gpu_basic)
unset(EIGEN_ADD_TEST_FILENAME_EXTENSION)
endif()
# HIP unit tests
option(EIGEN_TEST_HIP "Add HIP support." OFF)
if (EIGEN_TEST_HIP)
set(ROCM_PATH "/opt/rocm" CACHE STRING "Path to the ROCm installation.")
if (EXISTS ${ROCM_PATH}/hip)
set(HIP_PATH ${ROCM_PATH}/hip)
list(APPEND CMAKE_MODULE_PATH ${HIP_PATH}/cmake)
elseif (EXISTS ${ROCM_PATH}/lib/cmake/hip)
set(HIP_PATH ${ROCM_PATH})
list(APPEND CMAKE_MODULE_PATH ${HIP_PATH}/lib/cmake/hip)
else ()
message(FATAL_ERROR "EIGEN_TEST_HIP is ON, but could not find the ROCm installation under ${ROCM_PATH}")
endif()
find_package(HIP REQUIRED)
if (HIP_FOUND)
execute_process(COMMAND ${HIP_PATH}/bin/hipconfig --platform OUTPUT_VARIABLE HIP_PLATFORM)
if ((${HIP_PLATFORM} STREQUAL "hcc") OR (${HIP_PLATFORM} STREQUAL "amd"))
include_directories(${HIP_PATH}/include)
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"))
message(FATAL_ERROR "HIP_PLATFORM = nvcc is not supported within Eigen")
else ()
message(FATAL_ERROR "Unknown HIP_PLATFORM = ${HIP_PLATFORM}")
endif()
endif()
endif()
if(EIGEN_TEST_SYCL)
set(EIGEN_SYCL ON)
include(SyclConfigureTesting)
ei_add_test(sycl_basic)
set(EIGEN_SYCL OFF)
endif()
cmake_dependent_option(EIGEN_TEST_BUILD_DOCUMENTATION "Test building the doxygen documentation" OFF "EIGEN_BUILD_DOC" OFF)
if(EIGEN_TEST_BUILD_DOCUMENTATION)
add_dependencies(buildtests doc)
endif()
# Register all smoke tests
include("EigenSmokeTestList")
ei_add_smoke_tests("${ei_smoke_test_list}")
+132
View File
@@ -0,0 +1,132 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2025 The Eigen Authors.
//
// 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_TEST_CUSTOM_COMPLEX_H
#define EIGEN_TEST_CUSTOM_COMPLEX_H
#include <ostream>
#include <sstream>
namespace custom_complex {
template <typename Real>
struct CustomComplex {
CustomComplex() : re{0}, im{0} {}
CustomComplex(const CustomComplex& other) = default;
CustomComplex(CustomComplex&& other) = default;
CustomComplex& operator=(const CustomComplex& other) = default;
CustomComplex& operator=(CustomComplex&& other) = default;
CustomComplex(Real x) : re{x}, im{0} {}
CustomComplex(Real x, Real y) : re{x}, im{y} {}
CustomComplex operator+(const CustomComplex& other) const { return CustomComplex(re + other.re, im + other.im); }
CustomComplex operator-() const { return CustomComplex(-re, -im); }
CustomComplex operator-(const CustomComplex& other) const { return CustomComplex(re - other.re, im - other.im); }
CustomComplex operator*(const CustomComplex& other) const {
return CustomComplex(re * other.re - im * other.im, re * other.im + im * other.re);
}
CustomComplex operator/(const CustomComplex& other) const {
// Smith's complex division (https://arxiv.org/pdf/1210.4539.pdf),
// guards against over/under-flow.
const bool scale_imag = numext::abs(other.im) <= numext::abs(other.re);
const Real rscale = scale_imag ? Real(1) : other.re / other.im;
const Real iscale = scale_imag ? other.im / other.re : Real(1);
const Real denominator = other.re * rscale + other.im * iscale;
return CustomComplex((re * rscale + im * iscale) / denominator, (im * rscale - re * iscale) / denominator);
}
CustomComplex& operator+=(const CustomComplex& other) {
*this = *this + other;
return *this;
}
CustomComplex& operator-=(const CustomComplex& other) {
*this = *this - other;
return *this;
}
CustomComplex& operator*=(const CustomComplex& other) {
*this = *this * other;
return *this;
}
CustomComplex& operator/=(const CustomComplex& other) {
*this = *this / other;
return *this;
}
bool operator==(const CustomComplex& other) const {
return numext::equal_strict(re, other.re) && numext::equal_strict(im, other.im);
}
bool operator!=(const CustomComplex& other) const { return !(*this == other); }
friend CustomComplex operator+(const Real& a, const CustomComplex& b) { return CustomComplex(a + b.re, b.im); }
friend CustomComplex operator-(const Real& a, const CustomComplex& b) { return CustomComplex(a - b.re, -b.im); }
friend CustomComplex operator*(const Real& a, const CustomComplex& b) { return CustomComplex(a * b.re, a * b.im); }
friend CustomComplex operator*(const CustomComplex& a, const Real& b) { return CustomComplex(a.re * b, a.im * b); }
friend CustomComplex operator/(const CustomComplex& a, const Real& b) { return CustomComplex(a.re / b, a.im / b); }
friend std::ostream& operator<<(std::ostream& stream, const CustomComplex& x) {
std::stringstream ss;
ss << "(" << x.re << ", " << x.im << ")";
stream << ss.str();
return stream;
}
Real re;
Real im;
};
template <typename Real>
Real real(const CustomComplex<Real>& x) {
return x.re;
}
template <typename Real>
Real imag(const CustomComplex<Real>& x) {
return x.im;
}
template <typename Real>
CustomComplex<Real> conj(const CustomComplex<Real>& x) {
return CustomComplex<Real>(x.re, -x.im);
}
template <typename Real>
CustomComplex<Real> sqrt(const CustomComplex<Real>& x) {
return Eigen::internal::complex_sqrt(x);
}
template <typename Real>
Real abs(const CustomComplex<Real>& x) {
return Eigen::numext::sqrt(x.re * x.re + x.im * x.im);
}
} // namespace custom_complex
template <typename Real>
using CustomComplex = custom_complex::CustomComplex<Real>;
namespace Eigen {
template <typename Real>
struct NumTraits<CustomComplex<Real>> : NumTraits<Real> {
enum { IsComplex = 1 };
};
namespace numext {
template <typename Real>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool(isfinite)(const CustomComplex<Real>& x) {
return (numext::isfinite)(x.re) && (numext::isfinite)(x.im);
}
} // namespace numext
} // namespace Eigen
#endif // EIGEN_TEST_CUSTOM_COMPLEX_H
+54
View File
@@ -0,0 +1,54 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2020 Sebastien Boisvert <seb@boisvert.info>
//
// 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_MISC_MOVABLE_SCALAR_H
#define EIGEN_MISC_MOVABLE_SCALAR_H
namespace Eigen {
template <typename Scalar>
struct MovableScalar {
MovableScalar() : m_data(new Scalar) {}
~MovableScalar() { delete m_data; }
MovableScalar(const MovableScalar& other) : m_data(new Scalar) { set(other.get()); }
MovableScalar(MovableScalar&& other) noexcept : m_data(other.m_data) { other.m_data = nullptr; }
MovableScalar& operator=(const MovableScalar& other) {
set(other.get());
return *this;
}
MovableScalar& operator=(MovableScalar&& other) noexcept {
m_data = other.m_data;
other.m_data = nullptr;
return *this;
}
MovableScalar(const Scalar& scalar) : m_data(new Scalar) { set(scalar); }
operator Scalar() const { return get(); }
private:
void set(const Scalar& value) {
eigen_assert(m_data != nullptr);
// suppress compiler warnings
if (m_data != nullptr) *m_data = value;
}
Scalar get() const {
eigen_assert(m_data != nullptr);
// suppress compiler warnings
return m_data == nullptr ? Scalar() : *m_data;
}
Scalar* m_data = nullptr;
};
template <typename Scalar>
struct NumTraits<MovableScalar<Scalar>> : NumTraits<Scalar> {
enum { RequireInitialization = 1 };
};
} // namespace Eigen
#endif
+20
View File
@@ -0,0 +1,20 @@
// A Scalar with internal representation T+1 so that zero is internally
// represented by T(1). This is used to test memory fill.
//
#pragma once
template <typename T>
class OffByOneScalar {
public:
OffByOneScalar() : val_(1) {}
OffByOneScalar(const OffByOneScalar& other) = default;
OffByOneScalar& operator=(const OffByOneScalar& other) = default;
OffByOneScalar(T val) : val_(val + 1) {}
OffByOneScalar& operator=(T val) { val_ = val + 1; }
operator T() const { return val_ - 1; }
private:
T val_;
};
+33
View File
@@ -0,0 +1,33 @@
// A Scalar that asserts for uninitialized access.
template <typename T>
class SafeScalar {
public:
SafeScalar() : initialized_(false) {}
SafeScalar(const T& val) : val_(val), initialized_(true) {}
template <typename Source>
explicit SafeScalar(const Source& val) : SafeScalar(T(val)) {}
operator T() const {
VERIFY(initialized_ && "Uninitialized access.");
return val_;
}
template <typename Target>
explicit operator Target() const {
return Target(this->operator T());
}
private:
T val_;
bool initialized_;
};
namespace Eigen {
template <typename T>
struct NumTraits<SafeScalar<T>> : GenericNumTraits<T> {
enum { RequireInitialization = 1 };
};
} // namespace Eigen
+166
View File
@@ -0,0 +1,166 @@
#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>());
}
+236
View File
@@ -0,0 +1,236 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <bool IsInteger>
struct adjoint_specific;
template <>
struct adjoint_specific<true> {
template <typename Vec, typename Mat, typename Scalar>
static void run(const Vec& v1, const Vec& v2, Vec& v3, const Mat& square, Scalar s1, Scalar s2) {
VERIFY(test_isApproxWithRef((s1 * v1 + s2 * v2).dot(v3),
numext::conj(s1) * v1.dot(v3) + numext::conj(s2) * v2.dot(v3), 0));
VERIFY(test_isApproxWithRef(v3.dot(s1 * v1 + s2 * v2), s1 * v3.dot(v1) + s2 * v3.dot(v2), 0));
// check compatibility of dot and adjoint
VERIFY(test_isApproxWithRef(v1.dot(square * v2), (square.adjoint() * v1).dot(v2), 0));
}
};
template <>
struct adjoint_specific<false> {
template <typename Vec, typename Mat, typename Scalar>
static void run(const Vec& v1, const Vec& v2, Vec& v3, const Mat& square, Scalar s1, Scalar s2) {
typedef typename NumTraits<Scalar>::Real RealScalar;
using std::abs;
RealScalar ref = NumTraits<Scalar>::IsInteger ? RealScalar(0) : (std::max)((s1 * v1 + s2 * v2).norm(), v3.norm());
VERIFY(test_isApproxWithRef((s1 * v1 + s2 * v2).dot(v3),
numext::conj(s1) * v1.dot(v3) + numext::conj(s2) * v2.dot(v3), ref));
VERIFY(test_isApproxWithRef(v3.dot(s1 * v1 + s2 * v2), s1 * v3.dot(v1) + s2 * v3.dot(v2), ref));
VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm());
// check normalized() and normalize()
VERIFY_IS_APPROX(v1, v1.norm() * v1.normalized());
v3 = v1;
v3.normalize();
VERIFY_IS_APPROX(v1, v1.norm() * v3);
VERIFY_IS_APPROX(v3, v1.normalized());
VERIFY_IS_APPROX(v3.norm(), RealScalar(1));
// check null inputs
VERIFY_IS_APPROX((v1 * 0).normalized(), (v1 * 0));
#if (!EIGEN_ARCH_i386) || defined(EIGEN_VECTORIZE)
RealScalar very_small = (std::numeric_limits<RealScalar>::min)();
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();
VERIFY_IS_APPROX(v3, (v1 * very_small));
#endif
// check compatibility of dot and adjoint
ref = NumTraits<Scalar>::IsInteger ? 0
: (std::max)((std::max)(v1.norm(), v2.norm()),
(std::max)((square * v2).norm(), (square.adjoint() * v1).norm()));
VERIFY(internal::isMuchSmallerThan(abs(v1.dot(square * v2) - (square.adjoint() * v1).dot(v2)), ref,
test_precision<Scalar>()));
// check that Random().normalized() works: tricky as the random xpr must be evaluated by
// normalized() in order to produce a consistent result.
VERIFY_IS_APPROX(Vec::Random(v1.size()).normalized().norm(), RealScalar(1));
}
};
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:
Transpose.h Conjugate.h Dot.h
*/
using std::abs;
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
const Index PacketSize = internal::packet_traits<Scalar>::size;
Index rows = m.rows();
Index cols = m.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 = 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>(rmin, rmax), s2 = internal::random<Scalar>(rmin, rmax);
// check basic compatibility of adjoint, transpose, conjugate
VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1);
VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(), m1);
// check multiplicative behavior
VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(), m2.adjoint() * m1);
VERIFY_IS_APPROX((s1 * m1).adjoint(), numext::conj(s1) * m1.adjoint());
// check basic properties of dot, squaredNorm
VERIFY_IS_APPROX(numext::conj(v1.dot(v2)), v2.dot(v1));
VERIFY_IS_APPROX(numext::real(v1.dot(v1)), v1.squaredNorm());
adjoint_specific<NumTraits<Scalar>::IsInteger>::run(v1, v2, v3, square, s1, s2);
VERIFY_IS_MUCH_SMALLER_THAN(abs(vzero.dot(v1)), static_cast<RealScalar>(1));
// like in testBasicStuff, test operator() to check const-qualification
Index r = internal::random<Index>(0, rows - 1), c = internal::random<Index>(0, cols - 1);
VERIFY_IS_APPROX(m1.conjugate()(r, c), numext::conj(m1(r, c)));
VERIFY_IS_APPROX(m1.adjoint()(c, r), numext::conj(m1(r, c)));
// check inplace transpose
m3 = m1;
m3.transposeInPlace();
VERIFY_IS_APPROX(m3, m1.transpose());
m3.transposeInPlace();
VERIFY_IS_APPROX(m3, m1);
if (PacketSize < m3.rows() && PacketSize < m3.cols()) {
m3 = m1;
Index i = internal::random<Index>(0, m3.rows() - PacketSize);
Index j = internal::random<Index>(0, m3.cols() - PacketSize);
m3.template block<PacketSize, PacketSize>(i, j).transposeInPlace();
VERIFY_IS_APPROX((m3.template block<PacketSize, PacketSize>(i, j)),
(m1.template block<PacketSize, PacketSize>(i, j).transpose()));
m3.template block<PacketSize, PacketSize>(i, j).transposeInPlace();
VERIFY_IS_APPROX(m3, m1);
}
// check inplace adjoint
m3 = m1;
m3.adjointInPlace();
VERIFY_IS_APPROX(m3, m1.adjoint());
m3.transposeInPlace();
VERIFY_IS_APPROX(m3, m1.conjugate());
// check mixed dot product
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
RealVectorType rv1 = 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));
VERIFY(is_same_type(m1, m1.template conjugateIf<false>()));
VERIFY(is_same_type(m1.conjugate(), m1.template conjugateIf<true>()));
}
template <int>
void adjoint_extra() {
MatrixXcf a(10, 10), b(10, 10);
VERIFY_RAISES_ASSERT(a = a.transpose());
VERIFY_RAISES_ASSERT(a = a.transpose() + b);
VERIFY_RAISES_ASSERT(a = b + a.transpose());
VERIFY_RAISES_ASSERT(a = a.conjugate().transpose());
VERIFY_RAISES_ASSERT(a = a.adjoint());
VERIFY_RAISES_ASSERT(a = a.adjoint() + b);
VERIFY_RAISES_ASSERT(a = b + a.adjoint());
// no assertion should be triggered for these cases:
a.transpose() = a.transpose();
a.transpose() += a.transpose();
a.transpose() += a.transpose() + b;
a.transpose() = a.adjoint();
a.transpose() += a.adjoint();
a.transpose() += a.adjoint() + b;
// regression tests for check_for_aliasing
MatrixXd c(10, 10);
c = 1.0 * MatrixXd::Ones(10, 10) + c;
c = MatrixXd::Ones(10, 10) * 1.0 + c;
c = c + MatrixXd::Ones(10, 10).cwiseProduct(MatrixXd::Zero(10, 10));
c = MatrixXd::Ones(10, 10) * MatrixXd::Zero(10, 10);
// regression for bug 1646
for (int j = 0; j < 10; ++j) {
c.col(j).head(j) = c.row(j).head(j);
}
for (int j = 0; j < 10; ++j) {
c.col(j) = c.row(j);
}
a.conservativeResize(1, 1);
a = a.transpose();
a.conservativeResize(0, 0);
a = a.transpose();
}
EIGEN_DECLARE_TEST(adjoint) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(adjoint(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(adjoint(Matrix3d()));
CALL_SUBTEST_3(adjoint(Matrix4f()));
CALL_SUBTEST_4(adjoint(MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2),
internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2))));
CALL_SUBTEST_5(adjoint(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(adjoint(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
// Complement for 128 bits vectorization:
CALL_SUBTEST_8(adjoint(Matrix2d()));
CALL_SUBTEST_9(adjoint(Matrix<int, 4, 4>()));
// 256 bits vectorization:
CALL_SUBTEST_10(adjoint(Matrix<float, 8, 8>()));
CALL_SUBTEST_11(adjoint(Matrix<double, 4, 4>()));
CALL_SUBTEST_12(adjoint(Matrix<int, 8, 8>()));
}
// test a large static matrix only once
CALL_SUBTEST_7(adjoint(Matrix<float, 100, 100>()));
CALL_SUBTEST_13(adjoint_extra<0>());
}
File diff suppressed because it is too large Load Diff
+349
View File
@@ -0,0 +1,349 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType>
void array_for_matrix(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols);
ColVectorType cv1 = ColVectorType::Random(rows);
RowVectorType rv1 = RowVectorType::Random(cols);
Scalar s1 = internal::random<Scalar>(), s2 = internal::random<Scalar>();
// Prevent overflows for integer types.
if (Eigen::NumTraits<Scalar>::IsInteger) {
Scalar kMaxVal = Scalar(1000);
m1.array() = m1.array() - kMaxVal * (m1.array() / kMaxVal);
m2.array() = m2.array() - kMaxVal * (m2.array() / kMaxVal);
}
// scalar addition
VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows, cols, s1) + m1);
VERIFY_IS_APPROX(((m1 * Scalar(2)).array() - s2).matrix(), (m1 + m1) - MatrixType::Constant(rows, cols, s2));
m3 = m1;
m3.array() += s2;
VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
m3 = m1;
m3.array() -= s1;
VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());
// reductions
VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum().sum() - m1.sum(), m1.squaredNorm());
VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum().sum() - m1.sum(), m1.squaredNorm());
VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum() + m2.colwise().sum() - (m1 + m2).colwise().sum(),
(m1 + m2).squaredNorm());
VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum() - m2.rowwise().sum() - (m1 - m2).rowwise().sum(),
(m1 - m2).squaredNorm());
VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar, Scalar>()));
// vector-wise ops
m3 = m1;
VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
m3 = m1;
VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
m3 = m1;
VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
m3 = m1;
VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);
// empty objects
VERIFY_IS_EQUAL((m1.template block<0, Dynamic>(0, 0, 0, cols).colwise().sum()), RowVectorType::Zero(cols));
VERIFY_IS_EQUAL((m1.template block<Dynamic, 0>(0, 0, rows, 0).rowwise().sum()), ColVectorType::Zero(rows));
VERIFY_IS_EQUAL((m1.template block<0, Dynamic>(0, 0, 0, cols).colwise().prod()), RowVectorType::Ones(cols));
VERIFY_IS_EQUAL((m1.template block<Dynamic, 0>(0, 0, rows, 0).rowwise().prod()), ColVectorType::Ones(rows));
VERIFY_IS_EQUAL(m1.block(0, 0, 0, cols).colwise().sum(), RowVectorType::Zero(cols));
VERIFY_IS_EQUAL(m1.block(0, 0, rows, 0).rowwise().sum(), ColVectorType::Zero(rows));
VERIFY_IS_EQUAL(m1.block(0, 0, 0, cols).colwise().prod(), RowVectorType::Ones(cols));
VERIFY_IS_EQUAL(m1.block(0, 0, rows, 0).rowwise().prod(), ColVectorType::Ones(rows));
// verify the const accessors exist
const Scalar& ref_m1 = m.matrix().array().coeffRef(0);
const Scalar& ref_m2 = m.matrix().array().coeffRef(0, 0);
const Scalar& ref_a1 = m.array().matrix().coeffRef(0);
const Scalar& ref_a2 = m.array().matrix().coeffRef(0, 0);
VERIFY(&ref_a1 == &ref_m1);
VERIFY(&ref_a2 == &ref_m2);
// Check write accessors:
m1.array().coeffRef(0, 0) = 1;
VERIFY_IS_APPROX(m1(0, 0), Scalar(1));
m1.array()(0, 0) = 2;
VERIFY_IS_APPROX(m1(0, 0), Scalar(2));
m1.array().matrix().coeffRef(0, 0) = 3;
VERIFY_IS_APPROX(m1(0, 0), Scalar(3));
m1.array().matrix()(0, 0) = 4;
VERIFY_IS_APPROX(m1(0, 0), Scalar(4));
}
template <typename MatrixType>
void comparisons(const MatrixType& m) {
using std::abs;
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
Index rows = m.rows();
Index cols = m.cols();
Index r = internal::random<Index>(0, rows - 1), c = internal::random<Index>(0, cols - 1);
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols);
VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
if (rows * cols > 1) {
m3 = m1;
m3(r, c) += 1;
VERIFY(!(m1.array() < m3.array()).all());
VERIFY(!(m1.array() > m3.array()).all());
}
// comparisons to scalar
VERIFY((m1.array() != (m1(r, c) + 1)).any());
VERIFY((m1.array() > (m1(r, c) - 1)).any());
VERIFY((m1.array() < (m1(r, c) + 1)).any());
VERIFY((m1.array() == m1(r, c)).any());
VERIFY(m1.cwiseEqual(m1(r, c)).any());
// test select
VERIFY_IS_APPROX((m1.array() < m2.array()).select(m1, m2), m1.cwiseMin(m2));
VERIFY_IS_APPROX((m1.array() > m2.array()).select(m1, m2), m1.cwiseMax(m2));
Scalar mid = m1.cwiseAbs().minCoeff() / Scalar(2) + m1.cwiseAbs().maxCoeff() / Scalar(2);
for (int j = 0; j < cols; ++j)
for (int i = 0; i < rows; ++i) m3(i, j) = abs(m1(i, j)) < mid ? 0 : m1(i, j);
VERIFY_IS_APPROX(
(m1.array().abs() < MatrixType::Constant(rows, cols, mid).array()).select(MatrixType::Zero(rows, cols), m1), m3);
// shorter versions:
VERIFY_IS_APPROX((m1.array().abs() < MatrixType::Constant(rows, cols, mid).array()).select(0, m1), m3);
VERIFY_IS_APPROX((m1.array().abs() >= MatrixType::Constant(rows, cols, mid).array()).select(m1, 0), m3);
// even shorter version:
VERIFY_IS_APPROX((m1.array().abs() < mid).select(0, m1), m3);
// count
VERIFY(((m1.array().abs() + 1) > RealScalar(0.1)).count() == rows * cols);
// and/or
VERIFY(((m1.array() < RealScalar(0)).matrix() && (m1.array() > RealScalar(0)).matrix()).count() == 0);
VERIFY(((m1.array() < RealScalar(0)).matrix() || (m1.array() >= RealScalar(0)).matrix()).count() == rows * cols);
VERIFY(((m1.array() < -mid).matrix() || (m1.array() > mid).matrix()).count() ==
(m1.cwiseAbs().array() > mid).count());
typedef Matrix<Index, Dynamic, 1> VectorOfIndices;
// TODO allows colwise/rowwise for array
VERIFY_IS_APPROX(((m1.array().abs() + 1) > RealScalar(0.1)).matrix().colwise().count(),
VectorOfIndices::Constant(cols, rows).transpose());
VERIFY_IS_APPROX(((m1.array().abs() + 1) > RealScalar(0.1)).matrix().rowwise().count(),
VectorOfIndices::Constant(rows, cols));
}
template <typename VectorType>
void lpNorm(const VectorType& v) {
using std::sqrt;
typedef typename VectorType::RealScalar RealScalar;
VectorType u = VectorType::Random(v.size());
if (v.size() == 0) {
VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), RealScalar(0));
VERIFY_IS_APPROX(u.template lpNorm<1>(), RealScalar(0));
VERIFY_IS_APPROX(u.template lpNorm<2>(), RealScalar(0));
VERIFY_IS_APPROX(u.template lpNorm<5>(), RealScalar(0));
} else {
VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
}
VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
VERIFY_IS_APPROX(u.template lpNorm<2>(), sqrt(u.array().abs().square().sum()));
VERIFY_IS_APPROX(numext::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)),
u.array().abs().pow(5).sum());
}
template <typename MatrixType>
void cwise_min_max(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols);
// min/max with array
Scalar maxM1 = m1.maxCoeff();
Scalar minM1 = m1.minCoeff();
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, minM1), m1.cwiseMin(MatrixType::Constant(rows, cols, minM1)));
VERIFY_IS_APPROX(m1, m1.cwiseMin(MatrixType::Constant(rows, cols, maxM1)));
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, maxM1), m1.cwiseMax(MatrixType::Constant(rows, cols, maxM1)));
VERIFY_IS_APPROX(m1, m1.cwiseMax(MatrixType::Constant(rows, cols, minM1)));
// min/max with scalar input
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, minM1), m1.cwiseMin(minM1));
VERIFY_IS_APPROX(m1, m1.cwiseMin(maxM1));
VERIFY_IS_APPROX(-m1, (-m1).cwiseMin(-minM1));
VERIFY_IS_APPROX(-m1.array(), ((-m1).array().min)(-minM1));
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, maxM1), m1.cwiseMax(maxM1));
VERIFY_IS_APPROX(m1, m1.cwiseMax(minM1));
VERIFY_IS_APPROX(-m1, (-m1).cwiseMax(-maxM1));
VERIFY_IS_APPROX(-m1.array(), ((-m1).array().max)(-maxM1));
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, minM1).array(), (m1.array().min)(minM1));
VERIFY_IS_APPROX(m1.array(), (m1.array().min)(maxM1));
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) {
typedef typename MatrixTraits::Scalar Scalar;
typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType;
typedef Array<Scalar, Dynamic, Dynamic> Array2DType;
typedef Matrix<Scalar, Dynamic, 1> VectorType;
typedef Array<Scalar, Dynamic, 1> Array1DType;
Index rows = t.rows(), cols = t.cols();
MatrixType m(rows, cols);
VectorType v(rows);
Array2DType a2(rows, cols);
Array1DType a1(rows);
m.array().resize(rows + 1, cols + 1);
VERIFY(m.rows() == rows + 1 && m.cols() == cols + 1);
a2.matrix().resize(rows + 1, cols + 1);
VERIFY(a2.rows() == rows + 1 && a2.cols() == cols + 1);
v.array().resize(cols);
VERIFY(v.size() == cols);
a1.matrix().resize(cols);
VERIFY(a1.size() == cols);
}
template <int>
void regression_bug_654() {
ArrayXf a = RowVectorXf(3);
VectorXf v = Array<float, 1, Dynamic>(3);
}
// Check propagation of LvalueBit through Array/Matrix-Wrapper
template <int>
void regrrssion_bug_1410() {
const Matrix4i M;
const Array4i A;
ArrayWrapper<const Matrix4i> MA = M.array();
MA.row(0);
MatrixWrapper<const Array4i> AM = A.matrix();
AM.row(0);
VERIFY((internal::traits<ArrayWrapper<const Matrix4i> >::Flags & LvalueBit) == 0);
VERIFY((internal::traits<MatrixWrapper<const Array4i> >::Flags & LvalueBit) == 0);
VERIFY((internal::traits<ArrayWrapper<Matrix4i> >::Flags & LvalueBit) == LvalueBit);
VERIFY((internal::traits<MatrixWrapper<Array4i> >::Flags & LvalueBit) == LvalueBit);
}
EIGEN_DECLARE_TEST(array_for_matrix) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(array_for_matrix(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(array_for_matrix(Matrix2f()));
CALL_SUBTEST_3(array_for_matrix(Matrix4d()));
CALL_SUBTEST_4(array_for_matrix(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_5(array_for_matrix(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(array_for_matrix(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(comparisons(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(comparisons(Matrix2f()));
CALL_SUBTEST_3(comparisons(Matrix4d()));
CALL_SUBTEST_5(comparisons(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(comparisons(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(cwise_min_max(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(cwise_min_max(Matrix2f()));
CALL_SUBTEST_3(cwise_min_max(Matrix4d()));
CALL_SUBTEST_5(cwise_min_max(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(cwise_min_max(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(lpNorm(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(lpNorm(Vector2f()));
CALL_SUBTEST_7(lpNorm(Vector3d()));
CALL_SUBTEST_8(lpNorm(Vector4f()));
CALL_SUBTEST_5(lpNorm(VectorXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_4(lpNorm(VectorXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
CALL_SUBTEST_5(lpNorm(VectorXf(0)));
CALL_SUBTEST_4(lpNorm(VectorXcf(0)));
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_4(resize(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_5(
resize(MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(
resize(MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
CALL_SUBTEST_6(regression_bug_654<0>());
CALL_SUBTEST_6(regrrssion_bug_1410<0>());
}
+31
View File
@@ -0,0 +1,31 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
EIGEN_DECLARE_TEST(array_of_string) {
typedef Array<std::string, 1, Dynamic> ArrayXs;
ArrayXs a1(3), a2(3), a3(3), a3ref(3);
a1 << "one", "two", "three";
a2 << "1", "2", "3";
a3ref << "one (1)", "two (2)", "three (3)";
std::stringstream s1;
s1 << a1;
VERIFY_IS_EQUAL(s1.str(), std::string(" one two three"));
a3 = a1 + std::string(" (") + a2 + std::string(")");
VERIFY((a3 == a3ref).all());
a3 = a1;
a3 += std::string(" (") + a2 + std::string(")");
VERIFY((a3 == a3ref).all());
a1.swap(a3);
VERIFY((a1 == a3ref).all());
VERIFY((a3 != a3ref).all());
}
+73
View File
@@ -0,0 +1,73 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType>
void replicate(const MatrixType& m) {
/* this test covers the following files:
Replicate.cpp
*/
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, Dynamic, Dynamic> MatrixX;
typedef Matrix<Scalar, Dynamic, 1> VectorX;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols);
VectorType v1 = VectorType::Random(rows);
MatrixX x1, x2;
VectorX vx1;
int f1 = internal::random<int>(1, 10), f2 = internal::random<int>(1, 10);
x1.resize(rows * f1, cols * f2);
for (int j = 0; j < f2; j++)
for (int i = 0; i < f1; i++) x1.block(i * rows, j * cols, rows, cols) = m1;
VERIFY_IS_APPROX(x1, m1.replicate(f1, f2));
x2.resize(2 * rows, 3 * cols);
x2 << m2, m2, m2, m2, m2, m2;
VERIFY_IS_APPROX(x2, (m2.template replicate<2, 3>()));
x2.resize(rows, 3 * cols);
x2 << m2, m2, m2;
VERIFY_IS_APPROX(x2, (m2.template replicate<1, 3>()));
vx1.resize(3 * rows, cols);
vx1 << m2, m2, m2;
VERIFY_IS_APPROX(vx1 + vx1, vx1 + (m2.template replicate<3, 1>()));
vx1 = m2 + (m2.colwise().replicate(1));
if (m2.cols() == 1) VERIFY_IS_APPROX(m2.coeff(0), (m2.template replicate<3, 1>().coeff(m2.rows())));
x2.resize(rows, f1);
for (int j = 0; j < f1; ++j) x2.col(j) = v1;
VERIFY_IS_APPROX(x2, v1.rowwise().replicate(f1));
vx1.resize(rows * f2);
for (int j = 0; j < f2; ++j) vx1.segment(j * rows, rows) = v1;
VERIFY_IS_APPROX(vx1, v1.colwise().replicate(f2));
}
EIGEN_DECLARE_TEST(array_replicate) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(replicate(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(replicate(Vector2f()));
CALL_SUBTEST_3(replicate(Vector3d()));
CALL_SUBTEST_4(replicate(Vector4f()));
CALL_SUBTEST_5(replicate(VectorXf(16)));
CALL_SUBTEST_6(replicate(VectorXcd(10)));
}
}
+199
View File
@@ -0,0 +1,199 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
// Copyright (C) 2009 Ricard Marxer <email@ricardmarxer.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <iostream>
using namespace std;
template <typename MatrixType>
void reverse(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
Index rows = m.rows();
Index cols = m.cols();
// this test relies a lot on Random.h, and there's not much more that we can do
// to test it, hence I consider that we will have tested Random.h
MatrixType m1 = MatrixType::Random(rows, cols), m2;
VectorType v1 = VectorType::Random(rows);
MatrixType m1_r = m1.reverse();
// Verify that MatrixBase::reverse() works
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_r(i, j), m1(rows - 1 - i, cols - 1 - j));
}
}
Reverse<MatrixType> m1_rd(m1);
// Verify that a Reverse default (in both directions) of an expression works
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_rd(i, j), m1(rows - 1 - i, cols - 1 - j));
}
}
Reverse<MatrixType, BothDirections> m1_rb(m1);
// Verify that a Reverse in both directions of an expression works
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_rb(i, j), m1(rows - 1 - i, cols - 1 - j));
}
}
Reverse<MatrixType, Vertical> m1_rv(m1);
// Verify that a Reverse in the vertical directions of an expression works
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_rv(i, j), m1(rows - 1 - i, j));
}
}
Reverse<MatrixType, Horizontal> m1_rh(m1);
// Verify that a Reverse in the horizontal directions of an expression works
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_rh(i, j), m1(i, cols - 1 - j));
}
}
VectorType v1_r = v1.reverse();
// Verify that a VectorType::reverse() of an expression works
for (int i = 0; i < rows; i++) {
VERIFY_IS_APPROX(v1_r(i), v1(rows - 1 - i));
}
MatrixType m1_cr = m1.colwise().reverse();
// Verify that PartialRedux::reverse() works (for colwise())
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_cr(i, j), m1(rows - 1 - i, j));
}
}
MatrixType m1_rr = m1.rowwise().reverse();
// Verify that PartialRedux::reverse() works (for rowwise())
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
VERIFY_IS_APPROX(m1_rr(i, j), m1(i, cols - 1 - j));
}
}
Scalar x = internal::random<Scalar>();
Index r = internal::random<Index>(0, rows - 1), c = internal::random<Index>(0, cols - 1);
m1.reverse()(r, c) = x;
VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c));
m2 = m1;
m2.reverseInPlace();
VERIFY_IS_APPROX(m2, m1.reverse().eval());
m2 = m1;
m2.col(0).reverseInPlace();
VERIFY_IS_APPROX(m2.col(0), m1.col(0).reverse().eval());
m2 = m1;
m2.row(0).reverseInPlace();
VERIFY_IS_APPROX(m2.row(0), m1.row(0).reverse().eval());
m2 = m1;
m2.rowwise().reverseInPlace();
VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
m2 = m1;
m2.colwise().reverseInPlace();
VERIFY_IS_APPROX(m2, m1.colwise().reverse().eval());
m1.colwise().reverse()(r, c) = x;
VERIFY_IS_APPROX(x, m1(rows - 1 - r, c));
m1.rowwise().reverse()(r, c) = x;
VERIFY_IS_APPROX(x, m1(r, cols - 1 - c));
}
template <int>
void array_reverse_extra() {
Vector4f x;
x << 1, 2, 3, 4;
Vector4f y;
y << 4, 3, 2, 1;
VERIFY(x.reverse()[1] == 3);
VERIFY(x.reverse() == y);
}
// Simpler version of reverseInPlace leveraging a bug
// in clang 6/7 with -O2 and AVX or AVX512 enabled.
// This simpler version ensure that the clang bug is not simply hidden
// through mis-inlining of reverseInPlace or other minor changes.
template <typename MatrixType>
EIGEN_DONT_INLINE void bug1684_job1(MatrixType& m1, MatrixType& m2) {
m2 = m1;
m2.col(0).swap(m2.col(3));
m2.col(1).swap(m2.col(2));
}
template <typename MatrixType>
EIGEN_DONT_INLINE void bug1684_job2(MatrixType& m1, MatrixType& m2) {
m2 = m1; // load m1/m2 in AVX registers
m1.col(0) = m2.col(3); // perform 128 bits moves
m1.col(1) = m2.col(2);
m1.col(2) = m2.col(1);
m1.col(3) = m2.col(0);
}
template <typename MatrixType>
EIGEN_DONT_INLINE void bug1684_job3(MatrixType& m1, MatrixType& m2) {
m2 = m1;
Vector4f tmp;
tmp = m2.col(0);
m2.col(0) = m2.col(3);
m2.col(3) = tmp;
tmp = m2.col(1);
m2.col(1) = m2.col(2);
m2.col(2) = tmp;
}
template <int>
void bug1684() {
Matrix4f m1 = Matrix4f::Random();
Matrix4f m2 = Matrix4f::Random();
bug1684_job1(m1, m2);
VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
bug1684_job2(m1, m2);
VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
// This one still fail after our swap's workaround,
// but I expect users not to implement their own swap.
// bug1684_job3(m1,m2);
// VERIFY_IS_APPROX(m2, m1.rowwise().reverse().eval());
}
EIGEN_DECLARE_TEST(array_reverse) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(reverse(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(reverse(Matrix2f()));
CALL_SUBTEST_3(reverse(Matrix4f()));
CALL_SUBTEST_4(reverse(Matrix4d()));
CALL_SUBTEST_5(reverse(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(reverse(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_7(reverse(
MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_8(reverse(Matrix<float, 100, 100>()));
CALL_SUBTEST_9(reverse(Matrix<float, Dynamic, Dynamic, RowMajor>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE),
internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_3(bug1684<0>());
}
CALL_SUBTEST_3(array_reverse_extra<0>());
}
+84
View File
@@ -0,0 +1,84 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2023 Charlie Schlosser <cs.schlosser@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define EIGEN_USE_THREADS 1
#include "main.h"
#include <Eigen/ThreadPool>
namespace Eigen {
namespace internal {
// conveniently control vectorization logic
template <typename Scalar, bool Vectorize>
struct scalar_dummy_op {
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const Scalar& a) const { return a; }
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const {
return a;
}
};
template <typename Scalar, bool Vectorize>
struct functor_traits<scalar_dummy_op<Scalar, Vectorize> > {
enum { Cost = 1'000'000, PacketAccess = Vectorize && packet_traits<Scalar>::Vectorizable };
};
} // namespace internal
} // namespace Eigen
template <typename PlainObject>
void test_threaded_assignment(const PlainObject&, Index rows = PlainObject::RowsAtCompileTime,
Index cols = PlainObject::ColsAtCompileTime) {
using Scalar = typename PlainObject::Scalar;
using VectorizationOff = internal::scalar_dummy_op<Scalar, false>;
using VectorizationOn = internal::scalar_dummy_op<Scalar, true>;
int threads = 4;
ThreadPool pool(threads);
CoreThreadPoolDevice threadPoolDevice(pool);
PlainObject dst(rows, cols), ref(rows, cols), rhs(rows, cols);
rhs.setRandom();
const auto rhs_xpr = rhs.cwiseAbs2();
// linear access
dst.setRandom();
ref.setRandom();
ref = rhs_xpr.unaryExpr(VectorizationOff());
dst.device(threadPoolDevice) = rhs_xpr.unaryExpr(VectorizationOff());
VERIFY_IS_CWISE_EQUAL(ref, dst);
ref = rhs_xpr.unaryExpr(VectorizationOn());
dst.device(threadPoolDevice) = rhs_xpr.unaryExpr(VectorizationOn());
VERIFY_IS_CWISE_EQUAL(ref, dst);
// outer-inner access
Index blockRows = numext::maxi(Index(1), rows - 1);
Index blockCols = numext::maxi(Index(1), cols - 1);
dst.setRandom();
ref.setRandom();
ref.bottomRightCorner(blockRows, blockCols) =
rhs_xpr.bottomRightCorner(blockRows, blockCols).unaryExpr(VectorizationOff());
dst.bottomRightCorner(blockRows, blockCols).device(threadPoolDevice) =
rhs_xpr.bottomRightCorner(blockRows, blockCols).unaryExpr(VectorizationOff());
VERIFY_IS_CWISE_EQUAL(ref.bottomRightCorner(blockRows, blockCols), dst.bottomRightCorner(blockRows, blockCols));
ref.setZero();
dst.setZero();
ref.bottomRightCorner(blockRows, blockCols) =
rhs_xpr.bottomRightCorner(blockRows, blockCols).unaryExpr(VectorizationOn());
dst.bottomRightCorner(blockRows, blockCols).device(threadPoolDevice) =
rhs_xpr.bottomRightCorner(blockRows, blockCols).unaryExpr(VectorizationOn());
VERIFY_IS_CWISE_EQUAL(ref.bottomRightCorner(blockRows, blockCols), dst.bottomRightCorner(blockRows, blockCols));
}
EIGEN_DECLARE_TEST(test) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST(test_threaded_assignment(MatrixXd(), 123, 123));
CALL_SUBTEST(test_threaded_assignment(Matrix<float, 16, 16>()));
}
}
+66
View File
@@ -0,0 +1,66 @@
// This file is triangularView of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType>
void bandmatrix(const MatrixType& _m) {
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, Dynamic, Dynamic> DenseMatrixType;
Index rows = _m.rows();
Index cols = _m.cols();
Index supers = _m.supers();
Index subs = _m.subs();
MatrixType m(rows, cols, supers, subs);
DenseMatrixType dm1(rows, cols);
dm1.setZero();
m.diagonal().setConstant(123);
dm1.diagonal().setConstant(123);
for (int i = 1; i <= m.supers(); ++i) {
m.diagonal(i).setConstant(static_cast<RealScalar>(i));
dm1.diagonal(i).setConstant(static_cast<RealScalar>(i));
}
for (int i = 1; i <= m.subs(); ++i) {
m.diagonal(-i).setConstant(-static_cast<RealScalar>(i));
dm1.diagonal(-i).setConstant(-static_cast<RealScalar>(i));
}
// std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n\n\n";
VERIFY_IS_APPROX(dm1, m.toDenseMatrix());
for (int i = 0; i < cols; ++i) {
m.col(i).setConstant(static_cast<RealScalar>(i + 1));
dm1.col(i).setConstant(static_cast<RealScalar>(i + 1));
}
Index d = (std::min)(rows, cols);
Index a = std::max<Index>(0, cols - d - supers);
Index b = std::max<Index>(0, rows - d - subs);
if (a > 0) dm1.block(0, d + supers, rows, a).setZero();
dm1.block(0, supers + 1, cols - supers - 1 - a, cols - supers - 1 - a).template triangularView<Upper>().setZero();
dm1.block(subs + 1, 0, rows - subs - 1 - b, rows - subs - 1 - b).template triangularView<Lower>().setZero();
if (b > 0) dm1.block(d + subs, 0, b, cols).setZero();
// std::cerr << m.m_data << "\n\n" << m.toDense() << "\n\n" << dm1 << "\n\n";
VERIFY_IS_APPROX(dm1, m.toDenseMatrix());
}
using Eigen::internal::BandMatrix;
EIGEN_DECLARE_TEST(bandmatrix) {
for (int i = 0; i < 10 * g_repeat; i++) {
Index rows = internal::random<Index>(1, 10);
Index cols = internal::random<Index>(1, 10);
Index sups = internal::random<Index>(0, cols - 1);
Index subs = internal::random<Index>(0, rows - 1);
CALL_SUBTEST(bandmatrix(BandMatrix<float>(rows, cols, sups, subs)));
}
}
+352
View File
@@ -0,0 +1,352 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include "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;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
Index rows = m.rows();
Index cols = m.cols();
// this test relies a lot on Random.h, and there's not much more that we can do
// to test it, hence I consider that we will have tested Random.h
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols),
mzero = MatrixType::Zero(rows, cols),
square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
VectorType v1 = VectorType::Random(rows), vzero = VectorType::Zero(rows);
SquareMatrixType sm1 = SquareMatrixType::Random(rows, rows), sm2(rows, rows);
Scalar x = 0;
while (x == Scalar(0)) x = internal::random<Scalar>();
Index r = internal::random<Index>(0, rows - 1), c = internal::random<Index>(0, cols - 1);
m1.coeffRef(r, c) = x;
VERIFY_IS_APPROX(x, m1.coeff(r, c));
m1(r, c) = x;
VERIFY_IS_APPROX(x, m1(r, c));
v1.coeffRef(r) = x;
VERIFY_IS_APPROX(x, v1.coeff(r));
v1(r) = x;
VERIFY_IS_APPROX(x, v1(r));
v1[r] = x;
VERIFY_IS_APPROX(x, v1[r]);
// test fetching with various index types.
Index r1 = internal::random<Index>(0, numext::mini(Index(127), rows - 1));
x = v1(static_cast<char>(r1));
x = v1(static_cast<signed char>(r1));
x = v1(static_cast<unsigned char>(r1));
x = v1(static_cast<signed short>(r1));
x = v1(static_cast<unsigned short>(r1));
x = v1(static_cast<signed int>(r1));
x = v1(static_cast<unsigned int>(r1));
x = v1(static_cast<signed long>(r1));
x = v1(static_cast<unsigned long>(r1));
if (sizeof(Index) >= sizeof(long long int)) x = v1(static_cast<long long int>(r1));
if (sizeof(Index) >= sizeof(unsigned long long int)) x = v1(static_cast<unsigned long long int>(r1));
VERIFY_IS_APPROX(v1, v1);
VERIFY_IS_NOT_APPROX(v1, 2 * v1);
VERIFY_IS_MUCH_SMALLER_THAN(vzero, v1);
VERIFY_IS_MUCH_SMALLER_THAN(vzero, v1.squaredNorm());
VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1);
VERIFY_IS_APPROX(vzero, v1 - v1);
VERIFY_IS_APPROX(m1, m1);
VERIFY_IS_NOT_APPROX(m1, 2 * m1);
VERIFY_IS_MUCH_SMALLER_THAN(mzero, m1);
VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1);
VERIFY_IS_APPROX(mzero, m1 - m1);
// always test operator() on each read-only expression class,
// in order to check const-qualifiers.
// indeed, if an expression class (here Zero) is meant to be read-only,
// hence has no _write() method, the corresponding MatrixBase method (here zero())
// should return a const-qualified object so that it is the const-qualified
// operator() that gets called, which in turn calls _read().
VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols)(r, c), static_cast<Scalar>(1));
// now test copying a row-vector into a (column-)vector and conversely.
square.col(r) = square.row(r).eval();
Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
rv = square.row(r);
cv = square.col(r);
VERIFY_IS_APPROX(rv, cv.transpose());
if (cols != 1 && rows != 1 && MatrixType::SizeAtCompileTime != Dynamic) {
VERIFY_RAISES_ASSERT(m1 = (m2.block(0, 0, rows - 1, cols - 1)));
}
if (cols != 1 && rows != 1) {
check_index(m1);
}
VERIFY_IS_APPROX(m3 = m1, m1);
MatrixType m4;
VERIFY_IS_APPROX(m4 = m1, m1);
m3.real() = m1.real();
VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real());
VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real());
// check == / != operators
VERIFY(m1 == m1);
VERIFY(m1 != m2);
VERIFY(!(m1 == m2));
VERIFY(!(m1 != m1));
m1 = m2;
VERIFY(m1 == m2);
VERIFY(!(m1 != m2));
// check automatic transposition
sm2.setZero();
for (Index i = 0; i < rows; ++i) sm2.col(i) = sm1.row(i);
VERIFY_IS_APPROX(sm2, sm1.transpose());
sm2.setZero();
for (Index i = 0; i < rows; ++i) sm2.col(i).noalias() = sm1.row(i);
VERIFY_IS_APPROX(sm2, sm1.transpose());
sm2.setZero();
for (Index i = 0; i < rows; ++i) sm2.col(i).noalias() += sm1.row(i);
VERIFY_IS_APPROX(sm2, sm1.transpose());
sm2.setZero();
for (Index i = 0; i < rows; ++i) sm2.col(i).noalias() -= sm1.row(i);
VERIFY_IS_APPROX(sm2, -sm1.transpose());
// check ternary usage
{
bool b = internal::random<int>(0, 10) > 5;
m3 = b ? m1 : m2;
if (b)
VERIFY_IS_APPROX(m3, m1);
else
VERIFY_IS_APPROX(m3, m2);
m3 = b ? -m1 : m2;
if (b)
VERIFY_IS_APPROX(m3, -m1);
else
VERIFY_IS_APPROX(m3, m2);
m3 = b ? m1 : -m2;
if (b)
VERIFY_IS_APPROX(m3, m1);
else
VERIFY_IS_APPROX(m3, -m2);
}
}
template <typename MatrixType>
void basicStuffComplex(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> RealMatrixType;
Index rows = m.rows();
Index cols = m.cols();
Scalar s1 = internal::random<Scalar>(), s2 = internal::random<Scalar>();
VERIFY(numext::real(s1) == numext::real_ref(s1));
VERIFY(numext::imag(s1) == numext::imag_ref(s1));
numext::real_ref(s1) = numext::real(s2);
numext::imag_ref(s1) = numext::imag(s2);
VERIFY(internal::isApprox(s1, s2, NumTraits<RealScalar>::epsilon()));
// extended precision in Intel FPUs means that s1 == s2 in the line above is not guaranteed.
RealMatrixType rm1 = RealMatrixType::Random(rows, cols), rm2 = RealMatrixType::Random(rows, cols);
MatrixType cm(rows, cols);
cm.real() = rm1;
cm.imag() = rm2;
VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).real(), rm1);
VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).imag(), rm2);
rm1.setZero();
rm2.setZero();
rm1 = cm.real();
rm2 = cm.imag();
VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).real(), rm1);
VERIFY_IS_APPROX(static_cast<const MatrixType&>(cm).imag(), rm2);
cm.real().setZero();
VERIFY(static_cast<const MatrixType&>(cm).real().isZero());
VERIFY(!static_cast<const MatrixType&>(cm).imag().isZero());
}
template <typename SrcScalar, typename TgtScalar>
struct casting_test {
static void run() {
Matrix<SrcScalar, 4, 4> m;
for (int i = 0; i < m.rows(); ++i) {
for (int j = 0; j < m.cols(); ++j) {
m(i, j) = internal::random_without_cast_overflow<SrcScalar, TgtScalar>::value();
}
}
Matrix<TgtScalar, 4, 4> n = m.template cast<TgtScalar>();
for (int i = 0; i < m.rows(); ++i) {
for (int j = 0; j < m.cols(); ++j) {
VERIFY_IS_APPROX(n(i, j), (internal::cast<SrcScalar, TgtScalar>(m(i, j))));
}
}
}
};
template <typename SrcScalar, typename EnableIf = void>
struct casting_test_runner {
static void run() {
casting_test<SrcScalar, bool>::run();
casting_test<SrcScalar, int8_t>::run();
casting_test<SrcScalar, uint8_t>::run();
casting_test<SrcScalar, int16_t>::run();
casting_test<SrcScalar, uint16_t>::run();
casting_test<SrcScalar, int32_t>::run();
casting_test<SrcScalar, uint32_t>::run();
casting_test<SrcScalar, int64_t>::run();
casting_test<SrcScalar, uint64_t>::run();
casting_test<SrcScalar, half>::run();
casting_test<SrcScalar, bfloat16>::run();
casting_test<SrcScalar, float>::run();
casting_test<SrcScalar, double>::run();
casting_test<SrcScalar, std::complex<float>>::run();
casting_test<SrcScalar, std::complex<double>>::run();
}
};
template <typename SrcScalar>
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.
casting_test<SrcScalar, half>::run();
casting_test<SrcScalar, bfloat16>::run();
casting_test<SrcScalar, std::complex<float>>::run();
casting_test<SrcScalar, std::complex<double>>::run();
}
};
void casting_all() {
casting_test_runner<bool>::run();
casting_test_runner<int8_t>::run();
casting_test_runner<uint8_t>::run();
casting_test_runner<int16_t>::run();
casting_test_runner<uint16_t>::run();
casting_test_runner<int32_t>::run();
casting_test_runner<uint32_t>::run();
casting_test_runner<int64_t>::run();
casting_test_runner<uint64_t>::run();
casting_test_runner<half>::run();
casting_test_runner<bfloat16>::run();
casting_test_runner<float>::run();
casting_test_runner<double>::run();
casting_test_runner<std::complex<float>>::run();
casting_test_runner<std::complex<double>>::run();
}
template <typename Scalar>
void fixedSizeMatrixConstruction() {
Scalar raw[4];
for (int k = 0; k < 4; ++k) raw[k] = internal::random<Scalar>();
{
Matrix<Scalar, 4, 1> m(raw);
Array<Scalar, 4, 1> a(raw);
for (int k = 0; k < 4; ++k) VERIFY(m(k) == raw[k]);
for (int k = 0; k < 4; ++k) VERIFY(a(k) == raw[k]);
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 4, 1>(raw[0], raw[1], raw[2], raw[3])));
VERIFY((a == (Array<Scalar, 4, 1>(raw[0], raw[1], raw[2], raw[3]))).all());
}
{
Matrix<Scalar, 3, 1> m(raw);
Array<Scalar, 3, 1> a(raw);
for (int k = 0; k < 3; ++k) VERIFY(m(k) == raw[k]);
for (int k = 0; k < 3; ++k) VERIFY(a(k) == raw[k]);
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 3, 1>(raw[0], raw[1], raw[2])));
VERIFY((a == Array<Scalar, 3, 1>(raw[0], raw[1], raw[2])).all());
}
{
Matrix<Scalar, 2, 1> m(raw), m2((DenseIndex(raw[0])), (DenseIndex(raw[1])));
Array<Scalar, 2, 1> a(raw), a2((DenseIndex(raw[0])), (DenseIndex(raw[1])));
for (int k = 0; k < 2; ++k) VERIFY(m(k) == raw[k]);
for (int k = 0; k < 2; ++k) VERIFY(a(k) == raw[k]);
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 2, 1>(raw[0], raw[1])));
VERIFY((a == Array<Scalar, 2, 1>(raw[0], raw[1])).all());
for (int k = 0; k < 2; ++k) VERIFY(m2(k) == DenseIndex(raw[k]));
for (int k = 0; k < 2; ++k) VERIFY(a2(k) == DenseIndex(raw[k]));
}
{
Matrix<Scalar, 1, 2> m(raw), m2((DenseIndex(raw[0])), (DenseIndex(raw[1]))), m3((int(raw[0])), (int(raw[1]))),
m4((float(raw[0])), (float(raw[1])));
Array<Scalar, 1, 2> a(raw), a2((DenseIndex(raw[0])), (DenseIndex(raw[1])));
for (int k = 0; k < 2; ++k) VERIFY(m(k) == raw[k]);
for (int k = 0; k < 2; ++k) VERIFY(a(k) == raw[k]);
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 1, 2>(raw[0], raw[1])));
VERIFY((a == Array<Scalar, 1, 2>(raw[0], raw[1])).all());
for (int k = 0; k < 2; ++k) VERIFY(m2(k) == DenseIndex(raw[k]));
for (int k = 0; k < 2; ++k) VERIFY(a2(k) == DenseIndex(raw[k]));
for (int k = 0; k < 2; ++k) VERIFY(m3(k) == int(raw[k]));
for (int k = 0; k < 2; ++k) VERIFY((m4(k)) == Scalar(float(raw[k])));
}
{
Matrix<Scalar, 1, 1> m(raw), m1(raw[0]), m2((DenseIndex(raw[0]))), m3((int(raw[0])));
Array<Scalar, 1, 1> a(raw), a1(raw[0]), a2((DenseIndex(raw[0])));
VERIFY(m(0) == raw[0]);
VERIFY(a(0) == raw[0]);
VERIFY(m1(0) == raw[0]);
VERIFY(a1(0) == raw[0]);
VERIFY(m2(0) == DenseIndex(raw[0]));
VERIFY(a2(0) == DenseIndex(raw[0]));
VERIFY(m3(0) == int(raw[0]));
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 1, 1>(raw[0])));
VERIFY((a == Array<Scalar, 1, 1>(raw[0])).all());
}
}
EIGEN_DECLARE_TEST(basicstuff) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(basicStuff(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(basicStuff(Matrix4d()));
CALL_SUBTEST_3(basicStuff(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_4(basicStuff(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_5(basicStuff(
MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(basicStuff(Matrix<float, 100, 100>()));
CALL_SUBTEST_7(basicStuff(Matrix<long double, Dynamic, Dynamic>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE),
internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_8(casting_all());
CALL_SUBTEST_3(basicStuffComplex(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_5(basicStuffComplex(
MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
CALL_SUBTEST_1(fixedSizeMatrixConstruction<unsigned char>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<float>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<double>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<int>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<long int>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<std::ptrdiff_t>());
}
+177
View File
@@ -0,0 +1,177 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2013 Gauthier Brun <brun.gauthier@gmail.com>
// Copyright (C) 2013 Nicolas Carre <nicolas.carre@ensimag.fr>
// Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr>
// Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/
// discard stack allocation as that too bypasses malloc
#define EIGEN_STACK_ALLOCATION_LIMIT 0
#define EIGEN_RUNTIME_NO_MALLOC
#include "main.h"
#include <Eigen/SVD>
#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"
template <typename MatrixType>
void bdcsvd_method() {
enum { Size = MatrixType::RowsAtCompileTime };
typedef typename MatrixType::RealScalar RealScalar;
typedef Matrix<RealScalar, Size, 1> RealVecType;
MatrixType m = MatrixType::Identity();
VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones());
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU());
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV());
}
// compare the Singular values returned with Jacobi and Bdc
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());
}
// 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_thin_options(const MatrixType& input = MatrixType()) {
svd_thin_option_checks<MatrixType, 0>(input);
}
template <typename MatrixType>
void bdcsvd_full_options(const MatrixType& input = MatrixType()) {
svd_option_checks_full_only<MatrixType, 0>(input);
}
template <typename MatrixType>
void bdcsvd_verify_assert(const MatrixType& input = MatrixType()) {
svd_verify_assert<MatrixType>(input);
svd_verify_constructor_options_assert<BDCSVD<MatrixType>>(input);
}
template <typename MatrixType>
void bdcsvd_check_convergence(const MatrixType& input) {
BDCSVD<MatrixType, Eigen::ComputeThinU | Eigen::ComputeThinV> svd(input);
VERIFY(svd.info() == Eigen::Success);
MatrixType D = svd.matrixU() * svd.singularValues().asDiagonal() * svd.matrixV().transpose();
VERIFY_IS_APPROX(input, D);
}
EIGEN_DECLARE_TEST(bdcsvd) {
CALL_SUBTEST_1((bdcsvd_verify_assert<Matrix3f>()));
CALL_SUBTEST_2((bdcsvd_verify_assert<Matrix4d>()));
CALL_SUBTEST_3((bdcsvd_verify_assert<Matrix<float, 10, 7>>()));
CALL_SUBTEST_4((bdcsvd_verify_assert<Matrix<float, 7, 10>>()));
CALL_SUBTEST_5((bdcsvd_verify_assert<Matrix<std::complex<double>, 6, 9>>()));
CALL_SUBTEST_6((svd_all_trivial_2x2(bdcsvd_thin_options<Matrix2cd>)));
CALL_SUBTEST_7((svd_all_trivial_2x2(bdcsvd_full_options<Matrix2cd>)));
CALL_SUBTEST_8((svd_all_trivial_2x2(bdcsvd_thin_options<Matrix2d>)));
CALL_SUBTEST_9((svd_all_trivial_2x2(bdcsvd_full_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_10((compare_bdc_jacobi<MatrixXf>(MatrixXf(r, c))));
CALL_SUBTEST_11((compare_bdc_jacobi<MatrixXd>(MatrixXd(r, c))));
CALL_SUBTEST_12((compare_bdc_jacobi<MatrixXcd>(MatrixXcd(r, c))));
// Test on inf/nan matrix
CALL_SUBTEST_13((svd_inf_nan<MatrixXf>()));
CALL_SUBTEST_14((svd_inf_nan<MatrixXd>()));
// Verify some computations using all combinations of the Options template parameter.
CALL_SUBTEST_15((bdcsvd_thin_options<Matrix3f>()));
CALL_SUBTEST_16((bdcsvd_full_options<Matrix3f>()));
CALL_SUBTEST_17((bdcsvd_thin_options<Matrix<float, 2, 3>>()));
CALL_SUBTEST_18((bdcsvd_full_options<Matrix<float, 2, 3>>()));
CALL_SUBTEST_19((bdcsvd_thin_options<MatrixXd>(MatrixXd(20, 17))));
CALL_SUBTEST_20((bdcsvd_full_options<MatrixXd>(MatrixXd(20, 17))));
CALL_SUBTEST_21((bdcsvd_thin_options<MatrixXd>(MatrixXd(17, 20))));
CALL_SUBTEST_22((bdcsvd_full_options<MatrixXd>(MatrixXd(17, 20))));
CALL_SUBTEST_23((bdcsvd_thin_options<Matrix<double, Dynamic, 15>>(Matrix<double, Dynamic, 15>(r, 15))));
CALL_SUBTEST_24((bdcsvd_full_options<Matrix<double, Dynamic, 15>>(Matrix<double, Dynamic, 15>(r, 15))));
CALL_SUBTEST_25((bdcsvd_thin_options<Matrix<double, 13, Dynamic>>(Matrix<double, 13, Dynamic>(13, c))));
CALL_SUBTEST_26((bdcsvd_full_options<Matrix<double, 13, Dynamic>>(Matrix<double, 13, Dynamic>(13, c))));
CALL_SUBTEST_27((bdcsvd_thin_options<MatrixXf>(MatrixXf(r, c))));
CALL_SUBTEST_28((bdcsvd_full_options<MatrixXf>(MatrixXf(r, c))));
CALL_SUBTEST_29((bdcsvd_thin_options<MatrixXcd>(MatrixXcd(r, c))));
CALL_SUBTEST_30((bdcsvd_full_options<MatrixXcd>(MatrixXcd(r, c))));
CALL_SUBTEST_31((bdcsvd_thin_options<MatrixXd>(MatrixXd(r, c))));
CALL_SUBTEST_32((bdcsvd_full_options<MatrixXd>(MatrixXd(r, c))));
CALL_SUBTEST_33((bdcsvd_thin_options<Matrix<double, Dynamic, Dynamic, RowMajor>>(
Matrix<double, Dynamic, Dynamic, RowMajor>(20, 27))));
CALL_SUBTEST_34((bdcsvd_full_options<Matrix<double, Dynamic, Dynamic, RowMajor>>(
Matrix<double, Dynamic, Dynamic, RowMajor>(20, 27))));
CALL_SUBTEST_35((bdcsvd_thin_options<Matrix<double, Dynamic, Dynamic, RowMajor>>(
Matrix<double, Dynamic, Dynamic, RowMajor>(27, 20))));
CALL_SUBTEST_36((bdcsvd_full_options<Matrix<double, Dynamic, Dynamic, RowMajor>>(
Matrix<double, Dynamic, Dynamic, RowMajor>(27, 20))));
CALL_SUBTEST_37((
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 20, 35>, ColPivHouseholderQRPreconditioner>(
r, c)));
CALL_SUBTEST_38(
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 35, 20>, HouseholderQRPreconditioner>(r,
c)));
CALL_SUBTEST_39((
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 20, 35>, ColPivHouseholderQRPreconditioner>(
r, c)));
CALL_SUBTEST_40(
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 35, 20>, HouseholderQRPreconditioner>(r,
c)));
}
// test matrixbase method
CALL_SUBTEST_41((bdcsvd_method<Matrix2cd>()));
CALL_SUBTEST_42((bdcsvd_method<Matrix3f>()));
// Test problem size constructors
CALL_SUBTEST_43(BDCSVD<MatrixXf>(10, 10));
// Check that preallocation avoids subsequent mallocs
// Disabled because not supported by BDCSVD
// CALL_SUBTEST_9( svd_preallocate<void>() );
CALL_SUBTEST_44(svd_underoverflow<void>());
// Without total deflation issues.
CALL_SUBTEST_45((compare_bdc_jacobi_instance(true)));
CALL_SUBTEST_46((compare_bdc_jacobi_instance(false)));
// With total deflation issues before, when it shouldn't be triggered.
CALL_SUBTEST_47((compare_bdc_jacobi_instance(true, 3)));
CALL_SUBTEST_48((compare_bdc_jacobi_instance(false, 3)));
// Convergence for large constant matrix (https://gitlab.com/libeigen/eigen/-/issues/2491)
CALL_SUBTEST_49(bdcsvd_check_convergence<MatrixXf>(MatrixXf::Constant(500, 500, 1)));
}
+402
View File
@@ -0,0 +1,402 @@
// 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 <sstream>
#include <memory>
#include <math.h>
#include "main.h"
#define VERIFY_BFLOAT16_BITS_EQUAL(h, bits) \
VERIFY_IS_EQUAL((numext::bit_cast<numext::uint16_t>(h)), (static_cast<numext::uint16_t>(bits)))
// Make sure it's possible to forward declare Eigen::bfloat16
namespace Eigen {
struct bfloat16;
}
using Eigen::bfloat16;
float BinaryToFloat(uint32_t sign, uint32_t exponent, uint32_t high_mantissa, uint32_t low_mantissa) {
float dest;
uint32_t src = (sign << 31) + (exponent << 23) + (high_mantissa << 16) + low_mantissa;
memcpy(static_cast<void*>(&dest), static_cast<const void*>(&src), sizeof(dest));
return dest;
}
template <typename T>
void test_roundtrip() {
// Representable T round trip via bfloat16
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(-std::numeric_limits<T>::infinity()))),
-std::numeric_limits<T>::infinity());
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(std::numeric_limits<T>::infinity()))),
std::numeric_limits<T>::infinity());
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(T(-1.0)))), T(-1.0));
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(T(-0.5)))), T(-0.5));
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(T(-0.0)))), T(-0.0));
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(T(1.0)))), T(1.0));
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(T(0.5)))), T(0.5));
VERIFY_IS_EQUAL((internal::cast<bfloat16, T>(internal::cast<T, bfloat16>(T(0.0)))), T(0.0));
}
void test_conversion() {
using Eigen::bfloat16_impl::__bfloat16_raw;
// Round-trip casts
VERIFY_IS_EQUAL(numext::bit_cast<bfloat16>(numext::bit_cast<numext::uint16_t>(bfloat16(1.0f))), bfloat16(1.0f));
VERIFY_IS_EQUAL(numext::bit_cast<bfloat16>(numext::bit_cast<numext::uint16_t>(bfloat16(0.5f))), bfloat16(0.5f));
VERIFY_IS_EQUAL(numext::bit_cast<bfloat16>(numext::bit_cast<numext::uint16_t>(bfloat16(-0.33333f))),
bfloat16(-0.33333f));
VERIFY_IS_EQUAL(numext::bit_cast<bfloat16>(numext::bit_cast<numext::uint16_t>(bfloat16(0.0f))), bfloat16(0.0f));
// Conversion from float.
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(1.0f), 0x3f80);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(0.5f), 0x3f00);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(0.33333f), 0x3eab);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(3.38e38f), 0x7f7e);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(3.40e38f), 0x7f80); // Becomes infinity.
// Verify round-to-nearest-even behavior.
float val1 = static_cast<float>(bfloat16(__bfloat16_raw(0x3c00)));
float val2 = static_cast<float>(bfloat16(__bfloat16_raw(0x3c01)));
float val3 = static_cast<float>(bfloat16(__bfloat16_raw(0x3c02)));
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(0.5f * (val1 + val2)), 0x3c00);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(0.5f * (val2 + val3)), 0x3c02);
// Conversion from int.
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(-1), 0xbf80);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(0), 0x0000);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(1), 0x3f80);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(2), 0x4000);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(3), 0x4040);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(12), 0x4140);
// Conversion from bool.
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(false), 0x0000);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(true), 0x3f80);
// Conversion to bool
VERIFY_IS_EQUAL(static_cast<bool>(bfloat16(3)), true);
VERIFY_IS_EQUAL(static_cast<bool>(bfloat16(0.33333f)), true);
VERIFY_IS_EQUAL(static_cast<bool>(bfloat16(-0.0)), false);
VERIFY_IS_EQUAL(static_cast<bool>(bfloat16(0.0)), false);
// Explicit conversion to float.
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(__bfloat16_raw(0x0000))), 0.0f);
VERIFY_IS_EQUAL(static_cast<float>(bfloat16(__bfloat16_raw(0x3f80))), 1.0f);
// Implicit conversion to float
VERIFY_IS_EQUAL(bfloat16(__bfloat16_raw(0x0000)), 0.0f);
VERIFY_IS_EQUAL(bfloat16(__bfloat16_raw(0x3f80)), 1.0f);
// Zero representations
VERIFY_IS_EQUAL(bfloat16(0.0f), bfloat16(0.0f));
VERIFY_IS_EQUAL(bfloat16(-0.0f), bfloat16(0.0f));
VERIFY_IS_EQUAL(bfloat16(-0.0f), bfloat16(-0.0f));
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(0.0f), 0x0000);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(-0.0f), 0x8000);
// Default is zero
VERIFY_IS_EQUAL(static_cast<float>(bfloat16()), 0.0f);
// Representable floats round trip via bfloat16
test_roundtrip<float>();
test_roundtrip<double>();
test_roundtrip<std::complex<float> >();
test_roundtrip<std::complex<double> >();
// Conversion
Array<float, 1, 100> a;
for (int i = 0; i < 100; i++) a(i) = i + 1.25;
Array<bfloat16, 1, 100> b = a.cast<bfloat16>();
Array<float, 1, 100> c = b.cast<float>();
for (int i = 0; i < 100; ++i) {
VERIFY_LE(numext::abs(c(i) - a(i)), a(i) / 128);
}
// Epsilon
VERIFY_LE(1.0f, static_cast<float>((std::numeric_limits<bfloat16>::epsilon)() + bfloat16(1.0f)));
VERIFY_IS_EQUAL(1.0f,
static_cast<float>((std::numeric_limits<bfloat16>::epsilon)() / bfloat16(2.0f) + bfloat16(1.0f)));
// Negate
VERIFY_IS_EQUAL(static_cast<float>(-bfloat16(3.0f)), -3.0f);
VERIFY_IS_EQUAL(static_cast<float>(-bfloat16(-4.5f)), 4.5f);
#if !EIGEN_COMP_MSVC
// Visual Studio errors out on divisions by 0
VERIFY((numext::isnan)(static_cast<float>(bfloat16(0.0 / 0.0))));
VERIFY((numext::isinf)(static_cast<float>(bfloat16(1.0 / 0.0))));
VERIFY((numext::isinf)(static_cast<float>(bfloat16(-1.0 / 0.0))));
// Visual Studio errors out on divisions by 0
VERIFY((numext::isnan)(bfloat16(0.0 / 0.0)));
VERIFY((numext::isinf)(bfloat16(1.0 / 0.0)));
VERIFY((numext::isinf)(bfloat16(-1.0 / 0.0)));
#endif
// NaNs and infinities.
VERIFY(!(numext::isinf)(static_cast<float>(bfloat16(3.38e38f)))); // Largest finite number.
VERIFY(!(numext::isnan)(static_cast<float>(bfloat16(0.0f))));
VERIFY((numext::isinf)(static_cast<float>(bfloat16(__bfloat16_raw(0xff80)))));
VERIFY((numext::isnan)(static_cast<float>(bfloat16(__bfloat16_raw(0xffc0)))));
VERIFY((numext::isinf)(static_cast<float>(bfloat16(__bfloat16_raw(0x7f80)))));
VERIFY((numext::isnan)(static_cast<float>(bfloat16(__bfloat16_raw(0x7fc0)))));
// Exactly same checks as above, just directly on the bfloat16 representation.
VERIFY(!(numext::isinf)(bfloat16(__bfloat16_raw(0x7bff))));
VERIFY(!(numext::isnan)(bfloat16(__bfloat16_raw(0x0000))));
VERIFY((numext::isinf)(bfloat16(__bfloat16_raw(0xff80))));
VERIFY((numext::isnan)(bfloat16(__bfloat16_raw(0xffc0))));
VERIFY((numext::isinf)(bfloat16(__bfloat16_raw(0x7f80))));
VERIFY((numext::isnan)(bfloat16(__bfloat16_raw(0x7fc0))));
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(BinaryToFloat(0x0, 0xff, 0x40, 0x0)), 0x7fc0);
VERIFY_BFLOAT16_BITS_EQUAL(bfloat16(BinaryToFloat(0x1, 0xff, 0x40, 0x0)), 0xffc0);
}
void test_numtraits() {
std::cout << "epsilon = " << NumTraits<bfloat16>::epsilon() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<bfloat16>::epsilon()) << ")" << std::endl;
std::cout << "highest = " << NumTraits<bfloat16>::highest() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<bfloat16>::highest()) << ")" << std::endl;
std::cout << "lowest = " << NumTraits<bfloat16>::lowest() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<bfloat16>::lowest()) << ")" << std::endl;
std::cout << "min = " << (std::numeric_limits<bfloat16>::min)() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>((std::numeric_limits<bfloat16>::min)()) << ")" << std::endl;
std::cout << "denorm min = " << (std::numeric_limits<bfloat16>::denorm_min)() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>((std::numeric_limits<bfloat16>::denorm_min)()) << ")" << std::endl;
std::cout << "infinity = " << NumTraits<bfloat16>::infinity() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<bfloat16>::infinity()) << ")" << std::endl;
std::cout << "quiet nan = " << NumTraits<bfloat16>::quiet_NaN() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<bfloat16>::quiet_NaN()) << ")" << std::endl;
std::cout << "signaling nan = " << std::numeric_limits<bfloat16>::signaling_NaN() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(std::numeric_limits<bfloat16>::signaling_NaN()) << ")" << std::endl;
VERIFY(NumTraits<bfloat16>::IsSigned);
VERIFY_IS_EQUAL(numext::bit_cast<numext::uint16_t>(std::numeric_limits<bfloat16>::infinity()),
numext::bit_cast<numext::uint16_t>(bfloat16(std::numeric_limits<float>::infinity())));
// There is no guarantee that casting a 32-bit NaN to bfloat16 has a precise
// bit pattern. We test that it is in fact a NaN, then test the signaling
// bit (msb of significand is 1 for quiet, 0 for signaling).
const numext::uint16_t BFLOAT16_QUIET_BIT = 0x0040;
VERIFY((numext::isnan)(std::numeric_limits<bfloat16>::quiet_NaN()) &&
(numext::isnan)(bfloat16(std::numeric_limits<float>::quiet_NaN())) &&
((numext::bit_cast<numext::uint16_t>(std::numeric_limits<bfloat16>::quiet_NaN()) & BFLOAT16_QUIET_BIT) > 0) &&
((numext::bit_cast<numext::uint16_t>(bfloat16(std::numeric_limits<float>::quiet_NaN())) & BFLOAT16_QUIET_BIT) >
0));
// After a cast to bfloat16, a signaling NaN may become non-signaling. Thus,
// we check that both are NaN, and that only the `numeric_limits` version is
// signaling.
VERIFY(
(numext::isnan)(std::numeric_limits<bfloat16>::signaling_NaN()) &&
(numext::isnan)(bfloat16(std::numeric_limits<float>::signaling_NaN())) &&
((numext::bit_cast<numext::uint16_t>(std::numeric_limits<bfloat16>::signaling_NaN()) & BFLOAT16_QUIET_BIT) == 0));
VERIFY((std::numeric_limits<bfloat16>::min)() > bfloat16(0.f));
VERIFY((std::numeric_limits<bfloat16>::denorm_min)() > bfloat16(0.f));
VERIFY_IS_EQUAL((std::numeric_limits<bfloat16>::denorm_min)() / bfloat16(2), bfloat16(0.f));
}
void test_arithmetic() {
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);
VERIFY_IS_EQUAL(static_cast<float>(-bfloat16(4096.0f)), -4096.0f);
VERIFY_IS_EQUAL(static_cast<float>(-bfloat16(-4096.0f)), 4096.0f);
}
void test_comparison() {
VERIFY(bfloat16(1.0f) > bfloat16(0.5f));
VERIFY(bfloat16(0.5f) < bfloat16(1.0f));
VERIFY(!(bfloat16(1.0f) < bfloat16(0.5f)));
VERIFY(!(bfloat16(0.5f) > bfloat16(1.0f)));
VERIFY(!(bfloat16(4.0f) > bfloat16(4.0f)));
VERIFY(!(bfloat16(4.0f) < bfloat16(4.0f)));
VERIFY(!(bfloat16(0.0f) < bfloat16(-0.0f)));
VERIFY(!(bfloat16(-0.0f) < bfloat16(0.0f)));
VERIFY(!(bfloat16(0.0f) > bfloat16(-0.0f)));
VERIFY(!(bfloat16(-0.0f) > bfloat16(0.0f)));
VERIFY(bfloat16(0.2f) > bfloat16(-1.0f));
VERIFY(bfloat16(-1.0f) < bfloat16(0.2f));
VERIFY(bfloat16(-16.0f) < bfloat16(-15.0f));
VERIFY(bfloat16(1.0f) == bfloat16(1.0f));
VERIFY(bfloat16(1.0f) != bfloat16(2.0f));
// Comparisons with NaNs and infinities.
#if !EIGEN_COMP_MSVC
// Visual Studio errors out on divisions by 0
VERIFY(!(bfloat16(0.0 / 0.0) == bfloat16(0.0 / 0.0)));
VERIFY(bfloat16(0.0 / 0.0) != bfloat16(0.0 / 0.0));
VERIFY(!(bfloat16(1.0) == bfloat16(0.0 / 0.0)));
VERIFY(!(bfloat16(1.0) < bfloat16(0.0 / 0.0)));
VERIFY(!(bfloat16(1.0) > bfloat16(0.0 / 0.0)));
VERIFY(bfloat16(1.0) != bfloat16(0.0 / 0.0));
VERIFY(bfloat16(1.0) < bfloat16(1.0 / 0.0));
VERIFY(bfloat16(1.0) > bfloat16(-1.0 / 0.0));
#endif
}
void test_basic_functions() {
VERIFY_IS_EQUAL(static_cast<float>(numext::abs(bfloat16(3.5f))), 3.5f);
VERIFY_IS_EQUAL(static_cast<float>(abs(bfloat16(3.5f))), 3.5f);
VERIFY_IS_EQUAL(static_cast<float>(numext::abs(bfloat16(-3.5f))), 3.5f);
VERIFY_IS_EQUAL(static_cast<float>(abs(bfloat16(-3.5f))), 3.5f);
VERIFY_IS_EQUAL(static_cast<float>(numext::floor(bfloat16(3.5f))), 3.0f);
VERIFY_IS_EQUAL(static_cast<float>(floor(bfloat16(3.5f))), 3.0f);
VERIFY_IS_EQUAL(static_cast<float>(numext::floor(bfloat16(-3.5f))), -4.0f);
VERIFY_IS_EQUAL(static_cast<float>(floor(bfloat16(-3.5f))), -4.0f);
VERIFY_IS_EQUAL(static_cast<float>(numext::ceil(bfloat16(3.5f))), 4.0f);
VERIFY_IS_EQUAL(static_cast<float>(ceil(bfloat16(3.5f))), 4.0f);
VERIFY_IS_EQUAL(static_cast<float>(numext::ceil(bfloat16(-3.5f))), -3.0f);
VERIFY_IS_EQUAL(static_cast<float>(ceil(bfloat16(-3.5f))), -3.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::sqrt(bfloat16(0.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(sqrt(bfloat16(0.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::sqrt(bfloat16(4.0f))), 2.0f);
VERIFY_IS_APPROX(static_cast<float>(sqrt(bfloat16(4.0f))), 2.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::pow(bfloat16(0.0f), bfloat16(1.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(pow(bfloat16(0.0f), bfloat16(1.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::pow(bfloat16(2.0f), bfloat16(2.0f))), 4.0f);
VERIFY_IS_APPROX(static_cast<float>(pow(bfloat16(2.0f), bfloat16(2.0f))), 4.0f);
VERIFY_IS_EQUAL(static_cast<float>(numext::exp(bfloat16(0.0f))), 1.0f);
VERIFY_IS_EQUAL(static_cast<float>(exp(bfloat16(0.0f))), 1.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::exp(bfloat16(EIGEN_PI))), 20.f + static_cast<float>(EIGEN_PI));
VERIFY_IS_APPROX(static_cast<float>(exp(bfloat16(EIGEN_PI))), 20.f + static_cast<float>(EIGEN_PI));
VERIFY_IS_EQUAL(static_cast<float>(numext::expm1(bfloat16(0.0f))), 0.0f);
VERIFY_IS_EQUAL(static_cast<float>(expm1(bfloat16(0.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::expm1(bfloat16(2.0f))), 6.375f);
VERIFY_IS_APPROX(static_cast<float>(expm1(bfloat16(2.0f))), 6.375f);
VERIFY_IS_EQUAL(static_cast<float>(numext::log(bfloat16(1.0f))), 0.0f);
VERIFY_IS_EQUAL(static_cast<float>(log(bfloat16(1.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::log(bfloat16(10.0f))), 2.296875f);
VERIFY_IS_APPROX(static_cast<float>(log(bfloat16(10.0f))), 2.296875f);
VERIFY_IS_EQUAL(static_cast<float>(numext::log1p(bfloat16(0.0f))), 0.0f);
VERIFY_IS_EQUAL(static_cast<float>(log1p(bfloat16(0.0f))), 0.0f);
VERIFY_IS_APPROX(static_cast<float>(numext::log1p(bfloat16(10.0f))), 2.390625f);
VERIFY_IS_APPROX(static_cast<float>(log1p(bfloat16(10.0f))), 2.390625f);
}
void test_trigonometric_functions() {
VERIFY_IS_APPROX(numext::cos(bfloat16(0.0f)), bfloat16(cosf(0.0f)));
VERIFY_IS_APPROX(cos(bfloat16(0.0f)), bfloat16(cosf(0.0f)));
VERIFY_IS_APPROX(numext::cos(bfloat16(EIGEN_PI)), bfloat16(cosf(EIGEN_PI)));
// VERIFY_IS_APPROX(numext::cos(bfloat16(EIGEN_PI/2)), bfloat16(cosf(EIGEN_PI/2)));
// VERIFY_IS_APPROX(numext::cos(bfloat16(3*EIGEN_PI/2)), bfloat16(cosf(3*EIGEN_PI/2)));
VERIFY_IS_APPROX(numext::cos(bfloat16(3.5f)), bfloat16(cosf(3.5f)));
VERIFY_IS_APPROX(numext::sin(bfloat16(0.0f)), bfloat16(sinf(0.0f)));
VERIFY_IS_APPROX(sin(bfloat16(0.0f)), bfloat16(sinf(0.0f)));
// VERIFY_IS_APPROX(numext::sin(bfloat16(EIGEN_PI)), bfloat16(sinf(EIGEN_PI)));
VERIFY_IS_APPROX(numext::sin(bfloat16(EIGEN_PI / 2)), bfloat16(sinf(EIGEN_PI / 2)));
VERIFY_IS_APPROX(numext::sin(bfloat16(3 * EIGEN_PI / 2)), bfloat16(sinf(3 * EIGEN_PI / 2)));
VERIFY_IS_APPROX(numext::sin(bfloat16(3.5f)), bfloat16(sinf(3.5f)));
VERIFY_IS_APPROX(numext::tan(bfloat16(0.0f)), bfloat16(tanf(0.0f)));
VERIFY_IS_APPROX(tan(bfloat16(0.0f)), bfloat16(tanf(0.0f)));
// VERIFY_IS_APPROX(numext::tan(bfloat16(EIGEN_PI)), bfloat16(tanf(EIGEN_PI)));
// VERIFY_IS_APPROX(numext::tan(bfloat16(EIGEN_PI/2)), bfloat16(tanf(EIGEN_PI/2)));
// VERIFY_IS_APPROX(numext::tan(bfloat16(3*EIGEN_PI/2)), bfloat16(tanf(3*EIGEN_PI/2)));
VERIFY_IS_APPROX(numext::tan(bfloat16(3.5f)), bfloat16(tanf(3.5f)));
}
void test_array() {
typedef Array<bfloat16, 1, Dynamic> ArrayXh;
Index size = internal::random<Index>(1, 10);
Index i = internal::random<Index>(0, size - 1);
ArrayXh a1 = ArrayXh::Random(size), a2 = ArrayXh::Random(size);
VERIFY_IS_APPROX(a1 + a1, bfloat16(2) * a1);
VERIFY((a1.abs() >= bfloat16(0)).all());
VERIFY_IS_APPROX((a1 * a1).sqrt(), a1.abs());
VERIFY(((a1.min)(a2) <= (a1.max)(a2)).all());
a1(i) = bfloat16(-10.);
VERIFY_IS_EQUAL(a1.minCoeff(), bfloat16(-10.));
a1(i) = bfloat16(10.);
VERIFY_IS_EQUAL(a1.maxCoeff(), bfloat16(10.));
std::stringstream ss;
ss << a1;
}
void test_product() {
typedef Matrix<bfloat16, Dynamic, Dynamic> MatrixXh;
Index rows = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
Index cols = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
Index depth = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
MatrixXh Ah = MatrixXh::Random(rows, depth);
MatrixXh Bh = MatrixXh::Random(depth, cols);
MatrixXh Ch = MatrixXh::Random(rows, cols);
MatrixXf Af = Ah.cast<float>();
MatrixXf Bf = Bh.cast<float>();
MatrixXf Cf = Ch.cast<float>();
VERIFY_IS_APPROX(Ch.noalias() += Ah * Bh, (Cf.noalias() += Af * Bf).cast<bfloat16>());
}
void test_nextafter() {
VERIFY((numext::isnan)(numext::nextafter(std::numeric_limits<bfloat16>::quiet_NaN(), bfloat16(1.0f))));
VERIFY((numext::isnan)(numext::nextafter(bfloat16(1.0f), std::numeric_limits<bfloat16>::quiet_NaN())));
VERIFY(numext::nextafter(bfloat16(0.0f), bfloat16(0.0f)) == bfloat16(0.0f));
VERIFY(numext::nextafter(bfloat16(1.0f), bfloat16(1.0f)) == bfloat16(1.0f));
VERIFY(numext::nextafter(bfloat16(-1.0f), bfloat16(-1.0f)) == bfloat16(-1.0f));
VERIFY(numext::nextafter(std::numeric_limits<bfloat16>::infinity(), std::numeric_limits<bfloat16>::infinity()) ==
std::numeric_limits<bfloat16>::infinity());
VERIFY(numext::nextafter(std::numeric_limits<bfloat16>::infinity(), bfloat16(0.0f)) ==
(std::numeric_limits<bfloat16>::max)());
VERIFY(numext::nextafter(-std::numeric_limits<bfloat16>::infinity(), bfloat16(0.0f)) ==
-(std::numeric_limits<bfloat16>::max)());
VERIFY(numext::nextafter(bfloat16(1.0f), std::numeric_limits<bfloat16>::infinity()) ==
bfloat16(1.0f) + std::numeric_limits<bfloat16>::epsilon());
VERIFY(numext::nextafter(bfloat16(1.0f), -std::numeric_limits<bfloat16>::infinity()) ==
bfloat16(1.0f) - std::numeric_limits<bfloat16>::epsilon() / bfloat16(2.0f));
VERIFY(numext::nextafter(bfloat16(-1.0f), -std::numeric_limits<bfloat16>::infinity()) ==
bfloat16(-1.0f) - std::numeric_limits<bfloat16>::epsilon());
VERIFY(numext::nextafter(bfloat16(-1.0f), std::numeric_limits<bfloat16>::infinity()) ==
bfloat16(-1.0f) + std::numeric_limits<bfloat16>::epsilon() / bfloat16(2.0f));
VERIFY(numext::nextafter((std::numeric_limits<bfloat16>::max)(), std::numeric_limits<bfloat16>::infinity()) ==
std::numeric_limits<bfloat16>::infinity());
VERIFY(numext::nextafter(-(std::numeric_limits<bfloat16>::max)(), -std::numeric_limits<bfloat16>::infinity()) ==
-std::numeric_limits<bfloat16>::infinity());
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(0.0f), bfloat16(1.0f)), 0x0001);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(-0.0f), bfloat16(1.0f)), 0x0000);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(0.0f), bfloat16(-1.0f)), 0x8000);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(-0.0f), bfloat16(-1.0f)), 0x8001);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(0.0f), bfloat16(-0.0f)), 0x8000);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(-0.0f), bfloat16(0.0f)), 0x0000);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(0.0f), bfloat16(0.0f)), 0x0000);
VERIFY_BFLOAT16_BITS_EQUAL(numext::nextafter(bfloat16(-0.0f), bfloat16(-0.0f)), 0x8000);
}
EIGEN_DECLARE_TEST(bfloat16_float) {
CALL_SUBTEST(test_numtraits());
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST(test_conversion());
CALL_SUBTEST(test_arithmetic());
CALL_SUBTEST(test_comparison());
CALL_SUBTEST(test_basic_functions());
CALL_SUBTEST(test_trigonometric_functions());
CALL_SUBTEST(test_array());
CALL_SUBTEST(test_product());
CALL_SUBTEST(test_nextafter());
}
}
+88
View File
@@ -0,0 +1,88 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "sparse_solver.h"
#include <Eigen/IterativeLinearSolvers>
template <typename T, typename I_>
void test_bicgstab_T() {
BiCGSTAB<SparseMatrix<T, 0, I_>, DiagonalPreconditioner<T> > bicgstab_colmajor_diag;
BiCGSTAB<SparseMatrix<T, 0, I_>, IdentityPreconditioner> bicgstab_colmajor_I;
BiCGSTAB<SparseMatrix<T, 0, I_>, IncompleteLUT<T, I_> > bicgstab_colmajor_ilut;
// BiCGSTAB<SparseMatrix<T>, SSORPreconditioner<T> > bicgstab_colmajor_ssor;
bicgstab_colmajor_diag.setTolerance(NumTraits<T>::epsilon() * 4);
bicgstab_colmajor_ilut.setTolerance(NumTraits<T>::epsilon() * 4);
CALL_SUBTEST(check_sparse_square_solving(bicgstab_colmajor_diag));
// CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_I) );
CALL_SUBTEST(check_sparse_square_solving(bicgstab_colmajor_ilut));
// CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_ssor) );
}
// https://gitlab.com/libeigen/eigen/-/issues/2856
void test_2856() {
Eigen::MatrixXd D = Eigen::MatrixXd::Identity(14, 14);
D(6, 13) = 1;
D(13, 12) = 1;
using CSRMatrix = Eigen::SparseMatrix<double, Eigen::RowMajor>;
CSRMatrix A = D.sparseView();
Eigen::VectorXd b = Eigen::VectorXd::Zero(14);
b(12) = -1001;
Eigen::BiCGSTAB<CSRMatrix> solver;
solver.compute(A);
Eigen::VectorXd x = solver.solve(b);
Eigen::VectorXd expected = Eigen::VectorXd::Zero(14);
expected(6) = -1001;
expected(12) = -1001;
expected(13) = 1001;
VERIFY_IS_EQUAL(x, expected);
Eigen::VectorXd residual = b - A * x;
VERIFY(residual.isZero());
}
// https://gitlab.com/libeigen/eigen/-/issues/2899
void test_2899() {
Eigen::MatrixXd A = Eigen::MatrixXd::Zero(4, 4);
A(0, 0) = 1;
A(1, 0) = -1.0 / 6;
A(1, 1) = 2.0 / 3;
A(1, 2) = -1.0 / 6;
A(1, 3) = -1.0 / 3;
A(2, 1) = -1.0 / 3;
A(2, 2) = 1;
A(2, 3) = -2.0 / 3;
A(3, 1) = -1.0 / 3;
A(3, 2) = -1.0 / 3;
A(3, 3) = 2.0 / 3;
Eigen::VectorXd b = Eigen::VectorXd::Zero(4);
b(0) = 0;
b(1) = 1;
b(2) = 1;
b(3) = 1;
Eigen::BiCGSTAB<Eigen::MatrixXd> solver;
solver.compute(A);
Eigen::VectorXd x = solver.solve(b);
Eigen::VectorXd expected(4);
expected << 0, 15, 18, 18;
VERIFY_IS_APPROX(x, expected);
Eigen::VectorXd residual = b - A * x;
VERIFY(residual.isZero());
}
EIGEN_DECLARE_TEST(bicgstab) {
CALL_SUBTEST_1((test_bicgstab_T<double, int>()));
CALL_SUBTEST_2((test_bicgstab_T<std::complex<double>, int>()));
CALL_SUBTEST_3((test_bicgstab_T<double, long int>()));
CALL_SUBTEST_4(test_2856());
CALL_SUBTEST_5(test_2899());
}
+178
View File
@@ -0,0 +1,178 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2020 Everton Constantino <everton.constantino@ibm.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"
// Disable "ignoring attributes on template argument"
// for packet_traits<Packet*>
// => The only workaround would be to wrap _m128 and the likes
// within wrappers.
#if EIGEN_GNUC_STRICT_AT_LEAST(6, 0, 0)
#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
#define GET(i, j) (StorageOrder == RowMajor ? (i) * stride + (j) : (i) + (j) * stride)
#define SCATTER(i, j, k) (StorageOrder == RowMajor ? ((i) + (k)) * stride + (j) : (i) + ((j) + (k)) * stride)
template <typename Scalar, typename Packet>
void compare(const Packet& a, const Packet& b) {
int pktsz = internal::packet_traits<Scalar>::size;
Scalar* buffA = new Scalar[pktsz];
Scalar* buffB = new Scalar[pktsz];
internal::pstoreu<Scalar, Packet>(buffA, a);
internal::pstoreu<Scalar, Packet>(buffB, b);
for (int i = 0; i < pktsz; i++) {
VERIFY_IS_EQUAL(buffA[i], buffB[i]);
}
delete[] buffA;
delete[] buffB;
}
template <typename Scalar, int StorageOrder, int n>
struct PacketBlockSet {
typedef typename internal::packet_traits<Scalar>::type Packet;
void setPacketBlock(internal::PacketBlock<Packet, n>& block, Scalar value) {
for (int idx = 0; idx < n; idx++) {
block.packet[idx] = internal::pset1<Packet>(value);
}
}
void comparePacketBlock(Scalar* data, int i, int j, int stride, internal::PacketBlock<Packet, n>& block) {
for (int idx = 0; idx < n; idx++) {
Packet line = internal::ploadu<Packet>(data + SCATTER(i, j, idx));
compare<Scalar, Packet>(block.packet[idx], line);
}
}
};
template <typename Scalar, int StorageOrder, int BlockSize>
void run_bdmp_spec_1() {
typedef internal::blas_data_mapper<Scalar, int, StorageOrder> BlasDataMapper;
int packetSize = internal::packet_traits<Scalar>::size;
int minSize = std::max<int>(packetSize, BlockSize);
typedef typename internal::packet_traits<Scalar>::type Packet;
int szm = internal::random<int>(minSize, 500), szn = internal::random<int>(minSize, 500);
int stride = StorageOrder == RowMajor ? szn : szm;
Scalar* d = new Scalar[szn * szm];
// Initializing with random entries
for (int i = 0; i < szm * szn; i++) {
d[i] = internal::random<Scalar>(static_cast<Scalar>(3), static_cast<Scalar>(10));
}
BlasDataMapper bdm(d, stride);
// Testing operator()
for (int i = 0; i < szm; i++) {
for (int j = 0; j < szn; j++) {
VERIFY_IS_EQUAL(d[GET(i, j)], bdm(i, j));
}
}
// Testing getSubMapper and getLinearMapper
int i0 = internal::random<int>(0, szm - 2);
int j0 = internal::random<int>(0, szn - 2);
for (int i = i0; i < szm; i++) {
for (int j = j0; j < szn; j++) {
const BlasDataMapper& bdmSM = bdm.getSubMapper(i0, j0);
const internal::BlasLinearMapper<Scalar, int, 0>& bdmLM = bdm.getLinearMapper(i0, j0);
Scalar v = bdmSM(i - i0, j - j0);
Scalar vd = d[GET(i, j)];
VERIFY_IS_EQUAL(vd, v);
VERIFY_IS_EQUAL(vd, bdmLM(GET(i - i0, j - j0)));
}
}
// Testing loadPacket
for (int i = 0; i < szm - minSize; i++) {
for (int j = 0; j < szn - minSize; j++) {
Packet pktBDM = bdm.template loadPacket<Packet>(i, j);
Packet pktD = internal::ploadu<Packet>(d + GET(i, j));
compare<Scalar, Packet>(pktBDM, pktD);
}
}
// Testing gatherPacket
Scalar* buff = new Scalar[packetSize];
for (int i = 0; i < szm - minSize; i++) {
for (int j = 0; j < szn - minSize; j++) {
Packet p = bdm.template gatherPacket<Packet>(i, j);
internal::pstoreu<Scalar, Packet>(buff, p);
for (int k = 0; k < packetSize; k++) {
VERIFY_IS_EQUAL(d[SCATTER(i, j, k)], buff[k]);
}
}
}
delete[] buff;
// Testing scatterPacket
for (int i = 0; i < szm - minSize; i++) {
for (int j = 0; j < szn - minSize; j++) {
Packet p = internal::pset1<Packet>(static_cast<Scalar>(1));
bdm.template scatterPacket<Packet>(i, j, p);
for (int k = 0; k < packetSize; k++) {
VERIFY_IS_EQUAL(d[SCATTER(i, j, k)], static_cast<Scalar>(1));
}
}
}
// Testing storePacketBlock
internal::PacketBlock<Packet, BlockSize> block;
PacketBlockSet<Scalar, StorageOrder, BlockSize> pbs;
pbs.setPacketBlock(block, static_cast<Scalar>(2));
for (int i = 0; i < szm - minSize; i++) {
for (int j = 0; j < szn - minSize; j++) {
bdm.template storePacketBlock<Packet, BlockSize>(i, j, block);
pbs.comparePacketBlock(d, i, j, stride, block);
}
}
delete[] d;
}
template <typename Scalar>
void run_test() {
run_bdmp_spec_1<Scalar, RowMajor, 1>();
run_bdmp_spec_1<Scalar, ColMajor, 1>();
run_bdmp_spec_1<Scalar, RowMajor, 2>();
run_bdmp_spec_1<Scalar, ColMajor, 2>();
run_bdmp_spec_1<Scalar, RowMajor, 4>();
run_bdmp_spec_1<Scalar, ColMajor, 4>();
run_bdmp_spec_1<Scalar, RowMajor, 8>();
run_bdmp_spec_1<Scalar, ColMajor, 8>();
run_bdmp_spec_1<Scalar, RowMajor, 16>();
run_bdmp_spec_1<Scalar, ColMajor, 16>();
}
EIGEN_DECLARE_TEST(blasutil) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(run_test<numext::int8_t>());
CALL_SUBTEST_2(run_test<numext::int16_t>());
CALL_SUBTEST_3(run_test<numext::int32_t>());
// 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
CALL_SUBTEST_4(run_test<signed long long>());
CALL_SUBTEST_5(run_test<float_t>());
CALL_SUBTEST_6(run_test<double_t>());
CALL_SUBTEST_7(run_test<std::complex<float> >());
CALL_SUBTEST_8(run_test<std::complex<double> >());
}
}
+381
View File
@@ -0,0 +1,381 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType, typename Index, typename Scalar>
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));
VERIFY_IS_APPROX(m1.col(c1).cwiseMin(s1), m1.cwiseMin(s1).col(c1));
VERIFY_IS_APPROX(m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).cwiseMin(s1),
m1.cwiseMin(s1).block(r1, c1, r2 - r1 + 1, c2 - c1 + 1));
VERIFY_IS_APPROX(m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).cwiseMax(s1),
m1.cwiseMax(s1).block(r1, c1, r2 - r1 + 1, c2 - c1 + 1));
return Scalar(0);
}
template <typename MatrixType, typename Index, typename Scalar>
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>
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*/) {
if (c > 0) 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) {
if (r > 0) 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;
typedef typename MatrixType::RealScalar RealScalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;
typedef Matrix<Scalar, Dynamic, Dynamic, MatrixType::IsRowMajor ? RowMajor : ColMajor> DynamicMatrixType;
typedef Matrix<Scalar, Dynamic, 1> DynamicVectorType;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m1_copy = m1, m2 = MatrixType::Random(rows, cols), m3(rows, cols),
ones = MatrixType::Ones(rows, cols);
VectorType v1 = VectorType::Random(rows);
Scalar s1 = internal::random<Scalar>();
Index r1 = internal::random<Index>(0, rows - 1);
Index r2 = internal::random<Index>(r1, rows - 1);
Index c1 = internal::random<Index>(0, cols - 1);
Index c2 = internal::random<Index>(c1, cols - 1);
block_real_only(m1, r1, r2, c1, c1, s1);
// test fill logic with innerpanel and non-innerpanel blocks
m1.row(r1).setConstant(s1);
VERIFY_IS_CWISE_EQUAL(m1.row(r1), DynamicVectorType::Constant(cols, s1).transpose());
m1 = m1_copy;
m1.col(c1).setConstant(s1);
VERIFY_IS_CWISE_EQUAL(m1.col(c1), DynamicVectorType::Constant(rows, s1));
m1 = m1_copy;
// test setZero logic with innerpanel and non-innerpanel blocks
m1.row(r1).setZero();
VERIFY_IS_CWISE_EQUAL(m1.row(r1), DynamicVectorType::Zero(cols).transpose());
m1 = m1_copy;
m1.col(c1).setZero();
VERIFY_IS_CWISE_EQUAL(m1.col(c1), DynamicVectorType::Zero(rows));
m1 = m1_copy;
// check row() and col()
VERIFY_IS_EQUAL(m1.col(c1).transpose(), m1.transpose().row(c1));
// check operator(), both constant and non-constant, on row() and col()
m1 = m1_copy;
m1.row(r1) += s1 * m1_copy.row(r2);
VERIFY_IS_APPROX(m1.row(r1), m1_copy.row(r1) + s1 * m1_copy.row(r2));
// check nested block xpr on lhs
m1.row(r1).row(0) += s1 * m1_copy.row(r2);
VERIFY_IS_APPROX(m1.row(r1), m1_copy.row(r1) + Scalar(2) * s1 * m1_copy.row(r2));
m1 = m1_copy;
m1.col(c1) += s1 * m1_copy.col(c2);
VERIFY_IS_APPROX(m1.col(c1), m1_copy.col(c1) + s1 * m1_copy.col(c2));
m1.col(c1).col(0) += s1 * m1_copy.col(c2);
VERIFY_IS_APPROX(m1.col(c1), m1_copy.col(c1) + Scalar(2) * s1 * m1_copy.col(c2));
check_left_top(m1, r1, c1, rows, cols);
// check block()
Matrix<Scalar, Dynamic, Dynamic> b1(1, 1);
b1(0, 0) = m1(r1, c1);
RowVectorType br1(m1.block(r1, 0, 1, cols));
VectorType bc1(m1.block(0, c1, rows, 1));
VERIFY_IS_EQUAL(b1, m1.block(r1, c1, 1, 1));
VERIFY_IS_EQUAL(m1.row(r1), br1);
VERIFY_IS_EQUAL(m1.col(c1), bc1);
// check operator(), both constant and non-constant, on block()
m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1) = s1 * m2.block(0, 0, r2 - r1 + 1, c2 - c1 + 1);
m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1)(r2 - r1, c2 - c1) = m2.block(0, 0, r2 - r1 + 1, c2 - c1 + 1)(0, 0);
const Index BlockRows = 2;
const Index BlockCols = 5;
if (rows >= 5 && cols >= 8) {
// test fixed block() as lvalue
m1.template block<BlockRows, BlockCols>(1, 1) *= s1;
// test operator() on fixed block() both as constant and non-constant
m1.template block<BlockRows, BlockCols>(1, 1)(0, 3) = m1.template block<2, 5>(1, 1)(1, 2);
// check that fixed block() and block() agree
Matrix<Scalar, Dynamic, Dynamic> b = m1.template block<BlockRows, BlockCols>(3, 3);
VERIFY_IS_EQUAL(b, m1.block(3, 3, BlockRows, BlockCols));
// same tests with mixed fixed/dynamic size
m1.template block<BlockRows, Dynamic>(1, 1, BlockRows, BlockCols) *= s1;
m1.template block<BlockRows, Dynamic>(1, 1, BlockRows, BlockCols)(0, 3) = m1.template block<2, 5>(1, 1)(1, 2);
Matrix<Scalar, Dynamic, Dynamic> b2 = m1.template block<Dynamic, BlockCols>(3, 3, 2, 5);
VERIFY_IS_EQUAL(b2, m1.block(3, 3, BlockRows, BlockCols));
VERIFY(is_same_block(m1.block(3, 3, BlockRows, BlockCols),
m1.block(3, 3, fix<Dynamic>(BlockRows), fix<Dynamic>(BlockCols))));
VERIFY(is_same_block(m1.template block<BlockRows, Dynamic>(1, 1, BlockRows, BlockCols),
m1.block(1, 1, fix<BlockRows>, BlockCols)));
VERIFY(is_same_block(m1.template block<BlockRows, BlockCols>(1, 1, BlockRows, BlockCols),
m1.block(1, 1, fix<BlockRows>(), fix<BlockCols>)));
VERIFY(is_same_block(m1.template block<BlockRows, BlockCols>(1, 1, BlockRows, BlockCols),
m1.block(1, 1, fix<BlockRows>, fix<BlockCols>(BlockCols))));
}
if (rows > 2) {
// test sub vectors
VERIFY_IS_EQUAL(v1.template head<2>(), v1.block(0, 0, 2, 1));
VERIFY_IS_EQUAL(v1.template head<2>(), v1.head(2));
VERIFY_IS_EQUAL(v1.template head<2>(), v1.segment(0, 2));
VERIFY_IS_EQUAL(v1.template head<2>(), v1.template segment<2>(0));
Index i = rows - 2;
VERIFY_IS_EQUAL(v1.template tail<2>(), v1.block(i, 0, 2, 1));
VERIFY_IS_EQUAL(v1.template tail<2>(), v1.tail(2));
VERIFY_IS_EQUAL(v1.template tail<2>(), v1.segment(i, 2));
VERIFY_IS_EQUAL(v1.template tail<2>(), v1.template segment<2>(i));
i = internal::random<Index>(0, rows - 2);
VERIFY_IS_EQUAL(v1.segment(i, 2), v1.template segment<2>(i));
}
// stress some basic stuffs with block matrices
VERIFY_IS_EQUAL(numext::real(ones.col(c1).sum()), RealScalar(rows));
VERIFY_IS_EQUAL(numext::real(ones.row(r1).sum()), 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 accessors works on blocks
m1 = m1_copy;
// now test some block-inside-of-block.
// expressions with direct access
VERIFY_IS_EQUAL((m1.block(r1, c1, rows - r1, cols - c1).block(r2 - r1, c2 - c1, rows - r2, cols - c2)),
(m1.block(r2, c2, rows - r2, cols - c2)));
VERIFY_IS_EQUAL((m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).row(0)), (m1.row(r1).segment(c1, c2 - c1 + 1)));
VERIFY_IS_EQUAL((m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).col(0)), (m1.col(c1).segment(r1, r2 - r1 + 1)));
VERIFY_IS_EQUAL((m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).transpose().col(0)),
(m1.row(r1).segment(c1, c2 - c1 + 1)).transpose());
VERIFY_IS_EQUAL((m1.transpose().block(c1, r1, c2 - c1 + 1, r2 - r1 + 1).col(0)),
(m1.row(r1).segment(c1, c2 - c1 + 1)).transpose());
// expressions without direct access
VERIFY_IS_APPROX(((m1 + m2).block(r1, c1, rows - r1, cols - c1).block(r2 - r1, c2 - c1, rows - r2, cols - c2)),
((m1 + m2).block(r2, c2, rows - r2, cols - c2)));
VERIFY_IS_APPROX(((m1 + m2).block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).row(0)),
((m1 + m2).row(r1).segment(c1, c2 - c1 + 1)));
VERIFY_IS_APPROX(((m1 + m2).block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).row(0)),
((m1 + m2).eval().row(r1).segment(c1, c2 - c1 + 1)));
VERIFY_IS_APPROX(((m1 + m2).block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).col(0)),
((m1 + m2).col(c1).segment(r1, r2 - r1 + 1)));
VERIFY_IS_APPROX(((m1 + m2).block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).transpose().col(0)),
((m1 + m2).row(r1).segment(c1, c2 - c1 + 1)).transpose());
VERIFY_IS_APPROX(((m1 + m2).transpose().block(c1, r1, c2 - c1 + 1, r2 - r1 + 1).col(0)),
((m1 + m2).row(r1).segment(c1, c2 - c1 + 1)).transpose());
VERIFY_IS_APPROX(((m1 + m2).template block<Dynamic, 1>(r1, c1, r2 - r1 + 1, 1)),
((m1 + m2).eval().col(c1).eval().segment(r1, r2 - r1 + 1)));
VERIFY_IS_APPROX(((m1 + m2).template block<1, Dynamic>(r1, c1, 1, c2 - c1 + 1)),
((m1 + m2).eval().row(r1).eval().segment(c1, c2 - c1 + 1)));
VERIFY_IS_APPROX(((m1 + m2).transpose().template block<1, Dynamic>(c1, r1, 1, r2 - r1 + 1)),
((m1 + m2).eval().col(c1).eval().segment(r1, r2 - r1 + 1)).transpose());
VERIFY_IS_APPROX((m1 + m2).row(r1).eval(), (m1 + m2).eval().row(r1));
VERIFY_IS_APPROX((m1 + m2).adjoint().col(r1).eval(), (m1 + m2).adjoint().eval().col(r1));
VERIFY_IS_APPROX((m1 + m2).adjoint().row(c1).eval(), (m1 + m2).adjoint().eval().row(c1));
VERIFY_IS_APPROX((m1 * 1).row(r1).segment(c1, c2 - c1 + 1).eval(), m1.row(r1).eval().segment(c1, c2 - c1 + 1).eval());
VERIFY_IS_APPROX(m1.col(c1).reverse().segment(r1, r2 - r1 + 1).eval(),
m1.col(c1).reverse().eval().segment(r1, r2 - r1 + 1).eval());
VERIFY_IS_APPROX((m1 * 1).topRows(r1), m1.topRows(r1));
VERIFY_IS_APPROX((m1 * 1).leftCols(c1), m1.leftCols(c1));
VERIFY_IS_APPROX((m1 * 1).transpose().topRows(c1), m1.transpose().topRows(c1));
VERIFY_IS_APPROX((m1 * 1).transpose().leftCols(r1), m1.transpose().leftCols(r1));
VERIFY_IS_APPROX((m1 * 1).transpose().middleRows(c1, c2 - c1 + 1), m1.transpose().middleRows(c1, c2 - c1 + 1));
VERIFY_IS_APPROX((m1 * 1).transpose().middleCols(r1, r2 - r1 + 1), m1.transpose().middleCols(r1, r2 - r1 + 1));
// evaluation into plain matrices from expressions with direct access (stress MapBase)
DynamicMatrixType dm;
DynamicVectorType dv;
dm.setZero();
dm = m1.block(r1, c1, rows - r1, cols - c1).block(r2 - r1, c2 - c1, rows - r2, cols - c2);
VERIFY_IS_EQUAL(dm, (m1.block(r2, c2, rows - r2, cols - c2)));
dm.setZero();
dv.setZero();
dm = m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).row(0).transpose();
dv = m1.row(r1).segment(c1, c2 - c1 + 1);
VERIFY_IS_EQUAL(dv, dm);
dm.setZero();
dv.setZero();
dm = m1.col(c1).segment(r1, r2 - r1 + 1);
dv = m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).col(0);
VERIFY_IS_EQUAL(dv, dm);
dm.setZero();
dv.setZero();
dm = m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1).transpose().col(0);
dv = m1.row(r1).segment(c1, c2 - c1 + 1);
VERIFY_IS_EQUAL(dv, dm);
dm.setZero();
dv.setZero();
dm = m1.row(r1).segment(c1, c2 - c1 + 1).transpose();
dv = m1.transpose().block(c1, r1, c2 - c1 + 1, r2 - r1 + 1).col(0);
VERIFY_IS_EQUAL(dv, dm);
VERIFY_IS_EQUAL((m1.template block<Dynamic, 1>(1, 0, 0, 1)), m1.block(1, 0, 0, 1));
VERIFY_IS_EQUAL((m1.template block<1, Dynamic>(0, 1, 1, 0)), m1.block(0, 1, 1, 0));
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));
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));
VERIFY_IS_APPROX((m1 + m1).template subVector<Vertical>(c1), (m1 + m1).col(c1));
VERIFY_IS_EQUAL(m1.template subVectors<Horizontal>(), m1.rows());
VERIFY_IS_EQUAL(m1.template subVectors<Vertical>(), m1.cols());
if (rows >= 2 || cols >= 2) {
VERIFY_IS_EQUAL(int(m1.middleCols(0, 0).IsRowMajor), int(m1.IsRowMajor));
VERIFY_IS_EQUAL(m1.middleCols(0, 0).outerSize(), m1.IsRowMajor ? rows : 0);
VERIFY_IS_EQUAL(m1.middleCols(0, 0).innerSize(), m1.IsRowMajor ? 0 : rows);
VERIFY_IS_EQUAL(int(m1.middleRows(0, 0).IsRowMajor), int(m1.IsRowMajor));
VERIFY_IS_EQUAL(m1.middleRows(0, 0).outerSize(), m1.IsRowMajor ? 0 : cols);
VERIFY_IS_EQUAL(m1.middleRows(0, 0).innerSize(), m1.IsRowMajor ? cols : 0);
}
}
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 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();
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]);
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>
void data_and_stride(const MatrixType& m) {
Index rows = m.rows();
Index cols = m.cols();
Index r1 = internal::random<Index>(0, rows - 1);
Index r2 = internal::random<Index>(r1, rows - 1);
Index c1 = internal::random<Index>(0, cols - 1);
Index c2 = internal::random<Index>(c1, cols - 1);
MatrixType m1 = MatrixType::Random(rows, cols);
compare_using_data_and_stride(m1.block(r1, c1, r2 - r1 + 1, c2 - c1 + 1));
compare_using_data_and_stride(m1.transpose().block(c1, r1, c2 - c1 + 1, r2 - r1 + 1));
compare_using_data_and_stride(m1.row(r1));
compare_using_data_and_stride(m1.col(c1));
compare_using_data_and_stride(m1.row(r1).transpose());
compare_using_data_and_stride(m1.col(c1).transpose());
}
template <typename BaseXpr, typename Xpr = BaseXpr, int Depth = 0>
struct unwind_test_impl {
static void run(Xpr& xpr) {
Index startRow = internal::random<Index>(0, xpr.rows() / 5);
Index startCol = internal::random<Index>(0, xpr.cols() / 6);
Index rows = xpr.rows() / 3;
Index cols = xpr.cols() / 2;
// test equivalence of const expressions
const Block<const Xpr> constNestedBlock(xpr, startRow, startCol, rows, cols);
const Block<const BaseXpr> constUnwoundBlock = constNestedBlock.unwind();
VERIFY_IS_CWISE_EQUAL(constNestedBlock, constUnwoundBlock);
// modify a random element in each representation and test equivalence of non-const expressions
Block<Xpr> nestedBlock(xpr, startRow, startCol, rows, cols);
Block<BaseXpr> unwoundBlock = nestedBlock.unwind();
Index r1 = internal::random<Index>(0, rows - 1);
Index c1 = internal::random<Index>(0, cols - 1);
Index r2 = internal::random<Index>(0, rows - 1);
Index c2 = internal::random<Index>(0, cols - 1);
nestedBlock.coeffRef(r1, c1) = internal::random<typename DenseBase<Xpr>::Scalar>();
unwoundBlock.coeffRef(r2, c2) = internal::random<typename DenseBase<Xpr>::Scalar>();
VERIFY_IS_CWISE_EQUAL(nestedBlock, unwoundBlock);
unwind_test_impl<BaseXpr, Block<Xpr>, Depth + 1>::run(nestedBlock);
}
};
template <typename BaseXpr, typename Xpr>
struct unwind_test_impl<BaseXpr, Xpr, 4> {
static void run(const Xpr&) {}
};
template <typename BaseXpr>
void unwind_test(const BaseXpr&) {
BaseXpr xpr = BaseXpr::Random(100, 100);
unwind_test_impl<BaseXpr>::run(xpr);
}
EIGEN_DECLARE_TEST(block) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(block(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(block(Matrix<float, 1, Dynamic>(internal::random(2, 50))));
CALL_SUBTEST_1(block(Matrix<float, Dynamic, 1>(internal::random(2, 50))));
CALL_SUBTEST_2(block(Matrix4d()));
CALL_SUBTEST_3(block(MatrixXcf(internal::random(2, 50), internal::random(2, 50))));
CALL_SUBTEST_4(block(MatrixXi(internal::random(2, 50), internal::random(2, 50))));
CALL_SUBTEST_5(block(MatrixXcd(internal::random(2, 50), internal::random(2, 50))));
CALL_SUBTEST_6(block(MatrixXf(internal::random(2, 50), internal::random(2, 50))));
CALL_SUBTEST_7(block(Matrix<int, Dynamic, Dynamic, RowMajor>(internal::random(2, 50), internal::random(2, 50))));
CALL_SUBTEST_8(block(Matrix<float, Dynamic, 4>(3, 4)));
CALL_SUBTEST_9(unwind_test(MatrixXf()));
#ifndef EIGEN_DEFAULT_TO_ROW_MAJOR
CALL_SUBTEST_6(data_and_stride(MatrixXf(internal::random(5, 50), internal::random(5, 50))));
CALL_SUBTEST_7(
data_and_stride(Matrix<int, Dynamic, Dynamic, RowMajor>(internal::random(5, 50), internal::random(5, 50))));
#endif
}
}
+212
View File
@@ -0,0 +1,212 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <sstream>
#ifdef EIGEN_TEST_MAX_SIZE
#undef EIGEN_TEST_MAX_SIZE
#endif
#define EIGEN_TEST_MAX_SIZE 50
#ifdef EIGEN_TEST_PART_1
#include "cholesky.cpp"
#endif
#ifdef EIGEN_TEST_PART_2
#include "lu.cpp"
#endif
#ifdef EIGEN_TEST_PART_3
#include "qr.cpp"
#endif
#ifdef EIGEN_TEST_PART_4
#include "qr_colpivoting.cpp"
#endif
#ifdef EIGEN_TEST_PART_5
#include "qr_fullpivoting.cpp"
#endif
#ifdef EIGEN_TEST_PART_6
#include "eigensolver_selfadjoint.cpp"
#endif
#ifdef EIGEN_TEST_PART_7
#include "eigensolver_generic.cpp"
#endif
#ifdef EIGEN_TEST_PART_8
#include "eigensolver_generalized_real.cpp"
#endif
#ifdef EIGEN_TEST_PART_9
#include "jacobisvd.cpp"
#endif
#ifdef EIGEN_TEST_PART_10
#include "bdcsvd.cpp"
#endif
#ifdef EIGEN_TEST_PART_11
#include "simplicial_cholesky.cpp"
#endif
#include <Eigen/Dense>
#undef min
#undef max
#undef isnan
#undef isinf
#undef isfinite
#undef I
#include <boost/serialization/nvp.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/number.hpp>
#include <boost/math/special_functions.hpp>
#include <boost/math/complex.hpp>
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100>, boost::multiprecision::et_on> Real;
namespace Eigen {
template <>
struct NumTraits<Real> : GenericNumTraits<Real> {
static inline Real dummy_precision() { return 1e-50; }
};
template <typename T1, typename T2, typename T3, typename T4, typename T5>
struct NumTraits<boost::multiprecision::detail::expression<T1, T2, T3, T4, T5> > : NumTraits<Real> {};
template <>
Real test_precision<Real>() {
return 1e-50;
}
// needed in C++93 mode where number does not support explicit cast.
namespace internal {
template <typename NewType>
struct cast_impl<Real, NewType> {
static inline NewType run(const Real& x) { return x.template convert_to<NewType>(); }
};
template <>
struct cast_impl<Real, std::complex<Real> > {
static inline std::complex<Real> run(const Real& x) { return std::complex<Real>(x); }
};
} // namespace internal
} // namespace Eigen
namespace boost {
namespace multiprecision {
// to make ADL works as expected:
using boost::math::copysign;
using boost::math::hypot;
using boost::math::isfinite;
using boost::math::isinf;
using boost::math::isnan;
// The following is needed for std::complex<Real>:
Real fabs(const Real& a) { return abs EIGEN_NOT_A_MACRO(a); }
Real fmax(const Real& a, const Real& b) {
using std::max;
return max(a, b);
}
// some specialization for the unit tests:
inline bool test_isMuchSmallerThan(const Real& a, const Real& b) {
return internal::isMuchSmallerThan(a, b, test_precision<Real>());
}
inline bool test_isApprox(const Real& a, const Real& b) { return internal::isApprox(a, b, test_precision<Real>()); }
inline bool test_isApproxOrLessThan(const Real& a, const Real& b) {
return internal::isApproxOrLessThan(a, b, test_precision<Real>());
}
Real get_test_precision(const Real&) { return test_precision<Real>(); }
Real test_relative_error(const Real& a, const Real& b) {
using Eigen::numext::abs2;
return sqrt(abs2<Real>(a - b) / Eigen::numext::mini<Real>(abs2(a), abs2(b)));
}
} // namespace multiprecision
} // namespace boost
namespace Eigen {}
EIGEN_DECLARE_TEST(boostmultiprec) {
typedef Matrix<Real, Dynamic, Dynamic> Mat;
typedef Matrix<std::complex<Real>, Dynamic, Dynamic> MatC;
std::cout << "NumTraits<Real>::epsilon() = " << NumTraits<Real>::epsilon() << std::endl;
std::cout << "NumTraits<Real>::dummy_precision() = " << NumTraits<Real>::dummy_precision() << std::endl;
std::cout << "NumTraits<Real>::lowest() = " << NumTraits<Real>::lowest() << std::endl;
std::cout << "NumTraits<Real>::highest() = " << NumTraits<Real>::highest() << std::endl;
std::cout << "NumTraits<Real>::digits10() = " << NumTraits<Real>::digits10() << std::endl;
std::cout << "NumTraits<Real>::max_digits10() = " << NumTraits<Real>::max_digits10() << std::endl;
// check stream output
{
Mat A(10, 10);
A.setRandom();
std::stringstream ss;
ss << A;
}
{
MatC A(10, 10);
A.setRandom();
std::stringstream ss;
ss << A;
}
for (int i = 0; i < g_repeat; i++) {
int s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE);
CALL_SUBTEST_1(cholesky(Mat(s, s)));
CALL_SUBTEST_2(lu_non_invertible<Mat>());
CALL_SUBTEST_2(lu_invertible<Mat>());
CALL_SUBTEST_2(lu_non_invertible<MatC>());
CALL_SUBTEST_2(lu_invertible<MatC>());
CALL_SUBTEST_3(
qr(Mat(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_3(qr_invertible<Mat>());
CALL_SUBTEST_4(qr<Mat>());
CALL_SUBTEST_4(cod<Mat>());
CALL_SUBTEST_4(qr_invertible<Mat>());
CALL_SUBTEST_5(qr<Mat>());
CALL_SUBTEST_5(qr_invertible<Mat>());
CALL_SUBTEST_6(selfadjointeigensolver(Mat(s, s)));
CALL_SUBTEST_7(eigensolver(Mat(s, s)));
CALL_SUBTEST_8(generalized_eigensolver_real(Mat(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
CALL_SUBTEST_9(
(jacobisvd_thin_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_9(
(jacobisvd_full_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_thin_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_full_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>()));
}
+7
View File
@@ -0,0 +1,7 @@
// This anonymous enum is essential to trigger the linking issue
enum { Foo };
#include "bug1213.h"
bool bug1213_1(const Eigen::Vector3f& x) { return bug1213_2(x); }
+7
View File
@@ -0,0 +1,7 @@
#include <Eigen/Core>
template <typename T, int dim>
bool bug1213_2(const Eigen::Matrix<T, dim, 1>& x);
bool bug1213_1(const Eigen::Vector3f& x);
+13
View File
@@ -0,0 +1,13 @@
// This is a regression unit regarding a weird linking issue with gcc.
#include "bug1213.h"
int main() { return 0; }
template <typename T, int dim>
bool bug1213_2(const Eigen::Matrix<T, dim, 1>&) {
return true;
}
template bool bug1213_2<float, 3>(const Eigen::Vector3f&);
+500
View File
@@ -0,0 +1,500 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define TEST_ENABLE_TEMPORARY_TRACKING
#include "main.h"
#include <Eigen/Cholesky>
#include <Eigen/QR>
#include "solverbase.h"
template <typename MatrixType, int UpLo>
typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) {
if (m.cols() == 0) return typename MatrixType::RealScalar(0);
MatrixType symm = m.template selfadjointView<UpLo>();
return symm.cwiseAbs().colwise().sum().maxCoeff();
}
template <typename MatrixType, template <typename, int> class CholType>
void test_chol_update(const MatrixType& symm) {
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
MatrixType symmLo = symm.template triangularView<Lower>();
MatrixType symmUp = symm.template triangularView<Upper>();
MatrixType symmCpy = symm;
CholType<MatrixType, Lower> chollo(symmLo);
CholType<MatrixType, Upper> cholup(symmUp);
for (int k = 0; k < 10; ++k) {
VectorType vec = VectorType::Random(symm.rows());
RealScalar sigma = internal::random<RealScalar>();
symmCpy += sigma * vec * vec.adjoint();
// we are doing some downdates, so it might be the case that the matrix is not SPD anymore
CholType<MatrixType, Lower> chol(symmCpy);
if (chol.info() != Success) break;
chollo.rankUpdate(vec, sigma);
VERIFY_IS_APPROX(symmCpy, chollo.reconstructedMatrix());
cholup.rankUpdate(vec, sigma);
VERIFY_IS_APPROX(symmCpy, cholup.reconstructedMatrix());
}
}
template <typename MatrixType>
void cholesky(const MatrixType& m) {
/* this test covers the following files:
LLT.h LDLT.h
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
MatrixType a0 = MatrixType::Random(rows, cols);
VectorType vecB = VectorType::Random(rows), vecX(rows);
MatrixType matB = MatrixType::Random(rows, cols), matX(rows, cols);
SquareMatrixType symm = a0 * a0.adjoint();
// let's make sure the matrix is not singular or near singular
for (int k = 0; k < 3; ++k) {
MatrixType a1 = MatrixType::Random(rows, cols);
symm += a1 * a1.adjoint();
}
{
STATIC_CHECK((internal::is_same<typename LLT<MatrixType, Lower>::StorageIndex, int>::value));
STATIC_CHECK((internal::is_same<typename LLT<MatrixType, Upper>::StorageIndex, int>::value));
SquareMatrixType symmUp = symm.template triangularView<Upper>();
SquareMatrixType symmLo = symm.template triangularView<Lower>();
LLT<SquareMatrixType, Lower> chollo(symmLo);
VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
check_solverbase<VectorType, VectorType>(symm, chollo, rows, rows, 1);
check_solverbase<MatrixType, MatrixType>(symm, chollo, rows, cols, rows);
const MatrixType symmLo_inverse = chollo.solve(MatrixType::Identity(rows, cols));
RealScalar rcond =
(RealScalar(1) / matrix_l1_norm<MatrixType, Lower>(symmLo)) / matrix_l1_norm<MatrixType, Lower>(symmLo_inverse);
RealScalar rcond_est = chollo.rcond();
// Verify that the estimated condition number is within a factor of 10 of the
// truth.
VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10);
// test the upper mode
LLT<SquareMatrixType, Upper> cholup(symmUp);
VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix());
vecX = cholup.solve(vecB);
VERIFY_IS_APPROX(symm * vecX, vecB);
matX = cholup.solve(matB);
VERIFY_IS_APPROX(symm * matX, matB);
// Verify that the estimated condition number is within a factor of 10 of the
// truth.
const MatrixType symmUp_inverse = cholup.solve(MatrixType::Identity(rows, cols));
rcond =
(RealScalar(1) / matrix_l1_norm<MatrixType, Upper>(symmUp)) / matrix_l1_norm<MatrixType, Upper>(symmUp_inverse);
rcond_est = cholup.rcond();
VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10);
MatrixType neg = -symmLo;
chollo.compute(neg);
VERIFY(neg.size() == 0 || chollo.info() == NumericalIssue);
VERIFY_IS_APPROX(MatrixType(chollo.matrixL().transpose().conjugate()), MatrixType(chollo.matrixU()));
VERIFY_IS_APPROX(MatrixType(chollo.matrixU().transpose().conjugate()), MatrixType(chollo.matrixL()));
VERIFY_IS_APPROX(MatrixType(cholup.matrixL().transpose().conjugate()), MatrixType(cholup.matrixU()));
VERIFY_IS_APPROX(MatrixType(cholup.matrixU().transpose().conjugate()), MatrixType(cholup.matrixL()));
// test some special use cases of SelfCwiseBinaryOp:
MatrixType m1 = MatrixType::Random(rows, cols), m2(rows, cols);
m2 = m1;
m2 += symmLo.template selfadjointView<Lower>().llt().solve(matB);
VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB));
m2 = m1;
m2 -= symmLo.template selfadjointView<Lower>().llt().solve(matB);
VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB));
m2 = m1;
m2.noalias() += symmLo.template selfadjointView<Lower>().llt().solve(matB);
VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB));
m2 = m1;
m2.noalias() -= symmLo.template selfadjointView<Lower>().llt().solve(matB);
VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB));
}
// LDLT
{
STATIC_CHECK((internal::is_same<typename LDLT<MatrixType, Lower>::StorageIndex, int>::value));
STATIC_CHECK((internal::is_same<typename LDLT<MatrixType, Upper>::StorageIndex, int>::value));
int sign = internal::random<int>() % 2 ? 1 : -1;
if (sign == -1) {
symm = -symm; // test a negative matrix
}
SquareMatrixType symmUp = symm.template triangularView<Upper>();
SquareMatrixType symmLo = symm.template triangularView<Lower>();
LDLT<SquareMatrixType, Lower> ldltlo(symmLo);
VERIFY(ldltlo.info() == Success);
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
check_solverbase<VectorType, VectorType>(symm, ldltlo, rows, rows, 1);
check_solverbase<MatrixType, MatrixType>(symm, ldltlo, rows, cols, rows);
const MatrixType symmLo_inverse = ldltlo.solve(MatrixType::Identity(rows, cols));
RealScalar rcond =
(RealScalar(1) / matrix_l1_norm<MatrixType, Lower>(symmLo)) / matrix_l1_norm<MatrixType, Lower>(symmLo_inverse);
RealScalar rcond_est = ldltlo.rcond();
// Verify that the estimated condition number is within a factor of 10 of the
// truth.
VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10);
LDLT<SquareMatrixType, Upper> ldltup(symmUp);
VERIFY(ldltup.info() == Success);
VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
vecX = ldltup.solve(vecB);
VERIFY_IS_APPROX(symm * vecX, vecB);
matX = ldltup.solve(matB);
VERIFY_IS_APPROX(symm * matX, matB);
// Verify that the estimated condition number is within a factor of 10 of the
// truth.
const MatrixType symmUp_inverse = ldltup.solve(MatrixType::Identity(rows, cols));
rcond =
(RealScalar(1) / matrix_l1_norm<MatrixType, Upper>(symmUp)) / matrix_l1_norm<MatrixType, Upper>(symmUp_inverse);
rcond_est = ldltup.rcond();
VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10);
VERIFY_IS_APPROX(MatrixType(ldltlo.matrixL().transpose().conjugate()), MatrixType(ldltlo.matrixU()));
VERIFY_IS_APPROX(MatrixType(ldltlo.matrixU().transpose().conjugate()), MatrixType(ldltlo.matrixL()));
VERIFY_IS_APPROX(MatrixType(ldltup.matrixL().transpose().conjugate()), MatrixType(ldltup.matrixU()));
VERIFY_IS_APPROX(MatrixType(ldltup.matrixU().transpose().conjugate()), MatrixType(ldltup.matrixL()));
if (MatrixType::RowsAtCompileTime == Dynamic) {
// note : each inplace permutation requires a small temporary vector (mask)
// check inplace solve
matX = matB;
VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0);
VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval());
matX = matB;
VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0);
VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval());
}
// restore
if (sign == -1) symm = -symm;
// check matrices coming from linear constraints with Lagrange multipliers
if (rows >= 3) {
SquareMatrixType A = symm;
Index c = internal::random<Index>(0, rows - 2);
A.bottomRightCorner(c, c).setZero();
// Make sure a solution exists:
vecX.setRandom();
vecB = A * vecX;
vecX.setZero();
ldltlo.compute(A);
VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix());
vecX = ldltlo.solve(vecB);
VERIFY_IS_APPROX(A * vecX, vecB);
}
// check non-full rank matrices
if (rows >= 3) {
Index r = internal::random<Index>(1, rows - 1);
Matrix<Scalar, Dynamic, Dynamic> a = Matrix<Scalar, Dynamic, Dynamic>::Random(rows, r);
SquareMatrixType A = a * a.adjoint();
// Make sure a solution exists:
vecX.setRandom();
vecB = A * vecX;
vecX.setZero();
ldltlo.compute(A);
VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix());
vecX = ldltlo.solve(vecB);
VERIFY_IS_APPROX(A * vecX, vecB);
}
// check matrices with a wide spectrum
if (rows >= 3) {
using std::pow;
using std::sqrt;
RealScalar s = (std::min)(16, std::numeric_limits<RealScalar>::max_exponent10 / 8);
Matrix<Scalar, Dynamic, Dynamic> a = Matrix<Scalar, Dynamic, Dynamic>::Random(rows, rows);
Matrix<RealScalar, Dynamic, 1> d = Matrix<RealScalar, Dynamic, 1>::Random(rows);
for (Index k = 0; k < rows; ++k) d(k) = d(k) * pow(RealScalar(10), internal::random<RealScalar>(-s, s));
SquareMatrixType A = a * d.asDiagonal() * a.adjoint();
// Make sure a solution exists:
vecX.setRandom();
vecB = A * vecX;
vecX.setZero();
ldltlo.compute(A);
VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix());
vecX = ldltlo.solve(vecB);
if (ldltlo.vectorD().real().cwiseAbs().minCoeff() > RealScalar(0)) {
VERIFY_IS_APPROX(A * vecX, vecB);
} else {
RealScalar large_tol = sqrt(test_precision<RealScalar>());
VERIFY((A * vecX).isApprox(vecB, large_tol));
++g_test_level;
VERIFY_IS_APPROX(A * vecX, vecB);
--g_test_level;
}
}
}
// update/downdate
CALL_SUBTEST((test_chol_update<SquareMatrixType, LLT>(symm)));
CALL_SUBTEST((test_chol_update<SquareMatrixType, LDLT>(symm)));
}
template <typename MatrixType>
void cholesky_cplx(const MatrixType& m) {
// classic test
cholesky(m);
// test mixing real/scalar types
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RealMatrixType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
RealMatrixType a0 = RealMatrixType::Random(rows, cols);
VectorType vecB = VectorType::Random(rows), vecX(rows);
MatrixType matB = MatrixType::Random(rows, cols), matX(rows, cols);
RealMatrixType symm = a0 * a0.adjoint();
// let's make sure the matrix is not singular or near singular
for (int k = 0; k < 3; ++k) {
RealMatrixType a1 = RealMatrixType::Random(rows, cols);
symm += a1 * a1.adjoint();
}
{
RealMatrixType symmLo = symm.template triangularView<Lower>();
LLT<RealMatrixType, Lower> chollo(symmLo);
VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
check_solverbase<VectorType, VectorType>(symm, chollo, rows, rows, 1);
// check_solverbase<MatrixType, MatrixType>(symm, chollo, rows, cols, rows);
}
// LDLT
{
int sign = internal::random<int>() % 2 ? 1 : -1;
if (sign == -1) {
symm = -symm; // test a negative matrix
}
RealMatrixType symmLo = symm.template triangularView<Lower>();
LDLT<RealMatrixType, Lower> ldltlo(symmLo);
VERIFY(ldltlo.info() == Success);
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
check_solverbase<VectorType, VectorType>(symm, ldltlo, rows, rows, 1);
// check_solverbase<MatrixType, MatrixType>(symm, ldltlo, rows, cols, rows);
}
}
// regression test for bug 241
template <typename MatrixType>
void cholesky_bug241(const MatrixType& m) {
eigen_assert(m.rows() == 2 && m.cols() == 2);
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
MatrixType matA;
matA << 1, 1, 1, 1;
VectorType vecB;
vecB << 1, 1;
VectorType vecX = matA.ldlt().solve(vecB);
VERIFY_IS_APPROX(matA * vecX, vecB);
}
// LDLT is not guaranteed to work for indefinite matrices, but happens to work fine if matrix is diagonal.
// This test checks that LDLT reports correctly that matrix is indefinite.
// See http://forum.kde.org/viewtopic.php?f=74&t=106942 and bug 736
template <typename MatrixType>
void cholesky_definiteness(const MatrixType& m) {
eigen_assert(m.rows() == 2 && m.cols() == 2);
MatrixType mat;
LDLT<MatrixType> ldlt(2);
{
mat << 1, 0, 0, -1;
ldlt.compute(mat);
VERIFY(ldlt.info() == Success);
VERIFY(!ldlt.isNegative());
VERIFY(!ldlt.isPositive());
VERIFY_IS_APPROX(mat, ldlt.reconstructedMatrix());
}
{
mat << 1, 2, 2, 1;
ldlt.compute(mat);
VERIFY(ldlt.info() == Success);
VERIFY(!ldlt.isNegative());
VERIFY(!ldlt.isPositive());
VERIFY_IS_APPROX(mat, ldlt.reconstructedMatrix());
}
{
mat << 0, 0, 0, 0;
ldlt.compute(mat);
VERIFY(ldlt.info() == Success);
VERIFY(ldlt.isNegative());
VERIFY(ldlt.isPositive());
VERIFY_IS_APPROX(mat, ldlt.reconstructedMatrix());
}
{
mat << 0, 0, 0, 1;
ldlt.compute(mat);
VERIFY(ldlt.info() == Success);
VERIFY(!ldlt.isNegative());
VERIFY(ldlt.isPositive());
VERIFY_IS_APPROX(mat, ldlt.reconstructedMatrix());
}
{
mat << -1, 0, 0, 0;
ldlt.compute(mat);
VERIFY(ldlt.info() == Success);
VERIFY(ldlt.isNegative());
VERIFY(!ldlt.isPositive());
VERIFY_IS_APPROX(mat, ldlt.reconstructedMatrix());
}
}
template <typename>
void cholesky_faillure_cases() {
MatrixXd mat;
LDLT<MatrixXd> ldlt;
{
mat.resize(2, 2);
mat << 0, 1, 1, 0;
ldlt.compute(mat);
VERIFY_IS_NOT_APPROX(mat, ldlt.reconstructedMatrix());
VERIFY(ldlt.info() == NumericalIssue);
}
#if (!EIGEN_ARCH_i386) || defined(EIGEN_VECTORIZE_SSE2)
{
mat.resize(3, 3);
mat << -1, -3, 3, -3, -8.9999999999999999999, 1, 3, 1, 0;
ldlt.compute(mat);
VERIFY(ldlt.info() == NumericalIssue);
VERIFY_IS_NOT_APPROX(mat, ldlt.reconstructedMatrix());
}
#endif
{
mat.resize(3, 3);
mat << 1, 2, 3, 2, 4, 1, 3, 1, 0;
ldlt.compute(mat);
VERIFY(ldlt.info() == NumericalIssue);
VERIFY_IS_NOT_APPROX(mat, ldlt.reconstructedMatrix());
}
{
mat.resize(8, 8);
mat << 0.1, 0, -0.1, 0, 0, 0, 1, 0, 0, 4.24667, 0, 2.00333, 0, 0, 0, 0, -0.1, 0, 0.2, 0, -0.1, 0, 0, 0, 0, 2.00333,
0, 8.49333, 0, 2.00333, 0, 0, 0, 0, -0.1, 0, 0.1, 0, 0, 1, 0, 0, 0, 2.00333, 0, 4.24667, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0;
ldlt.compute(mat);
VERIFY(ldlt.info() == NumericalIssue);
VERIFY_IS_NOT_APPROX(mat, ldlt.reconstructedMatrix());
}
// bug 1479
{
mat.resize(4, 4);
mat << 1, 2, 0, 1, 2, 4, 0, 2, 0, 0, 0, 1, 1, 2, 1, 1;
ldlt.compute(mat);
VERIFY(ldlt.info() == NumericalIssue);
VERIFY_IS_NOT_APPROX(mat, ldlt.reconstructedMatrix());
}
}
template <typename MatrixType>
void cholesky_verify_assert() {
MatrixType tmp;
LLT<MatrixType> llt;
VERIFY_RAISES_ASSERT(llt.matrixL())
VERIFY_RAISES_ASSERT(llt.matrixU())
VERIFY_RAISES_ASSERT(llt.solve(tmp))
VERIFY_RAISES_ASSERT(llt.transpose().solve(tmp))
VERIFY_RAISES_ASSERT(llt.adjoint().solve(tmp))
VERIFY_RAISES_ASSERT(llt.solveInPlace(tmp))
LDLT<MatrixType> ldlt;
VERIFY_RAISES_ASSERT(ldlt.matrixL())
VERIFY_RAISES_ASSERT(ldlt.transpositionsP())
VERIFY_RAISES_ASSERT(ldlt.vectorD())
VERIFY_RAISES_ASSERT(ldlt.isPositive())
VERIFY_RAISES_ASSERT(ldlt.isNegative())
VERIFY_RAISES_ASSERT(ldlt.solve(tmp))
VERIFY_RAISES_ASSERT(ldlt.transpose().solve(tmp))
VERIFY_RAISES_ASSERT(ldlt.adjoint().solve(tmp))
VERIFY_RAISES_ASSERT(ldlt.solveInPlace(tmp))
}
EIGEN_DECLARE_TEST(cholesky) {
int s = 0;
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(cholesky(Matrix<double, 1, 1>()));
CALL_SUBTEST_3(cholesky(Matrix2d()));
CALL_SUBTEST_3(cholesky_bug241(Matrix2d()));
CALL_SUBTEST_3(cholesky_definiteness(Matrix2d()));
CALL_SUBTEST_4(cholesky(Matrix3f()));
CALL_SUBTEST_5(cholesky(Matrix4d()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE);
CALL_SUBTEST_2(cholesky(MatrixXd(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2);
CALL_SUBTEST_6(cholesky_cplx(MatrixXcd(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
// empty matrix, regression test for Bug 785:
CALL_SUBTEST_2(cholesky(MatrixXd(0, 0)));
// This does not work yet:
// CALL_SUBTEST_2( cholesky(Matrix<double,0,0>()) );
CALL_SUBTEST_4(cholesky_verify_assert<Matrix3f>());
CALL_SUBTEST_7(cholesky_verify_assert<Matrix3d>());
CALL_SUBTEST_8(cholesky_verify_assert<MatrixXf>());
CALL_SUBTEST_2(cholesky_verify_assert<MatrixXd>());
// Test problem size constructors
CALL_SUBTEST_9(LLT<MatrixXf>(10));
CALL_SUBTEST_9(LDLT<MatrixXf>(10));
CALL_SUBTEST_2(cholesky_faillure_cases<void>());
TEST_SET_BUT_UNUSED_VARIABLE(nb_temporaries)
}
+81
View File
@@ -0,0 +1,81 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS
#include "sparse_solver.h"
#include <Eigen/CholmodSupport>
template <typename SparseType>
void test_cholmod_ST() {
CholmodDecomposition<SparseType, Lower> g_chol_colmajor_lower;
g_chol_colmajor_lower.setMode(CholmodSupernodalLLt);
CholmodDecomposition<SparseType, Upper> g_chol_colmajor_upper;
g_chol_colmajor_upper.setMode(CholmodSupernodalLLt);
CholmodDecomposition<SparseType, Lower> g_llt_colmajor_lower;
g_llt_colmajor_lower.setMode(CholmodSimplicialLLt);
CholmodDecomposition<SparseType, Upper> g_llt_colmajor_upper;
g_llt_colmajor_upper.setMode(CholmodSimplicialLLt);
CholmodDecomposition<SparseType, Lower> g_ldlt_colmajor_lower;
g_ldlt_colmajor_lower.setMode(CholmodLDLt);
CholmodDecomposition<SparseType, Upper> g_ldlt_colmajor_upper;
g_ldlt_colmajor_upper.setMode(CholmodLDLt);
CholmodSupernodalLLT<SparseType, Lower> chol_colmajor_lower;
CholmodSupernodalLLT<SparseType, Upper> chol_colmajor_upper;
CholmodSimplicialLLT<SparseType, Lower> llt_colmajor_lower;
CholmodSimplicialLLT<SparseType, Upper> llt_colmajor_upper;
CholmodSimplicialLDLT<SparseType, Lower> ldlt_colmajor_lower;
CholmodSimplicialLDLT<SparseType, Upper> ldlt_colmajor_upper;
check_sparse_spd_solving(g_chol_colmajor_lower);
check_sparse_spd_solving(g_chol_colmajor_upper);
check_sparse_spd_solving(g_llt_colmajor_lower);
check_sparse_spd_solving(g_llt_colmajor_upper);
check_sparse_spd_solving(g_ldlt_colmajor_lower);
check_sparse_spd_solving(g_ldlt_colmajor_upper);
check_sparse_spd_solving(chol_colmajor_lower);
check_sparse_spd_solving(chol_colmajor_upper);
check_sparse_spd_solving(llt_colmajor_lower);
check_sparse_spd_solving(llt_colmajor_upper);
check_sparse_spd_solving(ldlt_colmajor_lower);
check_sparse_spd_solving(ldlt_colmajor_upper);
check_sparse_spd_determinant(chol_colmajor_lower);
check_sparse_spd_determinant(chol_colmajor_upper);
check_sparse_spd_determinant(llt_colmajor_lower);
check_sparse_spd_determinant(llt_colmajor_upper);
check_sparse_spd_determinant(ldlt_colmajor_lower);
check_sparse_spd_determinant(ldlt_colmajor_upper);
check_sparse_zero_matrix(chol_colmajor_lower);
check_sparse_zero_matrix(chol_colmajor_upper);
check_sparse_zero_matrix(llt_colmajor_lower);
check_sparse_zero_matrix(llt_colmajor_upper);
check_sparse_zero_matrix(ldlt_colmajor_lower);
check_sparse_zero_matrix(ldlt_colmajor_upper);
}
template <typename T, int flags, typename IdxType>
void test_cholmod_T() {
test_cholmod_ST<SparseMatrix<T, flags, IdxType> >();
}
EIGEN_DECLARE_TEST(cholmod_support) {
CALL_SUBTEST_11((test_cholmod_T<double, ColMajor, int>()));
CALL_SUBTEST_12((test_cholmod_T<double, ColMajor, long>()));
CALL_SUBTEST_13((test_cholmod_T<double, RowMajor, int>()));
CALL_SUBTEST_14((test_cholmod_T<double, RowMajor, long>()));
CALL_SUBTEST_21((test_cholmod_T<std::complex<double>, ColMajor, int>()));
CALL_SUBTEST_22((test_cholmod_T<std::complex<double>, ColMajor, long>()));
// TODO complex row-major matrices do not work at the moment:
// CALL_SUBTEST_23( (test_cholmod_T<std::complex<double>, RowMajor, int >()) );
// CALL_SUBTEST_24( (test_cholmod_T<std::complex<double>, RowMajor, long>()) );
}
+74
View File
@@ -0,0 +1,74 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2023 The Eigen Authors
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename T>
int ref_clz(T val) {
constexpr int kNumBits = sizeof(T) * CHAR_BIT;
T kMsbMask = T(1) << (kNumBits - 1);
int z = 0;
for (; z < kNumBits && ((val & kMsbMask) == 0); ++z) {
val <<= 1;
}
return z;
}
template <typename T>
int ref_ctz(T val) {
constexpr int kNumBits = sizeof(T) * CHAR_BIT;
T kLsbMask = T(1);
int z = 0;
for (; z < kNumBits && ((val & kLsbMask) == 0); ++z) {
val >>= 1;
}
return z;
}
template <typename T>
void test_clz_ctz() {
T step = sizeof(T) <= 2 ? 1 : (Eigen::NumTraits<T>::highest() / (T(1) << 16));
T iters = Eigen::NumTraits<T>::highest() / step;
for (T i = 0; i < iters; ++i) {
T val = i * step;
int expected_clz = ref_clz(val);
int actual_clz = Eigen::internal::clz(val);
VERIFY(expected_clz == actual_clz);
int expected_ctz = ref_ctz(val);
int actual_ctz = Eigen::internal::ctz(val);
VERIFY(expected_ctz == actual_ctz);
}
}
template <typename T>
void test_clz_ctz_random() {
for (int i = 0; i < 1024 * 1024; ++i) {
T val = Eigen::internal::random<T>();
int expected_clz = ref_clz(val);
int actual_clz = Eigen::internal::clz(val);
VERIFY(expected_clz == actual_clz);
int expected_ctz = ref_ctz(val);
int actual_ctz = Eigen::internal::ctz(val);
VERIFY(expected_ctz == actual_ctz);
}
}
EIGEN_DECLARE_TEST(clz) {
CALL_SUBTEST_1(test_clz_ctz<uint8_t>());
CALL_SUBTEST_2(test_clz_ctz<uint16_t>());
CALL_SUBTEST_3(test_clz_ctz<uint32_t>());
CALL_SUBTEST_4(test_clz_ctz<uint64_t>());
for (int i = 0; i < g_repeat; i++) {
test_clz_ctz_random<uint32_t>();
test_clz_ctz_random<uint64_t>();
}
}
+107
View File
@@ -0,0 +1,107 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <int M1, int M2, int N1, int N2>
void test_blocks() {
Matrix<int, M1 + M2, N1 + N2> m_fixed;
MatrixXi m_dynamic(M1 + M2, N1 + N2);
Matrix<int, M1, N1> mat11;
mat11.setRandom();
Matrix<int, M1, N2> mat12;
mat12.setRandom();
Matrix<int, M2, N1> mat21;
mat21.setRandom();
Matrix<int, M2, N2> mat22;
mat22.setRandom();
MatrixXi matx11 = mat11, matx12 = mat12, matx21 = mat21, matx22 = mat22;
{
VERIFY_IS_EQUAL((m_fixed << mat11, mat12, mat21, matx22).finished(),
(m_dynamic << mat11, matx12, mat21, matx22).finished());
VERIFY_IS_EQUAL((m_fixed.template topLeftCorner<M1, N1>()), mat11);
VERIFY_IS_EQUAL((m_fixed.template topRightCorner<M1, N2>()), mat12);
VERIFY_IS_EQUAL((m_fixed.template bottomLeftCorner<M2, N1>()), mat21);
VERIFY_IS_EQUAL((m_fixed.template bottomRightCorner<M2, N2>()), mat22);
VERIFY_IS_EQUAL((m_fixed << mat12, mat11, matx21, mat22).finished(),
(m_dynamic << mat12, matx11, matx21, mat22).finished());
}
if (N1 > 0) {
if (M1 > 0) {
VERIFY_RAISES_ASSERT((m_fixed << mat11, mat12, mat11, mat21, mat22));
}
if (M2 > 0) {
VERIFY_RAISES_ASSERT((m_fixed << mat11, mat12, mat21, mat21, mat22));
}
} else {
// allow insertion of zero-column blocks:
VERIFY_IS_EQUAL((m_fixed << mat11, mat12, mat11, mat11, mat21, mat21, mat22).finished(),
(m_dynamic << mat12, mat22).finished());
}
if (M1 != M2) {
VERIFY_RAISES_ASSERT((m_fixed << mat11, mat21, mat12, mat22));
}
}
template <int depth, int N = 0>
struct test_block_recursion {
static void run() {
test_block_recursion<depth - 1, N>::run();
test_block_recursion<depth - 1, N + (1 << (depth - 1))>::run();
}
};
template <int N>
struct test_block_recursion<0, N> {
static void run() { test_blocks<(N >> 6) & 3, (N >> 4) & 3, (N >> 2) & 3, N & 3>(); }
};
void test_basics() {
Matrix3d m3;
Matrix4d m4;
VERIFY_RAISES_ASSERT((m3 << 1, 2, 3, 4, 5, 6, 7, 8));
#ifndef _MSC_VER
VERIFY_RAISES_ASSERT((m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
#endif
double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Matrix3d ref = Map<Matrix<double, 3, 3, RowMajor> >(data);
m3 = Matrix3d::Random();
m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
VERIFY_IS_APPROX(m3, ref);
Vector3d vec[3];
vec[0] << 1, 4, 7;
vec[1] << 2, 5, 8;
vec[2] << 3, 6, 9;
m3 = Matrix3d::Random();
m3 << vec[0], vec[1], vec[2];
VERIFY_IS_APPROX(m3, ref);
vec[0] << 1, 2, 3;
vec[1] << 4, 5, 6;
vec[2] << 7, 8, 9;
m3 = Matrix3d::Random();
m3 << vec[0].transpose(), 4, 5, 6, vec[2].transpose();
VERIFY_IS_APPROX(m3, ref);
}
EIGEN_DECLARE_TEST(commainitializer) {
CALL_SUBTEST_1(test_basics());
// recursively test all block-sizes from 0 to 3:
CALL_SUBTEST_2(test_block_recursion<8>::run());
}
+33
View File
@@ -0,0 +1,33 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "sparse_solver.h"
#include <Eigen/IterativeLinearSolvers>
template <typename T, typename I_>
void test_conjugate_gradient_T() {
typedef SparseMatrix<T, 0, I_> SparseMatrixType;
ConjugateGradient<SparseMatrixType, Lower> cg_colmajor_lower_diag;
ConjugateGradient<SparseMatrixType, Upper> cg_colmajor_upper_diag;
ConjugateGradient<SparseMatrixType, Lower | Upper> cg_colmajor_loup_diag;
ConjugateGradient<SparseMatrixType, Lower, IdentityPreconditioner> cg_colmajor_lower_I;
ConjugateGradient<SparseMatrixType, Upper, IdentityPreconditioner> cg_colmajor_upper_I;
CALL_SUBTEST(check_sparse_spd_solving(cg_colmajor_lower_diag));
CALL_SUBTEST(check_sparse_spd_solving(cg_colmajor_upper_diag));
CALL_SUBTEST(check_sparse_spd_solving(cg_colmajor_loup_diag));
CALL_SUBTEST(check_sparse_spd_solving(cg_colmajor_lower_I));
CALL_SUBTEST(check_sparse_spd_solving(cg_colmajor_upper_I));
}
EIGEN_DECLARE_TEST(conjugate_gradient) {
CALL_SUBTEST_1((test_conjugate_gradient_T<double, int>()));
CALL_SUBTEST_2((test_conjugate_gradient_T<std::complex<double>, int>()));
CALL_SUBTEST_3((test_conjugate_gradient_T<double, long int>()));
}
+162
View File
@@ -0,0 +1,162 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Hauke Heibel <hauke.heibel@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Core>
#include "AnnoyingScalar.h"
using namespace Eigen;
template <typename Scalar, int Storage>
void run_matrix_tests() {
typedef Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Storage> MatrixType;
MatrixType m, n;
// boundary cases ...
m = n = MatrixType::Random(50, 50);
m.conservativeResize(1, 50);
VERIFY_IS_APPROX(m, n.block(0, 0, 1, 50));
m = n = MatrixType::Random(50, 50);
m.conservativeResize(50, 1);
VERIFY_IS_APPROX(m, n.block(0, 0, 50, 1));
m = n = MatrixType::Random(50, 50);
m.conservativeResize(50, 50);
VERIFY_IS_APPROX(m, n.block(0, 0, 50, 50));
// random shrinking ...
for (int i = 0; i < 25; ++i) {
const Index rows = internal::random<Index>(1, 50);
const Index cols = internal::random<Index>(1, 50);
m = n = MatrixType::Random(50, 50);
m.conservativeResize(rows, cols);
VERIFY_IS_APPROX(m, n.block(0, 0, rows, cols));
}
// random growing with zeroing ...
for (int i = 0; i < 25; ++i) {
const Index rows = internal::random<Index>(50, 75);
const Index cols = internal::random<Index>(50, 75);
m = n = MatrixType::Random(50, 50);
m.conservativeResizeLike(MatrixType::Zero(rows, cols));
VERIFY_IS_APPROX(m.block(0, 0, n.rows(), n.cols()), n);
VERIFY(rows <= 50 || m.block(50, 0, rows - 50, cols).sum() == Scalar(0));
VERIFY(cols <= 50 || m.block(0, 50, rows, cols - 50).sum() == Scalar(0));
}
}
template <typename Scalar>
void run_vector_tests() {
typedef Matrix<Scalar, 1, Eigen::Dynamic> VectorType;
VectorType m, n;
// boundary cases ...
m = n = VectorType::Random(50);
m.conservativeResize(1);
VERIFY_IS_APPROX(m, n.segment(0, 1));
m = n = VectorType::Random(50);
m.conservativeResize(50);
VERIFY_IS_APPROX(m, n.segment(0, 50));
m = n = VectorType::Random(50);
m.conservativeResize(m.rows(), 1);
VERIFY_IS_APPROX(m, n.segment(0, 1));
m = n = VectorType::Random(50);
m.conservativeResize(m.rows(), 50);
VERIFY_IS_APPROX(m, n.segment(0, 50));
// random shrinking ...
for (int i = 0; i < 50; ++i) {
const int size = internal::random<int>(1, 50);
m = n = VectorType::Random(50);
m.conservativeResize(size);
VERIFY_IS_APPROX(m, n.segment(0, size));
m = n = VectorType::Random(50);
m.conservativeResize(m.rows(), size);
VERIFY_IS_APPROX(m, n.segment(0, size));
}
// random growing with zeroing ...
for (int i = 0; i < 50; ++i) {
const int size = internal::random<int>(50, 100);
m = n = VectorType::Random(50);
m.conservativeResizeLike(VectorType::Zero(size));
VERIFY_IS_APPROX(m.segment(0, 50), n);
VERIFY(size <= 50 || m.segment(50, size - 50).sum() == Scalar(0));
m = n = VectorType::Random(50);
m.conservativeResizeLike(Matrix<Scalar, Dynamic, Dynamic>::Zero(1, size));
VERIFY_IS_APPROX(m.segment(0, 50), n);
VERIFY(size <= 50 || m.segment(50, size - 50).sum() == Scalar(0));
}
}
// Basic memory leak check with a non-copyable scalar type
template <int>
void noncopyable() {
typedef Eigen::Matrix<AnnoyingScalar, Dynamic, 1> VectorType;
typedef Eigen::Matrix<AnnoyingScalar, Dynamic, Dynamic> MatrixType;
{
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
AnnoyingScalar::dont_throw = true;
#endif
int n = 50;
VectorType v0(n), v1(n);
MatrixType m0(n, n), m1(n, n), m2(n, n);
v0.setOnes();
v1.setOnes();
m0.setOnes();
m1.setOnes();
m2.setOnes();
VERIFY(m0 == m1);
m0.conservativeResize(2 * n, 2 * n);
VERIFY(m0.topLeftCorner(n, n) == m1);
VERIFY(v0.head(n) == v1);
v0.conservativeResize(2 * n);
VERIFY(v0.head(n) == v1);
}
VERIFY(AnnoyingScalar::instances == 0 && "global memory leak detected in noncopyable");
}
EIGEN_DECLARE_TEST(conservative_resize) {
for (int i = 0; i < g_repeat; ++i) {
CALL_SUBTEST_1((run_matrix_tests<int, Eigen::RowMajor>()));
CALL_SUBTEST_1((run_matrix_tests<int, Eigen::ColMajor>()));
CALL_SUBTEST_2((run_matrix_tests<float, Eigen::RowMajor>()));
CALL_SUBTEST_2((run_matrix_tests<float, Eigen::ColMajor>()));
CALL_SUBTEST_3((run_matrix_tests<double, Eigen::RowMajor>()));
CALL_SUBTEST_3((run_matrix_tests<double, Eigen::ColMajor>()));
CALL_SUBTEST_4((run_matrix_tests<std::complex<float>, Eigen::RowMajor>()));
CALL_SUBTEST_4((run_matrix_tests<std::complex<float>, Eigen::ColMajor>()));
CALL_SUBTEST_5((run_matrix_tests<std::complex<double>, Eigen::RowMajor>()));
CALL_SUBTEST_5((run_matrix_tests<std::complex<double>, Eigen::ColMajor>()));
CALL_SUBTEST_1((run_matrix_tests<int, Eigen::RowMajor | Eigen::DontAlign>()));
CALL_SUBTEST_1((run_vector_tests<int>()));
CALL_SUBTEST_2((run_vector_tests<float>()));
CALL_SUBTEST_3((run_vector_tests<double>()));
CALL_SUBTEST_4((run_vector_tests<std::complex<float> >()));
CALL_SUBTEST_5((run_vector_tests<std::complex<double> >()));
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
AnnoyingScalar::dont_throw = true;
#endif
CALL_SUBTEST_6((run_vector_tests<AnnoyingScalar>()));
CALL_SUBTEST_6((noncopyable<0>()));
}
}
+82
View File
@@ -0,0 +1,82 @@
// 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/.
#define EIGEN_TESTING_CONSTEXPR
#include "main.h"
template <typename Scalar, int Rows>
struct ConstexprTest {
constexpr ConstexprTest(const Matrix<Scalar, Rows, Rows>& B) { A = B; }
Matrix<Scalar, Rows, Rows> A;
};
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 __cpp_constexpr >= 201907L
constexpr Matrix3i mat({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
VERIFY_IS_EQUAL(mat.size(), 9);
static_assert(mat(0, 0) == 1);
static_assert(mat(0) == 1);
static_assert(mat.coeff(0, 1) == 2);
constexpr Array33i arr({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
static_assert(arr(0, 0) == 1);
static_assert(arr(0) == 1);
VERIFY_IS_EQUAL(arr.size(), 9);
static_assert(arr.coeff(0, 1) == 2);
constexpr RowVector3i vec{{1, 2, 3}};
static_assert(vec(0, 0) == 1);
static_assert(vec[0] == 1);
VERIFY_IS_EQUAL(vec.size(), 3);
static_assert(vec.coeff(0, 1) == 2);
// Check assignment. A wrapper struct is used to avoid copy ellision.
constexpr ConstexprTest<double, 2> obj1(Matrix2d({{1, 2}, {3, 4}}));
VERIFY_IS_EQUAL(obj1.A.size(), 4);
static_assert(obj1.A(0, 0) == 1);
static_assert(obj1.A(0) == 1);
static_assert(obj1.A.coeff(0, 1) == 2);
constexpr ConstexprTest<double, 3> obj2(Matrix3d({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}));
VERIFY_IS_EQUAL(obj2.A.size(), 9);
static_assert(obj2.A(0, 0) == 1);
static_assert(obj2.A(0) == 1);
static_assert(obj2.A.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);
static_assert(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}});
static_assert(dyn_arr(0, 0) == 1);
static_assert(dyn_arr(0) == 1);
VERIFY_IS_EQUAL(dyn_arr.size(), 9);
static_assert(dyn_arr.coeff(0, 1) == 2);
#endif // __cpp_constexpr >= 201907L
}
// Check that we can use the std::initializer_list constructor for constexpr variables.
#if __cpp_constexpr >= 201907L
// 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);
static_assert(global_mat(0, 0) == 1);
static_assert(global_mat(0) == 1);
static_assert(global_mat.coeff(0, 0) == 1);
}
#endif // __cpp_constexpr >= 201907L
+97
View File
@@ -0,0 +1,97 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2017 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define TEST_ENABLE_TEMPORARY_TRACKING
#include "main.h"
template <typename MatrixType>
struct Wrapper {
MatrixType m_mat;
inline Wrapper(const MatrixType& x) : m_mat(x) {}
inline operator const MatrixType&() const { return m_mat; }
inline operator MatrixType&() { return m_mat; }
};
enum my_sizes { M = 12, N = 7 };
template <typename MatrixType>
void ctor_init1(const MatrixType& m) {
// Check logic in PlainObjectBase::_init1
Index rows = m.rows();
Index cols = m.cols();
MatrixType m0 = MatrixType::Random(rows, cols);
VERIFY_EVALUATION_COUNT(MatrixType m1(m0), 1);
VERIFY_EVALUATION_COUNT(MatrixType m2(m0 + m0), 1);
VERIFY_EVALUATION_COUNT(MatrixType m2(m0.block(0, 0, rows, cols)), 1);
Wrapper<MatrixType> wrapper(m0);
VERIFY_EVALUATION_COUNT(MatrixType m3(wrapper), 1);
}
EIGEN_DECLARE_TEST(constructor) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(ctor_init1(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(ctor_init1(Matrix4d()));
CALL_SUBTEST_1(ctor_init1(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_1(ctor_init1(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
{
Matrix<Index, 1, 1> a(123);
VERIFY_IS_EQUAL(a[0], 123);
}
{
Matrix<Index, 1, 1> a(123.0);
VERIFY_IS_EQUAL(a[0], 123);
}
{
Matrix<float, 1, 1> a(123);
VERIFY_IS_EQUAL(a[0], 123.f);
}
{
Array<Index, 1, 1> a(123);
VERIFY_IS_EQUAL(a[0], 123);
}
{
Array<Index, 1, 1> a(123.0);
VERIFY_IS_EQUAL(a[0], 123);
}
{
Array<float, 1, 1> a(123);
VERIFY_IS_EQUAL(a[0], 123.f);
}
{
Array<Index, 3, 3> a(123);
VERIFY_IS_EQUAL(a(4), 123);
}
{
Array<Index, 3, 3> a(123.0);
VERIFY_IS_EQUAL(a(4), 123);
}
{
Array<float, 3, 3> a(123);
VERIFY_IS_EQUAL(a(4), 123.f);
}
{
MatrixXi m1(M, N);
VERIFY_IS_EQUAL(m1.rows(), M);
VERIFY_IS_EQUAL(m1.cols(), N);
ArrayXXi a1(M, N);
VERIFY_IS_EQUAL(a1.rows(), M);
VERIFY_IS_EQUAL(a1.cols(), N);
VectorXi v1(M);
VERIFY_IS_EQUAL(v1.size(), M);
ArrayXi a2(M);
VERIFY_IS_EQUAL(a2.size(), M);
}
}
+125
View File
@@ -0,0 +1,125 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#define COMPARE_CORNER(A, B) \
VERIFY_IS_EQUAL(matrix.A, matrix.B); \
VERIFY_IS_EQUAL(const_matrix.A, const_matrix.B);
template <typename MatrixType>
void corners(const MatrixType& m) {
Index rows = m.rows();
Index cols = m.cols();
Index r = internal::random<Index>(1, rows);
Index c = internal::random<Index>(1, cols);
MatrixType matrix = MatrixType::Random(rows, cols);
const MatrixType const_matrix = MatrixType::Random(rows, cols);
COMPARE_CORNER(topLeftCorner(r, c), block(0, 0, r, c));
COMPARE_CORNER(topRightCorner(r, c), block(0, cols - c, r, c));
COMPARE_CORNER(bottomLeftCorner(r, c), block(rows - r, 0, r, c));
COMPARE_CORNER(bottomRightCorner(r, c), block(rows - r, cols - c, r, c));
Index sr = internal::random<Index>(1, rows) - 1;
Index nr = internal::random<Index>(1, rows - sr);
Index sc = internal::random<Index>(1, cols) - 1;
Index nc = internal::random<Index>(1, cols - sc);
COMPARE_CORNER(topRows(r), block(0, 0, r, cols));
COMPARE_CORNER(middleRows(sr, nr), block(sr, 0, nr, cols));
COMPARE_CORNER(bottomRows(r), block(rows - r, 0, r, cols));
COMPARE_CORNER(leftCols(c), block(0, 0, rows, c));
COMPARE_CORNER(middleCols(sc, nc), block(0, sc, rows, nc));
COMPARE_CORNER(rightCols(c), block(0, cols - c, rows, c));
}
template <typename MatrixType, int CRows, int CCols, int SRows, int SCols>
void corners_fixedsize() {
MatrixType matrix = MatrixType::Random();
const MatrixType const_matrix = MatrixType::Random();
enum {
rows = MatrixType::RowsAtCompileTime,
cols = MatrixType::ColsAtCompileTime,
r = CRows,
c = CCols,
sr = SRows,
sc = SCols
};
VERIFY_IS_EQUAL((matrix.template topLeftCorner<r, c>()), (matrix.template block<r, c>(0, 0)));
VERIFY_IS_EQUAL((matrix.template topRightCorner<r, c>()), (matrix.template block<r, c>(0, cols - c)));
VERIFY_IS_EQUAL((matrix.template bottomLeftCorner<r, c>()), (matrix.template block<r, c>(rows - r, 0)));
VERIFY_IS_EQUAL((matrix.template bottomRightCorner<r, c>()), (matrix.template block<r, c>(rows - r, cols - c)));
VERIFY_IS_EQUAL((matrix.template topLeftCorner<r, c>()), (matrix.template topLeftCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((matrix.template topRightCorner<r, c>()), (matrix.template topRightCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((matrix.template bottomLeftCorner<r, c>()), (matrix.template bottomLeftCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((matrix.template bottomRightCorner<r, c>()), (matrix.template bottomRightCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((matrix.template topLeftCorner<r, c>()), (matrix.template topLeftCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((matrix.template topRightCorner<r, c>()), (matrix.template topRightCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((matrix.template bottomLeftCorner<r, c>()), (matrix.template bottomLeftCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((matrix.template bottomRightCorner<r, c>()), (matrix.template bottomRightCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((matrix.template topRows<r>()), (matrix.template block<r, cols>(0, 0)));
VERIFY_IS_EQUAL((matrix.template middleRows<r>(sr)), (matrix.template block<r, cols>(sr, 0)));
VERIFY_IS_EQUAL((matrix.template bottomRows<r>()), (matrix.template block<r, cols>(rows - r, 0)));
VERIFY_IS_EQUAL((matrix.template leftCols<c>()), (matrix.template block<rows, c>(0, 0)));
VERIFY_IS_EQUAL((matrix.template middleCols<c>(sc)), (matrix.template block<rows, c>(0, sc)));
VERIFY_IS_EQUAL((matrix.template rightCols<c>()), (matrix.template block<rows, c>(0, cols - c)));
VERIFY_IS_EQUAL((const_matrix.template topLeftCorner<r, c>()), (const_matrix.template block<r, c>(0, 0)));
VERIFY_IS_EQUAL((const_matrix.template topRightCorner<r, c>()), (const_matrix.template block<r, c>(0, cols - c)));
VERIFY_IS_EQUAL((const_matrix.template bottomLeftCorner<r, c>()), (const_matrix.template block<r, c>(rows - r, 0)));
VERIFY_IS_EQUAL((const_matrix.template bottomRightCorner<r, c>()),
(const_matrix.template block<r, c>(rows - r, cols - c)));
VERIFY_IS_EQUAL((const_matrix.template topLeftCorner<r, c>()),
(const_matrix.template topLeftCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template topRightCorner<r, c>()),
(const_matrix.template topRightCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template bottomLeftCorner<r, c>()),
(const_matrix.template bottomLeftCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template bottomRightCorner<r, c>()),
(const_matrix.template bottomRightCorner<r, Dynamic>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template topLeftCorner<r, c>()),
(const_matrix.template topLeftCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template topRightCorner<r, c>()),
(const_matrix.template topRightCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template bottomLeftCorner<r, c>()),
(const_matrix.template bottomLeftCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template bottomRightCorner<r, c>()),
(const_matrix.template bottomRightCorner<Dynamic, c>(r, c)));
VERIFY_IS_EQUAL((const_matrix.template topRows<r>()), (const_matrix.template block<r, cols>(0, 0)));
VERIFY_IS_EQUAL((const_matrix.template middleRows<r>(sr)), (const_matrix.template block<r, cols>(sr, 0)));
VERIFY_IS_EQUAL((const_matrix.template bottomRows<r>()), (const_matrix.template block<r, cols>(rows - r, 0)));
VERIFY_IS_EQUAL((const_matrix.template leftCols<c>()), (const_matrix.template block<rows, c>(0, 0)));
VERIFY_IS_EQUAL((const_matrix.template middleCols<c>(sc)), (const_matrix.template block<rows, c>(0, sc)));
VERIFY_IS_EQUAL((const_matrix.template rightCols<c>()), (const_matrix.template block<rows, c>(0, cols - c)));
}
EIGEN_DECLARE_TEST(corners) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(corners(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(corners(Matrix4d()));
CALL_SUBTEST_3(corners(Matrix<int, 10, 12>()));
CALL_SUBTEST_4(corners(MatrixXcf(5, 7)));
CALL_SUBTEST_5(corners(MatrixXf(21, 20)));
CALL_SUBTEST_1((corners_fixedsize<Matrix<float, 1, 1>, 1, 1, 0, 0>()));
CALL_SUBTEST_2((corners_fixedsize<Matrix4d, 2, 2, 1, 1>()));
CALL_SUBTEST_3((corners_fixedsize<Matrix<int, 10, 12>, 4, 7, 5, 2>()));
}
}
+79
View File
@@ -0,0 +1,79 @@
#include "main.h"
#include <exception> // std::exception
struct Foo {
static Index object_count;
static Index object_limit;
int dummy;
Foo() : dummy(0) {
#ifdef EIGEN_EXCEPTIONS
// TODO: Is this the correct way to handle this?
if (Foo::object_count > Foo::object_limit) {
std::cout << "\nThrow!\n";
throw Foo::Fail();
}
#endif
std::cout << '+';
++Foo::object_count;
}
~Foo() {
std::cout << '-';
--Foo::object_count;
}
class Fail : public std::exception {};
};
Index Foo::object_count = 0;
Index Foo::object_limit = 0;
#undef EIGEN_TEST_MAX_SIZE
#define EIGEN_TEST_MAX_SIZE 3
EIGEN_DECLARE_TEST(ctorleak) {
typedef Matrix<Foo, Dynamic, Dynamic> MatrixX;
typedef Matrix<Foo, Dynamic, 1> VectorX;
Foo::object_count = 0;
for (int i = 0; i < g_repeat; i++) {
Index rows = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE),
cols = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
Foo::object_limit = rows * cols;
{
MatrixX r(rows, cols);
Foo::object_limit = r.size() + internal::random<Index>(0, rows * cols - 2);
std::cout << "object_limit =" << Foo::object_limit << std::endl;
#ifdef EIGEN_EXCEPTIONS
try {
#endif
if (internal::random<bool>()) {
std::cout << "\nMatrixX m(" << rows << ", " << cols << ");\n";
MatrixX m(rows, cols);
} else {
std::cout << "\nMatrixX m(r);\n";
MatrixX m(r);
}
#ifdef EIGEN_EXCEPTIONS
VERIFY(false); // not reached if exceptions are enabled
} catch (const Foo::Fail&) { /* ignore */
}
#endif
}
VERIFY_IS_EQUAL(Index(0), Foo::object_count);
{
Foo::object_limit = (rows + 1) * (cols + 1);
MatrixX A(rows, cols);
VERIFY_IS_EQUAL(Foo::object_count, rows * cols);
VectorX v = A.row(0);
VERIFY_IS_EQUAL(Foo::object_count, (rows + 1) * cols);
v = A.col(0);
VERIFY_IS_EQUAL(Foo::object_count, rows * (cols + 1));
}
VERIFY_IS_EQUAL(Index(0), Foo::object_count);
}
std::cout << "\n";
}
+172
View File
@@ -0,0 +1,172 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <iostream>
#include <fstream>
#include <iomanip>
#include "main.h"
#include <Eigen/LevenbergMarquardt>
using namespace std;
using namespace Eigen;
template <typename Scalar>
struct DenseLM : DenseFunctor<Scalar> {
typedef DenseFunctor<Scalar> Base;
typedef typename Base::JacobianType JacobianType;
typedef Matrix<Scalar, Dynamic, 1> VectorType;
DenseLM(int n, int m) : DenseFunctor<Scalar>(n, m) {}
VectorType model(const VectorType& uv, VectorType& x) {
VectorType y; // Should change to use expression template
int m = Base::values();
int n = Base::inputs();
eigen_assert(uv.size() % 2 == 0);
eigen_assert(uv.size() == n);
eigen_assert(x.size() == m);
y.setZero(m);
int half = n / 2;
VectorBlock<const VectorType> u(uv, 0, half);
VectorBlock<const VectorType> v(uv, half, half);
for (int j = 0; j < m; j++) {
for (int i = 0; i < half; i++) y(j) += u(i) * std::exp(-(x(j) - i) * (x(j) - i) / (v(i) * v(i)));
}
return y;
}
void initPoints(VectorType& uv_ref, VectorType& x) {
m_x = x;
m_y = this->model(uv_ref, x);
}
int operator()(const VectorType& uv, VectorType& fvec) {
int m = Base::values();
int n = Base::inputs();
eigen_assert(uv.size() % 2 == 0);
eigen_assert(uv.size() == n);
eigen_assert(fvec.size() == m);
int half = n / 2;
VectorBlock<const VectorType> u(uv, 0, half);
VectorBlock<const VectorType> v(uv, half, half);
for (int j = 0; j < m; j++) {
fvec(j) = m_y(j);
for (int i = 0; i < half; i++) {
fvec(j) -= u(i) * std::exp(-(m_x(j) - i) * (m_x(j) - i) / (v(i) * v(i)));
}
}
return 0;
}
int df(const VectorType& uv, JacobianType& fjac) {
int m = Base::values();
int n = Base::inputs();
eigen_assert(n == uv.size());
eigen_assert(fjac.rows() == m);
eigen_assert(fjac.cols() == n);
int half = n / 2;
VectorBlock<const VectorType> u(uv, 0, half);
VectorBlock<const VectorType> v(uv, half, half);
for (int j = 0; j < m; j++) {
for (int i = 0; i < half; i++) {
fjac.coeffRef(j, i) = -std::exp(-(m_x(j) - i) * (m_x(j) - i) / (v(i) * v(i)));
fjac.coeffRef(j, i + half) = -2. * u(i) * (m_x(j) - i) * (m_x(j) - i) / (std::pow(v(i), 3)) *
std::exp(-(m_x(j) - i) * (m_x(j) - i) / (v(i) * v(i)));
}
}
return 0;
}
VectorType m_x, m_y; // Data Points
};
template <typename FunctorType, typename VectorType>
int test_minimizeLM(FunctorType& functor, VectorType& uv) {
LevenbergMarquardt<FunctorType> lm(functor);
LevenbergMarquardtSpace::Status info;
info = lm.minimize(uv);
VERIFY_IS_EQUAL(info, 1);
// FIXME Check other parameters
return info;
}
template <typename FunctorType, typename VectorType>
int test_lmder(FunctorType& functor, VectorType& uv) {
typedef typename VectorType::Scalar Scalar;
LevenbergMarquardtSpace::Status info;
LevenbergMarquardt<FunctorType> lm(functor);
info = lm.lmder1(uv);
VERIFY_IS_EQUAL(info, 1);
// FIXME Check other parameters
return info;
}
template <typename FunctorType, typename VectorType>
int test_minimizeSteps(FunctorType& functor, VectorType& uv) {
LevenbergMarquardtSpace::Status info;
LevenbergMarquardt<FunctorType> lm(functor);
info = lm.minimizeInit(uv);
if (info == LevenbergMarquardtSpace::ImproperInputParameters) return info;
do {
info = lm.minimizeOneStep(uv);
} while (info == LevenbergMarquardtSpace::Running);
VERIFY_IS_EQUAL(info, 1);
// FIXME Check other parameters
return info;
}
template <typename T>
void test_denseLM_T() {
typedef Matrix<T, Dynamic, 1> VectorType;
int inputs = 10;
int values = 1000;
DenseLM<T> dense_gaussian(inputs, values);
VectorType uv(inputs), uv_ref(inputs);
VectorType x(values);
// Generate the reference solution
uv_ref << -2, 1, 4, 8, 6, 1.8, 1.2, 1.1, 1.9, 3;
// Generate the reference data points
x.setRandom();
x = 10 * x;
x.array() += 10;
dense_gaussian.initPoints(uv_ref, x);
// Generate the initial parameters
VectorBlock<VectorType> u(uv, 0, inputs / 2);
VectorBlock<VectorType> v(uv, inputs / 2, inputs / 2);
// Solve the optimization problem
// Solve in one go
u.setOnes();
v.setOnes();
test_minimizeLM(dense_gaussian, uv);
// Solve until the machine precision
u.setOnes();
v.setOnes();
test_lmder(dense_gaussian, uv);
// Solve step by step
v.setOnes();
u.setOnes();
test_minimizeSteps(dense_gaussian, uv);
}
EIGEN_DECLARE_TEST(denseLM) {
CALL_SUBTEST_2(test_denseLM_T<double>());
// CALL_SUBTEST_2(test_sparseLM_T<std::complex<double>());
}
+285
View File
@@ -0,0 +1,285 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2013 Hauke Heibel <hauke.heibel@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define EIGEN_TESTING_PLAINOBJECT_CTOR
#include "main.h"
#include "AnnoyingScalar.h"
#include "MovableScalar.h"
#include "SafeScalar.h"
#include <Eigen/Core>
using DenseStorageD3x3 = Eigen::DenseStorage<double, 9, 3, 3, 0>;
#if !defined(EIGEN_DENSE_STORAGE_CTOR_PLUGIN)
static_assert(std::is_trivially_copy_constructible<DenseStorageD3x3>::value,
"DenseStorage not trivially_copy_constructible");
static_assert(std::is_trivially_move_constructible<DenseStorageD3x3>::value,
"DenseStorage not trivially_move_constructible");
static_assert(std::is_trivially_copy_assignable<DenseStorageD3x3>::value, "DenseStorage not trivially_copy_assignable");
static_assert(std::is_trivially_move_assignable<DenseStorageD3x3>::value, "DenseStorage not trivially_move_assignable");
#endif
// all plain object types conform to standard layout
static_assert(std::is_standard_layout<Matrix4f>::value, "Matrix4f not standard_layout");
static_assert(std::is_standard_layout<Array4f>::value, "Array4f not standard_layout");
static_assert(std::is_standard_layout<VectorXf>::value, "VectorXf not standard_layout");
static_assert(std::is_standard_layout<ArrayXf>::value, "ArrayXf not standard_layout");
static_assert(std::is_standard_layout<MatrixXf>::value, "MatrixXf not standard_layout");
static_assert(std::is_standard_layout<ArrayXXf>::value, "ArrayXXf not standard_layout");
// all fixed-size, fixed-dimension plain object types are trivially default constructible
static_assert(std::is_trivially_default_constructible<Matrix4f>::value, "Matrix4f not trivially_default_constructible");
static_assert(std::is_trivially_default_constructible<Array4f>::value, "Array4f not trivially_default_constructible");
// all fixed-size, fixed-dimension plain object types are trivially move constructible
static_assert(std::is_trivially_move_constructible<Matrix4f>::value, "Matrix4f not trivially_move_constructible");
static_assert(std::is_trivially_move_constructible<Array4f>::value, "Array4f not trivially_move_constructible");
// all statically-allocated plain object types are trivially destructible
static_assert(std::is_trivially_destructible<Matrix4f>::value, "Matrix4f not trivially_destructible");
static_assert(std::is_trivially_destructible<Array4f>::value, "Array4f not trivially_destructible");
static_assert(std::is_trivially_destructible<Matrix<float, 4, Dynamic, 0, 4, 4>>::value,
"Matrix4X44 not trivially_destructible");
static_assert(std::is_trivially_destructible<Array<float, 4, Dynamic, 0, 4, 4>>::value,
"Array4X44 not trivially_destructible");
#if !defined(EIGEN_DENSE_STORAGE_CTOR_PLUGIN)
// all fixed-size, fixed-dimension plain object types are trivially copy constructible
static_assert(std::is_trivially_copy_constructible<Matrix4f>::value, "Matrix4f not trivially_copy_constructible");
static_assert(std::is_trivially_copy_constructible<Array4f>::value, "Array4f not trivially_copy_constructible");
#endif
template <typename T, int Size, int Rows, int Cols>
void dense_storage_copy(int rows, int cols) {
typedef DenseStorage<T, Size, Rows, Cols, 0> DenseStorageType;
const int size = rows * cols;
DenseStorageType reference(size, rows, cols);
T* raw_reference = reference.data();
for (int i = 0; i < size; ++i) raw_reference[i] = internal::random<T>();
DenseStorageType copied_reference(reference);
const T* raw_copied_reference = copied_reference.data();
for (int i = 0; i < size; ++i) VERIFY_IS_EQUAL(raw_reference[i], raw_copied_reference[i]);
}
template <typename T, int Size, int Rows, int Cols>
void dense_storage_assignment(int rows, int cols) {
typedef DenseStorage<T, Size, Rows, Cols, 0> DenseStorageType;
const int size = rows * cols;
DenseStorageType reference(size, rows, cols);
T* raw_reference = reference.data();
for (int i = 0; i < size; ++i) raw_reference[i] = internal::random<T>();
DenseStorageType copied_reference;
copied_reference = reference;
const T* raw_copied_reference = copied_reference.data();
for (int i = 0; i < size; ++i) VERIFY_IS_EQUAL(raw_reference[i], raw_copied_reference[i]);
}
template <typename T, int Size, int Rows, int Cols>
void dense_storage_swap(int rowsa, int colsa, int rowsb, int colsb) {
typedef DenseStorage<T, Size, Rows, Cols, 0> DenseStorageType;
const int sizea = rowsa * colsa;
ArrayX<T> referencea(sizea);
referencea.setRandom();
DenseStorageType a(sizea, rowsa, colsa);
for (int i = 0; i < sizea; ++i) a.data()[i] = referencea(i);
const int sizeb = rowsb * colsb;
ArrayX<T> referenceb(sizeb);
referenceb.setRandom();
DenseStorageType b(sizeb, rowsb, colsb);
for (int i = 0; i < sizeb; ++i) b.data()[i] = referenceb(i);
a.swap(b);
for (int i = 0; i < sizea; i++) VERIFY_IS_EQUAL(b.data()[i], referencea(i));
for (int i = 0; i < sizeb; i++) VERIFY_IS_EQUAL(a.data()[i], referenceb(i));
}
template <typename T, int Size, std::size_t Alignment>
void dense_storage_alignment() {
struct alignas(Alignment) Empty1 {};
VERIFY_IS_EQUAL(std::alignment_of<Empty1>::value, Alignment);
struct EIGEN_ALIGN_TO_BOUNDARY(Alignment) Empty2 {};
VERIFY_IS_EQUAL(std::alignment_of<Empty2>::value, Alignment);
struct Nested1 {
EIGEN_ALIGN_TO_BOUNDARY(Alignment) T data[Size];
};
VERIFY_IS_EQUAL(std::alignment_of<Nested1>::value, 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;
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>
void dense_storage_tests() {
// Dynamic Storage.
dense_storage_copy<T, Dynamic, Dynamic, Dynamic>(4, 3);
dense_storage_copy<T, Dynamic, Dynamic, 3>(4, 3);
dense_storage_copy<T, Dynamic, 4, Dynamic>(4, 3);
// Fixed Storage.
dense_storage_copy<T, 12, 4, 3>(4, 3);
dense_storage_copy<T, 12, Dynamic, Dynamic>(4, 3);
dense_storage_copy<T, 12, 4, Dynamic>(4, 3);
dense_storage_copy<T, 12, Dynamic, 3>(4, 3);
// Fixed Storage with Uninitialized Elements.
dense_storage_copy<T, 18, Dynamic, Dynamic>(4, 3);
dense_storage_copy<T, 18, 4, Dynamic>(4, 3);
dense_storage_copy<T, 18, Dynamic, 3>(4, 3);
// Dynamic Storage.
dense_storage_assignment<T, Dynamic, Dynamic, Dynamic>(4, 3);
dense_storage_assignment<T, Dynamic, Dynamic, 3>(4, 3);
dense_storage_assignment<T, Dynamic, 4, Dynamic>(4, 3);
// Fixed Storage.
dense_storage_assignment<T, 12, 4, 3>(4, 3);
dense_storage_assignment<T, 12, Dynamic, Dynamic>(4, 3);
dense_storage_assignment<T, 12, 4, Dynamic>(4, 3);
dense_storage_assignment<T, 12, Dynamic, 3>(4, 3);
// Fixed Storage with Uninitialized Elements.
dense_storage_assignment<T, 18, Dynamic, Dynamic>(4, 3);
dense_storage_assignment<T, 18, 4, Dynamic>(4, 3);
dense_storage_assignment<T, 18, Dynamic, 3>(4, 3);
// Dynamic Storage.
dense_storage_swap<T, Dynamic, Dynamic, Dynamic>(4, 3, 4, 3);
dense_storage_swap<T, Dynamic, Dynamic, Dynamic>(4, 3, 2, 1);
dense_storage_swap<T, Dynamic, Dynamic, Dynamic>(2, 1, 4, 3);
dense_storage_swap<T, Dynamic, Dynamic, 3>(4, 3, 4, 3);
dense_storage_swap<T, Dynamic, Dynamic, 3>(4, 3, 2, 3);
dense_storage_swap<T, Dynamic, Dynamic, 3>(2, 3, 4, 3);
dense_storage_swap<T, Dynamic, 4, Dynamic>(4, 3, 4, 3);
dense_storage_swap<T, Dynamic, 4, Dynamic>(4, 3, 4, 1);
dense_storage_swap<T, Dynamic, 4, Dynamic>(4, 1, 4, 3);
// Fixed Storage.
dense_storage_swap<T, 12, 4, 3>(4, 3, 4, 3);
dense_storage_swap<T, 12, Dynamic, Dynamic>(4, 3, 4, 3);
dense_storage_swap<T, 12, Dynamic, Dynamic>(4, 3, 2, 1);
dense_storage_swap<T, 12, Dynamic, Dynamic>(2, 1, 4, 3);
dense_storage_swap<T, 12, 4, Dynamic>(4, 3, 4, 3);
dense_storage_swap<T, 12, 4, Dynamic>(4, 3, 4, 1);
dense_storage_swap<T, 12, 4, Dynamic>(4, 1, 4, 3);
dense_storage_swap<T, 12, Dynamic, 3>(4, 3, 4, 3);
dense_storage_swap<T, 12, Dynamic, 3>(4, 3, 2, 3);
dense_storage_swap<T, 12, Dynamic, 3>(2, 3, 4, 3);
// Fixed Storage with Uninitialized Elements.
dense_storage_swap<T, 18, Dynamic, Dynamic>(4, 3, 4, 3);
dense_storage_swap<T, 18, Dynamic, Dynamic>(4, 3, 2, 1);
dense_storage_swap<T, 18, Dynamic, Dynamic>(2, 1, 4, 3);
dense_storage_swap<T, 18, 4, Dynamic>(4, 3, 4, 3);
dense_storage_swap<T, 18, 4, Dynamic>(4, 3, 4, 1);
dense_storage_swap<T, 18, 4, Dynamic>(4, 1, 4, 3);
dense_storage_swap<T, 18, Dynamic, 3>(4, 3, 4, 3);
dense_storage_swap<T, 18, Dynamic, 3>(4, 3, 2, 3);
dense_storage_swap<T, 18, Dynamic, 3>(2, 3, 4, 3);
dense_storage_alignment<T, 16, 8>();
dense_storage_alignment<T, 16, 16>();
dense_storage_alignment<T, 16, 32>();
dense_storage_alignment<T, 16, 64>();
}
template <typename PlainType>
void plaintype_tests() {
constexpr int RowsAtCompileTime = PlainType::RowsAtCompileTime;
constexpr int ColsAtCompileTime = PlainType::ColsAtCompileTime;
constexpr int MaxRowsAtCompileTime = PlainType::MaxRowsAtCompileTime;
constexpr int MaxColsAtCompileTime = PlainType::MaxColsAtCompileTime;
const Index expectedDefaultRows = RowsAtCompileTime == Dynamic ? 0 : RowsAtCompileTime;
const Index expectedDefaultCols = ColsAtCompileTime == Dynamic ? 0 : ColsAtCompileTime;
const Index minRows = RowsAtCompileTime == Dynamic ? 0 : RowsAtCompileTime;
const Index minCols = ColsAtCompileTime == Dynamic ? 0 : ColsAtCompileTime;
const Index maxRows = MaxRowsAtCompileTime == Dynamic ? 100 : MaxRowsAtCompileTime;
const Index maxCols = MaxColsAtCompileTime == Dynamic ? 100 : MaxColsAtCompileTime;
const Index rows = internal::random<Index>(minRows, maxRows);
const Index cols = internal::random<Index>(minCols, maxCols);
// default construction
PlainType m0;
VERIFY_IS_EQUAL(m0.rows(), expectedDefaultRows);
VERIFY_IS_EQUAL(m0.cols(), expectedDefaultCols);
m0.resize(rows, cols);
m0.setRandom();
// copy construction
PlainType m1(m0);
VERIFY_IS_EQUAL(m1.rows(), m0.rows());
VERIFY_IS_EQUAL(m1.cols(), m0.cols());
VERIFY_IS_CWISE_EQUAL(m1, m0);
// move construction
PlainType m2(std::move(m1));
VERIFY_IS_EQUAL(m2.rows(), m0.rows());
VERIFY_IS_EQUAL(m2.cols(), m0.cols());
VERIFY_IS_CWISE_EQUAL(m2, m0);
// check that object is usable after move construction
m1.resize(minRows, minCols);
m1.setRandom();
// copy assignment
m1 = m0;
VERIFY_IS_EQUAL(m1.rows(), m0.rows());
VERIFY_IS_EQUAL(m1.cols(), m0.cols());
VERIFY_IS_CWISE_EQUAL(m1, m0);
// move assignment
m2.resize(minRows, minCols);
m2.setRandom();
m2 = std::move(m1);
VERIFY_IS_EQUAL(m2.rows(), m0.rows());
VERIFY_IS_EQUAL(m2.cols(), m0.cols());
VERIFY_IS_CWISE_EQUAL(m2, m0);
// check that object is usable after move assignment
m1.resize(minRows, minCols);
m1.setRandom();
m1 = m2;
VERIFY_IS_EQUAL(m1.rows(), m0.rows());
VERIFY_IS_EQUAL(m1.cols(), m0.cols());
VERIFY_IS_CWISE_EQUAL(m1, m0);
}
EIGEN_DECLARE_TEST(dense_storage) {
dense_storage_tests<int>();
dense_storage_tests<float>();
dense_storage_tests<SafeScalar<float>>();
dense_storage_tests<MovableScalar<float>>();
dense_storage_tests<AnnoyingScalar>();
for (int i = 0; i < g_repeat; i++) {
plaintype_tests<Matrix<float, 0, 0, ColMajor>>();
plaintype_tests<Matrix<float, Dynamic, Dynamic, ColMajor, 0, 0>>();
plaintype_tests<Matrix<float, 16, 16, ColMajor>>();
plaintype_tests<Matrix<float, 16, Dynamic, ColMajor>>();
plaintype_tests<Matrix<float, Dynamic, Dynamic, ColMajor>>();
plaintype_tests<Matrix<float, Dynamic, Dynamic, ColMajor, 16, 16>>();
plaintype_tests<Matrix<SafeScalar<float>, 16, 16, ColMajor>>();
plaintype_tests<Matrix<SafeScalar<float>, 16, Dynamic, ColMajor>>();
plaintype_tests<Matrix<SafeScalar<float>, Dynamic, Dynamic, ColMajor>>();
plaintype_tests<Matrix<SafeScalar<float>, Dynamic, Dynamic, ColMajor, 16, 16>>();
plaintype_tests<Matrix<MovableScalar<float>, 16, 16, ColMajor>>();
plaintype_tests<Matrix<MovableScalar<float>, 16, Dynamic, ColMajor>>();
plaintype_tests<Matrix<MovableScalar<float>, Dynamic, Dynamic, ColMajor>>();
plaintype_tests<Matrix<MovableScalar<float>, Dynamic, Dynamic, ColMajor, 16, 16>>();
plaintype_tests<Matrix<AnnoyingScalar, 16, 16, ColMajor>>();
plaintype_tests<Matrix<AnnoyingScalar, 16, Dynamic, ColMajor>>();
plaintype_tests<Matrix<AnnoyingScalar, Dynamic, Dynamic, ColMajor>>();
plaintype_tests<Matrix<AnnoyingScalar, Dynamic, Dynamic, ColMajor, 16, 16>>();
}
}
#undef EIGEN_TESTING_PLAINOBJECT_CTOR
+65
View File
@@ -0,0 +1,65 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/LU>
template <typename MatrixType>
void determinant(const MatrixType& m) {
/* this test covers the following files:
Determinant.h
*/
Index size = m.rows();
MatrixType m1(size, size), m2(size, size);
m1.setRandom();
m2.setRandom();
typedef typename MatrixType::Scalar Scalar;
Scalar x = internal::random<Scalar>();
VERIFY_IS_APPROX(MatrixType::Identity(size, size).determinant(), Scalar(1));
VERIFY_IS_APPROX((m1 * m2).eval().determinant(), m1.determinant() * m2.determinant());
if (size == 1) return;
Index i = internal::random<Index>(0, size - 1);
Index j;
do {
j = internal::random<Index>(0, size - 1);
} while (j == i);
m2 = m1;
m2.row(i).swap(m2.row(j));
VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
m2 = m1;
m2.col(i).swap(m2.col(j));
VERIFY_IS_APPROX(m2.determinant(), -m1.determinant());
VERIFY_IS_APPROX(m2.determinant(), m2.transpose().determinant());
VERIFY_IS_APPROX(numext::conj(m2.determinant()), m2.adjoint().determinant());
m2 = m1;
m2.row(i) += x * m2.row(j);
VERIFY_IS_APPROX(m2.determinant(), m1.determinant());
m2 = m1;
m2.row(i) *= x;
VERIFY_IS_APPROX(m2.determinant(), m1.determinant() * x);
// check empty matrix
VERIFY_IS_APPROX(m2.block(0, 0, 0, 0).determinant(), Scalar(1));
}
EIGEN_DECLARE_TEST(determinant) {
for (int i = 0; i < g_repeat; i++) {
int s = 0;
CALL_SUBTEST_1(determinant(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(determinant(Matrix<double, 2, 2>()));
CALL_SUBTEST_3(determinant(Matrix<double, 3, 3>()));
CALL_SUBTEST_4(determinant(Matrix<double, 4, 4>()));
CALL_SUBTEST_5(determinant(Matrix<std::complex<double>, 10, 10>()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_6(determinant(MatrixXd(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
}
+102
View File
@@ -0,0 +1,102 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType>
void diagonal(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols);
Scalar s1 = internal::random<Scalar>();
// check diagonal()
VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal());
m2.diagonal() = 2 * m1.diagonal();
m2.diagonal()[0] *= 3;
if (rows > 2) {
enum { N1 = MatrixType::RowsAtCompileTime > 2 ? 2 : 0, N2 = MatrixType::RowsAtCompileTime > 1 ? -1 : 0 };
// check sub/super diagonal
if (MatrixType::SizeAtCompileTime != Dynamic) {
VERIFY(m1.template diagonal<N1>().RowsAtCompileTime == m1.diagonal(N1).size());
VERIFY(m1.template diagonal<N2>().RowsAtCompileTime == m1.diagonal(N2).size());
}
m2.template diagonal<N1>() = 2 * m1.template diagonal<N1>();
VERIFY_IS_APPROX(m2.template diagonal<N1>(), static_cast<Scalar>(2) * m1.diagonal(N1));
m2.template diagonal<N1>()[0] *= 3;
VERIFY_IS_APPROX(m2.template diagonal<N1>()[0], static_cast<Scalar>(6) * m1.template diagonal<N1>()[0]);
m2.template diagonal<N2>() = 2 * m1.template diagonal<N2>();
m2.template diagonal<N2>()[0] *= 3;
VERIFY_IS_APPROX(m2.template diagonal<N2>()[0], static_cast<Scalar>(6) * m1.template diagonal<N2>()[0]);
m2.diagonal(N1) = 2 * m1.diagonal(N1);
VERIFY_IS_APPROX(m2.template diagonal<N1>(), static_cast<Scalar>(2) * m1.diagonal(N1));
m2.diagonal(N1)[0] *= 3;
VERIFY_IS_APPROX(m2.diagonal(N1)[0], static_cast<Scalar>(6) * m1.diagonal(N1)[0]);
m2.diagonal(N2) = 2 * m1.diagonal(N2);
VERIFY_IS_APPROX(m2.template diagonal<N2>(), static_cast<Scalar>(2) * m1.diagonal(N2));
m2.diagonal(N2)[0] *= 3;
VERIFY_IS_APPROX(m2.diagonal(N2)[0], static_cast<Scalar>(6) * m1.diagonal(N2)[0]);
m2.diagonal(N2).x() = s1;
VERIFY_IS_APPROX(m2.diagonal(N2).x(), s1);
m2.diagonal(N2).coeffRef(0) = Scalar(2) * s1;
VERIFY_IS_APPROX(m2.diagonal(N2).coeff(0), Scalar(2) * s1);
}
VERIFY(m1.diagonal(cols).size() == 0);
VERIFY(m1.diagonal(-rows).size() == 0);
}
template <typename MatrixType>
void diagonal_assert(const MatrixType& m) {
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols);
if (rows >= 2 && cols >= 2) {
VERIFY_RAISES_ASSERT(m1 += m1.diagonal());
VERIFY_RAISES_ASSERT(m1 -= m1.diagonal());
VERIFY_RAISES_ASSERT(m1.array() *= m1.diagonal().array());
VERIFY_RAISES_ASSERT(m1.array() /= m1.diagonal().array());
}
VERIFY_RAISES_ASSERT(m1.diagonal(cols + 1));
VERIFY_RAISES_ASSERT(m1.diagonal(-(rows + 1)));
}
EIGEN_DECLARE_TEST(diagonal) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(diagonal(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(diagonal(Matrix<float, 4, 9>()));
CALL_SUBTEST_1(diagonal(Matrix<float, 7, 3>()));
CALL_SUBTEST_2(diagonal(Matrix4d()));
CALL_SUBTEST_2(diagonal(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_2(diagonal(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_2(diagonal(
MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_1(diagonal(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_1(diagonal(Matrix<float, Dynamic, 4>(3, 4)));
CALL_SUBTEST_1(diagonal_assert(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
}
+150
View File
@@ -0,0 +1,150 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2019 David Tellenbach <david.tellenbach@tellnotes.org>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#define VERIFY_IMPLICIT_CONVERSION_3(DIAGTYPE, V0, V1, V2) \
DIAGTYPE d(V0, V1, V2); \
DIAGTYPE::DenseMatrixType Dense = d.toDenseMatrix(); \
VERIFY_IS_APPROX(Dense(0, 0), (Scalar)V0); \
VERIFY_IS_APPROX(Dense(1, 1), (Scalar)V1); \
VERIFY_IS_APPROX(Dense(2, 2), (Scalar)V2);
#define VERIFY_IMPLICIT_CONVERSION_4(DIAGTYPE, V0, V1, V2, V3) \
DIAGTYPE d(V0, V1, V2, V3); \
DIAGTYPE::DenseMatrixType Dense = d.toDenseMatrix(); \
VERIFY_IS_APPROX(Dense(0, 0), (Scalar)V0); \
VERIFY_IS_APPROX(Dense(1, 1), (Scalar)V1); \
VERIFY_IS_APPROX(Dense(2, 2), (Scalar)V2); \
VERIFY_IS_APPROX(Dense(3, 3), (Scalar)V3);
#define VERIFY_IMPLICIT_CONVERSION_5(DIAGTYPE, V0, V1, V2, V3, V4) \
DIAGTYPE d(V0, V1, V2, V3, V4); \
DIAGTYPE::DenseMatrixType Dense = d.toDenseMatrix(); \
VERIFY_IS_APPROX(Dense(0, 0), (Scalar)V0); \
VERIFY_IS_APPROX(Dense(1, 1), (Scalar)V1); \
VERIFY_IS_APPROX(Dense(2, 2), (Scalar)V2); \
VERIFY_IS_APPROX(Dense(3, 3), (Scalar)V3); \
VERIFY_IS_APPROX(Dense(4, 4), (Scalar)V4);
template <typename Scalar>
void constructorTest() {
typedef DiagonalMatrix<Scalar, 0> DiagonalMatrix0;
typedef DiagonalMatrix<Scalar, 3> DiagonalMatrix3;
typedef DiagonalMatrix<Scalar, 4> DiagonalMatrix4;
typedef DiagonalMatrix<Scalar, Dynamic> DiagonalMatrixX;
Scalar raw[7];
for (int k = 0; k < 7; ++k) raw[k] = internal::random<Scalar>();
// Fixed-sized matrices
{
DiagonalMatrix0 a{{}};
VERIFY(a.rows() == 0);
VERIFY(a.cols() == 0);
typename DiagonalMatrix0::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{
DiagonalMatrix3 a{{raw[0], raw[1], raw[2]}};
VERIFY(a.rows() == 3);
VERIFY(a.cols() == 3);
typename DiagonalMatrix3::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{
DiagonalMatrix4 a{{raw[0], raw[1], raw[2], raw[3]}};
VERIFY(a.rows() == 4);
VERIFY(a.cols() == 4);
typename DiagonalMatrix4::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
// dynamically sized matrices
{
DiagonalMatrixX a{{}};
VERIFY(a.rows() == 0);
VERIFY(a.rows() == 0);
typename DiagonalMatrixX::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{
DiagonalMatrixX a{{raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6]}};
VERIFY(a.rows() == 7);
VERIFY(a.rows() == 7);
typename DiagonalMatrixX::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
}
template <>
void constructorTest<float>() {
typedef float Scalar;
typedef DiagonalMatrix<Scalar, 0> DiagonalMatrix0;
typedef DiagonalMatrix<Scalar, 3> DiagonalMatrix3;
typedef DiagonalMatrix<Scalar, 4> DiagonalMatrix4;
typedef DiagonalMatrix<Scalar, 5> DiagonalMatrix5;
typedef DiagonalMatrix<Scalar, Dynamic> DiagonalMatrixX;
Scalar raw[7];
for (int k = 0; k < 7; ++k) raw[k] = internal::random<Scalar>();
// Fixed-sized matrices
{
DiagonalMatrix0 a{{}};
VERIFY(a.rows() == 0);
VERIFY(a.cols() == 0);
typename DiagonalMatrix0::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{
DiagonalMatrix3 a{{raw[0], raw[1], raw[2]}};
VERIFY(a.rows() == 3);
VERIFY(a.cols() == 3);
typename DiagonalMatrix3::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{
DiagonalMatrix4 a{{raw[0], raw[1], raw[2], raw[3]}};
VERIFY(a.rows() == 4);
VERIFY(a.cols() == 4);
typename DiagonalMatrix4::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
// dynamically sized matrices
{
DiagonalMatrixX a{{}};
VERIFY(a.rows() == 0);
VERIFY(a.rows() == 0);
typename DiagonalMatrixX::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{
DiagonalMatrixX a{{raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6]}};
VERIFY(a.rows() == 7);
VERIFY(a.rows() == 7);
typename DiagonalMatrixX::DenseMatrixType m = a.toDenseMatrix();
for (Index k = 0; k < a.rows(); ++k) VERIFY(m(k, k) == raw[k]);
}
{ VERIFY_IMPLICIT_CONVERSION_3(DiagonalMatrix3, 1.2647, 2.56f, -3); }
{ VERIFY_IMPLICIT_CONVERSION_4(DiagonalMatrix4, 1.2647, 2.56f, -3, 3.23f); }
{ VERIFY_IMPLICIT_CONVERSION_5(DiagonalMatrix5, 1.2647, 2.56f, -3, 3.23f, 2); }
}
EIGEN_DECLARE_TEST(diagonal_matrix_variadic_ctor) {
CALL_SUBTEST_2(constructorTest<unsigned char>());
CALL_SUBTEST_2(constructorTest<float>());
CALL_SUBTEST_2(constructorTest<Index>());
CALL_SUBTEST_2(constructorTest<int>());
CALL_SUBTEST_2(constructorTest<long int>());
CALL_SUBTEST_2(constructorTest<std::ptrdiff_t>());
CALL_SUBTEST_2(constructorTest<std::complex<double>>());
}
+197
View File
@@ -0,0 +1,197 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// 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) {
typedef typename MatrixType::Scalar Scalar;
enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
typedef Matrix<Scalar, Rows, 1> VectorType;
typedef Matrix<Scalar, 1, Cols> RowVectorType;
typedef Matrix<Scalar, Rows, Rows> SquareMatrixType;
typedef Matrix<Scalar, Dynamic, Dynamic> DynMatrixType;
typedef DiagonalMatrix<Scalar, Rows> LeftDiagonalMatrix;
typedef DiagonalMatrix<Scalar, Cols> RightDiagonalMatrix;
typedef Matrix<Scalar, Rows == Dynamic ? Dynamic : 2 * Rows, Cols == Dynamic ? Dynamic : 2 * Cols> BigMatrix;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols);
VectorType v1 = VectorType::Random(rows), v2 = VectorType::Random(rows);
RowVectorType rv1 = RowVectorType::Random(cols), rv2 = RowVectorType::Random(cols);
LeftDiagonalMatrix ldm1(v1), ldm2(v2);
RightDiagonalMatrix rdm1(rv1), rdm2(rv2);
Scalar s1 = internal::random<Scalar>();
SquareMatrixType sq_m1(v1.asDiagonal());
VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
sq_m1 = v1.asDiagonal();
VERIFY_IS_APPROX(sq_m1, v1.asDiagonal().toDenseMatrix());
SquareMatrixType sq_m2 = v1.asDiagonal();
VERIFY_IS_APPROX(sq_m1, sq_m2);
ldm1 = v1.asDiagonal();
LeftDiagonalMatrix ldm3(v1);
VERIFY_IS_APPROX(ldm1.diagonal(), ldm3.diagonal());
LeftDiagonalMatrix ldm4 = v1.asDiagonal();
VERIFY_IS_APPROX(ldm1.diagonal(), ldm4.diagonal());
sq_m1.block(0, 0, rows, rows) = ldm1;
VERIFY_IS_APPROX(sq_m1, ldm1.toDenseMatrix());
sq_m1.transpose() = ldm1;
VERIFY_IS_APPROX(sq_m1, ldm1.toDenseMatrix());
Index i = internal::random<Index>(0, rows - 1);
Index j = internal::random<Index>(0, cols - 1);
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));
VERIFY_IS_APPROX(((v1.asDiagonal() * m1)(i, j)), v1(i) * m1(i, j));
VERIFY_IS_APPROX(((m1 * rv1.asDiagonal())(i, j)), rv1(j) * m1(i, j));
VERIFY_IS_APPROX((((v1 + v2).asDiagonal() * m1)(i, j)), (v1 + v2)(i)*m1(i, j));
VERIFY_IS_APPROX((((v1 + v2).asDiagonal() * (m1 + m2))(i, j)), (v1 + v2)(i) * (m1 + m2)(i, j));
VERIFY_IS_APPROX(((m1 * (rv1 + rv2).asDiagonal())(i, j)), (rv1 + rv2)(j)*m1(i, j));
VERIFY_IS_APPROX((((m1 + m2) * (rv1 + rv2).asDiagonal())(i, j)), (rv1 + rv2)(j) * (m1 + m2)(i, j));
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) {
DynMatrixType tmp = m1.topRows(rows / 2), res;
VERIFY_IS_APPROX((res = m1.topRows(rows / 2) * rv1.asDiagonal()), tmp * rv1.asDiagonal());
VERIFY_IS_APPROX((res = v1.head(rows / 2).asDiagonal() * m1.topRows(rows / 2)),
v1.head(rows / 2).asDiagonal() * tmp);
}
BigMatrix big;
big.setZero(2 * rows, 2 * cols);
big.block(i, j, rows, cols) = m1;
big.block(i, j, rows, cols) = v1.asDiagonal() * big.block(i, j, rows, cols);
VERIFY_IS_APPROX((big.block(i, j, rows, cols)), v1.asDiagonal() * m1);
big.block(i, j, rows, cols) = m1;
big.block(i, j, rows, cols) = big.block(i, j, rows, cols) * rv1.asDiagonal();
VERIFY_IS_APPROX((big.block(i, j, rows, cols)), m1 * rv1.asDiagonal());
// 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);
VERIFY_IS_APPROX(LeftDiagonalMatrix(s1 * ldm1).diagonal(), s1 * ldm1.diagonal());
VERIFY_IS_APPROX(m1 * (rdm1 * s1), (m1 * rdm1) * s1);
VERIFY_IS_APPROX(m1 * (s1 * rdm1), (m1 * rdm1) * s1);
// Diagonal to dense
sq_m1.setRandom();
sq_m2 = sq_m1;
VERIFY_IS_APPROX((sq_m1 += (s1 * v1).asDiagonal()), sq_m2 += (s1 * v1).asDiagonal().toDenseMatrix());
VERIFY_IS_APPROX((sq_m1 -= (s1 * v1).asDiagonal()), sq_m2 -= (s1 * v1).asDiagonal().toDenseMatrix());
VERIFY_IS_APPROX((sq_m1 = (s1 * v1).asDiagonal()), (s1 * v1).asDiagonal().toDenseMatrix());
sq_m1.setRandom();
sq_m2 = v1.asDiagonal();
sq_m2 = sq_m1 * sq_m2;
VERIFY_IS_APPROX((sq_m1 * v1.asDiagonal()).col(i), sq_m2.col(i));
VERIFY_IS_APPROX((sq_m1 * v1.asDiagonal()).row(i), sq_m2.row(i));
sq_m1 = v1.asDiagonal();
sq_m2 = v2.asDiagonal();
SquareMatrixType sq_m3 = v1.asDiagonal();
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) {
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, Dynamic, Dynamic> DynMatrixType;
typedef Matrix<Scalar, Dynamic, 1> DynVectorType;
typedef Matrix<Scalar, 1, Dynamic> DynRowVectorType;
Index rows = m.rows();
Index depth = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
VectorType v1 = VectorType::Random(rows);
DynVectorType dv1 = DynVectorType::Random(depth);
DynRowVectorType drv1 = DynRowVectorType::Random(depth);
DynMatrixType dm1 = dv1;
DynMatrixType drm1 = drv1;
Scalar s = v1(0);
VERIFY_IS_APPROX(v1.asDiagonal() * drv1, s * drv1);
VERIFY_IS_APPROX(dv1 * v1.asDiagonal(), dv1 * s);
VERIFY_IS_APPROX(v1.asDiagonal() * drm1, s * drm1);
VERIFY_IS_APPROX(dm1 * v1.asDiagonal(), dm1 * s);
}
template <int>
void bug987() {
Matrix3Xd points = Matrix3Xd::Random(3, 3);
Vector2d diag = Vector2d::Random();
Matrix2Xd tmp1 = points.topRows<2>(), res1, res2;
VERIFY_IS_APPROX(res1 = diag.asDiagonal() * points.topRows<2>(), res2 = diag.asDiagonal() * tmp1);
Matrix2d tmp2 = points.topLeftCorner<2, 2>();
VERIFY_IS_APPROX((res1 = points.topLeftCorner<2, 2>() * diag.asDiagonal()), res2 = tmp2 * diag.asDiagonal());
}
EIGEN_DECLARE_TEST(diagonalmatrices) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(diagonalmatrices(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(as_scalar_product(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(diagonalmatrices(Matrix3f()));
CALL_SUBTEST_3(diagonalmatrices(Matrix<double, 3, 3, RowMajor>()));
CALL_SUBTEST_4(diagonalmatrices(Matrix4d()));
CALL_SUBTEST_5(diagonalmatrices(Matrix<float, 4, 4, RowMajor>()));
CALL_SUBTEST_6(diagonalmatrices(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(as_scalar_product(MatrixXcf(1, 1)));
CALL_SUBTEST_7(diagonalmatrices(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_8(diagonalmatrices(Matrix<double, Dynamic, Dynamic, RowMajor>(
internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_9(diagonalmatrices(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_9(diagonalmatrices(MatrixXf(1, 1)));
CALL_SUBTEST_9(as_scalar_product(MatrixXf(1, 1)));
}
CALL_SUBTEST_10(bug987<0>());
}
+60
View File
@@ -0,0 +1,60 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#if defined EIGEN_TEST_PART_1 || defined EIGEN_TEST_PART_2 || defined EIGEN_TEST_PART_3 || defined EIGEN_TEST_PART_4
#define EIGEN_DONT_ALIGN
#elif defined EIGEN_TEST_PART_5 || defined EIGEN_TEST_PART_6 || defined EIGEN_TEST_PART_7 || defined EIGEN_TEST_PART_8
#define EIGEN_DONT_ALIGN_STATICALLY
#endif
#include "main.h"
#include <Eigen/Dense>
template <typename MatrixType>
void dontalign(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
Index rows = m.rows();
Index cols = m.cols();
MatrixType a = MatrixType::Random(rows, cols);
SquareMatrixType square = SquareMatrixType::Random(rows, rows);
VectorType v = VectorType::Random(rows);
VERIFY_IS_APPROX(v, square * square.colPivHouseholderQr().solve(v));
square = square.inverse().eval();
a = square * a;
square = square * square;
v = square * v;
v = a.adjoint() * v;
VERIFY(square.determinant() != Scalar(0));
// bug 219: MapAligned() was giving an assert with EIGEN_DONT_ALIGN, because Map Flags were miscomputed
Scalar* array = internal::aligned_new<Scalar>(rows);
v = VectorType::MapAligned(array, rows);
internal::aligned_delete(array, rows);
}
EIGEN_DECLARE_TEST(dontalign) {
#if defined EIGEN_TEST_PART_1 || defined EIGEN_TEST_PART_5
dontalign(Matrix3d());
dontalign(Matrix4f());
#elif defined EIGEN_TEST_PART_2 || defined EIGEN_TEST_PART_6
dontalign(Matrix3cd());
dontalign(Matrix4cf());
#elif defined EIGEN_TEST_PART_3 || defined EIGEN_TEST_PART_7
dontalign(Matrix<float, 32, 32>());
dontalign(Matrix<std::complex<float>, 32, 32>());
#elif defined EIGEN_TEST_PART_4 || defined EIGEN_TEST_PART_8
dontalign(MatrixXd(32, 32));
dontalign(MatrixXcf(32, 32));
#endif
}
+168
View File
@@ -0,0 +1,168 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#if EIGEN_MAX_ALIGN_BYTES > 0
#define ALIGNMENT EIGEN_MAX_ALIGN_BYTES
#else
#define ALIGNMENT 1
#endif
typedef Matrix<float, 16, 1> Vector16f;
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, alignment);
VERIFY(std::uintptr_t(p) % ALIGNMENT == 0);
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
for (int j = 0; j < i; j++) p[j] = 0;
internal::handmade_aligned_free(p);
}
}
void check_aligned_malloc() {
for (int i = ALIGNMENT; i < 1000; i++) {
char *p = (char *)internal::aligned_malloc(i);
VERIFY(std::uintptr_t(p) % ALIGNMENT == 0);
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
for (int j = 0; j < i; j++) p[j] = 0;
internal::aligned_free(p);
}
}
void check_aligned_new() {
for (int i = ALIGNMENT; i < 1000; i++) {
float *p = internal::aligned_new<float>(i);
VERIFY(std::uintptr_t(p) % ALIGNMENT == 0);
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
for (int j = 0; j < i; j++) p[j] = 0;
internal::aligned_delete(p, i);
}
}
void check_aligned_stack_alloc() {
for (int i = ALIGNMENT; i < 400; i++) {
ei_declare_aligned_stack_constructed_variable(float, p, i, 0);
VERIFY(std::uintptr_t(p) % ALIGNMENT == 0);
// if the buffer is wrongly allocated this will give a bad write --> check with valgrind
for (int j = 0; j < i; j++) p[j] = 0;
}
}
// test compilation with both a struct and a class...
struct MyStruct {
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
char dummychar;
Vector16f avec;
};
class MyClassA {
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
char dummychar;
Vector16f avec;
};
template <typename T>
void check_dynaligned() {
// TODO have to be updated once we support multiple alignment values
if (T::SizeAtCompileTime % ALIGNMENT == 0) {
T *obj = new T;
VERIFY(T::NeedsToAlign == 1);
VERIFY(std::uintptr_t(obj) % ALIGNMENT == 0);
delete obj;
}
}
template <typename T>
void check_custom_new_delete() {
{
T *t = new T;
delete t;
}
{
std::size_t N = internal::random<std::size_t>(1, 10);
T *t = new T[N];
delete[] t;
}
#if EIGEN_MAX_ALIGN_BYTES > 0 && (!EIGEN_HAS_CXX17_OVERALIGN)
{
T *t = static_cast<T *>((T::operator new)(sizeof(T)));
(T::operator delete)(t, sizeof(T));
}
{
T *t = static_cast<T *>((T::operator new)(sizeof(T)));
(T::operator delete)(t);
}
#endif
}
EIGEN_DECLARE_TEST(dynalloc) {
// low level dynamic memory allocation
CALL_SUBTEST(check_handmade_aligned_malloc());
CALL_SUBTEST(check_aligned_malloc());
CALL_SUBTEST(check_aligned_new());
CALL_SUBTEST(check_aligned_stack_alloc());
for (int i = 0; i < g_repeat * 100; ++i) {
CALL_SUBTEST(check_custom_new_delete<Vector4f>());
CALL_SUBTEST(check_custom_new_delete<Vector2f>());
CALL_SUBTEST(check_custom_new_delete<Matrix4f>());
CALL_SUBTEST(check_custom_new_delete<MatrixXi>());
}
// check static allocation, who knows ?
#if EIGEN_MAX_STATIC_ALIGN_BYTES
for (int i = 0; i < g_repeat * 100; ++i) {
CALL_SUBTEST(check_dynaligned<Vector4f>());
CALL_SUBTEST(check_dynaligned<Vector2d>());
CALL_SUBTEST(check_dynaligned<Matrix4f>());
CALL_SUBTEST(check_dynaligned<Vector4d>());
CALL_SUBTEST(check_dynaligned<Vector4i>());
CALL_SUBTEST(check_dynaligned<Vector8f>());
CALL_SUBTEST(check_dynaligned<Vector16f>());
}
{
MyStruct foo0;
VERIFY(std::uintptr_t(foo0.avec.data()) % ALIGNMENT == 0);
MyClassA fooA;
VERIFY(std::uintptr_t(fooA.avec.data()) % ALIGNMENT == 0);
}
// dynamic allocation, single object
for (int i = 0; i < g_repeat * 100; ++i) {
MyStruct *foo0 = new MyStruct();
VERIFY(std::uintptr_t(foo0->avec.data()) % ALIGNMENT == 0);
MyClassA *fooA = new MyClassA();
VERIFY(std::uintptr_t(fooA->avec.data()) % ALIGNMENT == 0);
delete foo0;
delete fooA;
}
// dynamic allocation, array
const int N = 10;
for (int i = 0; i < g_repeat * 100; ++i) {
MyStruct *foo0 = new MyStruct[N];
VERIFY(std::uintptr_t(foo0->avec.data()) % ALIGNMENT == 0);
MyClassA *fooA = new MyClassA[N];
VERIFY(std::uintptr_t(fooA->avec.data()) % ALIGNMENT == 0);
delete[] foo0;
delete[] fooA;
}
#endif
}
+62
View File
@@ -0,0 +1,62 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define EIGEN2_SUPPORT
#include "main.h"
template <typename MatrixType>
void eigen2support(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m3(rows, cols);
Scalar s1 = internal::random<Scalar>(), s2 = internal::random<Scalar>();
// scalar addition
VERIFY_IS_APPROX(m1.cwise() + s1, s1 + m1.cwise());
VERIFY_IS_APPROX(m1.cwise() + s1, MatrixType::Constant(rows, cols, s1) + m1);
VERIFY_IS_APPROX((m1 * Scalar(2)).cwise() - s2, (m1 + m1) - MatrixType::Constant(rows, cols, s2));
m3 = m1;
m3.cwise() += s2;
VERIFY_IS_APPROX(m3, m1.cwise() + s2);
m3 = m1;
m3.cwise() -= s1;
VERIFY_IS_APPROX(m3, m1.cwise() - s1);
VERIFY_IS_EQUAL((m1.corner(TopLeft, 1, 1)), (m1.block(0, 0, 1, 1)));
VERIFY_IS_EQUAL((m1.template corner<1, 1>(TopLeft)), (m1.template block<1, 1>(0, 0)));
VERIFY_IS_EQUAL((m1.col(0).start(1)), (m1.col(0).segment(0, 1)));
VERIFY_IS_EQUAL((m1.col(0).template start<1>()), (m1.col(0).segment(0, 1)));
VERIFY_IS_EQUAL((m1.col(0).end(1)), (m1.col(0).segment(rows - 1, 1)));
VERIFY_IS_EQUAL((m1.col(0).template end<1>()), (m1.col(0).segment(rows - 1, 1)));
using numext::abs2;
using numext::real;
using std::cos;
VERIFY_IS_EQUAL(ei_cos(s1), cos(s1));
VERIFY_IS_EQUAL(ei_real(s1), real(s1));
VERIFY_IS_EQUAL(ei_abs2(s1), abs2(s1));
m1.minor(0, 0);
}
EIGEN_DECLARE_TEST(eigen2support) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(eigen2support(Matrix<double, 1, 1>()));
CALL_SUBTEST_2(eigen2support(MatrixXd(1, 1)));
CALL_SUBTEST_4(eigen2support(Matrix3f()));
CALL_SUBTEST_5(eigen2support(Matrix4d()));
CALL_SUBTEST_2(eigen2support(MatrixXf(200, 200)));
CALL_SUBTEST_6(eigen2support(MatrixXcd(100, 100)));
}
}
+173
View File
@@ -0,0 +1,173 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <limits>
#include <Eigen/Eigenvalues>
#include <Eigen/LU>
#include "CustomComplex.h"
template <typename MatrixType>
bool find_pivot(typename MatrixType::Scalar tol, MatrixType& diffs, Index col = 0) {
bool match = diffs.diagonal().sum() <= tol;
if (match || col == diffs.cols()) {
return match;
} else {
Index n = diffs.cols();
std::vector<std::pair<Index, Index> > transpositions;
for (Index i = col; i < n; ++i) {
Index best_index(0);
if (diffs.col(col).segment(col, n - i).minCoeff(&best_index) > tol) break;
best_index += col;
diffs.row(col).swap(diffs.row(best_index));
if (find_pivot(tol, diffs, col + 1)) return true;
diffs.row(col).swap(diffs.row(best_index));
// move current pivot to the end
diffs.row(n - (i - col) - 1).swap(diffs.row(best_index));
transpositions.push_back(std::pair<Index, Index>(n - (i - col) - 1, best_index));
}
// restore
for (Index k = transpositions.size() - 1; k >= 0; --k)
diffs.row(transpositions[k].first).swap(diffs.row(transpositions[k].second));
}
return false;
}
/* Check that two column vectors are approximately equal up to permutations.
* Initially, this method checked that the k-th power sums are equal for all k = 1, ..., vec1.rows(),
* however this strategy is numerically inaccurate because of numerical cancellation issues.
*/
template <typename VectorType>
void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2) {
typedef typename VectorType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
VERIFY(vec1.cols() == 1);
VERIFY(vec2.cols() == 1);
VERIFY(vec1.rows() == vec2.rows());
Index n = vec1.rows();
RealScalar tol = test_precision<RealScalar>() * test_precision<RealScalar>() *
numext::maxi(vec1.squaredNorm(), vec2.squaredNorm());
Matrix<RealScalar, Dynamic, Dynamic> diffs =
(vec1.rowwise().replicate(n) - vec2.rowwise().replicate(n).transpose()).cwiseAbs2();
VERIFY(find_pivot(tol, diffs));
}
template <typename MatrixType>
void eigensolver(const MatrixType& m) {
/* this test covers the following files:
ComplexEigenSolver.h, and indirectly ComplexSchur.h
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
MatrixType a = MatrixType::Random(rows, cols);
MatrixType symmA = a.adjoint() * a;
ComplexEigenSolver<MatrixType> ei0(symmA);
VERIFY_IS_EQUAL(ei0.info(), Success);
VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());
ComplexEigenSolver<MatrixType> ei1(a);
VERIFY_IS_EQUAL(ei1.info(), Success);
VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
// Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus
// another algorithm so results may differ slightly
verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues());
ComplexEigenSolver<MatrixType> ei2;
ei2.setMaxIterations(ComplexSchur<MatrixType>::m_maxIterationsPerRow * rows).compute(a);
VERIFY_IS_EQUAL(ei2.info(), Success);
VERIFY_IS_EQUAL(ei2.eigenvectors(), ei1.eigenvectors());
VERIFY_IS_EQUAL(ei2.eigenvalues(), ei1.eigenvalues());
if (rows > 2) {
ei2.setMaxIterations(1).compute(a);
VERIFY_IS_EQUAL(ei2.info(), NoConvergence);
VERIFY_IS_EQUAL(ei2.getMaxIterations(), 1);
}
ComplexEigenSolver<MatrixType> eiNoEivecs(a, false);
VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());
// Regression test for issue #66
MatrixType z = MatrixType::Zero(rows, cols);
ComplexEigenSolver<MatrixType> eiz(z);
VERIFY((eiz.eigenvalues().cwiseEqual(0)).all());
MatrixType id = MatrixType::Identity(rows, cols);
VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
if (rows > 1 && rows < 20) {
// Test matrix with NaN
a(0, 0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
ComplexEigenSolver<MatrixType> eiNaN(a);
VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence);
}
// regression test for bug 1098
{
ComplexEigenSolver<MatrixType> eig(a.adjoint() * a);
eig.compute(a.adjoint() * a);
}
// regression test for bug 478
{
a.setZero();
ComplexEigenSolver<MatrixType> ei3(a);
VERIFY_IS_EQUAL(ei3.info(), Success);
VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(), RealScalar(1));
VERIFY((ei3.eigenvectors().transpose() * ei3.eigenvectors().transpose()).eval().isIdentity());
}
}
template <typename MatrixType>
void eigensolver_verify_assert(const MatrixType& m) {
ComplexEigenSolver<MatrixType> eig;
VERIFY_RAISES_ASSERT(eig.eigenvectors());
VERIFY_RAISES_ASSERT(eig.eigenvalues());
MatrixType a = MatrixType::Random(m.rows(), m.cols());
eig.compute(a, false);
VERIFY_RAISES_ASSERT(eig.eigenvectors());
}
EIGEN_DECLARE_TEST(eigensolver_complex) {
int s = 0;
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(eigensolver(Matrix4cf()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_2(eigensolver(MatrixXcd(s, s)));
CALL_SUBTEST_3(eigensolver(Matrix<std::complex<float>, 1, 1>()));
CALL_SUBTEST_4(eigensolver(Matrix3f()));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
CALL_SUBTEST_1(eigensolver_verify_assert(Matrix4cf()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_2(eigensolver_verify_assert(MatrixXcd(s, s)));
CALL_SUBTEST_3(eigensolver_verify_assert(Matrix<std::complex<float>, 1, 1>()));
CALL_SUBTEST_4(eigensolver_verify_assert(Matrix3f()));
// Test problem size constructors
CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf> tmp(s));
// Test custom complex scalar type.
CALL_SUBTEST_6(eigensolver(Matrix<CustomComplex<double>, 5, 5>()));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
+139
View File
@@ -0,0 +1,139 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define EIGEN_RUNTIME_NO_MALLOC
#include "main.h"
#include <limits>
#include <Eigen/Eigenvalues>
#include <Eigen/LU>
template <typename MatrixType>
void generalized_eigensolver_real(const MatrixType& m) {
/* this test covers the following files:
GeneralizedEigenSolver.h
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef std::complex<Scalar> ComplexScalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
MatrixType a = MatrixType::Random(rows, cols);
MatrixType b = MatrixType::Random(rows, cols);
MatrixType a1 = MatrixType::Random(rows, cols);
MatrixType b1 = MatrixType::Random(rows, cols);
MatrixType spdA = a.adjoint() * a + a1.adjoint() * a1;
MatrixType spdB = b.adjoint() * b + b1.adjoint() * b1;
// lets compare to GeneralizedSelfAdjointEigenSolver
{
GeneralizedSelfAdjointEigenSolver<MatrixType> symmEig(spdA, spdB);
GeneralizedEigenSolver<MatrixType> eig(spdA, spdB);
VERIFY_IS_EQUAL(eig.eigenvalues().imag().cwiseAbs().maxCoeff(), 0);
VectorType realEigenvalues = eig.eigenvalues().real();
std::sort(realEigenvalues.data(), realEigenvalues.data() + realEigenvalues.size());
VERIFY_IS_APPROX(realEigenvalues, symmEig.eigenvalues());
// check eigenvectors
typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType D = eig.eigenvalues().asDiagonal();
typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType V = eig.eigenvectors();
VERIFY_IS_APPROX(spdA * V, spdB * V * D);
}
// non symmetric case:
{
GeneralizedEigenSolver<MatrixType> eig(rows);
// TODO enable full-prealocation of required memory, this probably requires an in-place mode for
// HessenbergDecomposition
// Eigen::internal::set_is_malloc_allowed(false);
eig.compute(a, b);
// Eigen::internal::set_is_malloc_allowed(true);
for (Index k = 0; k < cols; ++k) {
Matrix<ComplexScalar, Dynamic, Dynamic> tmp =
(eig.betas()(k) * a).template cast<ComplexScalar>() - eig.alphas()(k) * b;
if (tmp.size() > 1 && tmp.norm() > (std::numeric_limits<Scalar>::min)()) tmp /= tmp.norm();
VERIFY_IS_MUCH_SMALLER_THAN(std::abs(tmp.determinant()), Scalar(1));
}
// check eigenvectors
typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType D = eig.eigenvalues().asDiagonal();
typename GeneralizedEigenSolver<MatrixType>::EigenvectorsType V = eig.eigenvectors();
VERIFY_IS_APPROX(a * V, b * V * D);
}
// regression test for bug 1098
{
GeneralizedSelfAdjointEigenSolver<MatrixType> eig1(a.adjoint() * a, b.adjoint() * b);
eig1.compute(a.adjoint() * a, b.adjoint() * b);
GeneralizedEigenSolver<MatrixType> eig2(a.adjoint() * a, b.adjoint() * b);
eig2.compute(a.adjoint() * a, b.adjoint() * b);
}
// check without eigenvectors
{
GeneralizedEigenSolver<MatrixType> eig1(spdA, spdB, true);
GeneralizedEigenSolver<MatrixType> eig2(spdA, spdB, false);
VERIFY_IS_APPROX(eig1.eigenvalues(), eig2.eigenvalues());
}
}
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++) {
int s = 0;
CALL_SUBTEST_1(generalized_eigensolver_real(Matrix4f()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_2(generalized_eigensolver_real(MatrixXd(s, s)));
// some trivial but implementation-wise special cases
CALL_SUBTEST_2(generalized_eigensolver_real(MatrixXd(1, 1)));
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)
}
}
+233
View File
@@ -0,0 +1,233 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2010,2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <limits>
#include <Eigen/Eigenvalues>
template <typename EigType, typename MatType>
void check_eigensolver_for_given_mat(const EigType& eig, const MatType& a) {
typedef typename NumTraits<typename MatType::Scalar>::Real RealScalar;
typedef Matrix<RealScalar, MatType::RowsAtCompileTime, 1> RealVectorType;
typedef typename std::complex<RealScalar> Complex;
Index n = a.rows();
VERIFY_IS_EQUAL(eig.info(), Success);
VERIFY_IS_APPROX(a * eig.pseudoEigenvectors(), eig.pseudoEigenvectors() * eig.pseudoEigenvalueMatrix());
VERIFY_IS_APPROX(a.template cast<Complex>() * eig.eigenvectors(),
eig.eigenvectors() * eig.eigenvalues().asDiagonal());
VERIFY_IS_APPROX(eig.eigenvectors().colwise().norm(), RealVectorType::Ones(n).transpose());
VERIFY_IS_APPROX(a.eigenvalues(), eig.eigenvalues());
}
template <typename MatrixType>
void eigensolver(const MatrixType& m) {
/* this test covers the following files:
EigenSolver.h
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef typename std::complex<RealScalar> Complex;
MatrixType a = MatrixType::Random(rows, cols);
MatrixType a1 = MatrixType::Random(rows, cols);
MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
EigenSolver<MatrixType> ei0(symmA);
VERIFY_IS_EQUAL(ei0.info(), Success);
VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix());
VERIFY_IS_APPROX((symmA.template cast<Complex>()) * (ei0.pseudoEigenvectors().template cast<Complex>()),
(ei0.pseudoEigenvectors().template cast<Complex>()) * (ei0.eigenvalues().asDiagonal()));
EigenSolver<MatrixType> ei1(a);
CALL_SUBTEST(check_eigensolver_for_given_mat(ei1, a));
EigenSolver<MatrixType> ei2;
ei2.setMaxIterations(RealSchur<MatrixType>::m_maxIterationsPerRow * rows).compute(a);
VERIFY_IS_EQUAL(ei2.info(), Success);
VERIFY_IS_EQUAL(ei2.eigenvectors(), ei1.eigenvectors());
VERIFY_IS_EQUAL(ei2.eigenvalues(), ei1.eigenvalues());
if (rows > 2) {
ei2.setMaxIterations(1).compute(a);
VERIFY_IS_EQUAL(ei2.info(), NoConvergence);
VERIFY_IS_EQUAL(ei2.getMaxIterations(), 1);
}
EigenSolver<MatrixType> eiNoEivecs(a, false);
VERIFY_IS_EQUAL(eiNoEivecs.info(), Success);
VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues());
VERIFY_IS_APPROX(ei1.pseudoEigenvalueMatrix(), eiNoEivecs.pseudoEigenvalueMatrix());
MatrixType id = MatrixType::Identity(rows, cols);
VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
if (rows > 2 && rows < 20) {
// Test matrix with NaN
a(0, 0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
EigenSolver<MatrixType> eiNaN(a);
VERIFY_IS_NOT_EQUAL(eiNaN.info(), Success);
}
// regression test for bug 1098
{
EigenSolver<MatrixType> eig(a.adjoint() * a);
eig.compute(a.adjoint() * a);
}
// regression test for bug 478
{
a.setZero();
EigenSolver<MatrixType> ei3(a);
VERIFY_IS_EQUAL(ei3.info(), Success);
VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(), RealScalar(1));
VERIFY((ei3.eigenvectors().transpose() * ei3.eigenvectors().transpose()).eval().isIdentity());
}
}
template <typename MatrixType>
void eigensolver_verify_assert(const MatrixType& m) {
EigenSolver<MatrixType> eig;
VERIFY_RAISES_ASSERT(eig.eigenvectors());
VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors());
VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix());
VERIFY_RAISES_ASSERT(eig.eigenvalues());
MatrixType a = MatrixType::Random(m.rows(), m.cols());
eig.compute(a, false);
VERIFY_RAISES_ASSERT(eig.eigenvectors());
VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors());
}
template <typename CoeffType>
Matrix<typename CoeffType::Scalar, Dynamic, Dynamic> make_companion(const CoeffType& coeffs) {
Index n = coeffs.size() - 1;
Matrix<typename CoeffType::Scalar, Dynamic, Dynamic> res(n, n);
res.setZero();
res.row(0) = -coeffs.tail(n) / coeffs(0);
res.diagonal(-1).setOnes();
return res;
}
template <int>
void eigensolver_generic_extra() {
{
// regression test for bug 793
MatrixXd a(3, 3);
a << 0, 0, 1, 1, 1, 1, 1, 1e+200, 1;
Eigen::EigenSolver<MatrixXd> eig(a);
double scale = 1e-200; // scale to avoid overflow during the comparisons
VERIFY_IS_APPROX(a * eig.pseudoEigenvectors() * scale,
eig.pseudoEigenvectors() * eig.pseudoEigenvalueMatrix() * scale);
VERIFY_IS_APPROX(a * eig.eigenvectors() * scale, eig.eigenvectors() * eig.eigenvalues().asDiagonal() * scale);
}
{
// check a case where all eigenvalues are null.
MatrixXd a(2, 2);
a << 1, 1, -1, -1;
Eigen::EigenSolver<MatrixXd> eig(a);
VERIFY_IS_APPROX(eig.pseudoEigenvectors().squaredNorm(), 2.);
VERIFY_IS_APPROX((a * eig.pseudoEigenvectors()).norm() + 1., 1.);
VERIFY_IS_APPROX((eig.pseudoEigenvectors() * eig.pseudoEigenvalueMatrix()).norm() + 1., 1.);
VERIFY_IS_APPROX((a * eig.eigenvectors()).norm() + 1., 1.);
VERIFY_IS_APPROX((eig.eigenvectors() * eig.eigenvalues().asDiagonal()).norm() + 1., 1.);
}
// regression test for bug 933
{
{
VectorXd coeffs(5);
coeffs << 1, -3, -175, -225, 2250;
MatrixXd C = make_companion(coeffs);
EigenSolver<MatrixXd> eig(C);
CALL_SUBTEST(check_eigensolver_for_given_mat(eig, C));
}
{
// this test is tricky because it requires high accuracy in smallest eigenvalues
VectorXd coeffs(5);
coeffs << 6.154671e-15, -1.003870e-10, -9.819570e-01, 3.995715e+03, 2.211511e+08;
MatrixXd C = make_companion(coeffs);
EigenSolver<MatrixXd> eig(C);
CALL_SUBTEST(check_eigensolver_for_given_mat(eig, C));
Index n = C.rows();
for (Index i = 0; i < n; ++i) {
typedef std::complex<double> Complex;
MatrixXcd ac = C.cast<Complex>();
ac.diagonal().array() -= eig.eigenvalues()(i);
VectorXd sv = ac.jacobiSvd().singularValues();
// comparing to sv(0) is not enough here to catch the "bug",
// the hard-coded 1.0 is important!
VERIFY_IS_MUCH_SMALLER_THAN(sv(n - 1), 1.0);
}
}
}
// regression test for bug 1557
{
// this test is interesting because it contains zeros on the diagonal.
MatrixXd A_bug1557(3, 3);
A_bug1557 << 0, 0, 0, 1, 0, 0.5887907064808635127, 0, 1, 0;
EigenSolver<MatrixXd> eig(A_bug1557);
CALL_SUBTEST(check_eigensolver_for_given_mat(eig, A_bug1557));
}
// regression test for bug 1174
{
Index n = 12;
MatrixXf A_bug1174(n, n);
A_bug1174 << 262144, 0, 0, 262144, 786432, 0, 0, 0, 0, 0, 0, 786432, 262144, 0, 0, 262144, 786432, 0, 0, 0, 0, 0, 0,
786432, 262144, 0, 0, 262144, 786432, 0, 0, 0, 0, 0, 0, 786432, 262144, 0, 0, 262144, 786432, 0, 0, 0, 0, 0, 0,
786432, 0, 262144, 262144, 0, 0, 262144, 262144, 262144, 262144, 262144, 262144, 0, 0, 262144, 262144, 0, 0,
262144, 262144, 262144, 262144, 262144, 262144, 0, 0, 262144, 262144, 0, 0, 262144, 262144, 262144, 262144,
262144, 262144, 0, 0, 262144, 262144, 0, 0, 262144, 262144, 262144, 262144, 262144, 262144, 0, 0, 262144,
262144, 0, 0, 262144, 262144, 262144, 262144, 262144, 262144, 0, 0, 262144, 262144, 0, 0, 262144, 262144,
262144, 262144, 262144, 262144, 0, 0, 262144, 262144, 0, 0, 262144, 262144, 262144, 262144, 262144, 262144, 0,
0, 262144, 262144, 0, 0, 262144, 262144, 262144, 262144, 262144, 262144, 0;
EigenSolver<MatrixXf> eig(A_bug1174);
CALL_SUBTEST(check_eigensolver_for_given_mat(eig, A_bug1174));
}
}
EIGEN_DECLARE_TEST(eigensolver_generic) {
int s = 0;
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(eigensolver(Matrix4f()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_2(eigensolver(MatrixXd(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
// some trivial but implementation-wise tricky cases
CALL_SUBTEST_2(eigensolver(MatrixXd(1, 1)));
CALL_SUBTEST_2(eigensolver(MatrixXd(2, 2)));
CALL_SUBTEST_3(eigensolver(Matrix<double, 1, 1>()));
CALL_SUBTEST_4(eigensolver(Matrix2d()));
}
CALL_SUBTEST_1(eigensolver_verify_assert(Matrix4f()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_2(eigensolver_verify_assert(MatrixXd(s, s)));
CALL_SUBTEST_3(eigensolver_verify_assert(Matrix<double, 1, 1>()));
CALL_SUBTEST_4(eigensolver_verify_assert(Matrix2d()));
// Test problem size constructors
CALL_SUBTEST_5(EigenSolver<MatrixXf> tmp(s));
// regression test for bug 410
CALL_SUBTEST_2({
MatrixXd A(1, 1);
A(0, 0) = std::sqrt(-1.); // is Not-a-Number
Eigen::EigenSolver<MatrixXd> solver(A);
VERIFY_IS_EQUAL(solver.info(), NumericalIssue);
});
CALL_SUBTEST_2(eigensolver_generic_extra<0>());
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
+270
View File
@@ -0,0 +1,270 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include "svd_fill.h"
#include <limits>
#include <Eigen/Eigenvalues>
#include <Eigen/SparseCore>
template <typename MatrixType>
void selfadjointeigensolver_essential_check(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
RealScalar eival_eps =
numext::mini<RealScalar>(test_precision<RealScalar>(), NumTraits<Scalar>::dummy_precision() * 20000);
SelfAdjointEigenSolver<MatrixType> eiSymm(m);
VERIFY_IS_EQUAL(eiSymm.info(), Success);
RealScalar scaling = m.cwiseAbs().maxCoeff();
RealScalar unitary_error_factor = RealScalar(16);
if (scaling < (std::numeric_limits<RealScalar>::min)()) {
VERIFY(eiSymm.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits<RealScalar>::min)());
} else {
VERIFY_IS_APPROX((m.template selfadjointView<Lower>() * eiSymm.eigenvectors()) / scaling,
(eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal()) / scaling);
}
VERIFY_IS_APPROX(m.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues());
VERIFY(eiSymm.eigenvectors().isUnitary(test_precision<RealScalar>() * unitary_error_factor));
if (m.cols() <= 4) {
SelfAdjointEigenSolver<MatrixType> eiDirect;
eiDirect.computeDirect(m);
VERIFY_IS_EQUAL(eiDirect.info(), Success);
if (!eiSymm.eigenvalues().isApprox(eiDirect.eigenvalues(), eival_eps)) {
std::cerr << "reference eigenvalues: " << eiSymm.eigenvalues().transpose() << "\n"
<< "obtained eigenvalues: " << eiDirect.eigenvalues().transpose() << "\n"
<< "diff: " << (eiSymm.eigenvalues() - eiDirect.eigenvalues()).transpose() << "\n"
<< "error (eps): "
<< (eiSymm.eigenvalues() - eiDirect.eigenvalues()).norm() / eiSymm.eigenvalues().norm() << " ("
<< eival_eps << ")\n";
}
if (scaling < (std::numeric_limits<RealScalar>::min)()) {
VERIFY(eiDirect.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits<RealScalar>::min)());
} else {
VERIFY_IS_APPROX(eiSymm.eigenvalues() / scaling, eiDirect.eigenvalues() / scaling);
VERIFY_IS_APPROX((m.template selfadjointView<Lower>() * eiDirect.eigenvectors()) / scaling,
(eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal()) / scaling);
VERIFY_IS_APPROX(m.template selfadjointView<Lower>().eigenvalues() / scaling, eiDirect.eigenvalues() / scaling);
}
VERIFY(eiDirect.eigenvectors().isUnitary(test_precision<RealScalar>() * unitary_error_factor));
}
}
template <typename MatrixType>
void selfadjointeigensolver(const MatrixType& m) {
/* this test covers the following files:
EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
RealScalar largerEps = 10 * test_precision<RealScalar>();
MatrixType a = MatrixType::Random(rows, cols);
MatrixType a1 = MatrixType::Random(rows, cols);
MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1;
MatrixType symmC = symmA;
svd_fill_random(symmA, Symmetric);
symmA.template triangularView<StrictlyUpper>().setZero();
symmC.template triangularView<StrictlyUpper>().setZero();
MatrixType b = MatrixType::Random(rows, cols);
MatrixType b1 = MatrixType::Random(rows, cols);
MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1;
symmB.template triangularView<StrictlyUpper>().setZero();
CALL_SUBTEST(selfadjointeigensolver_essential_check(symmA));
SelfAdjointEigenSolver<MatrixType> eiSymm(symmA);
// generalized eigen pb
GeneralizedSelfAdjointEigenSolver<MatrixType> eiSymmGen(symmC, symmB);
SelfAdjointEigenSolver<MatrixType> eiSymmNoEivecs(symmA, false);
VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success);
VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues());
// generalized eigen problem Ax = lBx
eiSymmGen.compute(symmC, symmB, Ax_lBx);
VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
VERIFY((symmC.template selfadjointView<Lower>() * eiSymmGen.eigenvectors())
.isApprox(symmB.template selfadjointView<Lower>() *
(eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()),
largerEps));
// generalized eigen problem BAx = lx
eiSymmGen.compute(symmC, symmB, BAx_lx);
VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
VERIFY(
(symmB.template selfadjointView<Lower>() * (symmC.template selfadjointView<Lower>() * eiSymmGen.eigenvectors()))
.isApprox((eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
// generalized eigen problem ABx = lx
eiSymmGen.compute(symmC, symmB, ABx_lx);
VERIFY_IS_EQUAL(eiSymmGen.info(), Success);
VERIFY(
(symmC.template selfadjointView<Lower>() * (symmB.template selfadjointView<Lower>() * eiSymmGen.eigenvectors()))
.isApprox((eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps));
eiSymm.compute(symmC);
MatrixType sqrtSymmA = eiSymm.operatorSqrt();
VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()), sqrtSymmA * sqrtSymmA);
VERIFY_IS_APPROX(sqrtSymmA, symmC.template selfadjointView<Lower>() * eiSymm.operatorInverseSqrt());
MatrixType id = MatrixType::Identity(rows, cols);
VERIFY_IS_APPROX(id.template selfadjointView<Lower>().operatorNorm(), RealScalar(1));
SelfAdjointEigenSolver<MatrixType> eiSymmUninitialized;
VERIFY_RAISES_ASSERT(eiSymmUninitialized.info());
VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues());
VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
eiSymmUninitialized.compute(symmA, false);
VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors());
VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt());
VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt());
// test Tridiagonalization's methods
Tridiagonalization<MatrixType> tridiag(symmC);
VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().diagonal());
VERIFY_IS_APPROX(tridiag.subDiagonal(), tridiag.matrixT().template diagonal<-1>());
Matrix<RealScalar, Dynamic, Dynamic> T = tridiag.matrixT();
if (rows > 1 && cols > 1) {
// FIXME check that upper and lower part are 0:
// VERIFY(T.topRightCorner(rows-2, cols-2).template triangularView<Upper>().isZero());
}
VERIFY_IS_APPROX(tridiag.diagonal(), T.diagonal());
VERIFY_IS_APPROX(tridiag.subDiagonal(), T.template diagonal<1>());
VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()),
tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint());
VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView<Lower>()),
tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint());
// Test computation of eigenvalues from tridiagonal matrix
if (rows > 1) {
SelfAdjointEigenSolver<MatrixType> eiSymmTridiag;
eiSymmTridiag.computeFromTridiagonal(tridiag.matrixT().diagonal(), tridiag.matrixT().diagonal(-1),
ComputeEigenvectors);
VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmTridiag.eigenvalues());
VERIFY_IS_APPROX(tridiag.matrixT(), eiSymmTridiag.eigenvectors().real() * eiSymmTridiag.eigenvalues().asDiagonal() *
eiSymmTridiag.eigenvectors().real().transpose());
}
if (rows > 1 && rows < 20) {
// Test matrix with NaN
symmC(0, 0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN();
SelfAdjointEigenSolver<MatrixType> eiSymmNaN(symmC);
VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence);
}
// regression test for bug 1098
{
SelfAdjointEigenSolver<MatrixType> eig(a.adjoint() * a);
eig.compute(a.adjoint() * a);
}
// regression test for bug 478
{
a.setZero();
SelfAdjointEigenSolver<MatrixType> ei3(a);
VERIFY_IS_EQUAL(ei3.info(), Success);
VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(), RealScalar(1));
VERIFY((ei3.eigenvectors().transpose() * ei3.eigenvectors().transpose()).eval().isIdentity());
}
}
template <int>
void bug_854() {
Matrix3d m;
m << 850.961, 51.966, 0, 51.966, 254.841, 0, 0, 0, 0;
selfadjointeigensolver_essential_check(m);
}
template <int>
void bug_1014() {
Matrix3d m;
m << 0.11111111111111114658, 0, 0, 0, 0.11111111111111109107, 0, 0, 0, 0.11111111111111107719;
selfadjointeigensolver_essential_check(m);
}
template <int>
void bug_1225() {
Matrix3d m1, m2;
m1.setRandom();
m1 = m1 * m1.transpose();
m2 = m1.triangularView<Upper>();
SelfAdjointEigenSolver<Matrix3d> eig1(m1);
SelfAdjointEigenSolver<Matrix3d> eig2(m2.selfadjointView<Upper>());
VERIFY_IS_APPROX(eig1.eigenvalues(), eig2.eigenvalues());
}
template <int>
void bug_1204() {
SparseMatrix<double> A(2, 2);
A.setIdentity();
SelfAdjointEigenSolver<Eigen::SparseMatrix<double> > eig(A);
}
EIGEN_DECLARE_TEST(eigensolver_selfadjoint) {
int s = 0;
for (int i = 0; i < g_repeat; i++) {
// trivial test for 1x1 matrices:
CALL_SUBTEST_1(selfadjointeigensolver(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(selfadjointeigensolver(Matrix<double, 1, 1>()));
CALL_SUBTEST_1(selfadjointeigensolver(Matrix<std::complex<double>, 1, 1>()));
// very important to test 3x3 and 2x2 matrices since we provide special paths for them
CALL_SUBTEST_12(selfadjointeigensolver(Matrix2f()));
CALL_SUBTEST_12(selfadjointeigensolver(Matrix2d()));
CALL_SUBTEST_12(selfadjointeigensolver(Matrix2cd()));
CALL_SUBTEST_13(selfadjointeigensolver(Matrix3f()));
CALL_SUBTEST_13(selfadjointeigensolver(Matrix3d()));
CALL_SUBTEST_13(selfadjointeigensolver(Matrix3cd()));
CALL_SUBTEST_2(selfadjointeigensolver(Matrix4d()));
CALL_SUBTEST_2(selfadjointeigensolver(Matrix4cd()));
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_3(selfadjointeigensolver(MatrixXf(s, s)));
CALL_SUBTEST_4(selfadjointeigensolver(MatrixXd(s, s)));
CALL_SUBTEST_5(selfadjointeigensolver(MatrixXcd(s, s)));
CALL_SUBTEST_9(selfadjointeigensolver(Matrix<std::complex<double>, Dynamic, Dynamic, RowMajor>(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
// some trivial but implementation-wise tricky cases
CALL_SUBTEST_4(selfadjointeigensolver(MatrixXd(1, 1)));
CALL_SUBTEST_4(selfadjointeigensolver(MatrixXd(2, 2)));
CALL_SUBTEST_5(selfadjointeigensolver(MatrixXcd(1, 1)));
CALL_SUBTEST_5(selfadjointeigensolver(MatrixXcd(2, 2)));
CALL_SUBTEST_6(selfadjointeigensolver(Matrix<double, 1, 1>()));
CALL_SUBTEST_7(selfadjointeigensolver(Matrix<double, 2, 2>()));
}
CALL_SUBTEST_13(bug_854<0>());
CALL_SUBTEST_13(bug_1014<0>());
CALL_SUBTEST_13(bug_1204<0>());
CALL_SUBTEST_13(bug_1225<0>());
// Test problem size constructors
s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 4);
CALL_SUBTEST_8(SelfAdjointEigenSolver<MatrixXf> tmp1(s));
CALL_SUBTEST_8(Tridiagonalization<MatrixXf> tmp2(s));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
View File
+541
View File
@@ -0,0 +1,541 @@
#include "main.h"
namespace Eigen {
template <typename Lhs, typename Rhs>
const Product<Lhs, Rhs> prod(const Lhs& lhs, const Rhs& rhs) {
return Product<Lhs, Rhs>(lhs, rhs);
}
template <typename Lhs, typename Rhs>
const Product<Lhs, Rhs, LazyProduct> lazyprod(const Lhs& lhs, const Rhs& rhs) {
return Product<Lhs, Rhs, LazyProduct>(lhs, rhs);
}
template <typename DstXprType, typename SrcXprType>
EIGEN_STRONG_INLINE DstXprType& copy_using_evaluator(const EigenBase<DstXprType>& dst, const SrcXprType& src) {
call_assignment(dst.const_cast_derived(), src.derived(),
internal::assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>());
return dst.const_cast_derived();
}
template <typename DstXprType, template <typename> class StorageBase, typename SrcXprType>
EIGEN_STRONG_INLINE const DstXprType& copy_using_evaluator(const NoAlias<DstXprType, StorageBase>& dst,
const SrcXprType& src) {
call_assignment(dst, src.derived(), internal::assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>());
return dst.expression();
}
template <typename DstXprType, typename SrcXprType>
EIGEN_STRONG_INLINE DstXprType& copy_using_evaluator(const PlainObjectBase<DstXprType>& dst, const SrcXprType& src) {
#ifdef EIGEN_NO_AUTOMATIC_RESIZING
eigen_assert((dst.size() == 0 || (IsVectorAtCompileTime ? (dst.size() == src.size())
: (dst.rows() == src.rows() && dst.cols() == src.cols()))) &&
"Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined");
#else
dst.const_cast_derived().resizeLike(src.derived());
#endif
call_assignment(dst.const_cast_derived(), src.derived(),
internal::assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>());
return dst.const_cast_derived();
}
template <typename DstXprType, typename SrcXprType>
void add_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) {
typedef typename DstXprType::Scalar Scalar;
call_assignment(const_cast<DstXprType&>(dst), src.derived(),
internal::add_assign_op<Scalar, typename SrcXprType::Scalar>());
}
template <typename DstXprType, typename SrcXprType>
void subtract_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) {
typedef typename DstXprType::Scalar Scalar;
call_assignment(const_cast<DstXprType&>(dst), src.derived(),
internal::sub_assign_op<Scalar, typename SrcXprType::Scalar>());
}
template <typename DstXprType, typename SrcXprType>
void multiply_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) {
typedef typename DstXprType::Scalar Scalar;
call_assignment(dst.const_cast_derived(), src.derived(),
internal::mul_assign_op<Scalar, typename SrcXprType::Scalar>());
}
template <typename DstXprType, typename SrcXprType>
void divide_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) {
typedef typename DstXprType::Scalar Scalar;
call_assignment(dst.const_cast_derived(), src.derived(),
internal::div_assign_op<Scalar, typename SrcXprType::Scalar>());
}
template <typename DstXprType, typename SrcXprType>
void swap_using_evaluator(const DstXprType& dst, const SrcXprType& src) {
typedef typename DstXprType::Scalar Scalar;
call_assignment(dst.const_cast_derived(), src.const_cast_derived(), internal::swap_assign_op<Scalar>());
}
namespace internal {
template <typename Dst, template <typename> class StorageBase, typename Src, typename Func>
EIGEN_DEVICE_FUNC void call_assignment(const NoAlias<Dst, StorageBase>& dst, const Src& src, const Func& func) {
call_assignment_no_alias(dst.expression(), src, func);
}
template <typename Dst, template <typename> class StorageBase, typename Src, typename Func>
EIGEN_DEVICE_FUNC void call_restricted_packet_assignment(const NoAlias<Dst, StorageBase>& dst, const Src& src,
const Func& func) {
call_restricted_packet_assignment_no_alias(dst.expression(), src, func);
}
} // namespace internal
} // namespace Eigen
template <typename XprType>
long get_cost(const XprType&) {
return Eigen::internal::evaluator<XprType>::CoeffReadCost;
}
using namespace std;
#define VERIFY_IS_APPROX_EVALUATOR(DEST, EXPR) VERIFY_IS_APPROX(copy_using_evaluator(DEST, (EXPR)), (EXPR).eval());
#define VERIFY_IS_APPROX_EVALUATOR2(DEST, EXPR, REF) VERIFY_IS_APPROX(copy_using_evaluator(DEST, (EXPR)), (REF).eval());
EIGEN_DECLARE_TEST(evaluators) {
// Testing Matrix evaluator and Transpose
Vector2d v = Vector2d::Random();
const Vector2d v_const(v);
Vector2d v2;
RowVector2d w;
VERIFY_IS_APPROX_EVALUATOR(v2, v);
VERIFY_IS_APPROX_EVALUATOR(v2, v_const);
// Testing Transpose
VERIFY_IS_APPROX_EVALUATOR(w, v.transpose()); // Transpose as rvalue
VERIFY_IS_APPROX_EVALUATOR(w, v_const.transpose());
copy_using_evaluator(w.transpose(), v); // Transpose as lvalue
VERIFY_IS_APPROX(w, v.transpose().eval());
copy_using_evaluator(w.transpose(), v_const);
VERIFY_IS_APPROX(w, v_const.transpose().eval());
// Testing Array evaluator
{
ArrayXXf a(2, 3);
ArrayXXf b(3, 2);
a << 1, 2, 3, 4, 5, 6;
const ArrayXXf a_const(a);
VERIFY_IS_APPROX_EVALUATOR(b, a.transpose());
VERIFY_IS_APPROX_EVALUATOR(b, a_const.transpose());
// Testing CwiseNullaryOp evaluator
copy_using_evaluator(w, RowVector2d::Random());
VERIFY((w.array() >= -1).all() && (w.array() <= 1).all()); // not easy to test ...
VERIFY_IS_APPROX_EVALUATOR(w, RowVector2d::Zero());
VERIFY_IS_APPROX_EVALUATOR(w, RowVector2d::Constant(3));
// mix CwiseNullaryOp and transpose
VERIFY_IS_APPROX_EVALUATOR(w, Vector2d::Zero().transpose());
}
{
// test product expressions
int s = internal::random<int>(1, 100);
MatrixXf a(s, s), b(s, s), c(s, s), d(s, s);
a.setRandom();
b.setRandom();
c.setRandom();
d.setRandom();
VERIFY_IS_APPROX_EVALUATOR(d, (a + b));
VERIFY_IS_APPROX_EVALUATOR(d, (a + b).transpose());
VERIFY_IS_APPROX_EVALUATOR2(d, prod(a, b), a * b);
VERIFY_IS_APPROX_EVALUATOR2(d.noalias(), prod(a, b), a * b);
VERIFY_IS_APPROX_EVALUATOR2(d, prod(a, b) + c, a * b + c);
VERIFY_IS_APPROX_EVALUATOR2(d, s * prod(a, b), s * a * b);
VERIFY_IS_APPROX_EVALUATOR2(d, prod(a, b).transpose(), (a * b).transpose());
VERIFY_IS_APPROX_EVALUATOR2(d, prod(a, b) + prod(b, c), a * b + b * c);
// check that prod works even with aliasing present
c = a * a;
copy_using_evaluator(a, prod(a, a));
VERIFY_IS_APPROX(a, c);
// check compound assignment of products
d = c;
add_assign_using_evaluator(c.noalias(), prod(a, b));
d.noalias() += a * b;
VERIFY_IS_APPROX(c, d);
d = c;
subtract_assign_using_evaluator(c.noalias(), prod(a, b));
d.noalias() -= a * b;
VERIFY_IS_APPROX(c, d);
}
{
// test product with all possible sizes
int s = internal::random<int>(1, 100);
Matrix<float, 1, 1> m11, res11;
m11.setRandom(1, 1);
Matrix<float, 1, 4> m14, res14;
m14.setRandom(1, 4);
Matrix<float, 1, Dynamic> m1X, res1X;
m1X.setRandom(1, s);
Matrix<float, 4, 1> m41, res41;
m41.setRandom(4, 1);
Matrix<float, 4, 4> m44, res44;
m44.setRandom(4, 4);
Matrix<float, 4, Dynamic> m4X, res4X;
m4X.setRandom(4, s);
Matrix<float, Dynamic, 1> mX1, resX1;
mX1.setRandom(s, 1);
Matrix<float, Dynamic, 4> mX4, resX4;
mX4.setRandom(s, 4);
Matrix<float, Dynamic, Dynamic> mXX, resXX;
mXX.setRandom(s, s);
VERIFY_IS_APPROX_EVALUATOR2(res11, prod(m11, m11), m11 * m11);
VERIFY_IS_APPROX_EVALUATOR2(res11, prod(m14, m41), m14 * m41);
VERIFY_IS_APPROX_EVALUATOR2(res11, prod(m1X, mX1), m1X * mX1);
VERIFY_IS_APPROX_EVALUATOR2(res14, prod(m11, m14), m11 * m14);
VERIFY_IS_APPROX_EVALUATOR2(res14, prod(m14, m44), m14 * m44);
VERIFY_IS_APPROX_EVALUATOR2(res14, prod(m1X, mX4), m1X * mX4);
VERIFY_IS_APPROX_EVALUATOR2(res1X, prod(m11, m1X), m11 * m1X);
VERIFY_IS_APPROX_EVALUATOR2(res1X, prod(m14, m4X), m14 * m4X);
VERIFY_IS_APPROX_EVALUATOR2(res1X, prod(m1X, mXX), m1X * mXX);
VERIFY_IS_APPROX_EVALUATOR2(res41, prod(m41, m11), m41 * m11);
VERIFY_IS_APPROX_EVALUATOR2(res41, prod(m44, m41), m44 * m41);
VERIFY_IS_APPROX_EVALUATOR2(res41, prod(m4X, mX1), m4X * mX1);
VERIFY_IS_APPROX_EVALUATOR2(res44, prod(m41, m14), m41 * m14);
VERIFY_IS_APPROX_EVALUATOR2(res44, prod(m44, m44), m44 * m44);
VERIFY_IS_APPROX_EVALUATOR2(res44, prod(m4X, mX4), m4X * mX4);
VERIFY_IS_APPROX_EVALUATOR2(res4X, prod(m41, m1X), m41 * m1X);
VERIFY_IS_APPROX_EVALUATOR2(res4X, prod(m44, m4X), m44 * m4X);
VERIFY_IS_APPROX_EVALUATOR2(res4X, prod(m4X, mXX), m4X * mXX);
VERIFY_IS_APPROX_EVALUATOR2(resX1, prod(mX1, m11), mX1 * m11);
VERIFY_IS_APPROX_EVALUATOR2(resX1, prod(mX4, m41), mX4 * m41);
VERIFY_IS_APPROX_EVALUATOR2(resX1, prod(mXX, mX1), mXX * mX1);
VERIFY_IS_APPROX_EVALUATOR2(resX4, prod(mX1, m14), mX1 * m14);
VERIFY_IS_APPROX_EVALUATOR2(resX4, prod(mX4, m44), mX4 * m44);
VERIFY_IS_APPROX_EVALUATOR2(resX4, prod(mXX, mX4), mXX * mX4);
VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mX1, m1X), mX1 * m1X);
VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mX4, m4X), mX4 * m4X);
VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mXX, mXX), mXX * mXX);
}
{
ArrayXXf a(2, 3);
ArrayXXf b(3, 2);
a << 1, 2, 3, 4, 5, 6;
const ArrayXXf a_const(a);
// this does not work because Random is eval-before-nested:
// copy_using_evaluator(w, Vector2d::Random().transpose());
// test CwiseUnaryOp
VERIFY_IS_APPROX_EVALUATOR(v2, 3 * v);
VERIFY_IS_APPROX_EVALUATOR(w, (3 * v).transpose());
VERIFY_IS_APPROX_EVALUATOR(b, (a + 3).transpose());
VERIFY_IS_APPROX_EVALUATOR(b, (2 * a_const + 3).transpose());
// test CwiseBinaryOp
VERIFY_IS_APPROX_EVALUATOR(v2, v + Vector2d::Ones());
VERIFY_IS_APPROX_EVALUATOR(w, (v + Vector2d::Ones()).transpose().cwiseProduct(RowVector2d::Constant(3)));
// dynamic matrices and arrays
MatrixXd mat1(6, 6), mat2(6, 6);
VERIFY_IS_APPROX_EVALUATOR(mat1, MatrixXd::Identity(6, 6));
VERIFY_IS_APPROX_EVALUATOR(mat2, mat1);
copy_using_evaluator(mat2.transpose(), mat1);
VERIFY_IS_APPROX(mat2.transpose(), mat1);
ArrayXXd arr1(6, 6), arr2(6, 6);
VERIFY_IS_APPROX_EVALUATOR(arr1, ArrayXXd::Constant(6, 6, 3.0));
VERIFY_IS_APPROX_EVALUATOR(arr2, arr1);
// test automatic resizing
mat2.resize(3, 3);
VERIFY_IS_APPROX_EVALUATOR(mat2, mat1);
arr2.resize(9, 9);
VERIFY_IS_APPROX_EVALUATOR(arr2, arr1);
// test direct traversal
Matrix3f m3;
Array33f a3;
VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Identity()); // matrix, nullary
// TODO: find a way to test direct traversal with array
VERIFY_IS_APPROX_EVALUATOR(m3.transpose(), Matrix3f::Identity().transpose()); // transpose
VERIFY_IS_APPROX_EVALUATOR(m3, 2 * Matrix3f::Identity()); // unary
VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Identity() + Matrix3f::Zero()); // binary
VERIFY_IS_APPROX_EVALUATOR(m3.block(0, 0, 2, 2), Matrix3f::Identity().block(1, 1, 2, 2)); // block
// test linear traversal
VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Zero()); // matrix, nullary
VERIFY_IS_APPROX_EVALUATOR(a3, Array33f::Zero()); // array
VERIFY_IS_APPROX_EVALUATOR(m3.transpose(), Matrix3f::Zero().transpose()); // transpose
VERIFY_IS_APPROX_EVALUATOR(m3, 2 * Matrix3f::Zero()); // unary
VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Zero() + m3); // binary
// test inner vectorization
Matrix4f m4, m4src = Matrix4f::Random();
Array44f a4, a4src = Matrix4f::Random();
VERIFY_IS_APPROX_EVALUATOR(m4, m4src); // matrix
VERIFY_IS_APPROX_EVALUATOR(a4, a4src); // array
VERIFY_IS_APPROX_EVALUATOR(m4.transpose(), m4src.transpose()); // transpose
// TODO: find out why Matrix4f::Zero() does not allow inner vectorization
VERIFY_IS_APPROX_EVALUATOR(m4, 2 * m4src); // unary
VERIFY_IS_APPROX_EVALUATOR(m4, m4src + m4src); // binary
// test linear vectorization
MatrixXf mX(6, 6), mXsrc = MatrixXf::Random(6, 6);
ArrayXXf aX(6, 6), aXsrc = ArrayXXf::Random(6, 6);
VERIFY_IS_APPROX_EVALUATOR(mX, mXsrc); // matrix
VERIFY_IS_APPROX_EVALUATOR(aX, aXsrc); // array
VERIFY_IS_APPROX_EVALUATOR(mX.transpose(), mXsrc.transpose()); // transpose
VERIFY_IS_APPROX_EVALUATOR(mX, MatrixXf::Zero(6, 6)); // nullary
VERIFY_IS_APPROX_EVALUATOR(mX, 2 * mXsrc); // unary
VERIFY_IS_APPROX_EVALUATOR(mX, mXsrc + mXsrc); // binary
// test blocks and slice vectorization
VERIFY_IS_APPROX_EVALUATOR(m4, (mXsrc.block<4, 4>(1, 0)));
VERIFY_IS_APPROX_EVALUATOR(aX, ArrayXXf::Constant(10, 10, 3.0).block(2, 3, 6, 6));
Matrix4f m4ref = m4;
copy_using_evaluator(m4.block(1, 1, 2, 3), m3.bottomRows(2));
m4ref.block(1, 1, 2, 3) = m3.bottomRows(2);
VERIFY_IS_APPROX(m4, m4ref);
mX.setIdentity(20, 20);
MatrixXf mXref = MatrixXf::Identity(20, 20);
mXsrc = MatrixXf::Random(9, 12);
copy_using_evaluator(mX.block(4, 4, 9, 12), mXsrc);
mXref.block(4, 4, 9, 12) = mXsrc;
VERIFY_IS_APPROX(mX, mXref);
// test Map
const float raw[3] = {1, 2, 3};
float buffer[3] = {0, 0, 0};
Vector3f v3;
Array3f a3f;
VERIFY_IS_APPROX_EVALUATOR(v3, Map<const Vector3f>(raw));
VERIFY_IS_APPROX_EVALUATOR(a3f, Map<const Array3f>(raw));
Vector3f::Map(buffer) = 2 * v3;
VERIFY(buffer[0] == 2);
VERIFY(buffer[1] == 4);
VERIFY(buffer[2] == 6);
// test CwiseUnaryView
mat1.setRandom();
mat2.setIdentity();
MatrixXcd matXcd(6, 6), matXcd_ref(6, 6);
copy_using_evaluator(matXcd.real(), mat1);
copy_using_evaluator(matXcd.imag(), mat2);
matXcd_ref.real() = mat1;
matXcd_ref.imag() = mat2;
VERIFY_IS_APPROX(matXcd, matXcd_ref);
// test select
VERIFY_IS_APPROX_EVALUATOR(aX, (aXsrc > 0).select(aXsrc, -aXsrc));
// test Replicate
mXsrc = MatrixXf::Random(6, 6);
VectorXf vX = VectorXf::Random(6);
mX.resize(6, 6);
VERIFY_IS_APPROX_EVALUATOR(mX, mXsrc.colwise() + vX);
matXcd.resize(12, 12);
VERIFY_IS_APPROX_EVALUATOR(matXcd, matXcd_ref.replicate(2, 2));
VERIFY_IS_APPROX_EVALUATOR(matXcd, (matXcd_ref.replicate<2, 2>()));
// test partial reductions
VectorXd vec1(6);
VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.rowwise().sum());
VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.colwise().sum().transpose());
// test MatrixWrapper and ArrayWrapper
mat1.setRandom(6, 6);
arr1.setRandom(6, 6);
VERIFY_IS_APPROX_EVALUATOR(mat2, arr1.matrix());
VERIFY_IS_APPROX_EVALUATOR(arr2, mat1.array());
VERIFY_IS_APPROX_EVALUATOR(mat2, (arr1 + 2).matrix());
VERIFY_IS_APPROX_EVALUATOR(arr2, mat1.array() + 2);
mat2.array() = arr1 * arr1;
VERIFY_IS_APPROX(mat2, (arr1 * arr1).matrix());
arr2.matrix() = MatrixXd::Identity(6, 6);
VERIFY_IS_APPROX(arr2, MatrixXd::Identity(6, 6).array());
// test Reverse
VERIFY_IS_APPROX_EVALUATOR(arr2, arr1.reverse());
VERIFY_IS_APPROX_EVALUATOR(arr2, arr1.colwise().reverse());
VERIFY_IS_APPROX_EVALUATOR(arr2, arr1.rowwise().reverse());
arr2.reverse() = arr1;
VERIFY_IS_APPROX(arr2, arr1.reverse());
mat2.array() = mat1.array().reverse();
VERIFY_IS_APPROX(mat2.array(), mat1.array().reverse());
// test Diagonal
VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.diagonal());
vec1.resize(5);
VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.diagonal(1));
VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.diagonal<-1>());
vec1.setRandom();
mat2 = mat1;
copy_using_evaluator(mat1.diagonal(1), vec1);
mat2.diagonal(1) = vec1;
VERIFY_IS_APPROX(mat1, mat2);
copy_using_evaluator(mat1.diagonal<-1>(), mat1.diagonal(1));
mat2.diagonal<-1>() = mat2.diagonal(1);
VERIFY_IS_APPROX(mat1, mat2);
}
{
// test swapping
MatrixXd mat1, mat2, mat1ref, mat2ref;
mat1ref = mat1 = MatrixXd::Random(6, 6);
mat2ref = mat2 = 2 * mat1 + MatrixXd::Identity(6, 6);
swap_using_evaluator(mat1, mat2);
mat1ref.swap(mat2ref);
VERIFY_IS_APPROX(mat1, mat1ref);
VERIFY_IS_APPROX(mat2, mat2ref);
swap_using_evaluator(mat1.block(0, 0, 3, 3), mat2.block(3, 3, 3, 3));
mat1ref.block(0, 0, 3, 3).swap(mat2ref.block(3, 3, 3, 3));
VERIFY_IS_APPROX(mat1, mat1ref);
VERIFY_IS_APPROX(mat2, mat2ref);
swap_using_evaluator(mat1.row(2), mat2.col(3).transpose());
mat1.row(2).swap(mat2.col(3).transpose());
VERIFY_IS_APPROX(mat1, mat1ref);
VERIFY_IS_APPROX(mat2, mat2ref);
}
{
// test compound assignment
const Matrix4d mat_const = Matrix4d::Random();
Matrix4d mat, mat_ref;
mat = mat_ref = Matrix4d::Identity();
add_assign_using_evaluator(mat, mat_const);
mat_ref += mat_const;
VERIFY_IS_APPROX(mat, mat_ref);
subtract_assign_using_evaluator(mat.row(1), 2 * mat.row(2));
mat_ref.row(1) -= 2 * mat_ref.row(2);
VERIFY_IS_APPROX(mat, mat_ref);
const ArrayXXf arr_const = ArrayXXf::Random(5, 3);
ArrayXXf arr, arr_ref;
arr = arr_ref = ArrayXXf::Constant(5, 3, 0.5);
multiply_assign_using_evaluator(arr, arr_const);
arr_ref *= arr_const;
VERIFY_IS_APPROX(arr, arr_ref);
divide_assign_using_evaluator(arr.row(1), arr.row(2) + 1);
arr_ref.row(1) /= (arr_ref.row(2) + 1);
VERIFY_IS_APPROX(arr, arr_ref);
}
{
// test triangular shapes
MatrixXd A = MatrixXd::Random(6, 6), B(6, 6), C(6, 6), D(6, 6);
A.setRandom();
B.setRandom();
VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView<Upper>(), MatrixXd(A.triangularView<Upper>()));
A.setRandom();
B.setRandom();
VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView<UnitLower>(), MatrixXd(A.triangularView<UnitLower>()));
A.setRandom();
B.setRandom();
VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView<UnitUpper>(), MatrixXd(A.triangularView<UnitUpper>()));
A.setRandom();
B.setRandom();
C = B;
C.triangularView<Upper>() = A;
copy_using_evaluator(B.triangularView<Upper>(), A);
VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView<Upper>(), A)");
A.setRandom();
B.setRandom();
C = B;
C.triangularView<Lower>() = A.triangularView<Lower>();
copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Lower>());
VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Lower>())");
A.setRandom();
B.setRandom();
C = B;
C.triangularView<Lower>() = A.triangularView<Upper>().transpose();
copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Upper>().transpose());
VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView<Lower>(), A.triangularView<Lower>().transpose())");
A.setRandom();
B.setRandom();
C = B;
D = A;
C.triangularView<Upper>().swap(D.triangularView<Upper>());
swap_using_evaluator(B.triangularView<Upper>(), A.triangularView<Upper>());
VERIFY(B.isApprox(C) && "swap_using_evaluator(B.triangularView<Upper>(), A.triangularView<Upper>())");
VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.triangularView<Upper>(), A), MatrixXd(A.triangularView<Upper>() * A));
VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.selfadjointView<Upper>(), A), MatrixXd(A.selfadjointView<Upper>() * A));
}
{
// test diagonal shapes
VectorXd d = VectorXd::Random(6);
MatrixXd A = MatrixXd::Random(6, 6), B(6, 6);
A.setRandom();
B.setRandom();
VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(d.asDiagonal(), A), MatrixXd(d.asDiagonal() * A));
VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(A, d.asDiagonal()), MatrixXd(A * d.asDiagonal()));
}
{
// test CoeffReadCost
Matrix4d a, b;
VERIFY_IS_EQUAL(get_cost(a), 1);
VERIFY_IS_EQUAL(get_cost(a + b), 3);
VERIFY_IS_EQUAL(get_cost(2 * a + b), 4);
VERIFY_IS_EQUAL(get_cost(a * b), 1);
VERIFY_IS_EQUAL(get_cost(a.lazyProduct(b)), 15);
VERIFY_IS_EQUAL(get_cost(a * (a * b)), 1);
VERIFY_IS_EQUAL(get_cost(a.lazyProduct(a * b)), 15);
VERIFY_IS_EQUAL(get_cost(a * (a + b)), 1);
VERIFY_IS_EQUAL(get_cost(a.lazyProduct(a + b)), 15);
}
// regression test for PR 544 and bug 1622 (introduced in #71609c4)
{
// test restricted_packet_assignment with an unaligned destination
const size_t M = 2;
const size_t K = 2;
const size_t N = 5;
float* destMem = new float[(M * N) + 1];
// In case of no alignment, avoid division by zero.
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
float* dest = (std::uintptr_t(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);
Map<Matrix<float, Dynamic, Dynamic, RowMajor> > z(dest, M, N);
;
Product<Matrix<float, Dynamic, Dynamic, RowMajor>, Matrix<float, Dynamic, Dynamic, RowMajor>, LazyProduct> tmp(a,
b);
internal::call_restricted_packet_assignment(z.noalias(), tmp.derived(), internal::assign_op<float, float>());
VERIFY_IS_APPROX(z, a * b);
delete[] destMem;
}
}
+55
View File
@@ -0,0 +1,55 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Various sanity tests with exceptions and non trivially copyable scalar type.
// - no memory leak when a custom scalar type throw an exceptions
// - todo: complete the list of tests!
#define EIGEN_STACK_ALLOCATION_LIMIT 100000000
#include "main.h"
#include "AnnoyingScalar.h"
#define CHECK_MEMLEAK(OP) \
{ \
AnnoyingScalar::countdown = 100; \
int before = AnnoyingScalar::instances; \
bool exception_thrown = false; \
EIGEN_TRY { OP; } \
EIGEN_CATCH(my_exception) { \
exception_thrown = true; \
VERIFY(AnnoyingScalar::instances == before && "memory leak detected in " && EIGEN_MAKESTRING(OP)); \
} \
VERIFY((AnnoyingScalar::dont_throw) || (exception_thrown && " no exception thrown in " && EIGEN_MAKESTRING(OP))); \
}
EIGEN_DECLARE_TEST(exceptions) {
typedef Eigen::Matrix<AnnoyingScalar, Dynamic, 1> VectorType;
typedef Eigen::Matrix<AnnoyingScalar, Dynamic, Dynamic> MatrixType;
{
#if defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW)
AnnoyingScalar::dont_throw = false;
#else
AnnoyingScalar::dont_throw = true;
#endif
int n = 50;
VectorType v0(n), v1(n);
MatrixType m0(n, n), m1(n, n), m2(n, n);
v0.setOnes();
v1.setOnes();
m0.setOnes();
m1.setOnes();
m2.setOnes();
CHECK_MEMLEAK(v0 = m0 * m1 * v1);
CHECK_MEMLEAK(m2 = m0 * m1 * m2);
CHECK_MEMLEAK((v0 + v1).dot(v0 + v1));
}
VERIFY(AnnoyingScalar::instances == 0 && "global memory leak detected in " && EIGEN_MAKESTRING(OP));
}
+209
View File
@@ -0,0 +1,209 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// 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
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
void check(bool b, bool ref) {
std::cout << b;
if (b == ref)
std::cout << " OK ";
else
std::cout << " BAD ";
}
#if EIGEN_COMP_MSVC && EIGEN_COMP_MSVC < 1800
namespace std {
template <typename T>
bool(isfinite)(T x) {
return _finite(x);
}
template <typename T>
bool(isnan)(T x) {
return _isnan(x);
}
template <typename T>
bool(isinf)(T x) {
return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF;
}
} // namespace std
#endif
template <typename T>
void check_inf_nan(bool dryrun) {
Matrix<T, Dynamic, 1> m(10);
m.setRandom();
m(3) = std::numeric_limits<T>::quiet_NaN();
if (dryrun) {
std::cout << "std::isfinite(" << m(3) << ") = ";
check((std::isfinite)(m(3)), false);
std::cout << " ; numext::isfinite = ";
check((numext::isfinite)(m(3)), false);
std::cout << "\n";
std::cout << "std::isinf(" << m(3) << ") = ";
check((std::isinf)(m(3)), false);
std::cout << " ; numext::isinf = ";
check((numext::isinf)(m(3)), false);
std::cout << "\n";
std::cout << "std::isnan(" << m(3) << ") = ";
check((std::isnan)(m(3)), true);
std::cout << " ; numext::isnan = ";
check((numext::isnan)(m(3)), true);
std::cout << "\n";
std::cout << "allFinite: ";
check(m.allFinite(), 0);
std::cout << "\n";
std::cout << "hasNaN: ";
check(m.hasNaN(), 1);
std::cout << "\n";
std::cout << "\n";
} else {
if ((std::isfinite)(m(3))) {
g_test_level = 1;
VERIFY(!(numext::isfinite)(m(3)));
g_test_level = 0;
}
if ((std::isinf)(m(3))) {
g_test_level = 1;
VERIFY(!(numext::isinf)(m(3)));
g_test_level = 0;
}
if (!(std::isnan)(m(3))) {
g_test_level = 1;
VERIFY((numext::isnan)(m(3)));
g_test_level = 0;
}
if ((std::isfinite)(m(3))) {
g_test_level = 1;
VERIFY(!m.allFinite());
g_test_level = 0;
}
if (!(std::isnan)(m(3))) {
g_test_level = 1;
VERIFY(m.hasNaN());
g_test_level = 0;
}
}
T hidden_zero = (std::numeric_limits<T>::min)() * (std::numeric_limits<T>::min)();
m(4) /= hidden_zero;
if (dryrun) {
std::cout << "std::isfinite(" << m(4) << ") = ";
check((std::isfinite)(m(4)), false);
std::cout << " ; numext::isfinite = ";
check((numext::isfinite)(m(4)), false);
std::cout << "\n";
std::cout << "std::isinf(" << m(4) << ") = ";
check((std::isinf)(m(4)), true);
std::cout << " ; numext::isinf = ";
check((numext::isinf)(m(4)), true);
std::cout << "\n";
std::cout << "std::isnan(" << m(4) << ") = ";
check((std::isnan)(m(4)), false);
std::cout << " ; numext::isnan = ";
check((numext::isnan)(m(4)), false);
std::cout << "\n";
std::cout << "allFinite: ";
check(m.allFinite(), 0);
std::cout << "\n";
std::cout << "hasNaN: ";
check(m.hasNaN(), 1);
std::cout << "\n";
std::cout << "\n";
} else {
if ((std::isfinite)(m(3))) {
g_test_level = 1;
VERIFY(!(numext::isfinite)(m(4)));
g_test_level = 0;
}
if (!(std::isinf)(m(3))) {
g_test_level = 1;
VERIFY((numext::isinf)(m(4)));
g_test_level = 0;
}
if ((std::isnan)(m(3))) {
g_test_level = 1;
VERIFY(!(numext::isnan)(m(4)));
g_test_level = 0;
}
if ((std::isfinite)(m(3))) {
g_test_level = 1;
VERIFY(!m.allFinite());
g_test_level = 0;
}
if (!(std::isnan)(m(3))) {
g_test_level = 1;
VERIFY(m.hasNaN());
g_test_level = 0;
}
}
m(3) = 0;
if (dryrun) {
std::cout << "std::isfinite(" << m(3) << ") = ";
check((std::isfinite)(m(3)), true);
std::cout << " ; numext::isfinite = ";
check((numext::isfinite)(m(3)), true);
std::cout << "\n";
std::cout << "std::isinf(" << m(3) << ") = ";
check((std::isinf)(m(3)), false);
std::cout << " ; numext::isinf = ";
check((numext::isinf)(m(3)), false);
std::cout << "\n";
std::cout << "std::isnan(" << m(3) << ") = ";
check((std::isnan)(m(3)), false);
std::cout << " ; numext::isnan = ";
check((numext::isnan)(m(3)), false);
std::cout << "\n";
std::cout << "allFinite: ";
check(m.allFinite(), 0);
std::cout << "\n";
std::cout << "hasNaN: ";
check(m.hasNaN(), 0);
std::cout << "\n";
std::cout << "\n\n";
} else {
if (!(std::isfinite)(m(3))) {
g_test_level = 1;
VERIFY((numext::isfinite)(m(3)));
g_test_level = 0;
}
if ((std::isinf)(m(3))) {
g_test_level = 1;
VERIFY(!(numext::isinf)(m(3)));
g_test_level = 0;
}
if ((std::isnan)(m(3))) {
g_test_level = 1;
VERIFY(!(numext::isnan)(m(3)));
g_test_level = 0;
}
if ((std::isfinite)(m(3))) {
g_test_level = 1;
VERIFY(!m.allFinite());
g_test_level = 0;
}
if ((std::isnan)(m(3))) {
g_test_level = 1;
VERIFY(!m.hasNaN());
g_test_level = 0;
}
}
}
EIGEN_DECLARE_TEST(fastmath) {
std::cout << "*** float *** \n\n";
check_inf_nan<float>(true);
std::cout << "*** double ***\n\n";
check_inf_nan<double>(true);
std::cout << "*** long double *** \n\n";
check_inf_nan<long double>(true);
check_inf_nan<float>(false);
check_inf_nan<double>(false);
check_inf_nan<long double>(false);
}
+50
View File
@@ -0,0 +1,50 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename Scalar>
void test_first_aligned_helper(Scalar *array, int size) {
const int packet_size = sizeof(Scalar) * internal::packet_traits<Scalar>::size;
VERIFY(((size_t(array) + sizeof(Scalar) * internal::first_default_aligned(array, size)) % packet_size) == 0);
}
template <typename Scalar>
void test_none_aligned_helper(Scalar *array, int size) {
EIGEN_UNUSED_VARIABLE(array);
EIGEN_UNUSED_VARIABLE(size);
VERIFY(internal::packet_traits<Scalar>::size == 1 || internal::first_default_aligned(array, size) == size);
}
struct some_non_vectorizable_type {
float x;
};
EIGEN_DECLARE_TEST(first_aligned) {
EIGEN_ALIGN16 float array_float[100];
test_first_aligned_helper(array_float, 50);
test_first_aligned_helper(array_float + 1, 50);
test_first_aligned_helper(array_float + 2, 50);
test_first_aligned_helper(array_float + 3, 50);
test_first_aligned_helper(array_float + 4, 50);
test_first_aligned_helper(array_float + 5, 50);
EIGEN_ALIGN16 double array_double[100];
test_first_aligned_helper(array_double, 50);
test_first_aligned_helper(array_double + 1, 50);
test_first_aligned_helper(array_double + 2, 50);
double *array_double_plus_4_bytes = (double *)(std::uintptr_t(array_double) + 4);
test_none_aligned_helper(array_double_plus_4_bytes, 50);
test_none_aligned_helper(array_double_plus_4_bytes + 1, 50);
some_non_vectorizable_type array_nonvec[100];
test_first_aligned_helper(array_nonvec, 100);
test_none_aligned_helper(array_nonvec, 100);
}
+50
View File
@@ -0,0 +1,50 @@
// 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 <sstream>
#include "main.h"
template <typename From, typename To>
void test_conversion() {
typedef Array<From, Dynamic, 1> ArrayXFrom;
typedef Array<To, Dynamic, 1> ArrayXTo;
typedef Array<double, Dynamic, 1> ArrayXDouble;
Index size = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
double from_min = static_cast<double>((std::numeric_limits<From>::min)());
double from_range = static_cast<double>((std::numeric_limits<From>::max)()) - from_min;
// ArrayXFrom::Random() only generates 32-bit values (#2749), so we generate
// doubles and scale to fit the range.
ArrayXDouble doubles = (ArrayXDouble::Random(size) + 1.0) * (from_range / 2.0) + from_min;
ArrayXFrom from = doubles.template cast<From>();
ArrayXTo to(size);
for (Index i = 0; i < size; ++i) {
to(i) = static_cast<To>(from(i));
}
VERIFY_IS_APPROX(from.template cast<To>(), to);
}
template <typename To>
void test_conversion_to() {
CALL_SUBTEST((test_conversion<int64_t, To>()));
CALL_SUBTEST((test_conversion<uint64_t, To>()));
CALL_SUBTEST((test_conversion<int32_t, To>()));
CALL_SUBTEST((test_conversion<uint32_t, To>()));
CALL_SUBTEST((test_conversion<int16_t, To>()));
CALL_SUBTEST((test_conversion<uint16_t, To>()));
CALL_SUBTEST((test_conversion<int8_t, To>()));
CALL_SUBTEST((test_conversion<uint8_t, To>()));
}
EIGEN_DECLARE_TEST(float_conversion) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST(test_conversion_to<float>());
CALL_SUBTEST(test_conversion_to<double>());
}
}
+521
View File
@@ -0,0 +1,521 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
using namespace std;
// NOTE the following workaround was needed on some 32 bits builds to kill extra precision of x87 registers.
// It seems that it is not needed anymore, but let's keep it here, just in case...
template <typename T>
EIGEN_DONT_INLINE void kill_extra_precision(T& /* x */) {
// This one worked but triggered a warning:
/* eigen_assert((void*)(&x) != (void*)0); */
// An alternative could be:
/* volatile T tmp = x; */
/* x = tmp; */
}
template <typename BoxType>
void alignedbox(const BoxType& box) {
/* this test covers the following files:
AlignedBox.h
*/
typedef typename BoxType::Scalar Scalar;
typedef NumTraits<Scalar> ScalarTraits;
typedef typename ScalarTraits::Real RealScalar;
typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
const Index dim = box.dim();
VectorType p0 = VectorType::Random(dim) / Scalar(2);
VectorType p1 = VectorType::Random(dim) / Scalar(2);
while (p1 == p0) {
p1 = VectorType::Random(dim) / Scalar(2);
}
RealScalar s1 = internal::random<RealScalar>(0, 1);
BoxType b0(dim);
BoxType b1(VectorType::Random(dim), VectorType::Random(dim));
BoxType b2;
kill_extra_precision(b1);
kill_extra_precision(p0);
kill_extra_precision(p1);
VERIFY(numext::equal_strict(b0.volume(), Scalar(0)));
b0.extend(p0);
b0.extend(p1);
VERIFY(b0.contains(p0 * s1 + (Scalar(1) - s1) * p1));
VERIFY(b0.contains(b0.center()));
VERIFY_IS_APPROX(b0.center(), (p0 + p1) / Scalar(2));
(b2 = b0).extend(b1);
VERIFY(b2.contains(b0));
VERIFY(b2.contains(b1));
VERIFY_IS_APPROX(b2.clamp(b0), b0);
// intersection
BoxType box1(VectorType::Random(dim));
box1.extend(VectorType::Random(dim));
BoxType box2(VectorType::Random(dim));
box2.extend(VectorType::Random(dim));
VERIFY(box1.intersects(box2) == !box1.intersection(box2).isEmpty());
// alignment -- make sure there is no memory alignment assertion
BoxType* bp0 = new BoxType(dim);
BoxType* bp1 = new BoxType(dim);
bp0->extend(*bp1);
delete bp0;
delete bp1;
// sampling
for (int i = 0; i < 10; ++i) {
VectorType r = b0.sample();
VERIFY(b0.contains(r));
}
}
template <typename BoxType>
void alignedboxTranslatable(const BoxType& box) {
typedef typename BoxType::Scalar Scalar;
typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
typedef Transform<Scalar, BoxType::AmbientDimAtCompileTime, Isometry> IsometryTransform;
typedef Transform<Scalar, BoxType::AmbientDimAtCompileTime, Affine> AffineTransform;
alignedbox(box);
const VectorType Ones = VectorType::Ones();
const VectorType UnitX = VectorType::UnitX();
const Index dim = box.dim();
// box((-1, -1, -1), (1, 1, 1))
BoxType a(-Ones, Ones);
VERIFY_IS_APPROX(a.sizes(), Ones * Scalar(2));
BoxType b = a;
VectorType translate = Ones;
translate[0] = Scalar(2);
b.translate(translate);
// translate by (2, 1, 1) -> box((1, 0, 0), (3, 2, 2))
VERIFY_IS_APPROX(b.sizes(), Ones * Scalar(2));
VERIFY_IS_APPROX((b.min)(), UnitX);
VERIFY_IS_APPROX((b.max)(), Ones * Scalar(2) + UnitX);
// Test transform
IsometryTransform tf = IsometryTransform::Identity();
tf.translation() = -translate;
BoxType c = b.transformed(tf);
// translate by (-2, -1, -1) -> box((-1, -1, -1), (1, 1, 1))
VERIFY_IS_APPROX(c.sizes(), a.sizes());
VERIFY_IS_APPROX((c.min)(), (a.min)());
VERIFY_IS_APPROX((c.max)(), (a.max)());
c.transform(tf);
// translate by (-2, -1, -1) -> box((-3, -2, -2), (-1, 0, 0))
VERIFY_IS_APPROX(c.sizes(), a.sizes());
VERIFY_IS_APPROX((c.min)(), Ones * Scalar(-2) - UnitX);
VERIFY_IS_APPROX((c.max)(), -UnitX);
// Scaling
AffineTransform atf = AffineTransform::Identity();
atf.scale(Scalar(3));
c.transform(atf);
// scale by 3 -> box((-9, -6, -6), (-3, 0, 0))
VERIFY_IS_APPROX(c.sizes(), Scalar(3) * a.sizes());
VERIFY_IS_APPROX((c.min)(), Ones * Scalar(-6) - UnitX * Scalar(3));
VERIFY_IS_APPROX((c.max)(), UnitX * Scalar(-3));
atf = AffineTransform::Identity();
atf.scale(Scalar(-3));
c.transform(atf);
// scale by -3 -> box((27, 18, 18), (9, 0, 0))
VERIFY_IS_APPROX(c.sizes(), Scalar(9) * a.sizes());
VERIFY_IS_APPROX((c.min)(), UnitX * Scalar(9));
VERIFY_IS_APPROX((c.max)(), Ones * Scalar(18) + UnitX * Scalar(9));
// Check identity transform within numerical precision.
BoxType transformedC = c.transformed(IsometryTransform::Identity());
VERIFY_IS_APPROX(transformedC, c);
for (size_t i = 0; i < 10; ++i) {
VectorType minCorner;
VectorType maxCorner;
for (Index d = 0; d < dim; ++d) {
minCorner[d] = internal::random<Scalar>(-10, 10);
maxCorner[d] = minCorner[d] + internal::random<Scalar>(0, 10);
}
c = BoxType(minCorner, maxCorner);
translate = VectorType::Random();
c.translate(translate);
VERIFY_IS_APPROX((c.min)(), minCorner + translate);
VERIFY_IS_APPROX((c.max)(), maxCorner + translate);
}
}
template <typename Scalar, typename Rotation>
Rotation rotate2D(Scalar angle) {
return Rotation2D<Scalar>(angle);
}
template <typename Scalar, typename Rotation>
Rotation rotate2DIntegral(typename NumTraits<Scalar>::NonInteger angle) {
typedef typename NumTraits<Scalar>::NonInteger NonInteger;
return Rotation2D<NonInteger>(angle).toRotationMatrix().template cast<Scalar>();
}
template <typename Scalar, typename Rotation>
Rotation rotate3DZAxis(Scalar angle) {
return AngleAxis<Scalar>(angle, Matrix<Scalar, 3, 1>(0, 0, 1));
}
template <typename Scalar, typename Rotation>
Rotation rotate3DZAxisIntegral(typename NumTraits<Scalar>::NonInteger angle) {
typedef typename NumTraits<Scalar>::NonInteger NonInteger;
return AngleAxis<NonInteger>(angle, Matrix<NonInteger, 3, 1>(0, 0, 1)).toRotationMatrix().template cast<Scalar>();
}
template <typename Scalar, typename Rotation>
Rotation rotate4DZWAxis(Scalar angle) {
Rotation result = Matrix<Scalar, 4, 4>::Identity();
result.block(0, 0, 3, 3) = rotate3DZAxis<Scalar, AngleAxisd>(angle).toRotationMatrix();
return result;
}
template <typename MatrixType>
MatrixType randomRotationMatrix() {
// algorithm from
// 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, 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;
const MatrixType rotation = svd.matrixU() * diag * svd.matrixV().transpose();
return rotation;
}
template <typename Scalar, int Dim>
Matrix<Scalar, Dim, (1 << Dim)> boxGetCorners(const Matrix<Scalar, Dim, 1>& min_, const Matrix<Scalar, Dim, 1>& max_) {
Matrix<Scalar, Dim, (1 << Dim)> result;
for (Index i = 0; i < (1 << Dim); ++i) {
for (Index j = 0; j < Dim; ++j) result(j, i) = (i & (Index(1) << j)) ? min_(j) : max_(j);
}
return result;
}
template <typename BoxType, typename Rotation>
void alignedboxRotatable(const BoxType& box,
Rotation (*rotate)(typename NumTraits<typename BoxType::Scalar>::NonInteger /*_angle*/)) {
alignedboxTranslatable(box);
typedef typename BoxType::Scalar Scalar;
typedef typename NumTraits<Scalar>::NonInteger NonInteger;
typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
typedef Transform<Scalar, BoxType::AmbientDimAtCompileTime, Isometry> IsometryTransform;
typedef Transform<Scalar, BoxType::AmbientDimAtCompileTime, Affine> AffineTransform;
const VectorType Zero = VectorType::Zero();
const VectorType Ones = VectorType::Ones();
const VectorType UnitX = VectorType::UnitX();
const VectorType UnitY = VectorType::UnitY();
// this is vector (0, 0, -1, -1, -1, ...), i.e. with zeros at first and second dimensions
const VectorType UnitZ = Ones - UnitX - UnitY;
// in this kind of comments the 3D case values will be illustrated
// box((-1, -1, -1), (1, 1, 1))
BoxType a(-Ones, Ones);
// to allow templating this test for both 2D and 3D cases, we always set all
// but the first coordinate to the same value; so basically 3D case works as
// if you were looking at the scene from top
VectorType minPoint = -2 * Ones;
minPoint[0] = -3;
VectorType maxPoint = Zero;
maxPoint[0] = -1;
BoxType c(minPoint, maxPoint);
// box((-3, -2, -2), (-1, 0, 0))
IsometryTransform tf2 = IsometryTransform::Identity();
// for some weird reason the following statement has to be put separate from
// the following rotate call, otherwise precision problems arise...
Rotation rot = rotate(NonInteger(EIGEN_PI));
tf2.rotate(rot);
c.transform(tf2);
// rotate by 180 deg around origin -> box((1, 0, -2), (3, 2, 0))
VERIFY_IS_APPROX(c.sizes(), a.sizes());
VERIFY_IS_APPROX((c.min)(), UnitX - UnitZ * Scalar(2));
VERIFY_IS_APPROX((c.max)(), UnitX * Scalar(3) + UnitY * Scalar(2));
rot = rotate(NonInteger(EIGEN_PI / 2));
tf2.setIdentity();
tf2.rotate(rot);
c.transform(tf2);
// rotate by 90 deg around origin -> box((-2, 1, -2), (0, 3, 0))
VERIFY_IS_APPROX(c.sizes(), a.sizes());
VERIFY_IS_APPROX((c.min)(), Ones * Scalar(-2) + UnitY * Scalar(3));
VERIFY_IS_APPROX((c.max)(), UnitY * Scalar(3));
// box((-1, -1, -1), (1, 1, 1))
AffineTransform atf = AffineTransform::Identity();
atf.linearExt()(0, 1) = Scalar(1);
c = BoxType(-Ones, Ones);
c.transform(atf);
// 45 deg shear in x direction -> box((-2, -1, -1), (2, 1, 1))
VERIFY_IS_APPROX(c.sizes(), Ones * Scalar(2) + UnitX * Scalar(2));
VERIFY_IS_APPROX((c.min)(), -Ones - UnitX);
VERIFY_IS_APPROX((c.max)(), Ones + UnitX);
}
template <typename BoxType, typename Rotation>
void alignedboxNonIntegralRotatable(
const BoxType& box, Rotation (*rotate)(typename NumTraits<typename BoxType::Scalar>::NonInteger /*_angle*/)) {
alignedboxRotatable(box, rotate);
typedef typename BoxType::Scalar Scalar;
typedef typename NumTraits<Scalar>::NonInteger NonInteger;
enum { Dim = BoxType::AmbientDimAtCompileTime };
typedef Matrix<Scalar, Dim, 1> VectorType;
typedef Matrix<Scalar, Dim, (1 << Dim)> CornersType;
typedef Transform<Scalar, Dim, Isometry> IsometryTransform;
typedef Transform<Scalar, Dim, Affine> AffineTransform;
const Index dim = box.dim();
const VectorType Zero = VectorType::Zero();
const VectorType Ones = VectorType::Ones();
VectorType minPoint = -2 * Ones;
minPoint[1] = 1;
VectorType maxPoint = Zero;
maxPoint[1] = 3;
BoxType c(minPoint, maxPoint);
// ((-2, 1, -2), (0, 3, 0))
VectorType cornerBL = (c.min)();
VectorType cornerTR = (c.max)();
VectorType cornerBR = (c.min)();
cornerBR[0] = cornerTR[0];
VectorType cornerTL = (c.max)();
cornerTL[0] = cornerBL[0];
NonInteger angle = NonInteger(EIGEN_PI / 3);
Rotation rot = rotate(angle);
IsometryTransform tf2;
tf2.setIdentity();
tf2.rotate(rot);
c.transform(tf2);
// rotate by 60 deg -> box((-3.59, -1.23, -2), (-0.86, 1.5, 0))
cornerBL = tf2 * cornerBL;
cornerBR = tf2 * cornerBR;
cornerTL = tf2 * cornerTL;
cornerTR = tf2 * cornerTR;
VectorType minCorner = Ones * Scalar(-2);
VectorType maxCorner = Zero;
minCorner[0] = (min)((min)(cornerBL[0], cornerBR[0]), (min)(cornerTL[0], cornerTR[0]));
maxCorner[0] = (max)((max)(cornerBL[0], cornerBR[0]), (max)(cornerTL[0], cornerTR[0]));
minCorner[1] = (min)((min)(cornerBL[1], cornerBR[1]), (min)(cornerTL[1], cornerTR[1]));
maxCorner[1] = (max)((max)(cornerBL[1], cornerBR[1]), (max)(cornerTL[1], cornerTR[1]));
for (Index d = 2; d < dim; ++d) VERIFY_IS_APPROX(c.sizes()[d], Scalar(2));
VERIFY_IS_APPROX((c.min)(), minCorner);
VERIFY_IS_APPROX((c.max)(), maxCorner);
VectorType minCornerValue = Ones * Scalar(-2);
VectorType maxCornerValue = Zero;
minCornerValue[0] = Scalar(Scalar(-sqrt(2 * 2 + 3 * 3)) * Scalar(cos(Scalar(atan(2.0 / 3.0)) - angle / 2)));
minCornerValue[1] = Scalar(Scalar(-sqrt(1 * 1 + 2 * 2)) * Scalar(sin(Scalar(atan(2.0 / 1.0)) - angle / 2)));
maxCornerValue[0] = Scalar(-sin(angle));
maxCornerValue[1] = Scalar(3 * cos(angle));
VERIFY_IS_APPROX((c.min)(), minCornerValue);
VERIFY_IS_APPROX((c.max)(), maxCornerValue);
// randomized test - translate and rotate the box and compare to a box made of transformed vertices
for (size_t i = 0; i < 10; ++i) {
for (Index d = 0; d < dim; ++d) {
minCorner[d] = internal::random<Scalar>(-10, 10);
maxCorner[d] = minCorner[d] + internal::random<Scalar>(0, 10);
}
c = BoxType(minCorner, maxCorner);
CornersType corners = boxGetCorners(minCorner, maxCorner);
typename AffineTransform::LinearMatrixType rotation =
randomRotationMatrix<typename AffineTransform::LinearMatrixType>();
tf2.setIdentity();
tf2.rotate(rotation);
tf2.translate(VectorType::Random());
c.transform(tf2);
corners = tf2 * corners;
minCorner = corners.rowwise().minCoeff();
maxCorner = corners.rowwise().maxCoeff();
VERIFY_IS_APPROX((c.min)(), minCorner);
VERIFY_IS_APPROX((c.max)(), maxCorner);
}
// randomized test - transform the box with a random affine matrix and compare to a box made of transformed vertices
for (size_t i = 0; i < 10; ++i) {
for (Index d = 0; d < dim; ++d) {
minCorner[d] = internal::random<Scalar>(-10, 10);
maxCorner[d] = minCorner[d] + internal::random<Scalar>(0, 10);
}
c = BoxType(minCorner, maxCorner);
CornersType corners = boxGetCorners(minCorner, maxCorner);
AffineTransform atf = AffineTransform::Identity();
atf.linearExt() = AffineTransform::LinearPart::Random();
atf.translate(VectorType::Random());
c.transform(atf);
corners = atf * corners;
minCorner = corners.rowwise().minCoeff();
maxCorner = corners.rowwise().maxCoeff();
VERIFY_IS_APPROX((c.min)(), minCorner);
VERIFY_IS_APPROX((c.max)(), maxCorner);
}
}
template <typename BoxType>
void alignedboxCastTests(const BoxType& box) {
// casting
typedef typename BoxType::Scalar Scalar;
typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;
const Index dim = box.dim();
VectorType p0 = VectorType::Random(dim);
VectorType p1 = VectorType::Random(dim);
BoxType b0(dim);
VERIFY(numext::equal_strict(b0.volume(), Scalar(0)));
b0.extend(p0);
b0.extend(p1);
const int Dim = BoxType::AmbientDimAtCompileTime;
typedef typename GetDifferentType<Scalar>::type OtherScalar;
AlignedBox<OtherScalar, Dim> hp1f = b0.template cast<OtherScalar>();
VERIFY_IS_APPROX(hp1f.template cast<Scalar>(), b0);
AlignedBox<Scalar, Dim> hp1d = b0.template cast<Scalar>();
VERIFY_IS_APPROX(hp1d.template cast<Scalar>(), b0);
}
void specificTest1() {
Vector2f m;
m << -1.0f, -2.0f;
Vector2f M;
M << 1.0f, 5.0f;
typedef AlignedBox2f BoxType;
BoxType box(m, M);
Vector2f sides = M - m;
VERIFY_IS_APPROX(sides, box.sizes());
VERIFY_IS_APPROX(sides[1], box.sizes()[1]);
VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff());
VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff());
VERIFY_IS_APPROX(14.0f, box.volume());
VERIFY_IS_APPROX(53.0f, box.diagonal().squaredNorm());
VERIFY_IS_APPROX(std::sqrt(53.0f), box.diagonal().norm());
VERIFY_IS_APPROX(m, box.corner(BoxType::BottomLeft));
VERIFY_IS_APPROX(M, box.corner(BoxType::TopRight));
Vector2f bottomRight;
bottomRight << M[0], m[1];
Vector2f topLeft;
topLeft << m[0], M[1];
VERIFY_IS_APPROX(bottomRight, box.corner(BoxType::BottomRight));
VERIFY_IS_APPROX(topLeft, box.corner(BoxType::TopLeft));
}
void specificTest2() {
Vector3i m;
m << -1, -2, 0;
Vector3i M;
M << 1, 5, 3;
typedef AlignedBox3i BoxType;
BoxType box(m, M);
Vector3i sides = M - m;
VERIFY_IS_APPROX(sides, box.sizes());
VERIFY_IS_APPROX(sides[1], box.sizes()[1]);
VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff());
VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff());
VERIFY_IS_APPROX(42, box.volume());
VERIFY_IS_APPROX(62, box.diagonal().squaredNorm());
VERIFY_IS_APPROX(m, box.corner(BoxType::BottomLeftFloor));
VERIFY_IS_APPROX(M, box.corner(BoxType::TopRightCeil));
Vector3i bottomRightFloor;
bottomRightFloor << M[0], m[1], m[2];
Vector3i topLeftFloor;
topLeftFloor << m[0], M[1], m[2];
VERIFY_IS_APPROX(bottomRightFloor, box.corner(BoxType::BottomRightFloor));
VERIFY_IS_APPROX(topLeftFloor, box.corner(BoxType::TopLeftFloor));
}
EIGEN_DECLARE_TEST(geo_alignedbox) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1((alignedboxNonIntegralRotatable<AlignedBox2f, Rotation2Df>(AlignedBox2f(), &rotate2D)));
CALL_SUBTEST_2(alignedboxCastTests(AlignedBox2f()));
CALL_SUBTEST_3((alignedboxNonIntegralRotatable<AlignedBox3f, AngleAxisf>(AlignedBox3f(), &rotate3DZAxis)));
CALL_SUBTEST_4(alignedboxCastTests(AlignedBox3f()));
CALL_SUBTEST_5((alignedboxNonIntegralRotatable<AlignedBox4d, Matrix4d>(AlignedBox4d(), &rotate4DZWAxis)));
CALL_SUBTEST_6(alignedboxCastTests(AlignedBox4d()));
CALL_SUBTEST_7(alignedboxTranslatable(AlignedBox1d()));
CALL_SUBTEST_8(alignedboxCastTests(AlignedBox1d()));
CALL_SUBTEST_9(alignedboxTranslatable(AlignedBox1i()));
CALL_SUBTEST_10((alignedboxRotatable<AlignedBox2i, Matrix2i>(AlignedBox2i(), &rotate2DIntegral<int, Matrix2i>)));
CALL_SUBTEST_11(
(alignedboxRotatable<AlignedBox3i, Matrix3i>(AlignedBox3i(), &rotate3DZAxisIntegral<int, Matrix3i>)));
CALL_SUBTEST_14(alignedbox(AlignedBox<double, Dynamic>(4)));
}
CALL_SUBTEST_12(specificTest1());
CALL_SUBTEST_13(specificTest2());
}
+203
View File
@@ -0,0 +1,203 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2012 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2023 Juraj Oršulić, University of Zagreb <juraj.orsulic@fer.hr>
//
// 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/.
// Silence warnings about using the deprecated non-canonical .eulerAngles(), which are still being tested.
#define EIGEN_NO_DEPRECATED_WARNING
#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/SVD>
template <typename Scalar>
void verify_euler(const Matrix<Scalar, 3, 1>& ea, int i, int j, int k) {
typedef Matrix<Scalar, 3, 3> Matrix3;
typedef Matrix<Scalar, 3, 1> Vector3;
typedef AngleAxis<Scalar> AngleAxisx;
const Matrix3 m(AngleAxisx(ea[0], Vector3::Unit(i)) * AngleAxisx(ea[1], Vector3::Unit(j)) *
AngleAxisx(ea[2], Vector3::Unit(k)));
const Scalar kPi = Scalar(EIGEN_PI);
// Test non-canonical eulerAngles
{
Vector3 eabis = m.eulerAngles(i, j, k);
Matrix3 mbis(AngleAxisx(eabis[0], Vector3::Unit(i)) * AngleAxisx(eabis[1], Vector3::Unit(j)) *
AngleAxisx(eabis[2], Vector3::Unit(k)));
VERIFY_IS_APPROX(m, mbis);
// approx_or_less_than does not work for 0
VERIFY(0 < eabis[0] || test_isMuchSmallerThan(eabis[0], Scalar(1)));
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], kPi);
VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[1]);
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], kPi);
VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[2]);
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], kPi);
}
// Test canonicalEulerAngles
{
Vector3 eabis = m.canonicalEulerAngles(i, j, k);
Matrix3 mbis(AngleAxisx(eabis[0], Vector3::Unit(i)) * AngleAxisx(eabis[1], Vector3::Unit(j)) *
AngleAxisx(eabis[2], Vector3::Unit(k)));
VERIFY_IS_APPROX(m, mbis);
VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[0]);
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], kPi);
if (i != k) {
// Tait-Bryan sequence
VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(kPi / 2), eabis[1]);
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(kPi / 2));
} else {
// Proper Euler sequence
// approx_or_less_than does not work for 0
VERIFY(0 < eabis[1] || test_isMuchSmallerThan(eabis[1], Scalar(1)));
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], kPi);
}
VERIFY_IS_APPROX_OR_LESS_THAN(-kPi, eabis[2]);
VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], kPi);
}
}
template <typename Scalar>
void check_all_var(const Matrix<Scalar, 3, 1>& ea) {
auto verify_permutation = [](const Matrix<Scalar, 3, 1>& eap) {
verify_euler(eap, 0, 1, 2);
verify_euler(eap, 0, 1, 0);
verify_euler(eap, 0, 2, 1);
verify_euler(eap, 0, 2, 0);
verify_euler(eap, 1, 2, 0);
verify_euler(eap, 1, 2, 1);
verify_euler(eap, 1, 0, 2);
verify_euler(eap, 1, 0, 1);
verify_euler(eap, 2, 0, 1);
verify_euler(eap, 2, 0, 2);
verify_euler(eap, 2, 1, 0);
verify_euler(eap, 2, 1, 2);
};
int i, j, k;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
for (k = 0; k < 3; k++) {
Matrix<Scalar, 3, 1> eap(ea(i), ea(j), ea(k));
verify_permutation(eap);
}
}
template <typename Scalar>
void eulerangles() {
typedef Matrix<Scalar, 3, 3> Matrix3;
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Array<Scalar, 3, 1> Array3;
typedef Quaternion<Scalar> Quaternionx;
typedef AngleAxis<Scalar> AngleAxisx;
const Scalar kPi = Scalar(EIGEN_PI);
const Scalar smallVal = static_cast<Scalar>(0.001);
Scalar a = internal::random<Scalar>(-kPi, kPi);
Quaternionx q1;
q1 = AngleAxisx(a, Vector3::Random().normalized());
Matrix3 m;
m = q1;
Vector3 ea = m.eulerAngles(0, 1, 2);
check_all_var(ea);
ea = m.eulerAngles(0, 1, 0);
check_all_var(ea);
// Check with purely random Quaternion:
q1.coeffs() = Quaternionx::Coefficients::Random().normalized();
m = q1;
ea = m.eulerAngles(0, 1, 2);
check_all_var(ea);
ea = m.eulerAngles(0, 1, 0);
check_all_var(ea);
// Check with random angles in range [-pi:pi]x[-pi:pi]x[-pi:pi].
ea = Array3::Random() * kPi;
check_all_var(ea);
auto test_with_some_zeros = [=](const Vector3& eaz) {
check_all_var(eaz);
Vector3 ea_glz = eaz;
ea_glz[0] = Scalar(0);
check_all_var(ea_glz);
ea_glz[0] = internal::random<Scalar>(-smallVal, smallVal);
check_all_var(ea_glz);
ea_glz[2] = Scalar(0);
check_all_var(ea_glz);
ea_glz[2] = internal::random<Scalar>(-smallVal, smallVal);
check_all_var(ea_glz);
};
// Check gimbal lock configurations and a bit noisy gimbal locks
Vector3 ea_gl = ea;
ea_gl[1] = kPi / 2;
test_with_some_zeros(ea_gl);
ea_gl[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea_gl[1] = -kPi / 2;
test_with_some_zeros(ea_gl);
ea_gl[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea_gl[1] = kPi / 2;
ea_gl[2] = ea_gl[0];
test_with_some_zeros(ea_gl);
ea_gl[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea_gl[1] = -kPi / 2;
test_with_some_zeros(ea_gl);
ea_gl[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
// Similar to above, but with pi instead of pi/2
Vector3 ea_pi = ea;
ea_pi[1] = kPi;
test_with_some_zeros(ea_gl);
ea_pi[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea_pi[1] = -kPi;
test_with_some_zeros(ea_gl);
ea_pi[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea_pi[1] = kPi;
ea_pi[2] = ea_pi[0];
test_with_some_zeros(ea_gl);
ea_pi[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea_pi[1] = -kPi;
test_with_some_zeros(ea_gl);
ea_pi[1] += internal::random<Scalar>(-smallVal, smallVal);
test_with_some_zeros(ea_gl);
ea[2] = ea[0] = internal::random<Scalar>(0, kPi);
check_all_var(ea);
ea[0] = ea[1] = internal::random<Scalar>(0, kPi);
check_all_var(ea);
ea[1] = 0;
check_all_var(ea);
ea.head(2).setZero();
check_all_var(ea);
ea.setZero();
check_all_var(ea);
}
EIGEN_DECLARE_TEST(geo_eulerangles) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(eulerangles<float>());
CALL_SUBTEST_2(eulerangles<double>());
}
}
+144
View File
@@ -0,0 +1,144 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
template <typename Scalar, int Size>
void homogeneous(void) {
/* this test covers the following files:
Homogeneous.h
*/
typedef Matrix<Scalar, Size, Size> MatrixType;
typedef Matrix<Scalar, Size, 1, ColMajor> VectorType;
typedef Matrix<Scalar, Size + 1, Size> HMatrixType;
typedef Matrix<Scalar, Size + 1, 1> HVectorType;
typedef Matrix<Scalar, Size, Size + 1> T1MatrixType;
typedef Matrix<Scalar, Size + 1, Size + 1> T2MatrixType;
typedef Matrix<Scalar, Size + 1, Size> T3MatrixType;
VectorType v0 = VectorType::Random(), ones = VectorType::Ones();
HVectorType hv0 = HVectorType::Random();
MatrixType m0 = MatrixType::Random();
HMatrixType hm0 = HMatrixType::Random();
hv0 << v0, 1;
VERIFY_IS_APPROX(v0.homogeneous(), hv0);
VERIFY_IS_APPROX(v0, hv0.hnormalized());
VERIFY_IS_APPROX(v0.homogeneous().sum(), hv0.sum());
VERIFY_IS_APPROX(v0.homogeneous().minCoeff(), hv0.minCoeff());
VERIFY_IS_APPROX(v0.homogeneous().maxCoeff(), hv0.maxCoeff());
hm0 << m0, ones.transpose();
VERIFY_IS_APPROX(m0.colwise().homogeneous(), hm0);
VERIFY_IS_APPROX(m0, hm0.colwise().hnormalized());
hm0.row(Size - 1).setRandom();
for (int j = 0; j < Size; ++j) m0.col(j) = hm0.col(j).head(Size) / hm0(Size, j);
VERIFY_IS_APPROX(m0, hm0.colwise().hnormalized());
T1MatrixType t1 = T1MatrixType::Random();
VERIFY_IS_APPROX(t1 * (v0.homogeneous().eval()), t1 * v0.homogeneous());
VERIFY_IS_APPROX(t1 * (m0.colwise().homogeneous().eval()), t1 * m0.colwise().homogeneous());
T2MatrixType t2 = T2MatrixType::Random();
VERIFY_IS_APPROX(t2 * (v0.homogeneous().eval()), t2 * v0.homogeneous());
VERIFY_IS_APPROX(t2 * (m0.colwise().homogeneous().eval()), t2 * m0.colwise().homogeneous());
VERIFY_IS_APPROX(t2 * (v0.homogeneous().asDiagonal()), t2 * hv0.asDiagonal());
VERIFY_IS_APPROX((v0.homogeneous().asDiagonal()) * t2, hv0.asDiagonal() * t2);
VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t2, v0.transpose().rowwise().homogeneous() * t2);
VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t2, m0.transpose().rowwise().homogeneous() * t2);
T3MatrixType t3 = T3MatrixType::Random();
VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t3, v0.transpose().rowwise().homogeneous() * t3);
VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t3, m0.transpose().rowwise().homogeneous() * t3);
// test product with a Transform object
Transform<Scalar, Size, Affine> aff;
Transform<Scalar, Size, AffineCompact> caff;
Transform<Scalar, Size, Projective> proj;
Matrix<Scalar, Size, Dynamic> pts;
Matrix<Scalar, Size + 1, Dynamic> pts1, pts2;
aff.affine().setRandom();
proj = caff = aff;
pts.setRandom(Size, internal::random<int>(1, 20));
pts1 = pts.colwise().homogeneous();
VERIFY_IS_APPROX(aff * pts.colwise().homogeneous(), (aff * pts1).colwise().hnormalized());
VERIFY_IS_APPROX(caff * pts.colwise().homogeneous(), (caff * pts1).colwise().hnormalized());
VERIFY_IS_APPROX(proj * pts.colwise().homogeneous(), (proj * pts1));
VERIFY_IS_APPROX((aff * pts1).colwise().hnormalized(), aff * pts);
VERIFY_IS_APPROX((caff * pts1).colwise().hnormalized(), caff * pts);
pts2 = pts1;
pts2.row(Size).setRandom();
VERIFY_IS_APPROX((aff * pts2).colwise().hnormalized(), aff * pts2.colwise().hnormalized());
VERIFY_IS_APPROX((caff * pts2).colwise().hnormalized(), caff * pts2.colwise().hnormalized());
VERIFY_IS_APPROX((proj * pts2).colwise().hnormalized(),
(proj * pts2.colwise().hnormalized().colwise().homogeneous()).colwise().hnormalized());
// Test combination of homogeneous
VERIFY_IS_APPROX((t2 * v0.homogeneous()).hnormalized(),
(t2.template topLeftCorner<Size, Size>() * v0 + t2.template topRightCorner<Size, 1>()) /
((t2.template bottomLeftCorner<1, Size>() * v0).value() + t2(Size, Size)));
VERIFY_IS_APPROX((t2 * pts.colwise().homogeneous()).colwise().hnormalized(),
(Matrix<Scalar, Size + 1, Dynamic>(t2 * pts1).colwise().hnormalized()));
VERIFY_IS_APPROX((t2.lazyProduct(v0.homogeneous())).hnormalized(), (t2 * v0.homogeneous()).hnormalized());
VERIFY_IS_APPROX((t2.lazyProduct(pts.colwise().homogeneous())).colwise().hnormalized(),
(t2 * pts1).colwise().hnormalized());
VERIFY_IS_APPROX((v0.transpose().homogeneous().lazyProduct(t2)).hnormalized(),
(v0.transpose().homogeneous() * t2).hnormalized());
VERIFY_IS_APPROX((pts.transpose().rowwise().homogeneous().lazyProduct(t2)).rowwise().hnormalized(),
(pts1.transpose() * t2).rowwise().hnormalized());
VERIFY_IS_APPROX((t2.template triangularView<Lower>() * v0.homogeneous()).eval(),
(t2.template triangularView<Lower>() * hv0));
{
const MatrixType points = MatrixType::Random();
const VectorType center = VectorType::Random();
const auto pts3 = points.rowwise() - center.transpose();
const auto pts_xy1 = pts3.template leftCols<Size - 1>().rowwise().homogeneous();
const auto pts_xy2 = pts3.template topRows<Size - 1>().colwise().homogeneous();
VERIFY_IS_APPROX(pts_xy1.transpose() * pts_xy1, pts_xy1.transpose() * pts_xy1.eval());
VERIFY_IS_APPROX(pts_xy2 * pts_xy2.transpose(), pts_xy2.eval() * pts_xy2.transpose());
}
{
const Eigen::PermutationMatrix<Size> P{Eigen::Vector<int, Size>::EqualSpaced(0, 1)};
const auto right = Eigen::Vector<Scalar, Size - 1>::Random().homogeneous();
const auto left = Eigen::RowVector<Scalar, Size - 1>::Random().homogeneous();
VERIFY_IS_APPROX(P * right, P * right.eval());
VERIFY_IS_APPROX(left * P, left.eval() * P);
}
}
EIGEN_DECLARE_TEST(geo_homogeneous) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1((homogeneous<float, 1>()));
CALL_SUBTEST_2((homogeneous<double, 3>()));
CALL_SUBTEST_3((homogeneous<double, 8>()));
}
}
+184
View File
@@ -0,0 +1,184 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/QR>
template <typename HyperplaneType>
void hyperplane(const HyperplaneType &_plane) {
/* this test covers the following files:
Hyperplane.h
*/
using std::abs;
const Index dim = _plane.dim();
enum { Options = HyperplaneType::Options };
typedef typename HyperplaneType::Scalar Scalar;
typedef typename HyperplaneType::RealScalar RealScalar;
typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, HyperplaneType::AmbientDimAtCompileTime> MatrixType;
VectorType p0 = VectorType::Random(dim);
VectorType p1 = VectorType::Random(dim);
VectorType n0 = VectorType::Random(dim).normalized();
VectorType n1 = VectorType::Random(dim).normalized();
HyperplaneType pl0(n0, p0);
HyperplaneType pl1(n1, p1);
HyperplaneType pl2 = pl1;
Scalar s0 = internal::random<Scalar>();
Scalar s1 = internal::random<Scalar>();
VERIFY_IS_APPROX(n1.dot(n1), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(pl0.absDistance(p0), Scalar(1));
if (numext::abs2(s0) > RealScalar(1e-6))
VERIFY_IS_APPROX(pl1.signedDistance(p1 + n1 * s0), s0);
else
VERIFY_IS_MUCH_SMALLER_THAN(abs(pl1.signedDistance(p1 + n1 * s0) - s0), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(pl1.signedDistance(pl1.projection(p0)), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1));
// transform
if (!NumTraits<Scalar>::IsComplex) {
MatrixType rot = MatrixType::Random(dim, dim).householderQr().householderQ();
DiagonalMatrix<Scalar, HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
Translation<Scalar, HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());
while (scaling.diagonal().cwiseAbs().minCoeff() < RealScalar(1e-4)) scaling.diagonal() = VectorType::Random();
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN(pl2.transform(rot).absDistance(rot * p1), Scalar(1));
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN(pl2.transform(rot, Isometry).absDistance(rot * p1), Scalar(1));
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN(pl2.transform(rot * scaling).absDistance((rot * scaling) * p1), Scalar(1));
VERIFY_IS_APPROX(pl2.normal().norm(), RealScalar(1));
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN(
pl2.transform(rot * scaling * translation).absDistance((rot * scaling * translation) * p1), Scalar(1));
VERIFY_IS_APPROX(pl2.normal().norm(), RealScalar(1));
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN(pl2.transform(rot * translation, Isometry).absDistance((rot * translation) * p1),
Scalar(1));
VERIFY_IS_APPROX(pl2.normal().norm(), RealScalar(1));
}
// casting
const int Dim = HyperplaneType::AmbientDimAtCompileTime;
typedef typename GetDifferentType<Scalar>::type OtherScalar;
Hyperplane<OtherScalar, Dim, Options> hp1f = pl1.template cast<OtherScalar>();
VERIFY_IS_APPROX(hp1f.template cast<Scalar>(), pl1);
Hyperplane<Scalar, Dim, Options> hp1d = pl1.template cast<Scalar>();
VERIFY_IS_APPROX(hp1d.template cast<Scalar>(), pl1);
}
template <typename Scalar>
void lines() {
using std::abs;
typedef Hyperplane<Scalar, 2> HLine;
typedef ParametrizedLine<Scalar, 2> PLine;
typedef Matrix<Scalar, 2, 1> Vector;
typedef Matrix<Scalar, 3, 1> CoeffsType;
for (int i = 0; i < 10; i++) {
Vector center = Vector::Random();
Vector u = Vector::Random();
Vector v = Vector::Random();
Scalar a = internal::random<Scalar>();
while (abs(a - 1) < Scalar(1e-4)) a = internal::random<Scalar>();
while (u.norm() < Scalar(1e-4)) u = Vector::Random();
while (v.norm() < Scalar(1e-4)) v = Vector::Random();
HLine line_u = HLine::Through(center + u, center + a * u);
HLine line_v = HLine::Through(center + v, center + a * v);
// the line equations should be normalized so that a^2+b^2=1
VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));
Vector result = line_u.intersection(line_v);
// the lines should intersect at the point we called "center"
if (abs(a - 1) > Scalar(1e-2) && abs(v.normalized().dot(u.normalized())) < Scalar(0.9))
VERIFY_IS_APPROX(result, center);
// check conversions between two types of lines
PLine pl(line_u); // gcc 3.3 will crash if we don't name this variable.
HLine line_u2(pl);
CoeffsType converted_coeffs = line_u2.coeffs();
if (line_u2.normal().dot(line_u.normal()) < Scalar(0)) converted_coeffs = -line_u2.coeffs();
VERIFY(line_u.coeffs().isApprox(converted_coeffs));
}
}
template <typename Scalar>
void planes() {
using std::abs;
typedef Hyperplane<Scalar, 3> Plane;
typedef Matrix<Scalar, 3, 1> Vector;
for (int i = 0; i < 10; i++) {
Vector v0 = Vector::Random();
Vector v1(v0), v2(v0);
if (internal::random<double>(0, 1) > 0.25) v1 += Vector::Random();
if (internal::random<double>(0, 1) > 0.25)
v2 += v1 * std::pow(internal::random<Scalar>(0, 1), internal::random<int>(1, 16));
if (internal::random<double>(0, 1) > 0.25)
v2 += Vector::Random() * std::pow(internal::random<Scalar>(0, 1), internal::random<int>(1, 16));
Plane p0 = Plane::Through(v0, v1, v2);
VERIFY_IS_APPROX(p0.normal().norm(), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(p0.absDistance(v0), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(p0.absDistance(v1), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(p0.absDistance(v2), Scalar(1));
}
}
template <typename Scalar>
void hyperplane_alignment() {
typedef Hyperplane<Scalar, 3, AutoAlign> Plane3a;
typedef Hyperplane<Scalar, 3, DontAlign> Plane3u;
EIGEN_ALIGN_MAX Scalar array1[4];
EIGEN_ALIGN_MAX Scalar array2[4];
EIGEN_ALIGN_MAX Scalar array3[4 + 1];
Scalar *array3u = array3 + 1;
Plane3a *p1 = ::new (reinterpret_cast<void *>(array1)) Plane3a;
Plane3u *p2 = ::new (reinterpret_cast<void *>(array2)) Plane3u;
Plane3u *p3 = ::new (reinterpret_cast<void *>(array3u)) Plane3u;
p1->coeffs().setRandom();
*p2 = *p1;
*p3 = *p1;
VERIFY_IS_APPROX(p1->coeffs(), p2->coeffs());
VERIFY_IS_APPROX(p1->coeffs(), p3->coeffs());
}
EIGEN_DECLARE_TEST(geo_hyperplane) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(hyperplane(Hyperplane<float, 2>()));
CALL_SUBTEST_2(hyperplane(Hyperplane<float, 3>()));
CALL_SUBTEST_2(hyperplane(Hyperplane<float, 3, DontAlign>()));
CALL_SUBTEST_2(hyperplane_alignment<float>());
CALL_SUBTEST_3(hyperplane(Hyperplane<double, 4>()));
CALL_SUBTEST_4(hyperplane(Hyperplane<std::complex<double>, 5>()));
CALL_SUBTEST_1(lines<float>());
CALL_SUBTEST_3(lines<double>());
CALL_SUBTEST_2(planes<float>());
CALL_SUBTEST_5(planes<double>());
}
}
+159
View File
@@ -0,0 +1,159 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/SVD>
/* this test covers the following files:
Geometry/OrthoMethods.h
*/
template <typename Scalar>
void orthomethods_3() {
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, 3, 3> Matrix3;
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Matrix<Scalar, 4, 1> Vector4;
Vector3 v0 = Vector3::Random(), v1 = Vector3::Random(), v2 = Vector3::Random();
// cross product
VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v1), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(Vector3::Random()).dot(v1), Scalar(1));
Matrix3 mat3;
mat3 << v0.normalized(), (v0.cross(v1)).normalized(), (v0.cross(v1).cross(v0)).normalized();
VERIFY(mat3.isUnitary());
mat3.setRandom();
VERIFY_IS_APPROX(v0.cross(mat3 * v1), -(mat3 * v1).cross(v0));
VERIFY_IS_APPROX(v0.cross(mat3.lazyProduct(v1)), -(mat3.lazyProduct(v1)).cross(v0));
// colwise/rowwise cross product
mat3.setRandom();
Vector3 vec3 = Vector3::Random();
Matrix3 mcross;
int i = internal::random<int>(0, 2);
mcross = mat3.colwise().cross(vec3);
VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(),
Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));
mcross = mat3.rowwise().cross(vec3);
VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
// cross3
Vector4 v40 = Vector4::Random(), v41 = Vector4::Random(), v42 = Vector4::Random();
v40.w() = v41.w() = v42.w() = 0;
v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>());
VERIFY_IS_APPROX(v40.cross3(v41), v42);
VERIFY_IS_MUCH_SMALLER_THAN(v40.cross3(Vector4::Random()).dot(v40), Scalar(1));
// check mixed product
typedef Matrix<RealScalar, 3, 1> RealVector3;
RealVector3 rv1 = RealVector3::Random();
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) {
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, Size, 1> VectorType;
typedef Matrix<Scalar, 3, Size> Matrix3N;
typedef Matrix<Scalar, Size, 3> MatrixN3;
typedef Matrix<Scalar, 3, 1> Vector3;
VectorType v0 = VectorType::Random(size);
// unitOrthogonal
VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
if (size >= 3) {
v0.template head<2>().setZero();
v0.tail(size - 2).setRandom();
VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
}
// colwise/rowwise cross product
Vector3 vec3 = Vector3::Random();
int i = internal::random<int>(0, size - 1);
Matrix3N mat3N(3, size), mcross3N(3, size);
mat3N.setRandom();
mcross3N = mat3N.colwise().cross(vec3);
VERIFY_IS_APPROX(mcross3N.col(i), mat3N.col(i).cross(vec3));
MatrixN3 matN3(size, 3), mcrossN3(size, 3);
matN3.setRandom();
mcrossN3 = matN3.rowwise().cross(vec3);
VERIFY_IS_APPROX(mcrossN3.row(i), matN3.row(i).cross(vec3));
}
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> >());
CALL_SUBTEST_1((orthomethods<float, 2>()));
CALL_SUBTEST_2((orthomethods<double, 2>()));
CALL_SUBTEST_1((orthomethods<float, 3>()));
CALL_SUBTEST_2((orthomethods<double, 3>()));
CALL_SUBTEST_3((orthomethods<float, 7>()));
CALL_SUBTEST_4((orthomethods<std::complex<double>, 8>()));
CALL_SUBTEST_5((orthomethods<float, Dynamic>(36)));
CALL_SUBTEST_6((orthomethods<double, Dynamic>(35)));
}
}
+121
View File
@@ -0,0 +1,121 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/QR>
template <typename LineType>
void parametrizedline(const LineType &_line) {
/* this test covers the following files:
ParametrizedLine.h
*/
using std::abs;
const Index dim = _line.dim();
typedef typename LineType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, LineType::AmbientDimAtCompileTime, 1> VectorType;
typedef Hyperplane<Scalar, LineType::AmbientDimAtCompileTime> HyperplaneType;
typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, HyperplaneType::AmbientDimAtCompileTime> MatrixType;
VectorType p0 = VectorType::Random(dim);
VectorType p1 = VectorType::Random(dim);
VectorType d0 = VectorType::Random(dim).normalized();
LineType l0(p0, d0);
Scalar s0 = internal::random<Scalar>();
Scalar s1 = abs(internal::random<Scalar>());
VERIFY_IS_MUCH_SMALLER_THAN(l0.distance(p0), RealScalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(l0.distance(p0 + s0 * d0), RealScalar(1));
VERIFY_IS_APPROX((l0.projection(p1) - p1).norm(), l0.distance(p1));
VERIFY_IS_MUCH_SMALLER_THAN(l0.distance(l0.projection(p1)), RealScalar(1));
VERIFY_IS_APPROX(Scalar(l0.distance((p0 + s0 * d0) + d0.unitOrthogonal() * s1)), s1);
// casting
const int Dim = LineType::AmbientDimAtCompileTime;
typedef typename GetDifferentType<Scalar>::type OtherScalar;
ParametrizedLine<OtherScalar, Dim> hp1f = l0.template cast<OtherScalar>();
VERIFY_IS_APPROX(hp1f.template cast<Scalar>(), l0);
ParametrizedLine<Scalar, Dim> hp1d = l0.template cast<Scalar>();
VERIFY_IS_APPROX(hp1d.template cast<Scalar>(), l0);
// intersections
VectorType p2 = VectorType::Random(dim);
VectorType n2 = VectorType::Random(dim).normalized();
HyperplaneType hp(p2, n2);
Scalar t = l0.intersectionParameter(hp);
VectorType pi = l0.pointAt(t);
VERIFY_IS_MUCH_SMALLER_THAN(hp.signedDistance(pi), RealScalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(l0.distance(pi), RealScalar(1));
VERIFY_IS_APPROX(l0.intersectionPoint(hp), pi);
// transform
if (!NumTraits<Scalar>::IsComplex) {
MatrixType rot = MatrixType::Random(dim, dim).householderQr().householderQ();
DiagonalMatrix<Scalar, LineType::AmbientDimAtCompileTime> scaling(VectorType::Random());
Translation<Scalar, LineType::AmbientDimAtCompileTime> translation(VectorType::Random());
while (scaling.diagonal().cwiseAbs().minCoeff() < RealScalar(1e-4)) scaling.diagonal() = VectorType::Random();
LineType l1 = l0;
VectorType p3 = l0.pointAt(Scalar(1));
VERIFY_IS_MUCH_SMALLER_THAN(l1.transform(rot).distance(rot * p3), Scalar(1));
l1 = l0;
VERIFY_IS_MUCH_SMALLER_THAN(l1.transform(rot, Isometry).distance(rot * p3), Scalar(1));
l1 = l0;
VERIFY_IS_MUCH_SMALLER_THAN(l1.transform(rot * scaling).distance((rot * scaling) * p3), Scalar(1));
l1 = l0;
VERIFY_IS_MUCH_SMALLER_THAN(l1.transform(rot * scaling * translation).distance((rot * scaling * translation) * p3),
Scalar(1));
l1 = l0;
VERIFY_IS_MUCH_SMALLER_THAN(l1.transform(rot * translation, Isometry).distance((rot * translation) * p3),
Scalar(1));
}
}
template <typename Scalar>
void parametrizedline_alignment() {
typedef ParametrizedLine<Scalar, 4, AutoAlign> Line4a;
typedef ParametrizedLine<Scalar, 4, DontAlign> Line4u;
EIGEN_ALIGN_MAX Scalar array1[16];
EIGEN_ALIGN_MAX Scalar array2[16];
EIGEN_ALIGN_MAX Scalar array3[16 + 1];
Scalar *array3u = array3 + 1;
Line4a *p1 = ::new (reinterpret_cast<void *>(array1)) Line4a;
Line4u *p2 = ::new (reinterpret_cast<void *>(array2)) Line4u;
Line4u *p3 = ::new (reinterpret_cast<void *>(array3u)) Line4u;
p1->origin().setRandom();
p1->direction().setRandom();
*p2 = *p1;
*p3 = *p1;
VERIFY_IS_APPROX(p1->origin(), p2->origin());
VERIFY_IS_APPROX(p1->origin(), p3->origin());
VERIFY_IS_APPROX(p1->direction(), p2->direction());
VERIFY_IS_APPROX(p1->direction(), p3->direction());
}
EIGEN_DECLARE_TEST(geo_parametrizedline) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(parametrizedline(ParametrizedLine<float, 2>()));
CALL_SUBTEST_2(parametrizedline(ParametrizedLine<float, 3>()));
CALL_SUBTEST_2(parametrizedline_alignment<float>());
CALL_SUBTEST_3(parametrizedline(ParametrizedLine<double, 4>()));
CALL_SUBTEST_3(parametrizedline_alignment<double>());
CALL_SUBTEST_4(parametrizedline(ParametrizedLine<std::complex<double>, 5>()));
}
}
+333
View File
@@ -0,0 +1,333 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2009 Mathieu Gautier <mathieu.gautier@cea.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/SVD>
#include "AnnoyingScalar.h"
template <typename T>
T bounded_acos(T v) {
using std::acos;
using std::max;
using std::min;
return acos((max)(T(-1), (min)(v, T(1))));
}
template <typename QuatType>
void check_slerp(const QuatType& q0, const QuatType& q1) {
using std::abs;
typedef typename QuatType::Scalar Scalar;
typedef AngleAxis<Scalar> AA;
Scalar largeEps = test_precision<Scalar>();
Scalar theta_tot = AA(q1 * q0.inverse()).angle();
if (theta_tot > Scalar(EIGEN_PI)) theta_tot = Scalar(2.) * Scalar(EIGEN_PI) - theta_tot;
for (Scalar t = 0; t <= Scalar(1.001); t += Scalar(0.1)) {
QuatType q = q0.slerp(t, q1);
Scalar theta = AA(q * q0.inverse()).angle();
VERIFY(abs(q.norm() - 1) < largeEps);
if (theta_tot == 0)
VERIFY(theta_tot == 0);
else
VERIFY(abs(theta - t * theta_tot) < largeEps);
}
}
template <typename Scalar, int Options>
void quaternion(void) {
/* this test covers the following files:
Quaternion.h
*/
using std::abs;
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Matrix<Scalar, 3, 3> Matrix3;
typedef Quaternion<Scalar, Options> Quaternionx;
typedef AngleAxis<Scalar> AngleAxisx;
Scalar largeEps = test_precision<Scalar>();
if (internal::is_same<Scalar, float>::value) largeEps = Scalar(1e-3);
Scalar eps = internal::random<Scalar>() * Scalar(1e-2);
Vector3 v0 = Vector3::Random(), v1 = Vector3::Random(), v2 = Vector3::Random(), v3 = Vector3::Random();
Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)),
b = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
// Quaternion: Identity(), setIdentity();
Quaternionx q1, q2;
q2.setIdentity();
VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
q1.coeffs().setRandom();
VERIFY_IS_APPROX(q1.coeffs(), (q1 * q2).coeffs());
#ifndef EIGEN_NO_IO
// Printing
std::ostringstream ss;
ss << q2;
VERIFY(ss.str() == "0i + 0j + 0k + 1");
#endif
// Consistent handling of scalar first/last conventions regardless of Eigen's own coefficient layout
const Scalar w(a);
const Vector3 xyz(v0);
q1 = Quaternionx::FromCoeffsScalarFirst(w, xyz.x(), xyz.y(), xyz.z());
q2 = Quaternionx::FromCoeffsScalarLast(xyz.x(), xyz.y(), xyz.z(), w);
VERIFY_IS_EQUAL(q1, q2);
VERIFY_IS_EQUAL(q1.coeffsScalarFirst()[0], w);
VERIFY_IS_EQUAL(q1.coeffsScalarFirst()(seqN(1, 3)), xyz);
VERIFY_IS_EQUAL(q1.coeffsScalarLast()[3], w);
VERIFY_IS_EQUAL(q1.coeffsScalarLast()(seqN(0, 3)), xyz);
// concatenation
q1 *= q2;
q1 = AngleAxisx(a, v0.normalized());
q2 = AngleAxisx(a, v1.normalized());
// angular distance
Scalar refangle = abs(AngleAxisx(q1.inverse() * q2).angle());
if (refangle > Scalar(EIGEN_PI)) refangle = Scalar(2) * Scalar(EIGEN_PI) - refangle;
if ((q1.coeffs() - q2.coeffs()).norm() > Scalar(10) * largeEps) {
VERIFY_IS_MUCH_SMALLER_THAN(abs(q1.angularDistance(q2) - refangle), Scalar(1));
}
// Action on vector by the q v q* formula
VERIFY_IS_APPROX(q1 * v2, (q1 * Quaternionx(Scalar(0), v2) * q1.inverse()).vec());
VERIFY_IS_APPROX(q1.inverse() * v2, (q1.inverse() * Quaternionx(Scalar(0), v2) * q1).vec());
// rotation matrix conversion
VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
VERIFY_IS_APPROX(q1 * q2 * v2, q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
VERIFY((q2 * q1).isApprox(q1 * q2, largeEps) ||
!(q2 * q1 * v2).isApprox(q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
q2 = q1.toRotationMatrix();
VERIFY_IS_APPROX(q1 * v1, q2 * v1);
Matrix3 rot1(q1);
VERIFY_IS_APPROX(q1 * v1, rot1 * v1);
Quaternionx q3(rot1.transpose() * rot1);
VERIFY_IS_APPROX(q3 * v1, v1);
// angle-axis conversion
AngleAxisx aa = AngleAxisx(q1);
VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
// Do not execute the test if the rotation angle is almost zero, or
// the rotation axis and v1 are almost parallel.
if (abs(aa.angle()) > Scalar(5) * test_precision<Scalar>() && (aa.axis() - v1.normalized()).norm() < Scalar(1.99) &&
(aa.axis() + v1.normalized()).norm() < Scalar(1.99)) {
VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle() * 2, aa.axis())) * v1);
}
// from two vector creation
VERIFY_IS_APPROX(v2.normalized(), (q2.setFromTwoVectors(v1, v2) * v1).normalized());
VERIFY_IS_APPROX(v1.normalized(), (q2.setFromTwoVectors(v1, v1) * v1).normalized());
VERIFY_IS_APPROX(-v1.normalized(), (q2.setFromTwoVectors(v1, -v1) * v1).normalized());
if (internal::is_same<Scalar, double>::value) {
v3 = (v1.array() + eps).matrix();
VERIFY_IS_APPROX(v3.normalized(), (q2.setFromTwoVectors(v1, v3) * v1).normalized());
VERIFY_IS_APPROX(-v3.normalized(), (q2.setFromTwoVectors(v1, -v3) * v1).normalized());
}
// from two vector creation static function
VERIFY_IS_APPROX(v2.normalized(), (Quaternionx::FromTwoVectors(v1, v2) * v1).normalized());
VERIFY_IS_APPROX(v1.normalized(), (Quaternionx::FromTwoVectors(v1, v1) * v1).normalized());
VERIFY_IS_APPROX(-v1.normalized(), (Quaternionx::FromTwoVectors(v1, -v1) * v1).normalized());
if (internal::is_same<Scalar, double>::value) {
v3 = (v1.array() + eps).matrix();
VERIFY_IS_APPROX(v3.normalized(), (Quaternionx::FromTwoVectors(v1, v3) * v1).normalized());
VERIFY_IS_APPROX(-v3.normalized(), (Quaternionx::FromTwoVectors(v1, -v3) * v1).normalized());
}
// inverse and conjugate
VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
// test casting
Quaternion<float> q1f = q1.template cast<float>();
VERIFY_IS_APPROX(q1f.template cast<Scalar>(), q1);
Quaternion<double> q1d = q1.template cast<double>();
VERIFY_IS_APPROX(q1d.template cast<Scalar>(), q1);
// test bug 369 - improper alignment.
Quaternionx* q = new Quaternionx;
delete q;
q1 = Quaternionx::UnitRandom();
q2 = Quaternionx::UnitRandom();
check_slerp(q1, q2);
q1 = AngleAxisx(b, v1.normalized());
q2 = AngleAxisx(b + Scalar(EIGEN_PI), v1.normalized());
check_slerp(q1, q2);
q1 = AngleAxisx(b, v1.normalized());
q2 = AngleAxisx(-b, -v1.normalized());
check_slerp(q1, q2);
q1 = Quaternionx::UnitRandom();
q2.coeffs() = -q1.coeffs();
check_slerp(q1, q2);
}
template <typename Scalar>
void mapQuaternion(void) {
typedef Map<Quaternion<Scalar>, Aligned> MQuaternionA;
typedef Map<const Quaternion<Scalar>, Aligned> MCQuaternionA;
typedef Map<Quaternion<Scalar> > MQuaternionUA;
typedef Map<const Quaternion<Scalar> > MCQuaternionUA;
typedef Quaternion<Scalar> Quaternionx;
typedef Matrix<Scalar, 3, 1> Vector3;
typedef AngleAxis<Scalar> AngleAxisx;
Vector3 v0 = Vector3::Random(), v1 = Vector3::Random();
Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
EIGEN_ALIGN_MAX Scalar array1[4];
EIGEN_ALIGN_MAX Scalar array2[4];
EIGEN_ALIGN_MAX Scalar array3[4 + 1];
Scalar* array3unaligned = array3 + 1;
MQuaternionA mq1(array1);
MCQuaternionA mcq1(array1);
MQuaternionA mq2(array2);
MQuaternionUA mq3(array3unaligned);
MCQuaternionUA mcq3(array3unaligned);
// std::cerr << array1 << " " << array2 << " " << array3 << "\n";
mq1 = AngleAxisx(a, v0.normalized());
mq2 = mq1;
mq3 = mq1;
Quaternionx q1 = mq1;
Quaternionx q2 = mq2;
Quaternionx q3 = mq3;
Quaternionx q4 = MCQuaternionUA(array3unaligned);
VERIFY_IS_APPROX(q1.coeffs(), q2.coeffs());
VERIFY_IS_APPROX(q1.coeffs(), q3.coeffs());
VERIFY_IS_APPROX(q4.coeffs(), q3.coeffs());
VERIFY_IS_APPROX(mq1 * (mq1.inverse() * v1), v1);
VERIFY_IS_APPROX(mq1 * (mq1.conjugate() * v1), v1);
VERIFY_IS_APPROX(mcq1 * (mcq1.inverse() * v1), v1);
VERIFY_IS_APPROX(mcq1 * (mcq1.conjugate() * v1), v1);
VERIFY_IS_APPROX(mq3 * (mq3.inverse() * v1), v1);
VERIFY_IS_APPROX(mq3 * (mq3.conjugate() * v1), v1);
VERIFY_IS_APPROX(mcq3 * (mcq3.inverse() * v1), v1);
VERIFY_IS_APPROX(mcq3 * (mcq3.conjugate() * v1), v1);
VERIFY_IS_APPROX(mq1 * mq2, q1 * q2);
VERIFY_IS_APPROX(mq3 * mq2, q3 * q2);
VERIFY_IS_APPROX(mcq1 * mq2, q1 * q2);
VERIFY_IS_APPROX(mcq3 * mq2, q3 * q2);
// Bug 1461, compilation issue with Map<const Quat>::w(), and other reference/constness checks:
VERIFY_IS_APPROX(mcq3.coeffs().x() + mcq3.coeffs().y() + mcq3.coeffs().z() + mcq3.coeffs().w(), mcq3.coeffs().sum());
VERIFY_IS_APPROX(mcq3.x() + mcq3.y() + mcq3.z() + mcq3.w(), mcq3.coeffs().sum());
mq3.w() = 1;
const Quaternionx& cq3(q3);
VERIFY(&cq3.x() == &q3.x());
const MQuaternionUA& cmq3(mq3);
VERIFY(&cmq3.x() == &mq3.x());
// FIXME the following should be ok. The problem is that currently the LValueBit flag
// is used to determine whether we can return a coeff by reference or not, which is not enough for Map<const ...>.
// const MCQuaternionUA& cmcq3(mcq3);
// VERIFY( &cmcq3.x() == &mcq3.x() );
// test cast
{
Quaternion<float> q1f = mq1.template cast<float>();
VERIFY_IS_APPROX(q1f.template cast<Scalar>(), mq1);
Quaternion<double> q1d = mq1.template cast<double>();
VERIFY_IS_APPROX(q1d.template cast<Scalar>(), mq1);
}
}
template <typename Scalar>
void quaternionAlignment(void) {
typedef Quaternion<Scalar, AutoAlign> QuaternionA;
typedef Quaternion<Scalar, DontAlign> QuaternionUA;
EIGEN_ALIGN_MAX Scalar array1[4];
EIGEN_ALIGN_MAX Scalar array2[4];
EIGEN_ALIGN_MAX Scalar array3[4 + 1];
Scalar* arrayunaligned = array3 + 1;
QuaternionA* q1 = ::new (reinterpret_cast<void*>(array1)) QuaternionA;
QuaternionUA* q2 = ::new (reinterpret_cast<void*>(array2)) QuaternionUA;
QuaternionUA* q3 = ::new (reinterpret_cast<void*>(arrayunaligned)) QuaternionUA;
q1->coeffs().setRandom();
*q2 = *q1;
*q3 = *q1;
VERIFY_IS_APPROX(q1->coeffs(), q2->coeffs());
VERIFY_IS_APPROX(q1->coeffs(), q3->coeffs());
}
template <typename PlainObjectType>
void check_const_correctness(const PlainObjectType&) {
// there's a lot that we can't test here while still having this test compile!
// the only possible approach would be to run a script trying to compile stuff and checking that it fails.
// CMake can help with that.
// verify that map-to-const don't have LvalueBit
typedef 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));
}
// Regression for bug 1573
struct MovableClass {
// The following line is a workaround for gcc 4.7 and 4.8 (see bug 1573 comments).
static_assert(std::is_nothrow_move_constructible<Quaternionf>::value, "");
MovableClass() = default;
MovableClass(const MovableClass&) = default;
MovableClass(MovableClass&&) noexcept = default;
MovableClass& operator=(const MovableClass&) = default;
MovableClass& operator=(MovableClass&&) = default;
Quaternionf m_quat;
};
EIGEN_DECLARE_TEST(geo_quaternion) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1((quaternion<float, AutoAlign>()));
CALL_SUBTEST_1(check_const_correctness(Quaternionf()));
CALL_SUBTEST_1((quaternion<float, DontAlign>()));
CALL_SUBTEST_1((quaternionAlignment<float>()));
CALL_SUBTEST_1(mapQuaternion<float>());
CALL_SUBTEST_2((quaternion<double, AutoAlign>()));
CALL_SUBTEST_2(check_const_correctness(Quaterniond()));
CALL_SUBTEST_2((quaternion<double, DontAlign>()));
CALL_SUBTEST_2((quaternionAlignment<double>()));
CALL_SUBTEST_2(mapQuaternion<double>());
#ifndef EIGEN_TEST_ANNOYING_SCALAR_DONT_THROW
AnnoyingScalar::dont_throw = true;
#endif
CALL_SUBTEST_3((quaternion<AnnoyingScalar, AutoAlign>()));
}
}
+728
View File
@@ -0,0 +1,728 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/SVD>
template <typename T>
Matrix<T, 2, 1> angleToVec(T a) {
return Matrix<T, 2, 1>(std::cos(a), std::sin(a));
}
// This permits to workaround a bug in clang/llvm code generation.
template <typename T>
EIGEN_DONT_INLINE void dont_over_optimize(T& x) {
volatile typename T::Scalar tmp = x(0);
x(0) = tmp;
}
template <typename Scalar, int Mode, int Options>
void non_projective_only() {
/* this test covers the following files:
Cross.h Quaternion.h, Transform.cpp
*/
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Quaternion<Scalar> Quaternionx;
typedef AngleAxis<Scalar> AngleAxisx;
typedef Transform<Scalar, 3, Mode, Options> Transform3;
typedef DiagonalMatrix<Scalar, 3> AlignedScaling3;
typedef Translation<Scalar, 3> Translation3;
Vector3 v0 = Vector3::Random(), v1 = Vector3::Random();
Transform3 t0, t1, t2;
Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
Quaternionx q1, q2;
q1 = AngleAxisx(a, v0.normalized());
t0 = Transform3::Identity();
VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
t0.linear() = q1.toRotationMatrix();
v0 << 50, 2, 1;
t0.scale(v0);
VERIFY_IS_APPROX((t0 * Vector3(1, 0, 0)).template head<3>().norm(), v0.x());
t0.setIdentity();
t1.setIdentity();
v1 << 1, 2, 3;
t0.linear() = q1.toRotationMatrix();
t0.pretranslate(v0);
t0.scale(v1);
t1.linear() = q1.conjugate().toRotationMatrix();
t1.prescale(v1.cwiseInverse());
t1.translate(-v0);
VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
t1.fromPositionOrientationScale(v0, q1, v1);
VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
VERIFY_IS_APPROX(t1 * v1, t0 * v1);
// translation * vector
t0.setIdentity();
t0.translate(v0);
VERIFY_IS_APPROX((t0 * v1).template head<3>(), Translation3(v0) * v1);
// AlignedScaling * vector
t0.setIdentity();
t0.scale(v0);
VERIFY_IS_APPROX((t0 * v1).template head<3>(), AlignedScaling3(v0) * v1);
}
template <typename Scalar, int Mode, int Options>
void transformations() {
/* this test covers the following files:
Cross.h Quaternion.h, Transform.cpp
*/
using std::abs;
using std::cos;
typedef Matrix<Scalar, 3, 3> Matrix3;
typedef Matrix<Scalar, 4, 4> Matrix4;
typedef Matrix<Scalar, 2, 1> Vector2;
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Matrix<Scalar, 4, 1> Vector4;
typedef Quaternion<Scalar> Quaternionx;
typedef AngleAxis<Scalar> AngleAxisx;
typedef Transform<Scalar, 2, Mode, Options> Transform2;
typedef Transform<Scalar, 3, Mode, Options> Transform3;
typedef typename Transform3::MatrixType MatrixType;
typedef DiagonalMatrix<Scalar, 3> AlignedScaling3;
typedef Translation<Scalar, 2> Translation2;
typedef Translation<Scalar, 3> Translation3;
Vector3 v0 = Vector3::Random(), v1 = Vector3::Random();
Matrix3 matrot1, m;
Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
Scalar s0 = internal::random<Scalar>(), s1 = internal::random<Scalar>();
while (v0.norm() < test_precision<Scalar>()) v0 = Vector3::Random();
while (v1.norm() < test_precision<Scalar>()) v1 = Vector3::Random();
VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(EIGEN_PI), v0.unitOrthogonal()) * v0);
if (abs(cos(a)) > test_precision<Scalar>()) {
VERIFY_IS_APPROX(cos(a) * v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
}
m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
Quaternionx q1, q2;
q1 = AngleAxisx(a, v0.normalized());
q2 = AngleAxisx(a, v1.normalized());
// rotation matrix conversion
matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX()) * AngleAxisx(Scalar(0.2), Vector3::UnitY()) *
AngleAxisx(Scalar(0.3), Vector3::UnitZ());
VERIFY_IS_APPROX(matrot1 * v1, AngleAxisx(Scalar(0.1), Vector3(1, 0, 0)).toRotationMatrix() *
(AngleAxisx(Scalar(0.2), Vector3(0, 1, 0)).toRotationMatrix() *
(AngleAxisx(Scalar(0.3), Vector3(0, 0, 1)).toRotationMatrix() * v1)));
// angle-axis conversion
AngleAxisx aa = AngleAxisx(q1);
VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
// The following test is stable only if 2*angle != angle and v1 is not colinear with axis
if ((abs(aa.angle()) > test_precision<Scalar>()) &&
(abs(aa.axis().dot(v1.normalized())) < (Scalar(1) - Scalar(4) * test_precision<Scalar>()))) {
VERIFY(!(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle() * 2, aa.axis())) * v1));
}
aa.fromRotationMatrix(aa.toRotationMatrix());
VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
// The following test is stable only if 2*angle != angle and v1 is not colinear with axis
if ((abs(aa.angle()) > test_precision<Scalar>()) &&
(abs(aa.axis().dot(v1.normalized())) < (Scalar(1) - Scalar(4) * test_precision<Scalar>()))) {
VERIFY(!(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle() * 2, aa.axis())) * v1));
}
// AngleAxis
VERIFY_IS_APPROX(AngleAxisx(a, v1.normalized()).toRotationMatrix(),
Quaternionx(AngleAxisx(a, v1.normalized())).toRotationMatrix());
AngleAxisx aa1;
m = q1.toRotationMatrix();
aa1 = m;
VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(), Quaternionx(m).toRotationMatrix());
// Transform
// TODO complete the tests !
a = 0;
while (abs(a) < Scalar(0.1))
a = internal::random<Scalar>(-Scalar(0.4) * Scalar(EIGEN_PI), Scalar(0.4) * Scalar(EIGEN_PI));
q1 = AngleAxisx(a, v0.normalized());
Transform3 t0, t1, t2;
// first test setIdentity() and Identity()
t0.setIdentity();
VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
t0.matrix().setZero();
t0 = Transform3::Identity();
VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
t0.setIdentity();
t1.setIdentity();
v1 << 1, 2, 3;
t0.linear() = q1.toRotationMatrix();
t0.pretranslate(v0);
t0.scale(v1);
t1.linear() = q1.conjugate().toRotationMatrix();
t1.prescale(v1.cwiseInverse());
t1.translate(-v0);
VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
t1.fromPositionOrientationScale(v0, q1, v1);
VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
t0.setIdentity();
t0.scale(v0).rotate(q1.toRotationMatrix());
t1.setIdentity();
t1.scale(v0).rotate(q1);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.setIdentity();
t0.scale(v0).rotate(AngleAxisx(q1));
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
// More transform constructors, operator=, operator*=
Matrix3 mat3 = Matrix3::Random();
Matrix4 mat4;
mat4 << mat3, Vector3::Zero(), Vector4::Zero().transpose();
Transform3 tmat3(mat3), tmat4(mat4);
if (Mode != int(AffineCompact)) tmat4.matrix()(3, 3) = Scalar(1);
VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
Scalar a3 = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
Vector3 v3 = Vector3::Random().normalized();
AngleAxisx aa3(a3, v3);
Transform3 t3(aa3);
Transform3 t4;
t4 = aa3;
VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
t4.rotate(AngleAxisx(-a3, v3));
VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
t4 *= aa3;
VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
do {
v3 = Vector3::Random();
dont_over_optimize(v3);
} while (v3.cwiseAbs().minCoeff() < NumTraits<Scalar>::epsilon());
Translation3 tv3(v3);
Transform3 t5(tv3);
t4 = tv3;
VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
t4.translate((-v3).eval());
VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
t4 *= tv3;
VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
AlignedScaling3 sv3(v3);
Transform3 t6(sv3);
t4 = sv3;
VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
t4.scale(v3.cwiseInverse());
VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
t4 *= sv3;
VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
// matrix * transform
VERIFY_IS_APPROX((t3.matrix() * t4).matrix(), (t3 * t4).matrix());
// chained Transform product
VERIFY_IS_APPROX(((t3 * t4) * t5).matrix(), (t3 * (t4 * t5)).matrix());
// check that Transform product doesn't have aliasing problems
t5 = t4;
t5 = t5 * t5;
VERIFY_IS_APPROX(t5, t4 * t4);
// 2D transformation
Transform2 t20, t21;
Vector2 v20 = Vector2::Random();
Vector2 v21 = Vector2::Random();
for (int k = 0; k < 2; ++k)
if (abs(v21[k]) < Scalar(1e-3)) v21[k] = Scalar(1e-3);
t21.setIdentity();
t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20, a, v21).matrix(), t21.pretranslate(v20).scale(v21).matrix());
t21.setIdentity();
t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
VERIFY((t20.fromPositionOrientationScale(v20, a, v21) * (t21.prescale(v21.cwiseInverse()).translate(-v20)))
.matrix()
.isIdentity(test_precision<Scalar>()));
t20.setIdentity();
t20.shear(Scalar(2), Scalar(3));
Transform2 t23 = t20 * t21;
t21.preshear(Scalar(2), Scalar(3));
VERIFY_IS_APPROX(t21, t23);
// Transform - new API
// 3D
t0.setIdentity();
t0.rotate(q1).scale(v0).translate(v0);
// mat * aligned scaling and mat * translation
t1 = (Matrix3(q1) * AlignedScaling3(v0)) * Translation3(v0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t1 = (Matrix3(q1) * Eigen::Scaling(v0)) * Translation3(v0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t1 = (q1 * Eigen::Scaling(v0)) * Translation3(v0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// mat * transformation and aligned scaling * translation
t1 = Matrix3(q1) * (AlignedScaling3(v0) * Translation3(v0));
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.setIdentity();
t0.scale(s0).translate(v0);
t1 = Eigen::Scaling(s0) * Translation3(v0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.prescale(s0);
t1 = Eigen::Scaling(s0) * t1;
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0 = t3;
t0.scale(s0);
t1 = t3 * Eigen::Scaling(s0, s0, s0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.prescale(s0);
t1 = Eigen::Scaling(s0, s0, s0) * t1;
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0 = t3;
t0.scale(s0);
t1 = t3 * Eigen::Scaling(s0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.prescale(s0);
t1 = Eigen::Scaling(s0) * t1;
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.setIdentity();
t0.prerotate(q1).prescale(v0).pretranslate(v0);
// translation * aligned scaling and transformation * mat
t1 = (Translation3(v0) * AlignedScaling3(v0)) * Transform3(q1);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// scaling * mat and translation * mat
t1 = Translation3(v0) * (AlignedScaling3(v0) * Transform3(q1));
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t0.setIdentity();
t0.scale(v0).translate(v0).rotate(q1);
// translation * mat and aligned scaling * transformation
t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// transformation * aligned scaling
t0.scale(v0);
t1 *= AlignedScaling3(v0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
t1 = t1 * v0.asDiagonal();
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// transformation * translation
t0.translate(v0);
t1 = t1 * Translation3(v0);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// translation * transformation
t0.pretranslate(v0);
t1 = Translation3(v0) * t1;
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// transform * quaternion
t0.rotate(q1);
t1 = t1 * q1;
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// translation * quaternion
t0.translate(v1).rotate(q1);
t1 = t1 * (Translation3(v1) * q1);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// aligned scaling * quaternion
t0.scale(v1).rotate(q1);
t1 = t1 * (AlignedScaling3(v1) * q1);
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// quaternion * transform
t0.prerotate(q1);
t1 = q1 * t1;
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// quaternion * translation
t0.rotate(q1).translate(v1);
t1 = t1 * (q1 * Translation3(v1));
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// quaternion * aligned scaling
t0.rotate(q1).scale(v1);
t1 = t1 * (q1 * AlignedScaling3(v1));
VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
// test transform inversion
t0.setIdentity();
t0.translate(v0);
do {
t0.linear().setRandom();
} while (t0.linear().jacobiSvd().singularValues()(2) < test_precision<Scalar>());
Matrix4 t044 = Matrix4::Zero();
t044(3, 3) = 1;
t044.block(0, 0, t0.matrix().rows(), 4) = t0.matrix();
VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t044.inverse().block(0, 0, t0.matrix().rows(), 4));
t0.setIdentity();
t0.translate(v0).rotate(q1);
t044 = Matrix4::Zero();
t044(3, 3) = 1;
t044.block(0, 0, t0.matrix().rows(), 4) = t0.matrix();
VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t044.inverse().block(0, 0, t0.matrix().rows(), 4));
Matrix3 mat_rotation, mat_scaling;
t0.setIdentity();
t0.translate(v0).rotate(q1).scale(v1);
t0.computeRotationScaling(&mat_rotation, &mat_scaling);
VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
VERIFY_IS_APPROX(mat_rotation * mat_rotation.adjoint(), Matrix3::Identity());
VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
t0.computeScalingRotation(&mat_scaling, &mat_rotation);
VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
VERIFY_IS_APPROX(mat_rotation * mat_rotation.adjoint(), Matrix3::Identity());
VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
// test casting
Transform<float, 3, Mode> t1f = t1.template cast<float>();
VERIFY_IS_APPROX(t1f.template cast<Scalar>(), t1);
Transform<double, 3, Mode> t1d = t1.template cast<double>();
VERIFY_IS_APPROX(t1d.template cast<Scalar>(), t1);
Translation3 tr1(v0);
Translation<float, 3> tr1f = tr1.template cast<float>();
VERIFY_IS_APPROX(tr1f.template cast<Scalar>(), tr1);
Translation<double, 3> tr1d = tr1.template cast<double>();
VERIFY_IS_APPROX(tr1d.template cast<Scalar>(), tr1);
AngleAxis<float> aa1f = aa1.template cast<float>();
VERIFY_IS_APPROX(aa1f.template cast<Scalar>(), aa1);
AngleAxis<double> aa1d = aa1.template cast<double>();
VERIFY_IS_APPROX(aa1d.template cast<Scalar>(), aa1);
Rotation2D<Scalar> r2d1(internal::random<Scalar>());
Rotation2D<float> r2d1f = r2d1.template cast<float>();
VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(), r2d1);
Rotation2D<double> r2d1d = r2d1.template cast<double>();
VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(), r2d1);
for (int k = 0; k < 100; ++k) {
Scalar angle = internal::random<Scalar>(-100, 100);
Rotation2D<Scalar> rot2(angle);
VERIFY(rot2.smallestPositiveAngle() >= 0);
VERIFY(rot2.smallestPositiveAngle() <= Scalar(2) * Scalar(EIGEN_PI));
VERIFY_IS_APPROX(angleToVec(rot2.smallestPositiveAngle()), angleToVec(rot2.angle()));
VERIFY(rot2.smallestAngle() >= -Scalar(EIGEN_PI));
VERIFY(rot2.smallestAngle() <= Scalar(EIGEN_PI));
VERIFY_IS_APPROX(angleToVec(rot2.smallestAngle()), angleToVec(rot2.angle()));
Matrix<Scalar, 2, 2> rot2_as_mat(rot2);
Rotation2D<Scalar> rot3(rot2_as_mat);
VERIFY_IS_APPROX(angleToVec(rot2.smallestAngle()), angleToVec(rot3.angle()));
}
s0 = internal::random<Scalar>(-100, 100);
s1 = internal::random<Scalar>(-100, 100);
Rotation2D<Scalar> R0(s0), R1(s1);
t20 = Translation2(v20) * (R0 * Eigen::Scaling(s0));
t21 = Translation2(v20) * R0 * Eigen::Scaling(s0);
VERIFY_IS_APPROX(t20, t21);
t20 = Translation2(v20) * (R0 * R0.inverse() * Eigen::Scaling(s0));
t21 = Translation2(v20) * Eigen::Scaling(s0);
VERIFY_IS_APPROX(t20, t21);
VERIFY_IS_APPROX(s0, (R0.slerp(0, R1)).angle());
VERIFY_IS_APPROX(angleToVec(R1.smallestPositiveAngle()), angleToVec((R0.slerp(1, R1)).smallestPositiveAngle()));
VERIFY_IS_APPROX(R0.smallestPositiveAngle(), (R0.slerp(0.5, R0)).smallestPositiveAngle());
if (std::cos(s0) > 0)
VERIFY_IS_MUCH_SMALLER_THAN((R0.slerp(0.5, R0.inverse())).smallestAngle(), Scalar(1));
else
VERIFY_IS_APPROX(Scalar(EIGEN_PI), (R0.slerp(0.5, R0.inverse())).smallestPositiveAngle());
// Check path length
Scalar l = 0;
int path_steps = 100;
for (int k = 0; k < path_steps; ++k) {
Scalar a1 = R0.slerp(Scalar(k) / Scalar(path_steps), R1).angle();
Scalar a2 = R0.slerp(Scalar(k + 1) / Scalar(path_steps), R1).angle();
l += std::abs(a2 - a1);
}
VERIFY(l <= Scalar(EIGEN_PI) * (Scalar(1) + NumTraits<Scalar>::epsilon() * Scalar(path_steps / 2)));
// check basic features
{
Rotation2D<Scalar> r1; // default ctor
r1 = Rotation2D<Scalar>(s0); // copy assignment
VERIFY_IS_APPROX(r1.angle(), s0);
Rotation2D<Scalar> r2(r1); // copy ctor
VERIFY_IS_APPROX(r2.angle(), s0);
}
{
Transform3 t32(Matrix4::Random()), t33, t34;
t34 = t33 = t32;
t32.scale(v0);
t33 *= AlignedScaling3(v0);
VERIFY_IS_APPROX(t32.matrix(), t33.matrix());
t33 = t34 * AlignedScaling3(v0);
VERIFY_IS_APPROX(t32.matrix(), t33.matrix());
}
}
template <typename A1, typename A2, typename P, typename Q, typename V, typename H>
void transform_associativity_left(const A1& a1, const A2& a2, const P& p, const Q& q, const V& v, const H& h) {
VERIFY_IS_APPROX(q * (a1 * v), (q * a1) * v);
VERIFY_IS_APPROX(q * (a2 * v), (q * a2) * v);
VERIFY_IS_APPROX(q * (p * h).hnormalized(), ((q * p) * h).hnormalized());
}
template <typename A1, typename A2, typename P, typename Q, typename V, typename H>
void transform_associativity2(const A1& a1, const A2& a2, const P& p, const Q& q, const V& v, const H& h) {
VERIFY_IS_APPROX(a1 * (q * v), (a1 * q) * v);
VERIFY_IS_APPROX(a2 * (q * v), (a2 * q) * v);
VERIFY_IS_APPROX(p * (q * v).homogeneous(), (p * q) * v.homogeneous());
transform_associativity_left(a1, a2, p, q, v, h);
}
template <typename Scalar, int Dim, int Options, typename RotationType>
void transform_associativity(const RotationType& R) {
typedef Matrix<Scalar, Dim, 1> VectorType;
typedef Matrix<Scalar, Dim + 1, 1> HVectorType;
typedef Matrix<Scalar, Dim, Dim> LinearType;
typedef Matrix<Scalar, Dim + 1, Dim + 1> MatrixType;
typedef Transform<Scalar, Dim, AffineCompact, Options> AffineCompactType;
typedef Transform<Scalar, Dim, Affine, Options> AffineType;
typedef Transform<Scalar, Dim, Projective, Options> ProjectiveType;
typedef DiagonalMatrix<Scalar, Dim> ScalingType;
typedef Translation<Scalar, Dim> TranslationType;
AffineCompactType A1c;
A1c.matrix().setRandom();
AffineCompactType A2c;
A2c.matrix().setRandom();
AffineType A1(A1c);
AffineType A2(A2c);
ProjectiveType P1;
P1.matrix().setRandom();
VectorType v1 = VectorType::Random();
VectorType v2 = VectorType::Random();
HVectorType h1 = HVectorType::Random();
Scalar s1 = internal::random<Scalar>();
LinearType L = LinearType::Random();
MatrixType M = MatrixType::Random();
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, A2, v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, A2c, v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, v1.asDiagonal(), v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, ScalingType(v1), v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, Scaling(v1), v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, Scaling(s1), v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, TranslationType(v1), v2, h1));
CALL_SUBTEST(transform_associativity_left(A1c, A1, P1, L, v2, h1));
CALL_SUBTEST(transform_associativity2(A1c, A1, P1, R, v2, h1));
VERIFY_IS_APPROX(A1 * (M * h1), (A1 * M) * h1);
VERIFY_IS_APPROX(A1c * (M * h1), (A1c * M) * h1);
VERIFY_IS_APPROX(P1 * (M * h1), (P1 * M) * h1);
VERIFY_IS_APPROX(M * (A1 * h1), (M * A1) * h1);
VERIFY_IS_APPROX(M * (A1c * h1), (M * A1c) * h1);
VERIFY_IS_APPROX(M * (P1 * h1), ((M * P1) * h1));
}
template <typename Scalar>
void transform_alignment() {
typedef Transform<Scalar, 3, Projective, AutoAlign> Projective3a;
typedef Transform<Scalar, 3, Projective, DontAlign> Projective3u;
EIGEN_ALIGN_MAX Scalar array1[16];
EIGEN_ALIGN_MAX Scalar array2[16];
EIGEN_ALIGN_MAX Scalar array3[16 + 1];
Scalar* array3u = array3 + 1;
Projective3a* p1 = ::new (reinterpret_cast<void*>(array1)) Projective3a;
Projective3u* p2 = ::new (reinterpret_cast<void*>(array2)) Projective3u;
Projective3u* p3 = ::new (reinterpret_cast<void*>(array3u)) Projective3u;
p1->matrix().setRandom();
*p2 = *p1;
*p3 = *p1;
VERIFY_IS_APPROX(p1->matrix(), p2->matrix());
VERIFY_IS_APPROX(p1->matrix(), p3->matrix());
VERIFY_IS_APPROX((*p1) * (*p1), (*p2) * (*p3));
}
template <typename Scalar, int Dim, int Options>
void transform_products() {
typedef Matrix<Scalar, Dim + 1, Dim + 1> Mat;
typedef Transform<Scalar, Dim, Projective, Options> Proj;
typedef Transform<Scalar, Dim, Affine, Options> Aff;
typedef Transform<Scalar, Dim, AffineCompact, Options> AffC;
Proj p;
p.matrix().setRandom();
Aff a;
a.linear().setRandom();
a.translation().setRandom();
AffC ac = a;
Mat p_m(p.matrix()), a_m(a.matrix());
VERIFY_IS_APPROX((p * p).matrix(), p_m * p_m);
VERIFY_IS_APPROX((a * a).matrix(), a_m * a_m);
VERIFY_IS_APPROX((p * a).matrix(), p_m * a_m);
VERIFY_IS_APPROX((a * p).matrix(), a_m * p_m);
VERIFY_IS_APPROX((ac * a).matrix(), a_m * a_m);
VERIFY_IS_APPROX((a * ac).matrix(), a_m * a_m);
VERIFY_IS_APPROX((p * ac).matrix(), p_m * a_m);
VERIFY_IS_APPROX((ac * p).matrix(), a_m * p_m);
}
template <typename Scalar, int Mode, int Options>
void transformations_no_scale() {
/* this test covers the following files:
Cross.h Quaternion.h, Transform.h
*/
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Matrix<Scalar, 4, 1> Vector4;
typedef Quaternion<Scalar> Quaternionx;
typedef AngleAxis<Scalar> AngleAxisx;
typedef Transform<Scalar, 3, Mode, Options> Transform3;
typedef Translation<Scalar, 3> Translation3;
typedef Matrix<Scalar, 4, 4> Matrix4;
Vector3 v0 = Vector3::Random(), v1 = Vector3::Random();
Transform3 t0, t1, t2;
Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
Quaternionx q1, q2;
q1 = AngleAxisx(a, v0.normalized());
t0 = Transform3::Identity();
VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
t0.setIdentity();
t1.setIdentity();
v1 = Vector3::Ones();
t0.linear() = q1.toRotationMatrix();
t0.pretranslate(v0);
t1.linear() = q1.conjugate().toRotationMatrix();
t1.translate(-v0);
VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
t1.fromPositionOrientationScale(v0, q1, v1);
VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
VERIFY_IS_APPROX(t1 * v1, t0 * v1);
// translation * vector
t0.setIdentity();
t0.translate(v0);
VERIFY_IS_APPROX((t0 * v1).template head<3>(), Translation3(v0) * v1);
// Conversion to matrix.
Transform3 t3;
t3.linear() = q1.toRotationMatrix();
t3.translation() = v1;
Matrix4 m3 = t3.matrix();
VERIFY((m3 * m3.inverse()).isIdentity(test_precision<Scalar>()));
// Verify implicit last row is initialized.
VERIFY_IS_APPROX(Vector4(m3.row(3)), Vector4(0.0, 0.0, 0.0, 1.0));
VERIFY_IS_APPROX(t3.rotation(), t3.linear());
if (Mode == Isometry) VERIFY(t3.rotation().data() == t3.linear().data());
}
template <typename Scalar, int Mode, int Options>
void transformations_computed_scaling_continuity() {
typedef Matrix<Scalar, 3, 1> Vector3;
typedef Transform<Scalar, 3, Mode, Options> Transform3;
typedef Matrix<Scalar, 3, 3> Matrix3;
// Given: two transforms that differ by '2*eps'.
Scalar eps(1e-3);
Vector3 v0 = Vector3::Random().normalized(), v1 = Vector3::Random().normalized(), v3 = Vector3::Random().normalized();
Transform3 t0, t1;
// The interesting case is when their determinants have different signs.
Matrix3 rank2 = 50 * v0 * v0.adjoint() + 20 * v1 * v1.adjoint();
t0.linear() = rank2 + eps * v3 * v3.adjoint();
t1.linear() = rank2 - eps * v3 * v3.adjoint();
// When: computing the rotation-scaling parts
Matrix3 r0, s0, r1, s1;
t0.computeRotationScaling(&r0, &s0);
t1.computeRotationScaling(&r1, &s1);
// Then: the scaling parts should differ by no more than '2*eps'.
const Scalar c(2.1); // 2 + room for rounding errors
VERIFY((s0 - s1).norm() < c * eps);
}
EIGEN_DECLARE_TEST(geo_transformations) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1((transformations<double, Affine, AutoAlign>()));
CALL_SUBTEST_1((non_projective_only<double, Affine, AutoAlign>()));
CALL_SUBTEST_1((transformations_computed_scaling_continuity<double, Affine, AutoAlign>()));
CALL_SUBTEST_2((transformations<float, AffineCompact, AutoAlign>()));
CALL_SUBTEST_2((non_projective_only<float, AffineCompact, AutoAlign>()));
CALL_SUBTEST_2((transform_alignment<float>()));
CALL_SUBTEST_3((transformations<double, Projective, AutoAlign>()));
CALL_SUBTEST_3((transformations<double, Projective, DontAlign>()));
CALL_SUBTEST_3((transform_alignment<double>()));
CALL_SUBTEST_4((transformations<float, Affine, RowMajor | AutoAlign>()));
CALL_SUBTEST_4((non_projective_only<float, Affine, RowMajor>()));
CALL_SUBTEST_5((transformations<double, AffineCompact, RowMajor | AutoAlign>()));
CALL_SUBTEST_5((non_projective_only<double, AffineCompact, RowMajor>()));
CALL_SUBTEST_6((transformations<double, Projective, RowMajor | AutoAlign>()));
CALL_SUBTEST_6((transformations<double, Projective, RowMajor | DontAlign>()));
CALL_SUBTEST_7((transform_products<double, 3, RowMajor | AutoAlign>()));
CALL_SUBTEST_7((transform_products<float, 2, AutoAlign>()));
CALL_SUBTEST_8((transform_associativity<double, 2, ColMajor>(
Rotation2D<double>(internal::random<double>() * double(EIGEN_PI)))));
CALL_SUBTEST_8((transform_associativity<double, 3, ColMajor>(Quaterniond::UnitRandom())));
CALL_SUBTEST_9((transformations_no_scale<double, Affine, AutoAlign>()));
CALL_SUBTEST_9((transformations_no_scale<double, Isometry, AutoAlign>()));
}
}
+447
View File
@@ -0,0 +1,447 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2015-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// workaround issue between gcc >= 4.7 and cuda 5.5
#if (defined __GNUC__) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 7)
#undef _GLIBCXX_ATOMIC_BUILTINS
#undef _GLIBCXX_USE_INT128
#endif
#define EIGEN_TEST_NO_LONGDOUBLE
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
#define EIGEN_USE_GPU
#include "main.h"
#include "gpu_common.h"
// Check that dense modules can be properly parsed by nvcc
#include <Eigen/Dense>
// struct Foo{
// EIGEN_DEVICE_FUNC
// void operator()(int i, const float* mats, float* vecs) const {
// using namespace Eigen;
// // Matrix3f M(data);
// // Vector3f x(data+9);
// // Map<Vector3f>(data+9) = M.inverse() * x;
// Matrix3f M(mats+i/16);
// Vector3f x(vecs+i*3);
// // using std::min;
// // using std::sqrt;
// Map<Vector3f>(vecs+i*3) << x.minCoeff(), 1, 2;// / x.dot(x);//(M.inverse() * x) / x.x();
// //x = x*2 + x.y() * x + x * x.maxCoeff() - x / x.sum();
// }
// };
template <typename T>
struct coeff_wise {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
T x1(in + i);
T x2(in + i + 1);
T x3(in + i + 2);
Map<T> res(out + i * T::MaxSizeAtCompileTime);
res.array() += (in[0] * x1 + x2).array() * x3.array();
}
};
template <typename T>
struct complex_sqrt {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
typedef typename T::Scalar ComplexType;
typedef typename T::Scalar::value_type ValueType;
const int num_special_inputs = 18;
if (i == 0) {
const ValueType nan = std::numeric_limits<ValueType>::quiet_NaN();
typedef Eigen::Vector<ComplexType, num_special_inputs> SpecialInputs;
SpecialInputs special_in;
special_in.setZero();
int idx = 0;
special_in[idx++] = ComplexType(0, 0);
special_in[idx++] = ComplexType(-0, 0);
special_in[idx++] = ComplexType(0, -0);
special_in[idx++] = ComplexType(-0, -0);
// GCC's fallback sqrt implementation fails for inf inputs.
// It is called when _GLIBCXX_USE_C99_COMPLEX is false or if
// clang includes the GCC header (which temporarily disables
// _GLIBCXX_USE_C99_COMPLEX)
#if !defined(_GLIBCXX_COMPLEX) || (_GLIBCXX_USE_C99_COMPLEX && !defined(__CLANG_CUDA_WRAPPERS_COMPLEX))
const ValueType inf = std::numeric_limits<ValueType>::infinity();
special_in[idx++] = ComplexType(1.0, inf);
special_in[idx++] = ComplexType(nan, inf);
special_in[idx++] = ComplexType(1.0, -inf);
special_in[idx++] = ComplexType(nan, -inf);
special_in[idx++] = ComplexType(-inf, 1.0);
special_in[idx++] = ComplexType(inf, 1.0);
special_in[idx++] = ComplexType(-inf, -1.0);
special_in[idx++] = ComplexType(inf, -1.0);
special_in[idx++] = ComplexType(-inf, nan);
special_in[idx++] = ComplexType(inf, nan);
#endif
special_in[idx++] = ComplexType(1.0, nan);
special_in[idx++] = ComplexType(nan, 1.0);
special_in[idx++] = ComplexType(nan, -1.0);
special_in[idx++] = ComplexType(nan, nan);
Map<SpecialInputs> special_out(out);
special_out = special_in.cwiseSqrt();
}
T x1(in + i);
Map<T> res(out + num_special_inputs + i * T::MaxSizeAtCompileTime);
res = x1.cwiseSqrt();
}
};
template <typename T>
struct complex_operators {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
typedef typename T::Scalar ComplexType;
typedef typename T::Scalar::value_type ValueType;
const int num_scalar_operators = 24;
const int num_vector_operators = 23; // no unary + operator.
int out_idx = i * (num_scalar_operators + num_vector_operators * T::MaxSizeAtCompileTime);
// Scalar operators.
const ComplexType a = in[i];
const ComplexType b = in[i + 1];
out[out_idx++] = +a;
out[out_idx++] = -a;
out[out_idx++] = a + b;
out[out_idx++] = a + numext::real(b);
out[out_idx++] = numext::real(a) + b;
out[out_idx++] = a - b;
out[out_idx++] = a - numext::real(b);
out[out_idx++] = numext::real(a) - b;
out[out_idx++] = a * b;
out[out_idx++] = a * numext::real(b);
out[out_idx++] = numext::real(a) * b;
out[out_idx++] = a / b;
out[out_idx++] = a / numext::real(b);
out[out_idx++] = numext::real(a) / b;
#if !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));
out[out_idx++] = (a == b ? true_value : false_value);
out[out_idx++] = (a == numext::real(b) ? true_value : false_value);
out[out_idx++] = (numext::real(a) == b ? true_value : false_value);
out[out_idx++] = (a != b ? true_value : false_value);
out[out_idx++] = (a != numext::real(b) ? true_value : false_value);
out[out_idx++] = (numext::real(a) != b ? true_value : false_value);
// Vector versions.
T x1(in + i);
T x2(in + i + 1);
const int res_size = T::MaxSizeAtCompileTime * num_scalar_operators;
const int size = T::MaxSizeAtCompileTime;
int block_idx = 0;
Map<VectorX<ComplexType>> res(out + out_idx, res_size);
res.segment(block_idx, size) = -x1;
block_idx += size;
res.segment(block_idx, size) = x1 + x2;
block_idx += size;
res.segment(block_idx, size) = x1 + x2.real();
block_idx += size;
res.segment(block_idx, size) = x1.real() + x2;
block_idx += size;
res.segment(block_idx, size) = x1 - x2;
block_idx += size;
res.segment(block_idx, size) = x1 - x2.real();
block_idx += size;
res.segment(block_idx, size) = x1.real() - x2;
block_idx += size;
res.segment(block_idx, size) = x1.array() * x2.array();
block_idx += size;
res.segment(block_idx, size) = x1.array() * x2.real().array();
block_idx += size;
res.segment(block_idx, size) = x1.real().array() * x2.array();
block_idx += size;
res.segment(block_idx, size) = x1.array() / x2.array();
block_idx += size;
res.segment(block_idx, size) = x1.array() / x2.real().array();
block_idx += size;
res.segment(block_idx, size) = x1.real().array() / x2.array();
block_idx += size;
#if !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;
block_idx += size;
res.segment(block_idx, size) = x1;
res.segment(block_idx, size).array() *= x2.array();
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);
res.segment(block_idx, size) = (x1 == x2 ? true_vector : false_vector);
block_idx += size;
// Mixing types in equality comparison does not work.
// res.segment(block_idx, size) = (x1 == x2.real() ? true_vector : false_vector);
// block_idx += size;
// res.segment(block_idx, size) = (x1.real() == x2 ? true_vector : false_vector);
// block_idx += size;
res.segment(block_idx, size) = (x1 != x2 ? true_vector : false_vector);
block_idx += size;
// res.segment(block_idx, size) = (x1 != x2.real() ? true_vector : false_vector);
// block_idx += size;
// res.segment(block_idx, size) = (x1.real() != x2 ? true_vector : false_vector);
// block_idx += size;
}
};
template <typename T>
struct replicate {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
T x1(in + i);
int step = x1.size() * 4;
int stride = 3 * step;
typedef Map<Array<typename T::Scalar, Dynamic, Dynamic>> MapType;
MapType(out + i * stride + 0 * step, x1.rows() * 2, x1.cols() * 2) = x1.replicate(2, 2);
MapType(out + i * stride + 1 * step, x1.rows() * 3, x1.cols()) = in[i] * x1.colwise().replicate(3);
MapType(out + i * stride + 2 * step, x1.rows(), x1.cols() * 3) = in[i] * x1.rowwise().replicate(3);
}
};
template <typename T>
struct alloc_new_delete {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
int offset = 2 * i * T::MaxSizeAtCompileTime;
T* x = new T(in + offset);
Eigen::Map<T> u(out + offset);
u = *x;
delete x;
offset += T::MaxSizeAtCompileTime;
T* y = new T[1];
y[0] = T(in + offset);
Eigen::Map<T> v(out + offset);
v = y[0];
delete[] y;
}
};
template <typename T>
struct redux {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
int N = 10;
T x1(in + i);
out[i * N + 0] = x1.minCoeff();
out[i * N + 1] = x1.maxCoeff();
out[i * N + 2] = x1.sum();
out[i * N + 3] = x1.prod();
out[i * N + 4] = x1.matrix().squaredNorm();
out[i * N + 5] = x1.matrix().norm();
out[i * N + 6] = x1.colwise().sum().maxCoeff();
out[i * N + 7] = x1.rowwise().maxCoeff().sum();
out[i * N + 8] = x1.matrix().colwise().squaredNorm().sum();
}
};
template <typename T1, typename T2>
struct prod_test {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T1::Scalar* in, typename T1::Scalar* out) const {
using namespace Eigen;
typedef Matrix<typename T1::Scalar, T1::RowsAtCompileTime, T2::ColsAtCompileTime> T3;
T1 x1(in + i);
T2 x2(in + i + 1);
Map<T3> res(out + i * T3::MaxSizeAtCompileTime);
res += in[i] * x1 * x2;
}
};
template <typename T1, typename T2>
struct diagonal {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T1::Scalar* in, typename T1::Scalar* out) const {
using namespace Eigen;
T1 x1(in + i);
Map<T2> res(out + i * T2::MaxSizeAtCompileTime);
res += x1.diagonal();
}
};
template <typename T>
struct eigenvalues_direct {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
typedef Matrix<typename T::Scalar, T::RowsAtCompileTime, 1> Vec;
T M(in + i);
Map<Vec> res(out + i * Vec::MaxSizeAtCompileTime);
T A = M * M.adjoint();
SelfAdjointEigenSolver<T> eig;
eig.computeDirect(A);
res = eig.eigenvalues();
}
};
template <typename T>
struct eigenvalues {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
typedef Matrix<typename T::Scalar, T::RowsAtCompileTime, 1> Vec;
T M(in + i);
Map<Vec> res(out + i * Vec::MaxSizeAtCompileTime);
T A = M * M.adjoint();
SelfAdjointEigenSolver<T> eig;
eig.compute(A);
res = eig.eigenvalues();
}
};
template <typename T>
struct matrix_inverse {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
using namespace Eigen;
T M(in + i);
Map<T> res(out + i * T::MaxSizeAtCompileTime);
res = M.inverse();
}
};
template <typename T>
struct numeric_limits_test {
EIGEN_DEVICE_FUNC void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const {
EIGEN_UNUSED_VARIABLE(in)
int out_idx = i * 5;
out[out_idx++] = numext::numeric_limits<float>::epsilon();
out[out_idx++] = (numext::numeric_limits<float>::max)();
out[out_idx++] = (numext::numeric_limits<float>::min)();
out[out_idx++] = numext::numeric_limits<float>::infinity();
out[out_idx++] = numext::numeric_limits<float>::quiet_NaN();
}
};
template <typename Type1, typename Type2>
bool verifyIsApproxWithInfsNans(const Type1& a, const Type2& b,
typename Type1::Scalar* = 0) // Enabled for Eigen's type only
{
if (a.rows() != b.rows()) {
return false;
}
if (a.cols() != b.cols()) {
return false;
}
for (Index r = 0; r < a.rows(); ++r) {
for (Index c = 0; c < a.cols(); ++c) {
if (a(r, c) != b(r, c) && !((numext::isnan)(a(r, c)) && (numext::isnan)(b(r, c))) &&
!test_isApprox(a(r, c), b(r, c))) {
return false;
}
}
}
return true;
}
template <typename Kernel, typename Input, typename Output>
void test_with_infs_nans(const Kernel& ker, int n, const Input& in, Output& out) {
Output out_ref, out_gpu;
#if !defined(EIGEN_GPU_COMPILE_PHASE)
out_ref = out_gpu = out;
#else
EIGEN_UNUSED_VARIABLE(in);
EIGEN_UNUSED_VARIABLE(out);
#endif
run_on_cpu(ker, n, in, out_ref);
run_on_gpu(ker, n, in, out_gpu);
#if !defined(EIGEN_GPU_COMPILE_PHASE)
verifyIsApproxWithInfsNans(out_ref, out_gpu);
#endif
}
EIGEN_DECLARE_TEST(gpu_basic) {
ei_test_init_gpu();
int nthreads = 100;
Eigen::VectorXf in, out;
Eigen::VectorXcf cfin, cfout;
#if !defined(EIGEN_GPU_COMPILE_PHASE)
int data_size = nthreads * 512;
in.setRandom(data_size);
out.setConstant(data_size, -1);
cfin.setRandom(data_size);
cfout.setConstant(data_size, -1);
#endif
CALL_SUBTEST(run_and_compare_to_gpu(coeff_wise<Vector3f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(coeff_wise<Array44f>(), nthreads, in, out));
#if !defined(EIGEN_USE_HIP)
// FIXME
// These subtests result in a compile failure on the HIP platform
//
// eigen-upstream/Eigen/src/Core/Replicate.h:61:65: error:
// base class 'internal::dense_xpr_base<Replicate<Array<float, 4, 1, 0, 4, 1>, -1, -1> >::type'
// (aka 'ArrayBase<Eigen::Replicate<Eigen::Array<float, 4, 1, 0, 4, 1>, -1, -1> >') has protected default
// constructor
CALL_SUBTEST(run_and_compare_to_gpu(replicate<Array4f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(replicate<Array33f>(), nthreads, in, out));
// HIP does not support new/delete on device.
CALL_SUBTEST(run_and_compare_to_gpu(alloc_new_delete<Vector3f>(), nthreads, in, out));
#endif
CALL_SUBTEST(run_and_compare_to_gpu(redux<Array4f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(redux<Matrix3f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(prod_test<Matrix3f, Matrix3f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(prod_test<Matrix4f, Vector4f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(diagonal<Matrix3f, Vector3f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(diagonal<Matrix4f, Vector4f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(matrix_inverse<Matrix2f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(matrix_inverse<Matrix3f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(matrix_inverse<Matrix4f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(eigenvalues_direct<Matrix3f>(), nthreads, in, out));
CALL_SUBTEST(run_and_compare_to_gpu(eigenvalues_direct<Matrix2f>(), nthreads, in, out));
// Test std::complex.
CALL_SUBTEST(run_and_compare_to_gpu(complex_operators<Vector3cf>(), nthreads, cfin, cfout));
CALL_SUBTEST(test_with_infs_nans(complex_sqrt<Vector3cf>(), nthreads, cfin, cfout));
// numeric_limits
CALL_SUBTEST(test_with_infs_nans(numeric_limits_test<Vector3f>(), 1, in, out));
// These tests require dynamic-sized matrix multiplcation, which isn't currently
// supported on GPU.
// CALL_SUBTEST( run_and_compare_to_gpu(eigenvalues<Matrix4f>(), nthreads, in, out) );
// typedef Matrix<float,6,6> Matrix6f;
// CALL_SUBTEST( run_and_compare_to_gpu(eigenvalues<Matrix6f>(), nthreads, in, out) );
}
+161
View File
@@ -0,0 +1,161 @@
#ifndef EIGEN_TEST_GPU_COMMON_H
#define EIGEN_TEST_GPU_COMMON_H
#ifdef EIGEN_USE_HIP
#include <hip/hip_runtime.h>
#include <hip/hip_runtime_api.h>
#else
#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_runtime_api.h>
#endif
#include <iostream>
#if !defined(__CUDACC__) && !defined(__HIPCC__)
dim3 threadIdx, blockDim, blockIdx;
#endif
template <typename Kernel, typename Input, typename Output>
void run_on_cpu(const Kernel& ker, int n, const Input& in, Output& out) {
for (int i = 0; i < n; i++) ker(i, in.data(), out.data());
}
template <typename Kernel, typename Input, typename Output>
__global__ EIGEN_HIP_LAUNCH_BOUNDS_1024 void run_on_gpu_meta_kernel(const Kernel ker, int n, const Input* in,
Output* out) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
if (i < n) {
ker(i, in, out);
}
}
template <typename Kernel, typename Input, typename Output>
void run_on_gpu(const Kernel& ker, int n, const Input& in, Output& out) {
typename Input::Scalar* d_in;
typename Output::Scalar* d_out;
std::ptrdiff_t in_bytes = in.size() * sizeof(typename Input::Scalar);
std::ptrdiff_t out_bytes = out.size() * sizeof(typename Output::Scalar);
gpuMalloc((void**)(&d_in), in_bytes);
gpuMalloc((void**)(&d_out), out_bytes);
gpuMemcpy(d_in, in.data(), in_bytes, gpuMemcpyHostToDevice);
gpuMemcpy(d_out, out.data(), out_bytes, gpuMemcpyHostToDevice);
// Simple and non-optimal 1D mapping assuming n is not too large
// That's only for unit testing!
dim3 Blocks(128);
dim3 Grids((n + int(Blocks.x) - 1) / int(Blocks.x));
gpuDeviceSynchronize();
#ifdef EIGEN_USE_HIP
hipLaunchKernelGGL(HIP_KERNEL_NAME(run_on_gpu_meta_kernel<Kernel, typename std::decay<decltype(*d_in)>::type,
typename std::decay<decltype(*d_out)>::type>),
dim3(Grids), dim3(Blocks), 0, 0, ker, n, d_in, d_out);
#else
// Various versions of clang-format incorrectly add spaces to the kernel launch brackets.
// clang-format off
run_on_gpu_meta_kernel<<<Grids, Blocks>>>(ker, n, d_in, d_out);
// clang-format on
#endif
// Pre-launch errors.
gpuError_t err = gpuGetLastError();
if (err != gpuSuccess) {
printf("%s: %s\n", gpuGetErrorName(err), gpuGetErrorString(err));
gpu_assert(false);
}
// Kernel execution errors.
err = gpuDeviceSynchronize();
if (err != gpuSuccess) {
printf("%s: %s\n", gpuGetErrorName(err), gpuGetErrorString(err));
gpu_assert(false);
}
// check inputs have not been modified
gpuMemcpy(const_cast<typename Input::Scalar*>(in.data()), d_in, in_bytes, gpuMemcpyDeviceToHost);
gpuMemcpy(out.data(), d_out, out_bytes, gpuMemcpyDeviceToHost);
gpuFree(d_in);
gpuFree(d_out);
}
template <typename Kernel, typename Input, typename Output>
void run_and_compare_to_gpu(const Kernel& ker, int n, const Input& in, Output& out) {
Input in_ref, in_gpu;
Output out_ref, out_gpu;
#if !defined(EIGEN_GPU_COMPILE_PHASE)
in_ref = in_gpu = in;
out_ref = out_gpu = out;
#else
EIGEN_UNUSED_VARIABLE(in);
EIGEN_UNUSED_VARIABLE(out);
#endif
run_on_cpu(ker, n, in_ref, out_ref);
run_on_gpu(ker, n, in_gpu, out_gpu);
#if !defined(EIGEN_GPU_COMPILE_PHASE)
VERIFY_IS_APPROX(in_ref, in_gpu);
VERIFY_IS_APPROX(out_ref, out_gpu);
#endif
}
struct compile_time_device_info {
EIGEN_DEVICE_FUNC void operator()(int i, const int* /*in*/, int* info) const {
if (i == 0) {
EIGEN_UNUSED_VARIABLE(info)
#if defined(__CUDA_ARCH__)
info[0] = int(__CUDA_ARCH__ + 0);
#endif
#if defined(EIGEN_HIP_DEVICE_COMPILE)
info[1] = int(EIGEN_HIP_DEVICE_COMPILE + 0);
#endif
}
}
};
void ei_test_init_gpu() {
int device = 0;
gpuDeviceProp_t deviceProp;
gpuGetDeviceProperties(&deviceProp, device);
ArrayXi dummy(1), info(10);
info = -1;
run_on_gpu(compile_time_device_info(), 10, dummy, info);
std::cout << "GPU compile-time info:\n";
#ifdef EIGEN_CUDACC
std::cout << " EIGEN_CUDACC: " << int(EIGEN_CUDACC) << "\n";
#endif
#ifdef EIGEN_CUDA_SDK_VER
std::cout << " EIGEN_CUDA_SDK_VER: " << int(EIGEN_CUDA_SDK_VER) << "\n";
#endif
#if EIGEN_COMP_NVCC
std::cout << " EIGEN_COMP_NVCC: " << int(EIGEN_COMP_NVCC) << "\n";
#endif
#ifdef EIGEN_HIPCC
std::cout << " EIGEN_HIPCC: " << int(EIGEN_HIPCC) << "\n";
#endif
std::cout << " EIGEN_CUDA_ARCH: " << info[0] << "\n";
std::cout << " EIGEN_HIP_DEVICE_COMPILE: " << info[1] << "\n";
std::cout << "GPU device info:\n";
std::cout << " name: " << deviceProp.name << "\n";
std::cout << " capability: " << deviceProp.major << "." << deviceProp.minor << "\n";
std::cout << " multiProcessorCount: " << deviceProp.multiProcessorCount << "\n";
std::cout << " maxThreadsPerMultiProcessor: " << deviceProp.maxThreadsPerMultiProcessor << "\n";
std::cout << " warpSize: " << deviceProp.warpSize << "\n";
std::cout << " regsPerBlock: " << deviceProp.regsPerBlock << "\n";
std::cout << " concurrentKernels: " << deviceProp.concurrentKernels << "\n";
std::cout << " clockRate: " << deviceProp.clockRate << "\n";
std::cout << " canMapHostMemory: " << deviceProp.canMapHostMemory << "\n";
std::cout << " computeMode: " << deviceProp.computeMode << "\n";
}
#endif // EIGEN_TEST_GPU_COMMON_H
+120
View File
@@ -0,0 +1,120 @@
// 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.
#define EIGEN_USE_GPU
#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()));
}
}
+448
View File
@@ -0,0 +1,448 @@
#ifndef GPU_TEST_HELPER_H
#define GPU_TEST_HELPER_H
#include <Eigen/Core>
// Allow gpu** macros for generic tests.
#include <Eigen/src/Core/util/GpuHipCudaDefines.inc>
// 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::get;
using std::make_tuple;
using std::tie;
using std::tuple;
#else
using tuple_impl::get;
using tuple_impl::make_tuple;
using tuple_impl::tie;
using tuple_impl::tuple;
#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
#if 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
+346
View File
@@ -0,0 +1,346 @@
// 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 <sstream>
#include "main.h"
#define VERIFY_HALF_BITS_EQUAL(h, bits) \
VERIFY_IS_EQUAL((numext::bit_cast<numext::uint16_t>(h)), (static_cast<numext::uint16_t>(bits)))
// Make sure it's possible to forward declare Eigen::half
namespace Eigen {
struct half;
}
using Eigen::half;
void test_conversion() {
using Eigen::half_impl::__half_raw;
// Round-trip bit-cast with uint16.
VERIFY_IS_EQUAL(numext::bit_cast<half>(numext::bit_cast<numext::uint16_t>(half(1.0f))), half(1.0f));
VERIFY_IS_EQUAL(numext::bit_cast<half>(numext::bit_cast<numext::uint16_t>(half(0.5f))), half(0.5f));
VERIFY_IS_EQUAL(numext::bit_cast<half>(numext::bit_cast<numext::uint16_t>(half(-0.33333f))), half(-0.33333f));
VERIFY_IS_EQUAL(numext::bit_cast<half>(numext::bit_cast<numext::uint16_t>(half(0.0f))), half(0.0f));
// Conversion from float.
VERIFY_HALF_BITS_EQUAL(half(1.0f), 0x3c00);
VERIFY_HALF_BITS_EQUAL(half(0.5f), 0x3800);
VERIFY_HALF_BITS_EQUAL(half(0.33333f), 0x3555);
VERIFY_HALF_BITS_EQUAL(half(0.0f), 0x0000);
VERIFY_HALF_BITS_EQUAL(half(-0.0f), 0x8000);
VERIFY_HALF_BITS_EQUAL(half(65504.0f), 0x7bff);
VERIFY_HALF_BITS_EQUAL(half(65536.0f), 0x7c00); // Becomes infinity.
// Denormals.
VERIFY_HALF_BITS_EQUAL(half(-5.96046e-08f), 0x8001);
VERIFY_HALF_BITS_EQUAL(half(5.96046e-08f), 0x0001);
VERIFY_HALF_BITS_EQUAL(half(1.19209e-07f), 0x0002);
// Verify round-to-nearest-even behavior.
float val1 = float(half(__half_raw(0x3c00)));
float val2 = float(half(__half_raw(0x3c01)));
float val3 = float(half(__half_raw(0x3c02)));
VERIFY_HALF_BITS_EQUAL(half(0.5f * (val1 + val2)), 0x3c00);
VERIFY_HALF_BITS_EQUAL(half(0.5f * (val2 + val3)), 0x3c02);
// Conversion from int.
VERIFY_HALF_BITS_EQUAL(half(-1), 0xbc00);
VERIFY_HALF_BITS_EQUAL(half(0), 0x0000);
VERIFY_HALF_BITS_EQUAL(half(1), 0x3c00);
VERIFY_HALF_BITS_EQUAL(half(2), 0x4000);
VERIFY_HALF_BITS_EQUAL(half(3), 0x4200);
// Conversion from bool.
VERIFY_HALF_BITS_EQUAL(half(false), 0x0000);
VERIFY_HALF_BITS_EQUAL(half(true), 0x3c00);
// Conversion to float.
VERIFY_IS_EQUAL(float(half(__half_raw(0x0000))), 0.0f);
VERIFY_IS_EQUAL(float(half(__half_raw(0x3c00))), 1.0f);
// Denormals.
VERIFY_IS_APPROX(float(half(__half_raw(0x8001))), -5.96046e-08f);
VERIFY_IS_APPROX(float(half(__half_raw(0x0001))), 5.96046e-08f);
VERIFY_IS_APPROX(float(half(__half_raw(0x0002))), 1.19209e-07f);
// NaNs and infinities.
VERIFY(!(numext::isinf)(float(half(65504.0f)))); // Largest finite number.
VERIFY(!(numext::isnan)(float(half(0.0f))));
VERIFY((numext::isfinite)(float(half(65504.0f))));
VERIFY((numext::isfinite)(float(half(0.0f))));
VERIFY((numext::isinf)(float(half(__half_raw(0xfc00)))));
VERIFY((numext::isnan)(float(half(__half_raw(0xfc01)))));
VERIFY((numext::isinf)(float(half(__half_raw(0x7c00)))));
VERIFY((numext::isnan)(float(half(__half_raw(0x7c01)))));
VERIFY((numext::isnan)(float(NumTraits<half>::quiet_NaN())));
VERIFY((numext::isinf)(float(NumTraits<half>::infinity())));
VERIFY((numext::isinf)(float(-NumTraits<half>::infinity())));
// Exactly same checks as above, just directly on the half representation.
VERIFY(!(numext::isinf)(half(__half_raw(0x7bff))));
VERIFY(!(numext::isnan)(half(__half_raw(0x0000))));
VERIFY((numext::isinf)(half(__half_raw(0xfc00))));
VERIFY((numext::isnan)(half(__half_raw(0xfc01))));
VERIFY((numext::isinf)(half(__half_raw(0x7c00))));
VERIFY((numext::isnan)(half(__half_raw(0x7c01))));
VERIFY((numext::isnan)(NumTraits<half>::quiet_NaN()));
VERIFY((numext::isinf)(NumTraits<half>::infinity()));
VERIFY((numext::isinf)(-NumTraits<half>::infinity()));
// Conversion to bool
VERIFY(!static_cast<bool>(half(0.0)));
VERIFY(!static_cast<bool>(half(-0.0)));
VERIFY(static_cast<bool>(half(__half_raw(0x7bff))));
VERIFY(static_cast<bool>(half(-0.33333)));
VERIFY(static_cast<bool>(half(1.0)));
VERIFY(static_cast<bool>(half(-1.0)));
VERIFY(static_cast<bool>(half(-5.96046e-08f)));
}
void test_numtraits() {
std::cout << "epsilon = " << NumTraits<half>::epsilon() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<half>::epsilon()) << ")" << std::endl;
std::cout << "highest = " << NumTraits<half>::highest() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<half>::highest()) << ")" << std::endl;
std::cout << "lowest = " << NumTraits<half>::lowest() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<half>::lowest()) << ")" << std::endl;
std::cout << "min = " << (std::numeric_limits<half>::min)() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(half((std::numeric_limits<half>::min)())) << ")" << std::endl;
std::cout << "denorm min = " << (std::numeric_limits<half>::denorm_min)() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(half((std::numeric_limits<half>::denorm_min)())) << ")" << std::endl;
std::cout << "infinity = " << NumTraits<half>::infinity() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<half>::infinity()) << ")" << std::endl;
std::cout << "quiet nan = " << NumTraits<half>::quiet_NaN() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(NumTraits<half>::quiet_NaN()) << ")" << std::endl;
std::cout << "signaling nan = " << std::numeric_limits<half>::signaling_NaN() << " (0x" << std::hex
<< numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::signaling_NaN()) << ")" << std::endl;
VERIFY(NumTraits<half>::IsSigned);
VERIFY_IS_EQUAL(numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::infinity()),
numext::bit_cast<numext::uint16_t>(half(std::numeric_limits<float>::infinity())));
// There is no guarantee that casting a 32-bit NaN to 16-bit has a precise
// bit pattern. We test that it is in fact a NaN, then test the signaling
// bit (msb of significand is 1 for quiet, 0 for signaling).
const numext::uint16_t HALF_QUIET_BIT = 0x0200;
VERIFY((numext::isnan)(std::numeric_limits<half>::quiet_NaN()) &&
(numext::isnan)(half(std::numeric_limits<float>::quiet_NaN())) &&
((numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::quiet_NaN()) & HALF_QUIET_BIT) > 0) &&
((numext::bit_cast<numext::uint16_t>(half(std::numeric_limits<float>::quiet_NaN())) & HALF_QUIET_BIT) > 0));
// After a cast to half, a signaling NaN may become non-signaling
// (e.g. in the case of casting float to native __fp16). Thus, we check that
// both are NaN, and that only the `numeric_limits` version is signaling.
VERIFY((numext::isnan)(std::numeric_limits<half>::signaling_NaN()) &&
(numext::isnan)(half(std::numeric_limits<float>::signaling_NaN())) &&
((numext::bit_cast<numext::uint16_t>(std::numeric_limits<half>::signaling_NaN()) & HALF_QUIET_BIT) == 0));
VERIFY((std::numeric_limits<half>::min)() > half(0.f));
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() {
VERIFY_IS_EQUAL(float(half(2) + half(2)), 4);
VERIFY_IS_EQUAL(float(half(2) + half(-2)), 0);
VERIFY_IS_APPROX(float(half(0.33333f) + half(0.66667f)), 1.0f);
VERIFY_IS_EQUAL(float(half(2.0f) * half(-5.5f)), -11.0f);
VERIFY_IS_APPROX(float(half(1.0f) / half(3.0f)), 0.33333f);
VERIFY_IS_EQUAL(float(-half(4096.0f)), -4096.0f);
VERIFY_IS_EQUAL(float(-half(-4096.0f)), 4096.0f);
half x(3);
half y = ++x;
VERIFY_IS_EQUAL(x, half(4));
VERIFY_IS_EQUAL(y, half(4));
y = --x;
VERIFY_IS_EQUAL(x, half(3));
VERIFY_IS_EQUAL(y, half(3));
y = x++;
VERIFY_IS_EQUAL(x, half(4));
VERIFY_IS_EQUAL(y, half(3));
y = x--;
VERIFY_IS_EQUAL(x, half(3));
VERIFY_IS_EQUAL(y, half(4));
}
void test_comparison() {
VERIFY(half(1.0f) > half(0.5f));
VERIFY(half(0.5f) < half(1.0f));
VERIFY(!(half(1.0f) < half(0.5f)));
VERIFY(!(half(0.5f) > half(1.0f)));
VERIFY(!(half(4.0f) > half(4.0f)));
VERIFY(!(half(4.0f) < half(4.0f)));
VERIFY(!(half(0.0f) < half(-0.0f)));
VERIFY(!(half(-0.0f) < half(0.0f)));
VERIFY(!(half(0.0f) > half(-0.0f)));
VERIFY(!(half(-0.0f) > half(0.0f)));
VERIFY(half(0.2f) > half(-1.0f));
VERIFY(half(-1.0f) < half(0.2f));
VERIFY(half(-16.0f) < half(-15.0f));
VERIFY(half(1.0f) == half(1.0f));
VERIFY(half(1.0f) != half(2.0f));
// Comparisons with NaNs and infinities.
VERIFY(!(NumTraits<half>::quiet_NaN() == NumTraits<half>::quiet_NaN()));
VERIFY(NumTraits<half>::quiet_NaN() != NumTraits<half>::quiet_NaN());
VERIFY(!(internal::random<half>() == NumTraits<half>::quiet_NaN()));
VERIFY(!(internal::random<half>() < NumTraits<half>::quiet_NaN()));
VERIFY(!(internal::random<half>() > NumTraits<half>::quiet_NaN()));
VERIFY(!(internal::random<half>() <= NumTraits<half>::quiet_NaN()));
VERIFY(!(internal::random<half>() >= NumTraits<half>::quiet_NaN()));
VERIFY(internal::random<half>() != NumTraits<half>::quiet_NaN());
VERIFY(!(NumTraits<half>::quiet_NaN() == internal::random<half>()));
VERIFY(!(NumTraits<half>::quiet_NaN() < internal::random<half>()));
VERIFY(!(NumTraits<half>::quiet_NaN() > internal::random<half>()));
VERIFY(!(NumTraits<half>::quiet_NaN() <= internal::random<half>()));
VERIFY(!(NumTraits<half>::quiet_NaN() >= internal::random<half>()));
VERIFY(NumTraits<half>::quiet_NaN() != internal::random<half>());
VERIFY(internal::random<half>() < NumTraits<half>::infinity());
VERIFY(internal::random<half>() > -NumTraits<half>::infinity());
}
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);
VERIFY_IS_EQUAL(float(abs(half(-3.5f))), 3.5f);
VERIFY_IS_EQUAL(float(numext::floor(half(3.5f))), 3.0f);
VERIFY_IS_EQUAL(float(floor(half(3.5f))), 3.0f);
VERIFY_IS_EQUAL(float(numext::floor(half(-3.5f))), -4.0f);
VERIFY_IS_EQUAL(float(floor(half(-3.5f))), -4.0f);
VERIFY_IS_EQUAL(float(numext::ceil(half(3.5f))), 4.0f);
VERIFY_IS_EQUAL(float(ceil(half(3.5f))), 4.0f);
VERIFY_IS_EQUAL(float(numext::ceil(half(-3.5f))), -3.0f);
VERIFY_IS_EQUAL(float(ceil(half(-3.5f))), -3.0f);
VERIFY_IS_APPROX(float(numext::sqrt(half(0.0f))), 0.0f);
VERIFY_IS_APPROX(float(sqrt(half(0.0f))), 0.0f);
VERIFY_IS_APPROX(float(numext::sqrt(half(4.0f))), 2.0f);
VERIFY_IS_APPROX(float(sqrt(half(4.0f))), 2.0f);
VERIFY_IS_APPROX(float(numext::pow(half(0.0f), half(1.0f))), 0.0f);
VERIFY_IS_APPROX(float(pow(half(0.0f), half(1.0f))), 0.0f);
VERIFY_IS_APPROX(float(numext::pow(half(2.0f), half(2.0f))), 4.0f);
VERIFY_IS_APPROX(float(pow(half(2.0f), half(2.0f))), 4.0f);
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(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);
VERIFY_IS_APPROX(float(numext::expm1(half(2.0f))), 6.3890561f);
VERIFY_IS_APPROX(float(expm1(half(2.0f))), 6.3890561f);
VERIFY_IS_EQUAL(float(numext::log(half(1.0f))), 0.0f);
VERIFY_IS_EQUAL(float(log(half(1.0f))), 0.0f);
VERIFY_IS_APPROX(float(numext::log(half(10.0f))), 2.30273f);
VERIFY_IS_APPROX(float(log(half(10.0f))), 2.30273f);
VERIFY_IS_EQUAL(float(numext::log1p(half(0.0f))), 0.0f);
VERIFY_IS_EQUAL(float(log1p(half(0.0f))), 0.0f);
VERIFY_IS_APPROX(float(numext::log1p(half(10.0f))), 2.3978953f);
VERIFY_IS_APPROX(float(log1p(half(10.0f))), 2.3978953f);
VERIFY_IS_APPROX(numext::fmod(half(5.3f), half(2.0f)), half(1.3f));
VERIFY_IS_APPROX(fmod(half(5.3f), half(2.0f)), half(1.3f));
VERIFY_IS_APPROX(numext::fmod(half(-18.5f), half(-4.2f)), half(-1.7f));
VERIFY_IS_APPROX(fmod(half(-18.5f), half(-4.2f)), half(-1.7f));
}
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(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(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(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)));
}
void test_array() {
typedef Array<half, 1, Dynamic> ArrayXh;
Index size = internal::random<Index>(1, 10);
Index i = internal::random<Index>(0, size - 1);
ArrayXh a1 = ArrayXh::Random(size), a2 = ArrayXh::Random(size);
VERIFY_IS_APPROX(a1 + a1, half(2) * a1);
VERIFY((a1.abs() >= half(0)).all());
VERIFY_IS_APPROX((a1 * a1).sqrt(), a1.abs());
VERIFY(((a1.min)(a2) <= (a1.max)(a2)).all());
a1(i) = half(-10.);
VERIFY_IS_EQUAL(a1.minCoeff(), half(-10.));
a1(i) = half(10.);
VERIFY_IS_EQUAL(a1.maxCoeff(), half(10.));
std::stringstream ss;
ss << a1;
}
void test_product() {
typedef Matrix<half, Dynamic, Dynamic> MatrixXh;
Index rows = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
Index cols = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
Index depth = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
MatrixXh Ah = MatrixXh::Random(rows, depth);
MatrixXh Bh = MatrixXh::Random(depth, cols);
MatrixXh Ch = MatrixXh::Random(rows, cols);
MatrixXf Af = Ah.cast<float>();
MatrixXf Bf = Bh.cast<float>();
MatrixXf Cf = Ch.cast<float>();
VERIFY_IS_APPROX(Ch.noalias() += Ah * Bh, (Cf.noalias() += Af * Bf).cast<half>());
}
EIGEN_DECLARE_TEST(half_float) {
CALL_SUBTEST(test_numtraits());
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST(test_conversion());
CALL_SUBTEST(test_arithmetic());
CALL_SUBTEST(test_comparison());
CALL_SUBTEST(test_basic_functions());
CALL_SUBTEST(test_trigonometric_functions());
CALL_SUBTEST(test_array());
CALL_SUBTEST(test_product());
}
}
+61
View File
@@ -0,0 +1,61 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/Eigenvalues>
template <typename Scalar, int Size>
void hessenberg(int size = Size) {
typedef Matrix<Scalar, Size, Size> MatrixType;
// Test basic functionality: A = U H U* and H is Hessenberg
for (int counter = 0; counter < g_repeat; ++counter) {
MatrixType m = MatrixType::Random(size, size);
HessenbergDecomposition<MatrixType> hess(m);
MatrixType Q = hess.matrixQ();
MatrixType H = hess.matrixH();
VERIFY_IS_APPROX(m, Q * H * Q.adjoint());
for (int row = 2; row < size; ++row) {
for (int col = 0; col < row - 1; ++col) {
VERIFY(H(row, col) == (typename MatrixType::Scalar)0);
}
}
}
// Test whether compute() and constructor returns same result
MatrixType A = MatrixType::Random(size, size);
HessenbergDecomposition<MatrixType> cs1;
cs1.compute(A);
HessenbergDecomposition<MatrixType> cs2(A);
VERIFY_IS_EQUAL(cs1.matrixH().eval(), cs2.matrixH().eval());
MatrixType cs1Q = cs1.matrixQ();
MatrixType cs2Q = cs2.matrixQ();
VERIFY_IS_EQUAL(cs1Q, cs2Q);
// Test assertions for when used uninitialized
HessenbergDecomposition<MatrixType> hessUninitialized;
VERIFY_RAISES_ASSERT(hessUninitialized.matrixH());
VERIFY_RAISES_ASSERT(hessUninitialized.matrixQ());
VERIFY_RAISES_ASSERT(hessUninitialized.householderCoefficients());
VERIFY_RAISES_ASSERT(hessUninitialized.packedMatrix());
// TODO: Add tests for packedMatrix() and householderCoefficients()
}
EIGEN_DECLARE_TEST(hessenberg) {
CALL_SUBTEST_1((hessenberg<std::complex<double>, 1>()));
CALL_SUBTEST_2((hessenberg<std::complex<double>, 2>()));
CALL_SUBTEST_3((hessenberg<std::complex<float>, 4>()));
CALL_SUBTEST_4((hessenberg<float, Dynamic>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_5((hessenberg<std::complex<double>, Dynamic>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
// Test problem size constructors
CALL_SUBTEST_6(HessenbergDecomposition<MatrixXf>(10));
}
+235
View File
@@ -0,0 +1,235 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/QR>
template <typename MatrixType>
void householder(const MatrixType& m) {
static bool even = true;
even = !even;
/* this test covers the following files:
Householder.h
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
typedef Matrix<Scalar, internal::decrement_size<MatrixType::RowsAtCompileTime>::ret, 1> EssentialVectorType;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
typedef Matrix<Scalar, Dynamic, MatrixType::ColsAtCompileTime> HBlockMatrixType;
typedef Matrix<Scalar, Dynamic, 1> HCoeffsVectorType;
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime> TMatrixType;
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;
RealScalar alpha;
EssentialVectorType essential;
VectorType v1 = VectorType::Random(rows), v2;
v2 = v1;
v1.makeHouseholder(essential, beta, alpha);
v1.applyHouseholderOnTheLeft(essential, beta, tmp);
VERIFY_IS_APPROX(v1.norm(), v2.norm());
if (rows >= 2) VERIFY_IS_MUCH_SMALLER_THAN(v1.tail(rows - 1).norm(), v1.norm());
v1 = VectorType::Random(rows);
v2 = v1;
v1.applyHouseholderOnTheLeft(essential, beta, tmp);
VERIFY_IS_APPROX(v1.norm(), v2.norm());
// reconstruct householder matrix:
SquareMatrixType id, H1, H2;
id.setIdentity(rows, rows);
H1 = H2 = id;
VectorType vv(rows);
vv << Scalar(1), essential;
H1.applyHouseholderOnTheLeft(essential, beta, tmp);
H2.applyHouseholderOnTheRight(essential, beta, tmp);
VERIFY_IS_APPROX(H1, H2);
VERIFY_IS_APPROX(H1, id - beta * vv * vv.adjoint());
MatrixType m1(rows, cols), m2(rows, cols);
v1 = VectorType::Random(rows);
if (even) v1.tail(rows - 1).setZero();
m1.colwise() = v1;
m2 = m1;
m1.col(0).makeHouseholder(essential, beta, alpha);
m1.applyHouseholderOnTheLeft(essential, beta, tmp);
VERIFY_IS_APPROX(m1.norm(), m2.norm());
if (rows >= 2) VERIFY_IS_MUCH_SMALLER_THAN(m1.block(1, 0, rows - 1, cols).norm(), m1.norm());
VERIFY_IS_MUCH_SMALLER_THAN(numext::imag(m1(0, 0)), numext::real(m1(0, 0)));
VERIFY_IS_APPROX(numext::real(m1(0, 0)), alpha);
v1 = VectorType::Random(rows);
if (even) v1.tail(rows - 1).setZero();
SquareMatrixType m3(rows, rows), m4(rows, rows);
m3.rowwise() = v1.transpose();
m4 = m3;
m3.row(0).makeHouseholder(essential, beta, alpha);
m3.applyHouseholderOnTheRight(essential.conjugate(), beta, tmp);
VERIFY_IS_APPROX(m3.norm(), m4.norm());
if (rows >= 2) VERIFY_IS_MUCH_SMALLER_THAN(m3.block(0, 1, rows, rows - 1).norm(), m3.norm());
VERIFY_IS_MUCH_SMALLER_THAN(numext::imag(m3(0, 0)), numext::real(m3(0, 0)));
VERIFY_IS_APPROX(numext::real(m3(0, 0)), alpha);
// test householder sequence on the left with a shift
Index shift = internal::random<Index>(0, std::max<Index>(rows - 2, 0));
Index brows = rows - shift;
m1.setRandom(rows, cols);
HBlockMatrixType hbm = m1.block(shift, 0, brows, cols);
HouseholderQR<HBlockMatrixType> qr(hbm);
m2 = m1;
m2.block(shift, 0, brows, cols) = qr.matrixQR();
HCoeffsVectorType hc = qr.hCoeffs().conjugate();
HouseholderSequence<MatrixType, HCoeffsVectorType> hseq(m2, hc);
hseq.setLength(hc.size()).setShift(shift);
VERIFY(hseq.length() == hc.size());
VERIFY(hseq.shift() == shift);
MatrixType m5 = m2;
m5.block(shift, 0, brows, cols).template triangularView<StrictlyLower>().setZero();
VERIFY_IS_APPROX(hseq * m5, m1); // test applying hseq directly
m3 = hseq;
VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating hseq to a dense matrix, then applying
SquareMatrixType hseq_mat = hseq;
SquareMatrixType hseq_mat_conj = hseq.conjugate();
SquareMatrixType hseq_mat_adj = hseq.adjoint();
SquareMatrixType hseq_mat_trans = hseq.transpose();
SquareMatrixType m6 = SquareMatrixType::Random(rows, rows);
VERIFY_IS_APPROX(hseq_mat.adjoint(), hseq_mat_adj);
VERIFY_IS_APPROX(hseq_mat.conjugate(), hseq_mat_conj);
VERIFY_IS_APPROX(hseq_mat.transpose(), hseq_mat_trans);
VERIFY_IS_APPROX(hseq * m6, hseq_mat * m6);
VERIFY_IS_APPROX(hseq.adjoint() * m6, hseq_mat_adj * m6);
VERIFY_IS_APPROX(hseq.conjugate() * m6, hseq_mat_conj * m6);
VERIFY_IS_APPROX(hseq.transpose() * m6, hseq_mat_trans * m6);
VERIFY_IS_APPROX(m6 * hseq, m6 * hseq_mat);
VERIFY_IS_APPROX(m6 * hseq.adjoint(), m6 * hseq_mat_adj);
VERIFY_IS_APPROX(m6 * hseq.conjugate(), m6 * hseq_mat_conj);
VERIFY_IS_APPROX(m6 * hseq.transpose(), m6 * hseq_mat_trans);
// test householder sequence on the right with a shift
TMatrixType tm2 = m2.transpose();
HouseholderSequence<TMatrixType, HCoeffsVectorType, OnTheRight> rhseq(tm2, hc);
rhseq.setLength(hc.size()).setShift(shift);
VERIFY_IS_APPROX(rhseq * m5, m1); // test applying rhseq directly
m3 = rhseq;
VERIFY_IS_APPROX(m3 * m5, m1); // test evaluating rhseq to a dense matrix, then applying
}
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++) {
CALL_SUBTEST_1(householder(Matrix<double, 2, 2>()));
CALL_SUBTEST_2(householder(Matrix<float, 2, 3>()));
CALL_SUBTEST_3(householder(Matrix<double, 3, 5>()));
CALL_SUBTEST_4(householder(Matrix<float, 4, 4>()));
CALL_SUBTEST_5(householder(
MatrixXd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_6(householder(
MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_7(householder(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_8(householder(Matrix<double, 1, 1>()));
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))));
}
}
+89
View File
@@ -0,0 +1,89 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2025 Johannes Zipfel <johzip1010@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "sparse_solver.h"
#include <Eigen/IterativeLinearSolvers>
template <typename T, typename I_>
void test_incompleteLUT_T() {
IncompleteLUT<T, I_> ilut;
ilut.setDroptol(NumTraits<T>::epsilon() * 4);
}
template <typename T>
void test_extract_LU() {
typedef Eigen::SparseMatrix<T> SparseMatrix;
SparseMatrix A(5, 5);
std::vector<Eigen::Triplet<T>> triplets;
triplets.push_back({0, 0, 4});
triplets.push_back({0, 1, -1});
triplets.push_back({0, 4, -1});
triplets.push_back({1, 0, -1});
triplets.push_back({1, 1, 4});
triplets.push_back({1, 2, -1});
triplets.push_back({2, 1, -1});
triplets.push_back({2, 2, 4});
triplets.push_back({2, 3, -1});
triplets.push_back({3, 2, -1});
triplets.push_back({3, 3, 4});
triplets.push_back({3, 4, -1});
triplets.push_back({4, 0, -1});
triplets.push_back({4, 3, -1});
triplets.push_back({4, 4, 4});
A.setFromTriplets(triplets.begin(), triplets.end());
IncompleteLUT<T> ilut;
ilut.compute(A);
Eigen::SparseMatrix<T> matL = ilut.matrixL(); // Extract L
Eigen::SparseMatrix<T> matU = ilut.matrixU(); // Extract U
Eigen::SparseMatrix<T> expectedMatL(5, 5);
std::vector<Eigen::Triplet<T>> tripletsExL;
tripletsExL.emplace_back(0, 0, 1);
tripletsExL.emplace_back(1, 0, -0.25);
tripletsExL.emplace_back(1, 1, 1);
tripletsExL.emplace_back(2, 0, -0.25);
tripletsExL.emplace_back(2, 1, -0.0666667);
tripletsExL.emplace_back(2, 2, 1);
tripletsExL.emplace_back(3, 2, -0.25);
tripletsExL.emplace_back(3, 3, 1);
tripletsExL.emplace_back(4, 1, -0.266667);
tripletsExL.emplace_back(4, 3, -0.266667);
tripletsExL.emplace_back(4, 4, 1);
expectedMatL.setFromTriplets(tripletsExL.begin(), tripletsExL.end());
Eigen::SparseMatrix<T> expectedMatU(5, 5);
std::vector<Eigen::Triplet<T>> tripletsExU;
tripletsExU.emplace_back(0, 0, 4);
tripletsExU.emplace_back(0, 1, -1);
tripletsExU.emplace_back(1, 1, 3.75);
tripletsExU.emplace_back(1, 4, -1);
tripletsExU.emplace_back(2, 2, 4);
tripletsExU.emplace_back(2, 3, -1);
tripletsExU.emplace_back(3, 3, 3.75);
tripletsExU.emplace_back(3, 4, -1);
tripletsExU.emplace_back(4, 4, 3.46667);
expectedMatU.setFromTriplets(tripletsExU.begin(), tripletsExU.end());
VERIFY_IS_APPROX(expectedMatL, matL);
VERIFY_IS_APPROX(expectedMatU, matU);
}
EIGEN_DECLARE_TEST(incomplete_LUT) {
CALL_SUBTEST_1((test_incompleteLUT_T<double, int>()));
CALL_SUBTEST_1((test_incompleteLUT_T<float, int>()));
CALL_SUBTEST_2((test_incompleteLUT_T<std::complex<double>, int>()));
CALL_SUBTEST_3((test_incompleteLUT_T<double, long int>()));
CALL_SUBTEST_4(test_extract_LU<double>());
CALL_SUBTEST_4(test_extract_LU<float>());
}
+81
View File
@@ -0,0 +1,81 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2015-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// #define EIGEN_DONT_VECTORIZE
// #define EIGEN_MAX_ALIGN_BYTES 0
#include "sparse_solver.h"
#include <Eigen/IterativeLinearSolvers>
template <typename T, typename I_>
void test_incomplete_cholesky_T() {
typedef SparseMatrix<T, 0, I_> SparseMatrixType;
ConjugateGradient<SparseMatrixType, Lower, IncompleteCholesky<T, Lower, AMDOrdering<I_> > > cg_illt_lower_amd;
ConjugateGradient<SparseMatrixType, Lower, IncompleteCholesky<T, Lower, NaturalOrdering<I_> > > cg_illt_lower_nat;
ConjugateGradient<SparseMatrixType, Upper, IncompleteCholesky<T, Upper, AMDOrdering<I_> > > cg_illt_upper_amd;
ConjugateGradient<SparseMatrixType, Upper, IncompleteCholesky<T, Upper, NaturalOrdering<I_> > > cg_illt_upper_nat;
ConjugateGradient<SparseMatrixType, Upper | Lower, IncompleteCholesky<T, Lower, AMDOrdering<I_> > > cg_illt_uplo_amd;
CALL_SUBTEST(check_sparse_spd_solving(cg_illt_lower_amd));
CALL_SUBTEST(check_sparse_spd_solving(cg_illt_lower_nat));
CALL_SUBTEST(check_sparse_spd_solving(cg_illt_upper_amd));
CALL_SUBTEST(check_sparse_spd_solving(cg_illt_upper_nat));
CALL_SUBTEST(check_sparse_spd_solving(cg_illt_uplo_amd));
}
template <int>
void bug1150() {
// regression for bug 1150
for (int N = 1; N < 20; ++N) {
Eigen::MatrixXd b(N, N);
b.setOnes();
Eigen::SparseMatrix<double> m(N, N);
m.reserve(Eigen::VectorXi::Constant(N, 4));
for (int i = 0; i < N; ++i) {
m.insert(i, i) = 1;
m.coeffRef(i, i / 2) = 2;
m.coeffRef(i, i / 3) = 2;
m.coeffRef(i, i / 4) = 2;
}
Eigen::SparseMatrix<double> A;
A = m * m.transpose();
Eigen::ConjugateGradient<Eigen::SparseMatrix<double>, Eigen::Lower | Eigen::Upper,
Eigen::IncompleteCholesky<double> >
solver(A);
VERIFY(solver.preconditioner().info() == Eigen::Success);
VERIFY(solver.info() == Eigen::Success);
}
}
void test_non_spd() {
Eigen::SparseMatrix<double> A(2, 2);
A.insert(0, 0) = 0;
A.insert(1, 1) = 3;
Eigen::IncompleteCholesky<double> solver(A);
// Recover original matrix.
Eigen::MatrixXd M = solver.permutationP().transpose() *
(solver.scalingS().asDiagonal().inverse() *
(solver.matrixL() * solver.matrixL().transpose() -
solver.shift() * Eigen::MatrixXd::Identity(A.rows(), A.cols())) *
solver.scalingS().asDiagonal().inverse()) *
solver.permutationP();
VERIFY_IS_APPROX(A.toDense(), M);
}
EIGEN_DECLARE_TEST(incomplete_cholesky) {
CALL_SUBTEST_1((test_incomplete_cholesky_T<double, int>()));
CALL_SUBTEST_2((test_incomplete_cholesky_T<std::complex<double>, int>()));
CALL_SUBTEST_3((test_incomplete_cholesky_T<double, long int>()));
CALL_SUBTEST_4((bug1150<0>()));
CALL_SUBTEST_4(test_non_spd());
}
+869
View File
@@ -0,0 +1,869 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2017 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <vector>
#include "main.h"
using Eigen::placeholders::all;
using Eigen::placeholders::last;
using Eigen::placeholders::lastN;
using Eigen::placeholders::lastp1;
#include <array>
namespace test {
typedef std::pair<Index, Index> IndexPair;
}
int encode(Index i, Index j) { return int(i * 100 + j); }
test::IndexPair decode(Index ij) { return test::IndexPair(ij / 100, ij % 100); }
template <typename T>
bool match(const T& xpr, std::string ref, std::string str_xpr = "") {
EIGEN_UNUSED_VARIABLE(str_xpr);
std::stringstream str;
str << xpr;
if (!(str.str() == ref)) std::cout << str_xpr << "\n" << xpr << "\n\n";
return str.str() == ref;
}
#define MATCH(X, R) match(X, R, #X)
template <typename T1, typename T2>
std::enable_if_t<internal::is_same<T1, T2>::value, bool> is_same_eq(const T1& a, const T2& b) {
return (a == b).all();
}
template <typename T1, typename T2>
bool is_same_seq(const T1& a, const T2& b) {
bool ok = a.first() == b.first() && a.size() == b.size() && Index(a.incrObject()) == Index(b.incrObject());
;
if (!ok) {
std::cerr << "seqN(" << a.first() << ", " << a.size() << ", " << Index(a.incrObject()) << ") != ";
std::cerr << "seqN(" << b.first() << ", " << b.size() << ", " << Index(b.incrObject()) << ")\n";
}
return ok;
}
template <typename T1, typename T2>
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);
}
#define VERIFY_EQ_INT(A, B) VERIFY_IS_APPROX(int(A), int(B))
// C++03 does not allow local or unnamed enums as index
enum DummyEnum { XX = 0, YY = 1 };
void check_indexed_view() {
Index n = 10;
ArrayXd a = ArrayXd::LinSpaced(n, 0, n - 1);
Array<double, 1, Dynamic> b = a.transpose();
ArrayXXi A = ArrayXXi::NullaryExpr(n, n, std::ref(encode));
for (Index i = 0; i < n; ++i)
for (Index j = 0; j < n; ++j) VERIFY(decode(A(i, j)) == test::IndexPair(i, j));
Array4i eii(4);
eii << 3, 1, 6, 5;
std::vector<int> veci(4);
Map<ArrayXi>(veci.data(), 4) = eii;
VERIFY(MATCH(A(3, seq(9, 3, -1)), "309 308 307 306 305 304 303"));
VERIFY(MATCH(A(seqN(2, 5), seq(9, 3, -1)),
"209 208 207 206 205 204 203\n"
"309 308 307 306 305 304 303\n"
"409 408 407 406 405 404 403\n"
"509 508 507 506 505 504 503\n"
"609 608 607 606 605 604 603"));
VERIFY(MATCH(A(seqN(2, 5), 5),
"205\n"
"305\n"
"405\n"
"505\n"
"605"));
VERIFY(MATCH(A(seqN(last, 5, -1), seq(2, last)),
"902 903 904 905 906 907 908 909\n"
"802 803 804 805 806 807 808 809\n"
"702 703 704 705 706 707 708 709\n"
"602 603 604 605 606 607 608 609\n"
"502 503 504 505 506 507 508 509"));
VERIFY(MATCH(A(eii, veci),
"303 301 306 305\n"
"103 101 106 105\n"
"603 601 606 605\n"
"503 501 506 505"));
VERIFY(MATCH(A(eii, all),
"300 301 302 303 304 305 306 307 308 309\n"
"100 101 102 103 104 105 106 107 108 109\n"
"600 601 602 603 604 605 606 607 608 609\n"
"500 501 502 503 504 505 506 507 508 509"));
// take row number 3, and repeat it 5 times
VERIFY(MATCH(A(seqN(3, 5, 0), all),
"300 301 302 303 304 305 306 307 308 309\n"
"300 301 302 303 304 305 306 307 308 309\n"
"300 301 302 303 304 305 306 307 308 309\n"
"300 301 302 303 304 305 306 307 308 309\n"
"300 301 302 303 304 305 306 307 308 309"));
VERIFY(MATCH(a(seqN(3, 3), 0), "3\n4\n5"));
VERIFY(MATCH(a(seq(3, 5)), "3\n4\n5"));
VERIFY(MATCH(a(seqN(3, 3, 1)), "3\n4\n5"));
VERIFY(MATCH(a(seqN(5, 3, -1)), "5\n4\n3"));
VERIFY(MATCH(b(0, seqN(3, 3)), "3 4 5"));
VERIFY(MATCH(b(seq(3, 5)), "3 4 5"));
VERIFY(MATCH(b(seqN(3, 3, 1)), "3 4 5"));
VERIFY(MATCH(b(seqN(5, 3, -1)), "5 4 3"));
VERIFY(MATCH(b(all), "0 1 2 3 4 5 6 7 8 9"));
VERIFY(MATCH(b(eii), "3 1 6 5"));
Array44i B;
B.setRandom();
VERIFY((A(seqN(2, 5), 5)).ColsAtCompileTime == 1);
VERIFY((A(seqN(2, 5), 5)).RowsAtCompileTime == Dynamic);
VERIFY_EQ_INT((A(seqN(2, 5), 5)).InnerStrideAtCompileTime, A.InnerStrideAtCompileTime);
VERIFY_EQ_INT((A(seqN(2, 5), 5)).OuterStrideAtCompileTime, A.col(5).OuterStrideAtCompileTime);
VERIFY_EQ_INT((A(5, seqN(2, 5))).InnerStrideAtCompileTime, A.row(5).InnerStrideAtCompileTime);
VERIFY_EQ_INT((A(5, seqN(2, 5))).OuterStrideAtCompileTime, A.row(5).OuterStrideAtCompileTime);
VERIFY_EQ_INT((B(1, seqN(1, 2))).InnerStrideAtCompileTime, B.row(1).InnerStrideAtCompileTime);
VERIFY_EQ_INT((B(1, seqN(1, 2))).OuterStrideAtCompileTime, B.row(1).OuterStrideAtCompileTime);
VERIFY_EQ_INT((A(seqN(2, 5), seq(1, 3))).InnerStrideAtCompileTime, A.InnerStrideAtCompileTime);
VERIFY_EQ_INT((A(seqN(2, 5), seq(1, 3))).OuterStrideAtCompileTime, A.OuterStrideAtCompileTime);
VERIFY_EQ_INT((B(seqN(1, 2), seq(1, 3))).InnerStrideAtCompileTime, B.InnerStrideAtCompileTime);
VERIFY_EQ_INT((B(seqN(1, 2), seq(1, 3))).OuterStrideAtCompileTime, B.OuterStrideAtCompileTime);
VERIFY_EQ_INT((A(seqN(2, 5, 2), seq(1, 3, 2))).InnerStrideAtCompileTime, Dynamic);
VERIFY_EQ_INT((A(seqN(2, 5, 2), seq(1, 3, 2))).OuterStrideAtCompileTime, Dynamic);
VERIFY_EQ_INT((A(seqN(2, 5, fix<2>), seq(1, 3, fix<3>))).InnerStrideAtCompileTime, 2);
VERIFY_EQ_INT((A(seqN(2, 5, fix<2>), seq(1, 3, fix<3>))).OuterStrideAtCompileTime, Dynamic);
VERIFY_EQ_INT((B(seqN(1, 2, fix<2>), seq(1, 3, fix<3>))).InnerStrideAtCompileTime, 2);
VERIFY_EQ_INT((B(seqN(1, 2, fix<2>), seq(1, 3, fix<3>))).OuterStrideAtCompileTime, 3 * 4);
VERIFY_EQ_INT((A(seqN(2, fix<5>), seqN(1, fix<3>))).RowsAtCompileTime, 5);
VERIFY_EQ_INT((A(seqN(2, fix<5>), seqN(1, fix<3>))).ColsAtCompileTime, 3);
VERIFY_EQ_INT((A(seqN(2, fix<5>(5)), seqN(1, fix<3>(3)))).RowsAtCompileTime, 5);
VERIFY_EQ_INT((A(seqN(2, fix<5>(5)), seqN(1, fix<3>(3)))).ColsAtCompileTime, 3);
VERIFY_EQ_INT((A(seqN(2, fix<Dynamic>(5)), seqN(1, fix<Dynamic>(3)))).RowsAtCompileTime, Dynamic);
VERIFY_EQ_INT((A(seqN(2, fix<Dynamic>(5)), seqN(1, fix<Dynamic>(3)))).ColsAtCompileTime, Dynamic);
VERIFY_EQ_INT((A(seqN(2, fix<Dynamic>(5)), seqN(1, fix<Dynamic>(3)))).rows(), 5);
VERIFY_EQ_INT((A(seqN(2, fix<Dynamic>(5)), seqN(1, fix<Dynamic>(3)))).cols(), 3);
VERIFY(is_same_seq_type(seqN(2, 5, fix<-1>), seqN(2, 5, fix<-1>(-1))));
VERIFY(is_same_seq_type(seqN(2, 5), seqN(2, 5, fix<1>(1))));
VERIFY(is_same_seq_type(seqN(2, 5, 3), seqN(2, 5, fix<DynamicIndex>(3))));
VERIFY(is_same_seq_type(seq(2, 7, fix<3>), seqN(2, 2, fix<3>)));
VERIFY(is_same_seq_type(seqN(2, fix<Dynamic>(5), 3), seqN(2, 5, fix<DynamicIndex>(3))));
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)));
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>()),
seq(fix<1>, fix<5>, fix<2>())));
VERIFY(is_same_seq_type(seqN(2, std::integral_constant<int, 5>(), std::integral_constant<int, -2>()),
seqN(2, fix<5>, fix<-2>())));
VERIFY(is_same_seq_type(
seq(std::integral_constant<int, 1>(), std::integral_constant<int, 5>(), std::integral_constant<int, 2>()),
seq(fix<1>, fix<5>, fix<2>())));
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>)));
VERIFY((A(seqN(2, fix<5>), 5)).RowsAtCompileTime == 5);
VERIFY((A(4, all)).ColsAtCompileTime == Dynamic);
VERIFY((A(4, all)).RowsAtCompileTime == 1);
VERIFY((B(1, all)).ColsAtCompileTime == 4);
VERIFY((B(1, all)).RowsAtCompileTime == 1);
VERIFY((B(all, 1)).ColsAtCompileTime == 1);
VERIFY((B(all, 1)).RowsAtCompileTime == 4);
VERIFY(int((A(all, eii)).ColsAtCompileTime) == int(eii.SizeAtCompileTime));
VERIFY_EQ_INT((A(eii, eii)).Flags & DirectAccessBit, (unsigned int)(0));
VERIFY_EQ_INT((A(eii, eii)).InnerStrideAtCompileTime, 0);
VERIFY_EQ_INT((A(eii, eii)).OuterStrideAtCompileTime, 0);
VERIFY_IS_APPROX(A(seq(n - 1, 2, -2), seqN(n - 1 - 6, 3, -1)), A(seq(last, 2, fix<-2>), seqN(last - 6, 3, fix<-1>)));
VERIFY_IS_APPROX(A(seq(n - 1, 2, -2), seqN(n - 1 - 6, 4)), A(seq(last, 2, -2), seqN(last - 6, 4)));
VERIFY_IS_APPROX(A(seq(n - 1 - 6, n - 1 - 2), seqN(n - 1 - 6, 4)),
A(seq(last - 6, last - 2), seqN(6 + last - 6 - 6, 4)));
VERIFY_IS_APPROX(A(seq((n - 1) / 2, (n) / 2 + 3), seqN(2, 4)),
A(seq(last / 2, (last + 1) / 2 + 3), seqN(last + 2 - last, 4)));
VERIFY_IS_APPROX(A(seq(n - 2, 2, -2), seqN(n - 8, 4)), A(seq(lastp1 - 2, 2, -2), seqN(lastp1 - 8, 4)));
// Check all combinations of seq:
VERIFY_IS_APPROX(A(seq(1, n - 1 - 2, 2), seq(1, n - 1 - 2, 2)), A(seq(1, last - 2, 2), seq(1, last - 2, fix<2>)));
VERIFY_IS_APPROX(A(seq(n - 1 - 5, n - 1 - 2, 2), seq(n - 1 - 5, n - 1 - 2, 2)),
A(seq(last - 5, last - 2, 2), seq(last - 5, last - 2, fix<2>)));
VERIFY_IS_APPROX(A(seq(n - 1 - 5, 7, 2), seq(n - 1 - 5, 7, 2)), A(seq(last - 5, 7, 2), seq(last - 5, 7, fix<2>)));
VERIFY_IS_APPROX(A(seq(1, n - 1 - 2), seq(n - 1 - 5, 7)), A(seq(1, last - 2), seq(last - 5, 7)));
VERIFY_IS_APPROX(A(seq(n - 1 - 5, n - 1 - 2), seq(n - 1 - 5, n - 1 - 2)),
A(seq(last - 5, last - 2), seq(last - 5, last - 2)));
VERIFY_IS_APPROX(A.col(A.cols() - 1), A(all, last));
VERIFY_IS_APPROX(A(A.rows() - 2, A.cols() / 2), A(last - 1, lastp1 / 2));
VERIFY_IS_APPROX(a(a.size() - 2), a(last - 1));
VERIFY_IS_APPROX(a(a.size() / 2), a((last + 1) / 2));
// Check fall-back to Block
{
VERIFY(is_same_eq(A.col(0), A(all, 0)));
VERIFY(is_same_eq(A.row(0), A(0, all)));
VERIFY(is_same_eq(A.block(0, 0, 2, 2), A(seqN(0, 2), seq(0, 1))));
VERIFY(is_same_eq(A.middleRows(2, 4), A(seqN(2, 4), all)));
VERIFY(is_same_eq(A.middleCols(2, 4), A(all, seqN(2, 4))));
VERIFY(is_same_eq(A.col(A.cols() - 1), A(all, last)));
const ArrayXXi& cA(A);
VERIFY(is_same_eq(cA.col(0), cA(all, 0)));
VERIFY(is_same_eq(cA.row(0), cA(0, all)));
VERIFY(is_same_eq(cA.block(0, 0, 2, 2), cA(seqN(0, 2), seq(0, 1))));
VERIFY(is_same_eq(cA.middleRows(2, 4), cA(seqN(2, 4), all)));
VERIFY(is_same_eq(cA.middleCols(2, 4), cA(all, seqN(2, 4))));
VERIFY(is_same_eq(a.head(4), a(seq(0, 3))));
VERIFY(is_same_eq(a.tail(4), a(seqN(last - 3, 4))));
VERIFY(is_same_eq(a.tail(4), a(seq(lastp1 - 4, last))));
VERIFY(is_same_eq(a.segment<4>(3), a(seqN(3, fix<4>))));
}
ArrayXXi A1 = A, A2 = ArrayXXi::Random(4, 4);
ArrayXi range25(4);
range25 << 3, 2, 4, 5;
A1(seqN(3, 4), seq(2, 5)) = A2;
VERIFY_IS_APPROX(A1.block(3, 2, 4, 4), A2);
A1 = A;
A2.setOnes();
A1(seq(6, 3, -1), range25) = A2;
VERIFY_IS_APPROX(A1.block(3, 2, 4, 4), A2);
// check reverse
{
VERIFY(is_same_seq_type(seq(3, 7).reverse(), seqN(7, 5, fix<-1>)));
VERIFY(is_same_seq_type(seq(7, 3, fix<-2>).reverse(), seqN(3, 3, fix<2>)));
VERIFY_IS_APPROX(a(seqN(2, last / 2).reverse()), a(seqN(2 + (last / 2 - 1) * 1, last / 2, fix<-1>)));
VERIFY_IS_APPROX(a(seqN(last / 2, fix<4>).reverse()), a(seqN(last / 2, fix<4>)).reverse());
VERIFY_IS_APPROX(A(seq(last - 5, last - 1, 2).reverse(), seqN(last - 3, 3, fix<-2>).reverse()),
A(seq(last - 5, last - 1, 2), seqN(last - 3, 3, fix<-2>)).reverse());
}
// check lastN
VERIFY_IS_APPROX(a(lastN(3)), a.tail(3));
VERIFY(MATCH(a(lastN(3)), "7\n8\n9"));
VERIFY_IS_APPROX(a(lastN(fix<3>())), a.tail<3>());
VERIFY(MATCH(a(lastN(3, 2)), "5\n7\n9"));
VERIFY(MATCH(a(lastN(3, fix<2>())), "5\n7\n9"));
VERIFY(a(lastN(fix<3>())).SizeAtCompileTime == 3);
VERIFY((A(all, std::array<int, 4>{{1, 3, 2, 4}})).ColsAtCompileTime == 4);
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)));
VERIFY_IS_EQUAL(A(std::array<int, 3>{1, 3, 5}, std::array<int, 4>{3, 1, 6, 5}).RowsAtCompileTime, 3);
VERIFY_IS_EQUAL(A(std::array<int, 3>{1, 3, 5}, std::array<int, 4>{3, 1, 6, 5}).ColsAtCompileTime, 4);
VERIFY_IS_EQUAL(a(std::array<int, 3>{1, 3, 5}).SizeAtCompileTime, 3);
VERIFY_IS_EQUAL(b(std::array<int, 3>{1, 3, 5}).SizeAtCompileTime, 3);
// check different index types (C-style array, STL container, Eigen type)
{
Index size = 10;
ArrayXd r = ArrayXd::Random(size);
ArrayXi idx = ArrayXi::EqualSpaced(size, 0, 1);
std::shuffle(idx.begin(), idx.end(), std::random_device());
int c_array[3] = {idx[0], idx[1], idx[2]};
std::vector<int> std_vector{idx[0], idx[1], idx[2]};
Matrix<int, 3, 1> eigen_matrix{idx[0], idx[1], idx[2]};
// non-const access
VERIFY_IS_CWISE_EQUAL(r({idx[0], idx[1], idx[2]}), r(c_array));
VERIFY_IS_CWISE_EQUAL(r({idx[0], idx[1], idx[2]}), r(std_vector));
VERIFY_IS_CWISE_EQUAL(r({idx[0], idx[1], idx[2]}), r(eigen_matrix));
VERIFY_IS_CWISE_EQUAL(r(std_vector), r(c_array));
VERIFY_IS_CWISE_EQUAL(r(std_vector), r(eigen_matrix));
VERIFY_IS_CWISE_EQUAL(r(eigen_matrix), r(c_array));
const ArrayXd& r_ref = r;
// const access
VERIFY_IS_CWISE_EQUAL(r_ref({idx[0], idx[1], idx[2]}), r_ref(c_array));
VERIFY_IS_CWISE_EQUAL(r_ref({idx[0], idx[1], idx[2]}), r_ref(std_vector));
VERIFY_IS_CWISE_EQUAL(r_ref({idx[0], idx[1], idx[2]}), r_ref(eigen_matrix));
VERIFY_IS_CWISE_EQUAL(r_ref(std_vector), r_ref(c_array));
VERIFY_IS_CWISE_EQUAL(r_ref(std_vector), r_ref(eigen_matrix));
VERIFY_IS_CWISE_EQUAL(r_ref(eigen_matrix), r_ref(c_array));
}
{
Index rows = 8;
Index cols = 11;
ArrayXXd R = ArrayXXd::Random(rows, cols);
ArrayXi r_idx = ArrayXi::EqualSpaced(rows, 0, 1);
ArrayXi c_idx = ArrayXi::EqualSpaced(cols, 0, 1);
std::shuffle(r_idx.begin(), r_idx.end(), std::random_device());
std::shuffle(c_idx.begin(), c_idx.end(), std::random_device());
int c_array_rows[3] = {r_idx[0], r_idx[1], r_idx[2]};
int c_array_cols[4] = {c_idx[0], c_idx[1], c_idx[2], c_idx[3]};
std::vector<int> std_vector_rows{r_idx[0], r_idx[1], r_idx[2]};
std::vector<int> std_vector_cols{c_idx[0], c_idx[1], c_idx[2], c_idx[3]};
Matrix<int, 3, 1> eigen_matrix_rows{r_idx[0], r_idx[1], r_idx[2]};
Matrix<int, 4, 1> eigen_matrix_cols{c_idx[0], c_idx[1], c_idx[2], c_idx[3]};
// non-const access
VERIFY_IS_CWISE_EQUAL(R({r_idx[0], r_idx[1], r_idx[2]}, {c_idx[0], c_idx[1], c_idx[2], c_idx[3]}),
R(c_array_rows, c_array_cols));
VERIFY_IS_CWISE_EQUAL(R({r_idx[0], r_idx[1], r_idx[2]}, {c_idx[0], c_idx[1], c_idx[2], c_idx[3]}),
R(std_vector_rows, std_vector_cols));
VERIFY_IS_CWISE_EQUAL(R({r_idx[0], r_idx[1], r_idx[2]}, {c_idx[0], c_idx[1], c_idx[2], c_idx[3]}),
R(eigen_matrix_rows, eigen_matrix_cols));
VERIFY_IS_CWISE_EQUAL(R(std_vector_rows, std_vector_cols), R(c_array_rows, c_array_cols));
VERIFY_IS_CWISE_EQUAL(R(std_vector_rows, std_vector_cols), R(eigen_matrix_rows, eigen_matrix_cols));
VERIFY_IS_CWISE_EQUAL(R(eigen_matrix_rows, eigen_matrix_cols), R(c_array_rows, c_array_cols));
const ArrayXXd& R_ref = R;
// const access
VERIFY_IS_CWISE_EQUAL(R_ref({r_idx[0], r_idx[1], r_idx[2]}, {c_idx[0], c_idx[1], c_idx[2], c_idx[3]}),
R_ref(c_array_rows, c_array_cols));
VERIFY_IS_CWISE_EQUAL(R_ref({r_idx[0], r_idx[1], r_idx[2]}, {c_idx[0], c_idx[1], c_idx[2], c_idx[3]}),
R_ref(std_vector_rows, std_vector_cols));
VERIFY_IS_CWISE_EQUAL(R_ref({r_idx[0], r_idx[1], r_idx[2]}, {c_idx[0], c_idx[1], c_idx[2], c_idx[3]}),
R_ref(eigen_matrix_rows, eigen_matrix_cols));
VERIFY_IS_CWISE_EQUAL(R_ref(std_vector_rows, std_vector_cols), R_ref(c_array_rows, c_array_cols));
VERIFY_IS_CWISE_EQUAL(R_ref(std_vector_rows, std_vector_cols), R_ref(eigen_matrix_rows, eigen_matrix_cols));
VERIFY_IS_CWISE_EQUAL(R_ref(eigen_matrix_rows, eigen_matrix_cols), R_ref(c_array_rows, c_array_cols));
}
// check mat(i,j) with weird types for i and j
{
VERIFY_IS_APPROX(A(B.RowsAtCompileTime - 1, 1), A(3, 1));
VERIFY_IS_APPROX(A(B.RowsAtCompileTime, 1), A(4, 1));
VERIFY_IS_APPROX(A(B.RowsAtCompileTime - 1, B.ColsAtCompileTime - 1), A(3, 3));
VERIFY_IS_APPROX(A(B.RowsAtCompileTime, B.ColsAtCompileTime), A(4, 4));
const Index I_ = 3, J_ = 4;
VERIFY_IS_APPROX(A(I_, J_), A(3, 4));
}
// check extended block API
{
VERIFY(is_same_eq(A.block<3, 4>(1, 1), A.block(1, 1, fix<3>, fix<4>)));
VERIFY(is_same_eq(A.block<3, 4>(1, 1, 3, 4), A.block(1, 1, fix<3>(), fix<4>(4))));
VERIFY(is_same_eq(A.block<3, Dynamic>(1, 1, 3, 4), A.block(1, 1, fix<3>, 4)));
VERIFY(is_same_eq(A.block<Dynamic, 4>(1, 1, 3, 4), A.block(1, 1, fix<Dynamic>(3), fix<4>)));
VERIFY(is_same_eq(A.block(1, 1, 3, 4), A.block(1, 1, fix<Dynamic>(3), fix<Dynamic>(4))));
VERIFY(is_same_eq(A.topLeftCorner<3, 4>(), A.topLeftCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(A.bottomLeftCorner<3, 4>(), A.bottomLeftCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(A.bottomRightCorner<3, 4>(), A.bottomRightCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(A.topRightCorner<3, 4>(), A.topRightCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(A.leftCols<3>(), A.leftCols(fix<3>)));
VERIFY(is_same_eq(A.rightCols<3>(), A.rightCols(fix<3>)));
VERIFY(is_same_eq(A.middleCols<3>(1), A.middleCols(1, fix<3>)));
VERIFY(is_same_eq(A.topRows<3>(), A.topRows(fix<3>)));
VERIFY(is_same_eq(A.bottomRows<3>(), A.bottomRows(fix<3>)));
VERIFY(is_same_eq(A.middleRows<3>(1), A.middleRows(1, fix<3>)));
VERIFY(is_same_eq(a.segment<3>(1), a.segment(1, fix<3>)));
VERIFY(is_same_eq(a.head<3>(), a.head(fix<3>)));
VERIFY(is_same_eq(a.tail<3>(), a.tail(fix<3>)));
const ArrayXXi& cA(A);
VERIFY(is_same_eq(cA.block<Dynamic, 4>(1, 1, 3, 4), cA.block(1, 1, fix<Dynamic>(3), fix<4>)));
VERIFY(is_same_eq(cA.topLeftCorner<3, 4>(), cA.topLeftCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(cA.bottomLeftCorner<3, 4>(), cA.bottomLeftCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(cA.bottomRightCorner<3, 4>(), cA.bottomRightCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(cA.topRightCorner<3, 4>(), cA.topRightCorner(fix<3>, fix<4>)));
VERIFY(is_same_eq(cA.leftCols<3>(), cA.leftCols(fix<3>)));
VERIFY(is_same_eq(cA.rightCols<3>(), cA.rightCols(fix<3>)));
VERIFY(is_same_eq(cA.middleCols<3>(1), cA.middleCols(1, fix<3>)));
VERIFY(is_same_eq(cA.topRows<3>(), cA.topRows(fix<3>)));
VERIFY(is_same_eq(cA.bottomRows<3>(), cA.bottomRows(fix<3>)));
VERIFY(is_same_eq(cA.middleRows<3>(1), cA.middleRows(1, fix<3>)));
}
// Check compilation of enums as index type:
a(XX) = 1;
A(XX, YY) = 1;
// Anonymous enums only work with C++11
enum { X = 0, Y = 1 };
a(X) = 1;
A(X, Y) = 1;
A(XX, Y) = 1;
A(X, YY) = 1;
// check symbolic indices
a(last) = 1.0;
A(last, last) = 1;
// check weird non-const, non-lvalue scenarios
{
// in these scenarios, the objects are not declared 'const', and the compiler will atttempt to use the non-const
// overloads without intervention
// non-const map to a const object
Map<const ArrayXd> a_map(a.data(), a.size());
Map<const ArrayXXi> A_map(A.data(), A.rows(), A.cols());
VERIFY_IS_EQUAL(a_map(last), a.coeff(a.size() - 1));
VERIFY_IS_EQUAL(A_map(last, last), A.coeff(A.rows() - 1, A.cols() - 1));
// non-const expressions that have no modifiable data
using Op = internal::scalar_constant_op<double>;
using VectorXpr = CwiseNullaryOp<Op, VectorXd>;
using MatrixXpr = CwiseNullaryOp<Op, MatrixXd>;
double constant_val = internal::random<double>();
Op op(constant_val);
VectorXpr vectorXpr(10, 1, op);
MatrixXpr matrixXpr(8, 11, op);
VERIFY_IS_EQUAL(vectorXpr.coeff(vectorXpr.size() - 1), vectorXpr(last));
VERIFY_IS_EQUAL(matrixXpr.coeff(matrixXpr.rows() - 1, matrixXpr.cols() - 1), matrixXpr(last, last));
}
// Check compilation of varying integer types as index types:
Index i = n / 2;
short i_short = static_cast<short>(i);
std::size_t i_sizet(i);
VERIFY_IS_EQUAL(a(i), a.coeff(i_short));
VERIFY_IS_EQUAL(a(i), a.coeff(i_sizet));
VERIFY_IS_EQUAL(A(i, i), A.coeff(i_short, i_short));
VERIFY_IS_EQUAL(A(i, i), A.coeff(i_short, i));
VERIFY_IS_EQUAL(A(i, i), A.coeff(i, i_short));
VERIFY_IS_EQUAL(A(i, i), A.coeff(i, i_sizet));
VERIFY_IS_EQUAL(A(i, i), A.coeff(i_sizet, i));
VERIFY_IS_EQUAL(A(i, i), A.coeff(i_sizet, i_short));
VERIFY_IS_EQUAL(A(i, i), A.coeff(5, i_sizet));
// Regression test for Max{Rows,Cols}AtCompileTime
{
Matrix3i A3 = Matrix3i::Random();
ArrayXi ind(5);
ind << 1, 1, 1, 1, 1;
VERIFY_IS_EQUAL(A3(ind, ind).eval(), MatrixXi::Constant(5, 5, A3(1, 1)));
}
// Regression for bug 1736
{
VERIFY_IS_APPROX(A(all, eii).col(0).eval(), A.col(eii(0)));
A(all, eii).col(0) = A.col(eii(0));
}
// bug 1815: IndexedView should allow linear access
{
VERIFY(MATCH(b(eii)(0), "3"));
VERIFY(MATCH(a(eii)(0), "3"));
VERIFY(MATCH(A(1, eii)(0), "103"));
VERIFY(MATCH(A(eii, 1)(0), "301"));
VERIFY(MATCH(A(1, all)(1), "101"));
VERIFY(MATCH(A(all, 1)(1), "101"));
}
// 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));
}
// Direct access.
{
int rows = 3;
int row_start = internal::random<int>(0, rows - 1);
int row_inc = internal::random<int>(1, rows - row_start);
int row_size = internal::random<int>(1, (rows - row_start) / row_inc);
auto row_seq = seqN(row_start, row_size, row_inc);
int cols = 3;
int col_start = internal::random<int>(0, cols - 1);
int col_inc = internal::random<int>(1, cols - col_start);
int col_size = internal::random<int>(1, (cols - col_start) / col_inc);
auto col_seq = seqN(col_start, col_size, col_inc);
MatrixXd m1 = MatrixXd::Random(rows, cols);
MatrixXd m2 = MatrixXd::Random(cols, rows);
VERIFY_IS_APPROX(m1(row_seq, indexing::all) * m2, m1(row_seq, indexing::all).eval() * m2);
VERIFY_IS_APPROX(m1 * m2(indexing::all, col_seq), m1 * m2(indexing::all, col_seq).eval());
VERIFY_IS_APPROX(m1(row_seq, col_seq) * m2(col_seq, row_seq),
m1(row_seq, col_seq).eval() * m2(col_seq, row_seq).eval());
VectorXd v1 = VectorXd::Random(cols);
VERIFY_IS_APPROX(m1(row_seq, col_seq) * v1(col_seq), m1(row_seq, col_seq).eval() * v1(col_seq).eval());
VERIFY_IS_APPROX(v1(col_seq).transpose() * m2(col_seq, row_seq),
v1(col_seq).transpose().eval() * m2(col_seq, row_seq).eval());
}
}
void check_tutorial_examples() {
constexpr int kRows = 11;
constexpr int kCols = 21;
Matrix<double, kRows, kCols> A = Matrix<double, kRows, kCols>::Random();
Vector<double, kRows> v = Vector<double, kRows>::Random();
{
auto slice = A(seqN(fix<0>, fix<5>, fix<2>), seqN(fix<2>, fix<7>, fix<1>));
EIGEN_UNUSED_VARIABLE(slice);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), 7);
}
{
auto slice = A(seqN(fix<0>, fix<5>, fix<2>), indexing::all);
EIGEN_UNUSED_VARIABLE(slice);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), kCols);
}
// Examples from slicing tutorial.
// Bottom-left corner.
{
Index i = 3;
Index n = 5;
auto slice = A(seq(i, indexing::last), seqN(0, n));
auto block = A.bottomLeftCorner(A.rows() - i, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), Dynamic);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), Dynamic);
VERIFY_IS_EQUAL(slice, block);
}
{
auto i = fix<3>;
auto n = fix<5>;
auto slice = A(seq(i, indexing::last), seqN(fix<0>, n));
auto block = A.bottomLeftCorner(fix<kRows> - i, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), A.RowsAtCompileTime - i);
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), n);
VERIFY_IS_EQUAL(slice, block);
}
// Block starting at i,j of size m,n.
{
Index i = 4;
Index j = 2;
Index m = 3;
Index n = 5;
auto slice = A(seqN(i, m), seqN(j, n));
auto block = A.block(i, j, m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto i = fix<4>;
auto j = fix<2>;
auto m = fix<3>;
auto n = fix<5>;
auto slice = A(seqN(i, m), seqN(j, n));
auto block = A.block(i, j, m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Block starting at i0,j0 and ending at i1,j1.
{
Index i0 = 4;
Index i1 = 7;
Index j0 = 3;
Index j1 = 5;
auto slice = A(seq(i0, i1), seq(j0, j1));
auto block = A.block(i0, j0, i1 - i0 + 1, j1 - j0 + 1);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto i0 = fix<4>;
auto i1 = fix<7>;
auto j0 = fix<3>;
auto j1 = fix<5>;
auto slice = A(seq(i0, i1), seq(j0, j1));
auto block = A.block(i0, j0, i1 - i0 + fix<1>, j1 - j0 + fix<1>);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Even columns of A.
{
auto slice = A(all, seq(0, last, 2));
auto block =
Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<2 * kRows>>(A.data(), kRows, (kCols + 1) / 2);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto slice = A(all, seq(fix<0>, last, fix<2>));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, (kCols + 1) / 2>, 0, OuterStride<2 * kRows>>(A.data());
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// First n odd rows of A.
{
Index n = 3;
auto slice = A(seqN(1, n, 2), all);
auto block = Eigen::Map<Eigen::Matrix<double, Dynamic, kCols>, 0, Stride<kRows, 2>>(A.data() + 1, n, kCols);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto n = fix<3>;
auto slice = A(seqN(fix<1>, n, fix<2>), all);
auto block = Eigen::Map<Eigen::Matrix<double, 3, kCols>, 0, Stride<kRows, 2>>(A.data() + 1);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// The second-last column.
{
auto slice = A(all, last - 1);
auto block = A.col(A.cols() - 2);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto slice = A(all, last - fix<1>);
auto block = A.col(fix<kCols> - fix<2>);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// The middle row.
{
auto slice = A(last / 2, all);
auto block = A.row((A.rows() - 1) / 2);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto slice = A(last / fix<2>, all);
auto block = A.row(fix<(kRows - 1) / 2>);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last elements of v starting at i.
{
Index i = 7;
auto slice = v(seq(i, last));
auto block = v.tail(v.size() - i);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto i = fix<7>;
auto slice = v(seq(i, last));
auto block = v.tail(fix<kRows> - i);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last n elements of v.
{
Index n = 6;
auto slice = v(seq(last + 1 - n, last));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto n = fix<6>;
auto slice = v(seq(last + fix<1> - n, last));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last n elements of v.
{
Index n = 6;
auto slice = v(lastN(n));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto n = fix<6>;
auto slice = v(lastN(n));
auto block = v.tail(n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Bottom-right corner of A of size m times n.
{
Index m = 3;
Index n = 6;
auto slice = A(lastN(m), lastN(n));
auto block = A.bottomRightCorner(m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
auto m = fix<3>;
auto n = fix<6>;
auto slice = A(lastN(m), lastN(n));
auto block = A.bottomRightCorner(m, n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Last n columns with a stride of 3.
{
Index n = 4;
constexpr Index stride = 3;
auto slice = A(all, lastN(n, stride));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<stride * kRows>>(
A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
{
constexpr auto n = fix<4>;
constexpr auto stride = fix<3>;
auto slice = A(all, lastN(n, stride));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, n>, 0, OuterStride<stride * kRows>>(
A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n);
VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
VERIFY_IS_EQUAL(slice, block);
}
// Compile time size and increment.
{
auto slice1 = v(seq(last - fix<7>, last - fix<2>));
auto slice2 = v(seqN(last - 7, fix<6>));
VERIFY_IS_EQUAL(slice1, slice2);
VERIFY_IS_EQUAL(int(slice1.SizeAtCompileTime), 6);
VERIFY_IS_EQUAL(int(slice2.SizeAtCompileTime), 6);
auto slice3 = A(all, seq(fix<0>, last, fix<2>));
TEST_SET_BUT_UNUSED_VARIABLE(slice3)
VERIFY_IS_EQUAL(int(slice3.RowsAtCompileTime), kRows);
VERIFY_IS_EQUAL(int(slice3.ColsAtCompileTime), (kCols + 1) / 2);
}
// Reverse order.
{
auto slice = A(all, seq(20, 10, fix<-2>));
auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<-2 * kRows>>(
A.data() + 20 * kRows, A.rows(), (20 - 10 + 2) / 2);
VERIFY_IS_EQUAL(slice, block);
}
{
Index n = 10;
auto slice1 = A(seqN(last, n, fix<-1>), all);
auto slice2 = A(lastN(n).reverse(), all);
VERIFY_IS_EQUAL(slice1, slice2);
}
// Array of indices.
{
std::vector<int> ind{4, 2, 5, 5, 3};
auto slice1 = A(all, ind);
for (size_t i = 0; i < ind.size(); ++i) {
VERIFY_IS_EQUAL(slice1.col(i), A.col(ind[i]));
}
auto slice2 = A(all, {4, 2, 5, 5, 3});
VERIFY_IS_EQUAL(slice1, slice2);
Eigen::ArrayXi indarray(5);
indarray << 4, 2, 5, 5, 3;
auto slice3 = A(all, indarray);
VERIFY_IS_EQUAL(slice1, slice3);
}
// Custom index list.
{
struct pad {
Index size() const { return out_size; }
Index operator[](Index i) const { return std::max<Index>(0, i - (out_size - in_size)); }
Index in_size, out_size;
};
auto slice = A(pad{3, 5}, pad{3, 5});
Eigen::MatrixXd B = slice;
VERIFY_IS_EQUAL(B.block(2, 2, 3, 3), A.block(0, 0, 3, 3));
}
}
void check_aliasing() {
Eigen::Vector<float, 5> z = {0.0f, 1.1f, 2.2f, 3.3f, 4.4f};
std::vector<int> left_indices = {0, 1, 3, 4};
std::vector<int> right_indices = {1, 3, 4, 0};
z(left_indices) = z(right_indices);
Eigen::Vector<float, 5> expected = {1.1f, 3.3f, 2.2f, 4.4f, 0.0f};
VERIFY_IS_EQUAL(z, expected);
}
EIGEN_DECLARE_TEST(indexed_view) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(check_indexed_view());
}
CALL_SUBTEST_1(check_tutorial_examples());
CALL_SUBTEST_1(check_aliasing());
// static checks of some internals:
STATIC_CHECK((internal::is_valid_index_type<int>::value));
STATIC_CHECK((internal::is_valid_index_type<unsigned int>::value));
STATIC_CHECK((internal::is_valid_index_type<short>::value));
STATIC_CHECK((internal::is_valid_index_type<std::ptrdiff_t>::value));
STATIC_CHECK((internal::is_valid_index_type<std::size_t>::value));
STATIC_CHECK((!internal::valid_indexed_view_overload<int, int>::value));
STATIC_CHECK((!internal::valid_indexed_view_overload<int, std::ptrdiff_t>::value));
STATIC_CHECK((!internal::valid_indexed_view_overload<std::ptrdiff_t, int>::value));
STATIC_CHECK((!internal::valid_indexed_view_overload<std::size_t, int>::value));
}
+365
View File
@@ -0,0 +1,365 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2019 David Tellenbach <david.tellenbach@tellnotes.org>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#if defined(__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"
template <typename Scalar, bool is_integer = NumTraits<Scalar>::IsInteger>
struct TestMethodDispatching {
static void run() {}
};
template <typename Scalar>
struct TestMethodDispatching<Scalar, 1> {
static void run() {
{
Matrix<Scalar, Dynamic, Dynamic> m{3, 4};
Array<Scalar, Dynamic, Dynamic> a{3, 4};
VERIFY(m.rows() == 3);
VERIFY(m.cols() == 4);
VERIFY(a.rows() == 3);
VERIFY(a.cols() == 4);
}
{
Matrix<Scalar, 1, 2> m{3, 4};
Array<Scalar, 1, 2> a{3, 4};
VERIFY(m(0) == 3);
VERIFY(m(1) == 4);
VERIFY(a(0) == 3);
VERIFY(a(1) == 4);
}
{
Matrix<Scalar, 2, 1> m{3, 4};
Array<Scalar, 2, 1> a{3, 4};
VERIFY(m(0) == 3);
VERIFY(m(1) == 4);
VERIFY(a(0) == 3);
VERIFY(a(1) == 4);
}
}
};
template <typename Vec4, typename Vec5>
void fixedsizeVariadicVectorConstruction2() {
{
Vec4 ref = Vec4::Random();
Vec4 v{ref[0], ref[1], ref[2], ref[3]};
VERIFY_IS_APPROX(v, ref);
VERIFY_IS_APPROX(v, (Vec4(ref[0], ref[1], ref[2], ref[3])));
VERIFY_IS_APPROX(v, (Vec4({ref[0], ref[1], ref[2], ref[3]})));
Vec4 v2 = {ref[0], ref[1], ref[2], ref[3]};
VERIFY_IS_APPROX(v2, ref);
}
{
Vec5 ref = Vec5::Random();
Vec5 v{ref[0], ref[1], ref[2], ref[3], ref[4]};
VERIFY_IS_APPROX(v, ref);
VERIFY_IS_APPROX(v, (Vec5(ref[0], ref[1], ref[2], ref[3], ref[4])));
VERIFY_IS_APPROX(v, (Vec5({ref[0], ref[1], ref[2], ref[3], ref[4]})));
Vec5 v2 = {ref[0], ref[1], ref[2], ref[3], ref[4]};
VERIFY_IS_APPROX(v2, ref);
}
}
#define CHECK_MIXSCALAR_V5_APPROX(V, A0, A1, A2, A3, A4) \
{ \
VERIFY_IS_APPROX(V[0], Scalar(A0)); \
VERIFY_IS_APPROX(V[1], Scalar(A1)); \
VERIFY_IS_APPROX(V[2], Scalar(A2)); \
VERIFY_IS_APPROX(V[3], Scalar(A3)); \
VERIFY_IS_APPROX(V[4], Scalar(A4)); \
}
#define CHECK_MIXSCALAR_V5(VEC5, A0, A1, A2, A3, A4) \
{ \
typedef VEC5::Scalar Scalar; \
VEC5 v = {A0, A1, A2, A3, A4}; \
CHECK_MIXSCALAR_V5_APPROX(v, A0, A1, A2, A3, A4); \
}
template <int>
void fixedsizeVariadicVectorConstruction3() {
typedef Matrix<double, 5, 1> Vec5;
typedef Array<float, 5, 1> Arr5;
CHECK_MIXSCALAR_V5(Vec5, 1, 2., -3, 4.121, 5.53252);
CHECK_MIXSCALAR_V5(Arr5, 1, 2., 3.12f, 4.121, 5.53252);
}
template <typename Scalar>
void fixedsizeVariadicVectorConstruction() {
CALL_SUBTEST((fixedsizeVariadicVectorConstruction2<Matrix<Scalar, 4, 1>, Matrix<Scalar, 5, 1>>()));
CALL_SUBTEST((fixedsizeVariadicVectorConstruction2<Matrix<Scalar, 1, 4>, Matrix<Scalar, 1, 5>>()));
CALL_SUBTEST((fixedsizeVariadicVectorConstruction2<Array<Scalar, 4, 1>, Array<Scalar, 5, 1>>()));
CALL_SUBTEST((fixedsizeVariadicVectorConstruction2<Array<Scalar, 1, 4>, Array<Scalar, 1, 5>>()));
}
template <typename Scalar>
void initializerListVectorConstruction() {
Scalar raw[4];
for (int k = 0; k < 4; ++k) {
raw[k] = internal::random<Scalar>();
}
{
Matrix<Scalar, 4, 1> m{{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}};
Array<Scalar, 4, 1> a{{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}};
for (int k = 0; k < 4; ++k) {
VERIFY(m(k) == raw[k]);
}
for (int k = 0; k < 4; ++k) {
VERIFY(a(k) == raw[k]);
}
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 4, 1>({{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}})));
VERIFY((a == (Array<Scalar, 4, 1>({{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}}))).all());
}
{
Matrix<Scalar, 1, 4> m{{raw[0], raw[1], raw[2], raw[3]}};
Array<Scalar, 1, 4> a{{raw[0], raw[1], raw[2], raw[3]}};
for (int k = 0; k < 4; ++k) {
VERIFY(m(k) == raw[k]);
}
for (int k = 0; k < 4; ++k) {
VERIFY(a(k) == raw[k]);
}
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 1, 4>({{raw[0], raw[1], raw[2], raw[3]}})));
VERIFY((a == (Array<Scalar, 1, 4>({{raw[0], raw[1], raw[2], raw[3]}}))).all());
}
{
Matrix<Scalar, 4, Dynamic> m{{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}};
Array<Scalar, 4, Dynamic> a{{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}};
for (int k = 0; k < 4; ++k) {
VERIFY(m(k) == raw[k]);
}
for (int k = 0; k < 4; ++k) {
VERIFY(a(k) == raw[k]);
}
VERIFY_IS_EQUAL(m, (Matrix<Scalar, 4, Dynamic>({{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}})));
VERIFY((a == (Array<Scalar, 4, Dynamic>({{raw[0]}, {raw[1]}, {raw[2]}, {raw[3]}}))).all());
}
{
Matrix<Scalar, Dynamic, 4> m{{raw[0], raw[1], raw[2], raw[3]}};
Array<Scalar, Dynamic, 4> a{{raw[0], raw[1], raw[2], raw[3]}};
for (int k = 0; k < 4; ++k) {
VERIFY(m(k) == raw[k]);
}
for (int k = 0; k < 4; ++k) {
VERIFY(a(k) == raw[k]);
}
VERIFY_IS_EQUAL(m, (Matrix<Scalar, Dynamic, 4>({{raw[0], raw[1], raw[2], raw[3]}})));
VERIFY((a == (Array<Scalar, Dynamic, 4>({{raw[0], raw[1], raw[2], raw[3]}}))).all());
}
}
template <typename Scalar>
void initializerListMatrixConstruction() {
const Index RowsAtCompileTime = 5;
const Index ColsAtCompileTime = 4;
const Index SizeAtCompileTime = RowsAtCompileTime * ColsAtCompileTime;
Scalar raw[SizeAtCompileTime];
for (int i = 0; i < SizeAtCompileTime; ++i) {
raw[i] = internal::random<Scalar>();
}
{
Matrix<Scalar, Dynamic, Dynamic> m{};
VERIFY(m.cols() == 0);
VERIFY(m.rows() == 0);
VERIFY_IS_EQUAL(m, (Matrix<Scalar, Dynamic, Dynamic>()));
}
{
Matrix<Scalar, 5, 4> m{{raw[0], raw[1], raw[2], raw[3]},
{raw[4], raw[5], raw[6], raw[7]},
{raw[8], raw[9], raw[10], raw[11]},
{raw[12], raw[13], raw[14], raw[15]},
{raw[16], raw[17], raw[18], raw[19]}};
Matrix<Scalar, 5, 4> m2;
m2 << raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7], raw[8], raw[9], raw[10], raw[11], raw[12],
raw[13], raw[14], raw[15], raw[16], raw[17], raw[18], raw[19];
int k = 0;
for (int i = 0; i < RowsAtCompileTime; ++i) {
for (int j = 0; j < ColsAtCompileTime; ++j) {
VERIFY(m(i, j) == raw[k]);
++k;
}
}
VERIFY_IS_EQUAL(m, m2);
}
{
Matrix<Scalar, Dynamic, Dynamic> m{{raw[0], raw[1], raw[2], raw[3]},
{raw[4], raw[5], raw[6], raw[7]},
{raw[8], raw[9], raw[10], raw[11]},
{raw[12], raw[13], raw[14], raw[15]},
{raw[16], raw[17], raw[18], raw[19]}};
VERIFY(m.cols() == 4);
VERIFY(m.rows() == 5);
int k = 0;
for (int i = 0; i < RowsAtCompileTime; ++i) {
for (int j = 0; j < ColsAtCompileTime; ++j) {
VERIFY(m(i, j) == raw[k]);
++k;
}
}
Matrix<Scalar, Dynamic, Dynamic> m2(RowsAtCompileTime, ColsAtCompileTime);
k = 0;
for (int i = 0; i < RowsAtCompileTime; ++i) {
for (int j = 0; j < ColsAtCompileTime; ++j) {
m2(i, j) = raw[k];
++k;
}
}
VERIFY_IS_EQUAL(m, m2);
}
}
template <typename Scalar>
void initializerListArrayConstruction() {
const Index RowsAtCompileTime = 5;
const Index ColsAtCompileTime = 4;
const Index SizeAtCompileTime = RowsAtCompileTime * ColsAtCompileTime;
Scalar raw[SizeAtCompileTime];
for (int i = 0; i < SizeAtCompileTime; ++i) {
raw[i] = internal::random<Scalar>();
}
{
Array<Scalar, Dynamic, Dynamic> a{};
VERIFY(a.cols() == 0);
VERIFY(a.rows() == 0);
}
{
Array<Scalar, 5, 4> m{{raw[0], raw[1], raw[2], raw[3]},
{raw[4], raw[5], raw[6], raw[7]},
{raw[8], raw[9], raw[10], raw[11]},
{raw[12], raw[13], raw[14], raw[15]},
{raw[16], raw[17], raw[18], raw[19]}};
Array<Scalar, 5, 4> m2;
m2 << raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7], raw[8], raw[9], raw[10], raw[11], raw[12],
raw[13], raw[14], raw[15], raw[16], raw[17], raw[18], raw[19];
int k = 0;
for (int i = 0; i < RowsAtCompileTime; ++i) {
for (int j = 0; j < ColsAtCompileTime; ++j) {
VERIFY(m(i, j) == raw[k]);
++k;
}
}
VERIFY_IS_APPROX(m, m2);
}
{
Array<Scalar, Dynamic, Dynamic> m{{raw[0], raw[1], raw[2], raw[3]},
{raw[4], raw[5], raw[6], raw[7]},
{raw[8], raw[9], raw[10], raw[11]},
{raw[12], raw[13], raw[14], raw[15]},
{raw[16], raw[17], raw[18], raw[19]}};
VERIFY(m.cols() == 4);
VERIFY(m.rows() == 5);
int k = 0;
for (int i = 0; i < RowsAtCompileTime; ++i) {
for (int j = 0; j < ColsAtCompileTime; ++j) {
VERIFY(m(i, j) == raw[k]);
++k;
}
}
Array<Scalar, Dynamic, Dynamic> m2(RowsAtCompileTime, ColsAtCompileTime);
k = 0;
for (int i = 0; i < RowsAtCompileTime; ++i) {
for (int j = 0; j < ColsAtCompileTime; ++j) {
m2(i, j) = raw[k];
++k;
}
}
VERIFY_IS_APPROX(m, m2);
}
}
template <typename Scalar>
void dynamicVectorConstruction() {
const Index size = 4;
Scalar raw[size];
for (int i = 0; i < size; ++i) {
raw[i] = internal::random<Scalar>();
}
typedef Matrix<Scalar, Dynamic, 1> VectorX;
{
VectorX v{{raw[0], raw[1], raw[2], raw[3]}};
for (int i = 0; i < size; ++i) {
VERIFY(v(i) == raw[i]);
}
VERIFY(v.rows() == size);
VERIFY(v.cols() == 1);
VERIFY_IS_EQUAL(v, (VectorX{{raw[0], raw[1], raw[2], raw[3]}}));
}
}
EIGEN_DECLARE_TEST(initializer_list_construction) {
CALL_SUBTEST_1(initializerListVectorConstruction<unsigned char>());
CALL_SUBTEST_1(initializerListVectorConstruction<float>());
CALL_SUBTEST_1(initializerListVectorConstruction<double>());
CALL_SUBTEST_1(initializerListVectorConstruction<int>());
CALL_SUBTEST_1(initializerListVectorConstruction<long int>());
CALL_SUBTEST_1(initializerListVectorConstruction<std::ptrdiff_t>());
CALL_SUBTEST_1(initializerListVectorConstruction<std::complex<double>>());
CALL_SUBTEST_1(initializerListVectorConstruction<std::complex<float>>());
CALL_SUBTEST_2(initializerListMatrixConstruction<unsigned char>());
CALL_SUBTEST_2(initializerListMatrixConstruction<float>());
CALL_SUBTEST_2(initializerListMatrixConstruction<double>());
CALL_SUBTEST_2(initializerListMatrixConstruction<int>());
CALL_SUBTEST_2(initializerListMatrixConstruction<long int>());
CALL_SUBTEST_2(initializerListMatrixConstruction<std::ptrdiff_t>());
CALL_SUBTEST_2(initializerListMatrixConstruction<std::complex<double>>());
CALL_SUBTEST_2(initializerListMatrixConstruction<std::complex<float>>());
CALL_SUBTEST_3(initializerListArrayConstruction<unsigned char>());
CALL_SUBTEST_3(initializerListArrayConstruction<float>());
CALL_SUBTEST_3(initializerListArrayConstruction<double>());
CALL_SUBTEST_3(initializerListArrayConstruction<int>());
CALL_SUBTEST_3(initializerListArrayConstruction<long int>());
CALL_SUBTEST_3(initializerListArrayConstruction<std::ptrdiff_t>());
CALL_SUBTEST_3(initializerListArrayConstruction<std::complex<double>>());
CALL_SUBTEST_3(initializerListArrayConstruction<std::complex<float>>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<unsigned char>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<float>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<double>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<int>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<long int>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<std::ptrdiff_t>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<std::complex<double>>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction<std::complex<float>>());
CALL_SUBTEST_4(fixedsizeVariadicVectorConstruction3<0>());
CALL_SUBTEST_5(TestMethodDispatching<int>::run());
CALL_SUBTEST_5(TestMethodDispatching<long int>::run());
CALL_SUBTEST_6(dynamicVectorConstruction<unsigned char>());
CALL_SUBTEST_6(dynamicVectorConstruction<float>());
CALL_SUBTEST_6(dynamicVectorConstruction<double>());
CALL_SUBTEST_6(dynamicVectorConstruction<int>());
CALL_SUBTEST_6(dynamicVectorConstruction<long int>());
CALL_SUBTEST_6(dynamicVectorConstruction<std::ptrdiff_t>());
CALL_SUBTEST_6(dynamicVectorConstruction<std::complex<double>>());
CALL_SUBTEST_6(dynamicVectorConstruction<std::complex<float>>());
}
+100
View File
@@ -0,0 +1,100 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/LU>
#include <Eigen/Cholesky>
#include <Eigen/QR>
// This file test inplace decomposition through Ref<>, as supported by Cholesky, LU, and QR decompositions.
template <typename DecType, typename MatrixType>
void inplace(bool square = false, bool SPD = false) {
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RhsType;
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ResType;
Index rows = MatrixType::RowsAtCompileTime == Dynamic ? internal::random<Index>(2, EIGEN_TEST_MAX_SIZE / 2)
: Index(MatrixType::RowsAtCompileTime);
Index cols = MatrixType::ColsAtCompileTime == Dynamic ? (square ? rows : internal::random<Index>(2, rows))
: Index(MatrixType::ColsAtCompileTime);
MatrixType A = MatrixType::Random(rows, cols);
RhsType b = RhsType::Random(rows);
ResType x(cols);
if (SPD) {
assert(square);
A.topRows(cols) = A.topRows(cols).adjoint() * A.topRows(cols);
A.diagonal().array() += 1e-3;
}
MatrixType A0 = A;
MatrixType A1 = A;
DecType dec(A);
// Check that the content of A has been modified
VERIFY_IS_NOT_APPROX(A, A0);
// Check that the decomposition is correct:
if (rows == cols) {
VERIFY_IS_APPROX(A0 * (x = dec.solve(b)), b);
} else {
VERIFY_IS_APPROX(A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b);
}
// Check that modifying A breaks the current dec:
A.setRandom();
if (rows == cols) {
VERIFY_IS_NOT_APPROX(A0 * (x = dec.solve(b)), b);
} else {
VERIFY_IS_NOT_APPROX(A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b);
}
// Check that calling compute(A1) does not modify A1:
A = A0;
dec.compute(A1);
VERIFY_IS_EQUAL(A0, A1);
VERIFY_IS_NOT_APPROX(A, A0);
if (rows == cols) {
VERIFY_IS_APPROX(A0 * (x = dec.solve(b)), b);
} else {
VERIFY_IS_APPROX(A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b);
}
}
EIGEN_DECLARE_TEST(inplace_decomposition) {
EIGEN_UNUSED typedef Matrix<double, 4, 3> Matrix43d;
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1((inplace<LLT<Ref<MatrixXd> >, MatrixXd>(true, true)));
CALL_SUBTEST_1((inplace<LLT<Ref<Matrix4d> >, Matrix4d>(true, true)));
CALL_SUBTEST_2((inplace<LDLT<Ref<MatrixXd> >, MatrixXd>(true, true)));
CALL_SUBTEST_2((inplace<LDLT<Ref<Matrix4d> >, Matrix4d>(true, true)));
CALL_SUBTEST_3((inplace<PartialPivLU<Ref<MatrixXd> >, MatrixXd>(true, false)));
CALL_SUBTEST_3((inplace<PartialPivLU<Ref<Matrix4d> >, Matrix4d>(true, false)));
CALL_SUBTEST_4((inplace<FullPivLU<Ref<MatrixXd> >, MatrixXd>(true, false)));
CALL_SUBTEST_4((inplace<FullPivLU<Ref<Matrix4d> >, Matrix4d>(true, false)));
CALL_SUBTEST_5((inplace<HouseholderQR<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_5((inplace<HouseholderQR<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_6((inplace<ColPivHouseholderQR<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_6((inplace<ColPivHouseholderQR<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_7((inplace<FullPivHouseholderQR<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_7((inplace<FullPivHouseholderQR<Ref<Matrix43d> >, Matrix43d>(false, false)));
CALL_SUBTEST_8((inplace<CompleteOrthogonalDecomposition<Ref<MatrixXd> >, MatrixXd>(false, false)));
CALL_SUBTEST_8((inplace<CompleteOrthogonalDecomposition<Ref<Matrix43d> >, Matrix43d>(false, false)));
}
}
+162
View File
@@ -0,0 +1,162 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#undef VERIFY_IS_APPROX
#define VERIFY_IS_APPROX(a, b) VERIFY((a) == (b));
#undef VERIFY_IS_NOT_APPROX
#define VERIFY_IS_NOT_APPROX(a, b) VERIFY((a) != (b));
template <typename MatrixType>
void signed_integer_type_tests(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 };
VERIFY(is_signed == 1);
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1(rows, cols), m2 = MatrixType::Random(rows, cols), mzero = MatrixType::Zero(rows, cols);
do {
m1 = MatrixType::Random(rows, cols);
} while (m1 == mzero || m1 == m2);
// check linear structure
Scalar s1;
do {
s1 = internal::random<Scalar>();
} while (s1 == 0);
VERIFY_IS_EQUAL(-(-m1), m1);
VERIFY_IS_EQUAL(-m2 + m1 + m2, m1);
VERIFY_IS_EQUAL((-m1 + m2) * s1, -s1 * m1 + s1 * m2);
}
template <typename MatrixType>
void integer_type_tests(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
VERIFY(NumTraits<Scalar>::IsInteger);
enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 };
VERIFY(int(NumTraits<Scalar>::IsSigned) == is_signed);
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
Index rows = m.rows();
Index cols = m.cols();
// this test relies a lot on Random.h, and there's not much more that we can do
// to test it, hence I consider that we will have tested Random.h
MatrixType m1(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols), mzero = MatrixType::Zero(rows, cols);
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
SquareMatrixType identity = SquareMatrixType::Identity(rows, rows), square = SquareMatrixType::Random(rows, rows);
VectorType v1(rows), v2 = VectorType::Random(rows), vzero = VectorType::Zero(rows);
do {
m1 = MatrixType::Random(rows, cols);
} while (m1 == mzero || m1 == m2);
do {
v1 = VectorType::Random(rows);
} while (v1 == vzero || v1 == v2);
VERIFY_IS_APPROX(v1, v1);
VERIFY_IS_NOT_APPROX(v1, 2 * v1);
VERIFY_IS_APPROX(vzero, v1 - v1);
VERIFY_IS_APPROX(m1, m1);
VERIFY_IS_NOT_APPROX(m1, 2 * m1);
VERIFY_IS_APPROX(mzero, m1 - m1);
VERIFY_IS_APPROX(m3 = m1, m1);
MatrixType m4;
VERIFY_IS_APPROX(m4 = m1, m1);
m3.real() = m1.real();
VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real());
VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real());
// check == / != operators
VERIFY(m1 == m1);
VERIFY(m1 != m2);
VERIFY(!(m1 == m2));
VERIFY(!(m1 != m1));
m1 = m2;
VERIFY(m1 == m2);
VERIFY(!(m1 != m2));
// check linear structure
Scalar s1;
do {
s1 = internal::random<Scalar>();
} while (s1 == 0);
VERIFY_IS_EQUAL(m1 + m1, 2 * m1);
VERIFY_IS_EQUAL(m1 + m2 - m1, m2);
VERIFY_IS_EQUAL(m1 * s1, s1 * m1);
VERIFY_IS_EQUAL((m1 + m2) * s1, s1 * m1 + s1 * m2);
m3 = m2;
m3 += m1;
VERIFY_IS_EQUAL(m3, m1 + m2);
m3 = m2;
m3 -= m1;
VERIFY_IS_EQUAL(m3, m2 - m1);
m3 = m2;
m3 *= s1;
VERIFY_IS_EQUAL(m3, s1 * m2);
// check matrix product.
VERIFY_IS_APPROX(identity * m1, m1);
VERIFY_IS_APPROX(square * (m1 + m2), square * m1 + square * m2);
VERIFY_IS_APPROX((m1 + m2).transpose() * square, m1.transpose() * square + m2.transpose() * square);
VERIFY_IS_APPROX((m1 * m2.transpose()) * m1, m1 * (m2.transpose() * m1));
}
template <int>
void integer_types_extra() {
VERIFY_IS_EQUAL(int(internal::scalar_div_cost<int>::value), 8);
VERIFY_IS_EQUAL(int(internal::scalar_div_cost<unsigned int>::value), 8);
if (sizeof(long) > sizeof(int)) {
VERIFY(int(internal::scalar_div_cost<long>::value) > int(internal::scalar_div_cost<int>::value));
VERIFY(int(internal::scalar_div_cost<unsigned long>::value) > int(internal::scalar_div_cost<int>::value));
}
}
EIGEN_DECLARE_TEST(integer_types) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(integer_type_tests(Matrix<unsigned int, 1, 1>()));
CALL_SUBTEST_1(integer_type_tests(Matrix<unsigned long, 3, 4>()));
CALL_SUBTEST_2(integer_type_tests(Matrix<long, 2, 2>()));
CALL_SUBTEST_2(signed_integer_type_tests(Matrix<long, 2, 2>()));
CALL_SUBTEST_3(integer_type_tests(Matrix<char, 2, Dynamic>(2, 10)));
CALL_SUBTEST_3(signed_integer_type_tests(Matrix<signed char, 2, Dynamic>(2, 10)));
CALL_SUBTEST_4(integer_type_tests(Matrix<unsigned char, 3, 3>()));
CALL_SUBTEST_4(integer_type_tests(Matrix<unsigned char, Dynamic, Dynamic>(20, 20)));
CALL_SUBTEST_5(integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)));
CALL_SUBTEST_5(signed_integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)));
CALL_SUBTEST_6(integer_type_tests(Matrix<unsigned short, 4, 4>()));
CALL_SUBTEST_7(integer_type_tests(Matrix<long long, 11, 13>()));
CALL_SUBTEST_7(signed_integer_type_tests(Matrix<long long, 11, 13>()));
CALL_SUBTEST_8(integer_type_tests(Matrix<unsigned long long, Dynamic, 5>(1, 5)));
}
CALL_SUBTEST_9(integer_types_extra<0>());
}
+141
View File
@@ -0,0 +1,141 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/LU>
template <typename MatrixType>
void inverse_for_fixed_size(const MatrixType&, std::enable_if_t<MatrixType::SizeAtCompileTime == Dynamic>* = 0) {}
template <typename MatrixType>
void inverse_for_fixed_size(const MatrixType& m1, std::enable_if_t<MatrixType::SizeAtCompileTime != Dynamic>* = 0) {
using std::abs;
MatrixType m2, identity = MatrixType::Identity();
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
// computeInverseAndDetWithCheck tests
// First: an invertible matrix
bool invertible;
Scalar det;
m2.setZero();
m1.computeInverseAndDetWithCheck(m2, det, invertible);
VERIFY(invertible);
VERIFY_IS_APPROX(identity, m1 * m2);
VERIFY_IS_APPROX(det, m1.determinant());
m2.setZero();
m1.computeInverseWithCheck(m2, invertible);
VERIFY(invertible);
VERIFY_IS_APPROX(identity, m1 * m2);
// Second: a rank one matrix (not invertible, except for 1x1 matrices)
VectorType v3 = VectorType::Random();
MatrixType m3 = v3 * v3.transpose(), m4;
m3.computeInverseAndDetWithCheck(m4, det, invertible);
VERIFY(m1.rows() == 1 ? invertible : !invertible);
VERIFY_IS_MUCH_SMALLER_THAN(abs(det - m3.determinant()), RealScalar(1));
m3.computeInverseWithCheck(m4, invertible);
VERIFY(m1.rows() == 1 ? invertible : !invertible);
// check with submatrices
{
Matrix<Scalar, MatrixType::RowsAtCompileTime + 1, MatrixType::RowsAtCompileTime + 1, MatrixType::Options> m5;
m5.setRandom();
m5.topLeftCorner(m1.rows(), m1.rows()) = m1;
m2 = m5.template topLeftCorner<MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime>().inverse();
VERIFY_IS_APPROX((m5.template topLeftCorner<MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime>()),
m2.inverse());
}
}
template <typename MatrixType>
void inverse(const MatrixType& m) {
/* this test covers the following files:
Inverse.h
*/
Index rows = m.rows();
Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
MatrixType m1(rows, cols), m2(rows, cols), identity = MatrixType::Identity(rows, rows);
createRandomPIMatrixOfRank(rows, rows, rows, m1);
m2 = m1.inverse();
VERIFY_IS_APPROX(m1, m2.inverse());
VERIFY_IS_APPROX((Scalar(2) * m2).inverse(), m2.inverse() * Scalar(0.5));
VERIFY_IS_APPROX(identity, m1.inverse() * m1);
VERIFY_IS_APPROX(identity, m1 * m1.inverse());
VERIFY_IS_APPROX(m1, m1.inverse().inverse());
// since for the general case we implement separately row-major and col-major, test that
VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));
inverse_for_fixed_size(m1);
// check in-place inversion
if (MatrixType::RowsAtCompileTime >= 2 && MatrixType::RowsAtCompileTime <= 4) {
// in-place is forbidden
VERIFY_RAISES_ASSERT(m1 = m1.inverse());
} else {
m2 = m1.inverse();
m1 = m1.inverse();
VERIFY_IS_APPROX(m1, m2);
}
}
template <typename Scalar>
void inverse_zerosized() {
Matrix<Scalar, Dynamic, Dynamic> A(0, 0);
{
Matrix<Scalar, 0, 1> b, x;
x = A.inverse() * b;
}
{
Matrix<Scalar, Dynamic, Dynamic> b(0, 1), x;
x = A.inverse() * b;
VERIFY_IS_EQUAL(x.rows(), 0);
VERIFY_IS_EQUAL(x.cols(), 1);
}
}
EIGEN_DECLARE_TEST(inverse) {
int s = 0;
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(inverse(Matrix<double, 1, 1>()));
CALL_SUBTEST_2(inverse(Matrix2d()));
CALL_SUBTEST_3(inverse(Matrix3f()));
CALL_SUBTEST_4(inverse(Matrix4f()));
CALL_SUBTEST_4(inverse(Matrix<float, 4, 4, DontAlign>()));
s = internal::random<int>(50, 320);
CALL_SUBTEST_5(inverse(MatrixXf(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
CALL_SUBTEST_5(inverse_zerosized<float>());
CALL_SUBTEST_5(inverse(MatrixXf(0, 0)));
CALL_SUBTEST_5(inverse(MatrixXf(1, 1)));
s = internal::random<int>(25, 100);
CALL_SUBTEST_6(inverse(MatrixXcd(s, s)));
TEST_SET_BUT_UNUSED_VARIABLE(s)
CALL_SUBTEST_7(inverse(Matrix4d()));
CALL_SUBTEST_7(inverse(Matrix<double, 4, 4, DontAlign>()));
CALL_SUBTEST_8(inverse(Matrix4cd()));
}
}
+63
View File
@@ -0,0 +1,63 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2019 Joel Holdsworth <joel.holdsworth@vcatechnology.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 <sstream>
#include "main.h"
template <typename Scalar>
struct check_ostream_impl {
static void run() {
const Array<Scalar, 1, 1> array(123);
std::ostringstream ss;
ss << array;
VERIFY(ss.str() == "123");
check_ostream_impl<std::complex<Scalar> >::run();
};
};
template <>
struct check_ostream_impl<bool> {
static void run() {
const Array<bool, 1, 2> array(1, 0);
std::ostringstream ss;
ss << array;
VERIFY(ss.str() == "1 0");
};
};
template <typename Scalar>
struct check_ostream_impl<std::complex<Scalar> > {
static void run() {
const Array<std::complex<Scalar>, 1, 1> array(std::complex<Scalar>(12, 34));
std::ostringstream ss;
ss << array;
VERIFY(ss.str() == "(12,34)");
};
};
template <typename Scalar>
static void check_ostream() {
check_ostream_impl<Scalar>::run();
}
EIGEN_DECLARE_TEST(rand) {
CALL_SUBTEST(check_ostream<bool>());
CALL_SUBTEST(check_ostream<float>());
CALL_SUBTEST(check_ostream<double>());
CALL_SUBTEST(check_ostream<Eigen::numext::int8_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::uint8_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::int16_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::uint16_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::int32_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::uint32_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::int64_t>());
CALL_SUBTEST(check_ostream<Eigen::numext::uint64_t>());
}
+39
View File
@@ -0,0 +1,39 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// 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
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
using internal::is_same_dense;
EIGEN_DECLARE_TEST(is_same_dense) {
typedef Matrix<double, Dynamic, Dynamic, ColMajor> ColMatrixXd;
typedef Matrix<std::complex<double>, Dynamic, Dynamic, ColMajor> ColMatrixXcd;
ColMatrixXd m1(10, 10);
ColMatrixXcd m2(10, 10);
Ref<ColMatrixXd> ref_m1(m1);
Ref<ColMatrixXd, 0, Stride<Dynamic, Dynamic> > ref_m2_real(m2.real());
Ref<const ColMatrixXd> const_ref_m1(m1);
VERIFY(is_same_dense(m1, m1));
VERIFY(is_same_dense(m1, ref_m1));
VERIFY(is_same_dense(const_ref_m1, m1));
VERIFY(is_same_dense(const_ref_m1, ref_m1));
VERIFY(is_same_dense(m1.block(0, 0, m1.rows(), m1.cols()), m1));
VERIFY(!is_same_dense(m1.row(0), m1.col(0)));
Ref<const ColMatrixXd> const_ref_m1_row(m1.row(1));
VERIFY(!is_same_dense(m1.row(1), const_ref_m1_row));
Ref<const ColMatrixXd> const_ref_m1_col(m1.col(1));
VERIFY(is_same_dense(m1.col(1), const_ref_m1_col));
VERIFY(!is_same_dense(m1, ref_m2_real));
VERIFY(!is_same_dense(m2, ref_m2_real));
}
+81
View File
@@ -0,0 +1,81 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/SVD>
template <typename MatrixType, typename JacobiScalar>
void jacobi(const MatrixType& m = MatrixType()) {
Index rows = m.rows();
Index cols = m.cols();
enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime };
typedef Matrix<JacobiScalar, 2, 1> JacobiVector;
const MatrixType a(MatrixType::Random(rows, cols));
JacobiVector v = JacobiVector::Random().normalized();
JacobiScalar c = v.x(), s = v.y();
JacobiRotation<JacobiScalar> rot(c, s);
{
Index p = internal::random<Index>(0, rows - 1);
Index q;
do {
q = internal::random<Index>(0, rows - 1);
} while (q == p);
MatrixType b = a;
b.applyOnTheLeft(p, q, rot);
VERIFY_IS_APPROX(b.row(p), c * a.row(p) + numext::conj(s) * a.row(q));
VERIFY_IS_APPROX(b.row(q), -s * a.row(p) + numext::conj(c) * a.row(q));
}
{
Index p = internal::random<Index>(0, cols - 1);
Index q;
do {
q = internal::random<Index>(0, cols - 1);
} while (q == p);
MatrixType b = a;
b.applyOnTheRight(p, q, rot);
VERIFY_IS_APPROX(b.col(p), c * a.col(p) - s * a.col(q));
VERIFY_IS_APPROX(b.col(q), numext::conj(s) * a.col(p) + numext::conj(c) * a.col(q));
}
}
EIGEN_DECLARE_TEST(jacobi) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1((jacobi<Matrix3f, float>()));
CALL_SUBTEST_2((jacobi<Matrix4d, double>()));
CALL_SUBTEST_3((jacobi<Matrix4cf, float>()));
CALL_SUBTEST_3((jacobi<Matrix4cf, std::complex<float> >()));
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))));
CALL_SUBTEST_5((jacobi<MatrixXcd, double>(MatrixXcd(r, c))));
CALL_SUBTEST_5((jacobi<MatrixXcd, std::complex<double> >(MatrixXcd(r, c))));
// complex<float> is really important to test as it is the only way to cover conjugation issues in certain unaligned
// paths
CALL_SUBTEST_6((jacobi<MatrixXcf, float>(MatrixXcf(r, c))));
CALL_SUBTEST_6((jacobi<MatrixXcf, std::complex<float> >(MatrixXcf(r, c))));
TEST_SET_BUT_UNUSED_VARIABLE(r);
TEST_SET_BUT_UNUSED_VARIABLE(c);
}
}
+215
View File
@@ -0,0 +1,215 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// 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>
#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"
template <typename MatrixType>
void jacobisvd_method() {
enum { Size = MatrixType::RowsAtCompileTime };
typedef typename MatrixType::RealScalar RealScalar;
typedef Matrix<RealScalar, Size, 1> RealVecType;
MatrixType m = MatrixType::Identity();
VERIFY_IS_APPROX(m.jacobiSvd().singularValues(), RealVecType::Ones());
VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU());
VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV());
VERIFY_IS_APPROX(m.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);
}
template <typename MatrixType>
void jacobisvd_thin_options(const MatrixType& input = MatrixType()) {
MatrixType m(input.rows(), input.cols());
svd_fill_random(m);
svd_thin_option_checks<MatrixType, 0>(m);
svd_thin_option_checks<MatrixType, ColPivHouseholderQRPreconditioner>(m);
svd_thin_option_checks<MatrixType, HouseholderQRPreconditioner>(m);
}
template <typename MatrixType>
void jacobisvd_full_options(const MatrixType& input = MatrixType()) {
MatrixType m(input.rows(), input.cols());
svd_fill_random(m);
svd_option_checks_full_only<MatrixType, 0>(m);
svd_option_checks_full_only<MatrixType, ColPivHouseholderQRPreconditioner>(m);
svd_option_checks_full_only<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& input = MatrixType()) {
MatrixType m(input.rows(), input.cols());
svd_fill_random(m);
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);
}
template <typename MatrixType>
void jacobisvd_verify_inputs(const MatrixType& input = MatrixType()) {
// check defaults
typedef JacobiSVD<MatrixType> DefaultSVD;
MatrixType m(input.rows(), input.cols());
svd_fill_random(m);
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/
class Bar {
public:
Bar() {}
};
bool operator<(const Bar&, const Bar&) { return true; }
} // namespace Foo
// regression test for a very strange MSVC issue for which simply
// including SVDBase.h messes up with std::max and custom scalar type
void msvc_workaround() {
const Foo::Bar a;
const Foo::Bar b;
const Foo::Bar c = std::max EIGEN_NOT_A_MACRO(a, b);
EIGEN_UNUSED_VARIABLE(c)
}
EIGEN_DECLARE_TEST(jacobisvd) {
CALL_SUBTEST_1((jacobisvd_verify_inputs<Matrix4d>()));
CALL_SUBTEST_2((jacobisvd_verify_inputs(Matrix<float, 5, Dynamic>(5, 6))));
CALL_SUBTEST_3((jacobisvd_verify_inputs<Matrix<std::complex<double>, 7, 5>>()));
CALL_SUBTEST_4((jacobisvd_verify_assert<Matrix3f>()));
CALL_SUBTEST_5((jacobisvd_verify_assert<Matrix4d>()));
CALL_SUBTEST_6((jacobisvd_verify_assert<Matrix<float, 10, 12>>()));
CALL_SUBTEST_7((jacobisvd_verify_assert<Matrix<float, 12, 10>>()));
CALL_SUBTEST_8((jacobisvd_verify_assert<MatrixXf>(MatrixXf(10, 12))));
CALL_SUBTEST_9((jacobisvd_verify_assert<MatrixXcd>(MatrixXcd(7, 5))));
CALL_SUBTEST_10(svd_all_trivial_2x2(jacobisvd_thin_options<Matrix2cd>));
CALL_SUBTEST_11(svd_all_trivial_2x2(jacobisvd_thin_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_12((jacobisvd_thin_options<Matrix3f>()));
CALL_SUBTEST_13((jacobisvd_full_options<Matrix3f>()));
CALL_SUBTEST_14((jacobisvd_thin_options<Matrix4d>()));
CALL_SUBTEST_15((jacobisvd_full_options<Matrix4d>()));
CALL_SUBTEST_16((jacobisvd_thin_options<Matrix<float, 2, 3>>()));
CALL_SUBTEST_17((jacobisvd_full_options<Matrix<float, 2, 3>>()));
CALL_SUBTEST_18((jacobisvd_thin_options<Matrix<double, 4, 7>>()));
CALL_SUBTEST_19((jacobisvd_full_options<Matrix<double, 4, 7>>()));
CALL_SUBTEST_20((jacobisvd_thin_options<Matrix<double, 7, 4>>()));
CALL_SUBTEST_21((jacobisvd_full_options<Matrix<double, 7, 4>>()));
CALL_SUBTEST_22((jacobisvd_thin_options<Matrix<double, Dynamic, 5>>(Matrix<double, Dynamic, 5>(r, 5))));
CALL_SUBTEST_23((jacobisvd_full_options<Matrix<double, Dynamic, 5>>(Matrix<double, Dynamic, 5>(r, 5))));
CALL_SUBTEST_24((jacobisvd_thin_options<Matrix<double, 5, Dynamic>>(Matrix<double, 5, Dynamic>(5, c))));
CALL_SUBTEST_25((jacobisvd_full_options<Matrix<double, 5, Dynamic>>(Matrix<double, 5, Dynamic>(5, c))));
CALL_SUBTEST_26((jacobisvd_thin_options<MatrixXf>(MatrixXf(r, c))));
CALL_SUBTEST_27((jacobisvd_full_options<MatrixXf>(MatrixXf(r, c))));
CALL_SUBTEST_28((jacobisvd_thin_options<MatrixXcd>(MatrixXcd(r, c))));
CALL_SUBTEST_29((jacobisvd_full_options<MatrixXcd>(MatrixXcd(r, c))));
CALL_SUBTEST_30((jacobisvd_thin_options<MatrixXd>(MatrixXd(r, c))));
CALL_SUBTEST_31((jacobisvd_full_options<MatrixXd>(MatrixXd(r, c))));
CALL_SUBTEST_32((jacobisvd_thin_options<Matrix<double, 5, 7, RowMajor>>()));
CALL_SUBTEST_33((jacobisvd_full_options<Matrix<double, 5, 7, RowMajor>>()));
CALL_SUBTEST_34((jacobisvd_thin_options<Matrix<double, 7, 5, RowMajor>>()));
CALL_SUBTEST_35((jacobisvd_full_options<Matrix<double, 7, 5, RowMajor>>()));
MatrixXcd noQRTest = MatrixXcd(r, r);
svd_fill_random(noQRTest);
CALL_SUBTEST_36((svd_thin_option_checks<MatrixXcd, NoQRPreconditioner>(noQRTest)));
CALL_SUBTEST_36((svd_option_checks_full_only<MatrixXcd, NoQRPreconditioner>(noQRTest)));
CALL_SUBTEST_37((
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 13, 15>, ColPivHouseholderQRPreconditioner>(
r, c)));
CALL_SUBTEST_38(
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, ColMajor, 15, 13>, HouseholderQRPreconditioner>(r,
c)));
CALL_SUBTEST_39((
svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 13, 15>, ColPivHouseholderQRPreconditioner>(
r, c)));
CALL_SUBTEST_40(
(svd_check_max_size_matrix<Matrix<float, Dynamic, Dynamic, RowMajor, 15, 13>, HouseholderQRPreconditioner>(r,
c)));
// Test on inf/nan matrix
CALL_SUBTEST_41((svd_inf_nan<MatrixXf>()));
CALL_SUBTEST_42((svd_inf_nan<MatrixXd>()));
CALL_SUBTEST_43((jacobisvd_verify_assert<Matrix<double, 6, 1>>()));
CALL_SUBTEST_44((jacobisvd_verify_assert<Matrix<double, 1, 6>>()));
CALL_SUBTEST_45((jacobisvd_verify_assert<Matrix<double, Dynamic, 1>>(Matrix<double, Dynamic, 1>(r))));
CALL_SUBTEST_46((jacobisvd_verify_assert<Matrix<double, 1, Dynamic>>(Matrix<double, 1, Dynamic>(c))));
}
CALL_SUBTEST_47((jacobisvd_thin_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_48((jacobisvd_full_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_49((jacobisvd_thin_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)))));
CALL_SUBTEST_50((jacobisvd_full_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_51((jacobisvd_method<Matrix2cd>()));
CALL_SUBTEST_52((jacobisvd_method<Matrix3f>()));
// Test problem size constructors
CALL_SUBTEST_53(JacobiSVD<MatrixXf>(10, 10));
// Check that preallocation avoids subsequent mallocs
CALL_SUBTEST_54(svd_preallocate<void>());
CALL_SUBTEST_55(svd_underoverflow<void>());
msvc_workaround();
}
+30
View File
@@ -0,0 +1,30 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS
#include "sparse_solver.h"
#include <Eigen/KLUSupport>
template <typename T>
void test_klu_support_T() {
KLU<SparseMatrix<T, ColMajor> > klu_colmajor;
KLU<SparseMatrix<T, RowMajor> > klu_rowmajor;
check_sparse_square_solving(klu_colmajor);
check_sparse_square_solving(klu_rowmajor);
// check_sparse_square_determinant(umfpack_colmajor);
// check_sparse_square_determinant(umfpack_rowmajor);
}
EIGEN_DECLARE_TEST(klu_support) {
CALL_SUBTEST_1(test_klu_support_T<double>());
CALL_SUBTEST_2(test_klu_support_T<std::complex<double> >());
}
+151
View File
@@ -0,0 +1,151 @@
// 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) 2014 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
static bool g_called;
#define EIGEN_SCALAR_BINARY_OP_PLUGIN \
{ g_called |= (!internal::is_same<LhsScalar, RhsScalar>::value); }
#include "main.h"
template <typename MatrixType>
void linearStructure(const MatrixType& m) {
using std::abs;
/* this test covers the following files:
CwiseUnaryOp.h, CwiseBinaryOp.h, SelfCwiseBinaryOp.h
*/
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
Index rows = m.rows();
Index cols = m.cols();
// this test relies a lot on Random.h, and there's not much more that we can do
// to test it, hence I consider that we will have tested Random.h
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols);
Scalar s1 = internal::random<Scalar>();
while (abs(s1) < RealScalar(1e-3)) s1 = internal::random<Scalar>();
Index r = internal::random<Index>(0, rows - 1), c = internal::random<Index>(0, cols - 1);
VERIFY_IS_APPROX(-(-m1), m1);
VERIFY_IS_APPROX(m1 + m1, 2 * m1);
VERIFY_IS_APPROX(m1 + m2 - m1, m2);
VERIFY_IS_APPROX(-m2 + m1 + m2, m1);
VERIFY_IS_APPROX(m1 * s1, s1 * m1);
VERIFY_IS_APPROX((m1 + m2) * s1, s1 * m1 + s1 * m2);
VERIFY_IS_APPROX((-m1 + m2) * s1, -s1 * m1 + s1 * m2);
m3 = m2;
m3 += m1;
VERIFY_IS_APPROX(m3, m1 + m2);
m3 = m2;
m3 -= m1;
VERIFY_IS_APPROX(m3, m2 - m1);
m3 = m2;
m3 *= s1;
VERIFY_IS_APPROX(m3, s1 * m2);
if (!NumTraits<Scalar>::IsInteger) {
m3 = m2;
m3 /= s1;
VERIFY_IS_APPROX(m3, m2 / s1);
}
// again, test operator() to check const-qualification
VERIFY_IS_APPROX((-m1)(r, c), -(m1(r, c)));
VERIFY_IS_APPROX((m1 - m2)(r, c), (m1(r, c)) - (m2(r, c)));
VERIFY_IS_APPROX((m1 + m2)(r, c), (m1(r, c)) + (m2(r, c)));
VERIFY_IS_APPROX((s1 * m1)(r, c), s1 * (m1(r, c)));
VERIFY_IS_APPROX((m1 * s1)(r, c), (m1(r, c)) * s1);
if (!NumTraits<Scalar>::IsInteger) VERIFY_IS_APPROX((m1 / s1)(r, c), (m1(r, c)) / s1);
// use .block to disable vectorization and compare to the vectorized version
VERIFY_IS_APPROX(m1 + m1.block(0, 0, rows, cols), m1 + m1);
VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0, 0, rows, cols)), m1.cwiseProduct(m1));
VERIFY_IS_APPROX(m1 - m1.block(0, 0, rows, cols), m1 - m1);
VERIFY_IS_APPROX(m1.block(0, 0, rows, cols) * s1, m1 * s1);
}
// Make sure that complex * real and real * complex are properly optimized
template <typename MatrixType>
void real_complex(DenseIndex rows = MatrixType::RowsAtCompileTime, DenseIndex cols = MatrixType::ColsAtCompileTime) {
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
RealScalar s = internal::random<RealScalar>();
MatrixType m1 = MatrixType::Random(rows, cols);
g_called = false;
VERIFY_IS_APPROX(s * m1, Scalar(s) * m1);
VERIFY(g_called && "real * matrix<complex> not properly optimized");
g_called = false;
VERIFY_IS_APPROX(m1 * s, m1 * Scalar(s));
VERIFY(g_called && "matrix<complex> * real not properly optimized");
g_called = false;
VERIFY_IS_APPROX(m1 / s, m1 / Scalar(s));
VERIFY(g_called && "matrix<complex> / real not properly optimized");
g_called = false;
VERIFY_IS_APPROX(s + m1.array(), Scalar(s) + m1.array());
VERIFY(g_called && "real + matrix<complex> not properly optimized");
g_called = false;
VERIFY_IS_APPROX(m1.array() + s, m1.array() + Scalar(s));
VERIFY(g_called && "matrix<complex> + real not properly optimized");
g_called = false;
VERIFY_IS_APPROX(s - m1.array(), Scalar(s) - m1.array());
VERIFY(g_called && "real - matrix<complex> not properly optimized");
g_called = false;
VERIFY_IS_APPROX(m1.array() - s, m1.array() - Scalar(s));
VERIFY(g_called && "matrix<complex> - real not properly optimized");
}
template <int>
void linearstructure_overflow() {
// make sure that /=scalar and /scalar do not overflow
// rational: 1.0/4.94e-320 overflow, but m/4.94e-320 should not
Matrix4d m2, m3;
m3 = m2 = Matrix4d::Random() * 1e-20;
m2 = m2 / 4.9e-320;
VERIFY_IS_APPROX(m2.cwiseQuotient(m2), Matrix4d::Ones());
m3 /= 4.9e-320;
VERIFY_IS_APPROX(m3.cwiseQuotient(m3), Matrix4d::Ones());
}
EIGEN_DECLARE_TEST(linearstructure) {
g_called = true;
VERIFY(g_called); // avoid `unneeded-internal-declaration` warning.
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(linearStructure(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(linearStructure(Matrix2f()));
CALL_SUBTEST_3(linearStructure(Vector3d()));
CALL_SUBTEST_4(linearStructure(Matrix4d()));
CALL_SUBTEST_5(linearStructure(MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2),
internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2))));
CALL_SUBTEST_6(linearStructure(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_7(linearStructure(
MatrixXi(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_8(linearStructure(MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2),
internal::random<int>(1, EIGEN_TEST_MAX_SIZE / 2))));
CALL_SUBTEST_9(linearStructure(
ArrayXXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_10(linearStructure(
ArrayXXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
CALL_SUBTEST_11(real_complex<Matrix4cd>());
CALL_SUBTEST_11(real_complex<MatrixXcf>(10, 10));
CALL_SUBTEST_11(real_complex<ArrayXXcf>(10, 10));
}
CALL_SUBTEST_4(linearstructure_overflow<0>());
}
+36
View File
@@ -0,0 +1,36 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "sparse_solver.h"
#include <Eigen/IterativeLinearSolvers>
template <typename T>
void test_lscg_T() {
LeastSquaresConjugateGradient<SparseMatrix<T> > lscg_colmajor_diag;
LeastSquaresConjugateGradient<SparseMatrix<T>, IdentityPreconditioner> lscg_colmajor_I;
LeastSquaresConjugateGradient<SparseMatrix<T, RowMajor> > lscg_rowmajor_diag;
LeastSquaresConjugateGradient<SparseMatrix<T, RowMajor>, IdentityPreconditioner> lscg_rowmajor_I;
CALL_SUBTEST(check_sparse_square_solving(lscg_colmajor_diag));
CALL_SUBTEST(check_sparse_square_solving(lscg_colmajor_I));
CALL_SUBTEST(check_sparse_leastsquare_solving(lscg_colmajor_diag));
CALL_SUBTEST(check_sparse_leastsquare_solving(lscg_colmajor_I));
CALL_SUBTEST(check_sparse_square_solving(lscg_rowmajor_diag));
CALL_SUBTEST(check_sparse_square_solving(lscg_rowmajor_I));
CALL_SUBTEST(check_sparse_leastsquare_solving(lscg_rowmajor_diag));
CALL_SUBTEST(check_sparse_leastsquare_solving(lscg_rowmajor_I));
}
EIGEN_DECLARE_TEST(lscg) {
CALL_SUBTEST_1(test_lscg_T<double>());
CALL_SUBTEST_2(test_lscg_T<std::complex<double> >());
}
+260
View File
@@ -0,0 +1,260 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/LU>
#include "solverbase.h"
using namespace std;
template <typename MatrixType>
typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) {
return m.cwiseAbs().colwise().sum().maxCoeff();
}
template <typename MatrixType>
void lu_non_invertible() {
typedef typename MatrixType::RealScalar RealScalar;
/* this test covers the following files:
LU.h
*/
Index rows, cols, cols2;
if (MatrixType::RowsAtCompileTime == Dynamic) {
rows = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
} else {
rows = MatrixType::RowsAtCompileTime;
}
if (MatrixType::ColsAtCompileTime == Dynamic) {
cols = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
cols2 = internal::random<int>(2, EIGEN_TEST_MAX_SIZE);
} else {
cols2 = cols = MatrixType::ColsAtCompileTime;
}
enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime };
typedef typename internal::kernel_retval_base<FullPivLU<MatrixType> >::ReturnType KernelMatrixType;
typedef typename internal::image_retval_base<FullPivLU<MatrixType> >::ReturnType ImageMatrixType;
typedef Matrix<typename MatrixType::Scalar, ColsAtCompileTime, ColsAtCompileTime> CMatrixType;
typedef Matrix<typename MatrixType::Scalar, RowsAtCompileTime, RowsAtCompileTime> RMatrixType;
Index rank = internal::random<Index>(1, (std::min)(rows, cols) - 1);
// The image of the zero matrix should consist of a single (zero) column vector
VERIFY((MatrixType::Zero(rows, cols).fullPivLu().image(MatrixType::Zero(rows, cols)).cols() == 1));
// The kernel of the zero matrix is the entire space, and thus is an invertible matrix of dimensions cols.
KernelMatrixType kernel = MatrixType::Zero(rows, cols).fullPivLu().kernel();
VERIFY((kernel.fullPivLu().isInvertible()));
MatrixType m1(rows, cols), m3(rows, cols2);
CMatrixType m2(cols, cols2);
createRandomPIMatrixOfRank(rank, rows, cols, m1);
FullPivLU<MatrixType> lu;
// The special value 0.01 below works well in tests. Keep in mind that we're only computing the rank
// of singular values are either 0 or 1.
// So it's not clear at all that the epsilon should play any role there.
lu.setThreshold(RealScalar(0.01));
lu.compute(m1);
MatrixType u(rows, cols);
u = lu.matrixLU().template triangularView<Upper>();
RMatrixType l = RMatrixType::Identity(rows, rows);
l.block(0, 0, rows, (std::min)(rows, cols)).template triangularView<StrictlyLower>() =
lu.matrixLU().block(0, 0, rows, (std::min)(rows, cols));
VERIFY_IS_APPROX(lu.permutationP() * m1 * lu.permutationQ(), l * u);
KernelMatrixType m1kernel = lu.kernel();
ImageMatrixType m1image = lu.image(m1);
VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
VERIFY(rank == lu.rank());
VERIFY(cols - lu.rank() == lu.dimensionOfKernel());
VERIFY(!lu.isInjective());
VERIFY(!lu.isInvertible());
VERIFY(!lu.isSurjective());
VERIFY_IS_MUCH_SMALLER_THAN((m1 * m1kernel), m1);
VERIFY(m1image.fullPivLu().rank() == rank);
VERIFY_IS_APPROX(m1 * m1.adjoint() * m1image, m1image);
check_solverbase<CMatrixType, MatrixType>(m1, lu, rows, cols, cols2);
m2 = CMatrixType::Random(cols, cols2);
m3 = m1 * m2;
m2 = CMatrixType::Random(cols, cols2);
// test that the code, which does resize(), may be applied to an xpr
m2.block(0, 0, m2.rows(), m2.cols()) = lu.solve(m3);
VERIFY_IS_APPROX(m3, m1 * m2);
}
template <typename MatrixType>
void lu_invertible() {
/* this test covers the following files:
FullPivLU.h
*/
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
Index size = MatrixType::RowsAtCompileTime;
if (size == Dynamic) size = internal::random<Index>(1, EIGEN_TEST_MAX_SIZE);
MatrixType m1(size, size), m2(size, size), m3(size, size);
FullPivLU<MatrixType> lu;
lu.setThreshold(RealScalar(0.01));
do {
m1 = MatrixType::Random(size, size);
lu.compute(m1);
} while (!lu.isInvertible());
VERIFY_IS_APPROX(m1, lu.reconstructedMatrix());
VERIFY(0 == lu.dimensionOfKernel());
VERIFY(lu.kernel().cols() == 1); // the kernel() should consist of a single (zero) column vector
VERIFY(size == lu.rank());
VERIFY(lu.isInjective());
VERIFY(lu.isSurjective());
VERIFY(lu.isInvertible());
VERIFY(lu.image(m1).fullPivLu().isInvertible());
check_solverbase<MatrixType, MatrixType>(m1, lu, size, size, size);
MatrixType m1_inverse = lu.inverse();
m3 = MatrixType::Random(size, size);
m2 = lu.solve(m3);
VERIFY_IS_APPROX(m2, m1_inverse * m3);
RealScalar rcond = (RealScalar(1) / matrix_l1_norm(m1)) / matrix_l1_norm(m1_inverse);
const RealScalar rcond_est = lu.rcond();
// Verify that the estimated condition number is within a factor of 10 of the
// truth.
VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10);
// Regression test for Bug 302
MatrixType m4 = MatrixType::Random(size, size);
VERIFY_IS_APPROX(lu.solve(m3 * m4), lu.solve(m3) * m4);
}
template <typename MatrixType>
void lu_partial_piv(Index size = MatrixType::ColsAtCompileTime) {
/* this test covers the following files:
PartialPivLU.h
*/
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
MatrixType m1(size, size), m2(size, size), m3(size, size);
m1.setRandom();
PartialPivLU<MatrixType> plu(m1);
VERIFY_IS_APPROX(m1, plu.reconstructedMatrix());
check_solverbase<MatrixType, MatrixType>(m1, plu, size, size, size);
MatrixType m1_inverse = plu.inverse();
m3 = MatrixType::Random(size, size);
m2 = plu.solve(m3);
VERIFY_IS_APPROX(m2, m1_inverse * m3);
RealScalar rcond = (RealScalar(1) / matrix_l1_norm(m1)) / matrix_l1_norm(m1_inverse);
const RealScalar rcond_est = plu.rcond();
// Verify that the estimate is within a factor of 10 of the truth.
VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10);
}
template <typename MatrixType>
void lu_verify_assert() {
MatrixType tmp;
FullPivLU<MatrixType> lu;
VERIFY_RAISES_ASSERT(lu.matrixLU())
VERIFY_RAISES_ASSERT(lu.permutationP())
VERIFY_RAISES_ASSERT(lu.permutationQ())
VERIFY_RAISES_ASSERT(lu.kernel())
VERIFY_RAISES_ASSERT(lu.image(tmp))
VERIFY_RAISES_ASSERT(lu.solve(tmp))
VERIFY_RAISES_ASSERT(lu.transpose().solve(tmp))
VERIFY_RAISES_ASSERT(lu.adjoint().solve(tmp))
VERIFY_RAISES_ASSERT(lu.determinant())
VERIFY_RAISES_ASSERT(lu.rank())
VERIFY_RAISES_ASSERT(lu.dimensionOfKernel())
VERIFY_RAISES_ASSERT(lu.isInjective())
VERIFY_RAISES_ASSERT(lu.isSurjective())
VERIFY_RAISES_ASSERT(lu.isInvertible())
VERIFY_RAISES_ASSERT(lu.inverse())
PartialPivLU<MatrixType> plu;
VERIFY_RAISES_ASSERT(plu.matrixLU())
VERIFY_RAISES_ASSERT(plu.permutationP())
VERIFY_RAISES_ASSERT(plu.solve(tmp))
VERIFY_RAISES_ASSERT(plu.transpose().solve(tmp))
VERIFY_RAISES_ASSERT(plu.adjoint().solve(tmp))
VERIFY_RAISES_ASSERT(plu.determinant())
VERIFY_RAISES_ASSERT(plu.inverse())
}
// Rank-deficient matrix returns 0.
// https://gitlab.com/libeigen/eigen/-/issues/2889
void test_2889() {
Eigen::MatrixXd A =
Eigen::MatrixXd({{0.0000000000000000, 0.0000000000000000, 1.0000000000000000, 0.0000000000000000,
0.34149999916553497, 0.0000000000000000, 0.79877008515664061},
{0.0000000000000000, 1.0000000000000000, 0.0000000000000000, 0.29200000315904617,
0.0000000000000000, -0.37149999849498272, -0.16425902650844920},
{0.0000000000000000, 0.0000000000000000, 1.0000000000000000, 0.0000000000000000,
0.34149999916553497, 0.0000000000000000, 0.79877008515664061},
{0.0000000000000000, 1.0000000000000000, 0.0000000000000000, 0.040500000119209290,
0.0000000000000000, -0.30099999904632568, -0.081170580429391403},
{1.0000000000000000, 0.0000000000000000, 0.0000000000000000, 0.0000000000000000,
0.0000000000000000, 0.0000000000000000, -0.0000000000000000},
{0.0000000000000000, 0.70710689672598170, 0.70710666564709435, 0.027000000700354562,
0.025455838867477515, -0.025455847186317101, -0.0068972271572272821},
{1.0000000000000000, 0.0000000000000000, 0.0000000000000000, 0.0000000000000000,
0.0000000000000000, 0.0000000000000000, -0.0000000000000000}});
Eigen::FullPivLU<Eigen::MatrixXd> lu_factorization(A);
double rcond = lu_factorization.rcond();
VERIFY_IS_EQUAL(rcond, 0.0);
}
EIGEN_DECLARE_TEST(lu) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(lu_non_invertible<Matrix3f>());
CALL_SUBTEST_1(lu_invertible<Matrix3f>());
CALL_SUBTEST_1(lu_verify_assert<Matrix3f>());
CALL_SUBTEST_1(lu_partial_piv<Matrix3f>());
CALL_SUBTEST_2((lu_non_invertible<Matrix<double, 4, 6> >()));
CALL_SUBTEST_2((lu_verify_assert<Matrix<double, 4, 6> >()));
CALL_SUBTEST_2(lu_partial_piv<Matrix2d>());
CALL_SUBTEST_2(lu_partial_piv<Matrix4d>());
CALL_SUBTEST_2((lu_partial_piv<Matrix<double, 6, 6> >()));
CALL_SUBTEST_3(lu_non_invertible<MatrixXf>());
CALL_SUBTEST_3(lu_invertible<MatrixXf>());
CALL_SUBTEST_3(lu_verify_assert<MatrixXf>());
CALL_SUBTEST_4(lu_non_invertible<MatrixXd>());
CALL_SUBTEST_4(lu_invertible<MatrixXd>());
CALL_SUBTEST_4(lu_partial_piv<MatrixXd>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE)));
CALL_SUBTEST_4(lu_verify_assert<MatrixXd>());
CALL_SUBTEST_5(lu_non_invertible<MatrixXcf>());
CALL_SUBTEST_5(lu_invertible<MatrixXcf>());
CALL_SUBTEST_5(lu_verify_assert<MatrixXcf>());
CALL_SUBTEST_6(lu_non_invertible<MatrixXcd>());
CALL_SUBTEST_6(lu_invertible<MatrixXcd>());
CALL_SUBTEST_6(lu_partial_piv<MatrixXcd>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE)));
CALL_SUBTEST_6(lu_verify_assert<MatrixXcd>());
CALL_SUBTEST_7((lu_non_invertible<Matrix<float, Dynamic, 16> >()));
// Test problem size constructors
CALL_SUBTEST_8(PartialPivLU<MatrixXf>(10));
CALL_SUBTEST_8(FullPivLU<MatrixXf>(10, 20););
CALL_SUBTEST_9(test_2889());
}
}
+942
View File
@@ -0,0 +1,942 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <cstdlib>
#include <cerrno>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <limits>
#include <string>
#include <sstream>
#include <vector>
#include <typeinfo>
#include <type_traits>
#include <functional>
#ifdef EIGEN_USE_SYCL
#include <CL/sycl.hpp>
#endif
// 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
// for the macro definition of min/max and issue a warning or undefine the
// macros.
//
// Still, Windows defines min() and max() in windef.h as part of the regular
// Windows system interfaces and many other Windows APIs depend on these
// macros being available. To prevent the macro expansion of min/max and to
// make Eigen compatible with the Windows environment all function calls of
// std::min() and std::max() have to be written with parenthesis around the
// function name.
//
// All STL headers used by Eigen should be included here. Because main.h is
// included before any Eigen header and because the STL headers are guarded
// against multiple inclusions, no STL header will see our own min/max macro
// definitions.
#include <limits>
#include <algorithm>
// Disable ICC's std::complex operator specializations so we can use our own.
#define _OVERRIDE_COMPLEX_SPECIALIZATION_ 1
#include <complex>
#include <deque>
#include <queue>
#include <cassert>
#include <list>
#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)
#include <random>
#include <chrono>
#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
// 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) || 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) && !defined(EIGEN_POCKETFFT_DEFAULT)
//
// HIP header files include the following files
// <thread>
// <regex>
// <unordered_map>
// which seem to contain not-parenthesized calls to "max"/"min", triggering the following check and causing the compile
// to fail
//
// Including those header files before the following macro definition for "min" / "max", only partially resolves the
// issue This is because other HIP header files also define "isnan" / "isinf" / "isfinite" functions, which are needed
// in other headers.
//
// So instead choosing to simply disable this check for HIP
//
#define min(A, B) please_protect_your_min_with_parentheses
#define max(A, B) please_protect_your_max_with_parentheses
#define isnan(X) please_protect_your_isnan_with_parentheses
#define isinf(X) please_protect_your_isinf_with_parentheses
#define isfinite(X) please_protect_your_isfinite_with_parentheses
#endif
// test possible conflicts
struct real {};
struct imag {};
#ifdef M_PI
#undef M_PI
#endif
#define M_PI please_use_EIGEN_PI_instead_of_M_PI
#define FORBIDDEN_IDENTIFIER \
(this_identifier_is_forbidden_to_avoid_clashes) this_identifier_is_forbidden_to_avoid_clashes
// B0 is defined in POSIX header termios.h
#define B0 FORBIDDEN_IDENTIFIER
#define I FORBIDDEN_IDENTIFIER
// _res is defined by resolv.h
#define _res FORBIDDEN_IDENTIFIER
// Unit tests calling Eigen's blas library must preserve the default blocking size
// to avoid troubles.
#ifndef EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS
#define EIGEN_DEBUG_SMALL_PRODUCT_BLOCKS
#endif
// shuts down ICC's remark #593: variable "XXX" was set but never used
#define TEST_SET_BUT_UNUSED_VARIABLE(X) EIGEN_UNUSED_VARIABLE(X)
#ifdef TEST_ENABLE_TEMPORARY_TRACKING
static long int nb_temporaries;
static long int nb_temporaries_on_assert = -1;
#ifdef TEST_IGNORE_STACK_ALLOCATED_TEMPORARY
inline void on_temporary_creation(long int size, int SizeAtCompileTime) {
// ignore stack-allocated temporaries
if (SizeAtCompileTime != -1) return;
#else
inline void on_temporary_creation(long int size, int) {
#endif
// here's a great place to set a breakpoint when debugging failures in this test!
if (size != 0) nb_temporaries++;
if (nb_temporaries_on_assert > 0) assert(nb_temporaries < nb_temporaries_on_assert);
}
#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN \
{ on_temporary_creation(size, Size); }
#define VERIFY_EVALUATION_COUNT(XPR, N) \
{ \
nb_temporaries = 0; \
XPR; \
if (nb_temporaries != (N)) { \
std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
} \
VERIFY((#XPR) && nb_temporaries == (N)); \
}
#endif
#include "split_test_helper.h"
#ifdef NDEBUG
#undef NDEBUG
#endif
// On windows CE, NDEBUG is automatically defined <assert.h> if NDEBUG is not defined.
#ifndef DEBUG
#define DEBUG
#endif
#define DEFAULT_REPEAT 10
namespace Eigen {
static std::vector<std::string> g_test_stack;
// level == 0 <=> abort if test fail
// level >= 1 <=> warning message to std::cerr if test fail
static int g_test_level = 0;
static int g_repeat = 1;
static unsigned int g_seed = 0;
static bool g_has_set_repeat = false, g_has_set_seed = false;
class EigenTest {
public:
EigenTest() : m_func(0) {}
EigenTest(const char* a_name, void (*func)(void)) : m_name(a_name), m_func(func) {
get_registered_tests().push_back(this);
}
const std::string& name() const { return m_name; }
void operator()() const { m_func(); }
static const std::vector<EigenTest*>& all() { return get_registered_tests(); }
protected:
static std::vector<EigenTest*>& get_registered_tests() {
static std::vector<EigenTest*>* ms_registered_tests = new std::vector<EigenTest*>();
return *ms_registered_tests;
}
std::string m_name;
void (*m_func)(void);
};
// Declare and register a test, e.g.:
// EIGEN_DECLARE_TEST(mytest) { ... }
// will create a function:
// void test_mytest() { ... }
// that will be automatically called.
#define EIGEN_DECLARE_TEST(X) \
void EIGEN_CAT(test_, X)(); \
static EigenTest EIGEN_CAT(test_handler_, X)(EIGEN_MAKESTRING(X), &EIGEN_CAT(test_, X)); \
void EIGEN_CAT(test_, X)()
} // namespace Eigen
#define TRACK std::cerr << __FILE__ << " " << __LINE__ << std::endl
#define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, " ", "\n", "", "", "", "")
#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) && !defined(__HIP_DEVICE_COMPILE__) && \
!defined(__SYCL_DEVICE_ONLY__)
#define EIGEN_EXCEPTIONS
#endif
#ifndef EIGEN_NO_ASSERTION_CHECKING
namespace Eigen {
static const bool should_raise_an_assert = false;
// Used to avoid to raise two exceptions at a time in which
// case the exception is not properly caught.
// This may happen when a second exceptions is triggered in a destructor.
static bool no_more_assert = false;
static bool report_on_cerr_on_assert_failure = true;
struct eigen_assert_exception {
eigen_assert_exception(void) {}
~eigen_assert_exception() { Eigen::no_more_assert = false; }
};
struct eigen_static_assert_exception {
eigen_static_assert_exception(void) {}
~eigen_static_assert_exception() { Eigen::no_more_assert = false; }
};
} // namespace Eigen
// If EIGEN_DEBUG_ASSERTS is defined and if no assertion is triggered while
// one should have been, then the list of executed assertions is printed out.
//
// EIGEN_DEBUG_ASSERTS is not enabled by default as it
// significantly increases the compilation time
// and might even introduce side effects that would hide
// some memory errors.
#ifdef EIGEN_DEBUG_ASSERTS
namespace Eigen {
namespace internal {
static bool push_assert = false;
}
static std::vector<std::string> eigen_assert_list;
} // namespace Eigen
#define eigen_assert(a) \
if ((!(a)) && (!no_more_assert)) { \
if (report_on_cerr_on_assert_failure) std::cerr << #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \
Eigen::no_more_assert = true; \
EIGEN_THROW_X(Eigen::eigen_assert_exception()); \
} else if (Eigen::internal::push_assert) { \
eigen_assert_list.push_back(std::string(EIGEN_MAKESTRING(__FILE__) " (" EIGEN_MAKESTRING(__LINE__) ") : " #a)); \
}
#ifdef EIGEN_EXCEPTIONS
#define VERIFY_RAISES_ASSERT(a) \
{ \
Eigen::no_more_assert = false; \
Eigen::eigen_assert_list.clear(); \
Eigen::internal::push_assert = true; \
Eigen::report_on_cerr_on_assert_failure = false; \
try { \
a; \
std::cerr << "One of the following asserts should have been triggered:\n"; \
for (uint ai = 0; ai < eigen_assert_list.size(); ++ai) std::cerr << " " << eigen_assert_list[ai] << "\n"; \
VERIFY(Eigen::should_raise_an_assert&& #a); \
} catch (Eigen::eigen_assert_exception) { \
Eigen::internal::push_assert = false; \
VERIFY(true); \
} \
Eigen::report_on_cerr_on_assert_failure = true; \
Eigen::internal::push_assert = false; \
}
#endif // EIGEN_EXCEPTIONS
#elif !defined(__CUDACC__) && !defined(__HIPCC__) && !defined(__SYCL_DEVICE_ONLY__) // EIGEN_DEBUG_ASSERTS
#define eigen_assert(a) \
if ((!(a)) && (!no_more_assert)) { \
Eigen::no_more_assert = true; \
if (report_on_cerr_on_assert_failure) { \
eigen_plain_assert(a); \
} else { \
EIGEN_THROW_X(Eigen::eigen_assert_exception()); \
} \
}
#ifdef EIGEN_EXCEPTIONS
#define VERIFY_RAISES_ASSERT(a) \
{ \
Eigen::no_more_assert = false; \
Eigen::report_on_cerr_on_assert_failure = false; \
try { \
a; \
VERIFY(Eigen::should_raise_an_assert&& #a); \
} catch (Eigen::eigen_assert_exception&) { \
VERIFY(true); \
} \
Eigen::report_on_cerr_on_assert_failure = true; \
}
#endif // EIGEN_EXCEPTIONS
#endif // EIGEN_DEBUG_ASSERTS
#ifndef VERIFY_RAISES_ASSERT
#define VERIFY_RAISES_ASSERT(a) std::cout << "Can't VERIFY_RAISES_ASSERT( " #a " ) with exceptions disabled\n";
#endif
#if !defined(__CUDACC__) && !defined(__HIPCC__) && !defined(SYCL_DEVICE_ONLY)
#define EIGEN_USE_CUSTOM_ASSERT
#endif
#else // EIGEN_NO_ASSERTION_CHECKING
#define VERIFY_RAISES_ASSERT(a) \
{}
#endif // EIGEN_NO_ASSERTION_CHECKING
#if !defined(EIGEN_TESTING_CONSTEXPR) && !defined(EIGEN_TESTING_PLAINOBJECT_CTOR)
#define EIGEN_INTERNAL_DEBUGGING
#endif
#include <Eigen/Core>
inline void verify_impl(bool condition, const char* testname, const char* file, int line,
const char* condition_as_string) {
if (!condition) {
if (Eigen::g_test_level > 0) std::cerr << "WARNING: ";
std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" << std::endl
<< " " << condition_as_string << std::endl;
std::cerr << "Stack:\n";
const int test_stack_size = static_cast<int>(Eigen::g_test_stack.size());
for (int i = test_stack_size - 1; i >= 0; --i) std::cerr << " - " << Eigen::g_test_stack[i] << "\n";
std::cerr << "\n";
if (Eigen::g_test_level == 0) abort();
}
}
#define VERIFY(a) ::verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EIGEN_MAKESTRING(a))
#define VERIFY_GE(a, b) ::verify_impl(a >= b, g_test_stack.back().c_str(), __FILE__, __LINE__, EIGEN_MAKESTRING(a >= b))
#define VERIFY_LE(a, b) ::verify_impl(a <= b, g_test_stack.back().c_str(), __FILE__, __LINE__, EIGEN_MAKESTRING(a <= b))
#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b, true))
#define VERIFY_IS_NOT_EQUAL(a, b) VERIFY(test_is_equal(a, b, false))
#define VERIFY_IS_APPROX(a, b) VERIFY(verifyIsApprox(a, b))
#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b))
#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b))
#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b))
#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_isApproxOrLessThan(a, b))
#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_isApproxOrLessThan(a, b))
#define VERIFY_IS_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))
#define STATIC_CHECK(COND) EIGEN_STATIC_ASSERT((COND), EIGEN_INTERNAL_ERROR_PLEASE_FILE_A_BUG_REPORT)
#define CALL_SUBTEST(FUNC) \
do { \
g_test_stack.push_back(EIGEN_MAKESTRING(FUNC)); \
FUNC; \
g_test_stack.pop_back(); \
} 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>
std::enable_if_t<internal::is_same<T1, T2>::value, bool> is_same_type(const T1&, const T2&) {
return true;
}
template <typename T>
inline typename NumTraits<T>::Real test_precision() {
return NumTraits<T>::dummy_precision();
}
template <>
inline float test_precision<float>() {
return 1e-3f;
}
template <>
inline double test_precision<double>() {
return 1e-6;
}
template <>
inline long double test_precision<long double>() {
return 1e-6l;
}
template <>
inline float test_precision<std::complex<float> >() {
return test_precision<float>();
}
template <>
inline double test_precision<std::complex<double> >() {
return test_precision<double>();
}
template <>
inline long double test_precision<std::complex<long double> >() {
return test_precision<long double>();
}
#define EIGEN_TEST_SCALAR_TEST_OVERLOAD(TYPE) \
inline bool test_isApprox(TYPE a, TYPE b) { \
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) { \
return internal::isApproxOrLessThan(a, b, test_precision<TYPE>()); \
}
EIGEN_TEST_SCALAR_TEST_OVERLOAD(short)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(unsigned short)
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)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(long long)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(unsigned long long)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(float)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(double)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(half)
EIGEN_TEST_SCALAR_TEST_OVERLOAD(bfloat16)
#undef EIGEN_TEST_SCALAR_TEST_OVERLOAD
#ifndef EIGEN_TEST_NO_COMPLEX
inline bool test_isApprox(const std::complex<float>& a, const std::complex<float>& b) {
return internal::isApprox(a, b, test_precision<std::complex<float> >());
}
inline bool test_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b) {
return internal::isMuchSmallerThan(a, b, test_precision<std::complex<float> >());
}
inline bool test_isApprox(const std::complex<double>& a, const std::complex<double>& b) {
return internal::isApprox(a, b, test_precision<std::complex<double> >());
}
inline bool test_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b) {
return internal::isMuchSmallerThan(a, b, test_precision<std::complex<double> >());
}
#ifndef EIGEN_TEST_NO_LONGDOUBLE
inline bool test_isApprox(const std::complex<long double>& a, const std::complex<long double>& b) {
return internal::isApprox(a, b, test_precision<std::complex<long double> >());
}
inline bool test_isMuchSmallerThan(const std::complex<long double>& a, const std::complex<long double>& b) {
return internal::isMuchSmallerThan(a, b, test_precision<std::complex<long double> >());
}
#endif
#endif
#ifndef EIGEN_TEST_NO_LONGDOUBLE
inline bool test_isApprox(const long double& a, const long double& b) {
bool ret = internal::isApprox(a, b, test_precision<long double>());
if (!ret)
std::cerr << std::endl << " actual = " << a << std::endl << " expected = " << b << std::endl << std::endl;
return ret;
}
inline bool test_isMuchSmallerThan(const long double& a, const long double& b) {
return internal::isMuchSmallerThan(a, b, test_precision<long double>());
}
inline bool test_isApproxOrLessThan(const long double& a, const long double& b) {
return internal::isApproxOrLessThan(a, b, test_precision<long double>());
}
#endif // EIGEN_TEST_NO_LONGDOUBLE
// test_relative_error returns the relative difference between a and b as a real scalar as used in isApprox.
template <typename T1, typename T2>
typename NumTraits<typename T1::RealScalar>::NonInteger test_relative_error(const EigenBase<T1>& a,
const EigenBase<T2>& b) {
using std::sqrt;
typedef typename NumTraits<typename T1::RealScalar>::NonInteger RealScalar;
typename internal::nested_eval<T1, 2>::type ea(a.derived());
typename internal::nested_eval<T2, 2>::type eb(b.derived());
return sqrt(RealScalar((ea.matrix() - eb.matrix()).cwiseAbs2().sum()) /
RealScalar((std::min)(eb.cwiseAbs2().sum(), ea.cwiseAbs2().sum())));
}
template <typename T1, typename T2>
typename T1::RealScalar test_relative_error(const T1& a, const T2& b, const typename T1::Coefficients* = 0) {
return test_relative_error(a.coeffs(), b.coeffs());
}
template <typename T1, typename T2>
typename T1::Scalar test_relative_error(const T1& a, const T2& b, const typename T1::MatrixType* = 0) {
return test_relative_error(a.matrix(), b.matrix());
}
template <typename S, int D>
S test_relative_error(const Translation<S, D>& a, const Translation<S, D>& b) {
return test_relative_error(a.vector(), b.vector());
}
template <typename S, int D, int O>
S test_relative_error(const ParametrizedLine<S, D, O>& a, const ParametrizedLine<S, D, O>& b) {
return (std::max)(test_relative_error(a.origin(), b.origin()), test_relative_error(a.origin(), b.origin()));
}
template <typename S, int D>
S test_relative_error(const AlignedBox<S, D>& a, const AlignedBox<S, D>& b) {
return (std::max)(test_relative_error((a.min)(), (b.min)()), test_relative_error((a.max)(), (b.max)()));
}
template <typename Derived>
class SparseMatrixBase;
template <typename T1, typename T2>
typename T1::RealScalar test_relative_error(const MatrixBase<T1>& a, const SparseMatrixBase<T2>& b) {
return test_relative_error(a, b.toDense());
}
template <typename Derived>
class SparseMatrixBase;
template <typename T1, typename T2>
typename T1::RealScalar test_relative_error(const SparseMatrixBase<T1>& a, const MatrixBase<T2>& b) {
return test_relative_error(a.toDense(), b);
}
template <typename Derived>
class SparseMatrixBase;
template <typename T1, typename T2>
typename T1::RealScalar test_relative_error(const SparseMatrixBase<T1>& a, const SparseMatrixBase<T2>& b) {
return test_relative_error(a.toDense(), b.toDense());
}
template <typename T1, typename T2>
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))));
}
template <typename T>
T test_relative_error(const Rotation2D<T>& a, const Rotation2D<T>& b) {
return test_relative_error(a.angle(), b.angle());
}
template <typename T>
T test_relative_error(const AngleAxis<T>& a, const AngleAxis<T>& b) {
return (std::max)(test_relative_error(a.angle(), b.angle()), test_relative_error(a.axis(), b.axis()));
}
template <typename Type1, typename Type2>
inline bool test_isApprox(const Type1& a, const Type2& b, typename Type1::Scalar* = 0) // Enabled for Eigen's type only
{
return a.isApprox(b, test_precision<typename Type1::Scalar>());
}
// get_test_precision is a small wrapper to test_precision allowing to return the scalar precision for either scalars or
// expressions
template <typename T>
typename NumTraits<typename T::Scalar>::Real get_test_precision(const T&, const typename T::Scalar* = 0) {
return test_precision<typename NumTraits<typename T::Scalar>::Real>();
}
template <typename T>
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>();
}
// verifyIsApprox is a wrapper to test_isApprox that outputs the relative difference magnitude if the test fails.
template <typename Type1, typename Type2>
inline bool verifyIsApprox(const Type1& a, const Type2& b) {
bool ret = test_isApprox(a, b);
if (!ret) {
std::cerr << "Difference too large wrt tolerance " << get_test_precision(a)
<< ", relative error is: " << test_relative_error(a, b) << std::endl;
}
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
// Therefore, if for some reason a and b are very small compared to ref,
// we won't issue a false negative.
// This test could be: abs(a-b) <= eps * ref
// However, it seems that simply comparing a+ref and b+ref is more sensitive to true error.
template <typename Scalar, typename ScalarRef>
inline bool test_isApproxWithRef(const Scalar& a, const Scalar& b, const ScalarRef& ref) {
return test_isApprox(a + ref, b + ref);
}
template <typename Derived1, typename Derived2>
inline bool test_isMuchSmallerThan(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2) {
return m1.isMuchSmallerThan(m2, test_precision<typename internal::traits<Derived1>::Scalar>());
}
template <typename Derived>
inline bool test_isMuchSmallerThan(const MatrixBase<Derived>& m,
const typename NumTraits<typename internal::traits<Derived>::Scalar>::Real& s) {
return m.isMuchSmallerThan(s, test_precision<typename internal::traits<Derived>::Scalar>());
}
template <typename Derived>
inline bool test_isUnitary(const MatrixBase<Derived>& m) {
return m.isUnitary(test_precision<typename internal::traits<Derived>::Scalar>());
}
// 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 (numext::equal_strict(actual, expected) == expect_equal) return true;
// false:
std::cerr << "\n actual = " << actual << "\n expected " << (expect_equal ? "= " : "!=") << expected << "\n\n";
return false;
}
/**
* 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();
}
} // end namespace Eigen
#include "random_matrix_helper.h"
template <typename T>
struct GetDifferentType;
template <>
struct GetDifferentType<float> {
typedef double type;
};
template <>
struct GetDifferentType<double> {
typedef float type;
};
template <typename T>
struct GetDifferentType<std::complex<T> > {
typedef std::complex<typename GetDifferentType<T>::type> type;
};
template <typename T>
std::string type_name(T) {
return typeid(T).name();
}
template <>
std::string type_name<float>(float) {
return "float";
}
template <>
std::string type_name<double>(double) {
return "double";
}
template <>
std::string type_name<long double>(long double) {
return "long double";
}
template <>
std::string type_name<Eigen::half>(Eigen::half) {
return "half";
}
template <>
std::string type_name<Eigen::bfloat16>(Eigen::bfloat16) {
return "bfloat16";
}
template <>
std::string type_name<int8_t>(int8_t) {
return "int8_t";
}
template <>
std::string type_name<int16_t>(int16_t) {
return "int16_t";
}
template <>
std::string type_name<int32_t>(int32_t) {
return "int32_t";
}
template <>
std::string type_name<int64_t>(int64_t) {
return "int64_t";
}
template <>
std::string type_name<uint8_t>(uint8_t) {
return "uint8_t";
}
template <>
std::string type_name<uint16_t>(uint16_t) {
return "uint16_t";
}
template <>
std::string type_name<uint32_t>(uint32_t) {
return "uint32_t";
}
template <>
std::string type_name<uint64_t>(uint64_t) {
return "uint64_t";
}
template <>
std::string type_name<std::complex<float> >(std::complex<float>) {
return "complex<float>";
}
template <>
std::string type_name<std::complex<double> >(std::complex<double>) {
return "complex<double>";
}
template <>
std::string type_name<std::complex<long double> >(std::complex<long double>) {
return "complex<long double>";
}
template <>
std::string type_name<std::complex<int> >(std::complex<int>) {
return "complex<int>";
}
template <typename T>
std::string type_name() {
return type_name(T());
}
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;
g_repeat = int(strtoul(str, 0, 10));
if (errno || g_repeat <= 0) {
std::cout << "Invalid repeat value " << str << std::endl;
exit(EXIT_FAILURE);
}
g_has_set_repeat = true;
}
/**
* Set seed for randomized unit tests from input string.
*
* @param str input string
*/
inline void set_seed_from_string(const char* str) {
errno = 0;
g_seed = int(strtoul(str, 0, 10));
if (errno || g_seed == 0) {
std::cout << "Invalid seed value " << str << std::endl;
exit(EXIT_FAILURE);
}
g_has_set_seed = true;
}
int main(int argc, char* argv[]) {
g_has_set_repeat = false;
g_has_set_seed = false;
bool need_help = false;
for (int i = 1; i < argc; i++) {
if (argv[i][0] == 'r') {
if (g_has_set_repeat) {
std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
return 1;
}
set_repeat_from_string(argv[i] + 1);
} else if (argv[i][0] == 's') {
if (g_has_set_seed) {
std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
return 1;
}
set_seed_from_string(argv[i] + 1);
} else {
need_help = true;
}
}
if (need_help) {
std::cout << "This test application takes the following optional arguments:" << std::endl;
std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl;
std::cout << std::endl;
std::cout << "If defined, the environment variables EIGEN_REPEAT and EIGEN_SEED" << std::endl;
std::cout << "will be used as default values for these parameters." << std::endl;
return 1;
}
char* env_EIGEN_REPEAT = getenv("EIGEN_REPEAT");
if (!g_has_set_repeat && env_EIGEN_REPEAT) set_repeat_from_string(env_EIGEN_REPEAT);
char* env_EIGEN_SEED = getenv("EIGEN_SEED");
if (!g_has_set_seed && env_EIGEN_SEED) set_seed_from_string(env_EIGEN_SEED);
if (!g_has_set_seed) g_seed = (unsigned int)time(NULL);
if (!g_has_set_repeat) g_repeat = DEFAULT_REPEAT;
std::cout << "Initializing random number generator with seed " << g_seed << std::endl;
std::stringstream ss;
ss << "Seed: " << g_seed;
g_test_stack.push_back(ss.str());
srand(g_seed);
std::cout << "Repeating each test " << g_repeat << " times" << std::endl;
VERIFY(EigenTest::all().size() > 0);
for (std::size_t i = 0; i < EigenTest::all().size(); ++i) {
const EigenTest& current_test = *EigenTest::all()[i];
Eigen::g_test_stack.push_back(current_test.name());
current_test();
Eigen::g_test_stack.pop_back();
}
return 0;
}
// These warning are disabled here such that they are still ON when parsing Eigen's header files.
#if defined __INTEL_COMPILER
// remark #383: value copied to temporary, reference to temporary used
// -> this warning is raised even for legal usage as: g_test_stack.push_back("foo"); where g_test_stack is a
// std::vector<std::string>
// remark #1418: external function definition with no prior declaration
// -> this warning is raised for all our test functions. Declaring them static would fix the issue.
// warning #279: controlling expression is constant
// remark #1572: floating-point equality and inequality comparisons are unreliable
#pragma warning disable 279 383 1418 1572
#endif
#ifdef _MSC_VER
// 4503 - decorated name length exceeded, name was truncated
#pragma warning(disable : 4503)
#endif
#include "gpu_test_helper.h"
#ifndef EIGEN_TEST_MAX_SIZE
#define EIGEN_TEST_MAX_SIZE 320
#endif
+200
View File
@@ -0,0 +1,200 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#define EIGEN_TESTMAP_MAX_SIZE 256
template <typename VectorType>
void map_class_vector(const VectorType& m) {
typedef typename VectorType::Scalar Scalar;
Index size = m.size();
Scalar* array1 = internal::aligned_new<Scalar>(size);
Scalar* array2 = internal::aligned_new<Scalar>(size);
Scalar* array3 = new Scalar[size + 1];
// In case of no alignment, avoid division by zero.
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
Scalar* array3unaligned = (std::uintptr_t(array3) % alignment) == 0 ? array3 + 1 : array3;
Scalar array4[EIGEN_TESTMAP_MAX_SIZE];
Map<VectorType, AlignedMax>(array1, size) = VectorType::Random(size);
Map<VectorType, AlignedMax>(array2, size) = Map<VectorType, AlignedMax>(array1, size);
Map<VectorType>(array3unaligned, size) = Map<VectorType>(array1, size);
Map<VectorType>(array4, size) = Map<VectorType, AlignedMax>(array1, size);
VectorType ma1 = Map<VectorType, AlignedMax>(array1, size);
VectorType ma2 = Map<VectorType, AlignedMax>(array2, size);
VectorType ma3 = Map<VectorType>(array3unaligned, size);
VectorType ma4 = Map<VectorType>(array4, size);
VERIFY_IS_EQUAL(ma1, ma2);
VERIFY_IS_EQUAL(ma1, ma3);
VERIFY_IS_EQUAL(ma1, ma4);
#ifdef EIGEN_VECTORIZE
if (internal::packet_traits<Scalar>::Vectorizable && size >= AlignedMax)
VERIFY_RAISES_ASSERT((Map<VectorType, AlignedMax>(array3unaligned, size)))
#endif
internal::aligned_delete(array1, size);
internal::aligned_delete(array2, size);
delete[] array3;
}
template <typename MatrixType>
void map_class_matrix(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
Index rows = m.rows(), cols = m.cols(), size = rows * cols;
Scalar s1 = internal::random<Scalar>();
// array1 and array2 -> aligned heap allocation
Scalar* array1 = internal::aligned_new<Scalar>(size);
for (int i = 0; i < size; i++) array1[i] = Scalar(1);
Scalar* array2 = internal::aligned_new<Scalar>(size);
for (int i = 0; i < size; i++) array2[i] = Scalar(1);
// array3unaligned -> unaligned pointer to heap
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);
// In case of no alignment, avoid division by zero.
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
Scalar* array3unaligned = (std::uintptr_t(array3) % alignment) == 0 ? array3 + 1 : array3;
Scalar array4[256];
if (size <= 256)
for (int i = 0; i < size; i++) array4[i] = Scalar(1);
Map<MatrixType> map1(array1, rows, cols);
Map<MatrixType, AlignedMax> map2(array2, rows, cols);
Map<MatrixType> map3(array3unaligned, rows, cols);
Map<MatrixType> map4(array4, rows, cols);
VERIFY_IS_EQUAL(map1, MatrixType::Ones(rows, cols));
map1.setConstant(s1);
VERIFY_IS_EQUAL(map1, MatrixType::Constant(rows, cols, s1));
map1.setZero();
VERIFY_IS_EQUAL(map1, MatrixType::Zero(rows, cols));
VERIFY_IS_EQUAL(map2, MatrixType::Ones(rows, cols));
map2.setConstant(s1);
VERIFY_IS_EQUAL(map2, MatrixType::Constant(rows, cols, s1));
map2.setZero();
VERIFY_IS_EQUAL(map2, MatrixType::Zero(rows, cols));
VERIFY_IS_EQUAL(map3, MatrixType::Ones(rows, cols));
map3.setConstant(s1);
VERIFY_IS_EQUAL(map3, MatrixType::Constant(rows, cols, s1));
map3.setZero();
VERIFY_IS_EQUAL(map3, MatrixType::Zero(rows, cols));
map1 = MatrixType::Random(rows, cols);
map2 = map1;
map3 = map1;
MatrixType ma1 = map1;
MatrixType ma2 = map2;
MatrixType ma3 = map3;
VERIFY_IS_EQUAL(map1, map2);
VERIFY_IS_EQUAL(map1, map3);
VERIFY_IS_EQUAL(ma1, ma2);
VERIFY_IS_EQUAL(ma1, ma3);
VERIFY_IS_EQUAL(ma1, map3);
VERIFY_IS_APPROX(s1 * map1, s1 * map2);
VERIFY_IS_APPROX(s1 * ma1, s1 * ma2);
VERIFY_IS_EQUAL(s1 * ma1, s1 * ma3);
VERIFY_IS_APPROX(s1 * map1, s1 * map3);
map2 *= s1;
map3 *= s1;
VERIFY_IS_APPROX(s1 * map1, map2);
VERIFY_IS_APPROX(s1 * map1, map3);
if (size <= 256) {
VERIFY_IS_EQUAL(map4, MatrixType::Ones(rows, cols));
map4 = map1;
MatrixType ma4 = map4;
VERIFY_IS_EQUAL(map1, map4);
VERIFY_IS_EQUAL(ma1, map4);
VERIFY_IS_EQUAL(ma1, ma4);
VERIFY_IS_APPROX(s1 * map1, s1 * map4);
map4 *= s1;
VERIFY_IS_APPROX(s1 * map1, map4);
}
internal::aligned_delete(array1, size);
internal::aligned_delete(array2, size);
delete[] array3;
}
template <typename VectorType>
void map_static_methods(const VectorType& m) {
typedef typename VectorType::Scalar Scalar;
Index size = m.size();
Scalar* array1 = internal::aligned_new<Scalar>(size);
Scalar* array2 = internal::aligned_new<Scalar>(size);
Scalar* array3 = new Scalar[size + 1];
// In case of no alignment, avoid division by zero.
constexpr int alignment = (std::max<int>)(EIGEN_MAX_ALIGN_BYTES, 1);
Scalar* array3unaligned = (std::uintptr_t(array3) % alignment) == 0 ? array3 + 1 : array3;
VectorType::MapAligned(array1, size) = VectorType::Random(size);
VectorType::Map(array2, size) = VectorType::Map(array1, size);
VectorType::Map(array3unaligned, size) = VectorType::Map(array1, size);
VectorType ma1 = VectorType::Map(array1, size);
VectorType ma2 = VectorType::MapAligned(array2, size);
VectorType ma3 = VectorType::Map(array3unaligned, size);
VERIFY_IS_EQUAL(ma1, ma2);
VERIFY_IS_EQUAL(ma1, ma3);
internal::aligned_delete(array1, size);
internal::aligned_delete(array2, size);
delete[] array3;
}
template <typename PlainObjectType>
void check_const_correctness(const PlainObjectType&) {
// there's a lot that we can't test here while still having this test compile!
// the only possible approach would be to run a script trying to compile stuff and checking that it fails.
// CMake can help with that.
// verify that map-to-const don't have LvalueBit
typedef 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));
VERIFY(!(Map<ConstPlainObjectType, AlignedMax>::Flags & LvalueBit));
}
EIGEN_DECLARE_TEST(mapped_matrix) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(map_class_vector(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(check_const_correctness(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(map_class_vector(Vector4d()));
CALL_SUBTEST_2(map_class_vector(VectorXd(13)));
CALL_SUBTEST_2(check_const_correctness(Matrix4d()));
CALL_SUBTEST_3(map_class_vector(RowVector4f()));
CALL_SUBTEST_4(map_class_vector(VectorXcf(8)));
CALL_SUBTEST_5(map_class_vector(VectorXi(12)));
CALL_SUBTEST_5(check_const_correctness(VectorXi(12)));
CALL_SUBTEST_1(map_class_matrix(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(map_class_matrix(Matrix4d()));
CALL_SUBTEST_11(map_class_matrix(Matrix<float, 3, 5>()));
CALL_SUBTEST_4(map_class_matrix(MatrixXcf(internal::random<int>(1, 10), internal::random<int>(1, 10))));
CALL_SUBTEST_5(map_class_matrix(MatrixXi(internal::random<int>(1, 10), internal::random<int>(1, 10))));
CALL_SUBTEST_6(map_static_methods(Matrix<double, 1, 1>()));
CALL_SUBTEST_7(map_static_methods(Vector3f()));
CALL_SUBTEST_8(map_static_methods(RowVector3d()));
CALL_SUBTEST_9(map_static_methods(VectorXcd(8)));
CALL_SUBTEST_10(map_static_methods(VectorXf(12)));
}
}
+159
View File
@@ -0,0 +1,159 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename PlainObjectType, bool IsDynamicSize = PlainObjectType::SizeAtCompileTime == Dynamic,
bool IsVector = PlainObjectType::IsVectorAtCompileTime>
struct mapstaticmethods_impl {};
template <typename PlainObjectType, bool IsVector>
struct mapstaticmethods_impl<PlainObjectType, false, IsVector> {
static void run(const PlainObjectType& m, float* ptr, const float* const_ptr) {
mapstaticmethods_impl<PlainObjectType, true, IsVector>::run(m, ptr, const_ptr);
int i = internal::random<int>(2, 5), j = internal::random<int>(2, 5);
PlainObjectType::Map(ptr).setZero();
PlainObjectType::MapAligned(ptr).setZero();
PlainObjectType::Map(const_ptr).sum();
PlainObjectType::MapAligned(const_ptr).sum();
PlainObjectType::Map(ptr, InnerStride<>(i)).setZero();
PlainObjectType::MapAligned(ptr, InnerStride<>(i)).setZero();
PlainObjectType::Map(const_ptr, InnerStride<>(i)).sum();
PlainObjectType::MapAligned(const_ptr, InnerStride<>(i)).sum();
PlainObjectType::Map(ptr, InnerStride<2>()).setZero();
PlainObjectType::MapAligned(ptr, InnerStride<3>()).setZero();
PlainObjectType::Map(const_ptr, InnerStride<4>()).sum();
PlainObjectType::MapAligned(const_ptr, InnerStride<5>()).sum();
PlainObjectType::Map(ptr, OuterStride<>(i)).setZero();
PlainObjectType::MapAligned(ptr, OuterStride<>(i)).setZero();
PlainObjectType::Map(const_ptr, OuterStride<>(i)).sum();
PlainObjectType::MapAligned(const_ptr, OuterStride<>(i)).sum();
PlainObjectType::Map(ptr, OuterStride<2>()).setZero();
PlainObjectType::MapAligned(ptr, OuterStride<3>()).setZero();
PlainObjectType::Map(const_ptr, OuterStride<4>()).sum();
PlainObjectType::MapAligned(const_ptr, OuterStride<5>()).sum();
PlainObjectType::Map(ptr, Stride<Dynamic, Dynamic>(i, j)).setZero();
PlainObjectType::MapAligned(ptr, Stride<2, Dynamic>(2, i)).setZero();
PlainObjectType::Map(const_ptr, Stride<Dynamic, 3>(i, 3)).sum();
PlainObjectType::MapAligned(const_ptr, Stride<Dynamic, Dynamic>(i, j)).sum();
PlainObjectType::Map(ptr, Stride<2, 3>()).setZero();
PlainObjectType::MapAligned(ptr, Stride<3, 4>()).setZero();
PlainObjectType::Map(const_ptr, Stride<2, 4>()).sum();
PlainObjectType::MapAligned(const_ptr, Stride<5, 3>()).sum();
}
};
template <typename PlainObjectType>
struct mapstaticmethods_impl<PlainObjectType, true, false> {
static void run(const PlainObjectType& m, float* ptr, const float* const_ptr) {
Index rows = m.rows(), cols = m.cols();
int i = internal::random<int>(2, 5), j = internal::random<int>(2, 5);
PlainObjectType::Map(ptr, rows, cols).setZero();
PlainObjectType::MapAligned(ptr, rows, cols).setZero();
PlainObjectType::Map(const_ptr, rows, cols).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols).sum();
PlainObjectType::Map(ptr, rows, cols, InnerStride<>(i)).setZero();
PlainObjectType::MapAligned(ptr, rows, cols, InnerStride<>(i)).setZero();
PlainObjectType::Map(const_ptr, rows, cols, InnerStride<>(i)).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols, InnerStride<>(i)).sum();
PlainObjectType::Map(ptr, rows, cols, InnerStride<2>()).setZero();
PlainObjectType::MapAligned(ptr, rows, cols, InnerStride<3>()).setZero();
PlainObjectType::Map(const_ptr, rows, cols, InnerStride<4>()).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols, InnerStride<5>()).sum();
PlainObjectType::Map(ptr, rows, cols, OuterStride<>(i)).setZero();
PlainObjectType::MapAligned(ptr, rows, cols, OuterStride<>(i)).setZero();
PlainObjectType::Map(const_ptr, rows, cols, OuterStride<>(i)).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols, OuterStride<>(i)).sum();
PlainObjectType::Map(ptr, rows, cols, OuterStride<2>()).setZero();
PlainObjectType::MapAligned(ptr, rows, cols, OuterStride<3>()).setZero();
PlainObjectType::Map(const_ptr, rows, cols, OuterStride<4>()).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols, OuterStride<5>()).sum();
PlainObjectType::Map(ptr, rows, cols, Stride<Dynamic, Dynamic>(i, j)).setZero();
PlainObjectType::MapAligned(ptr, rows, cols, Stride<2, Dynamic>(2, i)).setZero();
PlainObjectType::Map(const_ptr, rows, cols, Stride<Dynamic, 3>(i, 3)).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols, Stride<Dynamic, Dynamic>(i, j)).sum();
PlainObjectType::Map(ptr, rows, cols, Stride<2, 3>()).setZero();
PlainObjectType::MapAligned(ptr, rows, cols, Stride<3, 4>()).setZero();
PlainObjectType::Map(const_ptr, rows, cols, Stride<2, 4>()).sum();
PlainObjectType::MapAligned(const_ptr, rows, cols, Stride<5, 3>()).sum();
}
};
template <typename PlainObjectType>
struct mapstaticmethods_impl<PlainObjectType, true, true> {
static void run(const PlainObjectType& v, float* ptr, const float* const_ptr) {
Index size = v.size();
int i = internal::random<int>(2, 5);
PlainObjectType::Map(ptr, size).setZero();
PlainObjectType::MapAligned(ptr, size).setZero();
PlainObjectType::Map(const_ptr, size).sum();
PlainObjectType::MapAligned(const_ptr, size).sum();
PlainObjectType::Map(ptr, size, InnerStride<>(i)).setZero();
PlainObjectType::MapAligned(ptr, size, InnerStride<>(i)).setZero();
PlainObjectType::Map(const_ptr, size, InnerStride<>(i)).sum();
PlainObjectType::MapAligned(const_ptr, size, InnerStride<>(i)).sum();
PlainObjectType::Map(ptr, size, InnerStride<2>()).setZero();
PlainObjectType::MapAligned(ptr, size, InnerStride<3>()).setZero();
PlainObjectType::Map(const_ptr, size, InnerStride<4>()).sum();
PlainObjectType::MapAligned(const_ptr, size, InnerStride<5>()).sum();
}
};
template <typename PlainObjectType>
void mapstaticmethods(const PlainObjectType& m, float* ptr, const float* const_ptr) {
mapstaticmethods_impl<PlainObjectType>::run(m, ptr, const_ptr);
VERIFY(true); // just to avoid 'unused function' warning
}
EIGEN_DECLARE_TEST(mapstaticmethods) {
float* ptr = internal::aligned_new<float>(1000);
for (int i = 0; i < 1000; i++) ptr[i] = float(i);
const float* const_ptr = ptr;
CALL_SUBTEST_1((mapstaticmethods(Matrix<float, 1, 1>(), ptr, const_ptr)));
CALL_SUBTEST_1((mapstaticmethods(Vector2f(), ptr, const_ptr)));
CALL_SUBTEST_2((mapstaticmethods(Vector3f(), ptr, const_ptr)));
CALL_SUBTEST_2((mapstaticmethods(Matrix2f(), ptr, const_ptr)));
CALL_SUBTEST_3((mapstaticmethods(Matrix4f(), ptr, const_ptr)));
CALL_SUBTEST_3((mapstaticmethods(Array4f(), ptr, const_ptr)));
CALL_SUBTEST_4((mapstaticmethods(Array3f(), ptr, const_ptr)));
CALL_SUBTEST_4((mapstaticmethods(Array33f(), ptr, const_ptr)));
CALL_SUBTEST_5((mapstaticmethods(Array44f(), ptr, const_ptr)));
CALL_SUBTEST_5((mapstaticmethods(VectorXf(1), ptr, const_ptr)));
CALL_SUBTEST_5((mapstaticmethods(VectorXf(8), ptr, const_ptr)));
CALL_SUBTEST_6((mapstaticmethods(MatrixXf(1, 1), ptr, const_ptr)));
CALL_SUBTEST_6((mapstaticmethods(MatrixXf(5, 7), ptr, const_ptr)));
CALL_SUBTEST_7((mapstaticmethods(ArrayXf(1), ptr, const_ptr)));
CALL_SUBTEST_7((mapstaticmethods(ArrayXf(5), ptr, const_ptr)));
CALL_SUBTEST_8((mapstaticmethods(ArrayXXf(1, 1), ptr, const_ptr)));
CALL_SUBTEST_8((mapstaticmethods(ArrayXXf(8, 6), ptr, const_ptr)));
internal::aligned_delete(ptr, 1000);
}
+275
View File
@@ -0,0 +1,275 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <int Alignment, typename VectorType>
void map_class_vector(const VectorType& m) {
typedef typename VectorType::Scalar Scalar;
Index size = m.size();
VectorType v = VectorType::Random(size);
Index arraysize = 3 * size;
Scalar* a_array = internal::aligned_new<Scalar>(arraysize + 1);
Scalar* array = a_array;
if (Alignment != Aligned)
array = (Scalar*)(std::intptr_t(a_array) + (internal::packet_traits<Scalar>::AlignedOnScalar
? sizeof(Scalar)
: sizeof(typename NumTraits<Scalar>::Real)));
{
Map<VectorType, Alignment, InnerStride<3> > map(array, size);
map = v;
for (int i = 0; i < size; ++i) {
VERIFY_IS_EQUAL(array[3 * i], v[i]);
VERIFY_IS_EQUAL(map[i], v[i]);
}
}
{
Map<VectorType, Unaligned, InnerStride<Dynamic> > map(array, size, InnerStride<Dynamic>(2));
map = v;
for (int i = 0; i < size; ++i) {
VERIFY_IS_EQUAL(array[2 * i], v[i]);
VERIFY_IS_EQUAL(map[i], v[i]);
}
}
internal::aligned_delete(a_array, arraysize + 1);
}
template <int Alignment, typename MatrixType>
void map_class_matrix(const MatrixType& _m) {
typedef typename MatrixType::Scalar Scalar;
Index rows = _m.rows(), cols = _m.cols();
MatrixType m = MatrixType::Random(rows, cols);
Scalar s1 = internal::random<Scalar>();
Index arraysize = 4 * (rows + 4) * (cols + 4);
Scalar* a_array1 = internal::aligned_new<Scalar>(arraysize + 1);
Scalar* array1 = a_array1;
if (Alignment != Aligned)
array1 = (Scalar*)(std::intptr_t(a_array1) + (internal::packet_traits<Scalar>::AlignedOnScalar
? sizeof(Scalar)
: sizeof(typename NumTraits<Scalar>::Real)));
Scalar a_array2[256];
Scalar* array2 = a_array2;
if (Alignment != Aligned) {
array2 = (Scalar*)(std::intptr_t(a_array2) + (internal::packet_traits<Scalar>::AlignedOnScalar
? sizeof(Scalar)
: sizeof(typename NumTraits<Scalar>::Real)));
} 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*)(((std::uintptr_t(a_array2) + alignment - 1) / alignment) * alignment);
}
Index maxsize2 = a_array2 - array2 + 256;
// test no inner stride and some dynamic outer stride
for (int k = 0; k < 2; ++k) {
if (k == 1 && (m.innerSize() + 1) * m.outerSize() > maxsize2) break;
Scalar* array = (k == 0 ? array1 : array2);
Map<MatrixType, Alignment, OuterStride<Dynamic> > map(array, rows, cols, OuterStride<Dynamic>(m.innerSize() + 1));
map = m;
VERIFY(map.outerStride() == map.innerSize() + 1);
for (int i = 0; i < m.outerSize(); ++i)
for (int j = 0; j < m.innerSize(); ++j) {
VERIFY_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;
VERIFY_IS_APPROX(map, s1 * m);
map.setZero();
VERIFY_IS_CWISE_EQUAL(map, MatrixType::Zero(rows, cols));
}
// test no inner stride and an outer stride of +4. This is quite important as for fixed-size matrices,
// this allows to hit the special case where it's vectorizable.
for (int k = 0; k < 2; ++k) {
if (k == 1 && (m.innerSize() + 4) * m.outerSize() > maxsize2) break;
Scalar* array = (k == 0 ? array1 : array2);
enum {
InnerSize = MatrixType::InnerSizeAtCompileTime,
OuterStrideAtCompileTime = InnerSize == Dynamic ? Dynamic : InnerSize + 4
};
Map<MatrixType, Alignment, OuterStride<OuterStrideAtCompileTime> > map(
array, rows, cols, OuterStride<OuterStrideAtCompileTime>(m.innerSize() + 4));
map = m;
VERIFY(map.outerStride() == map.innerSize() + 4);
for (int i = 0; i < m.outerSize(); ++i)
for (int j = 0; j < m.innerSize(); ++j) {
VERIFY_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;
VERIFY_IS_APPROX(map, s1 * m);
map.setZero();
VERIFY_IS_CWISE_EQUAL(map, MatrixType::Zero(rows, cols));
}
// test both inner stride and outer stride
for (int k = 0; k < 2; ++k) {
if (k == 1 && (2 * m.innerSize() + 1) * (m.outerSize() * 2) > maxsize2) break;
Scalar* array = (k == 0 ? array1 : array2);
Map<MatrixType, Alignment, Stride<Dynamic, Dynamic> > map(array, rows, cols,
Stride<Dynamic, Dynamic>(2 * m.innerSize() + 1, 2));
map = m;
VERIFY(map.outerStride() == 2 * map.innerSize() + 1);
VERIFY(map.innerStride() == 2);
for (int i = 0; i < m.outerSize(); ++i)
for (int j = 0; j < m.innerSize(); ++j) {
VERIFY_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;
VERIFY_IS_APPROX(map, s1 * m);
map.setZero();
VERIFY_IS_CWISE_EQUAL(map, MatrixType::Zero(rows, cols));
}
// test inner stride and no outer stride
for (int k = 0; k < 2; ++k) {
if (k == 1 && (m.innerSize() * 2) * m.outerSize() > maxsize2) break;
Scalar* array = (k == 0 ? array1 : array2);
Map<MatrixType, Alignment, InnerStride<Dynamic> > map(array, rows, cols, InnerStride<Dynamic>(2));
map = m;
VERIFY(map.outerStride() == map.innerSize() * 2);
for (int i = 0; i < m.outerSize(); ++i)
for (int j = 0; j < m.innerSize(); ++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;
VERIFY_IS_APPROX(map, s1 * m);
map.setZero();
VERIFY_IS_CWISE_EQUAL(map, MatrixType::Zero(rows, cols));
}
// test negative strides
{
Matrix<Scalar, Dynamic, 1>::Map(a_array1, arraysize + 1).setRandom();
Index outerstride = m.innerSize() + 4;
Scalar* array = array1;
{
Map<MatrixType, Alignment, OuterStride<> > map1(array, rows, cols, OuterStride<>(outerstride));
Map<MatrixType, Unaligned, OuterStride<> > map2(array + (m.outerSize() - 1) * outerstride, rows, cols,
OuterStride<>(-outerstride));
if (MatrixType::IsRowMajor)
VERIFY_IS_APPROX(map1.colwise().reverse(), map2);
else
VERIFY_IS_APPROX(map1.rowwise().reverse(), map2);
}
{
Map<MatrixType, Alignment, OuterStride<> > map1(array, rows, cols, OuterStride<>(outerstride));
Map<MatrixType, Unaligned, Stride<Dynamic, Dynamic> > map2(
array + (m.outerSize() - 1) * outerstride + m.innerSize() - 1, rows, cols,
Stride<Dynamic, Dynamic>(-outerstride, -1));
VERIFY_IS_APPROX(map1.reverse(), map2);
}
{
Map<MatrixType, Alignment, OuterStride<> > map1(array, rows, cols, OuterStride<>(outerstride));
Map<MatrixType, Unaligned, Stride<Dynamic, -1> > map2(
array + (m.outerSize() - 1) * outerstride + m.innerSize() - 1, rows, cols,
Stride<Dynamic, -1>(-outerstride, -1));
VERIFY_IS_APPROX(map1.reverse(), map2);
}
}
internal::aligned_delete(a_array1, arraysize + 1);
}
// Additional tests for inner-stride but no outer-stride
template <int>
void bug1453() {
const int data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
typedef Matrix<int, Dynamic, Dynamic, RowMajor> RowMatrixXi;
typedef Matrix<int, 2, 3, ColMajor> ColMatrix23i;
typedef Matrix<int, 3, 2, ColMajor> ColMatrix32i;
typedef Matrix<int, 2, 3, RowMajor> RowMatrix23i;
typedef Matrix<int, 3, 2, RowMajor> RowMatrix32i;
VERIFY_IS_APPROX(MatrixXi::Map(data, 2, 3, InnerStride<2>()), MatrixXi::Map(data, 2, 3, Stride<4, 2>()));
VERIFY_IS_APPROX(MatrixXi::Map(data, 2, 3, InnerStride<>(2)), MatrixXi::Map(data, 2, 3, Stride<4, 2>()));
VERIFY_IS_APPROX(MatrixXi::Map(data, 3, 2, InnerStride<2>()), MatrixXi::Map(data, 3, 2, Stride<6, 2>()));
VERIFY_IS_APPROX(MatrixXi::Map(data, 3, 2, InnerStride<>(2)), MatrixXi::Map(data, 3, 2, Stride<6, 2>()));
VERIFY_IS_APPROX(RowMatrixXi::Map(data, 2, 3, InnerStride<2>()), RowMatrixXi::Map(data, 2, 3, Stride<6, 2>()));
VERIFY_IS_APPROX(RowMatrixXi::Map(data, 2, 3, InnerStride<>(2)), RowMatrixXi::Map(data, 2, 3, Stride<6, 2>()));
VERIFY_IS_APPROX(RowMatrixXi::Map(data, 3, 2, InnerStride<2>()), RowMatrixXi::Map(data, 3, 2, Stride<4, 2>()));
VERIFY_IS_APPROX(RowMatrixXi::Map(data, 3, 2, InnerStride<>(2)), RowMatrixXi::Map(data, 3, 2, Stride<4, 2>()));
VERIFY_IS_APPROX(ColMatrix23i::Map(data, InnerStride<2>()), MatrixXi::Map(data, 2, 3, Stride<4, 2>()));
VERIFY_IS_APPROX(ColMatrix23i::Map(data, InnerStride<>(2)), MatrixXi::Map(data, 2, 3, Stride<4, 2>()));
VERIFY_IS_APPROX(ColMatrix32i::Map(data, InnerStride<2>()), MatrixXi::Map(data, 3, 2, Stride<6, 2>()));
VERIFY_IS_APPROX(ColMatrix32i::Map(data, InnerStride<>(2)), MatrixXi::Map(data, 3, 2, Stride<6, 2>()));
VERIFY_IS_APPROX(RowMatrix23i::Map(data, InnerStride<2>()), RowMatrixXi::Map(data, 2, 3, Stride<6, 2>()));
VERIFY_IS_APPROX(RowMatrix23i::Map(data, InnerStride<>(2)), RowMatrixXi::Map(data, 2, 3, Stride<6, 2>()));
VERIFY_IS_APPROX(RowMatrix32i::Map(data, InnerStride<2>()), RowMatrixXi::Map(data, 3, 2, Stride<4, 2>()));
VERIFY_IS_APPROX(RowMatrix32i::Map(data, InnerStride<>(2)), RowMatrixXi::Map(data, 3, 2, Stride<4, 2>()));
}
EIGEN_DECLARE_TEST(mapstride) {
for (int i = 0; i < g_repeat; i++) {
int maxn = 3;
CALL_SUBTEST_1(map_class_vector<Aligned>(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(map_class_vector<Unaligned>(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(map_class_vector<Aligned>(Vector4d()));
CALL_SUBTEST_2(map_class_vector<Unaligned>(Vector4d()));
CALL_SUBTEST_3(map_class_vector<Aligned>(RowVector4f()));
CALL_SUBTEST_3(map_class_vector<Unaligned>(RowVector4f()));
CALL_SUBTEST_4(map_class_vector<Aligned>(VectorXcf(internal::random<int>(1, maxn))));
CALL_SUBTEST_4(map_class_vector<Unaligned>(VectorXcf(internal::random<int>(1, maxn))));
CALL_SUBTEST_5(map_class_vector<Aligned>(VectorXi(internal::random<int>(1, maxn))));
CALL_SUBTEST_5(map_class_vector<Unaligned>(VectorXi(internal::random<int>(1, maxn))));
CALL_SUBTEST_1(map_class_matrix<Aligned>(Matrix<float, 1, 1>()));
CALL_SUBTEST_1(map_class_matrix<Unaligned>(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(map_class_matrix<Aligned>(Matrix4d()));
CALL_SUBTEST_2(map_class_matrix<Unaligned>(Matrix4d()));
CALL_SUBTEST_3(map_class_matrix<Aligned>(Matrix<float, 3, 5>()));
CALL_SUBTEST_3(map_class_matrix<Unaligned>(Matrix<float, 3, 5>()));
CALL_SUBTEST_3(map_class_matrix<Aligned>(Matrix<float, 4, 8>()));
CALL_SUBTEST_3(map_class_matrix<Unaligned>(Matrix<float, 4, 8>()));
CALL_SUBTEST_4(
map_class_matrix<Aligned>(MatrixXcf(internal::random<int>(1, maxn), internal::random<int>(1, maxn))));
CALL_SUBTEST_4(
map_class_matrix<Unaligned>(MatrixXcf(internal::random<int>(1, maxn), internal::random<int>(1, maxn))));
CALL_SUBTEST_5(map_class_matrix<Aligned>(MatrixXi(internal::random<int>(1, maxn), internal::random<int>(1, maxn))));
CALL_SUBTEST_5(
map_class_matrix<Unaligned>(MatrixXi(internal::random<int>(1, maxn), internal::random<int>(1, maxn))));
CALL_SUBTEST_6(
map_class_matrix<Aligned>(MatrixXcd(internal::random<int>(1, maxn), internal::random<int>(1, maxn))));
CALL_SUBTEST_6(
map_class_matrix<Unaligned>(MatrixXcd(internal::random<int>(1, maxn), internal::random<int>(1, maxn))));
CALL_SUBTEST_5(bug1453<0>());
TEST_SET_BUT_UNUSED_VARIABLE(maxn);
}
}
+302
View File
@@ -0,0 +1,302 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <vector>
#include "main.h"
template <typename MatrixType, typename NewScalar>
struct matrix_of {
using type = MatrixType;
};
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols, typename NewScalar>
struct matrix_of<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>, NewScalar> {
using type = Eigen::Matrix<NewScalar, Rows, Cols, Options, MaxRows, MaxCols>;
};
// Unary function reference.
template <typename MatrixType, typename Func,
typename OutMatrixType = typename matrix_of<
MatrixType, typename Eigen::internal::result_of<Func(typename MatrixType::Scalar)>::type>::type>
OutMatrixType cwise_ref(const MatrixType& m, Func f = Func()) {
OutMatrixType out(m.rows(), m.cols());
for (Eigen::Index r = 0; r < m.rows(); ++r) {
for (Eigen::Index c = 0; c < m.cols(); ++c) {
out(r, c) = f(m(r, c));
}
}
return out;
}
// Binary function reference.
template <typename MatrixType, typename Func,
typename OutMatrixType = typename matrix_of<
MatrixType, typename Eigen::internal::result_of<Func(typename MatrixType::Scalar,
typename MatrixType::Scalar)>::type>::type>
OutMatrixType cwise_ref(const MatrixType& m1, const MatrixType& m2, Func f = Func()) {
OutMatrixType out(m1.rows(), m1.cols());
for (Eigen::Index r = 0; r < m1.rows(); ++r) {
for (Eigen::Index c = 0; c < m1.cols(); ++c) {
out(r, c) = f(m1(r, c), m2(r, c));
}
}
return out;
}
template <typename MatrixType>
void test_cwise_real(const MatrixType& m) {
using Scalar = typename MatrixType::Scalar;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols);
MatrixType m2, m3, m4;
// Supported unary ops.
VERIFY_IS_CWISE_APPROX(m1.cwiseAbs(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::abs(x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseSign(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::sign(x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseCbrt(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::cbrt(x); }));
// For integers, avoid division by zero.
m2 = m1;
if (Eigen::NumTraits<Scalar>::IsInteger) {
m2 = m1.unaryExpr([](const Scalar& x) { return Eigen::numext::equal_strict(x, Scalar(0)) ? Scalar(1) : x; });
}
VERIFY_IS_CWISE_APPROX(m2.cwiseInverse(), cwise_ref(m2, [](const Scalar& x) { return Scalar(Scalar(1) / x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseArg(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::arg(x); }));
// Only take sqrt of positive values.
m2 = m1.cwiseAbs();
VERIFY_IS_CWISE_APPROX(m2.cwiseSqrt(), cwise_ref(m2, [](const Scalar& x) { return Eigen::numext::sqrt(x); }));
// Only find Square/Abs2 of +/- sqrt values so we don't overflow.
m2 = m2.cwiseSqrt().array() * m1.cwiseSign().array();
VERIFY_IS_CWISE_APPROX(m2.cwiseAbs2(), cwise_ref(m2, [](const Scalar& x) { return Eigen::numext::abs2(x); }));
VERIFY_IS_CWISE_APPROX(m2.cwiseSquare(), cwise_ref(m2, [](const Scalar& x) { return Scalar(x * x); }));
VERIFY_IS_CWISE_APPROX(m2.cwisePow(Scalar(2)),
cwise_ref(m2, [](const Scalar& x) { return Eigen::numext::pow(x, Scalar(2)); }));
// Supported binary ops.
m1.setRandom(rows, cols);
m2.setRandom(rows, cols);
VERIFY_IS_CWISE_EQUAL(m1.cwiseMin(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMin<PropagateFast>(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMin<PropagateNaN>(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMin<PropagateNumbers>(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.cwiseMax(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMax<PropagateFast>(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMax<PropagateNaN>(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMax<PropagateNumbers>(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
// Scalar comparison.
Scalar mean = Eigen::NumTraits<Scalar>::highest() / Scalar(2) + Eigen::NumTraits<Scalar>::lowest() / Scalar(2);
m4.setConstant(rows, cols, mean);
VERIFY_IS_CWISE_EQUAL(m1.cwiseMin(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMin<PropagateFast>(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMin<PropagateNaN>(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMin<PropagateNumbers>(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::mini(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.cwiseMax(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMax<PropagateFast>(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMax<PropagateNaN>(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
VERIFY_IS_CWISE_EQUAL(m1.template cwiseMax<PropagateNumbers>(mean),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Eigen::numext::maxi(x, y); }));
// For products, avoid integer overflow by limiting the input < sqrt(max).
m3 = m1;
m4 = m2;
if (Eigen::NumTraits<Scalar>::IsInteger) {
const Scalar kMax = Eigen::numext::sqrt(Eigen::NumTraits<Scalar>::highest());
m3 = m1 - ((m1 / kMax) * kMax);
m4 = m2 - ((m2 / kMax) * kMax);
}
VERIFY_IS_CWISE_APPROX(m3.cwiseProduct(m4),
cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return Scalar(x * y); }));
// For quotients involving integers, avoid division by zero.
m4 = m2;
if (Eigen::NumTraits<Scalar>::IsInteger) {
m4 = m2.unaryExpr([](const Scalar& x) { return Eigen::numext::equal_strict(x, Scalar(0)) ? Scalar(1) : x; });
}
VERIFY_IS_CWISE_APPROX(m1.cwiseQuotient(m4),
cwise_ref(m1, m4, [](const Scalar& x, const Scalar& y) { return Scalar(x / y); }));
// For equality comparisons, limit range to increase number of equalities.
if (Eigen::NumTraits<Scalar>::IsInteger) {
const Scalar kMax = Scalar(10);
m3 = m1 - ((m1 / kMax) * kMax);
m4 = m2 - ((m2 / kMax) * kMax);
mean = Eigen::NumTraits<Scalar>::IsSigned ? Scalar(0) : kMax / Scalar(2);
} else {
const Scalar kShift = Scalar(10);
m3 = (m1 * kShift).array().floor() / kShift;
m4 = (m2 * kShift).array().floor() / kShift;
mean = Scalar(0);
}
VERIFY_IS_CWISE_EQUAL(m3.cwiseEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseNotEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseLess(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x < y; }));
VERIFY_IS_CWISE_EQUAL(m3.cwiseGreater(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x > y; }));
VERIFY_IS_CWISE_EQUAL(m3.cwiseLessOrEqual(m4),
cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x <= y; }));
VERIFY_IS_CWISE_EQUAL(m3.cwiseGreaterOrEqual(m4),
cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x >= y; }));
// Typed-Equality.
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedNotEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedLess(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x < y ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedGreater(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x > y ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedLessOrEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x <= y ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedGreaterOrEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x >= y ? Scalar(1) : Scalar(0);
}));
// Scalar.
m4.setConstant(rows, cols, mean);
VERIFY_IS_CWISE_EQUAL(m3.cwiseEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseNotEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseLess(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x < y; }));
VERIFY_IS_CWISE_EQUAL(m3.cwiseGreater(mean),
cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x > y; }));
VERIFY_IS_CWISE_EQUAL(m3.cwiseLessOrEqual(mean),
cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x <= y; }));
VERIFY_IS_CWISE_EQUAL(m3.cwiseGreaterOrEqual(mean),
cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) { return x >= y; }));
// Typed.
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedNotEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedLess(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x < y ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedGreater(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x > y ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedLessOrEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x <= y ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedGreaterOrEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return x >= y ? Scalar(1) : Scalar(0);
}));
}
template <typename MatrixType>
void test_cwise_complex(const MatrixType& m) {
using Scalar = typename MatrixType::Scalar;
using RealScalar = typename NumTraits<Scalar>::Real;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols);
MatrixType m2, m3, m4;
// Supported unary ops.
VERIFY_IS_CWISE_APPROX(m1.cwiseAbs(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::abs(x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseSqrt(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::sqrt(x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseInverse(), cwise_ref(m1, [](const Scalar& x) { return Scalar(Scalar(1) / x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseArg(), cwise_ref(m1, [](const Scalar& x) { return Eigen::numext::arg(x); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseCArg(), cwise_ref(m1, [](const Scalar& x) { return Scalar(Eigen::numext::arg(x)); }));
// Only find Square/Abs2 of +/- sqrt values so we don't overflow.
m2 = m1.cwiseSqrt().array() * m1.cwiseSign().array();
VERIFY_IS_CWISE_APPROX(m2.cwiseAbs2(), cwise_ref(m2, [](const Scalar& x) { return Eigen::numext::abs2(x); }));
VERIFY_IS_CWISE_APPROX(m2.cwiseSquare(), cwise_ref(m2, [](const Scalar& x) { return Scalar(x * x); }));
VERIFY_IS_CWISE_APPROX(m2.cwisePow(Scalar(2)),
cwise_ref(m2, [](const Scalar& x) { return Eigen::numext::pow(x, Scalar(2)); }));
// Supported binary ops.
m1.setRandom(rows, cols);
m2.setRandom(rows, cols);
VERIFY_IS_CWISE_APPROX(m1.cwiseProduct(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Scalar(x * y); }));
VERIFY_IS_CWISE_APPROX(m1.cwiseQuotient(m2),
cwise_ref(m1, m2, [](const Scalar& x, const Scalar& y) { return Scalar(x / y); }));
// For equality comparisons, limit range to increase number of equalities.
{
const RealScalar kShift = RealScalar(10);
m3 = m1;
m4 = m2;
m3.real() = (m1.real() * kShift).array().floor() / kShift;
m3.imag() = (m1.imag() * kShift).array().floor() / kShift;
m4.real() = (m2.real() * kShift).array().floor() / kShift;
m4.imag() = (m2.imag() * kShift).array().floor() / kShift;
}
VERIFY_IS_CWISE_EQUAL(m3.cwiseEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseNotEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y);
}));
// Typed-Equality.
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedNotEqual(m4), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
// Scalar.
Scalar mean = Scalar(0);
m4.setConstant(rows, cols, mean);
VERIFY_IS_CWISE_EQUAL(m3.cwiseEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseNotEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y);
}));
// Typed.
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
VERIFY_IS_CWISE_EQUAL(m3.cwiseTypedNotEqual(mean), cwise_ref(m3, m4, [](const Scalar& x, const Scalar& y) {
return !Eigen::numext::equal_strict(x, y) ? Scalar(1) : Scalar(0);
}));
}
EIGEN_DECLARE_TEST(matrix_cwise) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(test_cwise_real(Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_1(test_cwise_real(Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_1(test_cwise_real(Eigen::Matrix<Eigen::half, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_1(test_cwise_real(Eigen::Matrix<Eigen::bfloat16, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_2(test_cwise_complex(Eigen::Matrix<std::complex<float>, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_2(test_cwise_complex(Eigen::Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_3(test_cwise_real(Eigen::Matrix<int8_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_3(test_cwise_real(Eigen::Matrix<int16_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_3(test_cwise_real(Eigen::Matrix<int32_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_3(test_cwise_real(Eigen::Matrix<int64_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_4(test_cwise_real(Eigen::Matrix<uint8_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_4(test_cwise_real(Eigen::Matrix<uint16_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_4(test_cwise_real(Eigen::Matrix<uint32_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
CALL_SUBTEST_4(test_cwise_real(Eigen::Matrix<uint64_t, Eigen::Dynamic, Eigen::Dynamic>(20, 20)));
}
}
+73
View File
@@ -0,0 +1,73 @@
#include "main.h"
#ifdef EIGEN_EXCEPTIONS
#include <exception> // std::exception
#endif
#include <Eigen/src/Core/util/MaxSizeVector.h>
struct Foo {
static Index object_count;
static Index object_limit;
EIGEN_ALIGN_TO_BOUNDARY(128) int dummy;
Foo(int x = 0) : dummy(x) {
#ifdef EIGEN_EXCEPTIONS
// TODO: Is this the correct way to handle this?
if (Foo::object_count > Foo::object_limit) {
std::cout << "\nThrow!\n";
throw Foo::Fail();
}
#endif
std::cout << '+';
++Foo::object_count;
eigen_assert((std::uintptr_t(this) & (127)) == 0);
}
Foo(const Foo&) {
std::cout << 'c';
++Foo::object_count;
eigen_assert((std::uintptr_t(this) & (127)) == 0);
}
~Foo() {
std::cout << '~';
--Foo::object_count;
}
#ifdef EIGEN_EXCEPTIONS
class Fail : public std::exception {};
#endif
};
Index Foo::object_count = 0;
Index Foo::object_limit = 0;
EIGEN_DECLARE_TEST(maxsizevector) {
typedef MaxSizeVector<Foo> VectorX;
Foo::object_count = 0;
for (int r = 0; r < g_repeat; r++) {
Index rows = internal::random<Index>(3, 30);
Foo::object_limit = internal::random<Index>(0, rows - 2);
std::cout << "object_limit = " << Foo::object_limit << std::endl;
#ifdef EIGEN_EXCEPTIONS
bool exception_raised = false;
try {
std::cout << "\nVectorX m(" << rows << ");\n";
VectorX vect(rows);
for (int i = 0; i < rows; ++i) vect.push_back(Foo());
VERIFY(false); // not reached if exceptions are enabled
} catch (const Foo::Fail&) {
exception_raised = true;
}
VERIFY(exception_raised);
#endif
VERIFY_IS_EQUAL(Index(0), Foo::object_count);
{
Foo::object_limit = rows + 1;
VectorX vect2(rows, Foo());
VERIFY_IS_EQUAL(Foo::object_count, rows);
}
VERIFY_IS_EQUAL(Index(0), Foo::object_count);
std::cout << '\n';
}
}
+533
View File
@@ -0,0 +1,533 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <array>
#include <Eigen/src/Core/util/Meta.h>
template <typename From, typename To>
bool check_is_convertible(const From&, const To&) {
return internal::is_convertible<From, To>::value;
}
struct FooReturnType {
typedef int ReturnType;
};
struct MyInterface {
virtual void func() = 0;
virtual ~MyInterface() {}
};
struct MyImpl : public MyInterface {
void func() {}
};
EIGEN_DECLARE_TEST(meta) {
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_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_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_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));
STATIC_CHECK((internal::is_convertible<int, double>::value));
STATIC_CHECK((internal::is_convertible<int, short>::value));
STATIC_CHECK((internal::is_convertible<short, int>::value));
STATIC_CHECK((internal::is_convertible<double, int>::value));
STATIC_CHECK((internal::is_convertible<double, std::complex<double>>::value));
STATIC_CHECK((!internal::is_convertible<std::complex<double>, double>::value));
STATIC_CHECK((internal::is_convertible<Array33f, Matrix3f>::value));
STATIC_CHECK((internal::is_convertible<Matrix3f&, Matrix3f>::value));
STATIC_CHECK((internal::is_convertible<Matrix3f&, Matrix3f&>::value));
STATIC_CHECK((internal::is_convertible<Matrix3f&, const Matrix3f&>::value));
STATIC_CHECK((internal::is_convertible<const Matrix3f&, Matrix3f>::value));
STATIC_CHECK((internal::is_convertible<const Matrix3f&, const Matrix3f&>::value));
STATIC_CHECK((!internal::is_convertible<const Matrix3f&, Matrix3f&>::value));
STATIC_CHECK((!internal::is_convertible<const Matrix3f, Matrix3f&>::value));
STATIC_CHECK(!(internal::is_convertible<Matrix3f, Matrix3f&>::value));
STATIC_CHECK(!(internal::is_convertible<int, int&>::value));
STATIC_CHECK((internal::is_convertible<const int, const int&>::value));
// STATIC_CHECK((!internal::is_convertible<Matrix3f,Matrix3d>::value )); //does not even compile because the
// conversion is prevented by a static assertion
STATIC_CHECK((!internal::is_convertible<Array33f, int>::value));
STATIC_CHECK((!internal::is_convertible<MatrixXf, float>::value));
{
float f = 0.0f;
MatrixXf A, B;
VectorXf a, b;
VERIFY((check_is_convertible(a.dot(b), f)));
VERIFY((check_is_convertible(a.transpose() * b, f)));
VERIFY((!check_is_convertible(A * B, f)));
VERIFY((check_is_convertible(A * B, A)));
}
#if (EIGEN_COMP_GNUC_STRICT && EIGEN_COMP_GNUC <= 990) || (EIGEN_COMP_CLANG_STRICT && EIGEN_COMP_CLANG <= 990) || \
(EIGEN_COMP_MSVC && EIGEN_COMP_MSVC <= 1914)
// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1752,
// basically, a fix in the c++ standard breaks our c++98 implementation
// of is_convertible for abstract classes.
// So the following tests are expected to fail with recent compilers.
STATIC_CHECK((!internal::is_convertible<MyInterface, MyImpl>::value));
STATIC_CHECK((!internal::is_convertible<MyImpl, MyInterface>::value));
STATIC_CHECK((internal::is_convertible<MyImpl, const MyInterface&>::value));
#endif
{
int i = 0;
VERIFY((check_is_convertible(fix<3>(), i)));
VERIFY((!check_is_convertible(i, fix<DynamicIndex>())));
}
VERIFY((internal::has_ReturnType<FooReturnType>::value));
VERIFY((internal::has_ReturnType<ScalarBinaryOpTraits<int, int>>::value));
VERIFY((!internal::has_ReturnType<MatrixXf>::value));
VERIFY((!internal::has_ReturnType<int>::value));
VERIFY(internal::meta_sqrt<1>::ret == 1);
#define VERIFY_META_SQRT(X) VERIFY(internal::meta_sqrt<X>::ret == int(std::sqrt(double(X))))
VERIFY_META_SQRT(2);
VERIFY_META_SQRT(3);
VERIFY_META_SQRT(4);
VERIFY_META_SQRT(5);
VERIFY_META_SQRT(6);
VERIFY_META_SQRT(8);
VERIFY_META_SQRT(9);
VERIFY_META_SQRT(15);
VERIFY_META_SQRT(16);
VERIFY_META_SQRT(17);
VERIFY_META_SQRT(255);
VERIFY_META_SQRT(256);
VERIFY_META_SQRT(257);
VERIFY_META_SQRT(1023);
VERIFY_META_SQRT(1024);
VERIFY_META_SQRT(1025);
}
using Eigen::internal::apply_op_from_left;
using Eigen::internal::apply_op_from_right;
using Eigen::internal::arg_prod;
using Eigen::internal::arg_sum;
using Eigen::internal::array_apply;
using Eigen::internal::array_apply_and_reduce;
using Eigen::internal::array_prod;
using Eigen::internal::array_reduce;
using Eigen::internal::array_reverse;
using Eigen::internal::array_sum;
using Eigen::internal::array_zip;
using Eigen::internal::array_zip_and_reduce;
using Eigen::internal::concat;
using Eigen::internal::contained_in_list;
using Eigen::internal::contained_in_list_gf;
using Eigen::internal::gen_numeric_list;
using Eigen::internal::gen_numeric_list_repeated;
using Eigen::internal::gen_numeric_list_reversed;
using Eigen::internal::gen_numeric_list_swapped_pair;
using Eigen::internal::get;
using Eigen::internal::id_numeric;
using Eigen::internal::id_type;
using Eigen::internal::instantiate_by_c_array;
using Eigen::internal::is_same;
using Eigen::internal::is_same_gf;
using Eigen::internal::mconcat;
using Eigen::internal::numeric_list;
using Eigen::internal::product_op;
using Eigen::internal::repeat;
using Eigen::internal::skip;
using Eigen::internal::slice;
using Eigen::internal::sum_op;
using Eigen::internal::take;
using Eigen::internal::type_list;
struct dummy_a {};
struct dummy_b {};
struct dummy_c {};
struct dummy_d {};
struct dummy_e {};
// dummy operation for testing apply
template <typename A, typename B>
struct dummy_op;
template <>
struct dummy_op<dummy_a, dummy_b> {
typedef dummy_c type;
};
template <>
struct dummy_op<dummy_b, dummy_a> {
typedef dummy_d type;
};
template <>
struct dummy_op<dummy_b, dummy_c> {
typedef dummy_a type;
};
template <>
struct dummy_op<dummy_c, dummy_b> {
typedef dummy_d type;
};
template <>
struct dummy_op<dummy_c, dummy_a> {
typedef dummy_b type;
};
template <>
struct dummy_op<dummy_a, dummy_c> {
typedef dummy_d type;
};
template <>
struct dummy_op<dummy_a, dummy_a> {
typedef dummy_e type;
};
template <>
struct dummy_op<dummy_b, dummy_b> {
typedef dummy_e type;
};
template <>
struct dummy_op<dummy_c, dummy_c> {
typedef dummy_e type;
};
template <typename A, typename B>
struct dummy_test {
constexpr static bool value = false;
constexpr static int global_flags = 0;
};
template <>
struct dummy_test<dummy_a, dummy_a> {
constexpr static bool value = true;
constexpr static int global_flags = 1;
};
template <>
struct dummy_test<dummy_b, dummy_b> {
constexpr static bool value = true;
constexpr static int global_flags = 2;
};
template <>
struct dummy_test<dummy_c, dummy_c> {
constexpr static bool value = true;
constexpr static int global_flags = 4;
};
struct times2_op {
template <typename A>
static A run(A v) {
return v * 2;
}
};
struct dummy_inst {
int c;
dummy_inst() : c(0) {}
explicit dummy_inst(int) : c(1) {}
dummy_inst(int, int) : c(2) {}
dummy_inst(int, int, int) : c(3) {}
dummy_inst(int, int, int, int) : c(4) {}
dummy_inst(int, int, int, int, int) : c(5) {}
};
static void test_gen_numeric_list() {
VERIFY((is_same<typename gen_numeric_list<int, 0>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 1>::type, numeric_list<int, 0>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 2>::type, numeric_list<int, 0, 1>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 5>::type, numeric_list<int, 0, 1, 2, 3, 4>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 10>::type, numeric_list<int, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 0, 42>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 1, 42>::type, numeric_list<int, 42>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 2, 42>::type, numeric_list<int, 42, 43>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 5, 42>::type, numeric_list<int, 42, 43, 44, 45, 46>>::value));
VERIFY((is_same<typename gen_numeric_list<int, 10, 42>::type,
numeric_list<int, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 0>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 1>::type, numeric_list<int, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 2>::type, numeric_list<int, 1, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 5>::type, numeric_list<int, 4, 3, 2, 1, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 10>::type,
numeric_list<int, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 0, 42>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 1, 42>::type, numeric_list<int, 42>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 2, 42>::type, numeric_list<int, 43, 42>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 5, 42>::type, numeric_list<int, 46, 45, 44, 43, 42>>::value));
VERIFY((is_same<typename gen_numeric_list_reversed<int, 10, 42>::type,
numeric_list<int, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 0, 2, 3>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 1, 2, 3>::type, numeric_list<int, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 2, 2, 3>::type, numeric_list<int, 0, 1>>::value));
VERIFY(
(is_same<typename gen_numeric_list_swapped_pair<int, 5, 2, 3>::type, numeric_list<int, 0, 1, 3, 2, 4>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 10, 2, 3>::type,
numeric_list<int, 0, 1, 3, 2, 4, 5, 6, 7, 8, 9>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 0, 44, 45, 42>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 1, 44, 45, 42>::type, numeric_list<int, 42>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 2, 44, 45, 42>::type, numeric_list<int, 42, 43>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 5, 44, 45, 42>::type,
numeric_list<int, 42, 43, 45, 44, 46>>::value));
VERIFY((is_same<typename gen_numeric_list_swapped_pair<int, 10, 44, 45, 42>::type,
numeric_list<int, 42, 43, 45, 44, 46, 47, 48, 49, 50, 51>>::value));
VERIFY((is_same<typename gen_numeric_list_repeated<int, 0, 0>::type, numeric_list<int>>::value));
VERIFY((is_same<typename gen_numeric_list_repeated<int, 1, 0>::type, numeric_list<int, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_repeated<int, 2, 0>::type, numeric_list<int, 0, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_repeated<int, 5, 0>::type, numeric_list<int, 0, 0, 0, 0, 0>>::value));
VERIFY((is_same<typename gen_numeric_list_repeated<int, 10, 0>::type,
numeric_list<int, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>::value));
}
static void test_concat() {
VERIFY(
(is_same<typename concat<type_list<dummy_a, dummy_a>, type_list<>>::type, type_list<dummy_a, dummy_a>>::value));
VERIFY(
(is_same<typename concat<type_list<>, type_list<dummy_a, dummy_a>>::type, type_list<dummy_a, dummy_a>>::value));
VERIFY((is_same<typename concat<type_list<dummy_a, dummy_a>, type_list<dummy_a, dummy_a>>::type,
type_list<dummy_a, dummy_a, dummy_a, dummy_a>>::value));
VERIFY((is_same<typename concat<type_list<dummy_a, dummy_a>, type_list<dummy_b, dummy_c>>::type,
type_list<dummy_a, dummy_a, dummy_b, dummy_c>>::value));
VERIFY((is_same<typename concat<type_list<dummy_a>, type_list<dummy_b, dummy_c>>::type,
type_list<dummy_a, dummy_b, dummy_c>>::value));
VERIFY((is_same<typename concat<numeric_list<int, 0, 0>, numeric_list<int>>::type, numeric_list<int, 0, 0>>::value));
VERIFY((is_same<typename concat<numeric_list<int>, numeric_list<int, 0, 0>>::type, numeric_list<int, 0, 0>>::value));
VERIFY((is_same<typename concat<numeric_list<int, 0, 0>, numeric_list<int, 0, 0>>::type,
numeric_list<int, 0, 0, 0, 0>>::value));
VERIFY((is_same<typename concat<numeric_list<int, 0, 0>, numeric_list<int, 1, 2>>::type,
numeric_list<int, 0, 0, 1, 2>>::value));
VERIFY((is_same<typename concat<numeric_list<int, 0>, numeric_list<int, 1, 2>>::type,
numeric_list<int, 0, 1, 2>>::value));
VERIFY((is_same<typename mconcat<type_list<dummy_a>>::type, type_list<dummy_a>>::value));
VERIFY((is_same<typename mconcat<type_list<dummy_a>, type_list<dummy_b>>::type, type_list<dummy_a, dummy_b>>::value));
VERIFY((is_same<typename mconcat<type_list<dummy_a>, type_list<dummy_b>, type_list<dummy_c>>::type,
type_list<dummy_a, dummy_b, dummy_c>>::value));
VERIFY((is_same<typename mconcat<type_list<dummy_a>, type_list<dummy_b, dummy_c>>::type,
type_list<dummy_a, dummy_b, dummy_c>>::value));
VERIFY((is_same<typename mconcat<type_list<dummy_a, dummy_b>, type_list<dummy_c>>::type,
type_list<dummy_a, dummy_b, dummy_c>>::value));
VERIFY((is_same<typename mconcat<numeric_list<int, 0>>::type, numeric_list<int, 0>>::value));
VERIFY((is_same<typename mconcat<numeric_list<int, 0>, numeric_list<int, 1>>::type, numeric_list<int, 0, 1>>::value));
VERIFY((is_same<typename mconcat<numeric_list<int, 0>, numeric_list<int, 1>, numeric_list<int, 2>>::type,
numeric_list<int, 0, 1, 2>>::value));
VERIFY((is_same<typename mconcat<numeric_list<int, 0>, numeric_list<int, 1, 2>>::type,
numeric_list<int, 0, 1, 2>>::value));
VERIFY((is_same<typename mconcat<numeric_list<int, 0, 1>, numeric_list<int, 2>>::type,
numeric_list<int, 0, 1, 2>>::value));
}
static void test_slice() {
typedef type_list<dummy_a, dummy_a, dummy_b, dummy_b, dummy_c, dummy_c> tl;
typedef numeric_list<int, 0, 1, 2, 3, 4, 5> il;
VERIFY((is_same<typename take<0, tl>::type, type_list<>>::value));
VERIFY((is_same<typename take<1, tl>::type, type_list<dummy_a>>::value));
VERIFY((is_same<typename take<2, tl>::type, type_list<dummy_a, dummy_a>>::value));
VERIFY((is_same<typename take<3, tl>::type, type_list<dummy_a, dummy_a, dummy_b>>::value));
VERIFY((is_same<typename take<4, tl>::type, type_list<dummy_a, dummy_a, dummy_b, dummy_b>>::value));
VERIFY((is_same<typename take<5, tl>::type, type_list<dummy_a, dummy_a, dummy_b, dummy_b, dummy_c>>::value));
VERIFY((is_same<typename take<6, tl>::type, type_list<dummy_a, dummy_a, dummy_b, dummy_b, dummy_c, dummy_c>>::value));
VERIFY((is_same<typename take<0, il>::type, numeric_list<int>>::value));
VERIFY((is_same<typename take<1, il>::type, numeric_list<int, 0>>::value));
VERIFY((is_same<typename take<2, il>::type, numeric_list<int, 0, 1>>::value));
VERIFY((is_same<typename take<3, il>::type, numeric_list<int, 0, 1, 2>>::value));
VERIFY((is_same<typename take<4, il>::type, numeric_list<int, 0, 1, 2, 3>>::value));
VERIFY((is_same<typename take<5, il>::type, numeric_list<int, 0, 1, 2, 3, 4>>::value));
VERIFY((is_same<typename take<6, il>::type, numeric_list<int, 0, 1, 2, 3, 4, 5>>::value));
VERIFY((is_same<typename skip<0, tl>::type, type_list<dummy_a, dummy_a, dummy_b, dummy_b, dummy_c, dummy_c>>::value));
VERIFY((is_same<typename skip<1, tl>::type, type_list<dummy_a, dummy_b, dummy_b, dummy_c, dummy_c>>::value));
VERIFY((is_same<typename skip<2, tl>::type, type_list<dummy_b, dummy_b, dummy_c, dummy_c>>::value));
VERIFY((is_same<typename skip<3, tl>::type, type_list<dummy_b, dummy_c, dummy_c>>::value));
VERIFY((is_same<typename skip<4, tl>::type, type_list<dummy_c, dummy_c>>::value));
VERIFY((is_same<typename skip<5, tl>::type, type_list<dummy_c>>::value));
VERIFY((is_same<typename skip<6, tl>::type, type_list<>>::value));
VERIFY((is_same<typename skip<0, il>::type, numeric_list<int, 0, 1, 2, 3, 4, 5>>::value));
VERIFY((is_same<typename skip<1, il>::type, numeric_list<int, 1, 2, 3, 4, 5>>::value));
VERIFY((is_same<typename skip<2, il>::type, numeric_list<int, 2, 3, 4, 5>>::value));
VERIFY((is_same<typename skip<3, il>::type, numeric_list<int, 3, 4, 5>>::value));
VERIFY((is_same<typename skip<4, il>::type, numeric_list<int, 4, 5>>::value));
VERIFY((is_same<typename skip<5, il>::type, numeric_list<int, 5>>::value));
VERIFY((is_same<typename skip<6, il>::type, numeric_list<int>>::value));
VERIFY((is_same<typename slice<0, 3, tl>::type, typename take<3, tl>::type>::value));
VERIFY((is_same<typename slice<0, 3, il>::type, typename take<3, il>::type>::value));
VERIFY((is_same<typename slice<1, 3, tl>::type, type_list<dummy_a, dummy_b, dummy_b>>::value));
VERIFY((is_same<typename slice<1, 3, il>::type, numeric_list<int, 1, 2, 3>>::value));
}
static void test_get() {
typedef type_list<dummy_a, dummy_a, dummy_b, dummy_b, dummy_c, dummy_c> tl;
typedef numeric_list<int, 4, 8, 15, 16, 23, 42> il;
VERIFY((is_same<typename get<0, tl>::type, dummy_a>::value));
VERIFY((is_same<typename get<1, tl>::type, dummy_a>::value));
VERIFY((is_same<typename get<2, tl>::type, dummy_b>::value));
VERIFY((is_same<typename get<3, tl>::type, dummy_b>::value));
VERIFY((is_same<typename get<4, tl>::type, dummy_c>::value));
VERIFY((is_same<typename get<5, tl>::type, dummy_c>::value));
VERIFY_IS_EQUAL(((int)get<0, il>::value), 4);
VERIFY_IS_EQUAL(((int)get<1, il>::value), 8);
VERIFY_IS_EQUAL(((int)get<2, il>::value), 15);
VERIFY_IS_EQUAL(((int)get<3, il>::value), 16);
VERIFY_IS_EQUAL(((int)get<4, il>::value), 23);
VERIFY_IS_EQUAL(((int)get<5, il>::value), 42);
}
static void test_id_helper(dummy_a a, dummy_a b, dummy_a c) {
(void)a;
(void)b;
(void)c;
}
template <int... ii>
static void test_id_numeric() {
test_id_helper(typename id_numeric<int, ii, dummy_a>::type()...);
}
template <typename... tt>
static void test_id_type() {
test_id_helper(typename id_type<tt, dummy_a>::type()...);
}
static void test_id() {
// don't call VERIFY here, just assume it works if it compiles
// (otherwise it will complain that it can't find the function)
test_id_numeric<1, 4, 6>();
test_id_type<dummy_a, dummy_b, dummy_c>();
}
static void test_is_same_gf() {
VERIFY((!is_same_gf<dummy_a, dummy_b>::value));
VERIFY((!!is_same_gf<dummy_a, dummy_a>::value));
VERIFY_IS_EQUAL((!!is_same_gf<dummy_a, dummy_b>::global_flags), false);
VERIFY_IS_EQUAL((!!is_same_gf<dummy_a, dummy_a>::global_flags), false);
}
static void test_apply_op() {
typedef type_list<dummy_a, dummy_b, dummy_c> tl;
VERIFY((!!is_same<typename apply_op_from_left<dummy_op, dummy_a, tl>::type,
type_list<dummy_e, dummy_c, dummy_d>>::value));
VERIFY((!!is_same<typename apply_op_from_right<dummy_op, dummy_a, tl>::type,
type_list<dummy_e, dummy_d, dummy_b>>::value));
}
static void test_contained_in_list() {
typedef type_list<dummy_a, dummy_b, dummy_c> tl;
VERIFY((!!contained_in_list<is_same, dummy_a, tl>::value));
VERIFY((!!contained_in_list<is_same, dummy_b, tl>::value));
VERIFY((!!contained_in_list<is_same, dummy_c, tl>::value));
VERIFY((!contained_in_list<is_same, dummy_d, tl>::value));
VERIFY((!contained_in_list<is_same, dummy_e, tl>::value));
VERIFY((!!contained_in_list_gf<dummy_test, dummy_a, tl>::value));
VERIFY((!!contained_in_list_gf<dummy_test, dummy_b, tl>::value));
VERIFY((!!contained_in_list_gf<dummy_test, dummy_c, tl>::value));
VERIFY((!contained_in_list_gf<dummy_test, dummy_d, tl>::value));
VERIFY((!contained_in_list_gf<dummy_test, dummy_e, tl>::value));
VERIFY_IS_EQUAL(((int)contained_in_list_gf<dummy_test, dummy_a, tl>::global_flags), 1);
VERIFY_IS_EQUAL(((int)contained_in_list_gf<dummy_test, dummy_b, tl>::global_flags), 2);
VERIFY_IS_EQUAL(((int)contained_in_list_gf<dummy_test, dummy_c, tl>::global_flags), 4);
VERIFY_IS_EQUAL(((int)contained_in_list_gf<dummy_test, dummy_d, tl>::global_flags), 0);
VERIFY_IS_EQUAL(((int)contained_in_list_gf<dummy_test, dummy_e, tl>::global_flags), 0);
}
static void test_arg_reductions() {
VERIFY_IS_EQUAL(arg_sum(1, 2, 3, 4), 10);
VERIFY_IS_EQUAL(arg_prod(1, 2, 3, 4), 24);
VERIFY_IS_APPROX(arg_sum(0.5, 2, 5), 7.5);
VERIFY_IS_APPROX(arg_prod(0.5, 2, 5), 5.0);
}
static void test_array_reverse_and_reduce() {
array<int, 6> a{{4, 8, 15, 16, 23, 42}};
array<int, 6> b{{42, 23, 16, 15, 8, 4}};
// there is no operator<< for std::array, so VERIFY_IS_EQUAL will
// not compile
VERIFY((array_reverse(a) == b));
VERIFY((array_reverse(b) == a));
VERIFY_IS_EQUAL((array_sum(a)), 108);
VERIFY_IS_EQUAL((array_sum(b)), 108);
VERIFY_IS_EQUAL((array_prod(a)), 7418880);
VERIFY_IS_EQUAL((array_prod(b)), 7418880);
}
static void test_array_zip_and_apply() {
array<int, 6> a{{4, 8, 15, 16, 23, 42}};
array<int, 6> b{{0, 1, 2, 3, 4, 5}};
array<int, 6> c{{4, 9, 17, 19, 27, 47}};
array<int, 6> d{{0, 8, 30, 48, 92, 210}};
array<int, 6> e{{0, 2, 4, 6, 8, 10}};
VERIFY((array_zip<sum_op>(a, b) == c));
VERIFY((array_zip<product_op>(a, b) == d));
VERIFY((array_apply<times2_op>(b) == e));
VERIFY_IS_EQUAL((array_apply_and_reduce<sum_op, times2_op>(a)), 216);
VERIFY_IS_EQUAL((array_apply_and_reduce<sum_op, times2_op>(b)), 30);
VERIFY_IS_EQUAL((array_zip_and_reduce<product_op, sum_op>(a, b)), 14755932);
VERIFY_IS_EQUAL((array_zip_and_reduce<sum_op, product_op>(a, b)), 388);
}
static void test_array_misc() {
array<int, 3> a3{{1, 1, 1}};
array<int, 6> a6{{2, 2, 2, 2, 2, 2}};
VERIFY((repeat<3, int>(1) == a3));
VERIFY((repeat<6, int>(2) == a6));
int data[5] = {0, 1, 2, 3, 4};
VERIFY_IS_EQUAL((instantiate_by_c_array<dummy_inst, int, 0>(data).c), 0);
VERIFY_IS_EQUAL((instantiate_by_c_array<dummy_inst, int, 1>(data).c), 1);
VERIFY_IS_EQUAL((instantiate_by_c_array<dummy_inst, int, 2>(data).c), 2);
VERIFY_IS_EQUAL((instantiate_by_c_array<dummy_inst, int, 3>(data).c), 3);
VERIFY_IS_EQUAL((instantiate_by_c_array<dummy_inst, int, 4>(data).c), 4);
VERIFY_IS_EQUAL((instantiate_by_c_array<dummy_inst, int, 5>(data).c), 5);
}
EIGEN_DECLARE_TEST(cxx11_meta) {
CALL_SUBTEST(test_gen_numeric_list());
CALL_SUBTEST(test_concat());
CALL_SUBTEST(test_slice());
CALL_SUBTEST(test_get());
CALL_SUBTEST(test_id());
CALL_SUBTEST(test_is_same_gf());
CALL_SUBTEST(test_apply_op());
CALL_SUBTEST(test_contained_in_list());
CALL_SUBTEST(test_arg_reductions());
CALL_SUBTEST(test_array_reverse_and_reduce());
CALL_SUBTEST(test_array_zip_and_apply());
CALL_SUBTEST(test_array_misc());
}
+22
View File
@@ -0,0 +1,22 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "sparse_solver.h"
#include <Eigen/SparseLU>
#include <Eigen/MetisSupport>
#include <unsupported/Eigen/SparseExtra>
template <typename T>
void test_metis_T() {
SparseLU<SparseMatrix<T, ColMajor>, MetisOrdering<int> > sparselu_metis;
check_sparse_square_solving(sparselu_metis);
}
EIGEN_DECLARE_TEST(metis_support) { CALL_SUBTEST_1(test_metis_T<double>()); }
+47
View File
@@ -0,0 +1,47 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType>
void miscMatrices(const MatrixType& m) {
/* this test covers the following files:
DiagonalMatrix.h Ones.h
*/
typedef typename MatrixType::Scalar Scalar;
typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
Index rows = m.rows();
Index cols = m.cols();
Index r = internal::random<Index>(0, rows - 1), r2 = internal::random<Index>(0, rows - 1),
c = internal::random<Index>(0, cols - 1);
VERIFY_IS_APPROX(MatrixType::Ones(rows, cols)(r, c), static_cast<Scalar>(1));
MatrixType m1 = MatrixType::Ones(rows, cols);
VERIFY_IS_APPROX(m1(r, c), static_cast<Scalar>(1));
VectorType v1 = VectorType::Random(rows);
v1[0];
Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> square(v1.asDiagonal());
if (r == r2)
VERIFY_IS_APPROX(square(r, r2), v1[r]);
else
VERIFY_IS_MUCH_SMALLER_THAN(square(r, r2), static_cast<Scalar>(1));
square = MatrixType::Zero(rows, rows);
square.diagonal() = VectorType::Ones(rows);
VERIFY_IS_APPROX(square, MatrixType::Identity(rows, rows));
}
EIGEN_DECLARE_TEST(miscmatrices) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(miscMatrices(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(miscMatrices(Matrix4d()));
CALL_SUBTEST_3(miscMatrices(MatrixXcf(3, 3)));
CALL_SUBTEST_4(miscMatrices(MatrixXi(8, 12)));
CALL_SUBTEST_5(miscMatrices(MatrixXcd(20, 20)));
}
}
+306
View File
@@ -0,0 +1,306 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#if defined(EIGEN_TEST_PART_7)
// ignore double-promotion diagnostic for clang and gcc, if we check for static assertion anyway:
// TODO do the same for MSVC?
#if defined(__clang__)
#if (__clang_major__ * 100 + __clang_minor__) >= 308
#pragma clang diagnostic ignored "-Wdouble-promotion"
#endif
#elif defined(__GNUC__)
// TODO is there a minimal GCC version for this? At least g++-4.7 seems to be fine with this.
#pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
#endif
#if defined(EIGEN_TEST_PART_1) || defined(EIGEN_TEST_PART_2) || defined(EIGEN_TEST_PART_3)
#ifndef EIGEN_DONT_VECTORIZE
#define EIGEN_DONT_VECTORIZE
#endif
#endif
static bool g_called;
#define EIGEN_SCALAR_BINARY_OP_PLUGIN \
{ g_called |= (!internal::is_same<LhsScalar, RhsScalar>::value); }
#include "main.h"
using namespace std;
#define VERIFY_MIX_SCALAR(XPR, REF) \
g_called = false; \
VERIFY_IS_APPROX(XPR, REF); \
VERIFY(g_called&& #XPR " not properly optimized");
template <int SizeAtCompileType>
void mixingtypes(int size = SizeAtCompileType) {
typedef std::complex<float> CF;
typedef std::complex<double> CD;
typedef Matrix<float, SizeAtCompileType, SizeAtCompileType> Mat_f;
typedef Matrix<double, SizeAtCompileType, SizeAtCompileType> Mat_d;
typedef Matrix<std::complex<float>, SizeAtCompileType, SizeAtCompileType> Mat_cf;
typedef Matrix<std::complex<double>, SizeAtCompileType, SizeAtCompileType> Mat_cd;
typedef Matrix<float, SizeAtCompileType, 1> Vec_f;
typedef Matrix<double, SizeAtCompileType, 1> Vec_d;
typedef Matrix<std::complex<float>, SizeAtCompileType, 1> Vec_cf;
typedef Matrix<std::complex<double>, SizeAtCompileType, 1> Vec_cd;
Mat_f mf = Mat_f::Random(size, size);
Mat_d md = mf.template cast<double>();
// Mat_d rd = md;
Mat_cf mcf = Mat_cf::Random(size, size);
Mat_cd mcd = mcf.template cast<complex<double> >();
Mat_cd rcd = mcd;
Vec_f vf = Vec_f::Random(size, 1);
Vec_d vd = vf.template cast<double>();
Vec_cf vcf = Vec_cf::Random(size, 1);
Vec_cd vcd = vcf.template cast<complex<double> >();
float sf = internal::random<float>();
double sd = internal::random<double>();
complex<float> scf = internal::random<complex<float> >();
complex<double> scd = internal::random<complex<double> >();
mf + mf;
float epsf = std::sqrt(std::numeric_limits<float>::min EIGEN_EMPTY());
double epsd = std::sqrt(std::numeric_limits<double>::min EIGEN_EMPTY());
while (std::abs(sf) < epsf) sf = internal::random<float>();
while (std::abs(sd) < epsd) sd = internal::random<double>();
while (std::abs(scf) < epsf) scf = internal::random<CF>();
while (std::abs(scd) < epsd) scd = internal::random<CD>();
// check scalar products
VERIFY_MIX_SCALAR(vcf * sf, vcf * complex<float>(sf));
VERIFY_MIX_SCALAR(sd * vcd, complex<double>(sd) * vcd);
VERIFY_MIX_SCALAR(vf * scf, vf.template cast<complex<float> >() * scf);
VERIFY_MIX_SCALAR(scd * vd, scd * vd.template cast<complex<double> >());
VERIFY_MIX_SCALAR(vcf * 2, vcf * complex<float>(2));
VERIFY_MIX_SCALAR(vcf * 2.1, vcf * complex<float>(2.1));
VERIFY_MIX_SCALAR(2 * vcf, vcf * complex<float>(2));
VERIFY_MIX_SCALAR(2.1 * vcf, vcf * complex<float>(2.1));
// check scalar quotients
VERIFY_MIX_SCALAR(vcf / sf, vcf / complex<float>(sf));
VERIFY_MIX_SCALAR(vf / scf, vf.template cast<complex<float> >() / scf);
VERIFY_MIX_SCALAR(vf.array() / scf, vf.template cast<complex<float> >().array() / scf);
VERIFY_MIX_SCALAR(scd / vd.array(), scd / vd.template cast<complex<double> >().array());
// check scalar increment
VERIFY_MIX_SCALAR(vcf.array() + sf, vcf.array() + complex<float>(sf));
VERIFY_MIX_SCALAR(sd + vcd.array(), complex<double>(sd) + vcd.array());
VERIFY_MIX_SCALAR(vf.array() + scf, vf.template cast<complex<float> >().array() + scf);
VERIFY_MIX_SCALAR(scd + vd.array(), scd + vd.template cast<complex<double> >().array());
// check scalar subtractions
VERIFY_MIX_SCALAR(vcf.array() - sf, vcf.array() - complex<float>(sf));
VERIFY_MIX_SCALAR(sd - vcd.array(), complex<double>(sd) - vcd.array());
VERIFY_MIX_SCALAR(vf.array() - scf, vf.template cast<complex<float> >().array() - scf);
VERIFY_MIX_SCALAR(scd - vd.array(), scd - vd.template cast<complex<double> >().array());
// check scalar powers
// 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_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
vf.dot(vf);
VERIFY_IS_APPROX(vcf.dot(vf), vcf.dot(vf.template cast<complex<float> >()));
// check diagonal product
VERIFY_IS_APPROX(vf.asDiagonal() * mcf, vf.template cast<complex<float> >().asDiagonal() * mcf);
VERIFY_IS_APPROX(vcd.asDiagonal() * md, vcd.asDiagonal() * md.template cast<complex<double> >());
VERIFY_IS_APPROX(mcf * vf.asDiagonal(), mcf * vf.template cast<complex<float> >().asDiagonal());
VERIFY_IS_APPROX(md * vcd.asDiagonal(), md.template cast<complex<double> >() * vcd.asDiagonal());
// check inner product
VERIFY_IS_APPROX((vf.transpose() * vcf).value(), (vf.template cast<complex<float> >().transpose() * vcf).value());
// check outer product
VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast<complex<float> >() * vcf.transpose()).eval());
// coeff wise product
VERIFY_IS_APPROX((vf * vcf.transpose()).eval(), (vf.template cast<complex<float> >() * vcf.transpose()).eval());
Mat_cd mcd2 = mcd;
VERIFY_IS_APPROX(mcd.array() *= md.array(), mcd2.array() *= md.array().template cast<std::complex<double> >());
// check matrix-matrix products
VERIFY_IS_APPROX(sd * md * mcd, (sd * md).template cast<CD>().eval() * mcd);
VERIFY_IS_APPROX(sd * mcd * md, sd * mcd * md.template cast<CD>());
VERIFY_IS_APPROX(scd * md * mcd, scd * md.template cast<CD>().eval() * mcd);
VERIFY_IS_APPROX(scd * mcd * md, scd * mcd * md.template cast<CD>());
VERIFY_IS_APPROX(sf * mf * mcf, sf * mf.template cast<CF>() * mcf);
VERIFY_IS_APPROX(sf * mcf * mf, sf * mcf * mf.template cast<CF>());
VERIFY_IS_APPROX(scf * mf * mcf, scf * mf.template cast<CF>() * mcf);
VERIFY_IS_APPROX(scf * mcf * mf, scf * mcf * mf.template cast<CF>());
VERIFY_IS_APPROX(sd * md.adjoint() * mcd, (sd * md).template cast<CD>().eval().adjoint() * mcd);
VERIFY_IS_APPROX(sd * mcd.adjoint() * md, sd * mcd.adjoint() * md.template cast<CD>());
VERIFY_IS_APPROX(sd * md.adjoint() * mcd.adjoint(), (sd * md).template cast<CD>().eval().adjoint() * mcd.adjoint());
VERIFY_IS_APPROX(sd * mcd.adjoint() * md.adjoint(), sd * mcd.adjoint() * md.template cast<CD>().adjoint());
VERIFY_IS_APPROX(sd * md * mcd.adjoint(), (sd * md).template cast<CD>().eval() * mcd.adjoint());
VERIFY_IS_APPROX(sd * mcd * md.adjoint(), sd * mcd * md.template cast<CD>().adjoint());
VERIFY_IS_APPROX(sf * mf.adjoint() * mcf, (sf * mf).template cast<CF>().eval().adjoint() * mcf);
VERIFY_IS_APPROX(sf * mcf.adjoint() * mf, sf * mcf.adjoint() * mf.template cast<CF>());
VERIFY_IS_APPROX(sf * mf.adjoint() * mcf.adjoint(), (sf * mf).template cast<CF>().eval().adjoint() * mcf.adjoint());
VERIFY_IS_APPROX(sf * mcf.adjoint() * mf.adjoint(), sf * mcf.adjoint() * mf.template cast<CF>().adjoint());
VERIFY_IS_APPROX(sf * mf * mcf.adjoint(), (sf * mf).template cast<CF>().eval() * mcf.adjoint());
VERIFY_IS_APPROX(sf * mcf * mf.adjoint(), sf * mcf * mf.template cast<CF>().adjoint());
VERIFY_IS_APPROX(sf * mf * vcf, (sf * mf).template cast<CF>().eval() * vcf);
VERIFY_IS_APPROX(scf * mf * vcf, (scf * mf.template cast<CF>()).eval() * vcf);
VERIFY_IS_APPROX(sf * mcf * vf, sf * mcf * vf.template cast<CF>());
VERIFY_IS_APPROX(scf * mcf * vf, scf * mcf * vf.template cast<CF>());
VERIFY_IS_APPROX(sf * vcf.adjoint() * mf, sf * vcf.adjoint() * mf.template cast<CF>().eval());
VERIFY_IS_APPROX(scf * vcf.adjoint() * mf, scf * vcf.adjoint() * mf.template cast<CF>().eval());
VERIFY_IS_APPROX(sf * vf.adjoint() * mcf, sf * vf.adjoint().template cast<CF>().eval() * mcf);
VERIFY_IS_APPROX(scf * vf.adjoint() * mcf, scf * vf.adjoint().template cast<CF>().eval() * mcf);
VERIFY_IS_APPROX(sd * md * vcd, (sd * md).template cast<CD>().eval() * vcd);
VERIFY_IS_APPROX(scd * md * vcd, (scd * md.template cast<CD>()).eval() * vcd);
VERIFY_IS_APPROX(sd * mcd * vd, sd * mcd * vd.template cast<CD>().eval());
VERIFY_IS_APPROX(scd * mcd * vd, scd * mcd * vd.template cast<CD>().eval());
VERIFY_IS_APPROX(sd * vcd.adjoint() * md, sd * vcd.adjoint() * md.template cast<CD>().eval());
VERIFY_IS_APPROX(scd * vcd.adjoint() * md, scd * vcd.adjoint() * md.template cast<CD>().eval());
VERIFY_IS_APPROX(sd * vd.adjoint() * mcd, sd * vd.adjoint().template cast<CD>().eval() * mcd);
VERIFY_IS_APPROX(scd * vd.adjoint() * mcd, scd * vd.adjoint().template cast<CD>().eval() * mcd);
VERIFY_IS_APPROX(sd * vcd.adjoint() * md.template triangularView<Upper>(),
sd * vcd.adjoint() * md.template cast<CD>().eval().template triangularView<Upper>());
VERIFY_IS_APPROX(scd * vcd.adjoint() * md.template triangularView<Lower>(),
scd * vcd.adjoint() * md.template cast<CD>().eval().template triangularView<Lower>());
VERIFY_IS_APPROX(sd * vcd.adjoint() * md.transpose().template triangularView<Upper>(),
sd * vcd.adjoint() * md.transpose().template cast<CD>().eval().template triangularView<Upper>());
VERIFY_IS_APPROX(scd * vcd.adjoint() * md.transpose().template triangularView<Lower>(),
scd * vcd.adjoint() * md.transpose().template cast<CD>().eval().template triangularView<Lower>());
VERIFY_IS_APPROX(sd * vd.adjoint() * mcd.template triangularView<Lower>(),
sd * vd.adjoint().template cast<CD>().eval() * mcd.template triangularView<Lower>());
VERIFY_IS_APPROX(scd * vd.adjoint() * mcd.template triangularView<Upper>(),
scd * vd.adjoint().template cast<CD>().eval() * mcd.template triangularView<Upper>());
VERIFY_IS_APPROX(sd * vd.adjoint() * mcd.transpose().template triangularView<Lower>(),
sd * vd.adjoint().template cast<CD>().eval() * mcd.transpose().template triangularView<Lower>());
VERIFY_IS_APPROX(scd * vd.adjoint() * mcd.transpose().template triangularView<Upper>(),
scd * vd.adjoint().template cast<CD>().eval() * mcd.transpose().template triangularView<Upper>());
// Not supported yet: trmm
// VERIFY_IS_APPROX(sd*mcd*md.template triangularView<Lower>(), sd*mcd*md.template cast<CD>().eval().template
// triangularView<Lower>()); VERIFY_IS_APPROX(scd*mcd*md.template triangularView<Upper>(), scd*mcd*md.template
// cast<CD>().eval().template triangularView<Upper>()); VERIFY_IS_APPROX(sd*md*mcd.template triangularView<Lower>(),
// sd*md.template cast<CD>().eval()*mcd.template triangularView<Lower>()); VERIFY_IS_APPROX(scd*md*mcd.template
// triangularView<Upper>(), scd*md.template cast<CD>().eval()*mcd.template triangularView<Upper>());
// Not supported yet: symv
// VERIFY_IS_APPROX(sd*vcd.adjoint()*md.template selfadjointView<Upper>(), sd*vcd.adjoint()*md.template
// cast<CD>().eval().template selfadjointView<Upper>()); VERIFY_IS_APPROX(scd*vcd.adjoint()*md.template
// selfadjointView<Lower>(), scd*vcd.adjoint()*md.template cast<CD>().eval().template selfadjointView<Lower>());
// VERIFY_IS_APPROX(sd*vd.adjoint()*mcd.template selfadjointView<Lower>(), sd*vd.adjoint().template
// cast<CD>().eval()*mcd.template selfadjointView<Lower>()); VERIFY_IS_APPROX(scd*vd.adjoint()*mcd.template
// selfadjointView<Upper>(), scd*vd.adjoint().template cast<CD>().eval()*mcd.template selfadjointView<Upper>());
// Not supported yet: symm
// VERIFY_IS_APPROX(sd*vcd.adjoint()*md.template selfadjointView<Upper>(), sd*vcd.adjoint()*md.template
// cast<CD>().eval().template selfadjointView<Upper>()); VERIFY_IS_APPROX(scd*vcd.adjoint()*md.template
// selfadjointView<Upper>(), scd*vcd.adjoint()*md.template cast<CD>().eval().template selfadjointView<Upper>());
// VERIFY_IS_APPROX(sd*vd.adjoint()*mcd.template selfadjointView<Upper>(), sd*vd.adjoint().template
// cast<CD>().eval()*mcd.template selfadjointView<Upper>()); VERIFY_IS_APPROX(scd*vd.adjoint()*mcd.template
// selfadjointView<Upper>(), scd*vd.adjoint().template cast<CD>().eval()*mcd.template selfadjointView<Upper>());
rcd.setZero();
VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView<Upper>() = sd * mcd * md),
Mat_cd((sd * mcd * md.template cast<CD>().eval()).template triangularView<Upper>()));
VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView<Upper>() = sd * md * mcd),
Mat_cd((sd * md.template cast<CD>().eval() * mcd).template triangularView<Upper>()));
VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView<Upper>() = scd * mcd * md),
Mat_cd((scd * mcd * md.template cast<CD>().eval()).template triangularView<Upper>()));
VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView<Upper>() = scd * md * mcd),
Mat_cd((scd * md.template cast<CD>().eval() * mcd).template triangularView<Upper>()));
VERIFY_IS_APPROX(md.array() * mcd.array(), md.template cast<CD>().eval().array() * mcd.array());
VERIFY_IS_APPROX(mcd.array() * md.array(), mcd.array() * md.template cast<CD>().eval().array());
VERIFY_IS_APPROX(md.array() + mcd.array(), md.template cast<CD>().eval().array() + mcd.array());
VERIFY_IS_APPROX(mcd.array() + md.array(), mcd.array() + md.template cast<CD>().eval().array());
VERIFY_IS_APPROX(md.array() - mcd.array(), md.template cast<CD>().eval().array() - mcd.array());
VERIFY_IS_APPROX(mcd.array() - md.array(), mcd.array() - md.template cast<CD>().eval().array());
if (mcd.array().abs().minCoeff() > epsd) {
VERIFY_IS_APPROX(md.array() / mcd.array(), md.template cast<CD>().eval().array() / mcd.array());
}
if (md.array().abs().minCoeff() > epsd) {
VERIFY_IS_APPROX(mcd.array() / md.array(), mcd.array() / md.template cast<CD>().eval().array());
}
if (md.array().abs().minCoeff() > epsd || mcd.array().abs().minCoeff() > epsd) {
VERIFY_IS_APPROX(md.array().pow(mcd.array()), md.template cast<CD>().eval().array().pow(mcd.array()));
VERIFY_IS_APPROX(mcd.array().pow(md.array()), mcd.array().pow(md.template cast<CD>().eval().array()));
VERIFY_IS_APPROX(pow(md.array(), mcd.array()), md.template cast<CD>().eval().array().pow(mcd.array()));
VERIFY_IS_APPROX(pow(mcd.array(), md.array()), mcd.array().pow(md.template cast<CD>().eval().array()));
}
rcd = mcd;
VERIFY_IS_APPROX(rcd = md, md.template cast<CD>().eval());
rcd = mcd;
VERIFY_IS_APPROX(rcd += md, mcd + md.template cast<CD>().eval());
rcd = mcd;
VERIFY_IS_APPROX(rcd -= md, mcd - md.template cast<CD>().eval());
rcd = mcd;
VERIFY_IS_APPROX(rcd.array() *= md.array(), mcd.array() * md.template cast<CD>().eval().array());
rcd = mcd;
if (md.array().abs().minCoeff() > epsd) {
VERIFY_IS_APPROX(rcd.array() /= md.array(), mcd.array() / md.template cast<CD>().eval().array());
}
rcd = mcd;
VERIFY_IS_APPROX(rcd.noalias() += md + mcd * md,
mcd + (md.template cast<CD>().eval()) + mcd * (md.template cast<CD>().eval()));
VERIFY_IS_APPROX(rcd.noalias() = md * md, ((md * md).eval().template cast<CD>()));
rcd = mcd;
VERIFY_IS_APPROX(rcd.noalias() += md * md, mcd + ((md * md).eval().template cast<CD>()));
rcd = mcd;
VERIFY_IS_APPROX(rcd.noalias() -= md * md, mcd - ((md * md).eval().template cast<CD>()));
VERIFY_IS_APPROX(rcd.noalias() = mcd + md * md, mcd + ((md * md).eval().template cast<CD>()));
rcd = mcd;
VERIFY_IS_APPROX(rcd.noalias() += mcd + md * md, mcd + mcd + ((md * md).eval().template cast<CD>()));
rcd = mcd;
VERIFY_IS_APPROX(rcd.noalias() -= mcd + md * md, -((md * md).eval().template cast<CD>()));
}
EIGEN_DECLARE_TEST(mixingtypes) {
g_called = false; // Silence -Wunneeded-internal-declaration.
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(mixingtypes<3>());
CALL_SUBTEST_2(mixingtypes<4>());
CALL_SUBTEST_3(mixingtypes<Dynamic>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE)));
CALL_SUBTEST_4(mixingtypes<3>());
CALL_SUBTEST_5(mixingtypes<4>());
CALL_SUBTEST_6(mixingtypes<Dynamic>(internal::random<int>(1, EIGEN_TEST_MAX_SIZE)));
}
}
+37
View File
@@ -0,0 +1,37 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2019 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define TEST_ENABLE_TEMPORARY_TRACKING
#include "main.h"
typedef NestByValue<MatrixXd> CpyMatrixXd;
typedef CwiseBinaryOp<internal::scalar_sum_op<double, double>, const CpyMatrixXd, const CpyMatrixXd> XprType;
XprType get_xpr_with_temps(const MatrixXd& a) {
MatrixXd t1 = a.rowwise().reverse();
MatrixXd t2 = a + a;
return t1.nestByValue() + t2.nestByValue();
}
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::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());
}
}
+101
View File
@@ -0,0 +1,101 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Hauke Heibel <hauke.heibel@gmail.com>
// 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
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#define TEST_ENABLE_TEMPORARY_TRACKING
#include "main.h"
template <int N, typename XprType>
void use_n_times(const XprType& xpr) {
typename internal::nested_eval<XprType, N>::type mat(xpr);
typename XprType::PlainObject res(mat.rows(), mat.cols());
nb_temporaries--; // remove res
res.setZero();
for (int i = 0; i < N; ++i) res += mat;
}
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<internal::remove_all_t<EvalType>, internal::remove_all_t<ReferenceType>>::value;
}
template <typename MatrixType>
void run_nesting_ops_1(const MatrixType& _m) {
typename internal::nested_eval<MatrixType, 2>::type m(_m);
// Make really sure that we are in debug mode!
VERIFY_RAISES_ASSERT(eigen_assert(false));
// The only intention of these tests is to ensure that this code does
// not trigger any asserts or segmentation faults... more to come.
VERIFY_IS_APPROX((m.transpose() * m).diagonal().sum(), (m.transpose() * m).diagonal().sum());
VERIFY_IS_APPROX((m.transpose() * m).diagonal().array().abs().sum(),
(m.transpose() * m).diagonal().array().abs().sum());
VERIFY_IS_APPROX((m.transpose() * m).array().abs().sum(), (m.transpose() * m).array().abs().sum());
}
template <typename MatrixType>
void run_nesting_ops_2(const MatrixType& _m) {
typedef typename MatrixType::Scalar Scalar;
Index rows = _m.rows();
Index cols = _m.cols();
MatrixType m1 = MatrixType::Random(rows, cols);
Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime, ColMajor> m2;
if ((MatrixType::SizeAtCompileTime == Dynamic)) {
VERIFY_EVALUATION_COUNT(use_n_times<1>(m1 + m1 * m1), 1);
VERIFY_EVALUATION_COUNT(use_n_times<10>(m1 + m1 * m1), 1);
VERIFY_EVALUATION_COUNT(use_n_times<1>(m1.template triangularView<Lower>().solve(m1.col(0))), 1);
VERIFY_EVALUATION_COUNT(use_n_times<10>(m1.template triangularView<Lower>().solve(m1.col(0))), 1);
VERIFY_EVALUATION_COUNT(use_n_times<1>(Scalar(2) * m1.template triangularView<Lower>().solve(m1.col(0))),
2); // FIXME could be one by applying the scaling in-place on the solve result
VERIFY_EVALUATION_COUNT(use_n_times<1>(m1.col(0) + m1.template triangularView<Lower>().solve(m1.col(0))),
2); // FIXME could be one by adding m1.col() inplace
VERIFY_EVALUATION_COUNT(use_n_times<10>(m1.col(0) + m1.template triangularView<Lower>().solve(m1.col(0))), 2);
}
{
VERIFY(verify_eval_type<10>(m1, m1));
if (!NumTraits<Scalar>::IsComplex) {
VERIFY(verify_eval_type<3>(2 * m1, 2 * m1));
VERIFY(verify_eval_type<4>(2 * m1, m1));
} else {
VERIFY(verify_eval_type<2>(2 * m1, 2 * m1));
VERIFY(verify_eval_type<3>(2 * m1, m1));
}
VERIFY(verify_eval_type<2>(m1 + m1, m1 + m1));
VERIFY(verify_eval_type<3>(m1 + m1, m1));
VERIFY(verify_eval_type<1>(m1 * m1.transpose(), m2));
VERIFY(verify_eval_type<1>(m1 * (m1 + m1).transpose(), m2));
VERIFY(verify_eval_type<2>(m1 * m1.transpose(), m2));
VERIFY(verify_eval_type<1>(m1 + m1 * m1, m1));
VERIFY(verify_eval_type<1>(m1.template triangularView<Lower>().solve(m1), m1));
VERIFY(verify_eval_type<1>(m1 + m1.template triangularView<Lower>().solve(m1), m1));
}
}
EIGEN_DECLARE_TEST(nesting_ops) {
CALL_SUBTEST_1(run_nesting_ops_1(MatrixXf::Random(25, 25)));
CALL_SUBTEST_2(run_nesting_ops_1(MatrixXcd::Random(25, 25)));
CALL_SUBTEST_3(run_nesting_ops_1(Matrix4f::Random()));
CALL_SUBTEST_4(run_nesting_ops_1(Matrix2d::Random()));
Index s = internal::random<int>(1, EIGEN_TEST_MAX_SIZE);
CALL_SUBTEST_1(run_nesting_ops_2(MatrixXf(s, s)));
CALL_SUBTEST_2(run_nesting_ops_2(MatrixXcd(s, s)));
CALL_SUBTEST_3(run_nesting_ops_2(Matrix4f()));
CALL_SUBTEST_4(run_nesting_ops_2(Matrix2d()));
TEST_SET_BUT_UNUSED_VARIABLE(s)
}
+231
View File
@@ -0,0 +1,231 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// 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"
#include <Eigen/Cholesky>
#include <Eigen/Eigenvalues>
#include <Eigen/LU>
#include <Eigen/QR>
#include <Eigen/SVD>
template <typename MatrixType>
void nomalloc(const MatrixType& m) {
/* this test check no dynamic memory allocation are issued with fixed-size matrices
*/
typedef typename MatrixType::Scalar Scalar;
Index rows = m.rows();
Index cols = m.cols();
MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols);
Scalar s1 = internal::random<Scalar>();
Index r = internal::random<Index>(0, rows - 1), c = internal::random<Index>(0, cols - 1);
VERIFY_IS_APPROX((m1 + m2) * s1, s1 * m1 + s1 * m2);
VERIFY_IS_APPROX((m1 + m2)(r, c), (m1(r, c)) + (m2(r, c)));
VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0, 0, rows, cols)), (m1.array() * m1.array()).matrix());
VERIFY_IS_APPROX((m1 * m1.transpose()) * m2, m1 * (m1.transpose() * m2));
m2.col(0).noalias() = m1 * m1.col(0);
m2.col(0).noalias() -= m1.adjoint() * m1.col(0);
m2.col(0).noalias() -= m1 * m1.row(0).adjoint();
m2.col(0).noalias() -= m1.adjoint() * m1.row(0).adjoint();
m2.row(0).noalias() = m1.row(0) * m1;
m2.row(0).noalias() -= m1.row(0) * m1.adjoint();
m2.row(0).noalias() -= m1.col(0).adjoint() * m1;
m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint();
VERIFY_IS_APPROX(m2, m2);
m2.col(0).noalias() = m1.template triangularView<Upper>() * m1.col(0);
m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.col(0);
m2.col(0).noalias() -= m1.template triangularView<Upper>() * m1.row(0).adjoint();
m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.row(0).adjoint();
m2.row(0).noalias() = m1.row(0) * m1.template triangularView<Upper>();
m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template triangularView<Upper>();
m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template triangularView<Upper>();
m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template triangularView<Upper>();
VERIFY_IS_APPROX(m2, m2);
m2.col(0).noalias() = m1.template selfadjointView<Upper>() * m1.col(0);
m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.col(0);
m2.col(0).noalias() -= m1.template selfadjointView<Upper>() * m1.row(0).adjoint();
m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.row(0).adjoint();
m2.row(0).noalias() = m1.row(0) * m1.template selfadjointView<Upper>();
m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template selfadjointView<Upper>();
m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template selfadjointView<Upper>();
m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template selfadjointView<Upper>();
VERIFY_IS_APPROX(m2, m2);
m2.template selfadjointView<Lower>().rankUpdate(m1.col(0), -1);
m2.template selfadjointView<Upper>().rankUpdate(m1.row(0), -1);
m2.template selfadjointView<Lower>().rankUpdate(m1.col(0), m1.col(0)); // rank-2
// The following fancy matrix-matrix products are not safe yet regarding static allocation
m2.template selfadjointView<Lower>().rankUpdate(m1);
m2 += m2.template triangularView<Upper>() * m1;
m2.template triangularView<Upper>() = m2 * m2;
m1 += m1.template selfadjointView<Lower>() * m2;
VERIFY_IS_APPROX(m2, m2);
}
template <typename Scalar>
void ctms_decompositions() {
const int maxSize = 16;
const int size = 12;
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, 0, maxSize, maxSize> Matrix;
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, 0, maxSize, 1> Vector;
typedef Eigen::Matrix<std::complex<Scalar>, Eigen::Dynamic, Eigen::Dynamic, 0, maxSize, maxSize> ComplexMatrix;
const Matrix A(Matrix::Random(size, size)), B(Matrix::Random(size, size));
Matrix X(size, size);
const ComplexMatrix complexA(ComplexMatrix::Random(size, size));
const Matrix saA = A.adjoint() * A;
const Vector b(Vector::Random(size));
Vector x(size);
// Cholesky module
Eigen::LLT<Matrix> LLT;
LLT.compute(A);
X = LLT.solve(B);
x = LLT.solve(b);
Eigen::LDLT<Matrix> LDLT;
LDLT.compute(A);
X = LDLT.solve(B);
x = LDLT.solve(b);
// Eigenvalues module
Eigen::HessenbergDecomposition<ComplexMatrix> hessDecomp;
hessDecomp.compute(complexA);
Eigen::ComplexSchur<ComplexMatrix> cSchur(size);
cSchur.compute(complexA);
Eigen::ComplexEigenSolver<ComplexMatrix> cEigSolver;
cEigSolver.compute(complexA);
Eigen::EigenSolver<Matrix> eigSolver;
eigSolver.compute(A);
Eigen::SelfAdjointEigenSolver<Matrix> saEigSolver(size);
saEigSolver.compute(saA);
Eigen::Tridiagonalization<Matrix> tridiag;
tridiag.compute(saA);
// LU module
Eigen::PartialPivLU<Matrix> ppLU;
ppLU.compute(A);
X = ppLU.solve(B);
x = ppLU.solve(b);
Eigen::FullPivLU<Matrix> fpLU;
fpLU.compute(A);
X = fpLU.solve(B);
x = fpLU.solve(b);
// QR module
Eigen::HouseholderQR<Matrix> hQR;
hQR.compute(A);
X = hQR.solve(B);
x = hQR.solve(b);
Eigen::ColPivHouseholderQR<Matrix> cpQR;
cpQR.compute(A);
X = cpQR.solve(B);
x = cpQR.solve(b);
Eigen::FullPivHouseholderQR<Matrix> fpQR;
fpQR.compute(A);
// FIXME X = fpQR.solve(B);
x = fpQR.solve(b);
// SVD module
Eigen::JacobiSVD<Matrix, ComputeFullU | ComputeFullV> jSVD;
jSVD.compute(A);
}
void test_zerosized() {
// default constructors:
Eigen::MatrixXd A;
Eigen::VectorXd v;
// explicit zero-sized:
Eigen::ArrayXXd A0(0, 0);
Eigen::ArrayXd v0(0);
// assigning empty objects to each other:
A = A0;
v = v0;
}
template <typename MatrixType>
void test_reference(const MatrixType& m) {
typedef typename MatrixType::Scalar Scalar;
enum { Flag = MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor };
enum { TransposeFlag = !MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor };
Index rows = m.rows(), cols = m.cols();
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Flag> MatrixX;
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, TransposeFlag> MatrixXT;
// Dynamic reference:
typedef Eigen::Ref<const MatrixX> Ref;
typedef Eigen::Ref<const MatrixXT> RefT;
Ref r1(m);
Ref r2(m.block(rows / 3, cols / 4, rows / 2, cols / 2));
RefT r3(m.transpose());
RefT r4(m.topLeftCorner(rows / 2, cols / 2).transpose());
VERIFY_RAISES_ASSERT(RefT r5(m));
VERIFY_RAISES_ASSERT(Ref r6(m.transpose()));
VERIFY_RAISES_ASSERT(Ref r7(Scalar(2) * m));
// Copy constructors shall also never malloc
Ref r8 = r1;
RefT r9 = r3;
// Initializing from a compatible Ref shall also never malloc
Eigen::Ref<const MatrixX, Unaligned, Stride<Dynamic, Dynamic> > r10 = r8, r11 = m;
// Initializing from an incompatible Ref will malloc:
typedef Eigen::Ref<const MatrixX, Aligned> RefAligned;
VERIFY_RAISES_ASSERT(RefAligned r12 = r10);
VERIFY_RAISES_ASSERT(Ref r13 = r10); // r10 has more dynamic strides
}
EIGEN_DECLARE_TEST(nomalloc) {
// create some dynamic objects
Eigen::MatrixXd M1 = MatrixXd::Random(3, 3);
Ref<const MatrixXd> R1 = 2.0 * M1; // Ref requires temporary
// from here on prohibit malloc:
Eigen::internal::set_is_malloc_allowed(false);
// check that our operator new is indeed called:
VERIFY_RAISES_ASSERT(MatrixXd dummy(MatrixXd::Random(3, 3)));
CALL_SUBTEST_1(nomalloc(Matrix<float, 1, 1>()));
CALL_SUBTEST_2(nomalloc(Matrix4d()));
CALL_SUBTEST_3(nomalloc(Matrix<float, 32, 32>()));
// Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms)
CALL_SUBTEST_4(ctms_decompositions<float>());
CALL_SUBTEST_5(test_zerosized());
CALL_SUBTEST_6(test_reference(Matrix<float, 32, 32>()));
CALL_SUBTEST_7(test_reference(R1));
CALL_SUBTEST_8(Ref<MatrixXd> R2 = M1.topRows<2>(); test_reference(R2));
// freeing is now possible
Eigen::internal::set_is_malloc_allowed(true);
}
+325
View File
@@ -0,0 +1,325 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010-2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
// Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename MatrixType>
bool equalsIdentity(const MatrixType& A) {
bool offDiagOK = true;
for (Index i = 0; i < A.rows(); ++i) {
for (Index j = i + 1; j < A.cols(); ++j) {
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 && numext::is_exactly_zero(A(i, j));
}
}
bool diagOK = (A.diagonal().array() == 1).all();
return offDiagOK && diagOK;
}
template <typename VectorType>
void check_extremity_accuracy(const VectorType& v, const typename VectorType::Scalar& low,
const typename VectorType::Scalar& high) {
typedef typename VectorType::Scalar Scalar;
typedef typename VectorType::RealScalar RealScalar;
RealScalar prec = internal::is_same<RealScalar, float>::value ? NumTraits<RealScalar>::dummy_precision() * 10
: NumTraits<RealScalar>::dummy_precision() / 10;
Index size = v.size();
if (size < 20) return;
for (int i = 0; i < size; ++i) {
if (i < 5 || i > size - 6) {
Scalar ref =
(low * RealScalar(size - i - 1)) / RealScalar(size - 1) + (high * RealScalar(i)) / RealScalar(size - 1);
if (std::abs(ref) > 1) {
if (!internal::isApprox(v(i), ref, prec))
std::cout << v(i) << " != " << ref << " ; relative error: " << std::abs((v(i) - ref) / ref)
<< " ; required precision: " << prec << " ; range: " << low << "," << high << " ; i: " << i
<< "\n";
VERIFY(internal::isApprox(
v(i),
(low * RealScalar(size - i - 1)) / RealScalar(size - 1) + (high * RealScalar(i)) / RealScalar(size - 1),
prec));
}
}
}
}
template <typename VectorType>
void testVectorType(const VectorType& base) {
typedef typename VectorType::Scalar Scalar;
typedef typename VectorType::RealScalar RealScalar;
const Index size = base.size();
Scalar high = internal::random<Scalar>(-500, 500);
Scalar low = (size == 1 ? high : internal::random<Scalar>(-500, 500));
if (numext::real(low) > numext::real(high)) std::swap(low, high);
// check low==high
if (internal::random<float>(0.f, 1.f) < 0.05f) low = high;
// check abs(low) >> abs(high)
else if (size > 2 && std::numeric_limits<RealScalar>::max_exponent10 > 0 && internal::random<float>(0.f, 1.f) < 0.1f)
low = -internal::random<Scalar>(1, 2) *
RealScalar(std::pow(RealScalar(10), std::numeric_limits<RealScalar>::max_exponent10 / 2));
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), o(base);
m.setLinSpaced(size, low, high);
o.setEqualSpaced(size, low, step);
if (!NumTraits<Scalar>::IsInteger) {
VectorType n(size);
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));
}
RealScalar range_length = numext::real(high - low);
if ((!NumTraits<Scalar>::IsInteger) || (range_length >= size && (Index(range_length) % (size - 1)) == 0) ||
(Index(range_length + 1) < size && (size % Index(range_length + 1)) == 0)) {
VectorType n(size);
if ((!NumTraits<Scalar>::IsInteger) || (range_length >= size))
for (int i = 0; i < size; ++i) n(i) = size == 1 ? low : (low + ((high - low) * Scalar(i)) / RealScalar(size - 1));
else
for (int i = 0; i < size; ++i)
n(i) = size == 1 ? low : low + Scalar((double(range_length + 1) * double(i)) / double(size));
VERIFY_IS_APPROX(m, n);
// random access version
m = VectorType::LinSpaced(size, low, high);
VERIFY_IS_APPROX(m, n);
VERIFY(internal::isApprox(m(m.size() - 1), high));
VERIFY(size == 1 || internal::isApprox(m(0), low));
VERIFY_IS_EQUAL(m(m.size() - 1), high);
if (!NumTraits<Scalar>::IsInteger) CALL_SUBTEST(check_extremity_accuracy(m, low, high));
}
VERIFY(numext::real(m(m.size() - 1)) <= numext::real(high));
VERIFY((m.array().real() <= numext::real(high)).all());
VERIFY((m.array().real() >= numext::real(low)).all());
VERIFY(numext::real(m(m.size() - 1)) >= numext::real(low));
if (size >= 1) {
VERIFY(internal::isApprox(m(0), low));
VERIFY_IS_EQUAL(m(0), low);
}
// check whether everything works with row and col major vectors
Matrix<Scalar, Dynamic, 1> row_vector(size);
Matrix<Scalar, 1, Dynamic> col_vector(size);
row_vector.setLinSpaced(size, low, high);
col_vector.setLinSpaced(size, low, high);
// when using the extended precision (e.g., FPU) the relative error might exceed 1 bit
// when computing the squared sum in isApprox, thus the 2x factor.
VERIFY(row_vector.isApprox(col_vector.transpose(), RealScalar(2) * NumTraits<Scalar>::epsilon()));
Matrix<Scalar, Dynamic, 1> size_changer(size + 50);
size_changer.setLinSpaced(size, low, high);
VERIFY(size_changer.size() == size);
typedef Matrix<Scalar, 1, 1> ScalarMatrix;
ScalarMatrix scalar;
scalar.setLinSpaced(1, low, high);
VERIFY_IS_APPROX(scalar, ScalarMatrix::Constant(high));
VERIFY_IS_APPROX(ScalarMatrix::LinSpaced(1, low, high), ScalarMatrix::Constant(high));
// regression test for bug 526 (linear vectorized transversal)
if (size > 1 && (!NumTraits<Scalar>::IsInteger)) {
m.tail(size - 1).setLinSpaced(low, high);
VERIFY_IS_APPROX(m(size - 1), high);
}
// regression test for bug 1383 (LinSpaced with empty size/range)
{
Index n0 = VectorType::SizeAtCompileTime == Dynamic ? 0 : VectorType::SizeAtCompileTime;
low = internal::random<Scalar>();
m = VectorType::LinSpaced(n0, low, low - RealScalar(1));
VERIFY(m.size() == n0);
if (VectorType::SizeAtCompileTime == Dynamic) {
VERIFY_IS_EQUAL(VectorType::LinSpaced(n0, 0, Scalar(n0 - 1)).sum(), Scalar(0));
VERIFY_IS_EQUAL(VectorType::LinSpaced(n0, low, low - RealScalar(1)).sum(), Scalar(0));
}
m.setLinSpaced(n0, 0, Scalar(n0 - 1));
VERIFY(m.size() == n0);
m.setLinSpaced(n0, low, low - RealScalar(1));
VERIFY(m.size() == n0);
// empty range only:
VERIFY_IS_APPROX(VectorType::LinSpaced(size, low, low), VectorType::Constant(size, low));
m.setLinSpaced(size, low, low);
VERIFY_IS_APPROX(m, VectorType::Constant(size, low));
if (NumTraits<Scalar>::IsInteger) {
VERIFY_IS_APPROX(VectorType::LinSpaced(size, low, low + Scalar(size - 1)),
VectorType::LinSpaced(size, low + Scalar(size - 1), low).reverse());
if (VectorType::SizeAtCompileTime == Dynamic) {
// Check negative multiplicator path:
for (Index k = 1; k < 5; ++k)
VERIFY_IS_APPROX(VectorType::LinSpaced(size, low, low + Scalar((size - 1) * k)),
VectorType::LinSpaced(size, low + Scalar((size - 1) * k), low).reverse());
// Check negative divisor path:
for (Index k = 1; k < 5; ++k)
VERIFY_IS_APPROX(VectorType::LinSpaced(size * k, low, low + Scalar(size - 1)),
VectorType::LinSpaced(size * k, low + Scalar(size - 1), low).reverse());
}
}
}
// test setUnit()
if (m.size() > 0) {
for (Index k = 0; k < 10; ++k) {
Index i = internal::random<Index>(0, m.size() - 1);
m.setUnit(i);
VERIFY_IS_APPROX(m, VectorType::Unit(m.size(), i));
}
if (VectorType::SizeAtCompileTime == Dynamic) {
Index i = internal::random<Index>(0, 2 * m.size() - 1);
m.setUnit(2 * m.size(), i);
VERIFY_IS_APPROX(m, VectorType::Unit(m.size(), i));
}
}
}
template <typename MatrixType>
void testMatrixType(const MatrixType& m) {
using std::abs;
const Index rows = m.rows();
const Index cols = m.cols();
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
Scalar s1;
do {
s1 = internal::random<Scalar>();
} while (abs(s1) < RealScalar(1e-5) && (!NumTraits<Scalar>::IsInteger));
MatrixType A;
A.setIdentity(rows, cols);
VERIFY(equalsIdentity(A));
VERIFY(equalsIdentity(MatrixType::Identity(rows, cols)));
A = MatrixType::Constant(rows, cols, s1);
Index i = internal::random<Index>(0, rows - 1);
Index j = internal::random<Index>(0, cols - 1);
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, s1)(i, j), s1);
VERIFY_IS_APPROX(MatrixType::Constant(rows, cols, s1).coeff(i, j), s1);
VERIFY_IS_APPROX(A(i, j), s1);
}
template <int>
void bug79() {
// Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79).
VERIFY((MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() <
std::numeric_limits<double>::epsilon());
}
template <int>
void bug1630() {
Array4d x4 = Array4d::LinSpaced(0.0, 1.0);
Array3d x3(Array4d::LinSpaced(0.0, 1.0).head(3));
VERIFY_IS_APPROX(x4.head(3), x3);
}
template <int>
void nullary_overflow() {
// Check possible overflow issue
int n = 60000;
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>
void nullary_internal_logic() {
// check some internal logic
VERIFY((internal::has_nullary_operator<internal::scalar_constant_op<double> >::value));
VERIFY((!internal::has_unary_operator<internal::scalar_constant_op<double> >::value));
VERIFY((!internal::has_binary_operator<internal::scalar_constant_op<double> >::value));
VERIFY((internal::functor_has_linear_access<internal::scalar_constant_op<double> >::ret));
VERIFY((!internal::has_nullary_operator<internal::scalar_identity_op<double> >::value));
VERIFY((!internal::has_unary_operator<internal::scalar_identity_op<double> >::value));
VERIFY((internal::has_binary_operator<internal::scalar_identity_op<double> >::value));
VERIFY((!internal::functor_has_linear_access<internal::scalar_identity_op<double> >::ret));
VERIFY((!internal::has_nullary_operator<internal::linspaced_op<float> >::value));
VERIFY((internal::has_unary_operator<internal::linspaced_op<float> >::value));
VERIFY((!internal::has_binary_operator<internal::linspaced_op<float> >::value));
VERIFY((internal::functor_has_linear_access<internal::linspaced_op<float> >::ret));
// Regression unit test for a weird MSVC bug.
// Search "nullary_wrapper_workaround_msvc" in CoreEvaluators.h for the details.
// See also traits<Ref>::match.
{
MatrixXf A = MatrixXf::Random(3, 3);
Ref<const MatrixXf> R = 2.0 * A;
VERIFY_IS_APPROX(R, A + A);
Ref<const MatrixXf> R1 = MatrixXf::Random(3, 3) + A;
VectorXi V = VectorXi::Random(3);
Ref<const VectorXi> R2 = VectorXi::LinSpaced(3, 1, 3) + V;
VERIFY_IS_APPROX(R2, V + Vector3i(1, 2, 3));
VERIFY((internal::has_nullary_operator<internal::scalar_constant_op<float> >::value));
VERIFY((!internal::has_unary_operator<internal::scalar_constant_op<float> >::value));
VERIFY((!internal::has_binary_operator<internal::scalar_constant_op<float> >::value));
VERIFY((internal::functor_has_linear_access<internal::scalar_constant_op<float> >::ret));
VERIFY((!internal::has_nullary_operator<internal::linspaced_op<int> >::value));
VERIFY((internal::has_unary_operator<internal::linspaced_op<int> >::value));
VERIFY((!internal::has_binary_operator<internal::linspaced_op<int> >::value));
VERIFY((internal::functor_has_linear_access<internal::linspaced_op<int> >::ret));
}
}
EIGEN_DECLARE_TEST(nullary) {
CALL_SUBTEST_1(testMatrixType(Matrix2d()));
CALL_SUBTEST_2(testMatrixType(MatrixXcf(internal::random<int>(1, 300), internal::random<int>(1, 300))));
CALL_SUBTEST_3(testMatrixType(MatrixXf(internal::random<int>(1, 300), internal::random<int>(1, 300))));
for (int i = 0; i < g_repeat * 10; i++) {
CALL_SUBTEST_3(testVectorType(VectorXcd(internal::random<int>(1, 30000))));
CALL_SUBTEST_4(testVectorType(VectorXd(internal::random<int>(1, 30000))));
CALL_SUBTEST_5(testVectorType(Vector4d())); // regression test for bug 232
CALL_SUBTEST_6(testVectorType(Vector3d()));
CALL_SUBTEST_7(testVectorType(VectorXf(internal::random<int>(1, 30000))));
CALL_SUBTEST_8(testVectorType(Vector3f()));
CALL_SUBTEST_8(testVectorType(Vector4f()));
CALL_SUBTEST_8(testVectorType(Matrix<float, 8, 1>()));
CALL_SUBTEST_8(testVectorType(Matrix<float, 1, 1>()));
CALL_SUBTEST_9(testVectorType(VectorXi(internal::random<int>(1, 10))));
CALL_SUBTEST_9(testVectorType(VectorXi(internal::random<int>(9, 300))));
CALL_SUBTEST_9(testVectorType(Matrix<int, 1, 1>()));
}
CALL_SUBTEST_6(bug79<0>());
CALL_SUBTEST_6(bug1630<0>());
CALL_SUBTEST_9(nullary_overflow<0>());
CALL_SUBTEST_10(nullary_internal_logic<0>());
}
+82
View File
@@ -0,0 +1,82 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2018 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
#include <Eigen/SparseCore>
template <int ExpectedDim, typename Xpr>
void check_dim(const Xpr&) {
STATIC_CHECK(Xpr::NumDimensions == ExpectedDim);
}
template <template <typename, int, int> class Object>
void map_num_dimensions() {
typedef Object<double, 1, 1> ArrayScalarType;
typedef Object<double, 2, 1> ArrayVectorType;
typedef Object<double, 1, 2> TransposeArrayVectorType;
typedef Object<double, 2, 2> ArrayType;
typedef Object<double, Eigen::Dynamic, 1> DynamicArrayVectorType;
typedef Object<double, 1, Eigen::Dynamic> DynamicTransposeArrayVectorType;
typedef Object<double, Eigen::Dynamic, Eigen::Dynamic> DynamicArrayType;
STATIC_CHECK(ArrayScalarType::NumDimensions == 0);
STATIC_CHECK(ArrayVectorType::NumDimensions == 1);
STATIC_CHECK(TransposeArrayVectorType::NumDimensions == 1);
STATIC_CHECK(ArrayType::NumDimensions == 2);
STATIC_CHECK(DynamicArrayVectorType::NumDimensions == 1);
STATIC_CHECK(DynamicTransposeArrayVectorType::NumDimensions == 1);
STATIC_CHECK(DynamicArrayType::NumDimensions == 2);
typedef Eigen::Map<ArrayScalarType> ArrayScalarMap;
typedef Eigen::Map<ArrayVectorType> ArrayVectorMap;
typedef Eigen::Map<TransposeArrayVectorType> TransposeArrayVectorMap;
typedef Eigen::Map<ArrayType> ArrayMap;
typedef Eigen::Map<DynamicArrayVectorType> DynamicArrayVectorMap;
typedef Eigen::Map<DynamicTransposeArrayVectorType> DynamicTransposeArrayVectorMap;
typedef Eigen::Map<DynamicArrayType> DynamicArrayMap;
STATIC_CHECK(ArrayScalarMap::NumDimensions == 0);
STATIC_CHECK(ArrayVectorMap::NumDimensions == 1);
STATIC_CHECK(TransposeArrayVectorMap::NumDimensions == 1);
STATIC_CHECK(ArrayMap::NumDimensions == 2);
STATIC_CHECK(DynamicArrayVectorMap::NumDimensions == 1);
STATIC_CHECK(DynamicTransposeArrayVectorMap::NumDimensions == 1);
STATIC_CHECK(DynamicArrayMap::NumDimensions == 2);
}
template <typename Scalar, int Rows, int Cols>
using TArray = Array<Scalar, Rows, Cols>;
template <typename Scalar, int Rows, int Cols>
using TMatrix = Matrix<Scalar, Rows, Cols>;
EIGEN_DECLARE_TEST(num_dimensions) {
int n = 10;
ArrayXXd A(n, n);
CALL_SUBTEST(check_dim<2>(A));
CALL_SUBTEST(check_dim<2>(A.block(1, 1, 2, 2)));
CALL_SUBTEST(check_dim<1>(A.col(1)));
CALL_SUBTEST(check_dim<1>(A.row(1)));
MatrixXd M(n, n);
CALL_SUBTEST(check_dim<0>(M.row(1) * M.col(1)));
SparseMatrix<double> S(n, n);
CALL_SUBTEST(check_dim<2>(S));
CALL_SUBTEST(check_dim<2>(S.block(1, 1, 2, 2)));
CALL_SUBTEST(check_dim<1>(S.col(1)));
CALL_SUBTEST(check_dim<1>(S.row(1)));
SparseVector<double> s(n);
CALL_SUBTEST(check_dim<1>(s));
CALL_SUBTEST(check_dim<1>(s.head(2)));
CALL_SUBTEST(map_num_dimensions<TArray>());
CALL_SUBTEST(map_num_dimensions<TMatrix>());
}
+389
View File
@@ -0,0 +1,389 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2017 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "main.h"
template <typename T, typename U>
bool check_if_equal_or_nans(const T& actual, const U& expected) {
return (numext::equal_strict(actual, expected) || ((numext::isnan)(actual) && (numext::isnan)(expected)));
}
template <typename T, typename U>
bool check_if_equal_or_nans(const std::complex<T>& actual, const std::complex<U>& expected) {
return check_if_equal_or_nans(numext::real(actual), numext::real(expected)) &&
check_if_equal_or_nans(numext::imag(actual), numext::imag(expected));
}
template <typename T, typename U>
bool test_is_equal_or_nans(const T& actual, const U& expected) {
if (check_if_equal_or_nans(actual, expected)) {
return true;
}
// false:
std::cerr << "\n actual = " << actual << "\n expected = " << expected << "\n\n";
return false;
}
#define VERIFY_IS_EQUAL_OR_NANS(a, b) VERIFY(test_is_equal_or_nans(a, b))
template <typename T>
void check_negate() {
Index size = 1000;
for (Index i = 0; i < size; i++) {
T val = i == 0 ? T(0) : internal::random<T>(T(0), NumTraits<T>::highest());
T neg_val = numext::negate(val);
VERIFY_IS_EQUAL(T(val + neg_val), T(0));
VERIFY_IS_EQUAL(numext::negate(neg_val), val);
}
}
template <typename T>
void check_abs() {
typedef typename NumTraits<T>::Real Real;
Real zero(0);
if (NumTraits<T>::IsSigned) VERIFY_IS_EQUAL(numext::abs(numext::negate(T(1))), T(1));
VERIFY_IS_EQUAL(numext::abs(T(0)), T(0));
VERIFY_IS_EQUAL(numext::abs(T(1)), T(1));
for (int k = 0; k < 100; ++k) {
T x = internal::random<T>();
x = x / Real(2);
if (NumTraits<T>::IsSigned) {
VERIFY_IS_EQUAL(numext::abs(x), numext::abs(numext::negate(x)));
VERIFY(numext::abs(numext::negate(x)) >= zero);
}
VERIFY(numext::abs(x) >= zero);
VERIFY_IS_APPROX(numext::abs2(x), numext::abs2(numext::abs(x)));
}
}
template <>
void check_abs<bool>() {
for (bool x : {true, false}) {
VERIFY_IS_EQUAL(numext::abs(x), x);
VERIFY(numext::abs(x) >= false);
VERIFY_IS_EQUAL(numext::abs2(x), numext::abs2(numext::abs(x)));
}
}
template <typename T>
void check_arg() {
typedef typename NumTraits<T>::Real Real;
VERIFY_IS_EQUAL(numext::abs(T(0)), T(0));
VERIFY_IS_EQUAL(numext::abs(T(1)), T(1));
for (int k = 0; k < 100; ++k) {
T x = internal::random<T>();
Real y = numext::arg(x);
VERIFY_IS_APPROX(y, std::arg(x));
}
}
template <typename T>
struct check_sqrt_impl {
static void run() {
for (int i = 0; i < 1000; ++i) {
const T x = numext::abs(internal::random<T>());
const T sqrtx = numext::sqrt(x);
VERIFY_IS_APPROX(sqrtx * sqrtx, x);
}
// Corner cases.
const T zero = T(0);
const T one = T(1);
const T inf = std::numeric_limits<T>::infinity();
const T nan = std::numeric_limits<T>::quiet_NaN();
VERIFY_IS_EQUAL(numext::sqrt(zero), zero);
VERIFY_IS_EQUAL(numext::sqrt(inf), inf);
VERIFY((numext::isnan)(numext::sqrt(nan)));
VERIFY((numext::isnan)(numext::sqrt(-one)));
}
};
template <typename T>
struct check_sqrt_impl<std::complex<T> > {
static void run() {
typedef typename std::complex<T> ComplexT;
for (int i = 0; i < 1000; ++i) {
const ComplexT x = internal::random<ComplexT>();
const ComplexT sqrtx = numext::sqrt(x);
VERIFY_IS_APPROX(sqrtx * sqrtx, x);
}
// Corner cases.
const T zero = T(0);
const T one = T(1);
const T inf = std::numeric_limits<T>::infinity();
const T nan = std::numeric_limits<T>::quiet_NaN();
// Set of corner cases from https://en.cppreference.com/w/cpp/numeric/complex/sqrt
const int kNumCorners = 20;
const ComplexT corners[kNumCorners][2] = {
{ComplexT(zero, zero), ComplexT(zero, zero)}, {ComplexT(-zero, zero), ComplexT(zero, zero)},
{ComplexT(zero, -zero), ComplexT(zero, zero)}, {ComplexT(-zero, -zero), ComplexT(zero, zero)},
{ComplexT(one, inf), ComplexT(inf, inf)}, {ComplexT(nan, inf), ComplexT(inf, inf)},
{ComplexT(one, -inf), ComplexT(inf, -inf)}, {ComplexT(nan, -inf), ComplexT(inf, -inf)},
{ComplexT(-inf, one), ComplexT(zero, inf)}, {ComplexT(inf, one), ComplexT(inf, zero)},
{ComplexT(-inf, -one), ComplexT(zero, -inf)}, {ComplexT(inf, -one), ComplexT(inf, -zero)},
{ComplexT(-inf, nan), ComplexT(nan, inf)}, {ComplexT(inf, nan), ComplexT(inf, nan)},
{ComplexT(zero, nan), ComplexT(nan, nan)}, {ComplexT(one, nan), ComplexT(nan, nan)},
{ComplexT(nan, zero), ComplexT(nan, nan)}, {ComplexT(nan, one), ComplexT(nan, nan)},
{ComplexT(nan, -one), ComplexT(nan, nan)}, {ComplexT(nan, nan), ComplexT(nan, nan)},
};
for (int i = 0; i < kNumCorners; ++i) {
const ComplexT& x = corners[i][0];
const ComplexT sqrtx = corners[i][1];
VERIFY_IS_EQUAL_OR_NANS(numext::sqrt(x), sqrtx);
}
}
};
template <typename T>
void check_sqrt() {
check_sqrt_impl<T>::run();
}
template <typename T>
struct check_rsqrt_impl {
static void run() {
const T zero = T(0);
const T one = T(1);
const T inf = std::numeric_limits<T>::infinity();
const T nan = std::numeric_limits<T>::quiet_NaN();
for (int i = 0; i < 1000; ++i) {
const T x = numext::abs(internal::random<T>());
const T rsqrtx = numext::rsqrt(x);
const T invx = one / x;
VERIFY_IS_APPROX(rsqrtx * rsqrtx, invx);
}
// Corner cases.
VERIFY_IS_EQUAL(numext::rsqrt(zero), inf);
VERIFY_IS_EQUAL(numext::rsqrt(inf), zero);
VERIFY((numext::isnan)(numext::rsqrt(nan)));
VERIFY((numext::isnan)(numext::rsqrt(-one)));
}
};
template <typename T>
struct check_rsqrt_impl<std::complex<T> > {
static void run() {
typedef typename std::complex<T> ComplexT;
const T zero = T(0);
const T one = T(1);
const T inf = std::numeric_limits<T>::infinity();
const T nan = std::numeric_limits<T>::quiet_NaN();
for (int i = 0; i < 1000; ++i) {
const ComplexT x = internal::random<ComplexT>();
const ComplexT invx = ComplexT(one, zero) / x;
const ComplexT rsqrtx = numext::rsqrt(x);
VERIFY_IS_APPROX(rsqrtx * rsqrtx, invx);
}
// GCC and MSVC differ in their treatment of 1/(0 + 0i)
// GCC/clang = (inf, nan)
// MSVC = (nan, nan)
// and 1 / (x + inf i)
// GCC/clang = (0, 0)
// MSVC = (nan, nan)
#if (EIGEN_COMP_GNUC)
{
const int kNumCorners = 20;
const ComplexT corners[kNumCorners][2] = {
// Only consistent across GCC, clang
{ComplexT(zero, zero), ComplexT(zero, zero)},
{ComplexT(-zero, zero), ComplexT(zero, zero)},
{ComplexT(zero, -zero), ComplexT(zero, zero)},
{ComplexT(-zero, -zero), ComplexT(zero, zero)},
{ComplexT(one, inf), ComplexT(inf, inf)},
{ComplexT(nan, inf), ComplexT(inf, inf)},
{ComplexT(one, -inf), ComplexT(inf, -inf)},
{ComplexT(nan, -inf), ComplexT(inf, -inf)},
// Consistent across GCC, clang, MSVC
{ComplexT(-inf, one), ComplexT(zero, inf)},
{ComplexT(inf, one), ComplexT(inf, zero)},
{ComplexT(-inf, -one), ComplexT(zero, -inf)},
{ComplexT(inf, -one), ComplexT(inf, -zero)},
{ComplexT(-inf, nan), ComplexT(nan, inf)},
{ComplexT(inf, nan), ComplexT(inf, nan)},
{ComplexT(zero, nan), ComplexT(nan, nan)},
{ComplexT(one, nan), ComplexT(nan, nan)},
{ComplexT(nan, zero), ComplexT(nan, nan)},
{ComplexT(nan, one), ComplexT(nan, nan)},
{ComplexT(nan, -one), ComplexT(nan, nan)},
{ComplexT(nan, nan), ComplexT(nan, nan)},
};
for (int i = 0; i < kNumCorners; ++i) {
const ComplexT& x = corners[i][0];
const ComplexT rsqrtx = ComplexT(one, zero) / corners[i][1];
VERIFY_IS_EQUAL_OR_NANS(numext::rsqrt(x), rsqrtx);
}
}
#endif
}
};
template <typename T>
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 {
// 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();
// has sign bit
const T neg_zero = numext::negate(pos_zero);
const T neg_one = numext::negate(pos_one);
const T neg_inf = numext::negate(pos_inf);
const T neg_nan = numext::negate(pos_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 check_all_pass = check_all(non_negative_values, false_mask);
check_all_pass = check_all_pass && check_all(negative_values, (NumTraits<T>::IsSigned ? true_mask : false_mask));
VERIFY(check_all_pass);
}
};
template <typename T>
void check_signbit() {
check_signbit_impl<T>::run();
}
template <typename T>
void check_shift() {
using SignedT = typename numext::get_integer_by_size<sizeof(T)>::signed_type;
using UnsignedT = typename numext::get_integer_by_size<sizeof(T)>::unsigned_type;
constexpr int kNumBits = CHAR_BIT * sizeof(T);
for (int i = 0; i < 1000; ++i) {
const T a = internal::random<T>();
for (int s = 1; s < kNumBits; s++) {
T a_bsll = numext::logical_shift_left(a, s);
T a_bsll_ref = a << s;
VERIFY_IS_EQUAL(a_bsll, a_bsll_ref);
T a_bsrl = numext::logical_shift_right(a, s);
T a_bsrl_ref = numext::bit_cast<T, UnsignedT>(numext::bit_cast<UnsignedT, T>(a) >> s);
VERIFY_IS_EQUAL(a_bsrl, a_bsrl_ref);
T a_bsra = numext::arithmetic_shift_right(a, s);
T a_bsra_ref = numext::bit_cast<T, SignedT>(numext::bit_cast<SignedT, T>(a) >> s);
VERIFY_IS_EQUAL(a_bsra, a_bsra_ref);
}
}
}
EIGEN_DECLARE_TEST(numext) {
for (int k = 0; k < g_repeat; ++k) {
CALL_SUBTEST(check_negate<signed char>());
CALL_SUBTEST(check_negate<unsigned char>());
CALL_SUBTEST(check_negate<short>());
CALL_SUBTEST(check_negate<unsigned short>());
CALL_SUBTEST(check_negate<int>());
CALL_SUBTEST(check_negate<unsigned int>());
CALL_SUBTEST(check_negate<long>());
CALL_SUBTEST(check_negate<unsigned long>());
CALL_SUBTEST(check_negate<half>());
CALL_SUBTEST(check_negate<bfloat16>());
CALL_SUBTEST(check_negate<float>());
CALL_SUBTEST(check_negate<double>());
CALL_SUBTEST(check_negate<long double>());
CALL_SUBTEST(check_negate<std::complex<float> >());
CALL_SUBTEST(check_negate<std::complex<double> >());
CALL_SUBTEST(check_abs<bool>());
CALL_SUBTEST(check_abs<signed char>());
CALL_SUBTEST(check_abs<unsigned char>());
CALL_SUBTEST(check_abs<short>());
CALL_SUBTEST(check_abs<unsigned short>());
CALL_SUBTEST(check_abs<int>());
CALL_SUBTEST(check_abs<unsigned int>());
CALL_SUBTEST(check_abs<long>());
CALL_SUBTEST(check_abs<unsigned long>());
CALL_SUBTEST(check_abs<half>());
CALL_SUBTEST(check_abs<bfloat16>());
CALL_SUBTEST(check_abs<float>());
CALL_SUBTEST(check_abs<double>());
CALL_SUBTEST(check_abs<long double>());
CALL_SUBTEST(check_abs<std::complex<float> >());
CALL_SUBTEST(check_abs<std::complex<double> >());
CALL_SUBTEST(check_arg<std::complex<float> >());
CALL_SUBTEST(check_arg<std::complex<double> >());
CALL_SUBTEST(check_sqrt<float>());
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>());
CALL_SUBTEST(check_shift<int8_t>());
CALL_SUBTEST(check_shift<int16_t>());
CALL_SUBTEST(check_shift<int32_t>());
CALL_SUBTEST(check_shift<int64_t>());
CALL_SUBTEST(check_shift<uint8_t>());
CALL_SUBTEST(check_shift<uint16_t>());
CALL_SUBTEST(check_shift<uint32_t>());
CALL_SUBTEST(check_shift<uint64_t>());
}
}

Some files were not shown because too many files have changed in this diff Show More