Commit d8e7ee4c authored by Davis King's avatar Davis King

Moved some functions for dealing with sparse vectors out of the svm_c_linear_trainer

implementation and into the sparse_vector.h header.  These are the add_to(), subtract_from(),
and max_index_plus_one() functions.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%404167
parent 392c7758
......@@ -11,6 +11,7 @@
#include "../algs.h"
#include "../matrix.h"
#include "../string.h"
#include "../svm/sparse_vector.h"
#include <vector>
namespace dlib
......@@ -221,12 +222,7 @@ namespace dlib
// figure out how many elements we need in our dense vectors.
unsigned long max_dim = 0;
for (unsigned long i = 0; i < samples.size(); ++i)
{
if (samples[i].size() > 0)
max_dim = std::max<unsigned long>(max_dim, (--samples[i].end())->first + 1);
}
const unsigned long max_dim = sparse_vector::max_index_plus_one(samples);
// now turn all the samples into dense samples
......
This diff is collapsed.
......@@ -29,6 +29,20 @@ namespace dlib
arithmetic things with sparse vectors.
!*/
// ----------------------------------------------------------------------------------------
/*!A has_unsigned_keys
This is a template where has_unsigned_keys<T>::value == true when T is a
sparse vector that contains unsigned integral keys and false otherwise.
!*/
template <typename T>
struct has_unsigned_keys
{
static const bool value = is_unsigned_type<typename T::value_type::first_type>::value;
};
// ----------------------------------------------------------------------------------------
namespace sparse_vector
......@@ -178,21 +192,74 @@ namespace dlib
(i.e. multiplies every element of the vector a by value)
!*/
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename T>
unsigned long max_index_plus_one (
const T& samples
);
/*!
requires
- samples == a single vector (either sparse or dense), or a container
of vectors which is either a dlib::matrix of vectors or something
convertible to a dlib::matrix via vector_to_matrix() (e.g. a std::vector)
Value types of samples include (but are not limited to):
- dlib::matrix<double,0,1> // A single dense vector
- std::map<unsigned int, double> // A single sparse vector
- std::vector<dlib::matrix<double,0,1> > // An array of dense vectors
- std::vector<std::map<unsigned int, double> > // An array of sparse vectors
ensures
- This function tells you the dimensionality of a set of vectors. The vectors
can be either sparse or dense.
- if (samples.size() == 0) then
- returns 0
- else if (samples contains dense vectors or is a dense vector) then
- returns the number of elements in the first sample vector. This means
we implicitly assume all dense vectors have the same length)
- else
- In this case samples contains sparse vectors or is a sparse vector.
- returns the largest element index in any sample + 1. Note that the element index values
are the values stored in std::pair::first. So this number tells you the dimensionality
of a set of sparse vectors.
!*/
/*!A has_unsigned_keys
// ----------------------------------------------------------------------------------------
This is a template where has_unsigned_keys<T>::value == true when T is a
sparse vector that contains unsigned integral keys and false otherwise.
!*/
template <typename T, long NR, long NC, typename MM, typename L, typename SRC, typename U>
inline void add_to (
matrix<T,NR,NC,MM,L>& dest,
const SRC& src,
const U& C = 1
);
/*!
requires
- SRC == a matrix expression or a sparse vector
- is_vector(dest) == true
- max_index_plus_one(src) <= dest.size()
ensures
- dest += C*src
!*/
template <typename T>
struct has_unsigned_keys
{
static const bool value = is_unsigned_type<typename T::value_type::first_type>::value;
};
// ----------------------------------------------------------------------------------------
template <typename T, long NR, long NC, typename MM, typename L, typename SRC, typename U>
inline void subtract_from (
matrix<T,NR,NC,MM,L>& dest,
const SRC& src,
const U& C = 1
);
/*!
requires
- SRC == a matrix expression or a sparse vector
- is_vector(dest) == true
- max_index_plus_one(src) <= dest.size()
ensures
- dest -= C*src
!*/
// ----------------------------------------------------------------------------------------
}
// ----------------------------------------------------------------------------------------
......
......@@ -16,45 +16,6 @@
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <typename T>
typename enable_if<is_matrix<typename T::type>,unsigned long>::type num_dimensions_in_samples (
const T& samples
)
{
if (samples.size() > 0)
return samples(0).size();
else
return 0;
}
template <typename T>
typename disable_if<is_matrix<typename T::type>,unsigned long>::type num_dimensions_in_samples (
const T& samples
)
/*!
T must be a sparse vector with an integral key type
!*/
{
typedef typename T::type sample_type;
// You are getting this error because you are attempting to use sparse sample vectors with
// the svm_c_linear_trainer object but you aren't using an unsigned integer as your key type
// in the sparse vectors.
COMPILE_TIME_ASSERT(sparse_vector::has_unsigned_keys<sample_type>::value);
// these should be sparse samples so look over all them to find the max dimension.
unsigned long max_dim = 0;
for (long i = 0; i < samples.size(); ++i)
{
if (samples(i).size() > 0)
max_dim = std::max<unsigned long>(max_dim, (--samples(i).end())->first + 1);
}
return max_dim;
}
// ----------------------------------------------------------------------------------------
template <
......@@ -105,7 +66,7 @@ namespace dlib
) const
{
// plus 1 for the bias term
return num_dimensions_in_samples(samples) + 1;
return sparse_vector::max_index_plus_one(samples) + 1;
}
virtual bool optimization_status (
......@@ -170,13 +131,13 @@ namespace dlib
{
if (labels(i) > 0)
{
subtract_from(subgradient, samples(i), Cpos);
sparse_vector::subtract_from(subgradient, samples(i), Cpos);
subgradient(subgradient.size()-1) += Cpos;
}
else
{
add_to(subgradient, samples(i), Cneg);
sparse_vector::add_to(subgradient, samples(i), Cneg);
subgradient(subgradient.size()-1) -= Cneg;
}
......@@ -194,51 +155,6 @@ namespace dlib
// -----------------------------------------------------
// -----------------------------------------------------
// The next few functions are overloads to handle both dense and sparse vectors
template <typename EXP>
inline void add_to (
matrix_type& subgradient,
const matrix_exp<EXP>& sample,
const scalar_type& C
) const
{
for (long r = 0; r < sample.size(); ++r)
subgradient(r) += C*sample(r);
}
template <typename T>
inline typename disable_if<is_matrix<T> >::type add_to (
matrix_type& subgradient,
const T& sample,
const scalar_type& C
) const
{
for (typename T::const_iterator i = sample.begin(); i != sample.end(); ++i)
subgradient(i->first) += C*i->second;
}
template <typename EXP>
inline void subtract_from (
matrix_type& subgradient,
const matrix_exp<EXP>& sample,
const scalar_type& C
) const
{
for (long r = 0; r < sample.size(); ++r)
subgradient(r) -= C*sample(r);
}
template <typename T>
inline typename disable_if<is_matrix<T> >::type subtract_from (
matrix_type& subgradient,
const T& sample,
const scalar_type& C
) const
{
for (typename T::const_iterator i = sample.begin(); i != sample.end(); ++i)
subgradient(i->first) -= C*i->second;
}
template <typename EXP>
scalar_type dot_helper (
const matrix_type& w,
......@@ -637,9 +553,9 @@ namespace dlib
df.basis_vectors.set_size(1);
// Copy the plane normal into the output basis vector. The output vector might be a
// sparse vector container so we need to use this special kind of copy to handle that case.
// As an aside, the reason for using num_dimensions_in_samples() and not just w.size()-1 is because
// As an aside, the reason for using max_index_plus_one() and not just w.size()-1 is because
// doing it this way avoids an inane warning from gcc that can occur in some cases.
const long out_size = num_dimensions_in_samples(x);
const long out_size = sparse_vector::max_index_plus_one(x);
sparse_vector::assign_dense_to_sparse(df.basis_vectors(0), matrix_cast<scalar_type>(colm(w, 0, out_size)));
df.alpha.set_size(1);
df.alpha(0) = 1;
......
......@@ -122,6 +122,47 @@ namespace
DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6);
DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6);
DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6);
// While we are at it, make sure the krr_trainer works with sparse samples
krr_trainer<sparse_linear_kernel<sparse_sample_type> > krr;
df = krr.train(samples, labels);
DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6);
DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6);
DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6);
DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6);
// Now test some of the sparse helper functions
DLIB_TEST(sparse_vector::max_index_plus_one(samples) == 2);
DLIB_TEST(sparse_vector::max_index_plus_one(samples[0]) == 2);
matrix<double,3,1> m;
m = 1;
sparse_vector::add_to(m, samples[3]);
DLIB_TEST(m(0) == 1 + samples[3][0].second);
DLIB_TEST(m(1) == 1 + samples[3][1].second);
DLIB_TEST(m(2) == 1);
m = 1;
sparse_vector::subtract_from(m, samples[3]);
DLIB_TEST(m(0) == 1 - samples[3][0].second);
DLIB_TEST(m(1) == 1 - samples[3][1].second);
DLIB_TEST(m(2) == 1);
m = 1;
sparse_vector::add_to(m, samples[3], 2);
DLIB_TEST(m(0) == 1 + 2*samples[3][0].second);
DLIB_TEST(m(1) == 1 + 2*samples[3][1].second);
DLIB_TEST(m(2) == 1);
m = 1;
sparse_vector::subtract_from(m, samples[3], 2);
DLIB_TEST(m(0) == 1 - 2*samples[3][0].second);
DLIB_TEST(m(1) == 1 - 2*samples[3][1].second);
DLIB_TEST(m(2) == 1);
}
// ----------------------------------------------------------------------------------------
......
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