// Copyright (C) 2009 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include <dlib/matrix.h> #include <sstream> #include <string> #include <cstdlib> #include <ctime> #include <vector> #include "../stl_checked.h" #include "../array.h" #include "../rand.h" #include <dlib/string.h> #include "tester.h" namespace { using namespace test; using namespace dlib; using namespace std; logger dlog("test.matrix_lu"); dlib::rand rnd; // ---------------------------------------------------------------------------------------- template <typename mat_type> const matrix<typename mat_type::type> symm(const mat_type& m) { return m*trans(m); } // ---------------------------------------------------------------------------------------- template <typename type> const matrix<type> randmat(long r, long c) { matrix<type> m(r,c); for (long row = 0; row < m.nr(); ++row) { for (long col = 0; col < m.nc(); ++col) { m(row,col) = static_cast<type>(rnd.get_random_double()); } } return m; } template <typename type, long NR, long NC> const matrix<type,NR,NC> randmat() { matrix<type,NR,NC> m; for (long row = 0; row < m.nr(); ++row) { for (long col = 0; col < m.nc(); ++col) { m(row,col) = static_cast<type>(rnd.get_random_double()); } } return m; } // ---------------------------------------------------------------------------------------- template <typename matrix_type> void test_lu ( const matrix_type& m) { typedef typename matrix_type::type type; const type eps = 10*max(abs(m))*sqrt(std::numeric_limits<type>::epsilon()); dlog << LDEBUG << "test_lu(): " << m.nr() << " x " << m.nc() << " eps: " << eps; print_spinner(); lu_decomposition<matrix_type> test(m); DLIB_TEST(test.is_square() == (m.nr() == m.nc())); DLIB_TEST(test.nr() == m.nr()); DLIB_TEST(test.nc() == m.nc()); dlog << LDEBUG << "m.nr(): " << m.nr() << " m.nc(): " << m.nc(); type temp; DLIB_TEST_MSG( (temp= max(abs(test.get_l()*test.get_u() - rowm(m,test.get_pivot())))) < eps,temp); if (test.is_square()) { // none of the matrices we should be passing in to test_lu() should be singular. DLIB_TEST_MSG (abs(test.det()) > eps/100, "det: " << test.det() ); dlog << LDEBUG << "big det: " << test.det(); DLIB_TEST(test.is_singular() == false); matrix<type> m2; matrix<type,0,1> col; m2 = identity_matrix<type>(m.nr()); DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); m2 = randmat<type>(m.nr(),5); DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); m2 = randmat<type>(m.nr(),1); DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); col = randmat<type>(m.nr(),1); DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2))); // now make us a singular matrix if (m.nr() > 1) { matrix<type> sm(m); set_colm(sm,0) = colm(sm,1); lu_decomposition<matrix_type> test2(sm); DLIB_TEST_MSG( (temp= max(abs(test2.get_l()*test2.get_u() - rowm(sm,test2.get_pivot())))) < eps,temp); // these checks are only accurate for small matrices if (test2.nr() < 100) { DLIB_TEST_MSG(test2.is_singular() == true,"det: " << test2.det()); DLIB_TEST_MSG(abs(test2.det()) < eps,"det: " << test2.det()); } } } } // ---------------------------------------------------------------------------------------- void matrix_test_double() { test_lu(10*randmat<double>(2,2)); test_lu(10*randmat<double>(1,1)); test_lu(10*symm(randmat<double>(2,2))); test_lu(10*randmat<double>(4,4)); test_lu(10*randmat<double>(9,4)); test_lu(10*randmat<double>(3,8)); test_lu(10*randmat<double>(15,15)); test_lu(2*symm(randmat<double>(15,15))); test_lu(10*randmat<double>(100,100)); test_lu(10*randmat<double>(137,200)); test_lu(10*randmat<double>(200,101)); test_lu(10*randmat<double,2,2>()); test_lu(10*randmat<double,1,1>()); test_lu(10*randmat<double,4,3>()); test_lu(10*randmat<double,4,4>()); test_lu(10*randmat<double,9,4>()); test_lu(10*randmat<double,3,8>()); test_lu(10*randmat<double,15,15>()); test_lu(10*randmat<double,100,100>()); test_lu(10*randmat<double,137,200>()); test_lu(10*randmat<double,200,101>()); typedef matrix<double,0,0,default_memory_manager, column_major_layout> mat; test_lu(mat(3*randmat<double>(4,4))); test_lu(mat(3*randmat<double>(9,4))); test_lu(mat(3*randmat<double>(3,8))); } // ---------------------------------------------------------------------------------------- void matrix_test_float() { // ------------------------------- test_lu(3*randmat<float>(1,1)); test_lu(3*randmat<float>(2,2)); test_lu(3*randmat<float>(4,4)); test_lu(3*randmat<float>(9,4)); test_lu(3*randmat<float>(3,8)); test_lu(3*randmat<float>(137,200)); test_lu(3*randmat<float>(200,101)); test_lu(3*randmat<float,1,1>()); test_lu(3*randmat<float,2,2>()); test_lu(3*randmat<float,4,3>()); test_lu(3*randmat<float,4,4>()); test_lu(3*randmat<float,9,4>()); test_lu(3*randmat<float,3,8>()); test_lu(3*randmat<float,137,200>()); test_lu(3*randmat<float,200,101>()); typedef matrix<float,0,0,default_memory_manager, column_major_layout> mat; test_lu(mat(3*randmat<float>(4,4))); test_lu(mat(3*randmat<float>(9,4))); test_lu(mat(3*randmat<float>(3,8))); } // ---------------------------------------------------------------------------------------- class matrix_tester : public tester { public: matrix_tester ( ) : tester ("test_matrix_lu", "Runs tests on the matrix LU component.") { //rnd.set_seed(cast_to_string(time(0))); } void perform_test ( ) { dlog << LINFO << "seed string: " << rnd.get_seed(); dlog << LINFO << "begin testing with double"; matrix_test_double(); dlog << LINFO << "begin testing with float"; matrix_test_float(); } } a; }