diff --git a/.ci/windows-steps.yaml b/.ci/windows-steps.yaml index 069c6c5b46..69a33520a3 100644 --- a/.ci/windows-steps.yaml +++ b/.ci/windows-steps.yaml @@ -78,6 +78,7 @@ steps: msbuildVersion: $(MSBuildVersion) configuration: 'Release' msbuildArchitecture: 'x64' + platform: 'x64' msbuildArguments: /m /p:BuildInParallel=true maximumCpuCount: false clean: false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8a4790897d..8640c26471 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,13 +8,31 @@ on: - master release: types: [published, created, edited] +name: R CMD check mlpack jobs: + cancel: + name: 'Cancel Previous Builds' + if: ${{ github.event_name == 'pull_request' && github.repository == 'mlpack/mlpack' }} + runs-on: ubuntu-latest + timeout-minutes: 3 + steps: + - name: Get all workflow ids and set to env variable + run: echo ::set-env name=WORKFLOW_IDS_TO_CANCEL::$(curl https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/workflows -s | jq -r '.workflows | map(.id|tostring) | join(",")') + + - uses: styfle/cancel-workflow-action@0.5.0 + with: + workflow_id: ${{ env.WORKFLOW_IDS_TO_CANCEL }} + access_token: ${{ secrets.GITHUB_TOKEN }} + jobR: - name: mlpack-R + name: Build mlpack_r_tarball + if: ${{ github.repository == 'mlpack/mlpack' }} runs-on: ubuntu-20.04 + outputs: r_bindings: ${{ steps.mlpack_version.outputs.mlpack_r_package }} + steps: - uses: actions/checkout@v2 @@ -27,16 +45,35 @@ jobs: MLPACK_VERSION_VALUE=${MLPACK_VERSION_MAJOR}.${MLPACK_VERSION_MINOR}.${MLPACK_VERSION_PATCH} echo ::set-output name=mlpack_r_package::$(echo mlpack_"$MLPACK_VERSION_VALUE".tar.gz) + - uses: r-lib/actions/setup-r@master + with: + r-version: release + + - name: Query dependencies + run: | + cp src/mlpack/bindings/R/mlpack/DESCRIPTION.in DESCRIPTION + Rscript -e "install.packages('remotes')" -e "saveRDS(remotes::dev_package_deps(dependencies = TRUE), 'depends.Rds')" + + - name: Cache R packages + if: runner.os != 'Windows' + uses: actions/cache@v1 + with: + path: ${{ env.R_LIBS_USER }} + key: ${{ runner.os }}-r-release-${{ hashFiles('depends.Rds') }} + restore-keys: ${{ runner.os }}-r-release- + - name: Install Build Dependencies run: | sudo apt-get update sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost-all-dev curl https://data.kurg.org/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo* cmake . && make && sudo make install && cd .. - sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu xenial-cran40/' - sudo apt-get -y update - sudo apt-get install -y r-base-core - sudo Rscript -e "install.packages(c('Rcpp', 'RcppArmadillo', 'RcppEnsmallen', 'BH', 'roxygen2', 'testthat'))" + + - name: Install R-bindings dependencies + run: | + remotes::install_deps(dependencies = TRUE) + remotes::install_cran("roxygen2") + shell: Rscript {0} - name: CMake run: | @@ -58,6 +95,7 @@ jobs: runs-on: ${{ matrix.config.os }} name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + if: ${{ github.repository == 'mlpack/mlpack' }} strategy: fail-fast: false @@ -74,6 +112,8 @@ jobs: R_CHECK_ARGS: "--no-build-vignettes" _R_CHECK_FORCE_SUGGESTS: 0 R_REMOTES_NO_ERRORS_FROM_WARNINGS: true + RSPM: ${{ matrix.config.rspm }} + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/download-artifact@v2 @@ -86,10 +126,22 @@ jobs: - uses: r-lib/actions/setup-pandoc@master + - name: Query dependencies + run: Rscript -e "install.packages('remotes')" -e "saveRDS(remotes::dev_package_deps('${{ needs.jobR.outputs.r_bindings }}', dependencies = TRUE), 'depends.Rds')" + + - name: Cache R packages + if: runner.os != 'Windows' + uses: actions/cache@v1 + with: + path: ${{ env.R_LIBS_USER }} + key: ${{ runner.os }}-r-${{ matrix.config.r }}-${{ hashFiles('depends.Rds') }} + restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}- + - name: Install dependencies run: | - Rscript -e "install.packages('remotes')" -e "remotes::install_cran('rcmdcheck')" - Rscript -e "install.packages(c('Rcpp', 'RcppArmadillo', 'RcppEnsmallen', 'BH', 'roxygen2', 'testthat'))" + remotes::install_deps('${{ needs.jobR.outputs.r_bindings }}', dependencies = TRUE) + remotes::install_cran("rcmdcheck") + shell: Rscript {0} - name: Check run: Rscript -e "rcmdcheck::rcmdcheck('${{ needs.jobR.outputs.r_bindings }}', args = c('--no-manual','--as-cran'), error_on = 'warning', check_dir = 'check')" diff --git a/HISTORY.md b/HISTORY.md index d7a2437e9e..5acdedcb4f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,8 @@ ###### ????-??-?? * Added Mean Absolute Percentage Error. + * Added Softmin activation function as layer in ann/layer. + ### mlpack 3.4.1 ###### 2020-09-07 * Fix incorrect parsing of required matrix/model parameters for command-line diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index 34ea03c6a7..b4726b0c6f 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -116,6 +116,8 @@ set(SOURCES celu_impl.hpp softshrink.hpp softshrink_impl.hpp + softmin.hpp + softmin_impl.hpp ) # Add directory name to sources. diff --git a/src/mlpack/methods/ann/layer/add.hpp b/src/mlpack/methods/ann/layer/add.hpp index b3f95dbbcc..42b27809b8 100644 --- a/src/mlpack/methods/ann/layer/add.hpp +++ b/src/mlpack/methods/ann/layer/add.hpp @@ -100,6 +100,9 @@ class Add //! Get the output size. size_t OutputSize() const { return outSize; } + //! Get the size of weights. + size_t WeightSize() const { return outSize; } + /** * Serialize the layer */ diff --git a/src/mlpack/methods/ann/layer/atrous_convolution.hpp b/src/mlpack/methods/ann/layer/atrous_convolution.hpp index b2a8f497e6..b3dfd1ce85 100644 --- a/src/mlpack/methods/ann/layer/atrous_convolution.hpp +++ b/src/mlpack/methods/ann/layer/atrous_convolution.hpp @@ -257,6 +257,12 @@ class AtrousConvolution //! Modify the internal Padding layer. ann::Padding<>& Padding() { return padding; } + //! Get size of the weight matrix. + size_t WeightSize() const + { + return (outSize * inSize * kernelWidth * kernelHeight) + outSize; + } + /** * Serialize the layer. */ diff --git a/src/mlpack/methods/ann/layer/layer.hpp b/src/mlpack/methods/ann/layer/layer.hpp index d005d1eb42..947395fd6b 100644 --- a/src/mlpack/methods/ann/layer/layer.hpp +++ b/src/mlpack/methods/ann/layer/layer.hpp @@ -66,6 +66,7 @@ #include "sequential.hpp" #include "softshrink.hpp" #include "softmax.hpp" +#include "softmin.hpp" #include "spatial_dropout.hpp" #include "subview.hpp" #include "transposed_convolution.hpp" diff --git a/src/mlpack/methods/ann/layer/linear.hpp b/src/mlpack/methods/ann/layer/linear.hpp index 1930181654..6dfd719d5f 100644 --- a/src/mlpack/methods/ann/layer/linear.hpp +++ b/src/mlpack/methods/ann/layer/linear.hpp @@ -146,6 +146,12 @@ class Linear //! Modify the bias weights of the layer. OutputDataType& Bias() { return bias; } + //! Get the size of the weights. + size_t WeightSize() const + { + return (inSize * outSize) + outSize; + } + /** * Serialize the layer */ diff --git a/src/mlpack/methods/ann/layer/softmin.hpp b/src/mlpack/methods/ann/layer/softmin.hpp new file mode 100644 index 0000000000..a7b882c942 --- /dev/null +++ b/src/mlpack/methods/ann/layer/softmin.hpp @@ -0,0 +1,97 @@ +/** + * @file methods/ann/layer/softmin.hpp + * @author Aakash Kaushik + * + * Definition of the Softmin class. + * + * 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_ANN_LAYER_SOFTMIN_HPP +#define MLPACK_METHODS_ANN_LAYER_SOFTMIN_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Implementation of the Softmin layer. The Softmin function takes as a input + * a vector of K real numbers, rescaling them so that the elements of the + * K-dimensional output vector lie in the range [0, 1] and sum to 1. + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class Softmin +{ + public: + /** + * Create the Softmin object. + */ + Softmin(); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const InputType& input, OutputType& output); + + /** + * Ordinary feed backward pass of a neural network, calculating the function + * f(x) by propagating x backwards through f. Using the results from the feed + * forward pass. + * + * @param input The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); + + //! Get the output parameter. + OutputDataType& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + InputDataType& Delta() const { return delta; } + //! Modify the delta. + InputDataType& Delta() { return delta; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& /* ar */, const unsigned int /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally stored output parameter object. + OutputDataType outputParameter; +}; // class Softmin + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "softmin_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/softmin_impl.hpp b/src/mlpack/methods/ann/layer/softmin_impl.hpp new file mode 100644 index 0000000000..7693ca11dd --- /dev/null +++ b/src/mlpack/methods/ann/layer/softmin_impl.hpp @@ -0,0 +1,61 @@ +/** + * @file methods/ann/layer/softmin_impl.hpp + * @author Aakash Kaushik + * + * Implementation of the Softmin class. + * + * 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_ANN_LAYER_SOFTMIN_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_SOFTMIN_IMPL_HPP + +// In case it hasn't yet been included. +#include "softmin.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +Softmin::Softmin() +{ + // Nothing to do here. +} + +template +template +void Softmin::Forward( + const InputType& input, + OutputType& output) +{ + InputType inputMin = arma::repmat(arma::min(input,0), input.n_rows, 1); + output = arma::repmat(arma::log(arma::sum( + arma::exp(-(input - inputMin)),0)), input.n_rows, 1); + output = arma::exp(-(input - inputMin) - output); +} + +template +template +void Softmin::Backward( + const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) +{ + g = input % (gy - arma::repmat(arma::sum(gy % input), input.n_rows, 1)); +} + +template +template +void Softmin::serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here. +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index fae84ae9a8..b273dd3e4e 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -8,8 +8,6 @@ add_executable(mlpack_test io_test.cpp cosine_tree_test.cpp dcgan_test.cpp - det_test.cpp - distribution_test.cpp drusilla_select_test.cpp emst_test.cpp fastmks_test.cpp @@ -36,7 +34,6 @@ add_executable(mlpack_test math_test.cpp matrix_completion_test.cpp maximal_inputs_test.cpp - mean_shift_test.cpp metric_test.cpp mlpack_test.cpp mock_categorical_data.hpp @@ -92,7 +89,6 @@ add_executable(mlpack_test main_tests/local_coordinate_coding_test.cpp main_tests/logistic_regression_test.cpp main_tests/lsh_test.cpp - main_tests/mean_shift_test.cpp main_tests/nbc_test.cpp main_tests/nmf_test.cpp main_tests/perceptron_test.cpp @@ -122,6 +118,8 @@ add_executable(mlpack_catch_test dbscan_test.cpp decision_stump_test.cpp decision_tree_test.cpp + det_test.cpp + distribution_test.cpp feedforward_network_test.cpp image_load_test.cpp imputation_test.cpp @@ -135,6 +133,7 @@ add_executable(mlpack_catch_test load_save_test.cpp loss_functions_test.cpp main.cpp + mean_shift_test.cpp nca_test.cpp one_hot_encoding_test.cpp pca_test.cpp @@ -168,6 +167,7 @@ add_executable(mlpack_catch_test main_tests/kmeans_test.cpp main_tests/knn_test.cpp main_tests/linear_regression_test.cpp + main_tests/mean_shift_test.cpp main_tests/nca_test.cpp main_tests/pca_test.cpp main_tests/preprocess_binarize_test.cpp diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 2c1fe63398..9ee1ebcaf9 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -558,6 +558,58 @@ void CheckCELUDerivativeCorrect(const arma::colvec input, } } +/** + * Implementation of the Softmin activation function test. The function is + * implemented as Softmin layer in the file softmin.hpp. + * + * @param input Input data used for evaluating the Softmin activation function. + * @param target Target data used to evaluate the Softmin activation. + */ +void CheckSoftminActivationCorrect(const arma::colvec input, + const arma::colvec target) +{ + // Initialize Softmin object. + Softmin<> softmin; + + // Test the activation function using the entire vector as input. + arma::colvec activations; + softmin.Forward(input,activations); + for (size_t i = 0; i < activations.n_elem; ++i) + { + REQUIRE(activations.at(i) == Approx(target.at(i)).epsilon(1e-5)); + } +} + +/** + * Implementation of the Softmin activation function derivative test. + * The function is implemented as Softmin layer in the file softmin.hpp. + * + * @param input Input data used for evaluating the Softmin activation function. + * @param target Target data used to evaluate the Softmin activation. + */ +void CheckSoftminDerivativeCorrect(const arma::colvec input, + const arma::colvec target) +{ + // Initialize Softmin object. + Softmin<> softmin; + + // Test the calculation of the derivatives using the entire vector as input. + arma::colvec derivatives, activations; + + // This error vector will be set to [[1.0],[0.0],[1.0],[0.0]] + // to get the derivatives. + arma::colvec error = arma::ones(input.n_elem); + error(1) = 0.0; + error(3) = 0.0; + softmin.Forward(input, activations); + softmin.Backward(activations, error, derivatives); + for (size_t i = 0; i < derivatives.n_elem; ++i) + { + REQUIRE(derivatives.at(i) == Approx(target.at(i)).epsilon(1e-5)); + } + +} + /** * Basic test of the tanh function. */ @@ -1063,3 +1115,23 @@ TEST_CASE("GaussianFunctionTest", "[ActivationFunctionsTest]") CheckDerivativeCorrect(desiredActivations, desiredDerivatives); } + +/** + * Basic test of the Softmin function. + */ +TEST_CASE("SoftminFunctionTest", "[ActivationFunctionsTest]") +{ + const arma::colvec activationData("4.2 2.4 7.0 6.4"); + + // Hand-calculated Values. + const arma::colvec desiredActivations("0.1384799751 0.8377550303 \ + 0.008420976 0.0153440186"); + + const arma::colvec desiredDerivatives("0.1181371351 -0.12306701070 \ + 0.0071839266 -0.0022540509"); + + CheckSoftminActivationCorrect(activationData, + desiredActivations); + CheckSoftminDerivativeCorrect(activationData, + desiredDerivatives); +} diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index dfd1ecf091..37a5a5b192 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -87,11 +87,10 @@ TEST_CASE("GradientAddLayerTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -416,11 +415,10 @@ TEST_CASE("GradientLinearLayerTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -508,13 +506,12 @@ TEST_CASE("GradientLinear3DLayerTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + inSize(4), + outSize(1), + nPoints(2), + batchSize(4) { - const size_t inSize = 4; - const size_t outSize = 1; - const size_t nPoints = 2; - const size_t batchSize = 4; - input = arma::randu(inSize * nPoints, batchSize); target = arma::zeros(outSize * nPoints, batchSize); target(0, 0) = 1; @@ -545,6 +542,10 @@ TEST_CASE("GradientLinear3DLayerTest", "[ANNLayerTest]") FFN, RandomInitialization>* model; arma::mat input, target; + const size_t inSize; + const size_t outSize; + const size_t nPoints; + const size_t batchSize; } function; REQUIRE(CheckGradient(function) <= 1e-7); @@ -591,11 +592,10 @@ TEST_CASE("GradientNoisyLinearLayerTest", "[ANNLayerTest]") // Noisy linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -695,11 +695,10 @@ TEST_CASE("GradientLinearNoBiasLayerTest", "[ANNLayerTest]") // LinearNoBias function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -797,11 +796,10 @@ TEST_CASE("GradientFlexibleReLULayerTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(2, 1)), + target(arma::mat("1")) { - input = arma::randu(2, 1); - target = arma::mat("1"); - model = new FFN, RandomInitialization>( NegativeLogLikelihood<>(), RandomInitialization(0.1, 0.5)); @@ -1017,10 +1015,10 @@ TEST_CASE("GradientLSTMLayerTest", "[ANNLayerTest]") // LSTM function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(1, 1, 5)), + target(arma::ones(1, 1, 5)) { - input = arma::randu(1, 1, 5); - target.ones(1, 1, 5); const size_t rho = 5; model = new RNN >(rho); @@ -1122,10 +1120,10 @@ TEST_CASE("GradientFastLSTMLayerTest", "[ANNLayerTest]") // Fast LSTM function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(1, 1, 5)), + target(arma::ones(1, 1, 5)) { - input = arma::randu(1, 1, 5); - target = arma::ones(1, 1, 5); const size_t rho = 5; model = new RNN >(rho); @@ -1391,10 +1389,10 @@ TEST_CASE("GradientGRULayerTest", "[ANNLayerTest]") // GRU function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(1, 1, 5)), + target(arma::ones(1, 1, 5)) { - input = arma::randu(1, 1, 5); - target = arma::ones(1, 1, 5); const size_t rho = 5; model = new RNN >(rho); @@ -1631,11 +1629,10 @@ TEST_CASE("GradientConcatLayerTest", "[ANNLayerTest]") // Concat function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -1700,11 +1697,10 @@ TEST_CASE("GradientConcatenateLayerTest", "[ANNLayerTest]") // Concatenate function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -1905,11 +1901,10 @@ TEST_CASE("GradientSoftmaxTest", "[ANNLayerTest]") // Softmax function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1; 0")) { - input = arma::randu(10, 1); - target = arma::mat("1; 0"); - model = new FFN, RandomInitialization>; model->Predictors() = input; model->Responses() = target; @@ -2109,12 +2104,10 @@ TEST_CASE("GradientBatchNormTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randn(32, 2048)), + target(arma::ones(1, 2048)) { - input = arma::randn(32, 2048); - arma::mat target; - target.ones(1, 2048); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -2184,12 +2177,11 @@ TEST_CASE("GradientVirtualBatchNormTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randn(5, 256)), + target(arma::ones(1, 256)) { - input = arma::randn(5, 256); arma::mat referenceBatch = arma::mat(input.memptr(), input.n_rows, 16); - arma::mat target; - target.ones(1, 256); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -2247,12 +2239,10 @@ TEST_CASE("MiniBatchDiscriminationTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randn(5, 4)), + target(arma::ones(1, 4)) { - input = arma::randn(5, 4); - arma::mat target; - target.ones(1, 4); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -2427,11 +2417,10 @@ TEST_CASE("GradientTransposedConvolutionLayerTest", "[ANNLayerTest]") { struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::linspace(0, 35, 36)), + target(arma::mat("1")) { - input = arma::linspace(0, 35, 36); - target = arma::mat("1"); - model = new FFN, RandomInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -2544,11 +2533,10 @@ TEST_CASE("GradientAtrousConvolutionLayerTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::linspace(0, 35, 36)), + target(arma::mat("1")) { - input = arma::linspace(0, 35, 36); - target = arma::mat("1"); - model = new FFN, RandomInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -2575,7 +2563,7 @@ TEST_CASE("GradientAtrousConvolutionLayerTest", "[ANNLayerTest]") arma::mat input, target; } function; - // TODO: this tolerance seems far higher than necessary. The implementation + // TODO: this tolerance seems far higher than necessary. The implementation // should be checked. REQUIRE(CheckGradient(function) <= 0.2); } @@ -2726,12 +2714,10 @@ TEST_CASE("GradientLayerNormTest", "[ANNLayerTest]") // Add function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randn(10, 256)), + target(arma::ones(1, 256)) { - input = arma::randn(10, 256); - arma::mat target; - target.ones(1, 256); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -3048,11 +3034,10 @@ TEST_CASE("GradientReparametrizationLayerTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -3092,11 +3077,10 @@ TEST_CASE("GradientReparametrizationLayerBetaTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 2)), + target(arma::mat("1 1")) { - input = arma::randu(10, 2); - target = arma::mat("1 1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -3248,11 +3232,10 @@ TEST_CASE("GradientHighwayLayerTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(5, 1)), + target(arma::mat("1")) { - input = arma::randu(5, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -3300,11 +3283,10 @@ TEST_CASE("GradientSequentialLayerTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -3351,11 +3333,10 @@ TEST_CASE("GradientWeightNormLayerTest", "[ANNLayerTest]") // Linear function gradient instantiation. struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randu(10, 1)), + target(arma::mat("1")) { - input = arma::randu(10, 1); - target = arma::mat("1"); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -4185,12 +4166,10 @@ TEST_CASE("GradientBatchNormWithMiniBatchesTest", "[ANNLayerTest]") { struct GradientFunction { - GradientFunction() + GradientFunction() : + input(arma::randn(16, 1024)), + target(arma::ones(1, 1024)) { - input = arma::randn(16, 1024); - arma::mat target; - target.ones(1, 1024); - model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; model->Responses() = target; @@ -4683,7 +4662,13 @@ TEST_CASE("GradientMultiheadAttentionTest", "[ANNLayerTest]") { struct GradientFunction { - GradientFunction() + GradientFunction() : + tgtSeqLen(2), + srcSeqLen(2), + embedDim(4), + nHeads(2), + vocabSize(5), + batchSize(2) { input = arma::randu(embedDim * (tgtSeqLen + 2 * srcSeqLen), batchSize); target = arma::zeros(vocabSize, batchSize); @@ -4736,13 +4721,13 @@ TEST_CASE("GradientMultiheadAttentionTest", "[ANNLayerTest]") MultiheadAttention<>* attnModule; arma::mat input, target, attnMask, keyPaddingMask; - const size_t tgtSeqLen = 2; - const size_t srcSeqLen = 2; - const size_t embedDim = 4; - const size_t nHeads = 2; - const size_t vocabSize = 5; - const size_t batchSize = 2; + const size_t tgtSeqLen; + const size_t srcSeqLen; + const size_t embedDim; + const size_t nHeads; + const size_t vocabSize; + const size_t batchSize; } function; - REQUIRE(CheckGradient(function) <= 2e-06); + REQUIRE(CheckGradient(function) <= 3e-06); } diff --git a/src/mlpack/tests/ann_visitor_test.cpp b/src/mlpack/tests/ann_visitor_test.cpp index 1b01308ff3..ccf3cca35f 100644 --- a/src/mlpack/tests/ann_visitor_test.cpp +++ b/src/mlpack/tests/ann_visitor_test.cpp @@ -52,3 +52,37 @@ TEST_CASE("BiasSetVisitorTest", "[ANNVisitorTest]") boost::apply_visitor(DeleteVisitor(), linear); } + +/** + * Test that WeightSetVisitor works properly. + */ +TEST_CASE("WeightSetVisitorTest", "[ANNVisitorTest]") +{ + size_t randomSize = arma::randi(arma::distr_param(1, 100)); + + LayerTypes<> linear = new Linear<>(randomSize, randomSize); + + arma::mat layerWeights(randomSize * randomSize + randomSize, 1); + layerWeights.zeros(); + + size_t setWeights = boost::apply_visitor(WeightSetVisitor(layerWeights, 0), + linear); + + REQUIRE(setWeights == randomSize * randomSize + randomSize); +} + +/** + * Test that WeightSizeVisitor works properly. + */ +TEST_CASE("WeightSizeVisitorTest", "[ANNVisitorTest]") +{ + size_t randomSize = arma::randi(arma::distr_param(1, 100)); + + LayerTypes<> linear = new Linear<>(randomSize, randomSize); + + size_t weightSize = boost::apply_visitor(WeightSizeVisitor(), + linear); + + REQUIRE(weightSize == randomSize * randomSize + randomSize); +} + diff --git a/src/mlpack/tests/det_test.cpp b/src/mlpack/tests/det_test.cpp index 4a16bbd060..c0989768eb 100644 --- a/src/mlpack/tests/det_test.cpp +++ b/src/mlpack/tests/det_test.cpp @@ -11,8 +11,7 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ #include -#include -#include "test_tools.hpp" +#include "catch.hpp" // This trick does not work on Windows. We will have to comment out the tests // that depend on it. @@ -33,13 +32,11 @@ using namespace mlpack; using namespace mlpack::det; using namespace std; -BOOST_AUTO_TEST_SUITE(DETTest); - // Tests for the private functions. We cannot perform these if we are on // Windows because we cannot make private functions accessible using the macro // trick above. #ifndef _WIN32 -BOOST_AUTO_TEST_CASE(TestGetMaxMinVals) +TEST_CASE("TestGetMaxMinVals", "[DETTest]") { arma::mat testData(3, 5); @@ -49,15 +46,15 @@ BOOST_AUTO_TEST_CASE(TestGetMaxMinVals) DTree tree(testData); - BOOST_REQUIRE_EQUAL(tree.MaxVals()[0], 7); - BOOST_REQUIRE_EQUAL(tree.MinVals()[0], 3); - BOOST_REQUIRE_EQUAL(tree.MaxVals()[1], 7); - BOOST_REQUIRE_EQUAL(tree.MinVals()[1], 0); - BOOST_REQUIRE_EQUAL(tree.MaxVals()[2], 8); - BOOST_REQUIRE_EQUAL(tree.MinVals()[2], 1); + REQUIRE(tree.MaxVals()[0] == 7); + REQUIRE(tree.MinVals()[0] == 3); + REQUIRE(tree.MaxVals()[1] == 7); + REQUIRE(tree.MinVals()[1] == 0); + REQUIRE(tree.MaxVals()[2] == 8); + REQUIRE(tree.MinVals()[2] == 1); } -BOOST_AUTO_TEST_CASE(TestComputeNodeError) +TEST_CASE("TestComputeNodeError", "[DETTest]") { arma::vec maxVals("7 7 8"); arma::vec minVals("3 0 1"); @@ -65,17 +62,18 @@ BOOST_AUTO_TEST_CASE(TestComputeNodeError) DTree testDTree(maxVals, minVals, 5); double trueNodeError = -log(4.0) - log(7.0) - log(7.0); - BOOST_REQUIRE_CLOSE((double) testDTree.logNegError, trueNodeError, 1e-10); + REQUIRE((double) testDTree.logNegError == + Approx(trueNodeError).epsilon(1e-12)); testDTree.start = 3; testDTree.end = 5; double nodeError = testDTree.LogNegativeError(5); trueNodeError = 2 * log(2.0 / 5.0) - log(4.0) - log(7.0) - log(7.0); - BOOST_REQUIRE_CLOSE(nodeError, trueNodeError, 1e-10); + REQUIRE(nodeError == Approx(trueNodeError).epsilon(1e-12)); } -BOOST_AUTO_TEST_CASE(TestWithinRange) +TEST_CASE("TestWithinRange", "[DETTest]") { arma::vec maxVals("7 7 8"); arma::vec minVals("3 0 1"); @@ -85,14 +83,14 @@ BOOST_AUTO_TEST_CASE(TestWithinRange) arma::vec testQuery(3); testQuery << 4.5 << 2.5 << 2; - BOOST_REQUIRE_EQUAL(testDTree.WithinRange(testQuery), true); + REQUIRE(testDTree.WithinRange(testQuery) == true); testQuery << 8.5 << 2.5 << 2; - BOOST_REQUIRE_EQUAL(testDTree.WithinRange(testQuery), false); + REQUIRE(testDTree.WithinRange(testQuery) == false); } -BOOST_AUTO_TEST_CASE(TestFindSplit) +TEST_CASE("TestFindSplit", "[DETTest]") { arma::mat testData(3, 5); @@ -108,20 +106,21 @@ BOOST_AUTO_TEST_CASE(TestFindSplit) size_t trueDim = 2; double trueSplit = 5.5; double trueLeftError = 2 * log(2.0 / 5.0) - (log(7.0) + log(4.0) + log(4.5)); - double trueRightError = 2 * log(3.0 / 5.0) - (log(7.0) + log(4.0) + log(2.5)); + double trueRightError = 2 * log(3.0 / 5.0) - (log(7.0) + log(4.0) + + log(2.5)); testDTree.logVolume = log(7.0) + log(4.0) + log(7.0); - BOOST_REQUIRE(testDTree.FindSplit( + REQUIRE(testDTree.FindSplit( testData, obDim, obSplit, obLeftError, obRightError, 1)); - BOOST_REQUIRE(trueDim == obDim); - BOOST_REQUIRE_CLOSE(trueSplit, obSplit, 1e-10); + REQUIRE(trueDim == obDim); + REQUIRE(trueSplit == Approx(obSplit).epsilon(1e-12)); - BOOST_REQUIRE_CLOSE(trueLeftError, obLeftError, 1e-10); - BOOST_REQUIRE_CLOSE(trueRightError, obRightError, 1e-10); + REQUIRE(trueLeftError == Approx(obLeftError).epsilon(1e-12)); + REQUIRE(trueRightError == Approx(obRightError).epsilon(1e-12)); } -BOOST_AUTO_TEST_CASE(TestSplitData) +TEST_CASE("TestSplitData", "[DETTest]") { arma::mat testData(3, 5); @@ -140,16 +139,16 @@ BOOST_AUTO_TEST_CASE(TestSplitData) size_t splitInd = testDTree.SplitData( testData, splitDim, trueSplitVal, oTest); - BOOST_REQUIRE_EQUAL(splitInd, 2); // 2 points on left side. + REQUIRE(splitInd == 2); // 2 points on left side. - BOOST_REQUIRE_EQUAL(oTest[0], 1); - BOOST_REQUIRE_EQUAL(oTest[1], 4); - BOOST_REQUIRE_EQUAL(oTest[2], 3); - BOOST_REQUIRE_EQUAL(oTest[3], 2); - BOOST_REQUIRE_EQUAL(oTest[4], 5); + REQUIRE(oTest[0] == 1); + REQUIRE(oTest[1] == 4); + REQUIRE(oTest[2] == 3); + REQUIRE(oTest[3] == 2); + REQUIRE(oTest[4] == 5); } -BOOST_AUTO_TEST_CASE(TestSparseFindSplit) +TEST_CASE("TestSparseFindSplit", "[DETTest]") { arma::mat realData(4, 7); @@ -173,17 +172,17 @@ BOOST_AUTO_TEST_CASE(TestSparseFindSplit) (log(7.0) + log(6.5) + log(8.0) + log(6.0)); testDTree.logVolume = log(7.0) + log(7.0) + log(8.0) + log(6.0); - BOOST_REQUIRE(testDTree.FindSplit( + REQUIRE(testDTree.FindSplit( testData, obDim, obSplit, obLeftError, obRightError, 1)); - BOOST_REQUIRE(trueDim == obDim); - BOOST_REQUIRE_CLOSE(trueSplit, obSplit, 1e-10); + REQUIRE(trueDim == obDim); + REQUIRE(trueSplit == Approx(obSplit).epsilon(1e-12)); - BOOST_REQUIRE_CLOSE(trueLeftError, obLeftError, 1e-10); - BOOST_REQUIRE_CLOSE(trueRightError, obRightError, 1e-10); + REQUIRE(trueLeftError == Approx(obLeftError).epsilon(1e-12)); + REQUIRE(trueRightError == Approx(obRightError).epsilon(1e-12)); } -BOOST_AUTO_TEST_CASE(TestSparseSplitData) +TEST_CASE("TestSparseSplitData", "[DETTest]") { arma::mat realData(4, 7); @@ -205,22 +204,22 @@ BOOST_AUTO_TEST_CASE(TestSparseSplitData) size_t splitInd = testDTree.SplitData( testData, splitDim, trueSplitVal, oTest); - BOOST_REQUIRE_EQUAL(splitInd, 3); // 2 points on left side. + REQUIRE(splitInd == 3); // 2 points on left side. - BOOST_REQUIRE_EQUAL(oTest[0], 1); - BOOST_REQUIRE_EQUAL(oTest[1], 4); - BOOST_REQUIRE_EQUAL(oTest[2], 3); - BOOST_REQUIRE_EQUAL(oTest[3], 2); - BOOST_REQUIRE_EQUAL(oTest[4], 5); - BOOST_REQUIRE_EQUAL(oTest[5], 6); - BOOST_REQUIRE_EQUAL(oTest[6], 7); + REQUIRE(oTest[0] == 1); + REQUIRE(oTest[1] == 4); + REQUIRE(oTest[2] == 3); + REQUIRE(oTest[3] == 2); + REQUIRE(oTest[4] == 5); + REQUIRE(oTest[5] == 6); + REQUIRE(oTest[6] == 7); } #endif // Tests for the public functions. -BOOST_AUTO_TEST_CASE(TestGrow) +TEST_CASE("TestGrow", "[DETTest]") { arma::mat testData(3, 5); @@ -244,34 +243,36 @@ BOOST_AUTO_TEST_CASE(TestGrow) DTree testDTree(testData); double alpha = testDTree.Grow(testData, oTest, false, 2, 1); - BOOST_REQUIRE_EQUAL(oTest[0], 0); - BOOST_REQUIRE_EQUAL(oTest[1], 3); - BOOST_REQUIRE_EQUAL(oTest[2], 1); - BOOST_REQUIRE_EQUAL(oTest[3], 2); - BOOST_REQUIRE_EQUAL(oTest[4], 4); + REQUIRE(oTest[0] == 0); + REQUIRE(oTest[1] == 3); + REQUIRE(oTest[2] == 1); + REQUIRE(oTest[3] == 2); + REQUIRE(oTest[4] == 4); // Test the structure of the tree. - BOOST_REQUIRE(testDTree.Left()->Left() == NULL); - BOOST_REQUIRE(testDTree.Left()->Right() == NULL); - BOOST_REQUIRE(testDTree.Right()->Left()->Left() == NULL); - BOOST_REQUIRE(testDTree.Right()->Left()->Right() == NULL); - BOOST_REQUIRE(testDTree.Right()->Right()->Left() == NULL); - BOOST_REQUIRE(testDTree.Right()->Right()->Right() == NULL); + REQUIRE(testDTree.Left()->Left() == NULL); + REQUIRE(testDTree.Left()->Right() == NULL); + REQUIRE(testDTree.Right()->Left()->Left() == NULL); + REQUIRE(testDTree.Right()->Left()->Right() == NULL); + REQUIRE(testDTree.Right()->Right()->Left() == NULL); + REQUIRE(testDTree.Right()->Right()->Right() == NULL); - BOOST_REQUIRE(testDTree.SubtreeLeaves() == 3); + REQUIRE(testDTree.SubtreeLeaves() == 3); - BOOST_REQUIRE(testDTree.SplitDim() == 2); - BOOST_REQUIRE_CLOSE(testDTree.SplitValue(), 5.5, 1e-5); - BOOST_REQUIRE(testDTree.Right()->SplitDim() == 1); - BOOST_REQUIRE_CLOSE(testDTree.Right()->SplitValue(), 0.5, 1e-5); + REQUIRE(testDTree.SplitDim() == 2); + REQUIRE(testDTree.SplitValue() == Approx(5.5).epsilon(1e-7)); + REQUIRE(testDTree.Right()->SplitDim() == 1); + REQUIRE(testDTree.Right()->SplitValue() == Approx(0.5).epsilon(1e-7)); // Test node errors for every node (these are private functions). #ifndef _WIN32 - BOOST_REQUIRE_CLOSE(testDTree.logNegError, rootError, 1e-10); - BOOST_REQUIRE_CLOSE(testDTree.Left()->logNegError, lError, 1e-10); - BOOST_REQUIRE_CLOSE(testDTree.Right()->logNegError, rError, 1e-10); - BOOST_REQUIRE_CLOSE(testDTree.Right()->Left()->logNegError, rlError, 1e-10); - BOOST_REQUIRE_CLOSE(testDTree.Right()->Right()->logNegError, rrError, 1e-10); + REQUIRE(testDTree.logNegError == Approx(rootError).epsilon(1e-12)); + REQUIRE(testDTree.Left()->logNegError == Approx(lError).epsilon(1e-12)); + REQUIRE(testDTree.Right()->logNegError == Approx(rError).epsilon(1e-12)); + REQUIRE(testDTree.Right()->Left()->logNegError == + Approx(rlError).epsilon(1e-12)); + REQUIRE(testDTree.Right()->Right()->logNegError == + Approx(rrError).epsilon(1e-12)); #endif // Test alpha. @@ -281,10 +282,10 @@ BOOST_AUTO_TEST_CASE(TestGrow) rAlpha = std::log(-(std::exp(rError) - (std::exp(rlError) + std::exp(rrError)))); - BOOST_REQUIRE_CLOSE(alpha, min(rootAlpha, rAlpha), 1e-10); + REQUIRE(alpha == Approx(min(rootAlpha, rAlpha)).epsilon(1e-12)); } -BOOST_AUTO_TEST_CASE(TestPruneAndUpdate) +TEST_CASE("TestPruneAndUpdate", "[DETTest]") { arma::mat testData(3, 5); @@ -298,18 +299,19 @@ BOOST_AUTO_TEST_CASE(TestPruneAndUpdate) double alpha = testDTree.Grow(testData, oTest, false, 2, 1); alpha = testDTree.PruneAndUpdate(alpha, testData.n_cols, false); - BOOST_REQUIRE_CLOSE(alpha, numeric_limits::max(), 1e-10); - BOOST_REQUIRE(testDTree.SubtreeLeaves() == 1); + REQUIRE(alpha == Approx(numeric_limits::max()).epsilon(1e-12)); + REQUIRE(testDTree.SubtreeLeaves() == 1); double rootError = -log(4.0) - log(7.0) - log(7.0); - BOOST_REQUIRE_CLOSE(testDTree.LogNegError(), rootError, 1e-10); - BOOST_REQUIRE_CLOSE(testDTree.SubtreeLeavesLogNegError(), rootError, 1e-10); - BOOST_REQUIRE(testDTree.Left() == NULL); - BOOST_REQUIRE(testDTree.Right() == NULL); + REQUIRE(testDTree.LogNegError() == Approx(rootError).epsilon(1e-12)); + REQUIRE(testDTree.SubtreeLeavesLogNegError() == + Approx(rootError).epsilon(1e-12)); + REQUIRE(testDTree.Left() == NULL); + REQUIRE(testDTree.Right() == NULL); } -BOOST_AUTO_TEST_CASE(TestComputeValue) +TEST_CASE("TestComputeValue", "[DETTest]") { arma::mat testData(3, 5); @@ -334,22 +336,22 @@ BOOST_AUTO_TEST_CASE(TestComputeValue) double d2 = (1.0 / 5.0) / exp(log(4.0) + log(0.5) + log(2.5)); double d3 = (2.0 / 5.0) / exp(log(4.0) + log(6.5) + log(2.5)); - BOOST_REQUIRE_CLOSE(d1, testDTree.ComputeValue(q1), 1e-10); - BOOST_REQUIRE_CLOSE(d2, testDTree.ComputeValue(q2), 1e-10); - BOOST_REQUIRE_CLOSE(d3, testDTree.ComputeValue(q3), 1e-10); - BOOST_REQUIRE_CLOSE(0.0, testDTree.ComputeValue(q4), 1e-10); + REQUIRE(d1 == Approx(testDTree.ComputeValue(q1)).epsilon(1e-12)); + REQUIRE(d2 == Approx(testDTree.ComputeValue(q2)).epsilon(1e-12)); + REQUIRE(d3 == Approx(testDTree.ComputeValue(q3)).epsilon(1e-12)); + REQUIRE(0.0 == Approx(testDTree.ComputeValue(q4)).epsilon(1e-12)); alpha = testDTree.PruneAndUpdate(alpha, testData.n_cols, false); double d = 1.0 / exp(log(4.0) + log(7.0) + log(7.0)); - BOOST_REQUIRE_CLOSE(d, testDTree.ComputeValue(q1), 1e-10); - BOOST_REQUIRE_CLOSE(d, testDTree.ComputeValue(q2), 1e-10); - BOOST_REQUIRE_CLOSE(d, testDTree.ComputeValue(q3), 1e-10); - BOOST_REQUIRE_CLOSE(0.0, testDTree.ComputeValue(q4), 1e-10); + REQUIRE(d == Approx(testDTree.ComputeValue(q1)).epsilon(1e-12)); + REQUIRE(d == Approx(testDTree.ComputeValue(q2)).epsilon(1e-12)); + REQUIRE(d == Approx(testDTree.ComputeValue(q3)).epsilon(1e-12)); + REQUIRE(0.0 == Approx(testDTree.ComputeValue(q4)).epsilon(1e-12)); } -BOOST_AUTO_TEST_CASE(TestVariableImportance) +TEST_CASE("TestVariableImportance", "[DETTest]") { arma::mat testData(3, 5); @@ -377,12 +379,14 @@ BOOST_AUTO_TEST_CASE(TestVariableImportance) testDTree.ComputeVariableImportance(imps); - BOOST_REQUIRE_CLOSE((double) 0.0, imps[0], 1e-10); - BOOST_REQUIRE_CLOSE((double) (rError - (rlError + rrError)), imps[1], 1e-10); - BOOST_REQUIRE_CLOSE((double) (rootError - (lError + rError)), imps[2], 1e-10); + REQUIRE((double) 0.0 == Approx(imps[0]).epsilon(1e-12)); + REQUIRE((double) (rError - (rlError + rrError)) == + Approx(imps[1]).epsilon(1e-12)); + REQUIRE((double) (rootError - (lError + rError)) == + Approx(imps[2]).epsilon(1e-12)); } -BOOST_AUTO_TEST_CASE(TestSparsePruneAndUpdate) +TEST_CASE("TestSparsePruneAndUpdate", "[DETTest]") { arma::mat realData(3, 5); @@ -399,18 +403,19 @@ BOOST_AUTO_TEST_CASE(TestSparsePruneAndUpdate) double alpha = testDTree.Grow(testData, oTest, false, 2, 1); alpha = testDTree.PruneAndUpdate(alpha, testData.n_cols, false); - BOOST_REQUIRE_CLOSE(alpha, numeric_limits::max(), 1e-10); - BOOST_REQUIRE(testDTree.SubtreeLeaves() == 1); + REQUIRE(alpha == Approx(numeric_limits::max()).epsilon(1e-12)); + REQUIRE(testDTree.SubtreeLeaves() == 1); double rootError = -log(4.0) - log(7.0) - log(7.0); - BOOST_REQUIRE_CLOSE(testDTree.LogNegError(), rootError, 1e-10); - BOOST_REQUIRE_CLOSE(testDTree.SubtreeLeavesLogNegError(), rootError, 1e-10); - BOOST_REQUIRE(testDTree.Left() == NULL); - BOOST_REQUIRE(testDTree.Right() == NULL); + REQUIRE(testDTree.LogNegError() == Approx(rootError).epsilon(1e-12)); + REQUIRE(testDTree.SubtreeLeavesLogNegError() == + Approx(rootError).epsilon(1e-12)); + REQUIRE(testDTree.Left() == NULL); + REQUIRE(testDTree.Right() == NULL); } -BOOST_AUTO_TEST_CASE(TestSparseComputeValue) +TEST_CASE("TestSparseComputeValue", "[DETTest]") { arma::mat realData(3, 5); @@ -438,25 +443,25 @@ BOOST_AUTO_TEST_CASE(TestSparseComputeValue) double d2 = (1.0 / 5.0) / exp(log(4.0) + log(0.5) + log(2.5)); double d3 = (2.0 / 5.0) / exp(log(4.0) + log(6.5) + log(2.5)); - BOOST_REQUIRE_CLOSE(d1, testDTree.ComputeValue(q1), 1e-10); - BOOST_REQUIRE_CLOSE(d2, testDTree.ComputeValue(q2), 1e-10); - BOOST_REQUIRE_CLOSE(d3, testDTree.ComputeValue(q3), 1e-10); - BOOST_REQUIRE_CLOSE(0.0, testDTree.ComputeValue(q4), 1e-10); + REQUIRE(d1 == Approx(testDTree.ComputeValue(q1)).epsilon(1e-12)); + REQUIRE(d2 == Approx(testDTree.ComputeValue(q2)).epsilon(1e-12)); + REQUIRE(d3 == Approx(testDTree.ComputeValue(q3)).epsilon(1e-12)); + REQUIRE(0.0 == Approx(testDTree.ComputeValue(q4)).epsilon(1e-12)); alpha = testDTree.PruneAndUpdate(alpha, testData.n_cols, false); double d = 1.0 / exp(log(4.0) + log(7.0) + log(7.0)); - BOOST_REQUIRE_CLOSE(d, testDTree.ComputeValue(q1), 1e-10); - BOOST_REQUIRE_CLOSE(d, testDTree.ComputeValue(q2), 1e-10); - BOOST_REQUIRE_CLOSE(d, testDTree.ComputeValue(q3), 1e-10); - BOOST_REQUIRE_CLOSE(0.0, testDTree.ComputeValue(q4), 1e-10); + REQUIRE(d == Approx(testDTree.ComputeValue(q1)).epsilon(1e-12)); + REQUIRE(d == Approx(testDTree.ComputeValue(q2)).epsilon(1e-12)); + REQUIRE(d == Approx(testDTree.ComputeValue(q3)).epsilon(1e-12)); + REQUIRE(0.0 == Approx(testDTree.ComputeValue(q4)).epsilon(1e-12)); } /** * These are not yet implemented. * -BOOST_AUTO_TEST_CASE(TestTagTree) +TEST_CASE("TestTagTree", "[DETTest]") { MatType testData(3, 5); @@ -469,7 +474,7 @@ BOOST_AUTO_TEST_CASE(TestTagTree) delete testDTree; } -BOOST_AUTO_TEST_CASE(TestFindBucket) +TEST_CASE("TestFindBucket", "[DETTest]") { MatType testData(3, 5); @@ -484,24 +489,24 @@ BOOST_AUTO_TEST_CASE(TestFindBucket) // Test functions in dt_utils.hpp -BOOST_AUTO_TEST_CASE(TestTrainer) +TEST_CASE("TestTrainer", "[DETTest]") { } -BOOST_AUTO_TEST_CASE(TestPrintVariableImportance) +TEST_CASE("TestPrintVariableImportance", "[DETTest]") { } -BOOST_AUTO_TEST_CASE(TestPrintLeafMembership) +TEST_CASE("TestPrintLeafMembership", "[DETTest]") { } */ // Test the copy constructor and the copy operator. -BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorTest) +TEST_CASE("CopyConstructorAndOperatorTest", "[DETTest]") { arma::mat testData(3, 5); @@ -544,76 +549,76 @@ BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorTest) delete testDTree; // Test the data of copied tree (using copy constructor). - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[0], maxVals0); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[0], minVals0); - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[1], maxVals1); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[1], minVals1); - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[2], maxVals2); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[2], minVals2); + REQUIRE(testDTree2.MaxVals()[0] == maxVals0); + REQUIRE(testDTree2.MinVals()[0] == minVals0); + REQUIRE(testDTree2.MaxVals()[1] == maxVals1); + REQUIRE(testDTree2.MinVals()[1] == minVals1); + REQUIRE(testDTree2.MaxVals()[2] == maxVals2); + REQUIRE(testDTree2.MinVals()[2] == minVals2); // Test the data of the copied tree (using the copy operator). - BOOST_REQUIRE_EQUAL(testDTree3.MaxVals()[0], maxVals0); - BOOST_REQUIRE_EQUAL(testDTree3.MinVals()[0], minVals0); - BOOST_REQUIRE_EQUAL(testDTree3.MaxVals()[1], maxVals1); - BOOST_REQUIRE_EQUAL(testDTree3.MinVals()[1], minVals1); - BOOST_REQUIRE_EQUAL(testDTree3.MaxVals()[2], maxVals2); - BOOST_REQUIRE_EQUAL(testDTree3.MinVals()[2], minVals2); + REQUIRE(testDTree3.MaxVals()[0] == maxVals0); + REQUIRE(testDTree3.MinVals()[0] == minVals0); + REQUIRE(testDTree3.MaxVals()[1] == maxVals1); + REQUIRE(testDTree3.MinVals()[1] == minVals1); + REQUIRE(testDTree3.MaxVals()[2] == maxVals2); + REQUIRE(testDTree3.MinVals()[2] == minVals2); // Test the structure of the tree copied using the copy constructor. - BOOST_REQUIRE(testDTree2.Left()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Left()->Right() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Left()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Left()->Right() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Right()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Right()->Right() == NULL); + REQUIRE(testDTree2.Left()->Left() == NULL); + REQUIRE(testDTree2.Left()->Right() == NULL); + REQUIRE(testDTree2.Right()->Left()->Left() == NULL); + REQUIRE(testDTree2.Right()->Left()->Right() == NULL); + REQUIRE(testDTree2.Right()->Right()->Left() == NULL); + REQUIRE(testDTree2.Right()->Right()->Right() == NULL); // Test the structure of the tree copied using the copy operator. - BOOST_REQUIRE(testDTree3.Left()->Left() == NULL); - BOOST_REQUIRE(testDTree3.Left()->Right() == NULL); - BOOST_REQUIRE(testDTree3.Right()->Left()->Left() == NULL); - BOOST_REQUIRE(testDTree3.Right()->Left()->Right() == NULL); - BOOST_REQUIRE(testDTree3.Right()->Right()->Left() == NULL); - BOOST_REQUIRE(testDTree3.Right()->Right()->Right() == NULL); + REQUIRE(testDTree3.Left()->Left() == NULL); + REQUIRE(testDTree3.Left()->Right() == NULL); + REQUIRE(testDTree3.Right()->Left()->Left() == NULL); + REQUIRE(testDTree3.Right()->Left()->Right() == NULL); + REQUIRE(testDTree3.Right()->Right()->Left() == NULL); + REQUIRE(testDTree3.Right()->Right()->Right() == NULL); // Test the data of the tree copied using the copy constructor. - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[0], maxValsL0); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[1], maxValsL1); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[2], maxValsL2); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[0], minValsL0); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[1], minValsL1); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[2], minValsL2); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[0], maxValsR0); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[1], maxValsR1); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[2], maxValsR2); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[0], minValsR0); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[1], minValsR1); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[2], minValsR2); - BOOST_REQUIRE(testDTree2.SplitDim() == 2); - BOOST_REQUIRE_CLOSE(testDTree2.SplitValue(), 5.5, 1e-5); - BOOST_REQUIRE(testDTree2.Right()->SplitDim() == 1); - BOOST_REQUIRE_CLOSE(testDTree2.Right()->SplitValue(), 0.5, 1e-5); + REQUIRE(testDTree2.Left()->MaxVals()[0] == maxValsL0); + REQUIRE(testDTree2.Left()->MaxVals()[1] == maxValsL1); + REQUIRE(testDTree2.Left()->MaxVals()[2] == maxValsL2); + REQUIRE(testDTree2.Left()->MinVals()[0] == minValsL0); + REQUIRE(testDTree2.Left()->MinVals()[1] == minValsL1); + REQUIRE(testDTree2.Left()->MinVals()[2] == minValsL2); + REQUIRE(testDTree2.Right()->MaxVals()[0] == maxValsR0); + REQUIRE(testDTree2.Right()->MaxVals()[1] == maxValsR1); + REQUIRE(testDTree2.Right()->MaxVals()[2] == maxValsR2); + REQUIRE(testDTree2.Right()->MinVals()[0] == minValsR0); + REQUIRE(testDTree2.Right()->MinVals()[1] == minValsR1); + REQUIRE(testDTree2.Right()->MinVals()[2] == minValsR2); + REQUIRE(testDTree2.SplitDim() == 2); + REQUIRE(testDTree2.SplitValue() == Approx(5.5).epsilon(1e-7)); + REQUIRE(testDTree2.Right()->SplitDim() == 1); + REQUIRE(testDTree2.Right()->SplitValue() == Approx(0.5).epsilon(1e-7)); // Test the data of the tree copied using the copy operator. - BOOST_REQUIRE_EQUAL(testDTree3.Left()->MaxVals()[0], maxValsL0); - BOOST_REQUIRE_EQUAL(testDTree3.Left()->MaxVals()[1], maxValsL1); - BOOST_REQUIRE_EQUAL(testDTree3.Left()->MaxVals()[2], maxValsL2); - BOOST_REQUIRE_EQUAL(testDTree3.Left()->MinVals()[0], minValsL0); - BOOST_REQUIRE_EQUAL(testDTree3.Left()->MinVals()[1], minValsL1); - BOOST_REQUIRE_EQUAL(testDTree3.Left()->MinVals()[2], minValsL2); - BOOST_REQUIRE_EQUAL(testDTree3.Right()->MaxVals()[0], maxValsR0); - BOOST_REQUIRE_EQUAL(testDTree3.Right()->MaxVals()[1], maxValsR1); - BOOST_REQUIRE_EQUAL(testDTree3.Right()->MaxVals()[2], maxValsR2); - BOOST_REQUIRE_EQUAL(testDTree3.Right()->MinVals()[0], minValsR0); - BOOST_REQUIRE_EQUAL(testDTree3.Right()->MinVals()[1], minValsR1); - BOOST_REQUIRE_EQUAL(testDTree3.Right()->MinVals()[2], minValsR2); - BOOST_REQUIRE(testDTree3.SplitDim() == 2); - BOOST_REQUIRE_CLOSE(testDTree3.SplitValue(), 5.5, 1e-5); - BOOST_REQUIRE(testDTree3.Right()->SplitDim() == 1); - BOOST_REQUIRE_CLOSE(testDTree3.Right()->SplitValue(), 0.5, 1e-5); + REQUIRE(testDTree3.Left()->MaxVals()[0] == maxValsL0); + REQUIRE(testDTree3.Left()->MaxVals()[1] == maxValsL1); + REQUIRE(testDTree3.Left()->MaxVals()[2] == maxValsL2); + REQUIRE(testDTree3.Left()->MinVals()[0] == minValsL0); + REQUIRE(testDTree3.Left()->MinVals()[1] == minValsL1); + REQUIRE(testDTree3.Left()->MinVals()[2] == minValsL2); + REQUIRE(testDTree3.Right()->MaxVals()[0] == maxValsR0); + REQUIRE(testDTree3.Right()->MaxVals()[1] == maxValsR1); + REQUIRE(testDTree3.Right()->MaxVals()[2] == maxValsR2); + REQUIRE(testDTree3.Right()->MinVals()[0] == minValsR0); + REQUIRE(testDTree3.Right()->MinVals()[1] == minValsR1); + REQUIRE(testDTree3.Right()->MinVals()[2] == minValsR2); + REQUIRE(testDTree3.SplitDim() == 2); + REQUIRE(testDTree3.SplitValue() == Approx(5.5).epsilon(1e-7)); + REQUIRE(testDTree3.Right()->SplitDim() == 1); + REQUIRE(testDTree3.Right()->SplitValue() == Approx(0.5).epsilon(1e-7)); } // Test the move constructor. -BOOST_AUTO_TEST_CASE(MoveConstructorTest) +TEST_CASE("MoveConstructorTest", "[DETTest]") { arma::mat testData(3, 5); @@ -653,50 +658,50 @@ BOOST_AUTO_TEST_CASE(MoveConstructorTest) DTree testDTree2(std::move(*testDTree)); // Check default values of the original tree. - BOOST_REQUIRE_EQUAL(testDTree->LogNegError(), -DBL_MAX); - BOOST_REQUIRE(testDTree->Left() == (DTree*) NULL); - BOOST_REQUIRE(testDTree->Right() == (DTree*) NULL); + REQUIRE(testDTree->LogNegError() == -DBL_MAX); + REQUIRE(testDTree->Left() == (DTree*) NULL); + REQUIRE(testDTree->Right() == (DTree*) NULL); // Delete the original tree. delete testDTree; // Test the data of the moved tree. - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[0], maxVals0); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[0], minVals0); - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[1], maxVals1); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[1], minVals1); - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[2], maxVals2); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[2], minVals2); + REQUIRE(testDTree2.MaxVals()[0] == maxVals0); + REQUIRE(testDTree2.MinVals()[0] == minVals0); + REQUIRE(testDTree2.MaxVals()[1] == maxVals1); + REQUIRE(testDTree2.MinVals()[1] == minVals1); + REQUIRE(testDTree2.MaxVals()[2] == maxVals2); + REQUIRE(testDTree2.MinVals()[2] == minVals2); // Test the structure of the moved tree. - BOOST_REQUIRE(testDTree2.Left()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Left()->Right() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Left()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Left()->Right() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Right()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Right()->Right() == NULL); + REQUIRE(testDTree2.Left()->Left() == NULL); + REQUIRE(testDTree2.Left()->Right() == NULL); + REQUIRE(testDTree2.Right()->Left()->Left() == NULL); + REQUIRE(testDTree2.Right()->Left()->Right() == NULL); + REQUIRE(testDTree2.Right()->Right()->Left() == NULL); + REQUIRE(testDTree2.Right()->Right()->Right() == NULL); // Test the data of the moved tree. - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[0], maxValsL0); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[1], maxValsL1); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[2], maxValsL2); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[0], minValsL0); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[1], minValsL1); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[2], minValsL2); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[0], maxValsR0); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[1], maxValsR1); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[2], maxValsR2); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[0], minValsR0); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[1], minValsR1); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[2], minValsR2); - BOOST_REQUIRE(testDTree2.SplitDim() == 2); - BOOST_REQUIRE_CLOSE(testDTree2.SplitValue(), 5.5, 1e-5); - BOOST_REQUIRE(testDTree2.Right()->SplitDim() == 1); - BOOST_REQUIRE_CLOSE(testDTree2.Right()->SplitValue(), 0.5, 1e-5); + REQUIRE(testDTree2.Left()->MaxVals()[0] == maxValsL0); + REQUIRE(testDTree2.Left()->MaxVals()[1] == maxValsL1); + REQUIRE(testDTree2.Left()->MaxVals()[2] == maxValsL2); + REQUIRE(testDTree2.Left()->MinVals()[0] == minValsL0); + REQUIRE(testDTree2.Left()->MinVals()[1] == minValsL1); + REQUIRE(testDTree2.Left()->MinVals()[2] == minValsL2); + REQUIRE(testDTree2.Right()->MaxVals()[0] == maxValsR0); + REQUIRE(testDTree2.Right()->MaxVals()[1] == maxValsR1); + REQUIRE(testDTree2.Right()->MaxVals()[2] == maxValsR2); + REQUIRE(testDTree2.Right()->MinVals()[0] == minValsR0); + REQUIRE(testDTree2.Right()->MinVals()[1] == minValsR1); + REQUIRE(testDTree2.Right()->MinVals()[2] == minValsR2); + REQUIRE(testDTree2.SplitDim() == 2); + REQUIRE(testDTree2.SplitValue() == Approx(5.5).epsilon(1e-7)); + REQUIRE(testDTree2.Right()->SplitDim() == 1); + REQUIRE(testDTree2.Right()->SplitValue() == Approx(0.5).epsilon(1e-7)); } // Test the move operator. -BOOST_AUTO_TEST_CASE(MoveOperatorTest) +TEST_CASE("MoveOperatorTest", "[DETTest]") { arma::mat testData(3, 5); @@ -736,46 +741,44 @@ BOOST_AUTO_TEST_CASE(MoveOperatorTest) DTree testDTree2 = std::move(*testDTree); // Check default values of the original tree. - BOOST_REQUIRE_EQUAL(testDTree->LogNegError(), -DBL_MAX); - BOOST_REQUIRE(testDTree->Left() == (DTree*) NULL); - BOOST_REQUIRE(testDTree->Right() == (DTree*) NULL); + REQUIRE(testDTree->LogNegError() == -DBL_MAX); + REQUIRE(testDTree->Left() == (DTree*) NULL); + REQUIRE(testDTree->Right() == (DTree*) NULL); // Delete the original tree. delete testDTree; // Test the data of the moved tree. - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[0], maxVals0); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[0], minVals0); - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[1], maxVals1); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[1], minVals1); - BOOST_REQUIRE_EQUAL(testDTree2.MaxVals()[2], maxVals2); - BOOST_REQUIRE_EQUAL(testDTree2.MinVals()[2], minVals2); + REQUIRE(testDTree2.MaxVals()[0] == maxVals0); + REQUIRE(testDTree2.MinVals()[0] == minVals0); + REQUIRE(testDTree2.MaxVals()[1] == maxVals1); + REQUIRE(testDTree2.MinVals()[1] == minVals1); + REQUIRE(testDTree2.MaxVals()[2] == maxVals2); + REQUIRE(testDTree2.MinVals()[2] == minVals2); // Test the structure of the moved tree. - BOOST_REQUIRE(testDTree2.Left()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Left()->Right() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Left()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Left()->Right() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Right()->Left() == NULL); - BOOST_REQUIRE(testDTree2.Right()->Right()->Right() == NULL); + REQUIRE(testDTree2.Left()->Left() == NULL); + REQUIRE(testDTree2.Left()->Right() == NULL); + REQUIRE(testDTree2.Right()->Left()->Left() == NULL); + REQUIRE(testDTree2.Right()->Left()->Right() == NULL); + REQUIRE(testDTree2.Right()->Right()->Left() == NULL); + REQUIRE(testDTree2.Right()->Right()->Right() == NULL); // Test the data of moved tree. - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[0], maxValsL0); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[1], maxValsL1); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MaxVals()[2], maxValsL2); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[0], minValsL0); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[1], minValsL1); - BOOST_REQUIRE_EQUAL(testDTree2.Left()->MinVals()[2], minValsL2); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[0], maxValsR0); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[1], maxValsR1); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MaxVals()[2], maxValsR2); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[0], minValsR0); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[1], minValsR1); - BOOST_REQUIRE_EQUAL(testDTree2.Right()->MinVals()[2], minValsR2); - BOOST_REQUIRE(testDTree2.SplitDim() == 2); - BOOST_REQUIRE_CLOSE(testDTree2.SplitValue(), 5.5, 1e-5); - BOOST_REQUIRE(testDTree2.Right()->SplitDim() == 1); - BOOST_REQUIRE_CLOSE(testDTree2.Right()->SplitValue(), 0.5, 1e-5); + REQUIRE(testDTree2.Left()->MaxVals()[0] == maxValsL0); + REQUIRE(testDTree2.Left()->MaxVals()[1] == maxValsL1); + REQUIRE(testDTree2.Left()->MaxVals()[2] == maxValsL2); + REQUIRE(testDTree2.Left()->MinVals()[0] == minValsL0); + REQUIRE(testDTree2.Left()->MinVals()[1] == minValsL1); + REQUIRE(testDTree2.Left()->MinVals()[2] == minValsL2); + REQUIRE(testDTree2.Right()->MaxVals()[0] == maxValsR0); + REQUIRE(testDTree2.Right()->MaxVals()[1] == maxValsR1); + REQUIRE(testDTree2.Right()->MaxVals()[2] == maxValsR2); + REQUIRE(testDTree2.Right()->MinVals()[0] == minValsR0); + REQUIRE(testDTree2.Right()->MinVals()[1] == minValsR1); + REQUIRE(testDTree2.Right()->MinVals()[2] == minValsR2); + REQUIRE(testDTree2.SplitDim() == 2); + REQUIRE(testDTree2.SplitValue() == Approx(5.5).epsilon(1e-7)); + REQUIRE(testDTree2.Right()->SplitDim() == 1); + REQUIRE(testDTree2.Right()->SplitValue() == Approx(0.5).epsilon(1e-7)); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/distribution_test.cpp b/src/mlpack/tests/distribution_test.cpp index 35103130b9..ab7d606a9f 100644 --- a/src/mlpack/tests/distribution_test.cpp +++ b/src/mlpack/tests/distribution_test.cpp @@ -19,17 +19,15 @@ #include #include -#include -#include "test_tools.hpp" -#include "serialization.hpp" +#include "catch.hpp" +#include "serialization_catch.hpp" +#include "test_catch_tools.hpp" using namespace mlpack; using namespace mlpack::distribution; using namespace mlpack::metric; using namespace mlpack::math; -BOOST_AUTO_TEST_SUITE(DistributionTest); - /*********************************/ /** Discrete Distribution Tests **/ /*********************************/ @@ -37,38 +35,38 @@ BOOST_AUTO_TEST_SUITE(DistributionTest); /** * Make sure we initialize correctly. */ -BOOST_AUTO_TEST_CASE(DiscreteDistributionConstructorTest) +TEST_CASE("DiscreteDistributionConstructorTest", "[DistributionTest]") { DiscreteDistribution d(5); - BOOST_REQUIRE_EQUAL(d.Probabilities().n_elem, 5); - BOOST_REQUIRE_CLOSE(d.Probability("0"), 0.2, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1"), 0.2, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("2"), 0.2, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("3"), 0.2, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("4"), 0.2, 1e-5); + REQUIRE(d.Probabilities().n_elem == 5); + REQUIRE(d.Probability("0") == Approx(0.2).epsilon(1e-7)); + REQUIRE(d.Probability("1") == Approx(0.2).epsilon(1e-7)); + REQUIRE(d.Probability("2") == Approx(0.2).epsilon(1e-7)); + REQUIRE(d.Probability("3") == Approx(0.2).epsilon(1e-7)); + REQUIRE(d.Probability("4") == Approx(0.2).epsilon(1e-7)); } /** * Make sure we get the probabilities of observations right. */ -BOOST_AUTO_TEST_CASE(DiscreteDistributionProbabilityTest) +TEST_CASE("DiscreteDistributionProbabilityTest", "[DistributionTest]") { DiscreteDistribution d(5); d.Probabilities() = "0.2 0.4 0.1 0.1 0.2"; - BOOST_REQUIRE_CLOSE(d.Probability("0"), 0.2, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1"), 0.4, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("2"), 0.1, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("3"), 0.1, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("4"), 0.2, 1e-5); + REQUIRE(d.Probability("0") == Approx(0.2).epsilon(1e-7)); + REQUIRE(d.Probability("1") == Approx(0.4).epsilon(1e-7)); + REQUIRE(d.Probability("2") == Approx(0.1).epsilon(1e-7)); + REQUIRE(d.Probability("3") == Approx(0.1).epsilon(1e-7)); + REQUIRE(d.Probability("4") == Approx(0.2).epsilon(1e-7)); } /** * Make sure we get random observations correct. */ -BOOST_AUTO_TEST_CASE(DiscreteDistributionRandomTest) +TEST_CASE("DiscreteDistributionRandomTest", "[DistributionTest]") { DiscreteDistribution d(arma::Col("3")); @@ -85,15 +83,15 @@ BOOST_AUTO_TEST_CASE(DiscreteDistributionRandomTest) actualProb /= accu(actualProb); // 8% tolerance, because this can be a noisy process. - BOOST_REQUIRE_CLOSE(actualProb(0), 0.3, 8.0); - BOOST_REQUIRE_CLOSE(actualProb(1), 0.6, 8.0); - BOOST_REQUIRE_CLOSE(actualProb(2), 0.1, 8.0); + REQUIRE(actualProb(0) == Approx(0.3).epsilon(0.08)); + REQUIRE(actualProb(1) == Approx(0.6).epsilon(0.08)); + REQUIRE(actualProb(2) == Approx(0.1).epsilon(0.08)); } /** * Make sure we can estimate from observations correctly. */ -BOOST_AUTO_TEST_CASE(DiscreteDistributionTrainTest) +TEST_CASE("DiscreteDistributionTrainTest", "[DistributionTest]") { DiscreteDistribution d(4); @@ -101,16 +99,16 @@ BOOST_AUTO_TEST_CASE(DiscreteDistributionTrainTest) d.Train(obs); - BOOST_REQUIRE_CLOSE(d.Probability("0"), 0.25, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1"), 0.25, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("2"), 0.375, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("3"), 0.125, 1e-5); + REQUIRE(d.Probability("0") == Approx(0.25).epsilon(1e-7)); + REQUIRE(d.Probability("1") == Approx(0.25).epsilon(1e-7)); + REQUIRE(d.Probability("2") == Approx(0.375).epsilon(1e-7)); + REQUIRE(d.Probability("3") == Approx(0.125).epsilon(1e-7)); } /** * Estimate from observations with probabilities. */ -BOOST_AUTO_TEST_CASE(DiscreteDistributionTrainProbTest) +TEST_CASE("DiscreteDistributionTrainProbTest", "[DistributionTest]") { DiscreteDistribution d(3); @@ -120,15 +118,15 @@ BOOST_AUTO_TEST_CASE(DiscreteDistributionTrainProbTest) d.Train(obs, prob); - BOOST_REQUIRE_CLOSE(d.Probability("0"), 0.25, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1"), 0.25, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("2"), 0.5, 1e-5); + REQUIRE(d.Probability("0") == Approx(0.25).epsilon(1e-7)); + REQUIRE(d.Probability("1") == Approx(0.25).epsilon(1e-7)); + REQUIRE(d.Probability("2") == Approx(0.5).epsilon(1e-7)); } /** * Achieve multidimensional probability distribution. */ -BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionTrainProbTest) +TEST_CASE("MultiDiscreteDistributionTrainProbTest", "[DistributionTest]") { DiscreteDistribution d("10 10 10"); @@ -137,29 +135,29 @@ BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionTrainProbTest) "0 0 0 1 1 2 2 2 2 2;"); d.Train(obs); - BOOST_REQUIRE_CLOSE(d.Probability("0 0 0"), 0.009, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("0 1 2"), 0.015, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("2 1 0"), 0.054, 1e-5); + REQUIRE(d.Probability("0 0 0") == Approx(0.009).epsilon(1e-7)); + REQUIRE(d.Probability("0 1 2") == Approx(0.015).epsilon(1e-7)); + REQUIRE(d.Probability("2 1 0") == Approx(0.054).epsilon(1e-7)); } /** * Make sure we initialize multidimensional probability distribution * correctly. */ -BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionConstructorTest) +TEST_CASE("MultiDiscreteDistributionConstructorTest", "[DistributionTest]") { DiscreteDistribution d("4 4 4 4"); - BOOST_REQUIRE_EQUAL(d.Probabilities(0).size(), 4); - BOOST_REQUIRE_EQUAL(d.Dimensionality(), 4); - BOOST_REQUIRE_CLOSE(d.Probability("0 0 0 0"), 0.00390625, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("0 1 2 3"), 0.00390625, 1e-5); + REQUIRE(d.Probabilities(0).size() == 4); + REQUIRE(d.Dimensionality() == 4); + REQUIRE(d.Probability("0 0 0 0") == Approx(0.00390625).epsilon(1e-7)); + REQUIRE(d.Probability("0 1 2 3") == Approx(0.00390625).epsilon(1e-7)); } /** * Achieve multidimensional probability distribution. */ -BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionTrainTest) +TEST_CASE("MultiDiscreteDistributionTrainTest", "[DistributionTest]") { std::vector pro; pro.push_back(arma::vec("0.1, 0.3, 0.6")); @@ -168,16 +166,16 @@ BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionTrainTest) DiscreteDistribution d(pro); - BOOST_REQUIRE_CLOSE(d.Probability("0 0 0"), 0.0083333, 1e-3); - BOOST_REQUIRE_CLOSE(d.Probability("0 1 2"), 0.0166666, 1e-3); - BOOST_REQUIRE_CLOSE(d.Probability("2 1 0"), 0.05, 1e-5); + REQUIRE(d.Probability("0 0 0") == Approx(0.0083333).epsilon(1e-5)); + REQUIRE(d.Probability("0 1 2") == Approx(0.0166666).epsilon(1e-5)); + REQUIRE(d.Probability("2 1 0") == Approx(0.05).epsilon(1e-7)); } /** * Estimate multidimensional probability distribution from observations with * probabilities. */ -BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionTrainProTest) +TEST_CASE("MultiDiscreteDistributionTrainProTest", "[DistributionTest]") { DiscreteDistribution d("5 5 5"); @@ -189,16 +187,16 @@ BOOST_AUTO_TEST_CASE(MultiDiscreteDistributionTrainProTest) d.Train(obs, prob); - BOOST_REQUIRE_CLOSE(d.Probability("0 0 0"), 0.00390625, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1 0 1"), 0.0078125, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("2 1 0"), 0.015625, 1e-5); + REQUIRE(d.Probability("0 0 0") == Approx(0.00390625).epsilon(1e-7)); + REQUIRE(d.Probability("1 0 1") == Approx(0.0078125).epsilon(1e-7)); + REQUIRE(d.Probability("2 1 0") == Approx(0.015625).epsilon(1e-7)); } /** * Test the LogProbability() function, for multiple points in the multivariate * Discrete case. */ -BOOST_AUTO_TEST_CASE(DiscreteLogProbabilityTest) +TEST_CASE("DiscreteLogProbabilityTest", "[DistributionTest]") { // Same case as before. DiscreteDistribution d("5 5"); @@ -210,17 +208,17 @@ BOOST_AUTO_TEST_CASE(DiscreteLogProbabilityTest) d.LogProbability(obs, logProb); - BOOST_REQUIRE_EQUAL(logProb.n_elem, 2); + REQUIRE(logProb.n_elem == 2); - BOOST_REQUIRE_CLOSE(logProb(0), -3.2188758248682, 1e-3); - BOOST_REQUIRE_CLOSE(logProb(1), -3.2188758248682, 1e-3); + REQUIRE(logProb(0) == Approx(-3.2188758248682).epsilon(1e-5)); + REQUIRE(logProb(1) == Approx(-3.2188758248682).epsilon(1e-5)); } /** * Test the Probability() function, for multiple points in the multivariate * Discrete case. */ -BOOST_AUTO_TEST_CASE(DiscreteProbabilityTest) +TEST_CASE("DiscreteProbabilityTest", "[DistributionTest]") { // Same case as before. DiscreteDistribution d("5 5"); @@ -232,10 +230,10 @@ BOOST_AUTO_TEST_CASE(DiscreteProbabilityTest) d.Probability(obs, prob); - BOOST_REQUIRE_EQUAL(prob.n_elem, 2); + REQUIRE(prob.n_elem == 2); - BOOST_REQUIRE_CLOSE(prob(0), 0.0400000000000, 1e-3); - BOOST_REQUIRE_CLOSE(prob(1), 0.0400000000000, 1e-3); + REQUIRE(prob(0) == Approx(0.0400000000000).epsilon(1e-5)); + REQUIRE(prob(1) == Approx(0.0400000000000).epsilon(1e-5)); } /*********************************/ @@ -245,32 +243,33 @@ BOOST_AUTO_TEST_CASE(DiscreteProbabilityTest) /** * Make sure Gaussian distributions are initialized correctly. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionEmptyConstructor) +TEST_CASE("GaussianDistributionEmptyConstructor", "[DistributionTest]") { GaussianDistribution d; - BOOST_REQUIRE_EQUAL(d.Mean().n_elem, 0); - BOOST_REQUIRE_EQUAL(d.Covariance().n_elem, 0); + REQUIRE(d.Mean().n_elem == 0); + REQUIRE(d.Covariance().n_elem == 0); } /** * Make sure Gaussian distributions are initialized to the correct * dimensionality. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionDimensionalityConstructor) +TEST_CASE("GaussianDistributionDimensionalityConstructor", + "[DistributionTest]") { GaussianDistribution d(4); - BOOST_REQUIRE_EQUAL(d.Mean().n_elem, 4); - BOOST_REQUIRE_EQUAL(d.Covariance().n_rows, 4); - BOOST_REQUIRE_EQUAL(d.Covariance().n_cols, 4); + REQUIRE(d.Mean().n_elem == 4); + REQUIRE(d.Covariance().n_rows == 4); + REQUIRE(d.Covariance().n_cols == 4); } /** * Make sure Gaussian distributions are initialized correctly when we give a * mean and covariance. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionDistributionConstructor) +TEST_CASE("GaussianDistributionDistributionConstructor", "[DistributionTest]") { arma::vec mean(3); arma::mat covariance(3, 3); @@ -283,17 +282,17 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionDistributionConstructor) GaussianDistribution d(mean, covariance); for (size_t i = 0; i < 3; ++i) - BOOST_REQUIRE_CLOSE(d.Mean()[i], mean[i], 1e-5); + REQUIRE(d.Mean()[i] == Approx(mean[i]).epsilon(1e-7)); for (size_t i = 0; i < 3; ++i) for (size_t j = 0; j < 3; ++j) - BOOST_REQUIRE_CLOSE(d.Covariance()(i, j), covariance(i, j), 1e-5); + REQUIRE(d.Covariance()(i, j) == Approx(covariance(i, j)).epsilon(1e-7)); } /** * Make sure the probability of observations is correct. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionProbabilityTest) +TEST_CASE("GaussianDistributionProbabilityTest", "[DistributionTest]") { arma::vec mean("5 6 3 3 2"); arma::mat cov("6 1 1 1 2;" @@ -304,52 +303,63 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionProbabilityTest) GaussianDistribution d(mean, cov); - BOOST_REQUIRE_CLOSE(d.LogProbability("0 1 2 3 4"), -13.432076798791542, 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("3 2 3 7 8"), -15.814880322345738, 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("2 2 0 8 1"), -13.754462857772776, 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("2 1 5 0 1"), -13.283283233107898, 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("3 0 5 1 0"), -13.800326511545279, 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("4 0 6 1 0"), -14.900192463287908, 1e-5); + REQUIRE(d.LogProbability("0 1 2 3 4") == + Approx(-13.432076798791542).epsilon(1e-7)); + REQUIRE(d.LogProbability("3 2 3 7 8") == + Approx(-15.814880322345738).epsilon(1e-7)); + REQUIRE(d.LogProbability("2 2 0 8 1") == + Approx(-13.754462857772776).epsilon(1e-7)); + REQUIRE(d.LogProbability("2 1 5 0 1") == + Approx(-13.283283233107898).epsilon(1e-7)); + REQUIRE(d.LogProbability("3 0 5 1 0") == + Approx(-13.800326511545279).epsilon(1e-7)); + REQUIRE(d.LogProbability("4 0 6 1 0") == + Approx(-14.900192463287908).epsilon(1e-7)); } /** * Test GaussianDistribution::Probability() in the univariate case. */ -BOOST_AUTO_TEST_CASE(GaussianUnivariateProbabilityTest) +TEST_CASE("GaussianUnivariateProbabilityTest", "[DistributionTest]") { GaussianDistribution g(arma::vec("0.0"), arma::mat("1.0")); // Simple case. - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("0.0")), 0.398942280401433, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("1.0")), 0.241970724519143, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("-1.0")), 0.241970724519143, - 1e-5); + REQUIRE(g.Probability(arma::vec("0.0")) == + Approx(0.398942280401433).epsilon(1e-7)); + REQUIRE(g.Probability(arma::vec("1.0")) == + Approx(0.241970724519143).epsilon(1e-7)); + REQUIRE(g.Probability(arma::vec("-1.0")) == + Approx(0.241970724519143).epsilon(1e-7)); // A few more cases... arma::mat covariance; covariance = 2.0; g.Covariance(std::move(covariance)); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("0.0")), 0.282094791773878, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("1.0")), 0.219695644733861, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("-1.0")), 0.219695644733861, - 1e-5); + REQUIRE(g.Probability(arma::vec("0.0")) == + Approx(0.282094791773878).epsilon(1e-7)); + REQUIRE(g.Probability(arma::vec("1.0")) == + Approx(0.219695644733861).epsilon(1e-7)); + REQUIRE(g.Probability(arma::vec("-1.0")) == + Approx(0.219695644733861).epsilon(1e-7)); g.Mean().fill(1.0); covariance = 1.0; g.Covariance(std::move(covariance)); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("1.0")), 0.398942280401433, 1e-5); + REQUIRE(g.Probability(arma::vec("1.0")) == + Approx(0.398942280401433).epsilon(1e-7)); covariance = 2.0; g.Covariance(std::move(covariance)); - BOOST_REQUIRE_CLOSE(g.Probability(arma::vec("-1.0")), 0.103776874355149, - 1e-5); + REQUIRE(g.Probability(arma::vec("-1.0")) == + Approx(0.103776874355149).epsilon(1e-7)); } /** * Test GaussianDistribution::Probability() in the multivariate case. */ -BOOST_AUTO_TEST_CASE(GaussianMultivariateProbabilityTest) +TEST_CASE("GaussianMultivariateProbabilityTest", "[DistributionTest]") { // Simple case. arma::vec mean = "0 0"; @@ -358,37 +368,37 @@ BOOST_AUTO_TEST_CASE(GaussianMultivariateProbabilityTest) GaussianDistribution g(mean, cov); - BOOST_REQUIRE_CLOSE(g.Probability(x), 0.159154943091895, 1e-5); + REQUIRE(g.Probability(x) == Approx(0.159154943091895).epsilon(1e-7)); arma::mat covariance; covariance = "2 0; 0 2"; g.Covariance(std::move(covariance)); - BOOST_REQUIRE_CLOSE(g.Probability(x), 0.0795774715459477, 1e-5); + REQUIRE(g.Probability(x) == Approx(0.0795774715459477).epsilon(1e-7)); x = "1 1"; - BOOST_REQUIRE_CLOSE(g.Probability(x), 0.0482661763150270, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(-x), 0.0482661763150270, 1e-5); + REQUIRE(g.Probability(x) == Approx(0.0482661763150270).epsilon(1e-7)); + REQUIRE(g.Probability(-x) == Approx(0.0482661763150270).epsilon(1e-7)); g.Mean() = "1 1"; - BOOST_REQUIRE_CLOSE(g.Probability(x), 0.0795774715459477, 1e-5); + REQUIRE(g.Probability(x) == Approx(0.0795774715459477).epsilon(1e-7)); g.Mean() *= -1; - BOOST_REQUIRE_CLOSE(g.Probability(-x), 0.0795774715459477, 1e-5); + REQUIRE(g.Probability(-x) == Approx(0.0795774715459477).epsilon(1e-7)); g.Mean() = "1 1"; covariance = "2 1.5; 1.5 4"; g.Covariance(std::move(covariance)); - BOOST_REQUIRE_CLOSE(g.Probability(x), 0.066372199406187285, 1e-5); + REQUIRE(g.Probability(x) == Approx(0.066372199406187285).epsilon(1e-7)); g.Mean() *= -1; - BOOST_REQUIRE_CLOSE(g.Probability(-x), 0.066372199406187285, 1e-5); + REQUIRE(g.Probability(-x) == Approx(0.066372199406187285).epsilon(1e-7)); g.Mean() = "1 1"; x = "-1 4"; - BOOST_REQUIRE_CLOSE(g.Probability(x), 0.00072147262356379415, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(-x), 0.00085851785428674523, 1e-5); + REQUIRE(g.Probability(x) == Approx(0.00072147262356379415).epsilon(1e-7)); + REQUIRE(g.Probability(-x) == Approx(0.00085851785428674523).epsilon(1e-7)); // Higher-dimensional case. x = "0 1 2 3 4"; @@ -401,19 +411,19 @@ BOOST_AUTO_TEST_CASE(GaussianMultivariateProbabilityTest) "2 0 1 0 6"; g.Covariance(std::move(covariance)); - BOOST_REQUIRE_CLOSE(g.Probability(x), 1.4673143531128877e-06, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(-x), 7.7404143494891786e-09, 1e-8); + REQUIRE(g.Probability(x) == Approx(1.4673143531128877e-06).epsilon(1e-7)); + REQUIRE(g.Probability(-x) == Approx(7.7404143494891786e-09).epsilon(1e-10)); g.Mean() *= -1; - BOOST_REQUIRE_CLOSE(g.Probability(-x), 1.4673143531128877e-06, 1e-5); - BOOST_REQUIRE_CLOSE(g.Probability(x), 7.7404143494891786e-09, 1e-8); + REQUIRE(g.Probability(-x) == Approx(1.4673143531128877e-06).epsilon(1e-7)); + REQUIRE(g.Probability(x) == Approx(7.7404143494891786e-09).epsilon(1e-10)); } /** * Test the phi() function, for multiple points in the multivariate Gaussian * case. */ -BOOST_AUTO_TEST_CASE(GaussianMultipointMultivariateProbabilityTest) +TEST_CASE("GaussianMultipointMultivariateProbabilityTest", "[DistributionTest]") { // Same case as before. arma::vec mean = "5 6 3 3 2"; @@ -433,20 +443,20 @@ BOOST_AUTO_TEST_CASE(GaussianMultipointMultivariateProbabilityTest) GaussianDistribution g(mean, cov); g.LogProbability(points, phis); - BOOST_REQUIRE_EQUAL(phis.n_elem, 6); + REQUIRE(phis.n_elem == 6); - BOOST_REQUIRE_CLOSE(phis(0), -13.432076798791542, 1e-5); - BOOST_REQUIRE_CLOSE(phis(1), -15.814880322345738, 1e-5); - BOOST_REQUIRE_CLOSE(phis(2), -13.754462857772776, 1e-5); - BOOST_REQUIRE_CLOSE(phis(3), -13.283283233107898, 1e-5); - BOOST_REQUIRE_CLOSE(phis(4), -13.800326511545279, 1e-5); - BOOST_REQUIRE_CLOSE(phis(5), -14.900192463287908, 1e-5); + REQUIRE(phis(0) == Approx(-13.432076798791542).epsilon(1e-7)); + REQUIRE(phis(1) == Approx(-15.814880322345738).epsilon(1e-7)); + REQUIRE(phis(2) == Approx(-13.754462857772776).epsilon(1e-7)); + REQUIRE(phis(3) == Approx(-13.283283233107898).epsilon(1e-7)); + REQUIRE(phis(4) == Approx(-13.800326511545279).epsilon(1e-7)); + REQUIRE(phis(5) == Approx(-14.900192463287908).epsilon(1e-7)); } /** * Make sure random observations follow the probability distribution correctly. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionRandomTest) +TEST_CASE("GaussianDistributionRandomTest", "[DistributionTest]") { arma::vec mean("1.0 2.25"); arma::mat cov("0.85 0.60;" @@ -464,19 +474,19 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionRandomTest) arma::mat obsCov = mlpack::math::ColumnCovariance(obs); // 10% tolerance because this can be noisy. - BOOST_REQUIRE_CLOSE(obsMean[0], mean[0], 10.0); - BOOST_REQUIRE_CLOSE(obsMean[1], mean[1], 10.0); + REQUIRE(obsMean[0] == Approx(mean[0]).epsilon(0.1)); + REQUIRE(obsMean[1] == Approx(mean[1]).epsilon(0.1)); - BOOST_REQUIRE_CLOSE(obsCov(0, 0), cov(0, 0), 10.0); - BOOST_REQUIRE_CLOSE(obsCov(0, 1), cov(0, 1), 10.0); - BOOST_REQUIRE_CLOSE(obsCov(1, 0), cov(1, 0), 10.0); - BOOST_REQUIRE_CLOSE(obsCov(1, 1), cov(1, 1), 10.0); + REQUIRE(obsCov(0, 0) == Approx(cov(0, 0)).epsilon(0.1)); + REQUIRE(obsCov(0, 1) == Approx(cov(0, 1)).epsilon(0.1)); + REQUIRE(obsCov(1, 0) == Approx(cov(1, 0)).epsilon(0.1)); + REQUIRE(obsCov(1, 1) == Approx(cov(1, 1)).epsilon(0.1)); } /** * Make sure that we can properly estimate from given observations. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionTrainTest) +TEST_CASE("GaussianDistributionTrainTest", "[DistributionTest]") { arma::vec mean("1.0 3.0 0.0 2.5"); arma::mat cov("3.0 0.0 1.0 4.0;" @@ -502,18 +512,22 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTrainTest) // Check that everything is estimated right. for (size_t i = 0; i < 4; ++i) - BOOST_REQUIRE_SMALL(d.Mean()[i] - actualMean[i], 1e-5); + REQUIRE(d.Mean()[i] - actualMean[i] == Approx(0.0).margin(1e-5)); for (size_t i = 0; i < 4; ++i) for (size_t j = 0; j < 4; ++j) - BOOST_REQUIRE_SMALL(d.Covariance()(i, j) - actualCov(i, j), 1e-5); + { + REQUIRE(d.Covariance()(i, j) - actualCov(i, j) == + Approx(0.0).margin(1e-5)); + } } /** * This test verifies the fitting of GaussianDistribution works properly when * probabilities for each sample is given. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionTrainWithProbabilitiesTest) +TEST_CASE("GaussianDistributionTrainWithProbabilitiesTest", + "[DistributionTest]") { arma::vec mean = ("5.0"); arma::vec cov = ("2.0"); @@ -538,18 +552,19 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTrainWithProbabilitiesTest) GaussianDistribution guDist2; guDist2.Train(rdata); - BOOST_REQUIRE_CLOSE(guDist.Mean()[0], guDist2.Mean()[0], 6); - BOOST_REQUIRE_CLOSE(guDist.Covariance()[0], guDist2.Covariance()[0], 6); + REQUIRE(guDist.Mean()[0] == Approx(guDist2.Mean()[0]).epsilon(0.06)); + REQUIRE(guDist.Covariance()[0] == + Approx(guDist2.Covariance()[0]).epsilon(0.06)); - BOOST_REQUIRE_CLOSE(guDist.Mean()[0], mean[0], 6); - BOOST_REQUIRE_CLOSE(guDist.Covariance()[0], cov[0], 6); + REQUIRE(guDist.Mean()[0] == Approx(mean[0]).epsilon(0.06)); + REQUIRE(guDist.Covariance()[0] == Approx(cov[0]).epsilon(0.06)); } /** * This test ensures that the same result is obtained when trained with * probabilities all set to 1 and with no probabilities at all. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionWithProbabilties1Test) +TEST_CASE("GaussianDistributionWithProbabilties1Test", "[DistributionTest]") { arma::vec mean = ("5.0"); arma::vec cov = ("4.0"); @@ -573,8 +588,9 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionWithProbabilties1Test) GaussianDistribution guDist2; guDist2.Train(rdata, probabilities); - BOOST_REQUIRE_CLOSE(guDist.Mean()[0], guDist2.Mean()[0], 1e-15); - BOOST_REQUIRE_CLOSE(guDist.Covariance()[0], guDist2.Covariance()[0], 1e-2); + REQUIRE(guDist.Mean()[0] == Approx(guDist2.Mean()[0]).epsilon(1e-17)); + REQUIRE(guDist.Covariance()[0] == + Approx(guDist2.Covariance()[0]).epsilon(1e-4)); } /** @@ -585,7 +601,8 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionWithProbabilties1Test) * We expect that the distribution we recover after training to be the same as * the second normal distribution (the one with high probabilities). */ -BOOST_AUTO_TEST_CASE(GaussianDistributionTrainWithTwoDistProbabilitiesTest) +TEST_CASE("GaussianDistributionTrainWithTwoDistProbabilitiesTest", + "[DistributionTest]") { arma::vec mean1 = ("5.0"); arma::vec cov1 = ("4.0"); @@ -626,8 +643,8 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTrainWithTwoDistProbabilitiesTest) GaussianDistribution guDist; guDist.Train(rdata, probabilities); - BOOST_REQUIRE_CLOSE(guDist.Mean()[0], mean1[0], 5); - BOOST_REQUIRE_CLOSE(guDist.Covariance()[0], cov1[0], 5); + REQUIRE(guDist.Mean()[0] == Approx(mean1[0]).epsilon(0.05)); + REQUIRE(guDist.Covariance()[0] == Approx(cov1[0]).epsilon(0.05)); } /******************************/ @@ -637,7 +654,7 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTrainWithTwoDistProbabilitiesTest) * Make sure that using an object to fit one reference set and then asking * to fit another works properly. */ -BOOST_AUTO_TEST_CASE(GammaDistributionTrainTest) +TEST_CASE("GammaDistributionTrainTest", "[DistributionTest]") { // Create a gamma distribution random generator. double alphaReal = 5.3; @@ -659,8 +676,8 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainTest) gDist.Train(rdata); // Training must estimate d pairs of alpha and beta parameters. - BOOST_REQUIRE_EQUAL(gDist.Dimensionality(), d); - BOOST_REQUIRE_EQUAL(gDist.Dimensionality(), d); + REQUIRE(gDist.Dimensionality() == d); + REQUIRE(gDist.Dimensionality() == d); // Create a N' x d' gamma distribution, fit results without new object. size_t N2 = 350; @@ -676,15 +693,15 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainTest) gDist.Train(rdata2); // Training must estimate d' pairs of alpha and beta parameters. - BOOST_REQUIRE_EQUAL(gDist.Dimensionality(), d2); - BOOST_REQUIRE_EQUAL(gDist.Dimensionality(), d2); + REQUIRE(gDist.Dimensionality() == d2); + REQUIRE(gDist.Dimensionality() == d2); } /** * This test verifies that the fitting procedure for GammaDistribution works * properly when probabilities for each sample is given. */ -BOOST_AUTO_TEST_CASE(GammaDistributionTrainWithProbabilitiesTest) +TEST_CASE("GammaDistributionTrainWithProbabilitiesTest", "[DistributionTest]") { double alphaReal = 5.4; double betaReal = 6.7; @@ -711,24 +728,24 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainWithProbabilitiesTest) GammaDistribution gDist2; gDist2.Train(rdata); - BOOST_REQUIRE_CLOSE(gDist2.Alpha(0), gDist.Alpha(0), 1.5); - BOOST_REQUIRE_CLOSE(gDist2.Beta(0), gDist.Beta(0), 1.5); + REQUIRE(gDist2.Alpha(0) == Approx(gDist.Alpha(0)).epsilon(0.015)); + REQUIRE(gDist2.Beta(0) == Approx(gDist.Beta(0)).epsilon(0.015)); - BOOST_REQUIRE_CLOSE(gDist2.Alpha(1), gDist.Alpha(1), 1.5); - BOOST_REQUIRE_CLOSE(gDist2.Beta(1), gDist.Beta(1), 1.5); + REQUIRE(gDist2.Alpha(1) == Approx(gDist.Alpha(1)).epsilon(0.015)); + REQUIRE(gDist2.Beta(1) == Approx(gDist.Beta(1)).epsilon(0.015)); - BOOST_REQUIRE_CLOSE(alphaReal, gDist.Alpha(0), 3.0); - BOOST_REQUIRE_CLOSE(betaReal, gDist.Beta(0), 3.0); + REQUIRE(alphaReal == Approx(gDist.Alpha(0)).epsilon(0.03)); + REQUIRE(betaReal == Approx(gDist.Beta(0)).epsilon(0.03)); - BOOST_REQUIRE_CLOSE(alphaReal, gDist.Alpha(1), 3.0); - BOOST_REQUIRE_CLOSE(betaReal, gDist.Beta(1), 3.0); + REQUIRE(alphaReal == Approx(gDist.Alpha(1)).epsilon(0.03)); + REQUIRE(betaReal == Approx(gDist.Beta(1)).epsilon(0.03)); } /** * This test ensures that the same result is obtained when trained with * probabilities all set to 1 and with no probabilities at all. */ -BOOST_AUTO_TEST_CASE(GammaDistributionTrainAllProbabilities1Test) +TEST_CASE("GammaDistributionTrainAllProbabilities1Test", "[DistributionTest]") { double alphaReal = 5.4; double betaReal = 6.7; @@ -753,11 +770,11 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainAllProbabilities1Test) arma::vec allProbabilities1(N, arma::fill::ones); gDist2.Train(rdata, allProbabilities1); - BOOST_REQUIRE_CLOSE(gDist2.Alpha(0), gDist.Alpha(0), 1e-5); - BOOST_REQUIRE_CLOSE(gDist2.Beta(0), gDist.Beta(0), 1e-5); + REQUIRE(gDist2.Alpha(0) == Approx(gDist.Alpha(0)).epsilon(1e-7)); + REQUIRE(gDist2.Beta(0) == Approx(gDist.Beta(0)).epsilon(1e-7)); - BOOST_REQUIRE_CLOSE(gDist2.Alpha(1), gDist.Alpha(1), 1e-5); - BOOST_REQUIRE_CLOSE(gDist2.Beta(1), gDist.Beta(1), 1e-5); + REQUIRE(gDist2.Alpha(1) == Approx(gDist.Alpha(1)).epsilon(1e-7)); + REQUIRE(gDist2.Beta(1) == Approx(gDist.Beta(1)).epsilon(1e-7)); } /** @@ -767,7 +784,8 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainAllProbabilities1Test) * gamma distribution recovered has the same parameters as the second gamma * distribution with high probabilities. */ -BOOST_AUTO_TEST_CASE(GammaDistributionTrainTwoDistProbabilities1Test) +TEST_CASE("GammaDistributionTrainTwoDistProbabilities1Test", + "[DistributionTest]") { double alphaReal = 5.4; double betaReal = 6.7; @@ -807,11 +825,11 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainTwoDistProbabilities1Test) GammaDistribution gDist; gDist.Train(rdata, probabilities); - BOOST_REQUIRE_CLOSE(alphaReal2, gDist.Alpha(0), 5); - BOOST_REQUIRE_CLOSE(betaReal2, gDist.Beta(0), 5); + REQUIRE(alphaReal2 == Approx(gDist.Alpha(0)).epsilon(0.05)); + REQUIRE(betaReal2 == Approx(gDist.Beta(0)).epsilon(0.05)); - BOOST_REQUIRE_CLOSE(alphaReal2, gDist.Alpha(1), 5); - BOOST_REQUIRE_CLOSE(betaReal2, gDist.Beta(1), 5); + REQUIRE(alphaReal2 == Approx(gDist.Alpha(1)).epsilon(0.05)); + REQUIRE(betaReal2 == Approx(gDist.Beta(1)).epsilon(0.05)); } /** @@ -820,7 +838,7 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainTwoDistProbabilities1Test) * with different alpha/beta parameters so we make sure we don't have some weird * bug that always converges to the same number. */ -BOOST_AUTO_TEST_CASE(GammaDistributionFittingTest) +TEST_CASE("GammaDistributionFittingTest", "[DistributionTest]") { // Offset from the actual alpha/beta. 10% is quite a relaxed tolerance since // the random points we generate are few (for test speed) and might be fitted @@ -848,8 +866,8 @@ BOOST_AUTO_TEST_CASE(GammaDistributionFittingTest) gDist.Train(rdata); // Estimated parameter must be close to real. - BOOST_REQUIRE_CLOSE(gDist.Alpha(0), alphaReal, errorTolerance); - BOOST_REQUIRE_CLOSE(gDist.Beta(0), betaReal, errorTolerance); + REQUIRE(gDist.Alpha(0) == Approx(alphaReal).epsilon(errorTolerance / 100)); + REQUIRE(gDist.Beta(0) == Approx(betaReal).epsilon(errorTolerance / 100)); /** Iteration 2 (different parameter set) **/ @@ -869,15 +887,15 @@ BOOST_AUTO_TEST_CASE(GammaDistributionFittingTest) gDist2.Train(rdata2); // Estimated parameter must be close to real. - BOOST_REQUIRE_CLOSE(gDist2.Alpha(0), alphaReal2, errorTolerance); - BOOST_REQUIRE_CLOSE(gDist2.Beta(0), betaReal2, errorTolerance); + REQUIRE(gDist2.Alpha(0) == Approx(alphaReal2).epsilon(errorTolerance / 100)); + REQUIRE(gDist2.Beta(0) == Approx(betaReal2).epsilon(errorTolerance / 100)); } /** * Test that Train() and the constructor that takes data give the same resulting * distribution. */ -BOOST_AUTO_TEST_CASE(GammaDistributionTrainConstructorTest) +TEST_CASE("GammaDistributionTrainConstructorTest", "[DistributionTest]") { const arma::mat data = arma::randu(10, 500); @@ -887,8 +905,8 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainConstructorTest) for (size_t i = 0; i < 10; ++i) { - BOOST_REQUIRE_CLOSE(d1.Alpha(i), d2.Alpha(i), 1e-5); - BOOST_REQUIRE_CLOSE(d1.Beta(i), d2.Beta(i), 1e-5); + REQUIRE(d1.Alpha(i) == Approx(d2.Alpha(i)).epsilon(1e-7)); + REQUIRE(d1.Beta(i) == Approx(d2.Beta(i)).epsilon(1e-7)); } } @@ -896,7 +914,7 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainConstructorTest) * Test that Train() with a dataset and Train() with dataset statistics return * the same results. */ -BOOST_AUTO_TEST_CASE(GammaDistributionTrainStatisticsTest) +TEST_CASE("GammaDistributionTrainStatisticsTest", "[DistributionTest]") { const arma::mat data = arma::randu(1, 500); @@ -910,15 +928,15 @@ BOOST_AUTO_TEST_CASE(GammaDistributionTrainStatisticsTest) const arma::vec logMeanx = arma::log(meanx); d2.Train(logMeanx, meanLogx, meanx); - BOOST_REQUIRE_CLOSE(d1.Alpha(0), d2.Alpha(0), 1e-5); - BOOST_REQUIRE_CLOSE(d1.Beta(0), d2.Beta(0), 1e-5); + REQUIRE(d1.Alpha(0) == Approx(d2.Alpha(0)).epsilon(1e-7)); + REQUIRE(d1.Beta(0) == Approx(d2.Beta(0)).epsilon(1e-7)); } /** * Tests that Random() generates points that can be reasonably well fit by the * distribution that generated them. */ -BOOST_AUTO_TEST_CASE(GammaDistributionRandomTest) +TEST_CASE("GammaDistributionRandomTest", "[DistributionTest]") { const arma::vec a("2.0 2.5 3.0"), b("0.4 0.6 1.3"); const size_t numPoints = 2000; @@ -934,12 +952,12 @@ BOOST_AUTO_TEST_CASE(GammaDistributionRandomTest) GammaDistribution d2(data); for (size_t i = 0; i < 3; ++i) { - BOOST_REQUIRE_CLOSE(d2.Alpha(i), a(i), 10); // Within 10% - BOOST_REQUIRE_CLOSE(d2.Beta(i), b(i), 10); + REQUIRE(d2.Alpha(i) == Approx(a(i)).epsilon(0.1)); // Within 10% + REQUIRE(d2.Beta(i) == Approx(b(i)).epsilon(0.1)); } } -BOOST_AUTO_TEST_CASE(GammaDistributionProbabilityTest) +TEST_CASE("GammaDistributionProbabilityTest", "[DistributionTest]") { // Train two 1-dimensional distributions. const arma::vec a1("2.0"), b1("0.9"), a2("3.1"), b2("1.4"); @@ -949,16 +967,16 @@ BOOST_AUTO_TEST_CASE(GammaDistributionProbabilityTest) // Evaluated at wolfram|alpha GammaDistribution d1(a1, b1); d1.Probability(x1, prob1); - BOOST_REQUIRE_CLOSE(prob1(0), 0.267575, 1e-3); + REQUIRE(prob1(0) == Approx(0.267575).epsilon(1e-5)); // Evaluated at wolfram|alpha GammaDistribution d2(a2, b2); d2.Probability(x2, prob2); - BOOST_REQUIRE_CLOSE(prob2(0), 0.189043, 1e-3); + REQUIRE(prob2(0) == Approx(0.189043).epsilon(1e-5)); // Check that the overload that returns the probability for 1 dimension // agrees. - BOOST_REQUIRE_CLOSE(prob2(0), d2.Probability(2.94, 0), 1e-5); + REQUIRE(prob2(0) == Approx(d2.Probability(2.94, 0)).epsilon(1e-7)); // Combine into one 2-dimensional distribution. const arma::vec a3("2.0 3.1"), b3("0.9 1.4"); @@ -971,11 +989,11 @@ BOOST_AUTO_TEST_CASE(GammaDistributionProbabilityTest) // 1-dimensional distributions (evaluated at wolfram|alpha). GammaDistribution d3(a3, b3); d3.Probability(x3, prob3); - BOOST_REQUIRE_CLOSE(prob3(0), 0.04408, 1e-2); - BOOST_REQUIRE_CLOSE(prob3(1), 0.026165, 1e-2); + REQUIRE(prob3(0) == Approx(0.04408).epsilon(1e-4)); + REQUIRE(prob3(1) == Approx(0.026165).epsilon(1e-4)); } -BOOST_AUTO_TEST_CASE(GammaDistributionLogProbabilityTest) +TEST_CASE("GammaDistributionLogProbabilityTest", "[DistributionTest]") { // Train two 1-dimensional distributions. const arma::vec a1("2.0"), b1("0.9"), a2("3.1"), b2("1.4"); @@ -985,16 +1003,16 @@ BOOST_AUTO_TEST_CASE(GammaDistributionLogProbabilityTest) // Evaluated at wolfram|alpha GammaDistribution d1(a1, b1); d1.LogProbability(x1, logprob1); - BOOST_REQUIRE_CLOSE(logprob1(0), std::log(0.267575), 1e-3); + REQUIRE(logprob1(0) == Approx(std::log(0.267575)).epsilon(1e-5)); // Evaluated at wolfram|alpha GammaDistribution d2(a2, b2); d2.LogProbability(x2, logprob2); - BOOST_REQUIRE_CLOSE(logprob2(0), std::log(0.189043), 1e-3); + REQUIRE(logprob2(0) == Approx(std::log(0.189043)).epsilon(1e-5)); // Check that the overload that returns the log probability for // 1 dimension agrees. - BOOST_REQUIRE_CLOSE(logprob2(0), d2.LogProbability(2.94, 0), 1e-5); + REQUIRE(logprob2(0) == Approx(d2.LogProbability(2.94, 0)).epsilon(1e-7)); // Combine into one 2-dimensional distribution. const arma::vec a3("2.0 3.1"), b3("0.9 1.4"); @@ -1008,14 +1026,14 @@ BOOST_AUTO_TEST_CASE(GammaDistributionLogProbabilityTest) // 1-dimensional distributions (evaluated at wolfram|alpha). GammaDistribution d3(a3, b3); d3.LogProbability(x3, logprob3); - BOOST_REQUIRE_CLOSE(logprob3(0), std::log(0.04408), 1e-3); - BOOST_REQUIRE_CLOSE(logprob3(1), std::log(0.026165), 1e-3); + REQUIRE(logprob3(0) == Approx(std::log(0.04408)).epsilon(1e-5)); + REQUIRE(logprob3(1) == Approx(std::log(0.026165)).epsilon(1e-5)); } /** * Discrete Distribution serialization test. */ -BOOST_AUTO_TEST_CASE(DiscreteDistributionTest) +TEST_CASE("DiscreteDistributionTest", "[DistributionTest]") { // I assume that I am properly saving vectors, so, this should be // straightforward. @@ -1036,15 +1054,15 @@ BOOST_AUTO_TEST_CASE(DiscreteDistributionTest) const double prob = t.Probability(obs); if (prob == 0.0) { - BOOST_REQUIRE_SMALL(xmlT.Probability(obs), 1e-8); - BOOST_REQUIRE_SMALL(textT.Probability(obs), 1e-8); - BOOST_REQUIRE_SMALL(binaryT.Probability(obs), 1e-8); + REQUIRE(xmlT.Probability(obs) == Approx(0.0).margin(1e-8)); + REQUIRE(textT.Probability(obs) == Approx(0.0).margin(1e-8)); + REQUIRE(binaryT.Probability(obs) == Approx(0.0).margin(1e-8)); } else { - BOOST_REQUIRE_CLOSE(prob, xmlT.Probability(obs), 1e-8); - BOOST_REQUIRE_CLOSE(prob, textT.Probability(obs), 1e-8); - BOOST_REQUIRE_CLOSE(prob, binaryT.Probability(obs), 1e-8); + REQUIRE(prob == Approx(xmlT.Probability(obs)).epsilon(1e-10)); + REQUIRE(prob == Approx(textT.Probability(obs)).epsilon(1e-10)); + REQUIRE(prob == Approx(binaryT.Probability(obs)).epsilon(1e-10)); } } } @@ -1052,7 +1070,7 @@ BOOST_AUTO_TEST_CASE(DiscreteDistributionTest) /** * Gaussian Distribution serialization test. */ -BOOST_AUTO_TEST_CASE(GaussianDistributionTest) +TEST_CASE("GaussianDistributionTest", "[DistributionTest]") { arma::vec mean(10); mean.randu(); @@ -1066,9 +1084,9 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTest) SerializeObjectAll(g, xmlG, textG, binaryG); - BOOST_REQUIRE_EQUAL(g.Dimensionality(), xmlG.Dimensionality()); - BOOST_REQUIRE_EQUAL(g.Dimensionality(), textG.Dimensionality()); - BOOST_REQUIRE_EQUAL(g.Dimensionality(), binaryG.Dimensionality()); + REQUIRE(g.Dimensionality() == xmlG.Dimensionality()); + REQUIRE(g.Dimensionality() == textG.Dimensionality()); + REQUIRE(g.Dimensionality() == binaryG.Dimensionality()); // First, check the means. CheckMatrices(g.Mean(), xmlG.Mean(), textG.Mean(), binaryG.Mean()); @@ -1088,18 +1106,21 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTest) if (prob == 0.0) { - BOOST_REQUIRE_SMALL(xmlG.Probability(randomObs.unsafe_col(i)), 1e-8); - BOOST_REQUIRE_SMALL(textG.Probability(randomObs.unsafe_col(i)), 1e-8); - BOOST_REQUIRE_SMALL(binaryG.Probability(randomObs.unsafe_col(i)), 1e-8); + REQUIRE(xmlG.Probability(randomObs.unsafe_col(i)) == + Approx(0.0).margin(1e-8)); + REQUIRE(textG.Probability(randomObs.unsafe_col(i)) == + Approx(0.0).margin(1e-8)); + REQUIRE(binaryG.Probability(randomObs.unsafe_col(i)) == + Approx(0.0).margin(1e-8)); } else { - BOOST_REQUIRE_CLOSE(prob, xmlG.Probability(randomObs.unsafe_col(i)), - 1e-8); - BOOST_REQUIRE_CLOSE(prob, textG.Probability(randomObs.unsafe_col(i)), - 1e-8); - BOOST_REQUIRE_CLOSE(prob, binaryG.Probability(randomObs.unsafe_col(i)), - 1e-8); + REQUIRE(prob == + Approx(xmlG.Probability(randomObs.unsafe_col(i))).epsilon(1e-10)); + REQUIRE(prob == + Approx(textG.Probability(randomObs.unsafe_col(i))).epsilon(1e-10)); + REQUIRE(prob == + Approx(binaryG.Probability(randomObs.unsafe_col(i))).epsilon(1e-10)); } } } @@ -1107,7 +1128,7 @@ BOOST_AUTO_TEST_CASE(GaussianDistributionTest) /** * Laplace Distribution serialization test. */ -BOOST_AUTO_TEST_CASE(LaplaceDistributionTest) +TEST_CASE("LaplaceDistributionTest", "[DistributionTest]") { arma::vec mean(20); mean.randu(); @@ -1117,9 +1138,9 @@ BOOST_AUTO_TEST_CASE(LaplaceDistributionTest) SerializeObjectAll(l, xmlL, textL, binaryL); - BOOST_REQUIRE_CLOSE(l.Scale(), xmlL.Scale(), 1e-8); - BOOST_REQUIRE_CLOSE(l.Scale(), textL.Scale(), 1e-8); - BOOST_REQUIRE_CLOSE(l.Scale(), binaryL.Scale(), 1e-8); + REQUIRE(l.Scale() == Approx(xmlL.Scale()).epsilon(1e-10)); + REQUIRE(l.Scale() == Approx(textL.Scale()).epsilon(1e-10)); + REQUIRE(l.Scale() == Approx(binaryL.Scale()).epsilon(1e-10)); CheckMatrices(l.Mean(), xmlL.Mean(), textL.Mean(), binaryL.Mean()); } @@ -1127,15 +1148,15 @@ BOOST_AUTO_TEST_CASE(LaplaceDistributionTest) /** * Laplace Distribution Probability Test. */ -BOOST_AUTO_TEST_CASE(LaplaceDistributionProbabilityTest) +TEST_CASE("LaplaceDistributionProbabilityTest", "[DistributionTest]") { LaplaceDistribution l(arma::vec("0.0"), 1.0); // Simple case. - BOOST_REQUIRE_CLOSE(l.Probability(arma::vec("0.0")), - 0.500000000000000, 1e-5); - BOOST_REQUIRE_CLOSE(l.Probability(arma::vec("1.0")), - 0.183939720585721, 1e-5); + REQUIRE(l.Probability(arma::vec("0.0")) == + Approx(0.500000000000000).epsilon(1e-7)); + REQUIRE(l.Probability(arma::vec("1.0")) == + Approx(0.183939720585721).epsilon(1e-7)); arma::mat points = "0.0 1.0;"; @@ -1143,24 +1164,24 @@ BOOST_AUTO_TEST_CASE(LaplaceDistributionProbabilityTest) l.Probability(points, probabilities); - BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2); + REQUIRE(probabilities.n_elem == 2); - BOOST_REQUIRE_CLOSE(probabilities(0), 0.500000000000000, 1e-5); - BOOST_REQUIRE_CLOSE(probabilities(1), 0.183939720585721, 1e-5); + REQUIRE(probabilities(0) == Approx(0.500000000000000).epsilon(1e-7)); + REQUIRE(probabilities(1) == Approx(0.183939720585721).epsilon(1e-7)); } /** * Laplace Distribution Log Probability Test. */ -BOOST_AUTO_TEST_CASE(LaplaceDistributionLogProbabilityTest) +TEST_CASE("LaplaceDistributionLogProbabilityTest", "[DistributionTest]") { LaplaceDistribution l(arma::vec("0.0"), 1.0); // Simple case. - BOOST_REQUIRE_CLOSE(l.LogProbability(arma::vec("0.0")), - -0.693147180559945, 1e-5); - BOOST_REQUIRE_CLOSE(l.LogProbability(arma::vec("1.0")), - -1.693147180559946, 1e-5); + REQUIRE(l.LogProbability(arma::vec("0.0")) == + Approx(-0.693147180559945).epsilon(1e-7)); + REQUIRE(l.LogProbability(arma::vec("1.0")) == + Approx(-1.693147180559946).epsilon(1e-7)); arma::mat points = "0.0 1.0;"; @@ -1168,18 +1189,19 @@ BOOST_AUTO_TEST_CASE(LaplaceDistributionLogProbabilityTest) l.LogProbability(points, logProbabilities); - BOOST_REQUIRE_EQUAL(logProbabilities.n_elem, 2); + REQUIRE(logProbabilities.n_elem == 2); - BOOST_REQUIRE_CLOSE(logProbabilities(0), -0.693147180559945, - 1e-5); - BOOST_REQUIRE_CLOSE(logProbabilities(1), -1.693147180559946, - 1e-5); + REQUIRE(logProbabilities(0) == + Approx(-0.693147180559945).epsilon(1e-7)); + + REQUIRE(logProbabilities(1) == + Approx(-1.693147180559946).epsilon(1e-7)); } /** * Mahalanobis Distance serialization test. */ -BOOST_AUTO_TEST_CASE(MahalanobisDistanceTest) +TEST_CASE("MahalanobisDistanceTest", "[DistributionTest]") { MahalanobisDistance<> d; d.Covariance().randu(50, 50); @@ -1198,7 +1220,7 @@ BOOST_AUTO_TEST_CASE(MahalanobisDistanceTest) /** * Regression distribution serialization test. */ -BOOST_AUTO_TEST_CASE(RegressionDistributionTest) +TEST_CASE("RegressionDistributionTest", "[DistributionTest]") { // Generate some random data. arma::mat data; @@ -1225,15 +1247,15 @@ BOOST_AUTO_TEST_CASE(RegressionDistributionTest) // Check the regression function. if (rd.Rf().Lambda() == 0.0) { - BOOST_REQUIRE_SMALL(xmlRd.Rf().Lambda(), 1e-8); - BOOST_REQUIRE_SMALL(textRd.Rf().Lambda(), 1e-8); - BOOST_REQUIRE_SMALL(binaryRd.Rf().Lambda(), 1e-8); + REQUIRE(xmlRd.Rf().Lambda() == Approx(0.0).margin(1e-8)); + REQUIRE(textRd.Rf().Lambda() == Approx(0.0).margin(1e-8)); + REQUIRE(binaryRd.Rf().Lambda() == Approx(0.0).margin(1e-8)); } else { - BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), xmlRd.Rf().Lambda(), 1e-8); - BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), textRd.Rf().Lambda(), 1e-8); - BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), binaryRd.Rf().Lambda(), 1e-8); + REQUIRE(rd.Rf().Lambda() == Approx(xmlRd.Rf().Lambda()).epsilon(1e-10)); + REQUIRE(rd.Rf().Lambda() == Approx(textRd.Rf().Lambda()).epsilon(1e-10)); + REQUIRE(rd.Rf().Lambda() == Approx(binaryRd.Rf().Lambda()).epsilon(1e-10)); } CheckMatrices(rd.Rf().Parameters(), @@ -1250,31 +1272,32 @@ BOOST_AUTO_TEST_CASE(RegressionDistributionTest) * Make sure Diagonal Covariance Gaussian distributions are initialized * correctly. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionEmptyConstructor) +TEST_CASE("DiagonalGaussianDistributionEmptyConstructor", "[DistributionTest]") { DiagonalGaussianDistribution d; - BOOST_REQUIRE_EQUAL(d.Mean().n_elem, 0); - BOOST_REQUIRE_EQUAL(d.Covariance().n_elem, 0); + REQUIRE(d.Mean().n_elem == 0); + REQUIRE(d.Covariance().n_elem == 0); } /** * Make sure Diagonal Covariance Gaussian distributions are initialized to * the correct dimensionality. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionDimensionalityConstructor) +TEST_CASE("DiagonalGaussianDistributionDimensionalityConstructor", + "[DistributionTest]") { DiagonalGaussianDistribution d(4); - BOOST_REQUIRE_EQUAL(d.Mean().n_elem, 4); - BOOST_REQUIRE_EQUAL(d.Covariance().n_elem, 4); + REQUIRE(d.Mean().n_elem == 4); + REQUIRE(d.Covariance().n_elem == 4); } /** * Make sure Diagonal Covariance Gaussian distributions are initialized * correctly when we give a mean and covariance. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionConstructor) +TEST_CASE("DiagonalGaussianDistributionConstructor", "[DistributionTest]") { arma::vec mean = arma::randu(3); arma::vec covariance = arma::randu(3); @@ -1284,8 +1307,8 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionConstructor) // Make sure the mean and covariance is correct. for (size_t i = 0; i < 3; ++i) { - BOOST_REQUIRE_CLOSE(d.Mean()(i), mean(i), 1e-5); - BOOST_REQUIRE_CLOSE(d.Covariance()(i), covariance(i), 1e-5); + REQUIRE(d.Mean()(i) == Approx(mean(i)).epsilon(1e-7)); + REQUIRE(d.Covariance()(i) == Approx(covariance(i)).epsilon(1e-7)); } } @@ -1293,7 +1316,7 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionConstructor) * Make sure the probability of observations is correct. * The values were calculated using 'dmvnorm' in R. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionProbabilityTest) +TEST_CASE("DiagonalGaussianDistributionProbabilityTest", "[DistributionTest]") { arma::vec mean("2 5 3 4 1"); arma::vec cov("3 1 5 3 2"); @@ -1301,56 +1324,56 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionProbabilityTest) DiagonalGaussianDistribution d(mean, cov); // Observations lists randomly selected. - BOOST_REQUIRE_CLOSE(d.LogProbability("3 5 2 7 8"), -20.861264167855161, - 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("7 8 4 0 5"), -22.277930834521829, - 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("6 8 7 7 5"), -21.111264167855161, - 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("2 9 5 6 3"), -16.911264167855162, - 1e-5); - BOOST_REQUIRE_CLOSE(d.LogProbability("5 8 2 9 7"), -26.111264167855161, - 1e-5); + REQUIRE(d.LogProbability("3 5 2 7 8") == + Approx(-20.861264167855161).epsilon(1e-7)); + REQUIRE(d.LogProbability("7 8 4 0 5") == + Approx(-22.277930834521829).epsilon(1e-7)); + REQUIRE(d.LogProbability("6 8 7 7 5") == + Approx(-21.111264167855161).epsilon(1e-7)); + REQUIRE(d.LogProbability("2 9 5 6 3") == + Approx(-16.9112641678551621).epsilon(1e-7)); + REQUIRE(d.LogProbability("5 8 2 9 7") == + Approx(-26.111264167855161).epsilon(1e-7)); } /** * Test DiagonalGaussianDistribution::Probability() in the univariate case. * The values were calculated using 'dmvnorm' in R. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianUnivariateProbabilityTest) +TEST_CASE("DiagonalGaussianUnivariateProbabilityTest", "[DistributionTest]") { DiagonalGaussianDistribution d(arma::vec("0.0"), arma::vec("1.0")); // Mean: 0.0, Covariance: 1.0 - BOOST_REQUIRE_CLOSE(d.Probability("0.0"), 0.3989422804014327, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1.0"), 0.24197072451914337, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("-1.0"), 0.24197072451914337, 1e-5); + REQUIRE(d.Probability("0.0") == Approx(0.3989422804014327).epsilon(1e-7)); + REQUIRE(d.Probability("1.0") == Approx(0.24197072451914337).epsilon(1e-7)); + REQUIRE(d.Probability("-1.0") == Approx(0.24197072451914337).epsilon(1e-7)); // Mean: 0.0, Covariance: 2.0 d.Covariance("2.0"); - BOOST_REQUIRE_CLOSE(d.Probability("0.0"), 0.28209479177387814, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1.0"), 0.21969564473386122, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("-1.0"), 0.21969564473386122, 1e-5); + REQUIRE(d.Probability("0.0") == Approx(0.28209479177387814).epsilon(1e-7)); + REQUIRE(d.Probability("1.0") == Approx(0.21969564473386122).epsilon(1e-7)); + REQUIRE(d.Probability("-1.0") == Approx(0.21969564473386122).epsilon(1e-7)); // Mean: 1.0, Covariance: 1.0 d.Mean() = "1.0"; d.Covariance("1.0"); - BOOST_REQUIRE_CLOSE(d.Probability("0.0"), 0.24197072451914337, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1.0"), 0.3989422804014327, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("-1.0"), 0.053990966513188056, 1e-5); + REQUIRE(d.Probability("0.0") == Approx(0.24197072451914337).epsilon(1e-7)); + REQUIRE(d.Probability("1.0") == Approx(0.3989422804014327).epsilon(1e-7)); + REQUIRE(d.Probability("-1.0") == Approx(0.053990966513188056).epsilon(1e-7)); // Mean: 1.0, Covariance: 2.0 d.Covariance("2.0"); - BOOST_REQUIRE_CLOSE(d.Probability("0.0"), 0.21969564473386122, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("1.0"), 0.28209479177387814, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability("-1.0"), 0.10377687435514872, 1e-5); + REQUIRE(d.Probability("0.0") == Approx(0.21969564473386122).epsilon(1e-7)); + REQUIRE(d.Probability("1.0") == Approx(0.28209479177387814).epsilon(1e-7)); + REQUIRE(d.Probability("-1.0") == Approx(0.10377687435514872).epsilon(1e-7)); } /** * Test DiagonalGaussianDistribution::Probability() in the multivariate case. * The values were calculated using 'dmvnorm' in R. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianMultivariateProbabilityTest) +TEST_CASE("DiagonalGaussianMultivariateProbabilityTest", "[DistributionTest]") { arma::vec mean("0 0"); arma::vec cov("2 2"); @@ -1358,27 +1381,28 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianMultivariateProbabilityTest) DiagonalGaussianDistribution d(mean, cov); - BOOST_REQUIRE_CLOSE(d.Probability(obs), 0.079577471545947673, 1e-5); + REQUIRE(d.Probability(obs) == Approx(0.079577471545947673).epsilon(1e-7)); obs = "1 1"; - BOOST_REQUIRE_CLOSE(d.Probability(obs), 0.048266176315026957, 1e-5); + REQUIRE(d.Probability(obs) == Approx(0.048266176315026957).epsilon(1e-7)); d.Mean() = "1 3"; - BOOST_REQUIRE_CLOSE(d.Probability(obs), 0.029274915762159581, 1e-5); - BOOST_REQUIRE_CLOSE(d.Probability(-obs), 0.00053618878559782773, 1e-5); + REQUIRE(d.Probability(obs) == Approx(0.029274915762159581).epsilon(1e-7)); + REQUIRE(d.Probability(-obs) == Approx(0.00053618878559782773).epsilon(1e-7)); // Higher dimensional case. d.Mean() = "1 3 6 2 7"; d.Covariance("3 1 5 3 2"); obs = "2 5 7 3 8"; - BOOST_REQUIRE_CLOSE(d.Probability(obs), 7.2790083003378082e-05, 1e-5); + REQUIRE(d.Probability(obs) == Approx(7.2790083003378082e-05).epsilon(1e-7)); } /** * Test the phi() function, for multiple points in the multivariate Gaussian * case. The values were calculated using 'dmvnorm' in R. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianMultipointMultivariateProbabilityTest) +TEST_CASE("DiagonalGaussianMultipointMultivariateProbabilityTest", + "[DistributionTest]") { arma::vec mean = "2 5 3 7 2"; arma::vec cov("9 2 1 4 8"); @@ -1391,20 +1415,20 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianMultipointMultivariateProbabilityTest) DiagonalGaussianDistribution d(mean, cov); d.LogProbability(points, phis); - BOOST_REQUIRE_EQUAL(phis.n_elem, 6); + REQUIRE(phis.n_elem == 6); - BOOST_REQUIRE_CLOSE(phis(0), -12.453302051926864, 1e-5); - BOOST_REQUIRE_CLOSE(phis(1), -10.147746496371308, 1e-5); - BOOST_REQUIRE_CLOSE(phis(2), -13.210246496371308, 1e-5); - BOOST_REQUIRE_CLOSE(phis(3), -19.724135385260197, 1e-5); - BOOST_REQUIRE_CLOSE(phis(4), -21.585246496371308, 1e-5); - BOOST_REQUIRE_CLOSE(phis(5), -13.647746496371308, 1e-5); + REQUIRE(phis(0) == Approx(-12.453302051926864).epsilon(1e-7)); + REQUIRE(phis(1) == Approx(-10.147746496371308).epsilon(1e-7)); + REQUIRE(phis(2) == Approx(-13.210246496371308).epsilon(1e-7)); + REQUIRE(phis(3) == Approx(-19.724135385260197).epsilon(1e-7)); + REQUIRE(phis(4) == Approx(-21.585246496371308).epsilon(1e-7)); + REQUIRE(phis(5) == Approx(-13.647746496371308).epsilon(1e-7)); } /** * Make sure random observations follow the probability distribution correctly. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionRandomTest) +TEST_CASE("DiagonalGaussianDistributionRandomTest", "[DistributionTest]") { arma::vec mean("2.5 1.25"); arma::vec cov("0.50 0.25"); @@ -1421,17 +1445,17 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionRandomTest) arma::mat obsCov = mlpack::math::ColumnCovariance(obs); // 10% tolerance because this can be noisy. - BOOST_REQUIRE_CLOSE(obsMean(0), mean(0), 10.0); - BOOST_REQUIRE_CLOSE(obsMean(1), mean(1), 10.0); + REQUIRE(obsMean(0) == Approx(mean(0)).epsilon(0.1)); + REQUIRE(obsMean(1) == Approx(mean(1)).epsilon(0.1)); - BOOST_REQUIRE_CLOSE(obsCov(0, 0), cov(0), 10); - BOOST_REQUIRE_CLOSE(obsCov(1, 1), cov(1), 10); + REQUIRE(obsCov(0, 0) == Approx(cov(0)).epsilon(0.1)); + REQUIRE(obsCov(1, 1) == Approx(cov(1)).epsilon(0.1)); } /** * Make sure that we can properly estimate from given observations. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionTrainTest) +TEST_CASE("DiagonalGaussianDistributionTrainTest", "[DistributionTest]") { arma::vec mean("2.5 1.5 8.2 3.1"); arma::vec cov("1.2 3.1 8.3 4.3"); @@ -1454,8 +1478,8 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionTrainTest) // Check that the estimated parameters are right. for (size_t i = 0; i < 4; ++i) { - BOOST_REQUIRE_SMALL(d.Mean()(i) - actualMean(i), 1e-5); - BOOST_REQUIRE_SMALL(d.Covariance()(i) - actualCov(i, i), 1e-5); + REQUIRE(d.Mean()(i) - actualMean(i) == Approx(0.0).margin(1e-5)); + REQUIRE(d.Covariance()(i) - actualCov(i, i) == Approx(0.0).margin(1e-5)); } } @@ -1463,7 +1487,7 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianDistributionTrainTest) * Make sure the unbiased estimator of the weighted sample works correctly. * The values were calculated using 'cov.wt' in R. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianUnbiasedEstimatorTest) +TEST_CASE("DiagonalGaussianUnbiasedEstimatorTest", "[DistributionTest]") { // Generate the observations. arma::mat observations("3 5 2 7;" @@ -1478,15 +1502,15 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianUnbiasedEstimatorTest) // Estimate the parameters. d.Train(observations, probs); - BOOST_REQUIRE_CLOSE(d.Mean()(0), 4.5, 1e-5); - BOOST_REQUIRE_CLOSE(d.Mean()(1), 4.4, 1e-5); - BOOST_REQUIRE_CLOSE(d.Mean()(2), 3.5, 1e-5); - BOOST_REQUIRE_CLOSE(d.Mean()(3), 6.8, 1e-5); + REQUIRE(d.Mean()(0) == Approx(4.5).epsilon(1e-7)); + REQUIRE(d.Mean()(1) == Approx(4.4).epsilon(1e-7)); + REQUIRE(d.Mean()(2) == Approx(3.5).epsilon(1e-7)); + REQUIRE(d.Mean()(3) == Approx(6.8).epsilon(1e-7)); - BOOST_REQUIRE_CLOSE(d.Covariance()(0), 3.78571428571428603, 1e-5); - BOOST_REQUIRE_CLOSE(d.Covariance()(1), 6.34285714285714253, 1e-5); - BOOST_REQUIRE_CLOSE(d.Covariance()(2), 6.64285714285714235, 1e-5); - BOOST_REQUIRE_CLOSE(d.Covariance()(3), 2.22857142857142865, 1e-5); + REQUIRE(d.Covariance()(0) == Approx(3.78571428571428603).epsilon(1e-7)); + REQUIRE(d.Covariance()(1) == Approx(6.34285714285714253).epsilon(1e-7)); + REQUIRE(d.Covariance()(2) == Approx(6.64285714285714235).epsilon(1e-7)); + REQUIRE(d.Covariance()(3) == Approx(2.22857142857142865).epsilon(1e-7)); } /** @@ -1494,7 +1518,7 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianUnbiasedEstimatorTest) * the weighted mean and covariance reduce to the unweighted sample mean and * covariance. */ -BOOST_AUTO_TEST_CASE(DiagonalGaussianWeightedParametersReductionTest) +TEST_CASE("DiagonalGaussianWeightedParametersReductionTest", "[DistributionTest]") { arma::vec mean("2.5 1.5 8.2 3.1"); arma::vec cov("1.2 3.1 8.3 4.3"); @@ -1516,9 +1540,7 @@ BOOST_AUTO_TEST_CASE(DiagonalGaussianWeightedParametersReductionTest) // Check if these are equal. for (size_t i = 0; i < 4; ++i) { - BOOST_REQUIRE_CLOSE(d1.Mean()(i), d2.Mean()(i), 1e-5); - BOOST_REQUIRE_CLOSE(d1.Covariance()(i), d2.Covariance()(i), 1e-5); + REQUIRE(d1.Mean()(i) == Approx(d2.Mean()(i)).epsilon(1e-7)); + REQUIRE(d1.Covariance()(i) == Approx(d2.Covariance()(i)).epsilon(1e-7)); } } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/feedforward_network_test.cpp b/src/mlpack/tests/feedforward_network_test.cpp index ba45afd29d..bcffa4c8a8 100644 --- a/src/mlpack/tests/feedforward_network_test.cpp +++ b/src/mlpack/tests/feedforward_network_test.cpp @@ -148,10 +148,10 @@ TEST_CASE("CheckCopyMovingVanillaNetworkTest", "[FeedForwardNetworkTest]") model1->Add >(8, 3); model1->Add >(); - // Check whether copy cpnstructor is working or not. + // Check whether copy constructor is working or not. CheckCopyFunction<>(model, trainData, trainLabels, 1); - // Check whether move cpnstructor is working or not. + // Check whether move constructor is working or not. CheckMoveFunction<>(model1, trainData, trainLabels, 1); } @@ -489,7 +489,7 @@ TEST_CASE("FFNMiscTest", "[FeedForwardNetworkTest]") auto copiedModel(model); copiedModel = model; auto movedModel(std::move(model)); - movedModel = std::move(copiedModel); + auto moveOperator = std::move(copiedModel); } /** @@ -764,7 +764,7 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") model.Add >(8, 3); // RBFN neural net with MeanSquaredError. - TestNetwork<>(model, trainData, trainLabels1, testData, testLabels, 10, 0.1); + TestNetwork<>(model, trainData, trainLabels1, testData, testLabels, 10, 0.2); arma::mat dataset; dataset.load("mnist_first250_training_4s_and_9s.arm"); @@ -796,5 +796,5 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") model1.Add >(140, 2); // RBFN neural net with MeanSquaredError. - TestNetwork<>(model1, dataset, labels1, dataset, labels, 10, 0.1); + TestNetwork<>(model1, dataset, labels1, dataset, labels, 10, 0.2); } diff --git a/src/mlpack/tests/main_tests/mean_shift_test.cpp b/src/mlpack/tests/main_tests/mean_shift_test.cpp index eea3ceb3c7..5da1c28b95 100644 --- a/src/mlpack/tests/main_tests/mean_shift_test.cpp +++ b/src/mlpack/tests/main_tests/mean_shift_test.cpp @@ -12,15 +12,16 @@ #include #define BINDING_TYPE BINDING_TYPE_TEST -static const std::string testName = "MeanShift"; #include +static const std::string testName = "MeanShift"; + #include #include -#include "test_helper.hpp" -#include -#include "../test_tools.hpp" +#include "test_helper.hpp" +#include "../test_catch_tools.hpp" +#include "../catch.hpp" using namespace mlpack; @@ -48,13 +49,13 @@ static void ResetSettings() IO::RestoreSettings(testName); } -BOOST_FIXTURE_TEST_SUITE(MeanShiftMainTest, MeanShiftTestFixture); - /** * Ensure that the output has 1 extra row for the labels and * check the number of points for output remain the same. */ -BOOST_AUTO_TEST_CASE(MeanShiftOutputDimensionTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftOutputDimensionTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; x.randu(3, 100); // 100 points in 3 dimension @@ -65,16 +66,18 @@ BOOST_AUTO_TEST_CASE(MeanShiftOutputDimensionTest) mlpackMain(); // Now check that the output has 1 extra row for labels. - BOOST_REQUIRE_EQUAL(IO::GetParam("output").n_rows, 3 + 1); + REQUIRE(IO::GetParam("output").n_rows == 3 + 1); // Check number of output points are the same. - BOOST_REQUIRE_EQUAL(IO::GetParam("output").n_cols, 100); + REQUIRE(IO::GetParam("output").n_cols == 100); } /** * Ensure that if we ask for labels_only, output has 1 row and * same number of columns for each point's label. */ -BOOST_AUTO_TEST_CASE(MeanShiftLabelOnlyOutputDimensionTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftLabelOnlyOutputDimensionTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; x.randu(3, 100); // 100 points in 3 dimension @@ -86,9 +89,9 @@ BOOST_AUTO_TEST_CASE(MeanShiftLabelOnlyOutputDimensionTest) mlpackMain(); // Check that there is only 1 row containing all the labels. - BOOST_REQUIRE_EQUAL(IO::GetParam("output").n_rows, 1); + REQUIRE(IO::GetParam("output").n_rows == 1); // Check number of output points are the same. - BOOST_REQUIRE_EQUAL(IO::GetParam("output").n_cols, 100); + REQUIRE(IO::GetParam("output").n_cols == 100); } /** @@ -96,11 +99,13 @@ BOOST_AUTO_TEST_CASE(MeanShiftLabelOnlyOutputDimensionTest) * and check the number of points remain the same if the --in_place * flag is set. */ -BOOST_AUTO_TEST_CASE(MeanShiftInPlaceTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftInPlaceTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; if (!data::Load("iris_test.csv", x)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + FAIL("Cannot load test dataset iris_test.csv!"); // Get initial number of rows and columns in file. int numRows = x.n_rows; @@ -113,20 +118,22 @@ BOOST_AUTO_TEST_CASE(MeanShiftInPlaceTest) mlpackMain(); // Now check that the output has 1 extra row for labels. - BOOST_REQUIRE_EQUAL(IO::GetParam("output").n_rows, numRows + 1); + REQUIRE(IO::GetParam("output").n_rows == numRows + 1); // Check number of output points are the same. - BOOST_REQUIRE_EQUAL(IO::GetParam("output").n_cols, numCols); + REQUIRE(IO::GetParam("output").n_cols == numCols); } /** * Ensure that force_convergence is used by testing that the * force_convergence flag makes a difference in the program. */ -BOOST_AUTO_TEST_CASE(MeanShiftForceConvergenceTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftForceConvergenceTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; if (!data::Load("iris_test.csv", x)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + FAIL("Cannot load test dataset iris_test.csv!"); // Input random data points. SetInputParam("input", x); @@ -150,18 +157,20 @@ BOOST_AUTO_TEST_CASE(MeanShiftForceConvergenceTest) const int numCentroids2 = IO::GetParam("centroid").n_cols; // Resulting number of centroids should be different. - BOOST_REQUIRE_NE(numCentroids1, numCentroids2); + REQUIRE(numCentroids1 != numCentroids2); } /** * Ensure that radius is used by testing that the radius * makes a difference in the program. */ -BOOST_AUTO_TEST_CASE(MeanShiftRadiusTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftRadiusTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; if (!data::Load("iris_test.csv", x)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + FAIL("Cannot load test dataset iris_test.csv!"); // Input random data points. SetInputParam("input", x); @@ -183,18 +192,20 @@ BOOST_AUTO_TEST_CASE(MeanShiftRadiusTest) const int numCentroids2 = IO::GetParam("centroid").n_cols; // Resulting number of centroids should be different. - BOOST_REQUIRE_NE(numCentroids1, numCentroids2); + REQUIRE(numCentroids1 != numCentroids2); } /** * Ensure that max_iterations is used by testing that the * max_iteration makes a difference in the program. */ -BOOST_AUTO_TEST_CASE(MeanShiftMaxIterationsTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftMaxIterationsTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; if (!data::Load("iris_test.csv", x)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + FAIL("Cannot load test dataset iris_test.csv!"); // Input random data points. SetInputParam("input", x); @@ -216,13 +227,15 @@ BOOST_AUTO_TEST_CASE(MeanShiftMaxIterationsTest) const int numCentroids2 = IO::GetParam("centroid").n_cols; // Resulting number of centroids should be different. - BOOST_REQUIRE_NE(numCentroids1, numCentroids2); + REQUIRE(numCentroids1 != numCentroids2); } /** * Ensure that we can't specify an invalid max number of iterations. */ -BOOST_AUTO_TEST_CASE(MeanShiftInvalidMaxIterationsTest) +TEST_CASE_METHOD( + MeanShiftTestFixture, "MeanShiftInvalidMaxIterationsTest", + "[MeanShiftMainTest][BindingTests]") { arma::mat x; x.randu(3, 100); // 100 points in 3 dimension @@ -233,8 +246,6 @@ BOOST_AUTO_TEST_CASE(MeanShiftInvalidMaxIterationsTest) SetInputParam("max_iterations", (int) -1); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/mean_shift_test.cpp b/src/mlpack/tests/mean_shift_test.cpp index 818602f632..9f6c229639 100644 --- a/src/mlpack/tests/mean_shift_test.cpp +++ b/src/mlpack/tests/mean_shift_test.cpp @@ -12,15 +12,13 @@ #include -#include -#include "test_tools.hpp" +#include "test_catch_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::meanshift; using namespace mlpack::distribution; -BOOST_AUTO_TEST_SUITE(MeanShiftTest); - // Generate dataset; written transposed because it's easier to read. arma::mat meanShiftData(" 0.0 0.0;" // Class 1. " 0.3 0.4;" @@ -57,7 +55,7 @@ arma::mat meanShiftData(" 0.0 0.0;" // Class 1. /** * 30-point 3-class test case for Mean Shift. */ -BOOST_AUTO_TEST_CASE(MeanShiftSimpleTest) +TEST_CASE("MeanShiftSimpleTest", "[MeanShiftTest]") { MeanShift<> meanShift; @@ -70,29 +68,29 @@ BOOST_AUTO_TEST_CASE(MeanShiftSimpleTest) size_t firstClass = assignments(0); for (size_t i = 1; i < 13; ++i) - BOOST_REQUIRE_EQUAL(assignments(i), firstClass); + REQUIRE(assignments(i) == firstClass); size_t secondClass = assignments(13); // To ensure that class 1 != class 2. - BOOST_REQUIRE_NE(firstClass, secondClass); + REQUIRE(firstClass != secondClass); for (size_t i = 13; i < 20; ++i) - BOOST_REQUIRE_EQUAL(assignments(i), secondClass); + REQUIRE(assignments(i) == secondClass); size_t thirdClass = assignments(20); // To ensure that this is the third class which we haven't seen yet. - BOOST_REQUIRE_NE(firstClass, thirdClass); - BOOST_REQUIRE_NE(secondClass, thirdClass); + REQUIRE(firstClass != thirdClass); + REQUIRE(secondClass != thirdClass); for (size_t i = 20; i < 30; ++i) - BOOST_REQUIRE_EQUAL(assignments(i), thirdClass); + REQUIRE(assignments(i) == thirdClass); } // Generate samples from four Gaussians, and make sure mean shift nearly // recovers those four centers. -BOOST_AUTO_TEST_CASE(GaussianClustering) +TEST_CASE("GaussianClustering", "[MeanShiftTest]") { GaussianDistribution g1("0.0 0.0 0.0", arma::eye(3, 3)); GaussianDistribution g2("5.0 5.0 5.0", 2 * arma::eye(3, 3)); @@ -162,7 +160,5 @@ BOOST_AUTO_TEST_CASE(GaussianClustering) break; } - BOOST_REQUIRE_EQUAL(success, true); + REQUIRE(success == true); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/random_forest_test.cpp b/src/mlpack/tests/random_forest_test.cpp index edc6bb2b60..3db62942c3 100644 --- a/src/mlpack/tests/random_forest_test.cpp +++ b/src/mlpack/tests/random_forest_test.cpp @@ -13,8 +13,9 @@ #include #include +#include "serialization_catch.hpp" +#include "test_catch_tools.hpp" #include "catch.hpp" -#include "serialization.hpp" #include "mock_categorical_data.hpp" using namespace mlpack;