Commit f3184b9b authored by Davis King's avatar Davis King

More code cleanup and spec refinement. I also added a unit test for the symmetric_matrix_cache.

Finally, I put the new structs for determining the return types from colm/rowm/diag
into the proper places.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403988
parent 71051985
......@@ -9,6 +9,7 @@
#include "matrix/matrix_math_functions.h"
#include "matrix/matrix_assign.h"
#include "matrix/matrix_la.h"
#include "matrix/symmetric_matrix_cache.h"
#ifdef DLIB_USE_BLAS
#include "matrix/matrix_blas_bindings.h"
......
......@@ -255,6 +255,12 @@ namespace dlib
return matrix_op<op>(op(m.ref(),row));
}
template <typename EXP>
struct rowm_exp
{
typedef matrix_op<op_rowm<EXP> > type;
};
// ----------------------------------------------------------------------------------------
template <typename M>
......@@ -404,6 +410,12 @@ namespace dlib
return matrix_op<op>(op(m.ref(),col));
}
template <typename EXP>
struct colm_exp
{
typedef matrix_op<op_colm<EXP> > type;
};
// ----------------------------------------------------------------------------------------
template <typename M>
......
......@@ -140,6 +140,36 @@ namespace dlib
R(i) == m(row,i)
!*/
template <typename EXP>
struct rowm_exp
{
/*!
WHAT THIS OBJECT REPRESENTS
This struct allows you to determine the type of matrix expression
object returned from the rowm(m,row) function. An example makes its
use clear:
template <typename EXP>
void do_something( const matrix_exp<EXP>& mat)
{
// r is a matrix expression that aliases mat.
typename rowm_exp<EXP>::type r = rowm(mat,0);
// Print the first row of mat. So we see that by using
// rowm_exp we can save the object returned by rowm() in
// a local variable.
cout << r << endl;
// Note that you can only save the return value of rowm() to
// a local variable if the argument to rowm() has a lifetime
// beyond the rowm() expression. The example shown above is
// OK but the following would result in undefined behavior:
typename rowm_exp<EXP>::type bad = rowm(mat + mat,0);
}
!*/
typedef type_of_expression_returned_by_rowm type;
};
// ----------------------------------------------------------------------------------------
const matrix_exp rowm (
......@@ -197,6 +227,36 @@ namespace dlib
R(i) == m(i,col)
!*/
template <typename EXP>
struct colm_exp
{
/*!
WHAT THIS OBJECT REPRESENTS
This struct allows you to determine the type of matrix expression
object returned from the colm(m,col) function. An example makes its
use clear:
template <typename EXP>
void do_something( const matrix_exp<EXP>& mat)
{
// c is a matrix expression that aliases mat.
typename colm_exp<EXP>::type c = colm(mat,0);
// Print the first column of mat. So we see that by using
// colm_exp we can save the object returned by colm() in
// a local variable.
cout << c << endl;
// Note that you can only save the return value of colm() to
// a local variable if the argument to colm() has a lifetime
// beyond the colm() expression. The example shown above is
// OK but the following would result in undefined behavior:
typename colm_exp<EXP>::type bad = colm(mat + mat,0);
}
!*/
typedef type_of_expression_returned_by_colm type;
};
// ----------------------------------------------------------------------------------------
const matrix_exp colm (
......
......@@ -1114,6 +1114,12 @@ namespace dlib
return matrix_op<op>(op(m.ref()));
}
template <typename EXP>
struct diag_exp
{
typedef matrix_op<op_diag<EXP> > type;
};
// ----------------------------------------------------------------------------------------
template <typename M, typename target_type>
......
......@@ -27,6 +27,36 @@ namespace dlib
of m in the order R(0)==m(0,0), R(1)==m(1,1), R(2)==m(2,2) and so on.
!*/
template <typename EXP>
struct diag_exp
{
/*!
WHAT THIS OBJECT REPRESENTS
This struct allows you to determine the type of matrix expression
object returned from the diag() function. An example makes its
use clear:
template <typename EXP>
void do_something( const matrix_exp<EXP>& mat)
{
// d is a matrix expression that aliases mat.
typename diag_exp<EXP>::type d = diag(mat);
// Print the diagonal of mat. So we see that by using
// diag_exp we can save the object returned by diag() in
// a local variable.
cout << d << endl;
// Note that you can only save the return value of diag() to
// a local variable if the argument to diag() has a lifetime
// beyond the diag() expression. The example shown above is
// OK but the following would result in undefined behavior:
typename diag_exp<EXP>::type bad = diag(mat + mat);
}
!*/
typedef type_of_expression_returned_by_diag type;
};
// ----------------------------------------------------------------------------------------
const matrix_exp diagm (
......
......@@ -436,26 +436,6 @@ namespace dlib
p.second));
}
// ----------------------------------------------------------------------------------------
template <typename EXP>
struct colm_exp
{
typedef matrix_op<op_colm<EXP> > type;
};
template <typename EXP>
struct rowm_exp
{
typedef matrix_op<op_rowm<EXP> > type;
};
template <typename EXP>
struct diag_exp
{
typedef matrix_op<op_diag<EXP> > type;
};
// ----------------------------------------------------------------------------------------
template <typename EXP, typename cache_element_type>
......
......@@ -88,6 +88,7 @@ set (tests
string.cpp
svm_c_linear.cpp
svm.cpp
symmetric_matrix_cache.cpp
thread_pool.cpp
threads.cpp
timer.cpp
......
......@@ -98,6 +98,7 @@ SRC += std_vector_c.cpp
SRC += string.cpp
SRC += svm.cpp
SRC += svm_c_linear.cpp
SRC += symmetric_matrix_cache.cpp
SRC += thread_pool.cpp
SRC += threads.cpp
SRC += timer.cpp
......
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#include "tester.h"
#include <dlib/matrix.h>
#include <dlib/rand.h>
#include <vector>
#include <sstream>
namespace
{
using namespace test;
using namespace dlib;
using namespace std;
dlib::logger dlog("test.symmetric_matrix_cache");
class test_symmetric_matrix_cache : public tester
{
/*!
WHAT THIS OBJECT REPRESENTS
This object represents a unit test. When it is constructed
it adds itself into the testing framework.
!*/
public:
test_symmetric_matrix_cache (
) :
tester (
"test_symmetric_matrix_cache", // the command line argument name for this test
"Run tests on the symmetric_matrix_cache function.", // the command line argument description
0 // the number of command line arguments for this test
)
{
}
dlib::rand::float_1a rnd;
// -----------------------------------
template <typename EXP1, typename EXP2>
void test_colm_exp (
const matrix_exp<EXP1>& m1,
const matrix_exp<EXP2>& m2
)
{
for (long i = 0; i < m1.nc(); ++i)
{
typename colm_exp<EXP1>::type c1 = colm(m1,i);
typename colm_exp<EXP2>::type c2 = colm(m2,i);
DLIB_TEST(equal(c1 , c2));
DLIB_TEST(equal(colm(m1,i) , c2));
DLIB_TEST(equal(c1 , colm(m2,i)));
DLIB_TEST(equal(colm(m1,i) , colm(m2,i)));
}
// Get a bunch of columns at once to test out the reference
// counting and automatic cache expansion built into the symmetric_matrix_cache.
// This test verifies that, for example, getting column 3 doesn't stomp on
// any of the previous columns.
typename colm_exp<EXP1>::type c1_0 = colm(m1,0);
typename colm_exp<EXP1>::type c1_1 = colm(m1,1);
typename colm_exp<EXP1>::type c1_2 = colm(m1,2);
typename colm_exp<EXP1>::type c1_3 = colm(m1,3);
typename colm_exp<EXP1>::type c1_4 = colm(m1,4);
typename colm_exp<EXP1>::type c1_5 = colm(m1,5);
typename colm_exp<EXP2>::type c2_0 = colm(m2,0);
typename colm_exp<EXP2>::type c2_1 = colm(m2,1);
typename colm_exp<EXP2>::type c2_2 = colm(m2,2);
typename colm_exp<EXP2>::type c2_3 = colm(m2,3);
typename colm_exp<EXP2>::type c2_4 = colm(m2,4);
typename colm_exp<EXP2>::type c2_5 = colm(m2,5);
DLIB_TEST(equal(c1_0, c2_0));
DLIB_TEST(equal(c1_1, c2_1));
DLIB_TEST(equal(c1_2, c2_2));
DLIB_TEST(equal(c1_3, c2_3));
DLIB_TEST(equal(c1_4, c2_4));
DLIB_TEST(equal(c1_5, c2_5));
}
// -----------------------------------
template <typename EXP1, typename EXP2>
void test_rowm_exp (
const matrix_exp<EXP1>& m1,
const matrix_exp<EXP2>& m2
)
{
for (long i = 0; i < m1.nc(); ++i)
{
typename rowm_exp<EXP1>::type r1 = rowm(m1,i);
typename rowm_exp<EXP2>::type r2 = rowm(m2,i);
DLIB_TEST(equal(r1 , r2));
DLIB_TEST(equal(rowm(m1,i) , r2));
DLIB_TEST(equal(r1 , rowm(m2,i)));
DLIB_TEST(equal(rowm(m1,i) , rowm(m2,i)));
}
// Get a bunch of rows at once to test out the reference
// counting and automatic cache expansion built into the symmetric_matrix_cache.
// This test verifies that, for example, getting row 3 doesn't stomp on
// any of the previous rows.
typename rowm_exp<EXP1>::type r1_0 = rowm(m1,0);
typename rowm_exp<EXP1>::type r1_1 = rowm(m1,1);
typename rowm_exp<EXP1>::type r1_2 = rowm(m1,2);
typename rowm_exp<EXP1>::type r1_3 = rowm(m1,3);
typename rowm_exp<EXP1>::type r1_4 = rowm(m1,4);
typename rowm_exp<EXP1>::type r1_5 = rowm(m1,5);
typename rowm_exp<EXP2>::type r2_0 = rowm(m2,0);
typename rowm_exp<EXP2>::type r2_1 = rowm(m2,1);
typename rowm_exp<EXP2>::type r2_2 = rowm(m2,2);
typename rowm_exp<EXP2>::type r2_3 = rowm(m2,3);
typename rowm_exp<EXP2>::type r2_4 = rowm(m2,4);
typename rowm_exp<EXP2>::type r2_5 = rowm(m2,5);
DLIB_TEST(equal(r1_0, r2_0));
DLIB_TEST(equal(r1_1, r2_1));
DLIB_TEST(equal(r1_2, r2_2));
DLIB_TEST(equal(r1_3, r2_3));
DLIB_TEST(equal(r1_4, r2_4));
DLIB_TEST(equal(r1_5, r2_5));
}
// -----------------------------------
template <typename EXP1, typename EXP2>
void test_diag_exp (
const matrix_exp<EXP1>& m1,
const matrix_exp<EXP2>& m2
)
{
typename diag_exp<EXP1>::type c1 = diag(m1);
typename diag_exp<EXP2>::type c2 = diag(m2);
DLIB_TEST(equal(c1 , c2));
DLIB_TEST(equal(diag(m1) , c2));
DLIB_TEST(equal(c1 , diag(m2)));
DLIB_TEST(equal(diag(m1) , diag(m2)));
}
// -----------------------------------
void test_stuff (
long csize
)
{
print_spinner();
dlog << LINFO << "csize: "<< csize;
matrix<double> m = randm(10,10,rnd);
m = make_symmetric(m);
DLIB_TEST(equal(symmetric_matrix_cache<float>(m, csize), matrix_cast<float>(m)));
DLIB_TEST(equal(symmetric_matrix_cache<double>(m, csize), matrix_cast<double>(m)));
dlog << LINFO << "test colm/rowm";
for (long i = 0; i < m.nr(); ++i)
{
DLIB_TEST(equal(colm(symmetric_matrix_cache<float>(m, csize),i), colm(matrix_cast<float>(m),i)));
DLIB_TEST(equal(rowm(symmetric_matrix_cache<float>(m, csize),i), rowm(matrix_cast<float>(m),i)));
// things are supposed to be symmetric
DLIB_TEST(equal(colm(symmetric_matrix_cache<float>(m, csize),i), trans(rowm(matrix_cast<float>(m),i))));
DLIB_TEST(equal(rowm(symmetric_matrix_cache<float>(m, csize),i), trans(colm(matrix_cast<float>(m),i))));
}
dlog << LINFO << "test diag";
DLIB_TEST(equal(diag(symmetric_matrix_cache<float>(m,csize)), diag(matrix_cast<float>(m))));
test_colm_exp(symmetric_matrix_cache<float>(m,csize), matrix_cast<float>(m));
test_rowm_exp(symmetric_matrix_cache<float>(m,csize), matrix_cast<float>(m));
test_diag_exp(symmetric_matrix_cache<float>(m,csize), matrix_cast<float>(m));
test_colm_exp(tmp(symmetric_matrix_cache<float>(m,csize)), tmp(matrix_cast<float>(m)));
test_rowm_exp(symmetric_matrix_cache<float>(m,csize), tmp(matrix_cast<float>(m)));
test_diag_exp(tmp(symmetric_matrix_cache<float>(m,csize)), tmp(matrix_cast<float>(m)));
}
void perform_test (
)
{
for (int itr = 0; itr < 5; ++itr)
{
test_stuff(0);
test_stuff(1);
test_stuff(2);
}
}
};
// Create an instance of this object. Doing this causes this test
// to be automatically inserted into the testing framework whenever this cpp file
// is linked into the project. Note that since we are inside an unnamed-namespace
// we won't get any linker errors about the symbol a being defined multiple times.
test_symmetric_matrix_cache a;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment