// Copyright (C) 2012 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include <dlib/sparse_vector.h> #include "tester.h" #include <dlib/rand.h> #include <dlib/string.h> #include <vector> #include <sstream> #include <ctime> namespace { using namespace test; using namespace dlib; using namespace std; dlib::logger dlog("test.sparse_vector"); void test_sparse_matrix_vector_multiplies() { dlib::rand rnd; const long size = 30; for (int iter = 0; iter < 10; ++iter) { print_spinner(); std::vector<sample_pair> edges; std::vector<ordered_sample_pair> oedges; matrix<double> M(size,size); M = 0; for (long i = 0; i < M.size()/3; ++i) { const long r = rnd.get_random_32bit_number()%M.nr(); const long c = rnd.get_random_32bit_number()%M.nc(); const double d = rnd.get_random_gaussian()*10; M(r,c) += d; oedges.push_back(ordered_sample_pair(r,c,d)); } matrix<double> SM(size,size); SM = 0; for (long i = 0; i < SM.size()/3; ++i) { const long r = rnd.get_random_32bit_number()%SM.nr(); const long c = rnd.get_random_32bit_number()%SM.nc(); const double d = rnd.get_random_gaussian()*10; SM(r,c) += d; if (r != c) SM(c,r) += d; edges.push_back(sample_pair(r,c,d)); } const matrix<double> v = randm(size,1); matrix<double> result; sparse_matrix_vector_multiply(oedges, v, result); DLIB_TEST_MSG(length(M*v - result) < 1e-12, length(M*v - result)); sparse_matrix_vector_multiply(edges, v, result); DLIB_TEST_MSG(length(SM*v - result) < 1e-12, length(SM*v - result)); } } // ---------------------------------------------------------------------------------------- void test_sparse_matrix_vector_multiply1() { print_spinner(); std::map<unsigned long,double> sv; sv[2] = 8; sv[6] = 2.3; matrix<double,10,1> v; v = 0; v(2) = 8; v(6) = 2.3; matrix<double,0,1> r1, r2; r1 = gaussian_randm(4,10)*v; r2 = sparse_matrix_vector_multiply(gaussian_randm(4,std::numeric_limits<long>::max()),sv); DLIB_TEST(max(abs(r1-r2)) < 1e-15); } // ---------------------------------------------------------------------------------------- void test_sparse_matrix_vector_multiply2() { std::vector<std::pair<unsigned long,double> > sv; sv.push_back(make_pair(6, 1.42)); sv.push_back(make_pair(3, 5)); matrix<double,9,1> v; v = 0; v(3) = 5; v(6) = 1.42; matrix<double,0,1> r1, r2; r1 = gaussian_randm(3,9)*v; r2 = sparse_matrix_vector_multiply(gaussian_randm(3,std::numeric_limits<long>::max()),sv); DLIB_TEST(max(abs(r1-r2)) < 1e-15); } // ---------------------------------------------------------------------------------------- void test_make_sparse_vector_inplace() { std::vector<std::pair<unsigned long,double> > vect; vect.push_back(make_pair(4,1)); vect.push_back(make_pair(0,1)); vect.push_back(make_pair(4,1)); vect.push_back(make_pair(3,1)); vect.push_back(make_pair(8,1)); vect.push_back(make_pair(8,1)); vect.push_back(make_pair(8,1)); vect.push_back(make_pair(8,1)); make_sparse_vector_inplace(vect); DLIB_TEST(vect.size() == 4); DLIB_TEST(vect[0].first == 0); DLIB_TEST(vect[1].first == 3); DLIB_TEST(vect[2].first == 4); DLIB_TEST(vect[3].first == 8); DLIB_TEST(vect[0].second == 1); DLIB_TEST(vect[1].second == 1); DLIB_TEST(vect[2].second == 2); DLIB_TEST(vect[3].second == 4); } // ---------------------------------------------------------------------------------------- class sparse_vector_tester : public tester { public: sparse_vector_tester ( ) : tester ( "test_sparse_vector", // the command line argument name for this test "Run tests on the sparse_vector routines.", // the command line argument description 0 // the number of command line arguments for this test ) { } void perform_test ( ) { test_make_sparse_vector_inplace(); std::map<unsigned int, double> v; v[4] = 8; v[2] = -4; v[9] = 10; DLIB_TEST(max(v) == 10); DLIB_TEST(min(v) == -4); v.clear(); v[4] = 8; v[9] = 10; DLIB_TEST(max(v) == 10); DLIB_TEST(min(v) == 0); v.clear(); v[4] = -9; v[9] = -4; DLIB_TEST(max(v) == 0); DLIB_TEST(min(v) == -9); { matrix<double> a(2,2), b(2,2); a = randm(2,2); b = randm(2,2); DLIB_TEST(equal(a-b, subtract(a,b))); DLIB_TEST(equal(a+b, add(a,b))); DLIB_TEST(equal(a-(b+b), subtract(a,b+b))); DLIB_TEST(equal(a+b+b, add(a,b+b))); } { std::map<unsigned long,double> a, b, c; a[1] = 2; a[3] = 5; b[0] = 3; b[1] = 1; c = add(a,b); DLIB_TEST(c.size() == 3); DLIB_TEST(c[0] == 3); DLIB_TEST(c[1] == 3); DLIB_TEST(c[3] == 5); c = subtract(a,b); DLIB_TEST(c.size() == 3); DLIB_TEST(c[0] == -3); DLIB_TEST(c[1] == 1); DLIB_TEST(c[3] == 5); c = add(b,a); DLIB_TEST(c.size() == 3); DLIB_TEST(c[0] == 3); DLIB_TEST(c[1] == 3); DLIB_TEST(c[3] == 5); c = subtract(b,a); DLIB_TEST(c.size() == 3); DLIB_TEST(c[0] == 3); DLIB_TEST(c[1] == -1); DLIB_TEST(c[3] == -5); std::vector<std::pair<unsigned long,double> > aa, bb, cc; aa.assign(a.begin(), a.end()); bb.assign(b.begin(), b.end()); cc = add(aa,bb); DLIB_TEST(cc.size() == 3); DLIB_TEST(cc[0].first == 0); DLIB_TEST(cc[1].first == 1); DLIB_TEST(cc[2].first == 3); DLIB_TEST(cc[0].second == 3); DLIB_TEST(cc[1].second == 3); DLIB_TEST(cc[2].second == 5); cc = subtract(aa,bb); DLIB_TEST(cc.size() == 3); DLIB_TEST(cc[0].first == 0); DLIB_TEST(cc[1].first == 1); DLIB_TEST(cc[2].first == 3); DLIB_TEST(cc[0].second == -3); DLIB_TEST(cc[1].second == 1); DLIB_TEST(cc[2].second == 5); cc = add(bb,aa); DLIB_TEST(cc.size() == 3); DLIB_TEST(cc[0].first == 0); DLIB_TEST(cc[1].first == 1); DLIB_TEST(cc[2].first == 3); DLIB_TEST(cc[0].second == 3); DLIB_TEST(cc[1].second == 3); DLIB_TEST(cc[2].second == 5); cc = subtract(bb,aa); DLIB_TEST(cc.size() == 3); DLIB_TEST(cc[0].first == 0); DLIB_TEST(cc[1].first == 1); DLIB_TEST(cc[2].first == 3); DLIB_TEST(cc[0].second == 3); DLIB_TEST(cc[1].second == -1); DLIB_TEST(cc[2].second == -5); } test_sparse_matrix_vector_multiplies(); test_sparse_matrix_vector_multiply1(); test_sparse_matrix_vector_multiply2(); { matrix<double,0,1> a, b; a = gaussian_randm(6,1, 0); b = gaussian_randm(6,1, 1); std::vector<std::pair<unsigned long,double> > aa, bb; assign(aa, a); assign(bb, b); // dot() does something special when the sparse vectors have entries for // each dimension, which is what happens when they are copied from dense // vectors. So the point of the tests in this block is to make sure dot() // works right in this case. DLIB_TEST(std::abs(dot(a,b) - dot(aa,bb)) < 1e-14); a(3) = 0; assign(aa, a); DLIB_TEST(std::abs(dot(a,b) - dot(aa,bb)) < 1e-14); } } }; sparse_vector_tester a; }