#ifndef _theplu_yat_classifier_kernel_lookup_
#define _theplu_yat_classifier_kernel_lookup_
// $Id$
/*
Copyright (C) 2005 Jari Häkkinen, Peter Johansson
Copyright (C) 2006 Jari Häkkinen, Markus Ringnér, Peter Johansson
Copyright (C) 2007, 2008 Peter Johansson
This file is part of the yat library, http://trac.thep.lu.se/yat
The yat library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The yat library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
#include "Kernel.h"
#include "yat/utility/Container2DIterator.h"
#include "yat/utility/Index.h"
#include "yat/utility/iterator_traits.h"
#include "yat/utility/SmartPtr.h"
#include "yat/utility/StrideIterator.h"
namespace theplu {
namespace yat {
namespace classifier {
class KernelFunction;
class MatrixLookup;
class MatrixLookupWeighted;
///
/// @brief Lookup into Kernel
///
/// This is the KernelLookup class to be used together with kernel
/// methods such as Support Vector Machines (SVM). The class does
/// not contain any data or values, but rather is a lookup into a
/// Kernel object. Each row and each column corresponds to a row and
/// a column in the Kernel, respectively. This design allows for fast
/// creation of sub-kernels, which is a common operation in most
/// traning/validation procedures.
///
/// A KernelLookup can be created directly from a Kernel or from
/// another KernelLookup. In the latter case, the resulting
/// KernelLookup is looking directly into the underlying Kernel to
/// avoid multiple lookups.
///
/// There is a possibility to set the KernelLookup as owner of the
/// underlying kernel. This implies that underlying kernel is deleted
/// in destructor of MatrixLookup, but only if there is no other
/// owner of the underlying kernel. A reference counter is used to
/// keep track of number of owners. Ownership is copied in copy
/// constructors and assignments.
///
class KernelLookup
{
public:
/// 'Read Only' iterator
typedef utility::StrideIterator<
utility::Container2DIterator >
const_iterator;
/**
'Read only' iterator intended to iterate over a column
*/
typedef const_iterator const_column_iterator;
/**
'Read only' iterator intended to iterate over a row
*/
typedef const_iterator const_row_iterator;
///
/// @brief Constructor a Lookup into a Kernel
///
/// Constructs a KernelLookup corresponding to the Kernel @a
/// kernel. By default @a owner is set to false, which means
/// KernelLookup does not own the underlying Kernel.
///
/// @note If underlying Kernel goes out of scope or is deleted, the
/// KernelLookup becomes invalid and the result of further use is
/// undefined.
///
/// @note Do not construct two KernelLookups from the same @a
/// kernel with @a owner set to true because that will cause
/// multiple deletion of @a kernel.
///
KernelLookup(const Kernel& kernel, const bool owner=false);
///
/// @brief Constructing a Lookup into a subKernel
///
/// Creating a Lookup into parts of the Kernel. In the created
/// Lookup the element in the \f$ i \f$ th row in the \f$ j \f$ th
/// column is identical to the element in row row[i] and columns
/// column[j] in the underlying @a kernel. If @a owner is set to
/// true yhe underlying @a kernel is destroyed in the destructor.
///
/// @note If @a kernel goes out of scope or is deleted, the
/// returned pointer becomes invalid and the result of further use is
/// undefined.
///
/// @note For training usage row index shall always be equal to
/// column index.
///
KernelLookup(const Kernel& kernel, const utility::Index& row,
const utility::Index& column, const bool owner=false);
///
/// @brief Copy constructor.
///
/// A Lookup is created looking into the
/// same underlying Kernel as @a kl is looking into.
///
/// If \a kl is owner of underlying data, constructed
/// KernelLookup will also be set as owner of underlying data.
///
KernelLookup(const KernelLookup& kl);
///
/// @brief Contructing a sub-KernelLookup.
///
/// Contructor building a sub-KernelLookup from a KernelLookup
/// defined by row index vector and column index vector. In the
/// created Lookup the element in the \f$ i \f$ th row in the
/// \f$ j \f$ th column is identical to the element in row row[i] and
/// columns column[j] in the copied @a kl. The resulting
/// KernelLookup is independent of the old KernelLookup, but is
/// undefined in case underlying Kernel is destroyed.
///
/// If \a kl is owner of underlying data, constructed
/// KernelLookup will also be set as owner of underlying data.
///
/// @note For training usage row index shall always be equal to
/// column index.
///
KernelLookup(const KernelLookup& kl, const utility::Index& row,
const utility::Index& column);
///
/// Constructor taking the column (default) or row index as
/// input. If @a row is false the created KernelLookup will have
/// equally many rows as @a kernel.
///
/// If \a kl is owner of underlying data, constructed
/// KernelLookup will also be set as owner of underlying data.
///
/// @note If underlying kernel goes out of scope or is deleted, the
/// KernelLookup becomes invalid and the result of further use is
/// undefined.
///
KernelLookup(const KernelLookup& kl, const utility::Index&,
const bool row=false);
///
/// @brief Destructor
///
/// Deletes underlying Kernel if KernelLookup owns it and there is
/// no other owner.
///
virtual ~KernelLookup(void);
/**
Iterator iterates along a row. When end of row is reached it
jumps to beginning of next row.
\return const_iterator pointing to upper-left element.
*/
const_iterator begin(void) const;
/**
Iterator iterates along a column.
\return iterator pointing to first element of column \a i.
*/
const_column_iterator begin_column(size_t) const;
/**
Iterator iterates along a column.
\return const_iterator pointing to first element of column \a i.
*/
const_row_iterator begin_row(size_t) const;
/**
\return number of columns
*/
size_t columns(void) const;
///
/// Each column in returned DataLookup corresponds to the column
/// in KernelLookup.
///
/// \return data that KernelLookup is built upon.
///
/// \throw if KernelLookup is weighted
///
MatrixLookup data(void) const;
///
/// Each column in returned DataLookup corresponds to the column
/// in KernelLookup.
///
/// \return data that KernelLookup is built upon.
///
/// \throw if KernelLookup is unweighted
///
MatrixLookupWeighted data_weighted(void) const;
/**
Function to calculate a new Kernel element using the underlying
KernelFunction. The value is calculated between @a vec and the
data vector of the \a i th sample, in other words, the
sample corresponding to the \a i th row.
*/
double element(const DataLookup1D& vec, size_t i) const;
/**
Function to calculate a new Kernel element using the underlying
KernelFunction. The value is calulated between @a vec and the
data vector of the \f$ i \f$ th sample, in other words, the
sample corresponding to the \f$ i \f$ th row or \f$ i \f$ th
column. In case KernelLookup is a sub-Kernel and not symmetric,
the kernel value is calculated between @a vec and the data
vector corresponding to \f$ i \f$ th row.
*/
double element(const DataLookupWeighted1D& vec, size_t i) const;
/**
\return const_iterator pointing to end of matrix
*/
const_iterator end(void) const;
/**
\return const_iterator pointing to end of column \a i
*/
const_column_iterator end_column(size_t) const;
/**
\return const_iterator pointing to end of row \a i
*/
const_row_iterator end_row(size_t) const;
/**
\return number of rows
*/
size_t rows(void) const;
/**
Each element in returned KernelLookup is calculated using only
selected features (defined by @a index). Each element
corresponds to the same pair of samples as in the original
KernelLookup.
*/
KernelLookup selected(const utility::Index& index) const;
/**
This function is useful when predicting on an independent data
set using a kernel-based classifier. In returned KernelLookup
column \f$ i \f$ corresponds to column \f$ i \f$ in @a
data. Row \f$ i \f$ in returned KernelLookup corresponds to
same sample as row \f$ i \f$ in @a this. In other words, this
function returns a KernelLookup containing the kernel elements
between the passed @a data and the internal underlying data @a
this was built from.
*/
KernelLookup test_kernel(const MatrixLookup& data) const;
/**
This function is useful when predicting on an independent data
set using a kernel-based classifier. In returned KernelLookup
column \f$ i \f$ corresponds to column \f$ i \f$ in @a
data. Row \f$ i \f$ in returned KernelLookup corresponds to
same sample as row \f$ i \f$ in @a this. In other words, this
function returns a KernelLookup containing the kernel elements
between the passed @a data and the internal underlying data @a
this was built from.
*/
KernelLookup test_kernel(const MatrixLookupWeighted& data) const;
/**
\return true if underlying Kernel is weighted
*/
bool weighted(void) const;
/**
\return element at position (\a row, \a column) in the Kernel
matrix
*/
double operator()(size_t row, size_t column) const;
private:
const KernelLookup& operator=(const KernelLookup&);
bool validate(const utility::Index&) const;
utility::Index column_index_;
utility::SmartPtr kernel_;
utility::Index row_index_;
}; // class KernelLookup
}}} // of namespace classifier, yat, and theplu
#endif