// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2014-2015 Gael Guennebaud // // 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/. template Array four_denorms(); template <> Array4f four_denorms() { return Array4f(5.60844e-39f, -5.60844e-39f, 4.94e-44f, -4.94e-44f); } template <> Array4d four_denorms() { return Array4d(5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324); } template Array four_denorms() { return four_denorms().cast(); } template ::IsComplex> struct maybe_set_imag_part { static void run(Scalar& x, typename NumTraits::Real y) { numext::imag_ref(x) = y; } }; template struct maybe_set_imag_part { static void run(Scalar&, typename NumTraits::Real) {} }; template void svd_fill_random(MatrixType &m, int Option = 0) { using std::pow; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; Index diagSize = (std::min)(m.rows(), m.cols()); RealScalar s = std::numeric_limits::max_exponent10 / 4; s = internal::random(1, s); Matrix d = Matrix::Random(diagSize); for (Index k = 0; k < diagSize; ++k) d(k) = d(k) * pow(RealScalar(10), internal::random(-s, s)); bool dup = internal::random(0, 10) < 3; // For SelfAdjoint, always use unitary U so the eigenvalues are exactly d // and the conditioning is controlled. For Symmetric/general SVD, randomly // choose unitary or arbitrary U/V. bool unit_uv = (Option == SelfAdjoint) || internal::random(0, 10) < (dup ? 7 : 3); // if we duplicate some diagonal entries, then increase // the chance to preserve them using unitary U and V // duplicate some singular values if (dup) { Index n = internal::random(0, d.size() - 1); for (Index i = 0; i < n; ++i) d(internal::random(0, d.size() - 1)) = d(internal::random(0, d.size() - 1)); } Matrix U(m.rows(), diagSize); Matrix VT(diagSize, m.cols()); if (unit_uv) { // in very rare cases let's try with a pure diagonal matrix if (internal::random(0, 10) < 1) { U.setIdentity(); VT.setIdentity(); } else { createRandomPIMatrixOfRank(diagSize, U.rows(), U.cols(), U); createRandomPIMatrixOfRank(diagSize, VT.rows(), VT.cols(), VT); } } else { U.setRandom(); VT.setRandom(); } Matrix samples(9); samples << Scalar(0), four_denorms(), -RealScalar(1) / NumTraits::highest(), RealScalar(1) / NumTraits::highest(), (std::numeric_limits::min)(), pow((std::numeric_limits::min)(), RealScalar(0.8)); if (Option == Symmetric || Option == SelfAdjoint) { if (Option == SelfAdjoint) m = U * d.asDiagonal() * U.adjoint(); else m = U * d.asDiagonal() * U.transpose(); // randomly nullify some rows/columns { Index count = internal::random(-diagSize, diagSize); for (Index k = 0; k < count; ++k) { Index i = internal::random(0, diagSize - 1); m.row(i).setZero(); m.col(i).setZero(); } if (count < 0) // (partly) cancel some coeffs if (!(dup && unit_uv)) { Index n = internal::random(0, m.size() - 1); for (Index k = 0; k < n; ++k) { Index i = internal::random(0, m.rows() - 1); Index j = internal::random(0, m.cols() - 1); Scalar val = samples(internal::random(0, samples.size() - 1)); maybe_set_imag_part::run(val, samples.real()(internal::random(0, samples.size() - 1))); if (Option == SelfAdjoint) { if (i == j) { // Diagonal entries of a Hermitian matrix must be real. m(i, i) = numext::real(val); } else { // Off-diagonal: m(j,i) = conj(m(i,j)) for Hermitian. m(i, j) = val; m(j, i) = numext::conj(val); } } else { m(i, j) = val; m(j, i) = val; } } } } } else { m = U * d.asDiagonal() * VT; // (partly) cancel some coeffs if (!(dup && unit_uv)) { Index n = internal::random(0, m.size() - 1); for (Index k = 0; k < n; ++k) { Index i = internal::random(0, m.rows() - 1); Index j = internal::random(0, m.cols() - 1); m(i, j) = samples(internal::random(0, samples.size() - 1)); maybe_set_imag_part::run(m(i, j), samples.real()(internal::random(0, samples.size() - 1))); } } } }