Add random matrix generation via SVD
diff --git a/test/random_matrix.cpp b/test/random_matrix.cpp
new file mode 100644
index 0000000..fb877de
--- /dev/null
+++ b/test/random_matrix.cpp
@@ -0,0 +1,136 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2021 Kolja Brix <kolja.brix@rwth-aachen.de>
+//
+// 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>
+void check_generateRandomUnitaryMatrix(const Index dim)
+{
+    const MatrixType Q = generateRandomUnitaryMatrix<MatrixType>(dim);
+
+    // validate dimensions
+    VERIFY_IS_EQUAL(Q.rows(), dim);
+    VERIFY_IS_EQUAL(Q.cols(), dim);
+
+    VERIFY_IS_UNITARY(Q);
+}
+
+template<typename VectorType, typename RealScalarType>
+void check_setupRandomSvs(const Index dim, const RealScalarType max)
+{
+    const VectorType v = setupRandomSvs<VectorType, RealScalarType>(dim, max);
+
+    // validate dimensions
+    VERIFY_IS_EQUAL(v.size(), dim);
+
+    // check entries
+    for(Index i = 0; i < v.size(); ++i)
+        VERIFY_GE(v(i), 0);
+    for(Index i = 0; i < v.size()-1; ++i)
+        VERIFY_GE(v(i), v(i+1));
+}
+
+template<typename VectorType, typename RealScalarType>
+void check_setupRangeSvs(const Index dim, const RealScalarType min, const RealScalarType max)
+{
+    const VectorType v = setupRangeSvs<VectorType, RealScalarType>(dim, min, max);
+
+    // validate dimensions
+    VERIFY_IS_EQUAL(v.size(), dim);
+
+    // check entries
+    if(dim == 1) {
+        VERIFY_IS_APPROX(v(0), min);
+    } else {
+        VERIFY_IS_APPROX(v(0), max);
+        VERIFY_IS_APPROX(v(dim-1), min);
+    }
+    for(Index i = 0; i < v.size()-1; ++i)
+        VERIFY_GE(v(i), v(i+1));
+}
+
+template<typename MatrixType, typename RealScalar, typename RealVectorType>
+void check_generateRandomMatrixSvs(const Index rows, const Index cols, const Index diag_size,
+                                   const RealScalar min_svs, const RealScalar max_svs)
+{
+    RealVectorType svs = setupRangeSvs<RealVectorType, RealScalar>(diag_size, min_svs, max_svs);
+
+    MatrixType M;
+    generateRandomMatrixSvs(svs, rows, cols, M);
+
+    // validate dimensions
+    VERIFY_IS_EQUAL(M.rows(), rows);
+    VERIFY_IS_EQUAL(M.cols(), cols);
+    VERIFY_IS_EQUAL(svs.size(), diag_size);
+
+    // validate singular values
+    Eigen::JacobiSVD<MatrixType> SVD(M);
+    VERIFY_IS_APPROX(svs, SVD.singularValues());
+}
+
+template<typename MatrixType>
+void check_random_matrix(const MatrixType &m)
+{
+    enum {
+        Rows = MatrixType::RowsAtCompileTime,
+        Cols = MatrixType::ColsAtCompileTime,
+        DiagSize = EIGEN_SIZE_MIN_PREFER_DYNAMIC(Rows, Cols)
+    };
+    typedef typename MatrixType::Scalar Scalar;
+    typedef typename NumTraits<Scalar>::Real RealScalar;
+    typedef Matrix<RealScalar, DiagSize, 1> RealVectorType;
+
+    const Index rows = m.rows(), cols = m.cols();
+    const Index diag_size = (std::min)(rows, cols);
+    const RealScalar min_svs = 1.0, max_svs = 1000.0;
+
+    // check generation of unitary random matrices
+    typedef Matrix<Scalar, Rows, Rows> MatrixAType;
+    typedef Matrix<Scalar, Cols, Cols> MatrixBType;
+    check_generateRandomUnitaryMatrix<MatrixAType>(rows);
+    check_generateRandomUnitaryMatrix<MatrixBType>(cols);
+
+    // test generators for singular values
+    check_setupRandomSvs<RealVectorType, RealScalar>(diag_size, max_svs);
+    check_setupRangeSvs<RealVectorType, RealScalar>(diag_size, min_svs, max_svs);
+
+    // check generation of random matrices
+    check_generateRandomMatrixSvs<MatrixType, RealScalar, RealVectorType>(rows, cols, diag_size, min_svs, max_svs);
+}
+
+EIGEN_DECLARE_TEST(random_matrix)
+{
+  for(int i = 0; i < g_repeat; i++) {
+    CALL_SUBTEST_1(check_random_matrix(Matrix<float, 1, 1>()));
+    CALL_SUBTEST_2(check_random_matrix(Matrix<float, 4, 4>()));
+    CALL_SUBTEST_3(check_random_matrix(Matrix<float, 2, 3>()));
+    CALL_SUBTEST_4(check_random_matrix(Matrix<float, 7, 4>()));
+
+    CALL_SUBTEST_5(check_random_matrix(Matrix<double, 1, 1>()));
+    CALL_SUBTEST_6(check_random_matrix(Matrix<double, 6, 6>()));
+    CALL_SUBTEST_7(check_random_matrix(Matrix<double, 5, 3>()));
+    CALL_SUBTEST_8(check_random_matrix(Matrix<double, 4, 9>()));
+
+    CALL_SUBTEST_9(check_random_matrix(Matrix<std::complex<float>, 12, 12>()));
+    CALL_SUBTEST_10(check_random_matrix(Matrix<std::complex<float>, 7, 14>()));
+    CALL_SUBTEST_11(check_random_matrix(Matrix<std::complex<double>, 15, 11>()));
+    CALL_SUBTEST_12(check_random_matrix(Matrix<std::complex<double>, 6, 9>()));
+
+    CALL_SUBTEST_13(check_random_matrix(
+        MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
+    CALL_SUBTEST_14(check_random_matrix(
+        MatrixXd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
+    CALL_SUBTEST_15(check_random_matrix(
+        MatrixXcf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
+    CALL_SUBTEST_16(check_random_matrix(
+        MatrixXcd(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
+  }
+}