Commit 73c7a654 authored by Davis King's avatar Davis King

Added rough version of the new symmetric_matrix_cache() function.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403986
parent 7b6575b0
// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_SYMMETRIC_MATRIX_CAcHE_H__
#define DLIB_SYMMETRIC_MATRIX_CAcHE_H__
//#include "svm_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include <vector>
#include "dlib/matrix.h"
#include "dlib/algs.h"
#include "dlib/array.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <typename M, typename cache_element_type>
struct op_symm_cache : basic_op_m<M>
{
inline op_symm_cache(
const M& m_,
long max_size_megabytes_
) :
basic_op_m<M>(m_),
max_size_megabytes(max_size_megabytes_),
is_initialized(false)
{
lookup.assign(this->m.nr(), -1);
diag_cache = matrix_cast<cache_element_type>(dlib::diag(m_));
}
op_symm_cache (
const op_symm_cache& item
) :
basic_op_m<M>(item.m),
diag_cache(item.diag_cache),
max_size_megabytes(item.max_size_megabytes),
is_initialized(false)
{
lookup.assign(this->m.nr(), -1);
}
typedef cache_element_type type;
typedef const cache_element_type& const_ret_type;
const static long cost = M::cost + 3;
inline const_ret_type apply ( long r, long c) const
{
if (lookup[c] != -1)
{
return cache[lookup[c]](r);
}
else if (r == c)
{
return diag_cache(r);
}
else if (lookup[r] != -1)
{
// the matrix is symmetric so this is legit
return cache[lookup[r]](c);
}
else
{
add_col_to_cache(c);
return cache[lookup[c]](r);
}
}
inline std::pair<const type*,long*> col(long i) const
/*!
requires
- 0 <= i < nc()
ensures
- returns a pair P such that:
- P.first == a pointer to the first element of the ith column
- P.second == a pointer to the integer used to count the number of
outstanding references to the ith column.
!*/
{
if (is_cached(i) == false)
add_col_to_cache(i);
// find where this column is in the cache
long idx = lookup[i];
if (idx == next)
{
// if this column was the next to be replaced
// then make sure that doesn't happen
next = (next + 1)%cache.size();
}
return std::make_pair(&cache[idx](0), &references[idx]);
}
const type* diag() const { init(); return &diag_cache(0); }
long* diag_ref_count() const
{
return &diag_reference_count;
}
private:
inline bool is_cached (
long r
) const
{
return (lookup[r] != -1);
}
inline void init() const
{
if (is_initialized == false)
{
// figure out how many columns of the matrix we can have
// with the given amount of memory.
long max_size = (max_size_megabytes*1024*1024)/(this->m.nr()*sizeof(type));
// don't let it be 0 or 1
if (max_size <= 1)
max_size = 2;
const long size = std::min(max_size,this->m.nr());
diag_reference_count = 0;
references.set_max_size(this->m.nr());
references.set_size(size);
for (unsigned long i = 0; i < references.size(); ++i)
references[i] = 0;
cache.set_max_size(this->m.nr());
cache.set_size(size);
rlookup.assign(size,-1);
next = 0;
is_initialized = true;
}
}
void make_sure_next_is_unreferenced (
) const
{
if (references[next] != 0)
{
// find an unreferenced element of the cache
unsigned long i;
for (i = 1; i < references.size(); ++i)
{
const unsigned long idx = (next+i)%references.size();
if (references[idx] == 0)
{
next = idx;
break;
}
}
// if all elements of the cache are referenced then make the cache bigger
// and use the new element.
if (references[next] != 0)
{
cache.resize(cache.size()+1);
next = references.size();
references.resize(references.size()+1);
references[next] = 0;
rlookup.push_back(-1);
}
}
}
inline void add_col_to_cache(
long c
) const
{
init();
make_sure_next_is_unreferenced();
// if the lookup table is pointing to cache(next,*) then clear lookup[next]
if (rlookup[next] != -1)
lookup[rlookup[next]] = -1;
// make the lookup table so that it says c is now cached at the spot indicated by next
lookup[c] = next;
rlookup[next] = c;
// compute this column in the matrix and store it in the cache
cache[next] = matrix_cast<cache_element_type>(colm(this->m,c));
next = (next + 1)%cache.size();
}
/*!
INITIAL VALUE
- for all valid x:
- lookup(x) == -1
- rlookup(x) == -1
CONVENTION
- if (lookup(c) != -1) then
- cache(lookup(c),*) == the cached column c of the matrix
- rlookup(lookup(c)) == c
- if (rlookup(x) != -1) then
- lookup(rlookup(x)) == x
- cache(x,*) == the cached column rlookup(x) of the matrix
- next == the next row in the cache table to use to cache something
!*/
mutable typename array<matrix<type,0,1,typename M::mem_manager_type> >::expand_1a cache;
mutable typename array<long>::expand_1a references;
mutable matrix<type,0,1,typename M::mem_manager_type> diag_cache;
mutable std::vector<long> lookup;
mutable std::vector<long> rlookup;
mutable long next;
const long max_size_megabytes;
mutable bool is_initialized;
mutable long diag_reference_count;
};
template <
typename cache_element_type,
typename EXP
>
const matrix_op<op_symm_cache<EXP,cache_element_type> > symmetric_matrix_cache (
const matrix_exp<EXP>& m,
long max_size_megabytes
)
{
DLIB_ASSERT(m.size() > 0 && m.nr() == m.nc() && max_size_megabytes > 0,
"\tconst matrix_exp symmetric_matrix_cache(const matrix_exp& m, max_size_megabytes)"
<< "\n\t You have given invalid arguments to this function"
<< "\n\t m.nr(): " << m.nr()
<< "\n\t m.nc(): " << m.nc()
<< "\n\t m.size(): " << m.size()
<< "\n\t max_size_megabytes: " << max_size_megabytes
);
typedef op_symm_cache<EXP,cache_element_type> op;
return matrix_op<op>(op(m.ref(), max_size_megabytes));
}
// ----------------------------------------------------------------------------------------
template <typename M, typename cache_element_type>
struct op_colm_symm_cache
{
typedef cache_element_type type;
op_colm_symm_cache(
const M& m_,
const type* data_,
long* ref_count_
) :
m(m_),
data(data_),
ref_count(ref_count_)
{
*ref_count += 1;
}
op_colm_symm_cache (
const op_colm_symm_cache& item
) :
m(item.m),
data(item.data),
ref_count(item.ref_count)
{
*ref_count += 1;
}
~op_colm_symm_cache(
)
{
*ref_count -= 1;
}
const M& m;
const type* const data;
long* const ref_count;
const static long cost = M::cost;
const static long NR = M::NR;
const static long NC = 1;
typedef const type& const_ret_type;
typedef typename M::mem_manager_type mem_manager_type;
typedef typename M::layout_type layout_type;
inline const_ret_type apply ( long r, long) const { return data[r]; }
long nr () const { return m.nr(); }
long nc () const { return 1; }
template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
};
template <
typename EXP,
typename cache_element_type
>
inline const matrix_op<op_colm_symm_cache<EXP,cache_element_type> > colm (
const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m,
long col
)
{
DLIB_ASSERT(col >= 0 && col < m.nc(),
"\tconst matrix_exp colm(const matrix_exp& m, row)"
<< "\n\tYou have specified invalid sub matrix dimensions"
<< "\n\tm.nr(): " << m.nr()
<< "\n\tm.nc(): " << m.nc()
<< "\n\tcol: " << col
);
std::pair<const cache_element_type*,long*> p = m.ref().op.col(col);
typedef op_colm_symm_cache<EXP,cache_element_type> op;
return matrix_op<op>(op(m.ref().op.m,
p.first,
p.second));
}
// ----------------------------------------------------------------------------------------
template <
typename EXP,
typename cache_element_type
>
inline const matrix_op<op_colm_symm_cache<EXP,cache_element_type> > diag (
const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m
)
{
typedef op_colm_symm_cache<EXP,cache_element_type> op;
return matrix_op<op>(op(m.ref().op.m,
m.ref().op.diag(),
m.ref().op.diag_ref_count()));
}
// ----------------------------------------------------------------------------------------
template <typename EXP>
struct colm_exp
{
typedef matrix_op<op_colm<EXP> > type;
};
template <typename EXP>
struct diag_exp
{
typedef matrix_op<op_diag<EXP> > type;
};
// ----------------------------------------------------------------------------------------
template <typename EXP, typename cache_element_type>
struct colm_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >
{
typedef matrix_op<op_colm_symm_cache<EXP, cache_element_type> > type;
};
template <typename EXP, typename cache_element_type>
struct diag_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >
{
typedef matrix_op<op_colm_symm_cache<EXP, cache_element_type> > type;
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_SYMMETRIC_MATRIX_CAcHE_H__
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