initial commit
This commit is contained in:
+204
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_;
|
||||
};
|
||||
Vendored
+33
@@ -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
@@ -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>());
|
||||
}
|
||||
Vendored
+236
@@ -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>());
|
||||
}
|
||||
+1432
File diff suppressed because it is too large
Load Diff
+349
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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>());
|
||||
}
|
||||
Vendored
+177
@@ -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
@@ -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());
|
||||
}
|
||||
}
|
||||
Vendored
+88
@@ -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());
|
||||
}
|
||||
Vendored
+178
@@ -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> >());
|
||||
}
|
||||
}
|
||||
Vendored
+381
@@ -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
@@ -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>()));
|
||||
}
|
||||
Vendored
+7
@@ -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); }
|
||||
Vendored
+7
@@ -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
@@ -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&);
|
||||
Vendored
+500
@@ -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
@@ -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>()) );
|
||||
}
|
||||
Vendored
+74
@@ -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
@@ -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
@@ -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
@@ -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>()));
|
||||
}
|
||||
}
|
||||
Vendored
+82
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
Vendored
+125
@@ -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>()));
|
||||
}
|
||||
}
|
||||
Vendored
+79
@@ -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";
|
||||
}
|
||||
Vendored
+172
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
Vendored
+102
@@ -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))));
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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>());
|
||||
}
|
||||
Vendored
+60
@@ -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
|
||||
}
|
||||
Vendored
+168
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
+541
@@ -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
@@ -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));
|
||||
}
|
||||
Vendored
+209
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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>()));
|
||||
}
|
||||
}
|
||||
Vendored
+447
@@ -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) );
|
||||
}
|
||||
Vendored
+161
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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>());
|
||||
}
|
||||
Vendored
+141
@@ -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()));
|
||||
}
|
||||
}
|
||||
Vendored
+63
@@ -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
@@ -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));
|
||||
}
|
||||
Vendored
+81
@@ -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);
|
||||
}
|
||||
}
|
||||
Vendored
+215
@@ -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
@@ -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
@@ -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>());
|
||||
}
|
||||
Vendored
+36
@@ -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> >());
|
||||
}
|
||||
Vendored
+260
@@ -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());
|
||||
}
|
||||
}
|
||||
Vendored
+942
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
Vendored
+275
@@ -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
@@ -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
@@ -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';
|
||||
}
|
||||
}
|
||||
Vendored
+533
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
Vendored
+231
@@ -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);
|
||||
}
|
||||
Vendored
+325
@@ -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
@@ -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>());
|
||||
}
|
||||
Vendored
+389
@@ -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
Reference in New Issue
Block a user