From 44939e9b2faa4e6a2dbb7000e77ea895177ee74f Mon Sep 17 00:00:00 2001 From: Saksham Bansal <7020962+saksham189@users.noreply.github.com> Date: Sat, 15 Dec 2018 21:34:24 +0700 Subject: [PATCH] kernel_pca_test.cpp: Add tests Add tests for kernel_pca command line. --- .../methods/kernel_pca/kernel_pca_main.cpp | 6 +- src/mlpack/tests/CMakeLists.txt | 1 + .../tests/main_tests/kernel_pca_test.cpp | 356 ++++++++++++++++++ 3 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 src/mlpack/tests/main_tests/kernel_pca_test.cpp diff --git a/src/mlpack/methods/kernel_pca/kernel_pca_main.cpp b/src/mlpack/methods/kernel_pca/kernel_pca_main.cpp index a9b3478e0f..1d39efb27e 100644 --- a/src/mlpack/methods/kernel_pca/kernel_pca_main.cpp +++ b/src/mlpack/methods/kernel_pca/kernel_pca_main.cpp @@ -135,19 +135,19 @@ void RunKPCA(arma::mat& dataset, if (sampling == "kmeans") { KernelPCA > >kpca; + KMeansSelection<> > > kpca(kernel, centerTransformedData); kpca.Apply(dataset, newDim); } else if (sampling == "random") { KernelPCA > kpca; + RandomSelection> > kpca(kernel, centerTransformedData); kpca.Apply(dataset, newDim); } else if (sampling == "ordered") { KernelPCA > kpca; + OrderedSelection> > kpca(kernel, centerTransformedData); kpca.Apply(dataset, newDim); } else diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 28a3637425..4bc7cbc524 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -143,6 +143,7 @@ add_executable(mlpack_test main_tests/hmm_generate_test.cpp main_tests/radical_test.cpp main_tests/hmm_test_utils.hpp + main_tests/kernel_pca_test.cpp ) # Link dependencies of test executable. diff --git a/src/mlpack/tests/main_tests/kernel_pca_test.cpp b/src/mlpack/tests/main_tests/kernel_pca_test.cpp new file mode 100644 index 0000000000..6e076a7585 --- /dev/null +++ b/src/mlpack/tests/main_tests/kernel_pca_test.cpp @@ -0,0 +1,356 @@ +/** + * @file kernel_pca_test.cpp + * @author Saksham Bansal + * + * Test mlpackMain() of kernel_pca_main.cpp. + * + * 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. + */ +#include + +#define BINDING_TYPE BINDING_TYPE_TEST +static const std::string testName = "KernelPrincipalComponentsAnalysis"; + +#include +#include "test_helper.hpp" +#include + +#include +#include "../test_tools.hpp" + +using namespace mlpack; + +struct KernelPCATestFixture +{ + public: + KernelPCATestFixture() + { + // Cache in the options for this program. + CLI::RestoreSettings(testName); + } + + ~KernelPCATestFixture() + { + // Clear the settings. + bindings::tests::CleanMemory(); + CLI::ClearSettings(); + } +}; + +static void ResetSettings() +{ + bindings::tests::CleanMemory(); + CLI::ClearSettings(); + CLI::RestoreSettings(testName); +} + +BOOST_FIXTURE_TEST_SUITE(KernelPCAMainTest, KernelPCATestFixture); + +/** + * Make sure that all valid kernels return correct output dimension. + */ +BOOST_AUTO_TEST_CASE(KernelPCADimensionTest) +{ + std::string kernels[] = { + "linear", "gaussian", "polynomial", + "hyptan", "laplacian", "epanechnikov", "cosine" + }; + + for (std::string& kernel: kernels) + { + ResetSettings(); + arma::mat x = arma::randu(5, 5); + // Random input, new dimensionality of 3. + SetInputParam("input", std::move(x)); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", kernel); + mlpackMain(); + + // Now check that the output has 3 dimensions. + BOOST_REQUIRE_EQUAL(CLI::GetParam("output").n_rows, 3); + BOOST_REQUIRE_EQUAL(CLI::GetParam("output").n_cols, 5); + } +} + +/** + * Check that error is thrown when no kernel is specified. + */ +BOOST_AUTO_TEST_CASE(KernelPCANoKernelTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", std::move(x)); + SetInputParam("new_dimensionality", (int) 3); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check that error is thrown when an invalid kernel is specified. + */ +BOOST_AUTO_TEST_CASE(KernelPCAInvalidKernelTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", std::move(x)); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", (std::string) "badName"); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Make sure if 0 dimensions is specified, we get a dataset with same + * dimensionality as input. + */ +BOOST_AUTO_TEST_CASE(KernelPCA0DimensionalityTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", std::move(x)); + SetInputParam("new_dimensionality", (int) 0); + SetInputParam("kernel", (std::string) "gaussian"); + mlpackMain(); + + // Now check that the output has same dimensions as input. + BOOST_REQUIRE_EQUAL(CLI::GetParam("output").n_rows, 5); + BOOST_REQUIRE_EQUAL(CLI::GetParam("output").n_cols, 5); +} + +/** + * Make sure that centering the dataset makes a difference. + */ +BOOST_AUTO_TEST_CASE(KernelPCACenterTest) +{ + arma::mat x = arma::randu(5, 5); + + // Get output without centering the dataset. + SetInputParam("input", x); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", (std::string) "linear"); + mlpackMain(); + arma::mat output1 = CLI::GetParam("output"); + + // Get output after centering the dataset. + SetInputParam("input", std::move(x)); + SetInputParam("center", true); + mlpackMain(); + arma::mat output2 = CLI::GetParam("output"); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); +} + +/** + * Check that we can't specify an invalid new dimensionality. + */ +BOOST_AUTO_TEST_CASE(KernelPCATooHighNewDimensionalityTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", std::move(x)); + SetInputParam("new_dimensionality", (int) 7); // Invalid. + SetInputParam("kernel", (std::string) "linear"); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check that error is thrown when no input is specified. + */ +BOOST_AUTO_TEST_CASE(KernelPCANoInputTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("new_dimensionality", (int) 2); + SetInputParam("kernel", (std::string) "linear"); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check that error is thrown if invalid sampling scheme is specified. + */ +BOOST_AUTO_TEST_CASE(KernelPCABadSamplingTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", std::move(x)); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", (std::string) "linear"); + SetInputParam("nystroem_method", true); + SetInputParam("sampling", (std::string) "badName"); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Test that bandwidth effects the result for gaussian, epanechnikov + * and laplacian kernels. + */ +BOOST_AUTO_TEST_CASE(KernelPCABandWidthTest) +{ + std::string kernels[] = { + "gaussian", "epanechnikov", "laplacian" + }; + + for (std::string& kernel: kernels) + { + ResetSettings(); + arma::mat x = arma::randu(5, 5); + + // Get output using bandwidth 1. + SetInputParam("input", x); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", kernel); + SetInputParam("bandwidth", (double) 1); + + mlpackMain(); + arma::mat output1 = CLI::GetParam("output"); + + // Get output using bandwidth 2. + SetInputParam("input", std::move(x)); + SetInputParam("bandwidth", (double) 2); + + mlpackMain(); + arma::mat output2 = CLI::GetParam("output"); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); + } +} + +/** + * Test that offset effects the result for polynomial and hyptan kernels. + */ +BOOST_AUTO_TEST_CASE(KernelPCAOffsetTest) +{ + std::string kernels[] = { + "polynomial", "hyptan" + }; + + for (std::string& kernel: kernels) + { + ResetSettings(); + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", x); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", kernel); + SetInputParam("offset", (double) 1); + + mlpackMain(); + arma::mat output1 = CLI::GetParam("output"); + + SetInputParam("input", std::move(x)); + SetInputParam("offset", (double) 2); + + mlpackMain(); + arma::mat output2 = CLI::GetParam("output"); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); + } +} + +/** + * Test that degree effects the result for polynomial kernel. + */ +BOOST_AUTO_TEST_CASE(KernelPCADegreeTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", x); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", (std::string) "polynomial"); + SetInputParam("degree", (double) 2); + + mlpackMain(); + arma::mat output1 = CLI::GetParam("output"); + + SetInputParam("input", std::move(x)); + SetInputParam("degree", (double) 3); + + mlpackMain(); + arma::mat output2 = CLI::GetParam("output"); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); +} + +/** + * Test that kernel scale effects the result for hyptan kernel. + */ +BOOST_AUTO_TEST_CASE(KernelPCAKernelScaleTest) +{ + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", x); + SetInputParam("new_dimensionality", (int) 3); + SetInputParam("kernel", (std::string) "hyptan"); + SetInputParam("kernel_scale", (double) 2); + + mlpackMain(); + arma::mat output1 = CLI::GetParam("output"); + + SetInputParam("input", std::move(x)); + SetInputParam("kernel_scale", (double) 3); + + mlpackMain(); + arma::mat output2 = CLI::GetParam("output"); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); +} + +/** + * Test that using a sampling scheme with nystroem method makes a difference. + */ +BOOST_AUTO_TEST_CASE(KernelPCASamplingSchemeTest) +{ + ResetSettings(); + + arma::mat x = arma::randu(5, 5); + + SetInputParam("input", x); + SetInputParam("new_dimensionality", (int) 1); + SetInputParam("kernel", (std::string) "gaussian"); + SetInputParam("nystroem_method", true); + SetInputParam("sampling", (std::string) "kmeans"); + + mlpackMain(); + + arma::mat output1 = CLI::GetParam("output"); + + SetInputParam("input", x); + SetInputParam("sampling", (std::string) "random"); + + mlpackMain(); + arma::mat output2 = CLI::GetParam("output"); + + SetInputParam("input", x); + SetInputParam("sampling", (std::string) "ordered"); + + mlpackMain(); + arma::mat output3 = CLI::GetParam("output"); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); + BOOST_REQUIRE(arma::any(arma::vectorise(output2 != output3))); + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output3))); +} + +BOOST_AUTO_TEST_SUITE_END();