Files
mlpack/src/mlpack/methods/kde/kde_model_impl.hpp
T

366 lines
11 KiB
C++

/**
* @file kde_model_impl.hpp
* @author Roberto Hueso
*
* Implementation of KDE Model.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_KDE_MODEL_IMPL_HPP
#define MLPACK_METHODS_KDE_MODEL_IMPL_HPP
// In case it hasn't been included yet.
#include "kde_model.hpp"
#include <boost/serialization/variant.hpp>
namespace mlpack {
namespace kde {
//! Initialize the KDEModel with the given parameters.
inline KDEModel::KDEModel(const double bandwidth,
const double relError,
const double absError,
const KernelTypes kernelType,
const TreeTypes treeType) :
bandwidth(bandwidth),
relError(relError),
absError(absError),
kernelType(kernelType),
treeType(treeType)
{
// Nothing to do.
}
// Copy constructor.
inline KDEModel::KDEModel(const KDEModel& other) :
bandwidth(other.bandwidth),
relError(other.relError),
absError(other.absError),
kernelType(other.kernelType),
treeType(other.treeType)
{
// Nothing to do.
}
// Move constructor.
inline KDEModel::KDEModel(KDEModel&& other) :
bandwidth(other.bandwidth),
relError(other.relError),
absError(other.absError),
kernelType(other.kernelType),
treeType(other.treeType),
kdeModel(std::move(other.kdeModel))
{
// Reset other model.
other.bandwidth = 1.0;
other.relError = 0.05;
other.absError = 0;
other.kernelType = KernelTypes::GAUSSIAN_KERNEL;
other.treeType = TreeTypes::KD_TREE;
other.kdeModel = decltype(other.kdeModel)();
}
inline KDEModel& KDEModel::operator=(KDEModel other)
{
boost::apply_visitor(DeleteVisitor(), kdeModel);
bandwidth = other.bandwidth;
relError = other.relError;
absError = other.absError;
kernelType = other.kernelType;
treeType = other.treeType;
kdeModel = std::move(other.kdeModel);
return *this;
}
// Clean memory.
inline KDEModel::~KDEModel()
{
boost::apply_visitor(DeleteVisitor(), kdeModel);
}
inline void KDEModel::BuildModel(arma::mat&& referenceSet)
{
// Clean memory, if necessary.
boost::apply_visitor(DeleteVisitor(), kdeModel);
// Build the actual model.
if (kernelType == GAUSSIAN_KERNEL && treeType == KD_TREE)
{
kdeModel = new KDEType<kernel::GaussianKernel, tree::KDTree>
(relError, absError, kernel::GaussianKernel(bandwidth));
}
else if (kernelType == GAUSSIAN_KERNEL && treeType == BALL_TREE)
{
kdeModel = new KDEType<kernel::GaussianKernel, tree::BallTree>
(relError, absError, kernel::GaussianKernel(bandwidth));
}
else if (kernelType == GAUSSIAN_KERNEL && treeType == COVER_TREE)
{
kdeModel = new KDEType<kernel::GaussianKernel, tree::StandardCoverTree>
(relError, absError, kernel::GaussianKernel(bandwidth));
}
else if (kernelType == GAUSSIAN_KERNEL && treeType == OCTREE)
{
kdeModel = new KDEType<kernel::GaussianKernel, tree::Octree>
(relError, absError, kernel::GaussianKernel(bandwidth));
}
else if (kernelType == GAUSSIAN_KERNEL && treeType == R_TREE)
{
kdeModel = new KDEType<kernel::GaussianKernel, tree::RTree>
(relError, absError, kernel::GaussianKernel(bandwidth));
}
else if (kernelType == EPANECHNIKOV_KERNEL && treeType == KD_TREE)
{
kdeModel = new KDEType<kernel::EpanechnikovKernel, tree::KDTree>
(relError, absError, kernel::EpanechnikovKernel(bandwidth));
}
else if (kernelType == EPANECHNIKOV_KERNEL && treeType == BALL_TREE)
{
kdeModel = new KDEType<kernel::EpanechnikovKernel, tree::BallTree>
(relError, absError, kernel::EpanechnikovKernel(bandwidth));
}
else if (kernelType == EPANECHNIKOV_KERNEL && treeType == COVER_TREE)
{
kdeModel = new KDEType<kernel::EpanechnikovKernel, tree::StandardCoverTree>
(relError, absError, kernel::EpanechnikovKernel(bandwidth));
}
else if (kernelType == EPANECHNIKOV_KERNEL && treeType == OCTREE)
{
kdeModel = new KDEType<kernel::EpanechnikovKernel, tree::Octree>
(relError, absError, kernel::EpanechnikovKernel(bandwidth));
}
else if (kernelType == EPANECHNIKOV_KERNEL && treeType == R_TREE)
{
kdeModel = new KDEType<kernel::EpanechnikovKernel, tree::RTree>
(relError, absError, kernel::EpanechnikovKernel(bandwidth));
}
else if (kernelType == LAPLACIAN_KERNEL && treeType == KD_TREE)
{
kdeModel = new KDEType<kernel::LaplacianKernel, tree::KDTree>
(relError, absError, kernel::LaplacianKernel(bandwidth));
}
else if (kernelType == LAPLACIAN_KERNEL && treeType == BALL_TREE)
{
kdeModel = new KDEType<kernel::LaplacianKernel, tree::BallTree>
(relError, absError, kernel::LaplacianKernel(bandwidth));
}
else if (kernelType == LAPLACIAN_KERNEL && treeType == COVER_TREE)
{
kdeModel = new KDEType<kernel::LaplacianKernel, tree::StandardCoverTree>
(relError, absError, kernel::LaplacianKernel(bandwidth));
}
else if (kernelType == LAPLACIAN_KERNEL && treeType == OCTREE)
{
kdeModel = new KDEType<kernel::LaplacianKernel, tree::Octree>
(relError, absError, kernel::LaplacianKernel(bandwidth));
}
else if (kernelType == LAPLACIAN_KERNEL && treeType == R_TREE)
{
kdeModel = new KDEType<kernel::LaplacianKernel, tree::RTree>
(relError, absError, kernel::LaplacianKernel(bandwidth));
}
else if (kernelType == SPHERICAL_KERNEL && treeType == KD_TREE)
{
kdeModel = new KDEType<kernel::SphericalKernel, tree::KDTree>
(relError, absError, kernel::SphericalKernel(bandwidth));
}
else if (kernelType == SPHERICAL_KERNEL && treeType == BALL_TREE)
{
kdeModel = new KDEType<kernel::SphericalKernel, tree::BallTree>
(relError, absError, kernel::SphericalKernel(bandwidth));
}
else if (kernelType == SPHERICAL_KERNEL && treeType == COVER_TREE)
{
kdeModel = new KDEType<kernel::SphericalKernel, tree::StandardCoverTree>
(relError, absError, kernel::SphericalKernel(bandwidth));
}
else if (kernelType == SPHERICAL_KERNEL && treeType == OCTREE)
{
kdeModel = new KDEType<kernel::SphericalKernel, tree::Octree>
(relError, absError, kernel::SphericalKernel(bandwidth));
}
else if (kernelType == SPHERICAL_KERNEL && treeType == R_TREE)
{
kdeModel = new KDEType<kernel::SphericalKernel, tree::RTree>
(relError, absError, kernel::SphericalKernel(bandwidth));
}
else if (kernelType == TRIANGULAR_KERNEL && treeType == KD_TREE)
{
kdeModel = new KDEType<kernel::TriangularKernel, tree::KDTree>
(relError, absError, kernel::TriangularKernel(bandwidth));
}
else if (kernelType == TRIANGULAR_KERNEL && treeType == BALL_TREE)
{
kdeModel = new KDEType<kernel::TriangularKernel, tree::BallTree>
(relError, absError, kernel::TriangularKernel(bandwidth));
}
else if (kernelType == TRIANGULAR_KERNEL && treeType == COVER_TREE)
{
kdeModel = new KDEType<kernel::TriangularKernel, tree::StandardCoverTree>
(relError, absError, kernel::TriangularKernel(bandwidth));
}
else if (kernelType == TRIANGULAR_KERNEL && treeType == OCTREE)
{
kdeModel = new KDEType<kernel::TriangularKernel, tree::Octree>
(relError, absError, kernel::TriangularKernel(bandwidth));
}
else if (kernelType == TRIANGULAR_KERNEL && treeType == R_TREE)
{
kdeModel = new KDEType<kernel::TriangularKernel, tree::RTree>
(relError, absError, kernel::TriangularKernel(bandwidth));
}
// Train the model.
TrainVisitor train(std::move(referenceSet));
boost::apply_visitor(train, kdeModel);
}
// Perform bichromatic evaluation.
inline void KDEModel::Evaluate(arma::mat&& querySet, arma::vec& estimations)
{
Log::Info << "Evaluating KDE..." << std::endl;
DualBiKDE eval(std::move(querySet), estimations);
boost::apply_visitor(eval, kdeModel);
}
// Perform monochromatic evaluation.
inline void KDEModel::Evaluate(arma::vec& estimations)
{
Log::Info << "Evaluating KDE..." << std::endl;
DualMonoKDE eval(estimations);
boost::apply_visitor(eval, kdeModel);
}
// Clean memory.
inline void KDEModel::CleanMemory()
{
boost::apply_visitor(DeleteVisitor(), kdeModel);
}
// Parameters for KDE evaluation.
DualMonoKDE::DualMonoKDE(arma::vec& estimations):
estimations(estimations)
{}
// Default KDE evaluation.
template<typename KernelType,
template<typename TreeMetricType,
typename TreeStatType,
typename TreeMatType> class TreeType>
void DualMonoKDE::operator()(KDETypeT<KernelType, TreeType>* kde) const
{
if (kde)
{
kde->Evaluate(estimations);
const size_t dimension = (kde->ReferenceTree())->Dataset().n_rows;
KernelNormalizer::ApplyNormalizer<KernelType>(kde->Kernel(),
dimension,
estimations);
}
else
{
throw std::runtime_error("no KDE model initialized");
}
}
// Parameters for KDE evaluation.
DualBiKDE::DualBiKDE(arma::mat&& querySet, arma::vec& estimations):
dimension(querySet.n_rows),
querySet(std::move(querySet)),
estimations(estimations)
{}
// Default KDE evaluation.
template<typename KernelType,
template<typename TreeMetricType,
typename TreeStatType,
typename TreeMatType> class TreeType>
void DualBiKDE::operator()(KDETypeT<KernelType, TreeType>* kde) const
{
if (kde)
{
kde->Evaluate(std::move(querySet), estimations);
KernelNormalizer::ApplyNormalizer<KernelType>(kde->Kernel(),
dimension,
estimations);
}
else
{
throw std::runtime_error("no KDE model initialized");
}
}
// Parameters for Train.
TrainVisitor::TrainVisitor(arma::mat&& referenceSet) :
referenceSet(std::move(referenceSet))
{}
// Default Train.
template<typename KernelType,
template<typename TreeMetricType,
typename TreeStatType,
typename TreeMatType> class TreeType>
void TrainVisitor::operator()(KDEType<KernelType, TreeType>* kde) const
{
Log::Info << "Training KDE model..." << std::endl;
if (kde)
kde->Train(std::move(referenceSet));
else
throw std::runtime_error("no KDE model initialized");
}
// Delete model.
template<typename KDEType>
void DeleteVisitor::operator()(KDEType* kde) const
{
if (kde)
delete kde;
}
// Mode of model.
template<typename KDEType>
KDEMode& ModeVisitor::operator()(KDEType* kde) const
{
if (kde)
return kde->Mode();
else
throw std::runtime_error("no KDE model initialized");
}
// Get mode of model.
KDEMode KDEModel::Mode() const
{
return boost::apply_visitor(ModeVisitor(), kdeModel);
}
// Modify mode of model.
KDEMode& KDEModel::Mode()
{
return boost::apply_visitor(ModeVisitor(), kdeModel);
}
// Serialize the model.
template<typename Archive>
void KDEModel::serialize(Archive& ar, const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(bandwidth);
ar & BOOST_SERIALIZATION_NVP(relError);
ar & BOOST_SERIALIZATION_NVP(absError);
ar & BOOST_SERIALIZATION_NVP(kernelType);
ar & BOOST_SERIALIZATION_NVP(treeType);
if (Archive::is_loading::value)
boost::apply_visitor(DeleteVisitor(), kdeModel);
ar & BOOST_SERIALIZATION_NVP(kdeModel);
}
} // namespace kde
} // namespace mlpack
#endif