// 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;
}