[mlpack-svn] r11660 - in mlpack/trunk/src/mlpack: core/kernels tests
fastlab-svn at coffeetalk-1.cc.gatech.edu
fastlab-svn at coffeetalk-1.cc.gatech.edu
Wed Feb 29 16:06:31 EST 2012
Author: nslagle
Date: 2012-02-29 16:06:30 -0500 (Wed, 29 Feb 2012)
New Revision: 11660
Added:
mlpack/trunk/src/mlpack/core/kernels/epanechnikov_kernel.hpp
mlpack/trunk/src/mlpack/core/kernels/spherical_kernel.hpp
Modified:
mlpack/trunk/src/mlpack/core/kernels/CMakeLists.txt
mlpack/trunk/src/mlpack/core/kernels/example_kernel.hpp
mlpack/trunk/src/mlpack/core/kernels/gaussian_kernel.hpp
mlpack/trunk/src/mlpack/tests/kernel_test.cpp
Log:
mlpack/core/kernels: add a couple of kernels appropriate for the forthcoming KCDE/KDE combo, per #200
Modified: mlpack/trunk/src/mlpack/core/kernels/CMakeLists.txt
===================================================================
--- mlpack/trunk/src/mlpack/core/kernels/CMakeLists.txt 2012-02-29 21:05:13 UTC (rev 11659)
+++ mlpack/trunk/src/mlpack/core/kernels/CMakeLists.txt 2012-02-29 21:06:30 UTC (rev 11660)
@@ -3,13 +3,14 @@
# Define the files we need to compile.
# Anything not in this list will not be compiled into MLPACK.
set(SOURCES
- gaussian_kernel.hpp
- linear_kernel.hpp
cosine_distance.hpp
cosine_distance_impl.hpp
+ gaussian_kernel.hpp
+ hyperbolic_tangent_kernel.hpp
laplacian_kernel.hpp
+ linear_kernel.hpp
polynomial_kernel.hpp
- hyperbolic_tangent_kernel.hpp
+ spherical_kernel.hpp
)
# add directory name to sources
Added: mlpack/trunk/src/mlpack/core/kernels/epanechnikov_kernel.hpp
===================================================================
--- mlpack/trunk/src/mlpack/core/kernels/epanechnikov_kernel.hpp (rev 0)
+++ mlpack/trunk/src/mlpack/core/kernels/epanechnikov_kernel.hpp 2012-02-29 21:06:30 UTC (rev 11660)
@@ -0,0 +1,100 @@
+/**
+ * @file epanechnikov_kernel.hpp
+ * @author Neil Slagle
+ *
+ * This is an example kernel. If you are making your own kernel, follow the
+ * outline specified in this file.
+ */
+#ifndef __MLPACK_CORE_KERNELS_EPANECHNIKOV_KERNEL_H
+#define __MLPACK_CORE_KERNELS_EPANECHNIKOV_KERNEL_H
+
+#include <boost/math/special_functions/gamma.hpp>
+
+#include <mlpack/core.hpp>
+#include <mlpack/core/metrics/lmetric.hpp>
+
+namespace mlpack {
+namespace kernel {
+
+class EpanechnikovKernel
+{
+ public:
+ EpanechnikovKernel() :
+ bandwidth(1.0),
+ inverseBandwidthSquared(1.0) {}
+ EpanechnikovKernel(double b) :
+ bandwidth(b),
+ inverseBandwidthSquared(1.0/(b*b)) {}
+
+ template<typename VecType>
+ double Evaluate(const VecType& a, const VecType& b)
+ {
+ double evaluatee =
+ 1.0 - metric::SquaredEuclideanDistance::Evaluate(a, b) * inverseBandwidthSquared;
+ return (evaluatee > 0.0) ? evaluatee : 0.0;
+ }
+ /**
+ * Obtains the convolution integral [integral K(||x-a||)K(||b-x||)dx]
+ * for the two vectors. In this case, because
+ * our simple example kernel has no internal parameters, we can declare the
+ * function static. For a more complex example which cannot be declared
+ * static, see the GaussianKernel, which stores an internal parameter.
+ *
+ * @tparam VecType Type of vector (arma::vec, arma::spvec should be expected).
+ * @param a First vector.
+ * @param b Second vector.
+ * @return the convolution integral value.
+ */
+ template<typename VecType>
+ double ConvolutionIntegral(const VecType& a, const VecType& b)
+ {
+ double distance = sqrt(metric::SquaredEuclideanDistance::Evaluate(a, b));
+ if (distance >= 2.0 * bandwidth)
+ {
+ return 0.0;
+ }
+ double volumeSquared = pow(Normalizer(a.n_rows), 2.0);
+
+ switch(a.n_rows)
+ {
+ case 1:
+ return 1.0 / volumeSquared *
+ (16.0/15.0*bandwidth-4.0*distance*distance /
+ (3.0*bandwidth)+2.0*distance*distance*distance/
+ (3.0*bandwidth*bandwidth) -
+ pow(distance,5.0)/(30.0*pow(bandwidth,4.0)));
+ break;
+ case 2:
+ return 1.0 / volumeSquared *
+ ((2.0/3.0*bandwidth*bandwidth-distance*distance)*
+ asin(sqrt(1.0-pow(distance/(2.0*bandwidth),2.0))) +
+ sqrt(4.0*bandwidth*bandwidth-distance*distance)*
+ (distance/6.0+2.0/9.0*distance*pow(distance/bandwidth,2.0)-
+ distance/72.0*pow(distance/bandwidth,4.0)));
+ break;
+ default:
+ Log::Fatal << "Epanechnikov doesn't support your dimension (yet).";
+ return -1.0;
+ break;
+ }
+ }
+
+ double Normalizer(size_t dimension)
+ {
+ return 2.0 * pow(bandwidth, dimension) * pow(M_PI, dimension / 2.0) /
+ (tgamma(dimension / 2.0 + 1.0) * (dimension + 2.0));
+ }
+ double Evaluate(double t)
+ {
+ double evaluatee = 1.0 - t * t * inverseBandwidthSquared;
+ return (evaluatee > 0.0) ? evaluatee : 0.0;
+ }
+ private:
+ double bandwidth;
+ double inverseBandwidthSquared;
+};
+
+}; // namespace kernel
+}; // namespace mlpack
+
+#endif
Modified: mlpack/trunk/src/mlpack/core/kernels/example_kernel.hpp
===================================================================
--- mlpack/trunk/src/mlpack/core/kernels/example_kernel.hpp 2012-02-29 21:05:13 UTC (rev 11659)
+++ mlpack/trunk/src/mlpack/core/kernels/example_kernel.hpp 2012-02-29 21:06:30 UTC (rev 11660)
@@ -100,6 +100,32 @@
*/
template<typename VecType>
static double Evaluate(const VecType& a, const VecType& b) { return 0; }
+ /**
+ * Obtains the convolution integral [integral K(||x-a||)K(||b-x||)dx]
+ * for the two vectors. In this case, because
+ * our simple example kernel has no internal parameters, we can declare the
+ * function static. For a more complex example which cannot be declared
+ * static, see the GaussianKernel, which stores an internal parameter.
+ *
+ * @tparam VecType Type of vector (arma::vec, arma::spvec should be expected).
+ * @param a First vector.
+ * @param b Second vector.
+ * @return the convolution integral value.
+ */
+ template<typename VecType>
+ static double ConvolutionIntegral(const VecType& a, const VecType& b) { return 0; }
+
+ /**
+ * Obtains the normalizing volume for the kernel with dimension $dimension$.
+ * In this case, because our simple example kernel has no internal parameters,
+ * we can declare the function static. For a more complex example which
+ * cannot be declared static, see the GaussianKernel, which stores an internal
+ * parameter.
+ *
+ * @param dimension the dimension of the space.
+ * @return the normalization constant.
+ */
+ static double Normalizer(size_t dimension) { return 0; }
};
}; // namespace kernel
Modified: mlpack/trunk/src/mlpack/core/kernels/gaussian_kernel.hpp
===================================================================
--- mlpack/trunk/src/mlpack/core/kernels/gaussian_kernel.hpp 2012-02-29 21:05:13 UTC (rev 11659)
+++ mlpack/trunk/src/mlpack/core/kernels/gaussian_kernel.hpp 2012-02-29 21:06:30 UTC (rev 11660)
@@ -74,7 +74,31 @@
// The precalculation of gamma saves us a little computation time.
return exp(gamma * t * t);
}
+ /**
+ * Obtain the normalization constant of the Gaussian kernel.
+ *
+ * @param dimension
+ * @return the normalization constant
+ */
+ double Normalizer(size_t dimension)
+ {
+ return pow(sqrt(2.0 * M_PI) * bandwidth, dimension);
+ }
+ /**
+ * Obtain a convolution integral of the Gaussian kernel.
+ *
+ * @param a, first vector
+ * @param b, second vector
+ * @return the convolution integral
+ */
+ template<typename VecType>
+ double ConvolutionIntegral(const VecType& a, const VecType& b)
+ {
+ return Evaluate(sqrt(metric::SquaredEuclideanDistance::Evaluate(a, b) / 2.0)) /
+ (Normalizer(a.n_rows) * pow(2.0, (double) a.n_rows / 2.0));
+ }
+
//! Get the bandwidth.
double Bandwidth() const { return bandwidth; }
//! Modify the bandwidth. This takes an argument because we must update the
Added: mlpack/trunk/src/mlpack/core/kernels/spherical_kernel.hpp
===================================================================
--- mlpack/trunk/src/mlpack/core/kernels/spherical_kernel.hpp (rev 0)
+++ mlpack/trunk/src/mlpack/core/kernels/spherical_kernel.hpp 2012-02-29 21:06:30 UTC (rev 11660)
@@ -0,0 +1,90 @@
+/**
+ * @file spherical_kernel.hpp
+ * @author Neil Slagle
+ *
+ * This is an example kernel. If you are making your own kernel, follow the
+ * outline specified in this file.
+ */
+#ifndef __MLPACK_CORE_KERNELS_SPHERICAL_KERNEL_H
+#define __MLPACK_CORE_KERNELS_SPHERICAL_KERNEL_H
+
+#include <boost/math/special_functions/gamma.hpp>
+#include <mlpack/core.hpp>
+
+namespace mlpack {
+namespace kernel {
+
+class SphericalKernel
+{
+ public:
+ SphericalKernel() :
+ bandwidth(1.0),
+ bandwidthSquared(1.0) {}
+ SphericalKernel(double b) :
+ bandwidth(b),
+ bandwidthSquared(b*b) {}
+
+ template<typename VecType>
+ double Evaluate(const VecType& a, const VecType& b)
+ {
+ return
+ (metric::SquaredEuclideanDistance::Evaluate(a, b) <= bandwidthSquared) ?
+ 1.0 : 0.0;
+ }
+ /**
+ * Obtains the convolution integral [integral K(||x-a||)K(||b-x||)dx]
+ * for the two vectors. In this case, because
+ * our simple example kernel has no internal parameters, we can declare the
+ * function static. For a more complex example which cannot be declared
+ * static, see the GaussianKernel, which stores an internal parameter.
+ *
+ * @tparam VecType Type of vector (arma::vec, arma::spvec should be expected).
+ * @param a First vector.
+ * @param b Second vector.
+ * @return the convolution integral value.
+ */
+ template<typename VecType>
+ double ConvolutionIntegral(const VecType& a, const VecType& b)
+ {
+ double distance = sqrt(metric::SquaredEuclideanDistance::Evaluate(a, b));
+ if (distance >= 2.0 * bandwidth)
+ {
+ return 0.0;
+ }
+ double volumeSquared = pow(Normalizer(a.n_rows), 2.0);
+
+ switch(a.n_rows)
+ {
+ case 1:
+ return 1.0 / volumeSquared * (2.0 * bandwidth - distance);
+ break;
+ case 2:
+ return 1.0 / volumeSquared *
+ (2.0 * bandwidth * bandwidth * acos(distance/(2.0 * bandwidth)) -
+ distance / 4.0 * sqrt(4.0*bandwidth*bandwidth-distance*distance));
+ break;
+ default:
+ Log::Fatal << "The spherical kernel does not support convolution\
+ integrals above dimension two, yet..." << std::endl;
+ return -1.0;
+ break;
+ }
+ }
+ double Normalizer(size_t dimension)
+ {
+ return pow(bandwidth, dimension) * pow(M_PI, dimension / 2.0) /
+ tgamma(dimension / 2.0 + 1.0);
+ }
+ double Evaluate(double t)
+ {
+ return (t <= bandwidth) ? 1.0 : 0.0;
+ }
+ private:
+ double bandwidth;
+ double bandwidthSquared;
+};
+
+}; // namespace kernel
+}; // namespace mlpack
+
+#endif
Modified: mlpack/trunk/src/mlpack/tests/kernel_test.cpp
===================================================================
--- mlpack/trunk/src/mlpack/tests/kernel_test.cpp 2012-02-29 21:05:13 UTC (rev 11659)
+++ mlpack/trunk/src/mlpack/tests/kernel_test.cpp 2012-02-29 21:06:30 UTC (rev 11660)
@@ -5,14 +5,17 @@
*
* Tests for the various kernel classes.
*/
-#include <mlpack/core/metrics/lmetric.hpp>
-#include <mlpack/core/metrics/mahalanobis_distance.hpp>
#include <mlpack/core/kernels/cosine_distance.hpp>
+#include <mlpack/core/kernels/epanechnikov_kernel.hpp>
#include <mlpack/core/kernels/gaussian_kernel.hpp>
+#include <mlpack/core/kernels/hyperbolic_tangent_kernel.hpp>
+#include <mlpack/core/kernels/laplacian_kernel.hpp>
#include <mlpack/core/kernels/linear_kernel.hpp>
+#include <mlpack/core/kernels/linear_kernel.hpp>
#include <mlpack/core/kernels/polynomial_kernel.hpp>
-#include <mlpack/core/kernels/laplacian_kernel.hpp>
-#include <mlpack/core/kernels/hyperbolic_tangent_kernel.hpp>
+#include <mlpack/core/kernels/spherical_kernel.hpp>
+#include <mlpack/core/metrics/lmetric.hpp>
+#include <mlpack/core/metrics/mahalanobis_distance.hpp>
#include <boost/test/unit_test.hpp>
@@ -242,8 +245,73 @@
BOOST_REQUIRE_CLOSE(gk.Evaluate(c,a), .018315638888734, 1e-5);
BOOST_REQUIRE_CLOSE(gk.Evaluate(b,c), .018315638888734, 1e-5);
BOOST_REQUIRE_CLOSE(gk.Evaluate(c,b), .018315638888734, 1e-5);
+ /* check the single dimension evaluate function */
+ BOOST_REQUIRE_CLOSE(gk.Evaluate(1.0), 0.1353352832366127, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.Evaluate(2.0), 0.00033546262790251185, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.Evaluate(3.0), 1.5229979744712629e-08, 1e-5);
+ /* check the normalization constant */
+ BOOST_REQUIRE_CLOSE(gk.Normalizer(1), 1.2533141373155001, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.Normalizer(2), 1.5707963267948963, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.Normalizer(3), 1.9687012432153019, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.Normalizer(4), 2.4674011002723386, 1e-5);
+ /* check the convolution integral */
+ BOOST_REQUIRE_CLOSE(gk.ConvolutionIntegral(a,b), 0.024304474038457577, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.ConvolutionIntegral(a,c), 0.024304474038457577, 1e-5);
+ BOOST_REQUIRE_CLOSE(gk.ConvolutionIntegral(b,c), 0.024304474038457577, 1e-5);
+
}
+BOOST_AUTO_TEST_CASE(spherical_kernel)
+{
+ arma::vec a = "1.0 0.0";
+ arma::vec b = "0.0 1.0";
+ arma::vec c = "0.2 0.9";
+
+ SphericalKernel sk(.5);
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(a,b), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(a,c), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(b,c), 1.0, 1e-5);
+ /* check the single dimension evaluate function */
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(0.10), 1.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(0.25), 1.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(0.50), 1.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Evaluate(1.00), 0.0, 1e-5);
+ /* check the normalization constant */
+ BOOST_REQUIRE_CLOSE(sk.Normalizer(1), 1.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Normalizer(2), 0.78539816339744828, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Normalizer(3), 0.52359877559829893, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.Normalizer(4), 0.30842513753404244, 1e-5);
+ /* check the convolution integral */
+ BOOST_REQUIRE_CLOSE(sk.ConvolutionIntegral(a,b), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.ConvolutionIntegral(a,c), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(sk.ConvolutionIntegral(b,c), 1.0021155029652784, 1e-5);
+}
+
+BOOST_AUTO_TEST_CASE(epanechnikov_kernel)
+{
+ arma::vec a = "1.0 0.0";
+ arma::vec b = "0.0 1.0";
+ arma::vec c = "0.1 0.9";
+
+ EpanechnikovKernel ek(.5);
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(a,b), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(b,c), 0.92, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(a,c), 0.0, 1e-5);
+ /* check the single dimension evaluate function */
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(0.10), 0.96, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(0.25), 0.75, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(0.50), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Evaluate(1.00), 0.0, 1e-5);
+ /* check the normalization constant */
+ BOOST_REQUIRE_CLOSE(ek.Normalizer(1), 0.666666666666666, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Normalizer(2), 0.39269908169872414, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Normalizer(3), 0.20943951023931956, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.Normalizer(4), 0.10280837917801415, 1e-5);
+ /* check the convolution integral */
+ BOOST_REQUIRE_CLOSE(ek.ConvolutionIntegral(a,b), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.ConvolutionIntegral(a,c), 0.0, 1e-5);
+ BOOST_REQUIRE_CLOSE(ek.ConvolutionIntegral(b,c), 1.5263455690698258, 1e-5);
+}
BOOST_AUTO_TEST_CASE(polynomial_kernel)
{
arma::vec a = "0 0 1";
More information about the mlpack-svn
mailing list