Merge remote-tracking branch 'origin2/master'

This commit is contained in:
Chip Kerchner
2025-10-28 20:26:26 +00:00
16 changed files with 103 additions and 66 deletions

View File

@@ -15,6 +15,7 @@
#include "Householder" #include "Householder"
#include "LU" #include "LU"
#include "Geometry" #include "Geometry"
#include "Sparse" // Needed by ComplexQZ.
#include "src/Core/util/DisableStupidWarnings.h" #include "src/Core/util/DisableStupidWarnings.h"

View File

@@ -2831,7 +2831,7 @@ inline __m128i segment_mask_4x8(Index begin, Index count) {
mask <<= CHAR_BIT * count; mask <<= CHAR_BIT * count;
mask--; mask--;
mask <<= CHAR_BIT * begin; mask <<= CHAR_BIT * begin;
#if defined(_WIN32) && !defined(_WIN64) #if !EIGEN_ARCH_x86_64
return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&mask)); return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&mask));
#else #else
return _mm_cvtsi64_si128(mask); return _mm_cvtsi64_si128(mask);
@@ -2847,7 +2847,7 @@ inline __m128i segment_mask_8x8(Index begin, Index count) {
mask <<= (CHAR_BIT / 2) * count; mask <<= (CHAR_BIT / 2) * count;
mask--; mask--;
mask <<= CHAR_BIT * begin; mask <<= CHAR_BIT * begin;
#if defined(_WIN32) && !defined(_WIN64) #if !EIGEN_ARCH_x86_64
return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&mask)); return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&mask));
#else #else
return _mm_cvtsi64_si128(mask); return _mm_cvtsi64_si128(mask);

View File

@@ -14,8 +14,6 @@
#ifndef EIGEN_COMPLEX_QZ_H_ #ifndef EIGEN_COMPLEX_QZ_H_
#define EIGEN_COMPLEX_QZ_H_ #define EIGEN_COMPLEX_QZ_H_
#include "../../Sparse"
// IWYU pragma: private // IWYU pragma: private
#include "./InternalHeaderCheck.h" #include "./InternalHeaderCheck.h"
@@ -126,9 +124,7 @@ class ComplexQZ {
computeQZ ? n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)), computeQZ ? n : (MatrixType::ColsAtCompileTime == Eigen::Dynamic ? 0 : MatrixType::ColsAtCompileTime)),
m_ws(2 * n), m_ws(2 * n),
m_computeQZ(computeQZ), m_computeQZ(computeQZ),
m_maxIters(maxIters){ m_maxIters(maxIters) {}
};
/** \brief Constructor. computes the QZ decomposition of given matrices /** \brief Constructor. computes the QZ decomposition of given matrices
* upon creation * upon creation
@@ -178,14 +174,14 @@ class ComplexQZ {
* *
* \returns \c Success if computation was successfull, \c NoConvergence otherwise. * \returns \c Success if computation was successfull, \c NoConvergence otherwise.
*/ */
ComputationInfo info() const { return m_info; }; ComputationInfo info() const { return m_info; }
/** \brief number of performed QZ steps /** \brief number of performed QZ steps
*/ */
unsigned int iterations() const { unsigned int iterations() const {
eigen_assert(m_isInitialized && "ComplexQZ is not initialized."); eigen_assert(m_isInitialized && "ComplexQZ is not initialized.");
return m_global_iter; return m_global_iter;
}; }
private: private:
Index m_n; Index m_n;
@@ -569,7 +565,9 @@ void ComplexQZ<MatrixType_>::push_down_zero_ST(Index k, Index l) {
for (Index j = k + 1; j <= l; j++) { for (Index j = k + 1; j <= l; j++) {
// Create a 0 at _T(j, j) // Create a 0 at _T(j, j)
J.makeGivens(m_T(j - 1, j), m_T(j, j), &m_T.coeffRef(j - 1, j)); J.makeGivens(m_T(j - 1, j), m_T(j, j), &m_T.coeffRef(j - 1, j));
m_T.rightCols(m_n - j - 1).applyOnTheLeft(j - 1, j, J.adjoint()); if (m_n - j - 1 > 0) {
m_T.rightCols(m_n - j - 1).applyOnTheLeft(j - 1, j, J.adjoint());
}
m_T.coeffRef(j, j) = Scalar(0); m_T.coeffRef(j, j) = Scalar(0);
m_S.applyOnTheLeft(j - 1, j, J.adjoint()); m_S.applyOnTheLeft(j - 1, j, J.adjoint());

View File

@@ -65,7 +65,6 @@ template <typename EssentialPart>
EIGEN_DEVICE_FUNC void MatrixBase<Derived>::makeHouseholder(EssentialPart& essential, Scalar& tau, EIGEN_DEVICE_FUNC void MatrixBase<Derived>::makeHouseholder(EssentialPart& essential, Scalar& tau,
RealScalar& beta) const { RealScalar& beta) const {
using numext::conj; using numext::conj;
using numext::sqrt;
EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart) EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart)
VectorBlock<const Derived, EssentialPart::SizeAtCompileTime> tail(derived(), 1, size() - 1); VectorBlock<const Derived, EssentialPart::SizeAtCompileTime> tail(derived(), 1, size() - 1);
@@ -79,7 +78,7 @@ EIGEN_DEVICE_FUNC void MatrixBase<Derived>::makeHouseholder(EssentialPart& essen
beta = numext::real(c0); beta = numext::real(c0);
essential.setZero(); essential.setZero();
} else { } else {
beta = sqrt(numext::abs2(c0) + tailSqNorm); beta = numext::sqrt(numext::abs2(c0) + tailSqNorm);
if (numext::real(c0) >= RealScalar(0)) beta = -beta; if (numext::real(c0) >= RealScalar(0)) beta = -beta;
essential = tail / (c0 - beta); essential = tail / (c0 - beta);
tau = conj((beta - c0) / beta); tau = conj((beta - c0) / beta);

View File

@@ -89,7 +89,7 @@ struct simpl_chol_helper {
m_set[u] = v; m_set[u] = v;
u = next; u = next;
} }
}; }
}; };
// Computes the higher adjacency pattern by transposing the input lower adjacency matrix. // Computes the higher adjacency pattern by transposing the input lower adjacency matrix.

View File

@@ -140,7 +140,7 @@ class SparseVector : public SparseCompressedBase<SparseVector<Scalar_, Options_,
return insertBack(inner); return insertBack(inner);
} }
inline Scalar& insertBack(Index i) { inline Scalar& insertBack(Index i) {
m_data.append(0, i); m_data.append(Scalar(0), i);
return m_data.value(m_data.size() - 1); return m_data.value(m_data.size() - 1);
} }
@@ -150,7 +150,7 @@ class SparseVector : public SparseCompressedBase<SparseVector<Scalar_, Options_,
return insertBackUnordered(inner); return insertBackUnordered(inner);
} }
inline Scalar& insertBackUnordered(Index i) { inline Scalar& insertBackUnordered(Index i) {
m_data.append(0, i); m_data.append(Scalar(0), i);
return m_data.value(m_data.size() - 1); return m_data.value(m_data.size() - 1);
} }
@@ -177,7 +177,7 @@ class SparseVector : public SparseCompressedBase<SparseVector<Scalar_, Options_,
--p; --p;
} }
m_data.index(p + 1) = convert_index(i); m_data.index(p + 1) = convert_index(i);
m_data.value(p + 1) = 0; m_data.value(p + 1) = Scalar(0);
return m_data.value(p + 1); return m_data.value(p + 1);
} }
@@ -367,7 +367,7 @@ class SparseVector : public SparseCompressedBase<SparseVector<Scalar_, Options_,
/** \internal \deprecated use insertBack(Index) */ /** \internal \deprecated use insertBack(Index) */
EIGEN_DEPRECATED_WITH_REASON("Use .insertBack() instead.") Scalar& fill(Index i) { EIGEN_DEPRECATED_WITH_REASON("Use .insertBack() instead.") Scalar& fill(Index i) {
m_data.append(0, i); m_data.append(Scalar(0), i);
return m_data.value(m_data.size() - 1); return m_data.value(m_data.size() - 1);
} }

View File

@@ -290,7 +290,7 @@ build:linux:cross:x86-64:gcc-10:default:smoketest:
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
tags: tags:
- saas-linux-small-amd64 - saas-linux-medium-amd64
build:linux:cross:x86-64:clang-12:default:smoketest: build:linux:cross:x86-64:clang-12:default:smoketest:
extends: build:linux:cross:x86-64:clang-12:default extends: build:linux:cross:x86-64:clang-12:default
@@ -299,4 +299,4 @@ build:linux:cross:x86-64:clang-12:default:smoketest:
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
tags: tags:
- saas-linux-small-amd64 - saas-linux-medium-amd64

View File

@@ -13,19 +13,29 @@ elif [[ ${EIGEN_CI_CTEST_LABEL} ]]; then
target="-L ${EIGEN_CI_CTEST_LABEL}" target="-L ${EIGEN_CI_CTEST_LABEL}"
fi fi
# Repeat tests up to three times to ignore flakes. Do not re-run with -T test, set +x
# otherwise we lose test results for those that passed.
# Note: starting with CMake 3.17, we can use --repeat until-pass:3, but we have ctest_cmd="ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${NPROC} --output-on-failure --no-compress-output --build-noclean ${target}"
# no way of easily installing this on ppc64le.
ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${NPROC} \ echo "Running initial tests..."
--output-on-failure --no-compress-output \ if ${ctest_cmd} -T test; then
--build-no-clean -T test ${target} || \ echo "Tests passed on the first attempt."
ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${NPROC} \ exit_code=$?
--output-on-failure --no-compress-output --rerun-failed || \ else
ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${NPROC} \ echo "Initial tests failed with exit code $?. Retrying up to ${EIGEN_CI_CTEST_REPEAT} times..."
--output-on-failure --no-compress-output --rerun-failed if ${ctest_cmd} --rerun-failed --repeat until-pass:${EIGEN_CI_CTEST_REPEAT}; then
echo "Tests passed on retry."
exit_code=42
else
exit_code=$?
fi
fi
set -x
# Return to root directory. # Return to root directory.
cd ${rootdir} cd ${rootdir}
set +x set +x
exit $exit_code

View File

@@ -13,18 +13,32 @@ if (${EIGEN_CI_CTEST_REGEX}) {
$target = "-L","${EIGEN_CI_CTEST_LABEL}" $target = "-L","${EIGEN_CI_CTEST_LABEL}"
} }
# Repeat tests up to three times to ignore flakes. Do not re-run with -T test, $ctest_cmd = { ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${NPROC} --output-on-failure --no-compress-output --build-noclean ${target} }
# otherwise we lose test results for those that passed.
# Note: starting with CMake 3.17, we can use --repeat until-pass:3, but we have
# no way of easily installing this on ppc64le.
ctest $EIGEN_CI_CTEST_ARGS -j$NPROC --output-on-failure --no-compress-output --build-no-clean -T test $target || `
ctest $EIGEN_CI_CTEST_ARGS -j$NPROC --output-on-failure --no-compress-output --rerun-failed || `
ctest $EIGEN_CI_CTEST_ARGS -j$NPROC --output-on-failure --no-compress-output --rerun-failed
$success = $LASTEXITCODE Write-Host "Running initial tests..."
& $ctest_cmd "-T test"
$exit_code = $LASTEXITCODE
if ($exit_code -eq 0) {
Write-Host "Tests passed on the first attempt."
}
else {
Write-Host "Initial tests failed with exit code $exit_code. Retrying up to $EIGEN_CI_CTEST_REPEAT times..."
# TODO: figure out how to use --repeat until-pass
for ($i = 1; $i -le $EIGEN_CI_CTEST_REPEAT; $i++) {
& $ctest_cmd "--rerun-failed"
$exit_code = $LASTEXITCODE
if ($exit_code -eq 0) {
Write-Host "Tests passed on retry."
$exit_code = 42
break
}
}
}
# Return to root directory. # Return to root directory.
cd ${rootdir} cd ${rootdir}
# Explicitly propagate exit code to indicate pass/failure of test command. Exit $exit_code
if($success -ne 0) { Exit $success }

View File

@@ -11,6 +11,8 @@
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_PROJECT_NAMESPACE == "libeigen" && $CI_MERGE_REQUEST_LABELS =~ "/all-tests/" - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_PROJECT_NAMESPACE == "libeigen" && $CI_MERGE_REQUEST_LABELS =~ "/all-tests/"
tags: tags:
- saas-linux-2xlarge-amd64 - saas-linux-2xlarge-amd64
allow_failure:
exit_codes: 42
##### x86-64 ################################################################### ##### x86-64 ###################################################################
.test:linux:x86-64: .test:linux:x86-64:
@@ -384,7 +386,7 @@ test:linux:x86-64:gcc-10:default:smoketest:
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
tags: tags:
- saas-linux-small-amd64 - saas-linux-medium-amd64
test:linux:x86-64:clang-12:default:smoketest: test:linux:x86-64:clang-12:default:smoketest:
extends: .test:linux:x86-64:clang-12:default extends: .test:linux:x86-64:clang-12:default
@@ -394,4 +396,4 @@ test:linux:x86-64:clang-12:default:smoketest:
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "merge_request_event"
tags: tags:
- saas-linux-small-amd64 - saas-linux-medium-amd64

View File

@@ -9,11 +9,12 @@
- if: $CI_PIPELINE_SOURCE == "schedule" && $CI_PROJECT_NAMESPACE == "libeigen" - if: $CI_PIPELINE_SOURCE == "schedule" && $CI_PROJECT_NAMESPACE == "libeigen"
- if: $CI_PIPELINE_SOURCE == "web" && $CI_PROJECT_NAMESPACE == "libeigen" - if: $CI_PIPELINE_SOURCE == "web" && $CI_PROJECT_NAMESPACE == "libeigen"
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_PROJECT_NAMESPACE == "libeigen" && $CI_MERGE_REQUEST_LABELS =~ "/all-tests/" - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_PROJECT_NAMESPACE == "libeigen" && $CI_MERGE_REQUEST_LABELS =~ "/all-tests/"
tags: tags:
- eigen-runner - eigen-runner
- windows - windows
- x86-64 - x86-64
allow_failure:
exit_codes: 42
##### MSVC ##################################################################### ##### MSVC #####################################################################

View File

@@ -91,7 +91,7 @@ set(ei_smoke_test_list
qr_1 qr_1
qr_colpivoting_7 qr_colpivoting_7
qr_fullpivoting_4 qr_fullpivoting_4
rand rand_1
real_qz_1 real_qz_1
redux_1 redux_1
ref_1 ref_1

View File

@@ -36,9 +36,9 @@ option in `find_package`:
``` ```
find_package(Eigen3 3.4 REQUIRED NO_MODULE) # Restricts to 3.4.z find_package(Eigen3 3.4 REQUIRED NO_MODULE) # Restricts to 3.4.z
``` ```
or to support a range of versions: Starting with Eigen 3.4.1, we also support a range spanning major versions:
``` ```
find_package(Eigen3 3.4...5 REQUIRED NO_MODULE) # Any version >=3.4.0 but <6.0.0. find_package(Eigen3 3.4...5 REQUIRED NO_MODULE) # Any version >=3.4.1 but <6.0.0.
``` ```
Do not forget to set the <a href="https://cmake.org/cmake/help/v3.7/variable/CMAKE_PREFIX_PATH.html">\c CMAKE_PREFIX_PATH </a> variable if Eigen is not installed in a default location or if you want to pick a specific version. For instance: Do not forget to set the <a href="https://cmake.org/cmake/help/v3.7/variable/CMAKE_PREFIX_PATH.html">\c CMAKE_PREFIX_PATH </a> variable if Eigen is not installed in a default location or if you want to pick a specific version. For instance:

View File

@@ -18,11 +18,9 @@
template <typename MatrixType> template <typename MatrixType>
void generate_random_matrix_pair(const Index dim, MatrixType& A, MatrixType& B) { void generate_random_matrix_pair(const Index dim, MatrixType& A, MatrixType& B) {
A.resize(dim, dim); A.setRandom(dim, dim);
B.resize(dim, dim); B.setRandom(dim, dim);
A.setRandom(); // Zero out each row of B to with a probability of 10%.
B.setRandom();
// Set each row of B with a probability of 10% to 0
for (int i = 0; i < dim; i++) { for (int i = 0; i < dim; i++) {
if (internal::random<int>(0, 10) == 0) B.row(i).setZero(); if (internal::random<int>(0, 10) == 0) B.row(i).setZero();
} }
@@ -59,8 +57,6 @@ void complex_qz(const MatrixType& A, const MatrixType& B) {
} }
EIGEN_DECLARE_TEST(complex_qz) { EIGEN_DECLARE_TEST(complex_qz) {
// const Index dim1 = 15;
// const Index dim2 = 80;
for (int i = 0; i < g_repeat; i++) { for (int i = 0; i < g_repeat; i++) {
// Check for very small, fixed-sized double- and float complex matrices // Check for very small, fixed-sized double- and float complex matrices
Eigen::Matrix2cd A_2x2, B_2x2; Eigen::Matrix2cd A_2x2, B_2x2;
@@ -71,16 +67,18 @@ EIGEN_DECLARE_TEST(complex_qz) {
A_3x3.setRandom(); A_3x3.setRandom();
B_3x3.setRandom(); B_3x3.setRandom();
B_3x3.col(i % 3).setRandom(); B_3x3.col(i % 3).setRandom();
// Test for small float complex matrices
Eigen::MatrixXcf A_float, B_float;
const Index dim1 = internal::random<Index>(15, 80), dim2 = internal::random<Index>(15, 80);
generate_random_matrix_pair(dim1, A_float, B_float);
// Test for a bit larger double complex matrices
Eigen::MatrixXcd A_double, B_double;
generate_random_matrix_pair(dim2, A_double, B_double);
CALL_SUBTEST_1(complex_qz(A_2x2, B_2x2)); CALL_SUBTEST_1(complex_qz(A_2x2, B_2x2));
CALL_SUBTEST_2(complex_qz(A_3x3, B_3x3)); CALL_SUBTEST_2(complex_qz(A_3x3, B_3x3));
// Test for float complex matrices
const Index dim = internal::random<Index>(15, 80);
Eigen::MatrixXcf A_float, B_float;
generate_random_matrix_pair(dim, A_float, B_float);
CALL_SUBTEST_3(complex_qz(A_float, B_float)); CALL_SUBTEST_3(complex_qz(A_float, B_float));
// Test for double complex matrices
Eigen::MatrixXcd A_double, B_double;
generate_random_matrix_pair(dim, A_double, B_double);
CALL_SUBTEST_4(complex_qz(A_double, B_double)); CALL_SUBTEST_4(complex_qz(A_double, B_double));
} }
} }

View File

@@ -186,7 +186,7 @@ inline void on_temporary_creation(long int size, int) {
namespace Eigen { namespace Eigen {
static std::vector<std::string> g_test_stack; static std::vector<std::string> g_test_stack;
// level == 0 <=> abort if test fail // level == 0 <=> return 1 if test fail
// level >= 1 <=> warning message to std::cerr if test fail // level >= 1 <=> warning message to std::cerr if test fail
static int g_test_level = 0; static int g_test_level = 0;
static int g_repeat = 1; static int g_repeat = 1;
@@ -356,7 +356,7 @@ inline void verify_impl(bool condition, const char* testname, const char* file,
const int test_stack_size = static_cast<int>(Eigen::g_test_stack.size()); 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"; for (int i = test_stack_size - 1; i >= 0; --i) std::cerr << " - " << Eigen::g_test_stack[i] << "\n";
std::cerr << "\n"; std::cerr << "\n";
if (Eigen::g_test_level == 0) abort(); if (Eigen::g_test_level == 0) exit(1);
} }
} }
@@ -858,6 +858,12 @@ inline void set_seed_from_string(const char* str) {
g_has_set_seed = true; g_has_set_seed = true;
} }
inline void set_seed_from_time() {
using namespace std::chrono;
long long ns = duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
g_seed = static_cast<decltype(g_seed)>(ns);
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
g_has_set_repeat = false; g_has_set_repeat = false;
g_has_set_seed = false; g_has_set_seed = false;
@@ -896,7 +902,7 @@ int main(int argc, char* argv[]) {
char* env_EIGEN_SEED = getenv("EIGEN_SEED"); 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 && 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_seed) set_seed_from_time();
if (!g_has_set_repeat) g_repeat = DEFAULT_REPEAT; if (!g_has_set_repeat) g_repeat = DEFAULT_REPEAT;
std::cout << "Initializing random number generator with seed " << g_seed << std::endl; std::cout << "Initializing random number generator with seed " << g_seed << std::endl;

View File

@@ -454,8 +454,16 @@ ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD>::compu
} }
} }
if (!(mode == 1 && isBempty) && !(mode == 2 && isBempty) && OP.info() != Success) if (!(mode == 1 && isBempty) && !(mode == 2 && isBempty) && OP.info() != Success) {
std::cout << "Error factoring matrix" << std::endl; m_info = OP.info() delete[] v;
delete[] iparam;
delete[] ipntr;
delete[] workd;
delete[] workl;
delete[] resid;
m_isInitialized = false;
return *this;
}
do { do {
internal::arpack_wrapper<Scalar, RealScalar>::saupd(&ido, bmat, &n, whch, &nev, &tol, resid, &ncv, v, &ldv, iparam, internal::arpack_wrapper<Scalar, RealScalar>::saupd(&ido, bmat, &n, whch, &nev, &tol, resid, &ncv, v, &ldv, iparam,
@@ -572,7 +580,7 @@ ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD>::compu
delete[] workl; delete[] workl;
delete[] resid; delete[] resid;
m_isInitialized = true; m_isInitialized = (m_info == Success);
return *this; return *this;
} }