Commit 2e30336b authored by Davis King's avatar Davis King

Added the running_covariance class.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403470
parent 3a04fa14
......@@ -167,6 +167,167 @@ namespace dlib
T max_value;
};
// ----------------------------------------------------------------------------------------
template <
typename matrix_type
>
class running_covariance
{
/*!
INITIAL VALUE
- vect_size == 0
- total_count == 0
CONVENTION
- vect_size == in_vector_size()
- total_count == current_n()
- if (total_count != 0)
- total_sum == the sum of all vectors given to add()
- the covariance of all the elements given to add() is given
by:
- let avg == total_sum/total_count
- covariance == total_cov/total_count - avg*trans(avg)
!*/
public:
typedef typename matrix_type::mem_manager_type mem_manager_type;
typedef typename matrix_type::type scalar_type;
typedef typename matrix_type::layout_type layout_type;
typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;
running_covariance(
)
{
clear();
}
void clear(
)
{
total_count = 0;
vect_size = 0;
total_sum.set_size(0);
total_cov.set_size(0,0);
}
long in_vector_size (
) const
{
return vect_size;
}
long current_n (
) const
{
return total_count;
}
template <typename EXP>
void add (
const matrix_exp<EXP>& val
)
{
// make sure requires clause is not broken
DLIB_ASSERT(is_col_vector(val) && (in_vector_size() == 0 || val.size() == in_vector_size()),
"\t void running_covariance::add()"
<< "\n\t Invalid inputs were given to this function"
<< "\n\t is_col_vector(val): " << is_col_vector(val)
<< "\n\t in_vector_size(): " << in_vector_size()
<< "\n\t val.size(): " << val.size()
<< "\n\t this: " << this
);
vect_size = val.size();
if (total_count == 0)
{
total_cov = val*trans(val);
total_sum = val;
}
else
{
total_cov += val*trans(val);
total_sum += val;
}
++total_count;
}
const column_matrix mean (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT( in_vector_size() != 0,
"\t running_covariance::mean()"
<< "\n\t This object can not execute this function in its current state."
<< "\n\t in_vector_size(): " << in_vector_size()
<< "\n\t current_n(): " << current_n()
<< "\n\t this: " << this
);
return total_sum/total_count;
}
const general_matrix covariance (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT( in_vector_size() != 0 && current_n() > 1,
"\t running_covariance::covariance()"
<< "\n\t This object can not execute this function in its current state."
<< "\n\t in_vector_size(): " << in_vector_size()
<< "\n\t current_n(): " << current_n()
<< "\n\t this: " << this
);
return (total_cov - total_sum*trans(total_sum)/total_count)/(total_count-1);
}
const running_covariance operator+ (
const running_covariance& item
) const
{
// make sure requires clause is not broken
DLIB_ASSERT((in_vector_size() == 0 || item.in_vector_size() == 0 || in_vector_size() == item.in_vector_size()),
"\t running_covariance running_covariance::operator+()"
<< "\n\t The two running_covariance objects being added must have compatible parameters"
<< "\n\t in_vector_size(): " << in_vector_size()
<< "\n\t item.in_vector_size(): " << item.in_vector_size()
<< "\n\t this: " << this
);
running_covariance temp(item);
// make sure we ignore empty matrices
if (total_count != 0 && temp.total_count != 0)
{
temp.total_cov += total_cov;
temp.total_sum += total_sum;
temp.total_count += total_count;
}
else if (total_count != 0)
{
temp.total_cov = total_cov;
temp.total_sum = total_sum;
temp.total_count = total_count;
}
return temp;
}
private:
general_matrix total_cov;
column_matrix total_sum;
scalar_type total_count;
long vect_size;
};
// ----------------------------------------------------------------------------------------
template <
......
......@@ -157,6 +157,115 @@ namespace dlib
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename matrix_type
>
class running_covariance
{
/*!
REQUIREMENTS ON matrix_type
Must be some type of dlib::matrix.
INITIAL VALUE
- in_vector_size() == 0
- current_n() == 0
WHAT THIS OBJECT REPRESENTS
This object is a simple tool for computing the mean and
covariance of a sequence of vectors.
!*/
public:
typedef typename matrix_type::mem_manager_type mem_manager_type;
typedef typename matrix_type::type scalar_type;
typedef typename matrix_type::layout_type layout_type;
typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;
running_covariance(
);
/*!
ensures
- this object is properly initialized
!*/
void clear(
);
/*!
ensures
- this object has its initial value
- clears all memory of any previous data points
!*/
long current_n (
) const;
/*!
ensures
- returns the number of samples that have been presented to this object
!*/
long in_vector_size (
) const;
/*!
ensures
- if (this object has been presented with any input vectors) then
- returns the dimension of the column vectors used with this object
- else
- returns 0
!*/
void add (
const matrix_exp& val
);
/*!
requires
- is_col_vector(val) == true
- if (in_vector_size() != 0) then
- val.size() == in_vector_size()
ensures
- updates the mean and covariance stored in this object so that
the new value is factored into them.
- #in_vector_size() == val.size()
!*/
const column_matrix mean (
) const;
/*!
requires
- in_vector_size() != 0
ensures
- returns the mean of all the vectors presented to this object
so far.
!*/
const general_matrix covariance (
) const;
/*!
requires
- in_vector_size() != 0
- current_n() > 1
ensures
- returns the unbiased sample covariance matrix for all the vectors
presented to this object so far.
!*/
const running_covariance operator+ (
const running_covariance& item
) const;
/*!
requires
- in_vector_size() == 0 || item.in_vector_size() == 0 || in_vector_size() == item.in_vector_size()
(i.e. the in_vector_size() of *this and item must match or one must be zero)
ensures
- returns a new running_covariance object that represents the combination of all
the vectors given to *this and item. That is, this function returns a
running_covariance object, R, that is equivalent to what you would obtain if all
calls to this->add() and item.add() had instead been done to R.
!*/
};
// ----------------------------------------------------------------------------------------
template <
......
......@@ -7,6 +7,7 @@
#include <cstdlib>
#include <ctime>
#include <dlib/statistics.h>
#include <dlib/rand.h>
#include "tester.h"
......@@ -99,11 +100,73 @@ namespace
}
}
void test_running_covariance (
)
{
dlib::rand::float_1a rnd;
std::vector<matrix<double,0,1> > vects;
running_covariance<matrix<double,0,1> > cov, cov2;
DLIB_TEST(cov.in_vector_size() == 0);
for (unsigned long dims = 1; dims < 5; ++dims)
{
for (unsigned long samps = 2; samps < 10; ++samps)
{
vects.clear();
cov.clear();
DLIB_TEST(cov.in_vector_size() == 0);
for (unsigned long i = 0; i < samps; ++i)
{
vects.push_back(randm(dims,1,rnd));
cov.add(vects.back());
}
DLIB_TEST(cov.in_vector_size() == dims);
DLIB_TEST(equal(mean(vector_to_matrix(vects)), cov.mean()));
DLIB_TEST_MSG(equal(covariance(vector_to_matrix(vects)), cov.covariance()),
max(abs(covariance(vector_to_matrix(vects)) - cov.covariance()))
<< " dims = " << dims << " samps = " << samps
);
}
}
for (unsigned long dims = 1; dims < 5; ++dims)
{
for (unsigned long samps = 2; samps < 10; ++samps)
{
vects.clear();
cov.clear();
cov2.clear();
DLIB_TEST(cov.in_vector_size() == 0);
for (unsigned long i = 0; i < samps; ++i)
{
vects.push_back(randm(dims,1,rnd));
if ((i%2) == 0)
cov.add(vects.back());
else
cov2.add(vects.back());
}
DLIB_TEST((cov+cov2).in_vector_size() == dims);
DLIB_TEST(equal(mean(vector_to_matrix(vects)), (cov+cov2).mean()));
DLIB_TEST_MSG(equal(covariance(vector_to_matrix(vects)), (cov+cov2).covariance()),
max(abs(covariance(vector_to_matrix(vects)) - (cov+cov2).covariance()))
<< " dims = " << dims << " samps = " << samps
);
}
}
}
void perform_test (
)
{
test_random_subset_selector();
test_random_subset_selector2();
test_running_covariance();
}
} 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