Compare commits

...

19 Commits

Author SHA1 Message Date
David Tellenbach
3e819d83bf Before 3.4 branch 2021-04-18 23:36:14 +02:00
Antonio Sanchez
69adf26aa3 Modify googlehash use to account for namespace issues.
The namespace declaration for googlehash is a configurable macro that
can be disabled.  In particular, it is disabled within google, causing
compile errors since `dense_hash_map`/`sparse_hash_map` are then in
the global namespace instead of in `::google`.

Here we play a bit of gynastics to allow for both `google::*_hash_map`
and `*_hash_map`, while limiting namespace polution.  Symbols within
the `::google` namespace are imported into `Eigen::google`.

We also remove checks based on `_SPARSE_HASH_MAP_H_`, as this is
fragile, and instead require `EIGEN_GOOGLEHASH_SUPPORT` to be
defined.
2021-04-12 19:00:39 -07:00
Christoph Hertzberg
9357feedc7 Avoid using uninitialized inputs and if available, use slightly more efficient movsd instruction for pset1<Packet2cf>. 2021-04-13 01:36:59 +02:00
Rasmus Munk Larsen
a2c0542010 Fix typo in TensorDimensions.h 2021-04-12 18:59:56 +00:00
Rohit Santhanam
dfd6720d82 Fix for float16 GPU unit test. 2021-04-12 10:19:06 +00:00
Christoph Hertzberg
1e1c8a735c Use EIGEN_HAS_CXX11 and EIGEN_COMP_CXXVER macros to detect C++ version for std::result_of and std::invoke_result.
Fixes #2209
2021-04-12 01:26:15 +00:00
Jens Wehner
f6fc66aa75 fixed doxygen for unsupported iterative solver module 2021-04-11 16:26:14 +00:00
Christoph Hertzberg
d58678069c Make iterators default constructible and assignable, by making... 2021-04-09 17:03:28 +00:00
Rohit Santhanam
2859db0220 This fixes an issue where the compiler was not choosing the GPU specific specialization of ScanLauncher.
The issue was discovered when the GPU scan unit test was run and resulted in a segmentation fault.

The segmantation fault occurred because the unit test allocated GPU memory and passed a pointer to that memory to the computation that it presumed would execute on the GPU.

But because of the issue, the computation was scheduled to execute on the CPU so a situation was constructed where the CPU attempted to access a GPU memory location.

The fix expands the GPU specific ScanLauncher specialization to handle cases where vectorization is enabled.

Previously, the GPU specialization is chosen only if Vectorization is not used.
2021-04-08 15:14:48 +00:00
Antonio Sanchez
fcb5106c6e Scaled epsilon the wrong way.
Should have been 0.5 to widen the bounds, since this is inverse
precision.  Setting to 0.5, however, leads to many more failing
tests at Google, so reverting to 1 for now.
2021-04-07 15:08:39 -07:00
Christoph Hertzberg
6197ce1a35 Replace -2147483648 by -0.0f or -0.0 constants (this should fix #2189).
Also, remove unnecessary `pgather` operations.
2021-04-07 11:25:27 +00:00
Rasmus Munk Larsen
22edb46823 Align local arrays to Packet boundary. 2021-04-06 16:22:36 +00:00
Antonio Sanchez
ace7f132ed Fix clang tidy warnings in AnnoyingScalar.
Clang-tidy complains that full specializations in headers can cause ODR
violations.  Marked these as `inline` to fix.

It also complains about renaming arguments in specializations.  Set the
argument names to match.
2021-04-05 12:49:38 -07:00
Antonio Sanchez
90187a33e1 Fix SelfAdjoingEigenSolver (#2191)
Adjust the relaxation step to use the condition
```
abs(subdiag[i]) <= epsilon * sqrt(abs(diag[i]) + abs(diag[i+1]))
```
for setting the subdiagonal entry to zero.

Also adjust Wilkinson shift for small `e = subdiag[end-1]` -
I couldn't find a reference for the original, and it was not
consistent with the Wilkinson definition.

Fixes #2191.
2021-04-05 11:19:09 -07:00
Rasmus Munk Larsen
3ddc0974ce Fix two bugs in commit 2021-04-02 22:06:27 +00:00
Chip Kerchner
c24bee6120 Fix address of temporary object errors in clang11.
This fixes the problem with taking the address of temporary objects which clang11 treats as errors.
2021-04-02 16:27:08 +00:00
David Tellenbach
e4233b6e3d Add CI infrastructure for pre-merge smoke tests.
This patch adds pre-merge smoke tests for x86 Linux using gcc-10 and clang-10.

Closes #2188.
2021-04-01 00:08:37 +00:00
David Tellenbach
ae95b74af9 Add CMake infrastructure for smoke testing
Necessary CMake changes to implement pre-merge smoke tests
running via CI.
2021-03-31 22:09:00 +00:00
Rasmus Munk Larsen
5bbc9cea93 Add an info() method to the SVDBase class to make it possible to tell the user that the computation failed, possibly due to invalid input.
Make Jacobi and divide-and-conquer fail fast and return info() == InvalidInput if the matrix contains NaN or +/-Inf.
2021-03-31 21:09:19 +00:00
31 changed files with 566 additions and 149 deletions

View File

@@ -8,6 +8,8 @@
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
stages:
- buildsmoketests
- smoketests
- build
- test
@@ -16,5 +18,6 @@ variables:
EIGEN_CI_CMAKE_GENEATOR: "Ninja"
include:
- "/ci/smoketests.gitlab-ci.yml"
- "/ci/build.gitlab-ci.yml"
- "/ci/test.gitlab-ci.yml"

View File

@@ -556,7 +556,7 @@ template<typename Packet> EIGEN_DEVICE_FUNC inline Packet
peven_mask(const Packet& /*a*/) {
typedef typename unpacket_traits<Packet>::type Scalar;
const size_t n = unpacket_traits<Packet>::size;
Scalar elements[n];
EIGEN_ALIGN_TO_BOUNDARY(sizeof(Packet)) Scalar elements[n];
for(size_t i = 0; i < n; ++i) {
memset(elements+i, ((i & 1) == 0 ? 0xff : 0), sizeof(Scalar));
}
@@ -731,7 +731,7 @@ EIGEN_DEVICE_FUNC inline typename unpacket_traits<Packet>::type
predux_helper(const Packet& a, Op op) {
typedef typename unpacket_traits<Packet>::type Scalar;
const size_t n = unpacket_traits<Packet>::size;
Scalar elements[n];
EIGEN_ALIGN_TO_BOUNDARY(sizeof(Packet)) Scalar elements[n];
pstoreu<Scalar>(elements, a);
for(size_t k = n / 2; k > 0; k /= 2) {
for(size_t i = 0; i < k; ++i) {

View File

@@ -7,6 +7,9 @@
// Public License v. 2.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_STLITERATORS_H
#define EIGEN_STLITERATORS_H
namespace Eigen {
namespace internal {
@@ -30,10 +33,10 @@ public:
typedef Index difference_type;
typedef std::random_access_iterator_tag iterator_category;
indexed_based_stl_iterator_base() : mp_xpr(0), m_index(0) {}
indexed_based_stl_iterator_base(XprType& xpr, Index index) : mp_xpr(&xpr), m_index(index) {}
indexed_based_stl_iterator_base() EIGEN_NO_THROW : mp_xpr(0), m_index(0) {}
indexed_based_stl_iterator_base(XprType& xpr, Index index) EIGEN_NO_THROW : mp_xpr(&xpr), m_index(index) {}
indexed_based_stl_iterator_base(const non_const_iterator& other)
indexed_based_stl_iterator_base(const non_const_iterator& other) EIGEN_NO_THROW
: mp_xpr(other.mp_xpr), m_index(other.m_index)
{}
@@ -190,17 +193,17 @@ public:
typedef typename internal::conditional<bool(is_lvalue), value_type&, const value_type&>::type reference;
pointer_based_stl_iterator() : m_ptr(0) {}
pointer_based_stl_iterator(XprType& xpr, Index index) : m_incr(xpr.innerStride())
pointer_based_stl_iterator() EIGEN_NO_THROW : m_ptr(0) {}
pointer_based_stl_iterator(XprType& xpr, Index index) EIGEN_NO_THROW : m_incr(xpr.innerStride())
{
m_ptr = xpr.data() + index * m_incr.value();
}
pointer_based_stl_iterator(const non_const_iterator& other)
pointer_based_stl_iterator(const non_const_iterator& other) EIGEN_NO_THROW
: m_ptr(other.m_ptr), m_incr(other.m_incr)
{}
pointer_based_stl_iterator& operator=(const non_const_iterator& other)
pointer_based_stl_iterator& operator=(const non_const_iterator& other) EIGEN_NO_THROW
{
m_ptr = other.m_ptr;
m_incr.setValue(other.m_incr);
@@ -456,3 +459,5 @@ inline typename DenseBase<Derived>::const_iterator DenseBase<Derived>::cend() co
}
} // namespace Eigen
#endif // EIGEN_STLITERATORS_H

View File

@@ -139,8 +139,8 @@ EIGEN_STRONG_INLINE Packet2cf pload2(const std::complex<float>* from0, const std
__asm__ ("xxpermdi %x0, %x2, %x1, 0" : "=wa" (res0) : "wa" (res0), "wa" (res1));
#endif
#else
*((std::complex<float> *)&res0[0]) = *from0;
*((std::complex<float> *)&res1[0]) = *from1;
*reinterpret_cast<std::complex<float> *>(&res0) = *from0;
*reinterpret_cast<std::complex<float> *>(&res1) = *from1;
res0 = vec_perm(res0, res1, p16uc_TRANSPOSE64_HI);
#endif
return Packet2cf(res0);

View File

@@ -486,19 +486,28 @@ struct dhs_cpack {
if(((StorageOrder == ColMajor) && UseLhs) || (((StorageOrder == RowMajor) && !UseLhs)))
{
if (UseLhs) {
cblock.packet[0] = pload<PacketC>(&lhs(j + 0, i));
cblock.packet[1] = pload<PacketC>(&lhs(j + 2, i));
cblock.packet[0] = lhs.template loadPacket<PacketC>(j + 0, i);
cblock.packet[1] = lhs.template loadPacket<PacketC>(j + 2, i);
} else {
cblock.packet[0] = pload<PacketC>(&lhs(i, j + 0));
cblock.packet[1] = pload<PacketC>(&lhs(i, j + 2));
cblock.packet[0] = lhs.template loadPacket<PacketC>(i, j + 0);
cblock.packet[1] = lhs.template loadPacket<PacketC>(i, j + 2);
}
} else {
const std::complex<Scalar> *lhs0, *lhs1;
if (UseLhs) {
cblock.packet[0] = pload2(&lhs(j + 0, i), &lhs(j + 1, i));
cblock.packet[1] = pload2(&lhs(j + 2, i), &lhs(j + 3, i));
lhs0 = &lhs(j + 0, i);
lhs1 = &lhs(j + 1, i);
cblock.packet[0] = pload2(lhs0, lhs1);
lhs0 = &lhs(j + 2, i);
lhs1 = &lhs(j + 3, i);
cblock.packet[1] = pload2(lhs0, lhs1);
} else {
cblock.packet[0] = pload2(&lhs(i, j + 0), &lhs(i, j + 1));
cblock.packet[1] = pload2(&lhs(i, j + 2), &lhs(i, j + 3));
lhs0 = &lhs(i, j + 0);
lhs1 = &lhs(i, j + 1);
cblock.packet[0] = pload2(lhs0, lhs1);
lhs0 = &lhs(i, j + 2);
lhs1 = &lhs(i, j + 3);
cblock.packet[1] = pload2(lhs0, lhs1);
}
}
@@ -859,8 +868,8 @@ struct dhs_cpack<double, Index, DataMapper, Packet, PacketC, StorageOrder, Conju
PacketBlock<Packet,1> blockr, blocki;
PacketBlock<PacketC,2> cblock;
cblock.packet[0] = pload<PacketC>(&lhs(j + 0, i));
cblock.packet[1] = pload<PacketC>(&lhs(j + 1, i));
cblock.packet[0] = lhs.template loadPacket<PacketC>(j + 0, i);
cblock.packet[1] = lhs.template loadPacket<PacketC>(j + 1, i);
blockr.packet[0] = vec_perm(cblock.packet[0].v, cblock.packet[1].v, p16uc_GETREAL64);
blocki.packet[0] = vec_perm(cblock.packet[0].v, cblock.packet[1].v, p16uc_GETIMAG64);
@@ -1100,7 +1109,7 @@ EIGEN_STRONG_INLINE void pgerc(PacketBlock<Packet,N>* accReal, PacketBlock<Packe
template<typename Scalar, typename Packet>
EIGEN_STRONG_INLINE Packet ploadLhs(const Scalar* lhs)
{
return *((Packet *)lhs);
return *reinterpret_cast<Packet *>(const_cast<Scalar *>(lhs));
}
// Zero the accumulator on PacketBlock.
@@ -1799,24 +1808,6 @@ EIGEN_STRONG_INLINE void MICRO_COMPLEX_EXTRA_COL(
else EIGEN_UNUSED_VARIABLE(rhs_ptr_imag);
}
template<typename Scalar, typename Packetc, typename Index, const Index accCols>
EIGEN_STRONG_INLINE void pstore_add_half(std::complex<Scalar>* to, Packetc &from)
{
#ifdef __VSX__
Packetc from2;
#ifndef _BIG_ENDIAN
__asm__ ("xxswapd %x0, %x0" : : "wa" (from.v));
#endif
__asm__ ("lxsdx %x0,%y1" : "=wa" (from2.v) : "Z" (*to));
from2 += from;
__asm__ ("stxsdx %x0,%y1" : : "wa" (from2.v), "Z" (*to));
#else
std::complex<Scalar> mem[accColsC];
pstoreu<std::complex<Scalar> >(mem, from);
*to += *mem;
#endif
}
template<typename Scalar, typename Packet, typename Packetc, typename DataMapper, typename Index, const Index accRows, const Index accCols, bool ConjugateLhs, bool ConjugateRhs, bool LhsIsReal, bool RhsIsReal>
EIGEN_STRONG_INLINE void gemm_complex_extra_col(
const DataMapper& res,
@@ -1886,12 +1877,12 @@ EIGEN_STRONG_INLINE void gemm_complex_extra_col(
if ((sizeof(Scalar) == sizeof(float)) && (remaining_rows == 1))
{
pstore_add_half<Scalar, Packetc, Index, accCols>(&res(row + 0, col + 0), acc0.packet[0]);
res(row + 0, col + 0) += pfirst<Packetc>(acc0.packet[0]);
} else {
acc0.packet[0] += res.template loadPacket<Packetc>(row + 0, col + 0);
res.template storePacketBlock<Packetc,1>(row + 0, col + 0, acc0);
if(remaining_rows > accColsC) {
pstore_add_half<Scalar, Packetc, Index, accCols>(&res(row + accColsC, col + 0), acc1.packet[0]);
res(row + accColsC, col + 0) += pfirst<Packetc>(acc1.packet[0]);
}
}
}
@@ -1997,7 +1988,7 @@ asm("#gemm_complex begin");
if ((sizeof(Scalar) == sizeof(float)) && (remaining_rows == 1))
{
for(Index j = 0; j < 4; j++) {
pstore_add_half<Scalar, Packetc, Index, accCols>(&res(row + 0, col + j), acc0.packet[j]);
res(row + 0, col + j) += pfirst<Packetc>(acc0.packet[j]);
}
} else {
for(Index j = 0; j < 4; j++) {
@@ -2005,7 +1996,7 @@ asm("#gemm_complex begin");
acc2.packet[0] = res.template loadPacket<Packetc>(row + 0, col + j) + acc0.packet[j];
res.template storePacketBlock<Packetc,1>(row + 0, col + j, acc2);
if(remaining_rows > accColsC) {
pstore_add_half<Scalar, Packetc, Index, accCols>(&res(row + accColsC, col + j), acc1.packet[j]);
res(row + accColsC, col + j) += pfirst<Packetc>(acc1.packet[j]);
}
}
}

View File

@@ -214,7 +214,7 @@ EIGEN_STRONG_INLINE void bcouple_common<Packet2d, Packet1cd>(PacketBlock<Packet2
template<typename Scalar, typename Packet>
EIGEN_STRONG_INLINE Packet ploadRhs(const Scalar* rhs)
{
return *((Packet *)rhs);
return *reinterpret_cast<Packet *>(const_cast<Scalar *>(rhs));
}
} // end namespace internal

View File

@@ -113,19 +113,13 @@ template<> EIGEN_STRONG_INLINE Packet2cf ploadu<Packet2cf>(const std::complex<fl
template<> EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>& from)
{
Packet2cf res;
#if EIGEN_GNUC_AT_MOST(4,2)
// Workaround annoying "may be used uninitialized in this function" warning with gcc 4.2
res.v = _mm_loadl_pi(_mm_set1_ps(0.0f), reinterpret_cast<const __m64*>(&from));
#elif EIGEN_GNUC_AT_LEAST(4,6)
// Suppress annoying "may be used uninitialized in this function" warning with gcc >= 4.6
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
res.v = _mm_loadl_pi(res.v, (const __m64*)&from);
#pragma GCC diagnostic pop
#ifdef EIGEN_VECTORIZE_SSE3
res.v = _mm_castpd_ps(_mm_loaddup_pd(reinterpret_cast<double const*>(&from)));
#else
res.v = _mm_loadl_pi(res.v, (const __m64*)&from);
res.v = _mm_castpd_ps(_mm_load_sd(reinterpret_cast<double const*>(&from)));
res.v = _mm_movelh_ps(res.v, res.v);
#endif
return Packet2cf(_mm_movelh_ps(res.v,res.v));
return res;
}
template<> EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex<float>* from) { return pset1<Packet2cf>(*from); }

View File

@@ -16,8 +16,8 @@
//------------------------------------------------------------------------------------------
#define EIGEN_WORLD_VERSION 3
#define EIGEN_MAJOR_VERSION 4
#define EIGEN_MINOR_VERSION 99
#define EIGEN_MAJOR_VERSION 3
#define EIGEN_MINOR_VERSION 90
#define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \
(EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \
@@ -684,8 +684,7 @@
// Does the compiler support result_of?
// result_of was deprecated in c++17 and removed in c++ 20
#ifndef EIGEN_HAS_STD_RESULT_OF
#if EIGEN_MAX_CPP_VER >= 11 && \
(defined(__cplusplus) && __cplusplus >= 201103L && __cplusplus < 201703L)
#if EIGEN_HAS_CXX11 && EIGEN_COMP_CXXVER < 17
#define EIGEN_HAS_STD_RESULT_OF 1
#else
#define EIGEN_HAS_STD_RESULT_OF 0
@@ -704,8 +703,7 @@
#endif // EIGEN_HAS_STD_HASH
#ifndef EIGEN_HAS_STD_INVOKE_RESULT
#if EIGEN_MAX_CPP_VER >= 17 && \
(defined(__cplusplus) && __cplusplus >= 201703L)
#if EIGEN_MAX_CPP_VER >= 17 && EIGEN_COMP_CXXVER >= 17
#define EIGEN_HAS_STD_INVOKE_RESULT 1
#else
#define EIGEN_HAS_STD_INVOKE_RESULT 0

View File

@@ -136,15 +136,14 @@ template<typename T, int Value> class variable_if_dynamic
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EIGEN_CONSTEXPR
operator T() const { return T(Value); }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
void setValue(T) const {}
void setValue(T v) const { EIGEN_ONLY_USED_FOR_DEBUG(v); eigen_assert(v == T(Value)); }
};
template<typename T> class variable_if_dynamic<T, Dynamic>
{
T m_value;
EIGEN_DEVICE_FUNC variable_if_dynamic() { eigen_assert(false); }
public:
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T value) : m_value(value) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T value = 0) EIGEN_NO_THROW : m_value(value) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T value() const { return m_value; }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator T() const { return m_value; }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; }

View File

@@ -498,8 +498,6 @@ template<typename MatrixType, typename DiagType, typename SubDiagType>
EIGEN_DEVICE_FUNC
ComputationInfo computeFromTridiagonal_impl(DiagType& diag, SubDiagType& subdiag, const Index maxIterations, bool computeEigenvectors, MatrixType& eivec)
{
EIGEN_USING_STD(abs);
ComputationInfo info;
typedef typename MatrixType::Scalar Scalar;
@@ -510,15 +508,23 @@ ComputationInfo computeFromTridiagonal_impl(DiagType& diag, SubDiagType& subdiag
typedef typename DiagType::RealScalar RealScalar;
const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
const RealScalar precision = RealScalar(2)*NumTraits<RealScalar>::epsilon();
const RealScalar precision_inv = RealScalar(1)/NumTraits<RealScalar>::epsilon();
while (end>0)
{
for (Index i = start; i<end; ++i)
if (internal::isMuchSmallerThan(abs(subdiag[i]),(abs(diag[i])+abs(diag[i+1])),precision) || abs(subdiag[i]) <= considerAsZero)
subdiag[i] = 0;
for (Index i = start; i<end; ++i) {
if (numext::abs(subdiag[i]) < considerAsZero) {
subdiag[i] = RealScalar(0);
} else {
// abs(subdiag[i]) <= epsilon * sqrt(abs(diag[i]) + abs(diag[i+1]))
// Scaled to prevent underflows.
const RealScalar scaled_subdiag = precision_inv * subdiag[i];
if (scaled_subdiag * scaled_subdiag <= (numext::abs(diag[i])+numext::abs(diag[i+1]))) {
subdiag[i] = RealScalar(0);
}
}
}
// find the largest unreduced block
// find the largest unreduced block at the end of the matrix.
while (end>0 && subdiag[end-1]==RealScalar(0))
{
end--;
@@ -821,32 +827,38 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
}
namespace internal {
// Francis implicit QR step.
template<int StorageOrder,typename RealScalar, typename Scalar, typename Index>
EIGEN_DEVICE_FUNC
static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n)
{
EIGEN_USING_STD(abs);
// Wilkinson Shift.
RealScalar td = (diag[end-1] - diag[end])*RealScalar(0.5);
RealScalar e = subdiag[end-1];
// Note that thanks to scaling, e^2 or td^2 cannot overflow, however they can still
// underflow thus leading to inf/NaN values when using the following commented code:
// RealScalar e2 = numext::abs2(subdiag[end-1]);
// RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2));
// RealScalar e2 = numext::abs2(subdiag[end-1]);
// RealScalar mu = diag[end] - e2 / (td + (td>0 ? 1 : -1) * sqrt(td*td + e2));
// This explain the following, somewhat more complicated, version:
RealScalar mu = diag[end];
if(td==RealScalar(0))
mu -= abs(e);
else
{
RealScalar e2 = numext::abs2(subdiag[end-1]);
RealScalar h = numext::hypot(td,e);
if(e2==RealScalar(0)) mu -= (e / (td + (td>RealScalar(0) ? RealScalar(1) : RealScalar(-1)))) * (e / h);
else mu -= e2 / (td + (td>RealScalar(0) ? h : -h));
if(td==RealScalar(0)) {
mu -= numext::abs(e);
} else if (e != RealScalar(0)) {
const RealScalar e2 = numext::abs2(e);
const RealScalar h = numext::hypot(td,e);
if(e2 == RealScalar(0)) {
mu -= e / ((td + (td>RealScalar(0) ? h : -h)) / e);
} else {
mu -= e2 / (td + (td>RealScalar(0) ? h : -h));
}
}
RealScalar x = diag[start] - mu;
RealScalar z = subdiag[start];
for (Index k = start; k < end; ++k)
// If z ever becomes zero, the Givens rotation will be the identity and
// z will stay zero for all future iterations.
for (Index k = start; k < end && z != RealScalar(0); ++k)
{
JacobiRotation<RealScalar> rot;
rot.makeGivens(x, z);
@@ -859,12 +871,11 @@ static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index sta
diag[k+1] = rot.s() * sdk + rot.c() * dkp1;
subdiag[k] = rot.c() * sdk - rot.s() * dkp1;
if (k > start)
subdiag[k - 1] = rot.c() * subdiag[k-1] - rot.s() * z;
// "Chasing the bulge" to return to triangular form.
x = subdiag[k];
if (k < end - 1)
{
z = -rot.s() * subdiag[k+1];

View File

@@ -141,8 +141,8 @@ struct compute_inverse_size4<Architecture::Target, float, MatrixType, ResultType
iC = psub(iC, pmul(vec4f_swizzle2(A, A, 1, 0, 3, 2), vec4f_swizzle2(DC, DC, 2, 1, 2, 1)));
iC = psub(pmul(B, vec4f_duplane(dC, 0)), iC);
const int bits[4] = {0, -2147483648, -2147483648, 0};
const Packet4f p4f_sign_PNNP = preinterpret<Packet4f, Packet4i>(pgather<int, Packet4i>(bits, static_cast<Eigen::Index>(1)));
const float sign_mask[4] = {0.0f, -0.0f, -0.0f, 0.0f};
const Packet4f p4f_sign_PNNP = pset<Packet4f>(sign_mask);
rd = pxor(rd, p4f_sign_PNNP);
iA = pmul(iA, rd);
iB = pmul(iB, rd);
@@ -323,12 +323,12 @@ struct compute_inverse_size4<Architecture::Target, double, MatrixType, ResultTyp
iC1 = psub(pmul(B1, dC), iC1);
iC2 = psub(pmul(B2, dC), iC2);
const int bits1[4] = {0, -2147483648, 0, 0};
const int bits2[4] = {0, 0, 0, -2147483648};
const Packet2d _Sign_NP = preinterpret<Packet2d, Packet4i>(pgather<int, Packet4i>(bits1, static_cast<Eigen::Index>(1)));
const Packet2d _Sign_PN = preinterpret<Packet2d, Packet4i>(pgather<int, Packet4i>(bits2, static_cast<Eigen::Index>(1)));
d1 = pxor(rd, _Sign_PN);
d2 = pxor(rd, _Sign_NP);
const double sign_mask1[2] = {0.0, -0.0};
const double sign_mask2[2] = {-0.0, 0.0};
const Packet2d sign_PN = pset<Packet2d>(sign_mask1);
const Packet2d sign_NP = pset<Packet2d>(sign_mask2);
d1 = pxor(rd, sign_PN);
d2 = pxor(rd, sign_NP);
Index res_stride = result.outerStride();
double *res = result.data();

View File

@@ -208,6 +208,7 @@ protected:
using Base::m_computeThinV;
using Base::m_matrixU;
using Base::m_matrixV;
using Base::m_info;
using Base::m_isInitialized;
using Base::m_nonzeroSingularValues;
@@ -256,16 +257,25 @@ BDCSVD<MatrixType>& BDCSVD<MatrixType>::compute(const MatrixType& matrix, unsign
{
// FIXME this line involves temporaries
JacobiSVD<MatrixType> jsvd(matrix,computationOptions);
if(computeU()) m_matrixU = jsvd.matrixU();
if(computeV()) m_matrixV = jsvd.matrixV();
m_singularValues = jsvd.singularValues();
m_nonzeroSingularValues = jsvd.nonzeroSingularValues();
m_isInitialized = true;
m_info = jsvd.info();
if (m_info == Success || m_info == NoConvergence) {
if(computeU()) m_matrixU = jsvd.matrixU();
if(computeV()) m_matrixV = jsvd.matrixV();
m_singularValues = jsvd.singularValues();
m_nonzeroSingularValues = jsvd.nonzeroSingularValues();
}
return *this;
}
//**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows
RealScalar scale = matrix.cwiseAbs().maxCoeff();
RealScalar scale = matrix.cwiseAbs().template maxCoeff<PropagateNaN>();
if (!(numext::isfinite)(scale)) {
m_isInitialized = true;
m_info = InvalidInput;
return *this;
}
if(scale==Literal(0)) scale = Literal(1);
MatrixX copy;
if (m_isTranspose) copy = matrix.adjoint()/scale;
@@ -282,7 +292,11 @@ BDCSVD<MatrixType>& BDCSVD<MatrixType>::compute(const MatrixType& matrix, unsign
m_computed.topRows(m_diagSize) = bid.bidiagonal().toDenseMatrix().transpose();
m_computed.template bottomRows<1>().setZero();
divide(0, m_diagSize - 1, 0, 0, 0);
if (m_info != Success && m_info != NoConvergence) {
m_isInitialized = true;
return *this;
}
//**** step 3 - Copy singular values and vectors
for (int i=0; i<m_diagSize; i++)
{
@@ -394,7 +408,7 @@ void BDCSVD<MatrixType>::structured_update(Block<MatrixXr,Dynamic,Dynamic> A, co
//@param shift : Each time one takes the left submatrix, one must add 1 to the shift. Why? Because! We actually want the last column of the U submatrix
// to become the first column (*coeff) and to shift all the other columns to the right. There are more details on the reference paper.
template<typename MatrixType>
void BDCSVD<MatrixType>::divide (Eigen::Index firstCol, Eigen::Index lastCol, Eigen::Index firstRowW, Eigen::Index firstColW, Eigen::Index shift)
void BDCSVD<MatrixType>::divide(Eigen::Index firstCol, Eigen::Index lastCol, Eigen::Index firstRowW, Eigen::Index firstColW, Eigen::Index shift)
{
// requires rows = cols + 1;
using std::pow;
@@ -414,6 +428,8 @@ void BDCSVD<MatrixType>::divide (Eigen::Index firstCol, Eigen::Index lastCol, Ei
{
// FIXME this line involves temporaries
JacobiSVD<MatrixXr> b(m_computed.block(firstCol, firstCol, n + 1, n), ComputeFullU | (m_compV ? ComputeFullV : 0));
m_info = b.info();
if (m_info != Success && m_info != NoConvergence) return;
if (m_compU)
m_naiveU.block(firstCol, firstCol, n + 1, n + 1).real() = b.matrixU();
else
@@ -433,7 +449,9 @@ void BDCSVD<MatrixType>::divide (Eigen::Index firstCol, Eigen::Index lastCol, Ei
// and the divide of the right submatrice reads one column of the left submatrice. That's why we need to treat the
// right submatrix before the left one.
divide(k + 1 + firstCol, lastCol, k + 1 + firstRowW, k + 1 + firstColW, shift);
if (m_info != Success && m_info != NoConvergence) return;
divide(firstCol, k - 1 + firstCol, firstRowW, firstColW + 1, shift + 1);
if (m_info != Success && m_info != NoConvergence) return;
if (m_compU)
{

View File

@@ -585,6 +585,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
using Base::m_matrixU;
using Base::m_matrixV;
using Base::m_singularValues;
using Base::m_info;
using Base::m_isInitialized;
using Base::m_isAllocated;
using Base::m_usePrescribedThreshold;
@@ -625,6 +626,7 @@ void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Eigen::Index rows, Eigen:
m_rows = rows;
m_cols = cols;
m_info = Success;
m_isInitialized = false;
m_isAllocated = true;
m_computationOptions = computationOptions;
@@ -674,7 +676,12 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
// Scaling factor to reduce over/under-flows
RealScalar scale = matrix.cwiseAbs().maxCoeff();
RealScalar scale = matrix.cwiseAbs().template maxCoeff<PropagateNaN>();
if (!(numext::isfinite)(scale)) {
m_isInitialized = true;
m_info = InvalidInput;
return *this;
}
if(scale==RealScalar(0)) scale = RealScalar(1);
/*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */

View File

@@ -51,8 +51,11 @@ template<typename Derived> struct traits<SVDBase<Derived> >
* smaller value among \a n and \a p, there are only \a m singular vectors; the remaining columns of \a U and \a V do not correspond to actual
* singular vectors. Asking for \em thin \a U or \a V means asking for only their \a m first columns to be formed. So \a U is then a n-by-m matrix,
* and \a V is then a p-by-m matrix. Notice that thin \a U and \a V are all you need for (least squares) solving.
*
* The status of the computation can be retrived using the \a info() method. Unless \a info() returns \a Success, the results should be not
* considered well defined.
*
* If the input matrix has inf or nan coefficients, the result of the computation is undefined, but the computation is guaranteed to
* If the input matrix has inf or nan coefficients, the result of the computation is undefined, and \a info() will return \a InvalidInput, but the computation is guaranteed to
* terminate in finite (and reasonable) time.
* \sa class BDCSVD, class JacobiSVD
*/
@@ -97,7 +100,7 @@ public:
*/
const MatrixUType& matrixU() const
{
eigen_assert(m_isInitialized && "SVD is not initialized.");
_check_compute_assertions();
eigen_assert(computeU() && "This SVD decomposition didn't compute U. Did you ask for it?");
return m_matrixU;
}
@@ -113,7 +116,7 @@ public:
*/
const MatrixVType& matrixV() const
{
eigen_assert(m_isInitialized && "SVD is not initialized.");
_check_compute_assertions();
eigen_assert(computeV() && "This SVD decomposition didn't compute V. Did you ask for it?");
return m_matrixV;
}
@@ -125,14 +128,14 @@ public:
*/
const SingularValuesType& singularValues() const
{
eigen_assert(m_isInitialized && "SVD is not initialized.");
_check_compute_assertions();
return m_singularValues;
}
/** \returns the number of singular values that are not exactly 0 */
Index nonzeroSingularValues() const
{
eigen_assert(m_isInitialized && "SVD is not initialized.");
_check_compute_assertions();
return m_nonzeroSingularValues;
}
@@ -145,7 +148,7 @@ public:
inline Index rank() const
{
using std::abs;
eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
_check_compute_assertions();
if(m_singularValues.size()==0) return 0;
RealScalar premultiplied_threshold = numext::maxi<RealScalar>(m_singularValues.coeff(0) * threshold(), (std::numeric_limits<RealScalar>::min)());
Index i = m_nonzeroSingularValues-1;
@@ -224,6 +227,18 @@ public:
solve(const MatrixBase<Rhs>& b) const;
#endif
/** \brief Reports whether previous computation was successful.
*
* \returns \c Success if computation was successful.
*/
EIGEN_DEVICE_FUNC
ComputationInfo info() const
{
eigen_assert(m_isInitialized && "SVD is not initialized.");
return m_info;
}
#ifndef EIGEN_PARSED_BY_DOXYGEN
template<typename RhsType, typename DstType>
void _solve_impl(const RhsType &rhs, DstType &dst) const;
@@ -233,26 +248,31 @@ public:
#endif
protected:
static void check_template_parameters()
{
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
}
void _check_compute_assertions() const {
eigen_assert(m_isInitialized && "SVD is not initialized.");
}
template<bool Transpose_, typename Rhs>
void _check_solve_assertion(const Rhs& b) const {
EIGEN_ONLY_USED_FOR_DEBUG(b);
eigen_assert(m_isInitialized && "SVD is not initialized.");
_check_compute_assertions();
eigen_assert(computeU() && computeV() && "SVDBase::solve(): Both unitaries U and V are required to be computed (thin unitaries suffice).");
eigen_assert((Transpose_?cols():rows())==b.rows() && "SVDBase::solve(): invalid number of rows of the right hand side matrix b");
}
// return true if already allocated
bool allocate(Index rows, Index cols, unsigned int computationOptions) ;
MatrixUType m_matrixU;
MatrixVType m_matrixV;
SingularValuesType m_singularValues;
ComputationInfo m_info;
bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold;
bool m_computeFullU, m_computeThinU;
bool m_computeFullV, m_computeThinV;
@@ -265,7 +285,8 @@ protected:
* Default constructor of SVDBase
*/
SVDBase()
: m_isInitialized(false),
: m_info(Success),
m_isInitialized(false),
m_isAllocated(false),
m_usePrescribedThreshold(false),
m_computeFullU(false),
@@ -327,6 +348,7 @@ bool SVDBase<MatrixType>::allocate(Index rows, Index cols, unsigned int computat
m_rows = rows;
m_cols = cols;
m_info = Success;
m_isInitialized = false;
m_isAllocated = true;
m_computationOptions = computationOptions;

View File

@@ -1,6 +1,7 @@
#define NOGMM
#define NOMTL
#define EIGEN_GOOGLEHASH_SUPPORT 1
#include <map>
#include <ext/hash_map>

107
ci/smoketests.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,107 @@
.buildsmoketests:linux:base:
stage: buildsmoketests
image: ubuntu:18.04
before_script:
- apt-get update -y
- apt-get install -y --no-install-recommends software-properties-common
- add-apt-repository -y ppa:ubuntu-toolchain-r/test
- apt-get update
- apt-get install --no-install-recommends -y ${EIGEN_CI_CXX_COMPILER}
${EIGEN_CI_CC_COMPILER} cmake ninja-build
script:
- mkdir -p ${BUILDDIR} && cd ${BUILDDIR}
- CXX=${EIGEN_CI_CXX_COMPILER} CC=${EIGEN_CI_CC_COMPILER} cmake -G
${EIGEN_CI_CMAKE_GENEATOR} -DEIGEN_TEST_CXX11=${EIGEN_TEST_CXX11}
${EIGEN_CI_ADDITIONAL_ARGS} ..
- cmake --build . --target buildsmoketests
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
paths:
- ${BUILDDIR}/
expire_in: 5 days
only:
- merge_requests
buildsmoketests:x86-64:linux:gcc-10:cxx11-off:
extends: .buildsmoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: "g++-10"
EIGEN_CI_CC_COMPILER: "gcc-10"
EIGEN_TEST_CXX11: "off"
buildsmoketests:x86-64:linux:gcc-10:cxx11-on:
extends: .buildsmoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: "g++-10"
EIGEN_CI_CC_COMPILER: "gcc-10"
EIGEN_TEST_CXX11: "on"
buildsmoketests:x86-64:linux:clang-10:cxx11-off:
extends: .buildsmoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: "clang++-10"
EIGEN_CI_CC_COMPILER: "clang-10"
EIGEN_TEST_CXX11: "off"
buildsmoketests:x86-64:linux:clang-10:cxx11-on:
extends: .buildsmoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: "clang++-10"
EIGEN_CI_CC_COMPILER: "clang-10"
EIGEN_TEST_CXX11: "on"
.smoketests:linux:base:
stage: smoketests
image: ubuntu:18.04
before_script:
- apt-get update -y
- apt-get install -y --no-install-recommends software-properties-common
- add-apt-repository -y ppa:ubuntu-toolchain-r/test
- apt-get update
- apt-get install --no-install-recommends -y ${EIGEN_CI_CXX_COMPILER}
${EIGEN_CI_CC_COMPILER} cmake ninja-build xsltproc
script:
- export CXX=${EIGEN_CI_CXX_COMPILER}
- export CC=${EIGEN_CI_CC_COMPILER}
- cd ${BUILDDIR} && ctest --output-on-failure --no-compress-output
--build-no-clean -T test -L smoketest
after_script:
- apt-get update -y
- apt-get install --no-install-recommends -y xsltproc
- cd ${BUILDDIR}
- xsltproc ../ci/CTest2JUnit.xsl Testing/`head -n 1 < Testing/TAG`/Test.xml > "JUnitTestResults_$CI_JOB_ID.xml"
artifacts:
reports:
junit:
- ${BUILDDIR}/JUnitTestResults_$CI_JOB_ID.xml
expire_in: 5 days
only:
- merge_requests
smoketests:x86-64:linux:gcc-10:cxx11-off:
extends: .smoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: g++-10
EIGEN_CI_CC_COMPILER: gcc-10
needs: [ "buildsmoketests:x86-64:linux:gcc-10:cxx11-off" ]
smoketests:x86-64:linux:gcc-10:cxx11-on:
extends: .smoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: g++-10
EIGEN_CI_CC_COMPILER: gcc-10
needs: [ "buildsmoketests:x86-64:linux:gcc-10:cxx11-on" ]
smoketests:x86-64:linux:clang-10:cxx11-off:
extends: .smoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: clang++-10
EIGEN_CI_CC_COMPILER: clang-10
needs: [ "buildsmoketests:x86-64:linux:clang-10:cxx11-off" ]
smoketests:x86-64:linux:clang-10:cxx11-on:
extends: .smoketests:linux:base
variables:
EIGEN_CI_CXX_COMPILER: clang++-10
EIGEN_CI_CC_COMPILER: clang-10
needs: [ "buildsmoketests:x86-64:linux:clang-10:cxx11-on" ]

View File

@@ -0,0 +1,131 @@
# List of tests that will be build and run during Eigen's smoke testing. If one
# of these tests doesn't exists or cannot be build with the current configuration
# it will just be skipped.
set(ei_smoke_test_list
adjoint_1
alignedvector3
array_cwise_7
array_cwise_8
array_for_matrix_1
array_of_string
array_replicate_1
array_reverse_1
autodiff_1
autodiff_scalar_1
bandmatrix
bdcsvd_9
bessel_functions_1
bfloat16_float
blasutil_1
block_5
BVH
cholesky_1
cholmod_support_23
cholmod_support_24
conservative_resize_1
constructor_1
corners_1
ctorleakmiscmatrices_4
dense_storage
determinant_1
diagonal_1
diagonal_2
diagonalmatrices_1
dynalloc
eigensolver_complex_1
eigensolver_selfadjoint_8
EulerAngles_1
exceptions
fastmath
first_aligned
geo_alignedbox_2
geo_eulerangles_1
geo_homogeneous_1
geo_hyperplane_1
geo_orthomethods_1
geo_parametrizedline_1
geo_transformations_7
half_float
hessenberg_1
hessenberg_6qr_10
householder_8
indexed_view_1
inplace_decomposition_1
integer_types_1
inverse_1
is_same_dense
jacobi_1
jacobisvd_1
kronecker_product
linearstructure_1
mapped_matrix_1
mapstaticmethods_1
mapstride_1
matrix_square_root_1
meta
minres_2
miscmatrices_1
mixingtypes_7
nestbyvalue
nesting_ops_1
nomalloc_1
nullary_1
num_dimensions
NumericalDiff
numext
packetmath
permutationmatrices_1
polynomialsolver_1
prec_inverse_4x4_1
product_extra_5
product_selfadjoint_1
product_small_7
product_symm_1
product_syrk_1
product_trmm_1
product_trmv_1
product_trsolve_5
qr_1
qr_colpivoting_7
qr_fullpivoting_4
rand
real_qz_1
redux_1
ref_1
resize
rvalue_types_1
schur_complex_1
schur_real_1
selfadjoint_1
sizeof
sizeoverflow
smallvectors
sparse_basic_3
sparse_block_1
sparse_extra_4
sparse_permutations_2
sparse_product_4
sparse_ref_1
sparse_solvers_1
sparse_vector_1
special_functions_1
special_numbers_1
special_packetmath_1
spqr_support_2
stable_norm_1
stddeque_1
stddeque_overload_1
stdlist_1
stdlist_overload_1
stdvector_1
stdvector_overload_1
stl_iterators_1
swap_1
symbolic_index_1
triangular_1
type_aliaslu_9
umeyama_3
unalignedassert
unalignedcount
vectorwiseop_1
visitor_1)

View File

@@ -18,6 +18,11 @@ macro(ei_add_test_internal testname testname_with_suffix)
set(filename ${testname}.cpp)
endif()
# Add the current target to the list of subtest targets
get_property(EIGEN_SUBTESTS_LIST GLOBAL PROPERTY EIGEN_SUBTESTS_LIST)
set(EIGEN_SUBTESTS_LIST "${EIGEN_SUBTESTS_LIST}${targetname}\n")
set_property(GLOBAL PROPERTY EIGEN_SUBTESTS_LIST "${EIGEN_SUBTESTS_LIST}")
if(EIGEN_ADD_TEST_FILENAME_EXTENSION STREQUAL cu)
if(EIGEN_TEST_HIP)
hip_reset_flags()
@@ -413,11 +418,13 @@ macro(ei_init_testing)
define_property(GLOBAL PROPERTY EIGEN_MISSING_BACKENDS BRIEF_DOCS " " FULL_DOCS " ")
define_property(GLOBAL PROPERTY EIGEN_TESTING_SUMMARY BRIEF_DOCS " " FULL_DOCS " ")
define_property(GLOBAL PROPERTY EIGEN_TESTS_LIST BRIEF_DOCS " " FULL_DOCS " ")
define_property(GLOBAL PROPERTY EIGEN_SUBTESTS_LIST BRIEF_DOCS " " FULL_DOCS " ")
set_property(GLOBAL PROPERTY EIGEN_TESTED_BACKENDS "")
set_property(GLOBAL PROPERTY EIGEN_MISSING_BACKENDS "")
set_property(GLOBAL PROPERTY EIGEN_TESTING_SUMMARY "")
set_property(GLOBAL PROPERTY EIGEN_TESTS_LIST "")
set_property(GLOBAL PROPERTY EIGEN_SUBTESTS_LIST "")
define_property(GLOBAL PROPERTY EIGEN_FAILTEST_FAILURE_COUNT BRIEF_DOCS " " FULL_DOCS " ")
define_property(GLOBAL PROPERTY EIGEN_FAILTEST_COUNT BRIEF_DOCS " " FULL_DOCS " ")
@@ -708,3 +715,56 @@ macro(ei_split_testsuite num_splits)
add_dependencies("${current_target}" "${curr_test}")
endforeach()
endmacro(ei_split_testsuite num_splits)
# Defines the custom command buildsmoketests to build a number of tests
# specified in smoke_test_list.
#
# Test in smoke_test_list can be either test targets (e.g. packetmath) or
# subtests targets (e.g. packetmath_2). If any of the test are not available
# in the current configuration they are just skipped.
#
# All tests added via this macro are labeled with the smoketest label. This
# allows running smoketests only using ctest.
#
# Smoke tests are intended to be run before the whole test suite is invoked,
# e.g., to smoke test patches.
macro(ei_add_smoke_tests smoke_test_list)
# Set the build target to build smoketests
set(buildtarget "buildsmoketests")
add_custom_target("${buildtarget}")
# Get list of all tests and translate it into a CMake list
get_property(EIGEN_TESTS_LIST GLOBAL PROPERTY EIGEN_TESTS_LIST)
string(REGEX REPLACE "\n" " " EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}")
set(EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}")
separate_arguments(EIGEN_TESTS_LIST)
# Check if the test in smoke_test_list is a currently valid test target
foreach(test IN ITEMS ${smoke_test_list})
# Add tests in smoke_test_list to our smoke test target but only if the test
# is currently available, i.e., is in EIGEN_SUBTESTS_LIST
if ("${test}" IN_LIST EIGEN_TESTS_LIST)
add_dependencies("${buildtarget}" "${test}")
# In the case of a test we match all subtests
set(ctest_regex "${ctest_regex}^${test}_[0-9]+$$|")
endif()
endforeach()
# Get list of all subtests and translate it into a CMake list
get_property(EIGEN_SUBTESTS_LIST GLOBAL PROPERTY EIGEN_SUBTESTS_LIST)
string(REGEX REPLACE "\n" " " EIGEN_SUBTESTS_LIST "${EIGEN_SUBTESTS_LIST}")
set(EIGEN_SUBTESTS_LIST "${EIGEN_SUBTESTS_LIST}")
separate_arguments(EIGEN_SUBTESTS_LIST)
# Check if the test in smoke_test_list is a currently valid subtest target
foreach(test IN ITEMS ${smoke_test_list})
# Add tests in smoke_test_list to our smoke test target but only if the test
# is currently available, i.e., is in EIGEN_SUBTESTS_LIST
if ("${test}" IN_LIST EIGEN_SUBTESTS_LIST)
add_dependencies("${buildtarget}" "${test}")
# Add label smoketest to be able to run smoketests using ctest
get_property(test_labels TEST ${test} PROPERTY LABELS)
set_property(TEST ${test} PROPERTY LABELS "${test_labels};smoketest")
endif()
endforeach()
endmacro(ei_add_smoke_tests)

View File

@@ -76,20 +76,20 @@ class AnnoyingScalar
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 *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; }
bool operator> (const AnnoyingScalar& other) const { return *v > *other.v; }
float* v;
float data;
static int instances;
@@ -136,12 +136,23 @@ struct NumTraits<AnnoyingScalar> : NumTraits<float>
template<> inline AnnoyingScalar test_precision<AnnoyingScalar>() { return test_precision<float>(); }
namespace internal {
template<> double cast(const AnnoyingScalar& x) { return double(*x.v); }
template<> float cast(const AnnoyingScalar& x) { return *x.v; }
namespace numext {
template<>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE
bool (isfinite)(const AnnoyingScalar& x) {
return (numext::isfinite)(*x.v);
}
}
namespace internal {
template<> EIGEN_STRONG_INLINE AnnoyingScalar pcmp_eq(const AnnoyingScalar& a, const AnnoyingScalar& b)
{ return AnnoyingScalar(pcmp_eq(*a.v, *b.v)); }
template<> EIGEN_STRONG_INLINE AnnoyingScalar pselect(const AnnoyingScalar& mask, const AnnoyingScalar& a, const AnnoyingScalar& b)
{ return numext::equal_strict(*mask.v, 0.f) ? b : a; }
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 Eigen
AnnoyingScalar get_test_precision(const AnnoyingScalar&)
{ return Eigen::test_precision<AnnoyingScalar>(); }

View File

@@ -460,3 +460,7 @@ cmake_dependent_option(EIGEN_TEST_BUILD_DOCUMENTATION "Test building the doxygen
if(EIGEN_TEST_BUILD_DOCUMENTATION)
add_dependencies(buildtests doc)
endif()
# Register all smoke tests
include("EigenSmokeTestList")
ei_add_smoke_tests("${ei_smoke_test_list}")

View File

@@ -332,7 +332,9 @@ EIGEN_DECLARE_TEST(geo_quaternion)
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>() ));
}
}

View File

@@ -29,10 +29,6 @@
#endif
#ifdef EIGEN_GOOGLEHASH_SUPPORT
#include <google/sparse_hash_map>
#endif
#include <Eigen/Cholesky>
#include <Eigen/LU>
#include <Eigen/Sparse>

View File

@@ -7,9 +7,9 @@
// Public License v. 2.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 <iterator>
#include <numeric>
#include "main.h"
template< class Iterator >
std::reverse_iterator<Iterator>
@@ -47,6 +47,18 @@ bool is_pointer_based_stl_iterator(const internal::pointer_based_stl_iterator<Xp
template<typename XprType>
bool is_generic_randaccess_stl_iterator(const internal::generic_randaccess_stl_iterator<XprType> &) { return true; }
template<typename Iter>
bool is_default_constructible_and_assignable(const Iter& it)
{
#if EIGEN_HAS_CXX11
VERIFY(std::is_default_constructible<Iter>::value);
VERIFY(std::is_nothrow_default_constructible<Iter>::value);
#endif
Iter it2;
it2 = it;
return (it==it2);
}
template<typename Xpr>
void check_begin_end_for_loop(Xpr xpr)
{
@@ -124,6 +136,22 @@ void test_stl_iterators(int rows=Rows, int cols=Cols)
Index i, j;
// Verify that iterators are default constructible (See bug #1900)
{
VERIFY( is_default_constructible_and_assignable(v.begin()));
VERIFY( is_default_constructible_and_assignable(v.end()));
VERIFY( is_default_constructible_and_assignable(cv.begin()));
VERIFY( is_default_constructible_and_assignable(cv.end()));
VERIFY( is_default_constructible_and_assignable(A.row(0).begin()));
VERIFY( is_default_constructible_and_assignable(A.row(0).end()));
VERIFY( is_default_constructible_and_assignable(cA.row(0).begin()));
VERIFY( is_default_constructible_and_assignable(cA.row(0).end()));
VERIFY( is_default_constructible_and_assignable(B.row(0).begin()));
VERIFY( is_default_constructible_and_assignable(B.row(0).end()));
}
// Check we got a fast pointer-based iterator when expected
{
VERIFY( is_pointer_based_stl_iterator(v.begin()) );

View File

@@ -298,7 +298,8 @@ EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); }
// workaround aggressive optimization in ICC
template<typename T> EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; }
// all this function does is verify we don't iterate infinitely on nan/inf values
// This function verifies we don't iterate infinitely on nan/inf values,
// and that info() returns InvalidInput.
template<typename SvdType, typename MatrixType>
void svd_inf_nan()
{
@@ -307,18 +308,22 @@ void svd_inf_nan()
Scalar some_inf = Scalar(1) / zero<Scalar>();
VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf));
svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV);
VERIFY(svd.info() == InvalidInput);
Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
VERIFY(nan != nan);
svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV);
VERIFY(svd.info() == InvalidInput);
MatrixType m = MatrixType::Zero(10,10);
m(internal::random<int>(0,9), internal::random<int>(0,9)) = some_inf;
svd.compute(m, ComputeFullU | ComputeFullV);
VERIFY(svd.info() == InvalidInput);
m = MatrixType::Zero(10,10);
m(internal::random<int>(0,9), internal::random<int>(0,9)) = nan;
svd.compute(m, ComputeFullU | ComputeFullV);
VERIFY(svd.info() == InvalidInput);
// regression test for bug 791
m.resize(3,3);
@@ -326,6 +331,7 @@ void svd_inf_nan()
0, -0.5, 0,
nan, 0, 0;
svd.compute(m, ComputeFullU | ComputeFullV);
VERIFY(svd.info() == InvalidInput);
m.resize(4,4);
m << 1, 0, 0, 0,
@@ -333,6 +339,7 @@ void svd_inf_nan()
1, 0, 1, nan,
0, nan, nan, 0;
svd.compute(m, ComputeFullU | ComputeFullV);
VERIFY(svd.info() == InvalidInput);
}
// Regression test for bug 286: JacobiSVD loops indefinitely with some

View File

@@ -466,7 +466,7 @@ struct sizes_match_below_dim {
template <typename Dims1, typename Dims2, ptrdiff_t n>
struct sizes_match_below_dim<Dims1, Dims2, n, n> {
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run(Dims1& dims1, Dims2& dims2) {
return (array_get<n-1>(dims1) == array_get<n-1>(dims2)) &
return (array_get<n-1>(dims1) == array_get<n-1>(dims2)) &&
sizes_match_below_dim<Dims1, Dims2, n-1, n-1>::run(dims1, dims2);
}
};

View File

@@ -357,8 +357,8 @@ __global__ EIGEN_HIP_LAUNCH_BOUNDS_1024 void ScanKernel(Self self, Index total_s
}
template <typename Self, typename Reducer>
struct ScanLauncher<Self, Reducer, GpuDevice, false> {
template <typename Self, typename Reducer, bool Vectorize>
struct ScanLauncher<Self, Reducer, GpuDevice, Vectorize> {
void operator()(const Self& self, typename Self::CoeffReturnType* data) {
Index total_size = internal::array_prod(self.dimensions());
Index num_blocks = (total_size / self.size() + 63) / 64;

View File

@@ -14,6 +14,7 @@
#include "../../Eigen/Jacobi"
#include "../../Eigen/Householder"
/**
* \defgroup IterativeLinearSolvers_Module Iterative solvers module
* This module aims to provide various iterative linear and non linear solver algorithms.
@@ -23,11 +24,12 @@
* - an IDR(s) implementation
* - a DGMRES implementation
* - a MINRES implementation
*
* \code
* #include <unsupported/Eigen/IterativeSolvers>
* \endcode
*/
//@{
#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
@@ -45,6 +47,5 @@
#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
//@}
#endif // EIGEN_ITERATIVE_SOLVERS_MODULE_H

View File

@@ -24,6 +24,7 @@
#ifdef EIGEN_GOOGLEHASH_SUPPORT
#include <google/dense_hash_map>
#include <google/sparse_hash_map>
#endif
/**

View File

@@ -10,7 +10,13 @@
#ifndef EIGEN_RANDOMSETTER_H
#define EIGEN_RANDOMSETTER_H
namespace Eigen {
#if defined(EIGEN_GOOGLEHASH_SUPPORT)
// Ensure the ::google namespace exists, required for checking existence of
// ::google::dense_hash_map and ::google::sparse_hash_map.
namespace google {}
#endif
namespace Eigen {
/** Represents a std::map
*
@@ -56,7 +62,26 @@ template<typename Scalar> struct StdUnorderedMapTraits
};
#endif // EIGEN_UNORDERED_MAP_SUPPORT
#ifdef _DENSE_HASH_MAP_H_
#if defined(EIGEN_GOOGLEHASH_SUPPORT)
namespace google {
// Namespace work-around, since sometimes dense_hash_map and sparse_hash_map
// are in the global namespace, and other times they are under ::google.
using namespace ::google;
template<typename KeyType, typename Scalar>
struct DenseHashMap {
typedef dense_hash_map<KeyType, Scalar> type;
};
template<typename KeyType, typename Scalar>
struct SparseHashMap {
typedef sparse_hash_map<KeyType, Scalar> type;
};
} // namespace google
/** Represents a google::dense_hash_map
*
* \see RandomSetter
@@ -64,7 +89,7 @@ template<typename Scalar> struct StdUnorderedMapTraits
template<typename Scalar> struct GoogleDenseHashMapTraits
{
typedef int KeyType;
typedef google::dense_hash_map<KeyType,Scalar> Type;
typedef typename google::DenseHashMap<KeyType,Scalar>::type Type;
enum {
IsSorted = 0
};
@@ -72,9 +97,7 @@ template<typename Scalar> struct GoogleDenseHashMapTraits
static void setInvalidKey(Type& map, const KeyType& k)
{ map.set_empty_key(k); }
};
#endif
#ifdef _SPARSE_HASH_MAP_H_
/** Represents a google::sparse_hash_map
*
* \see RandomSetter
@@ -82,7 +105,7 @@ template<typename Scalar> struct GoogleDenseHashMapTraits
template<typename Scalar> struct GoogleSparseHashMapTraits
{
typedef int KeyType;
typedef google::sparse_hash_map<KeyType,Scalar> Type;
typedef typename google::SparseHashMap<KeyType,Scalar>::type Type;
enum {
IsSorted = 0
};
@@ -134,18 +157,17 @@ template<typename Scalar> struct GoogleSparseHashMapTraits
* GoogleSparseHashMapTraits, GnuHashMapTraits, and finally StdMapTraits.
*
* For performance and memory consumption reasons it is highly recommended to use one of
* the Google's hash_map implementation. To enable the support for them, you have two options:
* - \#include <google/dense_hash_map> yourself \b before Eigen/Sparse header
* - define EIGEN_GOOGLEHASH_SUPPORT
* In the later case the inclusion of <google/dense_hash_map> is made for you.
* Google's hash_map implementations. To enable the support for them, you must define
* EIGEN_GOOGLEHASH_SUPPORT. This will include both <google/dense_hash_map> and
* <google/sparse_hash_map> for you.
*
* \see http://code.google.com/p/google-sparsehash/
* \see https://github.com/sparsehash/sparsehash
*/
template<typename SparseMatrixType,
template <typename T> class MapTraits =
#if defined _DENSE_HASH_MAP_H_
#if defined(EIGEN_GOOGLEHASH_SUPPORT)
GoogleDenseHashMapTraits
#elif defined _HASH_MAP
#elif defined(_HASH_MAP)
GnuHashMapTraits
#else
StdMapTraits

View File

@@ -444,7 +444,7 @@ void test_gpu_forced_evals() {
d_float, num_elem);
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_half1(
d_res_half1, num_elem);
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Unaligned> gpu_res_half2(
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Unaligned> gpu_res_half2(
d_res_half2, num_elem);
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_float(
d_res_float, num_elem);
@@ -461,7 +461,7 @@ void test_gpu_forced_evals() {
Tensor<float, 1> half_prec2(num_elem);
Tensor<float, 1> full_prec(num_elem);
gpu_device.memcpyDeviceToHost(half_prec1.data(), d_res_half1, num_elem*sizeof(float));
gpu_device.memcpyDeviceToHost(half_prec2.data(), d_res_half1, num_elem*sizeof(float));
gpu_device.memcpyDeviceToHost(half_prec2.data(), d_res_half2, num_elem*sizeof(float));
gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, num_elem*sizeof(float));
gpu_device.synchronize();

View File

@@ -123,10 +123,8 @@ template<typename SparseMatrixType> void sparse_extra(const SparseMatrixType& re
#ifdef EIGEN_UNORDERED_MAP_SUPPORT
VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdUnorderedMapTraits> >(m,refMat,nonzeroCoords) ));
#endif
#ifdef _DENSE_HASH_MAP_H_
#ifdef EIGEN_GOOGLEHASH_SUPPORT
VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleDenseHashMapTraits> >(m,refMat,nonzeroCoords) ));
#endif
#ifdef _SPARSE_HASH_MAP_H_
VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleSparseHashMapTraits> >(m,refMat,nonzeroCoords) ));
#endif