// SPDX-License-Identifier: Apache-2.0 // // Copyright 2011-2017 Ryan Curtin (http://www.ratml.org/) // Copyright 2017 National ICT Australia (NICTA) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ------------------------------------------------------------------------ #include #include "catch.hpp" using namespace arma; TEST_CASE("fn_eigs_test", "[eigs_sym]") { for (size_t trial = 0; trial < 10; ++trial) { // Test ARPACK decomposition of sparse matrices. sp_mat m(1000, 1000); sp_vec dd; for (size_t i = 0; i < 10; ++i) { dd.sprandu(1000, 1, 0.15); double eig = 10.0 * randu(); m += eig * dd * dd.t(); } mat d(m); // Eigendecompose, getting first 5 eigenvectors. vec sp_eigval; mat sp_eigvec; eigs_sym(sp_eigval, sp_eigvec, m, 5); // Do the same for the dense case. vec eigval; mat eigvec; eig_sym(eigval, eigvec, d); for (uword i = 0; i < 5; ++i) { // It may be pointed the wrong direction. REQUIRE( sp_eigval(i) == Approx(eigval(i + 995)).margin(0.01) ); for (uword j = 0; j < 1000; ++j) { REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, i + 995))).margin(0.01) ); } } } } TEST_CASE("fn_eigs_float_test", "[eigs_sym]") { for (size_t trial = 0; trial < 10; ++trial) { // Test ARPACK decomposition of sparse matrices. SpMat m(100, 100); SpCol dd; for (size_t i = 0; i < 10; ++i) { dd.sprandu(100, 1, 0.15); float eig = 10.0 * randu(); m += eig * dd * dd.t(); } Mat d(m); // Eigendecompose, getting first 5 eigenvectors. Col sp_eigval; Mat sp_eigvec; eigs_sym(sp_eigval, sp_eigvec, m, 5); // Do the same for the dense case. Col eigval; Mat eigvec; eig_sym(eigval, eigvec, d); for (uword i = 0; i < 5; ++i) { // It may be pointed the wrong direction. REQUIRE( sp_eigval(i) == Approx(eigval(i + 95)).margin(0.01) ); for (uword j = 0; j < 100; ++j) { REQUIRE(std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, i + 95))).margin(0.01) ); } } } } TEST_CASE("fn_eigs_sm_test", "[eigs_sym]") { for (size_t trial = 0; trial < 10; ++trial) { // Test ARPACK decomposition of sparse matrices. sp_mat m(100, 100); for (uword i = 0; i < 100; ++i) { m(i, i) = i + 10; } mat d(m); // Eigendecompose, getting first 5 eigenvectors. vec sp_eigval; mat sp_eigvec; eigs_sym(sp_eigval, sp_eigvec, m, 5, "sm"); // Do the same for the dense case. vec eigval; mat eigvec; eig_sym(eigval, eigvec, d); for (size_t i = 0; i < 5; ++i) { // It may be pointed the wrong direction. REQUIRE( sp_eigval(i) == Approx(eigval(i)).margin(0.01) ); for (size_t j = 0; j < 100; ++j) { REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, i))).margin(0.01) ); } } } } TEST_CASE("fn_eigs_sigma_test", "[eigs_sym]") { const uword n_trials = 10; uword count = 0; for(uword trial=0; trial < n_trials; ++trial) { // Test ARPACK decomposition of sparse matrices. sp_mat m; m.sprandu(100, 100, 0.1); m = m.t() + m; for(uword i = 0; i < 100; ++i) { m(i, i) = i + 10; } mat d(m); // Eigendecompose, getting first 5 eigenvectors around 12.1. vec sp_eigval; mat sp_eigvec; const bool status_sparse = eigs_sym(sp_eigval, sp_eigvec, m, 5, 12.1); // Do the same for the dense case. vec eigval; mat eigvec; const bool status_dense = eig_sym(eigval, eigvec, d); if(status_sparse && status_dense) { ++count; // The first sparse eignevalue returned may not be the smallest---so we have to find the right place in the dense eigenvalues. uword dense_index = 0; while ((dense_index < eigval.n_elem - 1) && (std::abs(sp_eigval(0) - eigval(dense_index)) > std::abs(sp_eigval(0) - eigval(dense_index + 1)))) { ++dense_index; } for(uword i = 0; i < 5; ++i) { // It may be pointed the wrong direction. REQUIRE( sp_eigval(i) == Approx(eigval(dense_index + i)).margin(0.01) ); for (size_t j = 0; j < 100; ++j) { REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_index + i))).margin(0.01) ); } } } } REQUIRE( count > 0 ); }