// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2010 Benoit Jacob // // 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/. // SPDX-License-Identifier: MPL-2.0 #include "main.h" #include // Verify that U * B * V^T ≈ A for the bidiagonal decomposition. template void upperbidiag_verify(const MatrixType& a) { const Index rows = a.rows(); const Index cols = a.cols(); typedef Matrix RealMatrixType; typedef Matrix TransposeMatrixType; internal::UpperBidiagonalization ubd(a); RealMatrixType b(rows, cols); b.setZero(); b.block(0, 0, cols, cols) = ubd.bidiagonal(); MatrixType c = ubd.householderU() * b * ubd.householderV().adjoint(); VERIFY_IS_APPROX(a, c); TransposeMatrixType d = ubd.householderV() * b.adjoint() * ubd.householderU().adjoint(); VERIFY_IS_APPROX(a.adjoint(), d); } // Verify the unblocked path directly. template void upperbidiag_verify_unblocked(const MatrixType& a) { const Index rows = a.rows(); const Index cols = a.cols(); typedef Matrix RealMatrixType; internal::UpperBidiagonalization ubd(rows, cols); ubd.computeUnblocked(a); RealMatrixType b(rows, cols); b.setZero(); b.block(0, 0, cols, cols) = ubd.bidiagonal(); MatrixType c = ubd.householderU() * b * ubd.householderV().adjoint(); VERIFY_IS_APPROX(a, c); } // Test with a random matrix of given dimensions. template void upperbidiag(const MatrixType& m) { MatrixType a = MatrixType::Random(m.rows(), m.cols()); upperbidiag_verify(a); } template void upperbidiag_default_construct() { internal::UpperBidiagonalization bidiag; VERIFY_IS_EQUAL(bidiag.householder().rows(), MatrixType::RowsAtCompileTime == Dynamic ? 0 : MatrixType::RowsAtCompileTime); VERIFY_IS_EQUAL(bidiag.householder().cols(), MatrixType::ColsAtCompileTime == Dynamic ? 0 : MatrixType::ColsAtCompileTime); VERIFY_IS_EQUAL(bidiag.bidiagonal().rows(), MatrixType::ColsAtCompileTime == Dynamic ? 0 : MatrixType::ColsAtCompileTime); VERIFY_IS_EQUAL(bidiag.bidiagonal().cols(), MatrixType::ColsAtCompileTime == Dynamic ? 0 : MatrixType::ColsAtCompileTime); } // Test with structured/ill-conditioned matrices. template void upperbidiag_structured(Index rows, Index cols) { typedef Matrix MatrixType; // Zero matrix. { MatrixType a = MatrixType::Zero(rows, cols); upperbidiag_verify(a); } // Identity (padded if non-square). { MatrixType a = MatrixType::Zero(rows, cols); a.block(0, 0, cols, cols).setIdentity(); upperbidiag_verify(a); } // Matrix with large dynamic range (graded singular values). { MatrixType U = MatrixType::Random(rows, rows); MatrixType V = MatrixType::Random(cols, cols); // Orthogonalize via QR. Eigen::HouseholderQR qrU(U), qrV(V); MatrixType Q_U = qrU.householderQ() * MatrixType::Identity(rows, rows); MatrixType Q_V = qrV.householderQ() * MatrixType::Identity(cols, cols); // Graded singular values: 1, 1e-2, 1e-4, ... MatrixType sigma = MatrixType::Zero(rows, cols); typedef typename NumTraits::Real RealScalar; for (Index i = 0; i < cols; ++i) { sigma(i, i) = static_cast(std::pow(RealScalar(10), -RealScalar(2) * i / (cols > 1 ? cols - 1 : 1))); } MatrixType a = Q_U * sigma * Q_V.adjoint(); upperbidiag_verify(a); } // Rank-1 matrix. { Matrix u = Matrix::Random(rows); Matrix v = Matrix::Random(cols); MatrixType a = u * v; upperbidiag_verify(a); } } EIGEN_DECLARE_TEST(upperbidiagonalization) { for (int i = 0; i < g_repeat; i++) { // Original small/fixed-size tests (unblocked path, bcols < 48). CALL_SUBTEST_1(upperbidiag(MatrixXf(3, 3))); CALL_SUBTEST_2(upperbidiag(MatrixXd(17, 12))); CALL_SUBTEST_3(upperbidiag(MatrixXcf(20, 20))); CALL_SUBTEST_4(upperbidiag(Matrix, Dynamic, Dynamic, RowMajor>(16, 15))); CALL_SUBTEST_5(upperbidiag(Matrix())); CALL_SUBTEST_6(upperbidiag(Matrix())); CALL_SUBTEST_7(upperbidiag(Matrix())); // Larger sizes that exercise the blocked path (bcols >= 48). CALL_SUBTEST_8(upperbidiag(MatrixXf(64, 64))); CALL_SUBTEST_9(upperbidiag(MatrixXd(100, 80))); CALL_SUBTEST_10(upperbidiag(MatrixXd(200, 200))); CALL_SUBTEST_11(upperbidiag(MatrixXf(300, 100))); // Tall-skinny matrices. CALL_SUBTEST_12(upperbidiag(MatrixXd(500, 10))); CALL_SUBTEST_13(upperbidiag(MatrixXf(1000, 50))); // Explicit unblocked path tests. CALL_SUBTEST_14(upperbidiag_default_construct()); CALL_SUBTEST_14(upperbidiag_default_construct()); CALL_SUBTEST_14(upperbidiag_verify_unblocked(MatrixXf(MatrixXf::Random(10, 8)))); CALL_SUBTEST_14(upperbidiag_verify_unblocked(MatrixXd(MatrixXd::Random(64, 64)))); CALL_SUBTEST_14(upperbidiag_verify_unblocked(MatrixXd(MatrixXd::Random(100, 80)))); // Structured/ill-conditioned matrices. CALL_SUBTEST_15(upperbidiag_structured(20, 15)); CALL_SUBTEST_15(upperbidiag_structured(100, 80)); CALL_SUBTEST_15(upperbidiag_structured(200, 200)); } }