From f3d8b7d8a2dc9901a6c0070a7a027e4e86186c47 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 21 Sep 2019 12:13:54 +0200 Subject: [PATCH 001/297] Add bayesian Ridge regression --- src/mlpack/methods/CMakeLists.txt | 1 + .../CMakeDirectoryInformation.cmake | 16 + .../DependInfo.cmake | 33 + .../cmake_clean.cmake | 12 + .../depend.make | 2 + .../flags.make | 10 + .../generate_pyx_bayesian_ridge.dir/link.txt | 1 + .../progress.make | 5 + .../CXX.includecache | 1186 +++++++++++++++++ .../DependInfo.cmake | 32 + .../bayesian_ridge_main.cpp.o | Bin 0 -> 955104 bytes .../cmake_clean.cmake | 10 + .../mlpack_bayesian_ridge.dir/depend.internal | 146 ++ .../mlpack_bayesian_ridge.dir/depend.make | 146 ++ .../mlpack_bayesian_ridge.dir/flags.make | 10 + .../mlpack_bayesian_ridge.dir/link.txt | 1 + .../mlpack_bayesian_ridge.dir/progress.make | 3 + .../bayesian_ridge/CMakeFiles/progress.marks | 1 + .../methods/bayesian_ridge/CMakeLists.txt | 19 + .../bayesian_ridge/CTestTestfile.cmake | 6 + src/mlpack/methods/bayesian_ridge/Makefile | 334 +++++ .../methods/bayesian_ridge/bayesian_ridge.cpp | 302 +++++ .../methods/bayesian_ridge/bayesian_ridge.hpp | 251 ++++ .../bayesian_ridge/bayesian_ridge_impl.hpp | 42 + .../bayesian_ridge/bayesian_ridge_main.cpp | 177 +++ .../bayesian_ridge/cmake_install.cmake | 59 + src/mlpack/methods/bayesian_ridge/utils.cpp | 51 + src/mlpack/methods/bayesian_ridge/utils.hpp | 42 + src/mlpack/tests/CMakeLists.txt | 1 + src/mlpack/tests/bayesian_ridge_test.cpp | 131 ++ 30 files changed, 3030 insertions(+) create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/cmake_clean.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/depend.internal create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/depend.make create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/flags.make create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/link.txt create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/progress.make create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/progress.marks create mode 100644 src/mlpack/methods/bayesian_ridge/CMakeLists.txt create mode 100644 src/mlpack/methods/bayesian_ridge/CTestTestfile.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/Makefile create mode 100644 src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp create mode 100644 src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp create mode 100644 src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp create mode 100644 src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp create mode 100644 src/mlpack/methods/bayesian_ridge/cmake_install.cmake create mode 100644 src/mlpack/methods/bayesian_ridge/utils.cpp create mode 100644 src/mlpack/methods/bayesian_ridge/utils.hpp create mode 100644 src/mlpack/tests/bayesian_ridge_test.cpp diff --git a/src/mlpack/methods/CMakeLists.txt b/src/mlpack/methods/CMakeLists.txt index 83c96e68dd..21822cafb8 100644 --- a/src/mlpack/methods/CMakeLists.txt +++ b/src/mlpack/methods/CMakeLists.txt @@ -6,6 +6,7 @@ set(DIRS ann approx_kfn bias_svd + bayesian_ridge block_krylov_svd cf dbscan diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000000..a6dbbd7d85 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.10 + +# Relative path conversion top directories. +set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/cmercier/Documents/c++/mlpack-3.1.1") +set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/cmercier/Documents/c++/mlpack-3.1.1") + +# Force unix paths in dependencies. +set(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake new file mode 100644 index 0000000000..5b7578e156 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake @@ -0,0 +1,33 @@ +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +set(CMAKE_DEPENDS_CHECK_CXX + "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/bindings/python/generate_pyx_bayesian_ridge.cpp" "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/generate_pyx_bayesian_ridge.cpp.o" + "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/bindings/python/print_pyx.cpp" "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/print_pyx.cpp.o" + ) +set(CMAKE_CXX_COMPILER_ID "GNU") + +# Preprocessor definitions for this target. +set(CMAKE_TARGET_DEFINITIONS_CXX + "ARMA_NO_DEBUG" + "BOOST_TEST_DYN_LINK" + "HAS_OPENMP" + "NDEBUG" + ) + +# The include file search paths: +set(CMAKE_CXX_TARGET_INCLUDE_PATH + "src" + "deps/ensmallen-1.16.2/include" + "src/mlpack/.." + ) + +# Targets to which this target links. +set(CMAKE_TARGET_LINKED_INFO_FILES + "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/CMakeFiles/mlpack.dir/DependInfo.cmake" + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake new file mode 100644 index 0000000000..527d4dc9a3 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake @@ -0,0 +1,12 @@ +file(REMOVE_RECURSE + "../../bindings/python/generate_pyx_bayesian_ridge.cpp" + "CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/generate_pyx_bayesian_ridge.cpp.o" + "CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/print_pyx.cpp.o" + "../../../../bin/generate_pyx_bayesian_ridge.pdb" + "../../../../bin/generate_pyx_bayesian_ridge" +) + +# Per-language clean rules from dependency scanning. +foreach(lang CXX) + include(CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make new file mode 100644 index 0000000000..058a3ed7a2 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make @@ -0,0 +1,2 @@ +# Empty dependencies file for generate_pyx_bayesian_ridge. +# This may be replaced when dependencies are built. diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make new file mode 100644 index 0000000000..17a2bd481b --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make @@ -0,0 +1,10 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.10 + +# compile CXX with /usr/bin/c++ +CXX_FLAGS = -Wall -Wextra -ftemplate-depth=1000 -O3 -fopenmp -DBINDING_TYPE=BINDING_TYPE_PYX -std=gnu++11 + +CXX_DEFINES = -DARMA_NO_DEBUG -DBOOST_TEST_DYN_LINK -DHAS_OPENMP -DNDEBUG + +CXX_INCLUDES = -I/home/cmercier/Documents/c++/mlpack-3.1.1/src -I/home/cmercier/Documents/c++/mlpack-3.1.1/deps/ensmallen-1.16.2/include -I/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/.. + diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt new file mode 100644 index 0000000000..918b8bbd23 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt @@ -0,0 +1 @@ +/usr/bin/c++ -Wall -Wextra -ftemplate-depth=1000 -O3 -fopenmp -rdynamic CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/generate_pyx_bayesian_ridge.cpp.o CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/print_pyx.cpp.o -o ../../../../bin/generate_pyx_bayesian_ridge -Wl,-rpath,/home/cmercier/Documents/c++/mlpack-3.1.1/lib ../../../../lib/libmlpack.so.3.1 /usr/lib/libarmadillo.so /usr/lib/x86_64-linux-gnu/libboost_program_options.so /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so /usr/lib/x86_64-linux-gnu/libboost_serialization.so diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make new file mode 100644 index 0000000000..3962a19c46 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make @@ -0,0 +1,5 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = 11 + diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache new file mode 100644 index 0000000000..08004f3324 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache @@ -0,0 +1,1186 @@ +#IncludeRegexLine: ^[ ]*[#%][ ]*(include|import)[ ]*[<"]([^">]+)([">]) + +#IncludeRegexScan: ^.*$ + +#IncludeRegexComplain: ^$ + +#IncludeRegexTransform: + +/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +mlpack/prereqs.hpp +- +bayesian_ridge_impl.hpp +/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp + +/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp +bayesian_ridge.hpp +/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp + +/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +mlpack/prereqs.hpp +- +mlpack/core/util/cli.hpp +- +mlpack/core/util/mlpack_main.hpp +- +bayesian_ridge.hpp +/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp + +src/mlpack/bindings/cli/add_to_po.hpp +mlpack/core/util/param_data.hpp +- +boost/program_options.hpp +- +mlpack/core/util/is_std_vector.hpp +- +map_parameter_name.hpp +src/mlpack/bindings/cli/map_parameter_name.hpp + +src/mlpack/bindings/cli/cli_option.hpp +string +- +mlpack/core/util/cli.hpp +- +parameter_type.hpp +src/mlpack/bindings/cli/parameter_type.hpp +add_to_po.hpp +src/mlpack/bindings/cli/add_to_po.hpp +default_param.hpp +src/mlpack/bindings/cli/default_param.hpp +output_param.hpp +src/mlpack/bindings/cli/output_param.hpp +get_printable_param.hpp +src/mlpack/bindings/cli/get_printable_param.hpp +string_type_param.hpp +src/mlpack/bindings/cli/string_type_param.hpp +get_param.hpp +src/mlpack/bindings/cli/get_param.hpp +get_raw_param.hpp +src/mlpack/bindings/cli/get_raw_param.hpp +map_parameter_name.hpp +src/mlpack/bindings/cli/map_parameter_name.hpp +set_param.hpp +src/mlpack/bindings/cli/set_param.hpp +get_printable_param_name.hpp +src/mlpack/bindings/cli/get_printable_param_name.hpp +get_printable_param_value.hpp +src/mlpack/bindings/cli/get_printable_param_value.hpp +get_allocated_memory.hpp +src/mlpack/bindings/cli/get_allocated_memory.hpp +delete_allocated_memory.hpp +src/mlpack/bindings/cli/delete_allocated_memory.hpp + +src/mlpack/bindings/cli/default_param.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- +mlpack/core/util/is_std_vector.hpp +- +default_param_impl.hpp +src/mlpack/bindings/cli/default_param_impl.hpp + +src/mlpack/bindings/cli/default_param_impl.hpp +default_param.hpp +src/mlpack/bindings/cli/default_param.hpp + +src/mlpack/bindings/cli/delete_allocated_memory.hpp +mlpack/core/util/param_data.hpp +- + +src/mlpack/bindings/cli/end_program.hpp +mlpack/core/util/cli.hpp +- + +src/mlpack/bindings/cli/get_allocated_memory.hpp +mlpack/core/util/param_data.hpp +- + +src/mlpack/bindings/cli/get_param.hpp +mlpack/prereqs.hpp +- +parameter_type.hpp +src/mlpack/bindings/cli/parameter_type.hpp + +src/mlpack/bindings/cli/get_printable_param.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- +mlpack/core/util/is_std_vector.hpp +- +get_printable_param_impl.hpp +src/mlpack/bindings/cli/get_printable_param_impl.hpp + +src/mlpack/bindings/cli/get_printable_param_impl.hpp +get_printable_param.hpp +src/mlpack/bindings/cli/get_printable_param.hpp + +src/mlpack/bindings/cli/get_printable_param_name.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- +get_printable_param_name_impl.hpp +src/mlpack/bindings/cli/get_printable_param_name_impl.hpp + +src/mlpack/bindings/cli/get_printable_param_name_impl.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- + +src/mlpack/bindings/cli/get_printable_param_value.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- +get_printable_param_value_impl.hpp +src/mlpack/bindings/cli/get_printable_param_value_impl.hpp + +src/mlpack/bindings/cli/get_printable_param_value_impl.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- + +src/mlpack/bindings/cli/get_printable_type.hpp +get_printable_type_impl.hpp +src/mlpack/bindings/cli/get_printable_type_impl.hpp + +src/mlpack/bindings/cli/get_printable_type_impl.hpp +get_printable_type.hpp +src/mlpack/bindings/cli/get_printable_type.hpp + +src/mlpack/bindings/cli/get_raw_param.hpp +mlpack/prereqs.hpp +- +parameter_type.hpp +src/mlpack/bindings/cli/parameter_type.hpp + +src/mlpack/bindings/cli/map_parameter_name.hpp +mlpack/core/util/param_data.hpp +- + +src/mlpack/bindings/cli/output_param.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- +mlpack/core/util/is_std_vector.hpp +- +output_param_impl.hpp +src/mlpack/bindings/cli/output_param_impl.hpp + +src/mlpack/bindings/cli/output_param_impl.hpp +output_param.hpp +src/mlpack/bindings/cli/output_param.hpp +mlpack/core/data/save.hpp +- +iostream +- + +src/mlpack/bindings/cli/parameter_type.hpp +mlpack/prereqs.hpp +- + +src/mlpack/bindings/cli/parse_command_line.hpp +mlpack/core.hpp +- +boost/program_options.hpp +- +print_help.hpp +src/mlpack/bindings/cli/print_help.hpp + +src/mlpack/bindings/cli/print_doc_functions.hpp +mlpack/core/util/hyphenate_string.hpp +- +print_doc_functions_impl.hpp +src/mlpack/bindings/cli/print_doc_functions_impl.hpp + +src/mlpack/bindings/cli/print_doc_functions_impl.hpp +mlpack/core/util/hyphenate_string.hpp +- + +src/mlpack/bindings/cli/print_help.hpp +mlpack/core.hpp +- + +src/mlpack/bindings/cli/set_param.hpp +mlpack/prereqs.hpp +- +parameter_type.hpp +src/mlpack/bindings/cli/parameter_type.hpp + +src/mlpack/bindings/cli/string_type_param.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/param_data.hpp +- +mlpack/core/util/is_std_vector.hpp +- +string_type_param_impl.hpp +src/mlpack/bindings/cli/string_type_param_impl.hpp + +src/mlpack/bindings/cli/string_type_param_impl.hpp +string_type_param.hpp +src/mlpack/bindings/cli/string_type_param.hpp + +src/mlpack/bindings/markdown/binding_info.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/program_doc.hpp +- + +src/mlpack/bindings/markdown/get_printable_type.hpp +binding_info.hpp +src/mlpack/bindings/markdown/binding_info.hpp +mlpack/bindings/cli/get_printable_type.hpp +- +mlpack/bindings/python/get_printable_type.hpp +- + +src/mlpack/bindings/markdown/is_serializable.hpp +mlpack/prereqs.hpp +- + +src/mlpack/bindings/markdown/md_option.hpp +mlpack/core/util/param_data.hpp +- +mlpack/core/util/cli.hpp +- +default_param.hpp +src/mlpack/bindings/markdown/default_param.hpp +get_param.hpp +src/mlpack/bindings/markdown/get_param.hpp +get_printable_param.hpp +src/mlpack/bindings/markdown/get_printable_param.hpp +get_printable_param_name.hpp +src/mlpack/bindings/markdown/get_printable_param_name.hpp +get_printable_param_value.hpp +src/mlpack/bindings/markdown/get_printable_param_value.hpp +get_printable_type.hpp +src/mlpack/bindings/markdown/get_printable_type.hpp +is_serializable.hpp +src/mlpack/bindings/markdown/is_serializable.hpp + +src/mlpack/bindings/markdown/print_doc_functions.hpp +mlpack/prereqs.hpp +- +print_doc_functions_impl.hpp +src/mlpack/bindings/markdown/print_doc_functions_impl.hpp + +src/mlpack/bindings/markdown/program_doc_wrapper.hpp +binding_info.hpp +src/mlpack/bindings/markdown/binding_info.hpp + +src/mlpack/bindings/python/get_arma_type.hpp +mlpack/prereqs.hpp +- + +src/mlpack/bindings/python/get_cython_type.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/is_std_vector.hpp +- + +src/mlpack/bindings/python/get_numpy_type.hpp +mlpack/prereqs.hpp +- + +src/mlpack/bindings/python/get_numpy_type_char.hpp +mlpack/prereqs.hpp +- + +src/mlpack/bindings/python/get_printable_type.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/is_std_vector.hpp +- +get_printable_type_impl.hpp +src/mlpack/bindings/python/get_printable_type_impl.hpp + +src/mlpack/bindings/python/import_decl.hpp +mlpack/prereqs.hpp +- +strip_type.hpp +src/mlpack/bindings/python/strip_type.hpp + +src/mlpack/bindings/python/print_class_defn.hpp +strip_type.hpp +src/mlpack/bindings/python/strip_type.hpp + +src/mlpack/bindings/python/print_defn.hpp +mlpack/prereqs.hpp +- + +src/mlpack/bindings/python/print_doc.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/hyphenate_string.hpp +- +get_printable_type.hpp +src/mlpack/bindings/python/get_printable_type.hpp + +src/mlpack/bindings/python/print_doc_functions.hpp +mlpack/core/util/hyphenate_string.hpp +- +print_doc_functions_impl.hpp +src/mlpack/bindings/python/print_doc_functions_impl.hpp + +src/mlpack/bindings/python/print_input_processing.hpp +mlpack/prereqs.hpp +- +get_arma_type.hpp +src/mlpack/bindings/python/get_arma_type.hpp +get_numpy_type.hpp +src/mlpack/bindings/python/get_numpy_type.hpp +get_numpy_type_char.hpp +src/mlpack/bindings/python/get_numpy_type_char.hpp +get_cython_type.hpp +src/mlpack/bindings/python/get_cython_type.hpp +strip_type.hpp +src/mlpack/bindings/python/strip_type.hpp + +src/mlpack/bindings/python/print_output_processing.hpp +mlpack/prereqs.hpp +- +get_arma_type.hpp +src/mlpack/bindings/python/get_arma_type.hpp +get_numpy_type_char.hpp +src/mlpack/bindings/python/get_numpy_type_char.hpp +get_cython_type.hpp +src/mlpack/bindings/python/get_cython_type.hpp + +src/mlpack/bindings/python/py_option.hpp +mlpack/core/util/param_data.hpp +- +default_param.hpp +src/mlpack/bindings/python/default_param.hpp +get_param.hpp +src/mlpack/bindings/python/get_param.hpp +get_printable_param.hpp +src/mlpack/bindings/python/get_printable_param.hpp +print_class_defn.hpp +src/mlpack/bindings/python/print_class_defn.hpp +print_defn.hpp +src/mlpack/bindings/python/print_defn.hpp +print_doc.hpp +src/mlpack/bindings/python/print_doc.hpp +print_input_processing.hpp +src/mlpack/bindings/python/print_input_processing.hpp +print_output_processing.hpp +src/mlpack/bindings/python/print_output_processing.hpp +import_decl.hpp +src/mlpack/bindings/python/import_decl.hpp + +src/mlpack/bindings/python/strip_type.hpp + +src/mlpack/bindings/tests/clean_memory.hpp + +src/mlpack/bindings/tests/ignore_check.hpp + +src/mlpack/bindings/tests/test_option.hpp +string +- +mlpack/core/util/cli.hpp +- +get_printable_param.hpp +src/mlpack/bindings/tests/get_printable_param.hpp +get_param.hpp +src/mlpack/bindings/tests/get_param.hpp +get_allocated_memory.hpp +src/mlpack/bindings/tests/get_allocated_memory.hpp +delete_allocated_memory.hpp +src/mlpack/bindings/tests/delete_allocated_memory.hpp + +src/mlpack/core.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/arma_traits.hpp +- +mlpack/core/util/log.hpp +- +mlpack/core/util/cli.hpp +- +mlpack/core/util/deprecated.hpp +- +mlpack/core/data/load.hpp +- +mlpack/core/data/save.hpp +- +mlpack/core/data/normalize_labels.hpp +- +mlpack/core/math/clamp.hpp +- +mlpack/core/math/random.hpp +- +mlpack/core/math/random_basis.hpp +- +mlpack/core/math/lin_alg.hpp +- +mlpack/core/math/range.hpp +- +mlpack/core/math/round.hpp +- +mlpack/core/math/shuffle_data.hpp +- +mlpack/core/math/ccov.hpp +- +mlpack/core/math/make_alias.hpp +- +mlpack/core/dists/discrete_distribution.hpp +- +mlpack/core/dists/gaussian_distribution.hpp +- +mlpack/core/dists/laplace_distribution.hpp +- +mlpack/core/dists/gamma_distribution.hpp +- +mlpack/core/dists/diagonal_gaussian_distribution.hpp +- +mlpack/core/data/confusion_matrix.hpp +- +mlpack/core/data/one_hot_encoding.hpp +- +mlpack/core/util/backtrace.hpp +- +mlpack/core/kernels/kernel_traits.hpp +- +mlpack/core/kernels/linear_kernel.hpp +- +mlpack/core/kernels/polynomial_kernel.hpp +- +mlpack/core/kernels/cosine_distance.hpp +- +mlpack/core/kernels/gaussian_kernel.hpp +- +mlpack/core/kernels/epanechnikov_kernel.hpp +- +mlpack/core/kernels/hyperbolic_tangent_kernel.hpp +- +mlpack/core/kernels/laplacian_kernel.hpp +- +mlpack/core/kernels/pspectrum_string_kernel.hpp +- +mlpack/core/kernels/spherical_kernel.hpp +- +mlpack/core/kernels/triangular_kernel.hpp +- +mlpack/core/kernels/cauchy_kernel.hpp +- +omp.h +- + +src/mlpack/core/arma_extend/arma_extend.hpp +boost/serialization/serialization.hpp +- +boost/serialization/nvp.hpp +- +boost/serialization/array.hpp +- +armadillo +- +hdf5_misc.hpp +src/mlpack/core/arma_extend/hdf5_misc.hpp +fn_inplace_reshape.hpp +src/mlpack/core/arma_extend/fn_inplace_reshape.hpp + +src/mlpack/core/arma_extend/fn_inplace_reshape.hpp + +src/mlpack/core/arma_extend/hdf5_misc.hpp + +src/mlpack/core/boost_backport/boost_backport_serialization.hpp +boost/version.hpp +- +mlpack/core/boost_backport/unordered_map.hpp +src/mlpack/core/boost_backport/mlpack/core/boost_backport/unordered_map.hpp +boost/serialization/unordered_map.hpp +- +mlpack/core/boost_backport/collections_load_imp.hpp +src/mlpack/core/boost_backport/mlpack/core/boost_backport/collections_load_imp.hpp +mlpack/core/boost_backport/collections_save_imp.hpp +src/mlpack/core/boost_backport/mlpack/core/boost_backport/collections_save_imp.hpp +mlpack/core/boost_backport/vector.hpp +src/mlpack/core/boost_backport/mlpack/core/boost_backport/vector.hpp +boost/serialization/vector.hpp +- + +src/mlpack/core/boost_backport/collections_load_imp.hpp +boost/assert.hpp +- +cstddef +- +boost/config.hpp +- +boost/detail/workaround.hpp +- +boost/archive/detail/basic_iarchive.hpp +- +boost/serialization/access.hpp +- +boost/serialization/nvp.hpp +- +boost/serialization/detail/stack_constructor.hpp +- +boost/serialization/collection_size_type.hpp +- +boost/serialization/item_version_type.hpp +- +boost/serialization/detail/is_default_constructible.hpp +- +boost/utility/enable_if.hpp +- + +src/mlpack/core/boost_backport/collections_save_imp.hpp +boost/config.hpp +- +boost/serialization/nvp.hpp +- +boost/serialization/serialization.hpp +- +boost/serialization/version.hpp +- +boost/serialization/collection_size_type.hpp +- +boost/serialization/item_version_type.hpp +- + +src/mlpack/core/boost_backport/unordered_collections_load_imp.hpp +boost/assert.hpp +- +cstddef +- +boost/config.hpp +- +boost/detail/workaround.hpp +- +boost/archive/detail/basic_iarchive.hpp +- +boost/serialization/access.hpp +- +boost/serialization/nvp.hpp +- +boost/serialization/detail/stack_constructor.hpp +- +boost/serialization/collection_size_type.hpp +- +boost/serialization/item_version_type.hpp +- + +src/mlpack/core/boost_backport/unordered_collections_save_imp.hpp +boost/config.hpp +- +boost/serialization/nvp.hpp +- +boost/serialization/serialization.hpp +- +boost/serialization/version.hpp +- +boost/serialization/collection_size_type.hpp +- +boost/serialization/item_version_type.hpp +- + +src/mlpack/core/boost_backport/unordered_map.hpp +boost/config.hpp +- +unordered_map +- +boost/serialization/utility.hpp +- +unordered_collections_save_imp.hpp +src/mlpack/core/boost_backport/unordered_collections_save_imp.hpp +unordered_collections_load_imp.hpp +src/mlpack/core/boost_backport/unordered_collections_load_imp.hpp +boost/serialization/split_free.hpp +- + +src/mlpack/core/boost_backport/vector.hpp +vector +- +boost/config.hpp +- +boost/detail/workaround.hpp +- +boost/archive/detail/basic_iarchive.hpp +- +boost/serialization/access.hpp +- +boost/serialization/nvp.hpp +- +boost/serialization/collection_size_type.hpp +- +boost/serialization/item_version_type.hpp +- +boost/serialization/collections_save_imp.hpp +- +boost/serialization/collections_load_imp.hpp +- +boost/serialization/split_free.hpp +- +boost/serialization/array.hpp +- +boost/serialization/detail/get_data.hpp +- +boost/serialization/detail/stack_constructor.hpp +- +boost/mpl/bool_fwd.hpp +- +boost/mpl/if.hpp +- +boost/serialization/collection_traits.hpp +- + +src/mlpack/core/data/confusion_matrix.hpp +mlpack/prereqs.hpp +- +confusion_matrix_impl.hpp +src/mlpack/core/data/confusion_matrix_impl.hpp + +src/mlpack/core/data/confusion_matrix_impl.hpp +confusion_matrix.hpp +src/mlpack/core/data/confusion_matrix.hpp + +src/mlpack/core/data/dataset_mapper.hpp +mlpack/prereqs.hpp +- +unordered_map +- +map_policies/increment_policy.hpp +src/mlpack/core/data/map_policies/increment_policy.hpp +dataset_mapper_impl.hpp +src/mlpack/core/data/dataset_mapper_impl.hpp + +src/mlpack/core/data/dataset_mapper_impl.hpp +dataset_mapper.hpp +src/mlpack/core/data/dataset_mapper.hpp + +src/mlpack/core/data/extension.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/data/format.hpp + +src/mlpack/core/data/has_serialize.hpp +mlpack/core/util/sfinae_utility.hpp +- +boost/serialization/serialization.hpp +- +boost/archive/xml_oarchive.hpp +- +type_traits +- + +src/mlpack/core/data/load.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/log.hpp +- +string +- +format.hpp +src/mlpack/core/data/format.hpp +dataset_mapper.hpp +src/mlpack/core/data/dataset_mapper.hpp +load_model_impl.hpp +src/mlpack/core/data/load_model_impl.hpp +load_vec_impl.hpp +src/mlpack/core/data/load_vec_impl.hpp + +src/mlpack/core/data/load_model_impl.hpp +load.hpp +src/mlpack/core/data/load.hpp +algorithm +- +mlpack/core/util/timers.hpp +- +extension.hpp +src/mlpack/core/data/extension.hpp +boost/serialization/serialization.hpp +- +boost/algorithm/string/trim.hpp +- +boost/archive/xml_iarchive.hpp +- +boost/archive/text_iarchive.hpp +- +boost/archive/binary_iarchive.hpp +- +boost/tokenizer.hpp +- +boost/algorithm/string.hpp +- + +src/mlpack/core/data/load_vec_impl.hpp +load.hpp +src/mlpack/core/data/load.hpp + +src/mlpack/core/data/map_policies/datatype.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/data/map_policies/increment_policy.hpp +mlpack/prereqs.hpp +- +unordered_map +- +mlpack/core/data/map_policies/datatype.hpp +- + +src/mlpack/core/data/normalize_labels.hpp +mlpack/prereqs.hpp +- +normalize_labels_impl.hpp +src/mlpack/core/data/normalize_labels_impl.hpp + +src/mlpack/core/data/normalize_labels_impl.hpp +normalize_labels.hpp +src/mlpack/core/data/normalize_labels.hpp + +src/mlpack/core/data/one_hot_encoding.hpp +mlpack/prereqs.hpp +- +one_hot_encoding_impl.hpp +src/mlpack/core/data/one_hot_encoding_impl.hpp + +src/mlpack/core/data/one_hot_encoding_impl.hpp +one_hot_encoding.hpp +src/mlpack/core/data/one_hot_encoding.hpp + +src/mlpack/core/data/save.hpp +mlpack/core/util/log.hpp +- +mlpack/core/arma_extend/arma_extend.hpp +- +string +- +format.hpp +src/mlpack/core/data/format.hpp +save_impl.hpp +src/mlpack/core/data/save_impl.hpp + +src/mlpack/core/data/save_impl.hpp +save.hpp +src/mlpack/core/data/save.hpp +extension.hpp +src/mlpack/core/data/extension.hpp +boost/serialization/serialization.hpp +- +boost/archive/xml_oarchive.hpp +- +boost/archive/text_oarchive.hpp +- +boost/archive/binary_oarchive.hpp +- + +src/mlpack/core/data/serialization_template_version.hpp + +src/mlpack/core/dists/diagonal_gaussian_distribution.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/dists/discrete_distribution.hpp +mlpack/prereqs.hpp +- +mlpack/core/util/log.hpp +- +mlpack/core/math/random.hpp +- + +src/mlpack/core/dists/gamma_distribution.hpp +mlpack/prereqs.hpp +- +mlpack/core/math/random.hpp +- +boost/program_options.hpp +- + +src/mlpack/core/dists/gaussian_distribution.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/dists/laplace_distribution.hpp + +src/mlpack/core/kernels/cauchy_kernel.hpp +mlpack/prereqs.hpp +- +mlpack/core/metrics/lmetric.hpp +- +mlpack/core/kernels/kernel_traits.hpp +- + +src/mlpack/core/kernels/cosine_distance.hpp +mlpack/prereqs.hpp +- +mlpack/core/kernels/kernel_traits.hpp +- +cosine_distance_impl.hpp +src/mlpack/core/kernels/cosine_distance_impl.hpp + +src/mlpack/core/kernels/cosine_distance_impl.hpp +cosine_distance.hpp +src/mlpack/core/kernels/cosine_distance.hpp + +src/mlpack/core/kernels/epanechnikov_kernel.hpp +mlpack/prereqs.hpp +- +mlpack/core/kernels/kernel_traits.hpp +- +epanechnikov_kernel_impl.hpp +src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp + +src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp +epanechnikov_kernel.hpp +src/mlpack/core/kernels/epanechnikov_kernel.hpp +mlpack/core/util/log.hpp +- +mlpack/core/metrics/lmetric.hpp +- + +src/mlpack/core/kernels/gaussian_kernel.hpp +mlpack/prereqs.hpp +- +mlpack/core/metrics/lmetric.hpp +- +mlpack/core/kernels/kernel_traits.hpp +- + +src/mlpack/core/kernels/hyperbolic_tangent_kernel.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/kernels/kernel_traits.hpp + +src/mlpack/core/kernels/laplacian_kernel.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/kernels/linear_kernel.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/kernels/polynomial_kernel.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/kernels/pspectrum_string_kernel.hpp +map +- +string +- +vector +- +mlpack/prereqs.hpp +- +mlpack/core/util/log.hpp +- +pspectrum_string_kernel_impl.hpp +src/mlpack/core/kernels/pspectrum_string_kernel_impl.hpp + +src/mlpack/core/kernels/pspectrum_string_kernel_impl.hpp +pspectrum_string_kernel.hpp +src/mlpack/core/kernels/pspectrum_string_kernel.hpp + +src/mlpack/core/kernels/spherical_kernel.hpp +boost/math/special_functions/gamma.hpp +- +mlpack/prereqs.hpp +- + +src/mlpack/core/kernels/triangular_kernel.hpp +mlpack/prereqs.hpp +- +mlpack/core/metrics/lmetric.hpp +- + +src/mlpack/core/math/ccov.hpp +mlpack/prereqs.hpp +- +ccov_impl.hpp +src/mlpack/core/math/ccov_impl.hpp + +src/mlpack/core/math/ccov_impl.hpp +ccov.hpp +src/mlpack/core/math/ccov.hpp + +src/mlpack/core/math/clamp.hpp +stdlib.h +- +math.h +- +float.h +- + +src/mlpack/core/math/lin_alg.hpp +mlpack/prereqs.hpp +- +lin_alg_impl.hpp +src/mlpack/core/math/lin_alg_impl.hpp + +src/mlpack/core/math/lin_alg_impl.hpp +lin_alg.hpp +src/mlpack/core/math/lin_alg.hpp + +src/mlpack/core/math/make_alias.hpp + +src/mlpack/core/math/random.hpp +mlpack/prereqs.hpp +- +mlpack/mlpack_export.hpp +- +random +- + +src/mlpack/core/math/random_basis.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/math/range.hpp +range_impl.hpp +src/mlpack/core/math/range_impl.hpp + +src/mlpack/core/math/range_impl.hpp +range.hpp +src/mlpack/core/math/range.hpp +float.h +- +sstream +- + +src/mlpack/core/math/round.hpp + +src/mlpack/core/math/shuffle_data.hpp +mlpack/prereqs.hpp +- + +src/mlpack/core/metrics/lmetric.hpp +mlpack/prereqs.hpp +- +lmetric_impl.hpp +src/mlpack/core/metrics/lmetric_impl.hpp + +src/mlpack/core/metrics/lmetric_impl.hpp +lmetric.hpp +src/mlpack/core/metrics/lmetric.hpp + +src/mlpack/core/util/arma_config.hpp + +src/mlpack/core/util/arma_config_check.hpp +arma_config.hpp +src/mlpack/core/util/arma_config.hpp + +src/mlpack/core/util/arma_traits.hpp + +src/mlpack/core/util/backtrace.hpp +string +- +vector +- + +src/mlpack/core/util/cli.hpp +list +- +iostream +- +map +- +string +- +boost/any.hpp +- +mlpack/prereqs.hpp +- +timers.hpp +src/mlpack/core/util/timers.hpp +program_doc.hpp +src/mlpack/core/util/program_doc.hpp +version.hpp +src/mlpack/core/util/version.hpp +param_data.hpp +src/mlpack/core/util/param_data.hpp +cli_impl.hpp +src/mlpack/core/util/cli_impl.hpp + +src/mlpack/core/util/cli_impl.hpp +cli.hpp +src/mlpack/core/util/cli.hpp +prefixedoutstream.hpp +src/mlpack/core/util/prefixedoutstream.hpp +mlpack/core/data/load.hpp +- +mlpack/core/data/save.hpp +- + +src/mlpack/core/util/deprecated.hpp + +src/mlpack/core/util/hyphenate_string.hpp + +src/mlpack/core/util/is_std_vector.hpp +vector +- + +src/mlpack/core/util/log.hpp +string +- +mlpack/mlpack_export.hpp +- +prefixedoutstream.hpp +src/mlpack/core/util/prefixedoutstream.hpp +nulloutstream.hpp +src/mlpack/core/util/nulloutstream.hpp + +src/mlpack/core/util/mlpack_main.hpp +mlpack/bindings/cli/cli_option.hpp +- +mlpack/bindings/cli/print_doc_functions.hpp +- +mlpack/core/util/param.hpp +- +mlpack/bindings/cli/parse_command_line.hpp +- +mlpack/bindings/cli/end_program.hpp +- +mlpack/bindings/tests/test_option.hpp +- +mlpack/bindings/tests/ignore_check.hpp +- +mlpack/bindings/tests/clean_memory.hpp +- +mlpack/core/util/param.hpp +- +mlpack/bindings/python/py_option.hpp +- +mlpack/bindings/python/print_doc_functions.hpp +- +mlpack/core/util/param.hpp +- +mlpack/bindings/markdown/md_option.hpp +- +mlpack/bindings/markdown/print_doc_functions.hpp +- +mlpack/core/util/param.hpp +- +mlpack/bindings/markdown/program_doc_wrapper.hpp +- +param_checks.hpp +src/mlpack/core/util/param_checks.hpp + +src/mlpack/core/util/nulloutstream.hpp +iostream +- +streambuf +- +string +- + +src/mlpack/core/util/param.hpp + +src/mlpack/core/util/param_checks.hpp +mlpack/prereqs.hpp +- +param_checks_impl.hpp +src/mlpack/core/util/param_checks_impl.hpp + +src/mlpack/core/util/param_checks_impl.hpp +param_checks.hpp +src/mlpack/core/util/param_checks.hpp + +src/mlpack/core/util/param_data.hpp +mlpack/prereqs.hpp +- +boost/any.hpp +- + +src/mlpack/core/util/prefixedoutstream.hpp +mlpack/prereqs.hpp +- +prefixedoutstream_impl.hpp +src/mlpack/core/util/prefixedoutstream_impl.hpp + +src/mlpack/core/util/prefixedoutstream_impl.hpp +prefixedoutstream.hpp +src/mlpack/core/util/prefixedoutstream.hpp +backtrace.hpp +src/mlpack/core/util/backtrace.hpp +iostream +- +sstream +- + +src/mlpack/core/util/program_doc.hpp + +src/mlpack/core/util/sfinae_utility.hpp +type_traits +- +cstring +- + +src/mlpack/core/util/timers.hpp +map +- +string +- +chrono +- +thread +- +mutex +- +list +- +atomic +- + +src/mlpack/core/util/version.hpp +string +- + +src/mlpack/mlpack_export.hpp + +src/mlpack/prereqs.hpp +cmath +- +cstdlib +- +cstdio +- +cstring +- +cctype +- +climits +- +cfloat +- +cstdint +- +stdexcept +- +tuple +- +utility +- +boost/serialization/serialization.hpp +- +boost/serialization/map.hpp +- +mlpack/core/boost_backport/boost_backport_serialization.hpp +src/mlpack/mlpack/core/boost_backport/boost_backport_serialization.hpp +mlpack/core/data/has_serialize.hpp +- +mlpack/core/data/serialization_template_version.hpp +- +mlpack/core/arma_extend/arma_extend.hpp +- +mlpack/core/util/arma_traits.hpp +- +mlpack/core/util/arma_config_check.hpp +- +mlpack/core/util/log.hpp +- +mlpack/core/util/timers.hpp +- +mlpack/core/util/deprecated.hpp +- + diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake new file mode 100644 index 0000000000..ae8bcc2000 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake @@ -0,0 +1,32 @@ +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +set(CMAKE_DEPENDS_CHECK_CXX + "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp" "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o" + ) +set(CMAKE_CXX_COMPILER_ID "GNU") + +# Preprocessor definitions for this target. +set(CMAKE_TARGET_DEFINITIONS_CXX + "ARMA_NO_DEBUG" + "BOOST_TEST_DYN_LINK" + "HAS_OPENMP" + "NDEBUG" + ) + +# The include file search paths: +set(CMAKE_CXX_TARGET_INCLUDE_PATH + "src" + "deps/ensmallen-1.16.2/include" + "src/mlpack/.." + ) + +# Targets to which this target links. +set(CMAKE_TARGET_LINKED_INFO_FILES + "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/CMakeFiles/mlpack.dir/DependInfo.cmake" + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o new file mode 100644 index 0000000000000000000000000000000000000000..bc6546fcefed1def8fcb87d6a76e615aa7fddfd6 GIT binary patch literal 955104 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 U;_tnY6 zJ0xO?zeCb6D7iz@ym@ah1rhB1%FIpNxk6){7SIsb4rMkB?Nq`EDerLF8_mr{ed#d5 zWP;uC&6LM&XcBO}wL$5yJ&oL9wTItRAj)0pxT#v?8-|_S}D!&QVrD5rBrarOSE6jlKJ&+-5za6)zkxSaFQB5awqE3x7 zOm4gNtM}Yn8=ps19G)qODK;~w*#dmWRVSZne=B5}YwJ{+BPyPS6mvdH6WX*Tf_#qK z4j9R9U3)v@iNw^$t#uPIz+UUdspcY^(=ZM@9t`2yXC)Y#sqc6&G%~;*3~)Mgp9&wDSF8UT`Ytxf(OlMCitBxb5n$v`NK9SD2hVzWd ztKrbzh25Ws+jAlK?Ru&i%bWh?I$xKOvi5J>)l}t<<*{Nc>-jkix`oyq?z4JWTW8_w_#3vGo5u(Jd_xXs<*-A0z ze7#&K&55Vkh`C@1=unCy>g{}b+0*qhHd`qU(;S}WSUpF>(=Rl=o*BzPt)5JJTaD;g zT8+Ary&Sy+$I@%$u06F0$5iChCY-m1-d0k2I*Mjm<}*( zvCbcKy6UznZOiLTB6t=(+$_Xq(UfMH-Igi5_auqUefs56wR0a{E}g_xx#re2*lfbp zvou_u7uzE5DKSVQ*aWjpEpGd0!yJDd*{WhS4a@n+dx-2u^%<^ceoA11^lct+*u?nA z$E@)#UH#6AGqf6Rj4c+%D|lM1J{s2cMoC+)wVZ?4cEoU1+iJvk8myUu2*1>J3pwESSaoypGe5qEbZ5$>8^u_3G4Bk)P*cgyN zWAw6-;ej6ZK-HbhPA%-#?+iwiZ-qMTE!|EtL)6QQp=Q7p?39DuRv*&o*}mg&*Z zfau3CF2aR85Wx_|)mpnzY$HrKh%G8Q62n$KiHERNi?2jBj9}a262NVDr)s@Z*+OM_ zDfFFGSIXbj8#KFm0A&W?u=ZSeY9kbljO#cqT-#R8xp=u7tZUn@oQH=-mW~d)_?_i8 zIDOQ6qN(YpJL)k}Mh6zI#D=|4ML6(6^&g=Fi??KZQne^js^B3=)siNu3h8C0)2ij! zP^hiZJqfo2O)gzZqi<6IZ^0>9s|z`oWYt&R)+bnTg_2SUb-a(ZP=^GyIQ=j(D8M}_ zcykF^#+8b?n5FevDv}0DgYW8>wpy?#Iy+MBL{pr2Jrqr?wPI=`R?^*t5=9HgxE@rh zSf<>R7f6j^Lde6Oo^B^B>u{WfBnoOypYP>#jYNYyTzSXiEnKxf-PnCh_a@VQ490x8 z4S0Z0Ngd!r9oSA;V5>XfhLpPYM7qtf(%liw&C|>6qpkZMIUUj?YK6^eTY!nDS_g~R zd4~HrYwmQZT3B7mPr!z1$H}e9R$Lgy7iv|Q2UwfSq|-Pkh3-)aCU9$R0qzB*hSE0< z4W?^QH>mkx==#I>gog~??c3qQkTIB^3z)(iykVa=^ndgW-N=|*^wga}Bb;t+MY&Q< zr*muaxl`O#a6=AU;FQZvSLl{6nwyZ}jOU$)Mr6(a&TFgtL|vHkfKfTknKYQ`88cI) zry8+ChhygYw)P)-#eO{ia~(Ve zz4UA`KR~ytL7>rnTj)uJ=hvZMv5yFIEYsDzyDFQ@*Sy2u!P4~P)N~21Xo4sO;W2vY zKtG=HOww?&%)tv<5`7RnLo;nSZ>3_+oA2S}!E&4iL}7$8-+5{?Jmy4_!wsO z^25s}@y5Z{hx*ILyXhs0F{}>~B|K(1@WCy*GuiRNddC@n&vYLiPEOE_6}8!BI=TaA z*EX;)RMf^g!t;cU4h(FltThI-!Ewi?r(i9D=DskCmc+@UdIlxQ=g*(CrKw!e26q`E=pCNmdDA)9$pZl3>|JocvK6+v5ml-hZ@`^vQXBhg3OpEM(Dk}a2{m1 zl}*G(xhe?UfZboeUV5@TF@gXSg>7jgGJ;#s zea=gom+h5I(Pww6^HJ;PgN>H$UhyvUc6HmLE;`RHtG8U7Q9dy&|%=(e`@G}k4fo6i4ct)BgcwxJI92Vy;JX!dLHwm!md ziZBaquX7wvDfV^B?BDXUP8xT}0fE{b=hbZc3ic?WJT3-$TO~GC%!2f8W@1nT zt#F2*>Vq9(YK~ghEGk$cnb7LgJuEZ%^^NU^unM|eJ%557_#;dw)U1ZEi%gKGab9w`h#LQ3E?Pi@kOVCWlvq~jFZGOugjF04!wxQ=tjkjB`77(SD%QM6 zcucPx{n;W-n7i8Jq$4Y|(DWZ5dWI)Dt%BB_DInIp$!h zi4mT6TWIHtFUyR?I{j98|Ju7Vfl_W6GHHNa#q4o*D>$M|B$Fvx${jd>wX^D|sRI!EHv zj%(0K_UKVbmaWJQ7WZ2}Un!D9jO)F_u2C8O|G`Kpihf6?`|>k2xZ54x+m$W|eJV^0 zN7=XokT&u{KJeawW&FQFjBp)K1)1ju(w^t7OE>Wuq zZUmc`wZJ@Bl)~(93OlGGG!_0 z_}2Im#Z_wS*7#_WsxM-dm&oNdscNLNR&vfZFZ#ypYA5QKHk8DS3V)r!jhZYk#ctGM zW`C#5>8N+4bauLMMDtGT=7g34zd~r8RB5b-N2F1CYmGx}712|{#jK<0XhTV)Xl*hy z3bcmFhGvI!CztNl%RrCpp2EH9B<5n;&0QCJ_QL@Kh$hRX}U&Y1r6 zSAdoqV_y*7oMkJM@+HS+i`8(aW7F_vr|k@FxcoB?()`xTa-foL*wDryYu7TV3X`zR zM;0>%{Z5eb9O}_d$6Cki>8yVwD_$V}Y2BXakR&h!l$=GK_EGD(mQ)ml`KVQk;GDaxJ2hQ_YiA0T+H{sqs>HXEz1yp!yztv}_hMg% z4i&^3NRoL6*t$V2t4{`DG1{?&l*sGlG4$glCpAM24X0FHe4b6x;vo|`>9Ydt*Q z^vItA_-=|O^*s+>1e|#u_282p{55De{Gc5r5C5nK_v&5e!OI@`jUIeQ4}P8pe{#FJ zKR@Qdr#$kX&^Z3``sbPe&guH4hi5Yn&l4W`DQ@>h8HKjgu^dN20ytoQI-;laKBf6~JFeEdiYKWy*tl z;rEt{mu{ufhhJaf$=`iE zc*WzN13kDmA7Aakz4g+V#xY;^1|zwCdzT0QJ(PXMciFmb&#yh@ah(U>#>4aO5d0Dk z?)CqbA^4ph`~VOCFFm+d@BZ7=?L5#Ue}V`1%9k~ce%Rk5f4)clAP;_p2lw*a8G@&_ zt=r>G?`u5xy`FsR_26FlArF3^M}D3Mzu$uodvI?&9IJ6m@4F$mIDgOc;Oji;z1qX$ zwdXpI{Chk+-|*mGo(DpB9{0$f<>C3e2S3|`ZwIl5KWP7ZJ@_FW{6UW&Uhl!DJ?UED z!N2B_f3wDcI^|7oIRt-q2!5`I-)sM+9{Keid%oxWlpJm`ns5d8HX9}qcPj*UC%6QsNRgtY4HSnKEAGK*akzWEXVyR8ZkYc)xha(1 zvOk=@&F?(tnKf%>&+OUulAiGoTjbw7Pgr<6{$Ex2VimqD{>Hx!{8-}O7jFKKfSdp0;O770!rSrRR^j*HV}FP- zFt+ewgej z|I;e|528P=DLlvR$KhKx|3CTP@Yx9dLg6z+lA0W*{tfgSqyMz<$lLLhyToW=(AA&i z_Z1%bIRKx(pue1QpGAKl`j^q4K)G+hSHS0Ee78BKbcIzBPF` z3LpF135B=&+ZpKXZ~gE${%hgxN4LSI{dOd^QemnUXUF{zEu^-M{c=UhA)dk_k zvk5+y+XubvzBAnR-3#u#b0mBp@_#|$5x?a=jNap=7vTDQRq+{d%&z=I9!{b^i~)E2 z8Mp9=$Nn%$;qCq~C3^eAtoW})edj~(x@J|lc~}?j@$fEi_4~lppA1)jcHxm9+xH^4 z?RzCY`rnIQp9d@a3Ap~xRrsrgN4r?=`{*tAn+l(3tj3_(+Wl>g3ZEZtxhoVNdGokp zOZ4XXAoLzbomSC5T+zQ((a$+{r&^uy|7804Uhq@k2f`h%j)k9!{uH?TV?Vg#%(d{N z=>K=Yjpr@+z04P%!i{r^a>6w7uYP8@@h=IFb16B`t_{C~a<_n=j(#_I922I`5rsF> ze;LP4L2tYCha2bhaF56S1V4j#9)^2-_*b~&@LO=#zaPV0Uw;Wdj&>ZWoUn@g8~+S& z^ZaYLd0rH5o>zyP=Pe3v=XqE3#@`QaKe-xiKK}|={~FwWKH7ML_Pd?P&m?gB?V@n? zE5qHt_JpfH9B%tw4Of3V{7m}KYjE`+!_DU;<9~mBr-$2bSBC4q0o;CjBwYRR@Uw{j zg2JOeOwIl{#sq`nJRAL_aQoE)@P7C#13w3!_2ByK1J~zBc$~A%apNqwKDWX382~>I zpXcEEd?^YK{^uFpPjeU5}*fX`WQeQty6GXQ=eKF`7R z`3kPj$P*39&qer53fE@=xIW9kFUDs*xIX*9^*IuL2|j1R^|=kM&j9$P_`Cqu=QFrI z!%sXYKbPS%7F?eh;QGu1zZ{=M;rgr%*Jlg(75Hoq*XK~UKBpGmSp3U8eocknSK-f8 z`1=(;>?B?JY?s@k!WXFUwJLm<3O}yG`&am%D*V+7A8OL?uh*m%K2L?OR^dBTc;5=Y zw8HPL@E0rms|ufRvhT0&oE5%Og>O^gM^yNQ6@F)hKUd+ORrt7*e}BDZt?=b4e9H%h6;bA!UtCPh&_kuZ0&J!stVs2?)jDj;jYuquJBtb{K*Rcu);_C<@d)w zeT6Sx;Tu)>z7>9Yh5xR?AFc3rD}1CWzrS8nSNI|o{+kNlv%*iV@M|mlFBSe)g%3B? z_t&dug)dm)YghQL6@Gk$Us>UQuJG3?{9U-`wMLox`|JCw3SYFs*Q)SsEBv4eKc~Wf zU*S(x_(v5!`ZV8P-x(@=i3;Di!uPB2Gb;SX3V*D^->dMEr~UqVO;h2$D}4P5->bq; zsqpJ6{GkeeyTXT`u2QcGzi;~Q*B{7P5*m>a%_${2zdB5;qGJsRrK3c^t)B`eJlEtD*AKKyT3mJUwf26d43sw5BVSZSA+6w zza0s#&scDMW`pZ9FI=BR;QDL?*JmrZK0CtoISFq6zX7h#ZE$_Qg4=KBn`Kbm>_5E= zZ}-pT(c3>)huc55g6qFy#sBb%{@9BCqKf{?ivFI8{(*}AN%Z#5&(NPf+Mxb9-K>N1 zc?Ntz_?htD@SW+;pA{bYzn1Z8%-II{?|^>N!b86ud|LR-@FnqaeYY0+>nQg?^p<-x zddocxZn-z(W4Y7JKB!)gu)psF_rBc2;L}mBbKv@43_lb7EpY4gZQ+s6Indua$M?ti zJp3%$_igyu@U7cTsRceK|{=)K?L3;efh?q$t*R{Qm!eA+I16(0E+m3m!@{v7go4f=4g7q{ z9eA!5@5obIjll%3$=#6tXxIRbXa~nQqpx5UHxIXvb zW4)%EzbpQT(|K*>!kZ$8vfplk-u-twxchHke2nK_xZ}(R6+Zd`U2#S{`b=1O#D50k zTMzV(pS{q(h<+LPskHBE@YB%$7H<0<3pdZ_!Q&q3><`Zs-mcdx=AU+c9mGeOO-%0-EcU5>iH=6rVxh<}9zolHCM=N@{`kK!Z_^5xX!fXCd zqaV2|J)QeteGX;3!XrPgHu`3l?`$>wxaIeuf4v*}iO}mmbm8rORpaJiAmvU{@u}%2 zt?0|;f=+(yxBA30Ynh+!l&gM7%KZoBmSx9x;#|E_uj>ns_R{Coihj7#0PS|!y`rDC zqBn1!|C{31=f{lyE8=g4md+OW`MTjbK3HG%V^s7L!fX9apC7Z_VVj*l`+0ZDRX-&4 z)#t}7ca*`bulgaWuRh(WulgY=ckIEeuloPSawi(h`l=t2`s&l2_EkS5<@OlN`l|nL zEO*+$tgreZsjoiWXbrA%sLzjC?wW&HU-d&$Uwyh$U-d&$?)rmSU-kcu z#P31vD}>pv%czwq`vxer+w8ANx6FsW_{KFH-O!r{_1!rRiFaG& z@!nV*H=YWg5pJA|!u44Nu1_DhKIQUw=eX4P_bmFzo803u-}h+0^?imly?ImLoxGh( ze!5ex`XMRT_l0(+z08m8rB8R-OCQ_IyxCrI^M5gU>rVXU&G_}{PW<`|N&J@)zwLf` z!@qC8R&Tqjuk|;tr(A`<{F(~CuEKAq@EhT_*Ub&j@xl7u(ha@!RbQ)bt=yWA75;REKU?9?SNIDR{!)d%0(ZZDt>ND{p1j@-y?Ik#%UiA7 znvebM?SE4|`gCW%cyBQCqrO(J?&POCKIZ46N`AWIV?6o{ZhmU@{VBxxd8Hk{sN_w( z^-^!%93SHNIJP+7`!)VKUkAUt5#{lTKHhgaMVK^O=4_9{I5<6X5m4lG&t49({-=vP2LEPU<4qu#!+-n@CAO!liN*ZVr=!9RYN_jxQ| zc=(%V@6+%;v^<{d)C-^9_>4~cE5Y^O4(@e?yloS*N$f7Sl;Q|QmOul>9{*3j86i^gceUukl#4~+!ym3h9UqcO*_qzu7yjkWgxaVo}xFWdc&6X{GQI6;L z^0=a1?!HCeF86S_<(>_<+)E2@mwOL->-!ko`aTD@+<(F?cj&UfZkOxvr~T*J;uCuL z$oR;cChBaFpZLC~L(0D=E1$tVPn*Z#!Hs`G^q!|(4X(fKrT=c|^*Zyl zAB5}wI$Zyy3vcJYUxj~E;pTbfN}j!b(VaYd{lYx!Z=UtfFDZK5U>&@Wqr{|)V z+pp~Z|E~RaDav)c-L&w?v*qp$cfUIfZho>};p2XHMbSqdEZ6bYavg6iw>#sl<<`dA z+I)QraoR4m@iyucTh!M$yVF07vsaijTRT7YPyM^oKlQhNn*YJ=pVrs;(fT?+4({=Q zqRm!zr z>EE4xrT-7nubhvpuj7Ar`jzAJvgE<>-~MK~_BYGzPJgppk25XTanEuc_bj(Nat^U3!&W_cdi^Aetao)3TH z%=4w~I5#NzcASU6S0w%`;VZ%Kg|7mCsPHIv+a^C5|2ybcMSm-NWw`6UKQ+OAQ|`z9 zHU3dXo`3FzkLPu3+C<{(e6tZ z9`(0N%g}osxE6mNf41Y#{jq7+5snKSX`?|4-F-&eDOReJ2^MB&+#& zv%;5}tV@QauMA2&2caE_LG~7KI(OTv#8E?|0CS`K3jOZzBx{YkM+%YFu3)drS!w#)^|y` z_1%4} zaO-;`-1^>y|3$R#Q*i714nFqhf1tO0CnulQH^-UCkM-RUz4hI<@OFI-ovSZQq=yBF+QZADySngZp)yU(NCkA)n@j(KA6 zM^3KrD++J>j83~)Zl33B*K53rzx#zg*$>-3>r{NEAkK(2+i_a-p10TEezGP$4>pD8 zII|u;XVD+FfgArWaNBW2{QrV~#u>4niNE=A{9Fuw%iR!eKe610D0haUZ`p=+V@nr`MwUFyZr1A`M00sI2PP?Ka6&<-H$3f^tQX_b583nuUp}+A0H?@;W^32Cw%)v?=-cgbHQf5%2si(C z!Hx6r!XqB*`#RkCzpn5R%7I<@*l#C;>oaSG_pb0|;P&&w;QC)$;dfT}&-+W)10+B1 zFI{=~d4K83Lv4TgUz<<&j6u8E+T*tO$2$JxdDrghZ|SoCj{n0I{!)c6Q<-Id%ec*&76RFwlDtPZ>j$rH)W2we|S=#ABSbalkyh zK)0jZ0tnk+> z{JjbvF*c&Quv#RC=p=PUfR3jeCYa~^5ew>FPBUs$h2EB$J{3g4^3Yu7i=ujp&n zyYH>&U#Rd8D}0zr{~4vir>gM9Dtz4vuk9CmRrDuScx}IUprU`d!t=hnc0U=mvVNSZ z!soB>RVsX)3g4x|Ppa@MD*WyWA5h`1R`{@ym}YC|XOaq^y~5|K@YO2Z^SZAz<4N9+ zI%8Kj--)MJg|A(BG{580_7(ks6`sd+5w7Dy9zVDF4HcifUn1ghe15Z{|DwWwQQ5D3 zzR5WAxG2i?ebGJ_{Kd$F&fA;+R~gUqeuj2^OZVx_JKjIs{Ap*4a$m-$rXQoCpRn-% zTe)vH{@G9RJb9Gsee#|MHqKQkSD($``s@eSXF<62J)y#DdH6B&_QAg?Z~FYuc{4vB zH~%=PmHG`sewI zc7OX8z5dy+LT{e0LoXkt(m&1f2aIDsM8DGir_irHXWX-28RwAnEB)7-3uJeoK{?z7|^-H_Nc<@NmczOTH8SoKC z9mEfWdmn}OOGn%1`S5(dM0=d~`t?Zo-(1G4wtgUdWc1@jVa?Xo&s5y5{DA()ArxqU7yPbCISK*i8&0Cyed`#q*W-<|h8dL4f>_9M?*>c0bVu0%Y2;j6$;As*k~ zcs=@6(dYOadGP&>BjID5H9lQMKMUOZvOG@q{*Xl~`sLu>AF@H=?f$kM-20mLf!m)Q zZ{4r+zN5DP&G@+gZc=!3-}srS>?bFpw|)Nr--&j42yUEt{V}}%)&!OF#W?Jb`cDG) z`>JNC@Oj}w6Hl+gqui${*Lh?d`tvG9ANNs?3(x1*!e>1AMwILKTY3K3_vD<8-uA6s zmw6NYiPUT92&CEKBYtw;T(9tGck{U|+;-U&Zk|tp>*IA3`MnkWzzScE`Eh*mxjtO~ z9pT1*GTeSxyHDvF^!EQJ;FkM3-2Lm_!lQaVKmG~a=f{VR25GkVIFfd(o!6Zi{ch;H zGhaN=40h$uhx#eZ7ZcFFy*pXxif=FK)d%i;aR}V`;+VoC|IQazpm)CT`f_c)Fiz(S z`P}$#Nc@`-lo8#No=ZI`$P zop~c7a=Y7oPA^1u~-=lm+ zeu6Jk{%szDFIMnGi=J{Hd$ z4cvKuKe+ni;l}?vxc%@?aP^PCo%eITZs%?IPDktNhmPB$6&}@g-X9n4yx$Wa=l%KN z#<@J)d4F)vw|G6}nZ`56Nw3d73*V@zPi#@I=ipm)XcvDTzAOCi@LZRL&kOLw(Z2{k z4*nAS7W%*Qe%_A}{?7Yfqj%oV@wl=6m-AGom2!i7p33{{regdor&T)ndAa$cC_lEP zx;{Gp4wn04u4mijK2h}Ta$ko}N4cNF?I(F3W|SE}1IzrlAbGIgt_s)3@zDL^-<3Cy zb39LYA@wr~Y*Fqs@M+=tuL8G!ZUR?-T!r5bf1Etr2e-Zh;NI8z7~K0mpMn1n z{pzRIKNp~V&Hwrpp8c@h-}XUo{;!4GPws|W?iUq4dTE#Vn2G*2Kka4z{0-dxwjJDZ z&#v(4qmwsVyS@u|;qUN`Dtz|}&+B4s|2UqDE%1I&knEM*X?;K+r{x#UK?+> zrCrn?T;czy@Y;QYvyp%Om#pwSo^0ps?-l)$97j1mUs!njS^VVq{Ev!$!6>lV+WI)x z8e4qmAIBcCwe{zec`tr#eRI9o=Fe30A5{3z!*`1PPXFAk!v73^jB)i*xZ~{`aO3|7 z?s)r6;gJWg*Nk4d?lTeGa%U+#d}g8l_eSsW!!mGvHiR30AGq=7^{FWLA@XwodgqHH z;La~+z%BPexcTo7*XItnK2O5+c?NF1UWV)c8C?H7j}&uh=7RK&SM!*hLoOZk12 zyH&&E_p#mC`QNVjD|q_kd9%>_y%?_-ef+)Oi(&t_zxjODPQ;Vt@i^RgdK7*5+wSQf-0R)0qrKkkeSr4Qjq&$={@cK#jQswKQ(HWb zPtGsAUEgcr*7rHM@9lpTZk`HRMC^;QAJz8LayZZ#zI&se1fTx&hiT!L z!{?~*+@B&I^@|sMRvzt>ar z@jWxIG=G%+FwciXxv#==y&U{C_=%MJZIi6@IiEO}re1$S@A1Y*=#BGpxb@BBoKHq1a-^a&1=X-48 z*Typr=MD6q7;Zc>a6Z9u^ZohZZ@G)&^E&-xC49`=dhq4wCp*K{d)-R?p_Kau2nG4eHK0mlC ze68XW@pyfI6S&uB`@qfTVQ}l^bx-ScZqY}ct=GkH>vbjEdffoGUJn=EuGceg>-93+ zdgXm95vSvMuGfM)p67iu!JSWcDE`5n?+${icOB=v@cW{VdO1G-1@3)ic|T0(J-+h( z6ZP{IpNR9#=8y8YVo`YfZeaPh=j)7ToAUd1ocqHa_l|-)znl-(|7y7UKf=|I#rS4B z=J|xElkJ$_3lrRSnH3+~u{T`(nsD3E_c<7+_tV-ge=R=kcFgzH2UlNvf5LK6p=Jxc z{XEC#;Et<@gt*z_&&*riSJ2MSc_D7L;O6J54*l+N;JtA3^8nm-dAsn4)4X{fwf%fH z@@9UHqg`yT)8NLR@6Bk}_eS*Q$NM+_rC#W*m+zmkUY{0y)YtfDia?qzxb+>rL%Z_) zR`biz%fItIRPkr=ljnt&FTZc+bJGgn9q#^nFx>s|47l~W1g`!Lxca}r*Jd6Zf&AES zCxaX3)NuR%IK@A5^LCSr9QSga-pW$^3iW-1t3STAlvj zaq=4QDe+$up6wOot_5EQ{W|c1JNr=2=8q;UAnG4m_yq6S`PWcGjaWXD&rtr|Sa!DL zd0ukN7T>h|JCE;Dzir{uqkpFfBJ;KwJpN{2`S)_=GvfUX_1YNj{<2fy;c++GRBlwH>j17MS{x1ISSA717 z{yp?w=d#?q4%q1*5n}_w-zcxX?9eh*x(eTaSKEJa${Q9DgeAe_}h+8!;SwH{NE>UAHZ!#?;A0n`5vl>#daJyK(oci2l$U&c;s21iO_$D zKKAk0+WLI|Te}^7|C{YN4?bIv=Vd8(OZZCYjWeImjbDF6oJXT~e>@BSkI`RP(cg^z z6ZGC+w-s^bebn)1|3IJbiw?du`oB@G^?D872mQdpNAfBhYQ^EnW``Sg6<=lFkF@%cpr-fZoBj$C+rn9s2bj~w)8oSYWDJ^{$@c9z`rWO4j=)Xe0FM9W{v(ejsZh+f=ZiCx@ z?#18!6KkK?;=}Pd_O;mBe3)`VExf;Oewq0hrSQ-@{)~_Q8}yS`^s}S?7X94l&ChD+ z?I&Bphid+R#<^|9=V0{qpCi!Qf6hd2{x5)=|10n@|98R7{{#5A|2_dX&ZqG)&NtB8 z&)N)V;=gUx4kZf4~zdb6`z~X4~PB_75xL~ zZLdcv`lrzkkN->PZLbf|kAVKOihk4)nvT6Xd-<{zj;lFpq=TNxo>%REdj>n@n9`7TyzW1V+KM40Y z_64~5H{hNh7_TgtqaD>xR(Q0P_Ox!y;r&+HZbauvQsh5!8C z@2>k{eroUi-mI%Tbo#?19B*g8jear${q~ROy?*^};jzEOPo96ChW?<>ycNC@+YqaI{oA$YVqQV-{oC)ry?^^-xZ`k-PHnsDy94=mTpb?1e$j_r{AB;xq~eqJ zfrM6{Ln?aDPtHKOdA>b-ykGZ<;*;?VEdS1NIQYoS*UzH&c;Lmtqurf<-+_DHdw1v0#quJs1!+G%;6aPif+Ygs2yxkAIzs`Q>eRS40@1u+Qu0VbBd|<@yaeF`F zv0ZMc@Y~>yw|BwynYt-2wkX#)=jqU{{^R($2|VhMzm_hXdRy&SM66GC)*!>!G3MO8j1bR@j1uah)18iKOy2V ze(%$B99|TE$6?>|rvDn1IDdnWlQ|9t zAB%bINc8c$94AjKJmN8L-k)iIz8oL>^8kFz+f(R0U-x&o@p#?*v?i!Lz8#wV)c28& z!+w3zD1-F*Tt;~7vjaZ9r}Qv;1r^m;ELFY#i#F*HwetzB8g9 z7yVpt>+A8`F6>{vr`q~%UD<#0J)ANA_a z75{O`fqqir`A0=RO&K5J*Y?BN;O1u@xcf`5!rSqz2zQ*xaW%?yf7uhg^*WVujq`lC zarUqH+>TzKKf(2R7;b<2YsLRP^!k4e*FVSM$irl`SKi;!&S#GR&DL(O8R7c>y72gL zUS1Y%yQ~U#emNMfe$h@eUE{Fhd>&6moc8m)4?MX0#f8Nuxc&TUxckMeg-2NSljqUL zJtR4v=XHm+etgCg+p8zseEK|y{eRZV__HwFylsTP{oirkdgVI0-R>vgW1JUN%JsfY z$N9W(vz?#2i%)x;AArB({IkU4e3a)W+x{P-H~!Dy#@XrkO&hm;^0>Mk=NOT&qBqVd z3y+T}=qKKvY5o^NZ$I(9^v0jxPa1#L1OLs7PdolyD*pS!_0RJF@oUGWV=Df6-Zg%0 z{MS_cZ-VzE{+y56@#k~X!R_bo5|880FpQt-z28zk8G6U14V&^}i*g-*@_J31U(->4 zcl^8w?zr>^xcSfPn^C=AlApo7&-}IG-_F}a^#3XGpBrvFE(ACJeC{LSH2%DP8hk4J z*R1$#3ZEMNwuMLh?k{_zp9cLY75!y!+x_vv+xvB%$BX!_?+f_2zvpu(p`Vs`h7Qnd z@i85IM7aLr7T&IJJgX90eAq5|elNKB&*!FtJO1Z+zu?mo&k6yWtzGVhg~x~G_JLdO zPVgD<_xq7;$2@P)&VOEyj(E&--cKIfcD$~X+vYi*wB!FHahm^!;MObe8;@VxKVLwv z&)abOzt^eF!x!k?AAiBPq<*Br+j$!cy?L9d@F>Q1^n9%G=l4N}-aIUhk9k-Qu1}s1 z2_N&YA#qx-E%0%_-oB#GK|Lg>G{>4+V!=5ohZA;vAsBd;=CDcIk4!SM(=gB7vUcNzgBp= zy*%II^@6&G#rgKK7=*o)_}HcITl#jPv$6e}%u-@7}4DI~?PQ zd04gZ_%pB5tpj(z+W;T?o9Dglx1OKzI$e(E5x+hM6#sU=J%V!Ww^zWe*Nufoy}VBM z2ztk7zpu*iHqW=T+tKf(a@_uJ9G~~4AO1Iv&&L1r_}q2h@6Y3NS009BeBO`!;^*$;X2y;PG_RrDJwpCe`yrogZSsge`b8VKf!pGLjNoD-e0Od*YEA)E|2#-?%I|3 zZO47#hYoe{7+jgM7xbz_A67pMmj@W{YP?V~amC z&bap}w$K`9T*HbjxN*igy4Zq`L7WTYZ=6e@zqTnn+kFMNajuGwac+R#IJbry=Z^4; zX!j%WH_qeHUq_s$!;RDL%`wi)(HrOQ;Kq3yd<^1zvhZjx<9rVNjl}sX+&JID$2k9i z-Z+QixoP7Z0loxr_9(m^=d|d(Uvw6@an6a4arQ!QoXf(Ea~1fV#MuXb^SKlHIh&kh z|J)01ocrTroJXNI&QsvVc{Y4B;=B=mo9K6G zjx#eqL-U-qagJDc_{>F|W5SJdJba9^Cwk+Y32vNoz;`9i#2MnesI@Qx&CVVxc+iI_5Zg1 zYOkkUf4QF8ywt1RZ?}WHp33!C#P514*I&WoC-Z+0K90A?kWa_k)8US{=fQVo{<;N! z``ex9T~Fous~xA;NsaSqe2nu|xN*J%U!FLJjRZGaJI|vO9`U%I%Jo+}&I$1`&Z+P* z&RO8bITw6);#?7b^SK6k*HgLvYR9<=KE}B{KE}Bh+&B+}PeYt%;BTD$(7T?>^;bL2 ztMD<--{WJP_rZ#1CSwd3^rPmS|+e2nu$xN&|4e}m)Iu{drw&U}wq z#N&D@*I(^8r^d%PXXAL@I2V8$=c4et$me?a8|NnIT~Fous~zVK_!#Ft_!#HmaO3p7 zXJZoQCHNcXRrt7`%Jo+}&Rg*@&inB(&d1=!>3hs}qTT(zTI2j2AJy$^}QRh6a_WNXAPkmhRAHK3q znY6-ZsqncAk64V;^_T0Z)hj-IDm>q>AO1eyx>)n?*s|R-4@-C9&V1qV{JMpQ-sAbL zD*9c}`~2@waL1p^;Za5&XWm?Rdw#qZz5VcExc#v9p0T`NEAuc@S&#YL?s$v?d0$q< z<9qDqV%_KWqI#cIjALV$`0_reEI0GN8$RxLzVF5Q=5@XBvA);hO^$n!t*;$uFSt?&)t=6O4~>-PiT#@QF{ z_q3h~S6{nN_zv{?`~|Mh6NSfz`{Q%)_`jLwSK#WsFU$A%<^8?wc3GvYUxIso*THb} zevLj^aU`HN5R zdC@Nl_qps<;PavX4P5;;@cGg24p)Cr;ql>f-|_5!Z1G`!T))VDAF}*~icfskUTksR zz~{u{I|5>h{P>)BybC?H`0zP#ulrbTu17-eJT+dElh}egpT@b4*n;b`WQFH?p{+lr zqVHGXH&^&QaQENG;KrH9+wFL2$J=@RqOI@EaiIRoz z@no^WBOd4XHPAc1Z(7lBkKXzHFu3#kMR4P}0e|PaJJCDeJpgyUdj}u$`6c=&H|M(% zm>>QA$I0N%FViy*x*qX)dFz$WF-4xO*ZTNaudU$Lt1t0bulD`VS+6tkaUQ=FZkz)v z{@=iz7lw;JZnpSvUhsZq_0tx8cOK9Cg2Kl<%iO>2FaGgy#HfRgbDpo1`zm_(-~9fFDA)OYWadrlmG@nT-uXT6lL>DA zf9Uz$_kK8!f5`EJ^LXC>9O-Z#A1?xLw&2d=lfj*5^LtlA?>s(tMep}1IFGMf(dYLj z#IK#lz0bsUIimQ)hy0uhzoo+OEWACB-(Pst*LnP5e4NMQJK$oA595hnS z^HlnrP|?@s_m#WS+1W3m?Q{Iec|6+1`F%_D&hNVw-qs(8-ud0{!*YK2Ic4MdBmT~V zkKyk;=z9{J2fxP0Jdf6z*K!`5i22L;eHOU$j?XDOzi;01&ph|R$9nCF-g>!yw_cav zW4+q%56pVqh`;muQ*iU2?;mLIr}@26!JQX+#2+_Xd^o@R{sHw%6@A;s`Pw|^^S_~Y ze%}`#^Wb%7_ZR1D_19N?@;=@uSD%L}`ezG|kNC-U&-c{?`z`bPD3y76Z00-X_xxV< zh{yRo-(wTpdbv(_e)m1Aw#z+~Ydby!cb@fmCD-qr0ltZ)9nTm63U_|*S$O2f`F%FH zyPUD7JYm;zn>4cUGjd;__h3@ivFz%&v~{z zzkgcvQD5ix_>Q62;=}oU9OfzGnFQ|q9`68&Eqt8cqb*_!uFonJzGa0UT;WH-o!>8m zTke1g&+iFp$2nYOKAo(>r-M5_ECn~7yiU|E_X70#oca1U8#yQR$2tSf> z=6Lu5O-}MW>RE92uM6M{qW@jt5zo||-yVZ`#Bn2^Lx~vOU-CJW;QjFN{T?U4Yu|(5 z`#Q|?K_#Ac-cGIXYbyM{3jaj}-fZD-|IhcZwac9Yy>Yspb^ltcqR;nXw*618=&!8s z+VSDf=YP7MFYC_vpS|dxKcD~U%G=N9f4cJU^ZB2yJPhvjouAMDbmi^m^FLjA`1$-# zR~~*o|I?L+ANu^ygdFcVzyAvEd5OHwKMu1z|Fc=q2algTKHnN2&;RU!-t#{P!#)3V zF+LtoUWGo&&GSFMgM0ob-$&Pu^ELDjbDT3w2%D{a{ONJ8=M!c}Z{8Mxdp>7Xxb^b> z4cA9IR`j0#(Z}OteJ-r{Tw8d2#80;41Mt4AvtBB^ou4<+dp_p_^q$Wdy_|1p`*@$f zd0vY1Gp@hZ!bkny75!mw*MoWgM#STJ9^W%&p6{nz&+~Zyyytn|s+9XR-19tnzel9c zb>+AbV6z4HJkJzx^}m99o@ZXT`o#*556|Pp7*QAul2dK=-cOct}Z<4 z>v^7=@b^5=191Hxhr15_8{Bp7hj4vHuAFbF&Et6=c-ZOVbsYCo&lkyS=ZpGR;<>NF zpRMqJR`@q?&qvL}`5fz&-@n|hZ*4ukL6eu*qJ85h$Dd6DHe2|3y~gh&@OsVR9rbth zClnsuUaz?v?)4h)lQfPzXyypCC-g5p8ef;FS){A-2>ox1Z zop-imUUR-a8Xo?c=X@V^yI$v^w_aDkt=GeahmZC8D|+kocewL)`#mZd=UDN_%@!Zd z*Is|I+!c#H;&EQs7;fI2XPvJPLa)Ei_qm^*ThZTI;W^JnociQ_kL`Ts{f%K4KbfD& zm`9Etbm|`UU*~&7+wu7R5c7N*{?6Bz;;;U(ivAh6^YsV#IA4zx z0XADZPM;%lzMj75BbUzC-Y03fE1`G3UJLGgx;fnWdJnkzoHrvL=j-Du`m+j;59jM^ z;kNr+gFE!EmcKA47p9nY4r{QD0{Jur&<^2-YE7!&CdOh1JH|zB>-1$1c$0uSm z&QanYg*jhOQFy!D{Jw_Z&I>D}H*cH5ov(L=+g|xz^ze5-J)xq%s={l}H9TC=|Gn_| zh@YIV^FD`Q$1q>d!MtYtxh@X9^Ys$wov(dQtUmqFo9CRD!{7PZ^{@Jui%(nsHr#pB z=fRz?^M1v4f5`V`1$VxlFF>v(27wusaDI=(9>wkY2DdN#P_dS8U| z^+M>Kuh)RyM$$mIBKF-(k!>!j*aLdi_ zu}c4ZKJ+>CzF+8#!aK1v&sjISKxfPM!?)Yfb-nSlpKHi+{}jf}79VkMTi$o{2;BDz z`5qqMQ}hk`NASt#7US3Y_`R#{FTPjD`1AaEyS~eFJm7JAzK=A@^|(F1Hzc_4DcXy9 z-}e;xJs|Nn*&p(JdobTqdzNhE`xbG=?oOi+FrbQGAzTZ0$Iw z#K$6=jOy?oOvEB^yd)gVfY*8 z(fHg*K2L@l=Nb4IXP#$k$9XM2#(6V*Dcb!}{EhQ(=sgeiBHTD%!^b#3L~sB63T~Xk z@P3#9dtjzS?|H2m;l?>DKE}BKdgELYZk#K?&nC_-@Hd~^p^tORxgX{Gb0S9L z+#4U`JRBe6JOOT;r^6Sg-LJ#nIB!8e7jfPNH_kueW1NqnH_qqb#`!9IG2;9hf8!jp z^1huZD}1gBU#Re?lkfjI79PLLE)b>9N` zxb9o5;%LQqe|*@E=fYk0U0itN zGmhcQ@HNyO@c3Q!+k5bFUU(S2^TIQ5=Y^NxtFeE5fxqz&&2g#gzI{L_Vh}ydCGv=w0{y8g88P;bWXjpf}Ey;pTHK_=3c_BmU-d5A?444uBiyq4*f* z@#u~7EVyyz^PAy)DeZn6{>FI^KCb&7fE(u{_!#GN=#BFYxN*J*KaV&^s2s13&hf45 zzVYG4ISD?-IW2nQoE>hQ^THRQ-B-cie6Ee&b>BvCnQ%jEoa4Za zb7J^z&9Qy1H|Hq4Juc0M-gRGZxN+w9P_*aGRnZ&g`f%gi48A*Y?pJs_&f_cm!V15s z!v9cs)X8<<$MDJ6U#2MQqtM4s9_P#np9K9Tg-86Z6Km_NW6|4xPQ~9i&qeRL?`F6@ z4^{ZP_`7}?ZR95KW^3nv!U|uk!Z)t)y(;|73eWqWBOb5Q<^9iXJ`~sE9%$+qzmIJa zxc&LZ{Qi;Gn|PY8(%A;K;>mtBdIZ;O?f&-j_m6btryPxv+kL*dD3$o6& zfByXaBVEU7|E}*JnYxUNG5$Lq&I><-`C=is*K0O~pNW3I!eeZUxhDJJF>uGd6Y(*g zbJ06KUk>-Y!TtEyfAYE7sIPIpg3oQuFEh?};Kune{<~4%QOkNQ{4F={BMpx@&og@Y z`+UD>@c7B~-SzmGhd;0$G!Nd7Y94C$32z&PHCsCmCl($bah_+aj%ui(u7Jn?%{YHo zc=#CSUFePTLHNJKiH~{9?|*FPb7rm^&O`q5d+po$N738v9~VAD)RXc2i^3zUt?|$6 zhT-q^vhf2nTj=9igX}+(7akw3H>WPVUGB{2^1Vr3A4W5uV~)lnsRLMVIH1^_aV>u9B9<({zjAjZ==^IzZWC)uBRqy zVv8-f`N{hd!_NH7fZqJXJ{wzjn4dKZ4-8IeP26ZQWh!0yqAp;GW;EeNWsT==C`b?l^xpT>SvJ zaef0=U;93|{NA@{FZE?w=!^sBlFyvaBX8%yv!4c6-?RC5Y~kMz{Y)L&HO}ZWe}(rh zJbcc_XKD1kMjmuNc_sJ-=+}f>?r-3WHa=f=9e#eh8C?C=g-1LW;=f}>zZ?3C(C>@> z;)XZ>b+$v`=JP1H@f=rp#B&M$r=q_Uehyrpi{KNn-(6mK_+N(4wdnP^9d7)0<8wJa z1K{@ONAc1B8My8BB0g~~CdYaEbAQUUKVJ#AKdbLff7U107qMTQgMY6QXK?jP6&`uM z3jK=cuWoqrUuRnbZk+aK{WmW9c0bt)AN$D;aD8@%&q$v4!QXyzFnWFZ!j1nVeC#J@ z!R;ru@3rL3_Pq{n`>O9w`|8u3_Em5DUQax>?+p!a{_AYEuW{PG`VUF_>SO!vH<<0K zPv26H=;y{ixa~Ve@ri!x^XZepZzP{n6+T1rc@uob!XuuW;d2xo{yu+QE`xXG!Gkz& zlkc?-{o0I^&O1>?-w2@D*6RA`%!BH;E zZ|2SUI<$+&??x>Hu*XF;pSZU$*L{QQGkqyH;m*}l)yj<)aL z;kK{(?zFEyp7)dYF7=8$*UtMb+2k$T(e>90#JMK<(cku6s`2^0^M2~LCZ5`PKlL65 z*3SFA*uea@l z`LDA%UKywTS^tg8-~E3Xuk>-e8oJqEa-QwZc%@I@5>Mp8_=jY?dYwGmzHh*7U-jK- zUwyjMzUpn?+Ihb>n>d^QI-BiloVKt2L(;zb*uJX`X8Y>Xx6~ur*Z7B|ecz@XZQpm` zwy*l`w68wSNAljKUjMiGXxS!j*^bUfdlRSgk^Z*ta*faT%}46DCZ5`Sq`o`z(ZD9o zjNkdld^#WLKP2;!KF&vz4CZ{KkMoi7-%Z{wr(FiXYx9x*&PTS_i}=*$qxUG+{`@}N z{;a+`{aGK!tGDp)RpN~ORK4R>?fChF#;5tOvpHTFr~O&~jmzKtf0>W;al9I_*iL?2yv)R7JY5VFwB<-t@ z?Yr(^wy!>YOFg1}jel_4cc$VK{q~_IIoaQqt?*3?k8=Ns-go zK9^T~eh>c~|K}?Fn+oqSbk{E;5BkhocstG&;l{ZUKGxUoRr!KAcgN>TxZlsKPu^eJ zj^}2|_54GAKX2$gZhw$+jsFRJ+>d;(`&Uhz&3~QE_qy93-m3V&hyNwi_aEpz&*1yv zjWfSzE$S7|qGrDxF+j6LJG#D`r11DK&K~H^+sx?A+njLYSpXmNwkUe@whY{O@_qI3 zYyH>2-@N?>AM=*)w{QFOL2ur6z~8(bjNX2G1bXw9-yavhc3wUUAN#rAD`(!kZ~1Hb z+jaOD&n_oN#jouT z-d}Cr#zAj?^ZNpfrzd*-rzt$@W#01s?TE*`<@W@&k z58U>jG=$9--2G^(!sEkr#7uDWncuSzKK85p{-d_fq7|RKzao4NZ8SNa&(i!mw)nG0 zXy3Uzw2MCq&*Qq#d;QVlI{i1p=P`V?DLmqd?^Mcoc0q4E`@oIoOt|r!UwGU9D)h$l zJM{7H+>9sJgYEp>i{A55kHbBG^%~`VOCAQIx7<(A8|RnkdlTm{%=_kTWafS2oCt25 zQ{iKrGorWLInW#DeCQV?&isCXc0QNE$M)?DUxvKp_XtG$>VGDB<2j#r79*a^(VMsH z;KuU_+<3mM_~&s{)Yo`Mj=-BOKH^ZTk-tz{F!#&Ti5dx1#rY#NBY?$$7lpUJv2#@zRs{c)au++&KMy0k22AiND87U*cn& zoe8taSvzl|1!%U2-@N&~z{Zou3Grv;red@Hsy7b`<&#nts^)*V#^h8;{>pp#M2VA0OuJ zB7DqSf4Dx^!#&@4bK&t}-h58b_VqbI^Y%Rc_P1Bz_J@4WM*P~meT?4zmhTIVb~GN} z7pnj8%@`P4*qOJ{3J)LiHZEMBN#ORk9{8I#zu(IBLL5`Y7Ug>UpYIWkI9=D|dqjhK z9PWEWUDxFEiJ`aLd_J*V?oq_A{=`b0msRxFR`mINVmqFPEBZGp{vTBIU%}mv{QiQ= z8UIJ+`8)GD4$t4&ukw2hB7S|QtoV%B=wgdJ@5Oyey#h8{@NbC6^@Z)&o%PW#8c`mn z<@LUZ^CA3Ki$a?%%5@#IUWaz=7sKGQN#UV)9n=TC<>vik?Q-+J-?q=$_*m|Rl zU!ph8>Cw9$nGL;hE&~6Yyyf?XM?31XF?!40igI1o?1O3Lnqk4#V;Mn@zo%|2o^qaO25!V%X_Fe$hw2x`h1rJ?|dp zOohKbGs3-pW>)+?&RG<_ar*sn=52NK=50N=@oY-D=B*EU^R^S*c=9}OJ8%2pZ{7~Y z$Gr808>j18^X7Wiyyf}ih{t|@4e^+_+bQ=g+Sl*7bH8{HAM^G&K3*Sx25vkr!S#O~ zfAjV(dh_-PTp!o7ULSWoYuiT(JM{Lq z{9e4^#f^hl zV{7}zF;8;$BiDDXBWmlrb@8!ZZBlr|uTLMi?NXL0oj8Z)IKS+U9X>qV`+P=#d!LW` zo?X@b&VDyj;gKJGywB$x`eCn%-urw!Kj8D`BQ|k1R-G-c2SvHY>GdGv*|_{&5Z$DfXzC8Y`5|2LXpkD#~ z#ufcmg}3|dj_B>Thr{h}7sJP-pIldXm%{&*NG>OGlRbk z_xNxe;>_z8p&u9S^^5U{-|rn8AAP>xJA5X9UlX9&qP`R2^LzMk=m!)YALijv^zV^} zzoRz~Z^Az!52G}FIJSt#{e8^B`F_GqJJMcL$K&nz+t|X#JZyyCJb2t_9u7qRIOF75_&d&Ah~E5MQTPlI6h7CZcYnVb{v`Sb z3UAlzIrP@+J-GGqx`6&(7nq3tHg4rS|KwaRu%GySVdh~md>qG?gM0ku`wZQ$w?}V% z_k_D&p9Xhax*a|-_4WI*%kDe_7%mHWJfpkx%EZ zY2eNyJ`dtLI`4-JAJ@x!1Trbayzj@2+O5yK%+4~aJ=k=q|yI#)qW^nuMZj@`Bhfy#4TRuk+ zKCYMZIf8b5&%$R_`pJcra`QS-yMJDf-u{{QD@M8YtM|}P+l(iGI(tmUKbi}hQ@l44U0!Rr@}0~_Mw{&aW-aOn1HxI5)T}OXf^x^OL^DRE+ zXZW(tnxWCVjvk%$m*YU*&lc_CI@kB}Td(=?v0iJ#t=CR){e6G_tn{~o(7Qg$_v%L; z>?gig-#pxekK@~b!o$b?H@^?M-EUvV$NhKc^8Weoaa{5}{Ekb%;(hh5qZh!(`E+~q z&ZoP>&Cj$=9I-__uA?{a(5`XJ?-B5Ry!{!U4=VcbiS=^sM@PcrcLU46&x21zJ6>0K z@^%`04*2Exdp^_mQ|WVO#pi*FPd@(@aau30$62q*IPP7Bym@_1pPA9?vprm& zeEz*1&;IE3@jg9${*2yu9);_Z_t!yF=JR6a&F97R$@NtDk57NQ8GrNk0P)zqkDxbi&!e}$y$ZJ-z0PRf zK1OeUa~)?qLq`KPThvSc;R}xs^XBtn=FR8D^qB;I`&$qE&D*?i@26S>AMd|f4!!rG ztp@k_VQsj_A-PVBUt6xvd0DR4J=LFB{3D<0y}qgb+KT>u;#B`|Mep@W^&eF9U%}mv zhGl(mIs5OZaPv7%;Za}vRXz_D#pp9-#b?Au7hCx3TX`;KHs;4&I_j?DTibE0!ow$? zam(Y_xzT&RVo~^f_^(&-*%ZC!EBc_nl5%%OZ@CA+E%)?_Pe1gQdnx*>DEAulmU}zg za-XXB{2jgJzJ~s4%6%8T<$eJlK)=f8S)#r4nS|ps%iXT<(8s+2*}jLPx7-uqpHuGj zaQ*Z7i}0TWeI5rkMGkcZ>w@`0*lfYw@A5b>e(gB0JbK5g)#2`6Tfz0;vGDlN|L}_b z*or=n58LryS<&B9@z3YzeipcSSO{(&Rw_LF&F7lvdy)Um;fug`toY=6Hlj|(a~^t+$F9WR zKVW}510Un*2iHHJk8Afg z=LPeY=MBP6AI}@u-|j5sw)6Hl@ffG~)0(%}(3`h`aO276@7n#%^8@DX7p$j@XC%1( zqZi)J+j!{BTb?(FaP{%Lfq9z_fBW0)aOc^)P8$BkzX*Dd&zFXK9Fpe;!pHq?E%f?q z2-nBs{QWA&`3o|h*N*dxeP>*9-Qj&Tu0y@AMt#qwKCwl6*{^2m(5`V$AMdNNzxAr< zmnyv7-|{?jXKY{f-DzKaY+vWEUM0?`m-_Csujj99U*oiW^&gV<)yMYr{8e|_ zS0CHg_=lu@9hYoh$3xp!eRtYdAKSOK|Elj!`#N9PzQ$?$>OUmytB>vLe9@iu)yMWV z{vl~!=L_4{<15=&eRtYdAKSOK|Elj!`+EFo`x>Y1tN)O+uRgY~$DiG4Uwv#};~$dt z^*x`q@28^SO!X_Fwh3Z|%P2ubMcU|2muPYn-;P{zKBf`q;j{7q>g@ ztB>t#{6o^dz7N*+^?k^;ulnw^uRgYKZU0r@o%Z#8(YCK~+P?Y^N&D(!`})4SO!vKA7#RkL_#x zgWJBbo{a4m%}@OQ+u|S1He=UEhpkHc=JQiCG{0XBZhLuNqF3>0`!A0FWup$7-feUP zGqV}bM{xC@!)>p8fG)JbPc6E?h=I7`}$U{@I0U2*5~^W+T8ac#JeuD zUim(Rh{t*zU&`&o*_fq1--poFUxI!e{QJZ8&+Cc7ZpHuBiazg8YscgHfBj#=CvtI0 z^Ap==@I%RezHgzOw`s$)+1h;33itfB?YM14zf0lqVgKI;9{)G{|H1IMCp_EbD7gC5 z;p?II`4sheeKXi?w2SAl)!&YP-uGa~Gxe#T4j=vJfNzX` z9=Q4?;PI}f^w0M>wByP9oq}(QetmrOKN$WL_c-wPf7A(^!KiS5&(kB_yOmq%+nV+-znH+_Z2yGmjU|G$xkmlEe?pt@gpbEFd%~^P0q`j)_t3&a>v2wB^jkFlKilghc*K=6R(9v1dX^hRLVF7H-OTX*hFTbJ&LLSGhF@i@W@g8F1D$8 zKE*uG1~<=3@O+ASUa!LUsPLmJ{G`GoKF5c%;MVH`_%`J23b^`P;M=0V1Frr)c)TMq z^ZXaM`sd-1=W^IK)W`6X=+C2#7_IO<<5h((RN<>u_&SA0jOKG=xbbfV-;Vt32v@&9 ze0%hVz||iGk7q42pC`iAUjUDM=5`C*d_G=yXzicxSNO2awdvT}`iUyMN8u5p#2k82;XMeOEzCb;#Q4<2)F=6PYb`X%5yqhA58es%cK2lxWS=cUSL`G_p#UjtnBM4NaX0-W-rf%82MhXJSjIN%Z^qyJ>! zjORR!hvWGP2QFOsgypYy;PNa_KH}pCFfVtP1K$YzgGzpv&W9fY{}A;24ESu|JAi)} z_zS>40{lhlcln5)Y2b1ehkOK|16c9{}D6 zobhZ1J_Yjc1wIJ;MBt2bEASH`|9;?E;B$eq-aCPx0Qo-P^MRiWoO!hv`02M9+ubJMJfGxI;ESN=N#JbP+kx*3 z`QHFP7xc?dYK%bS7oJl-dO z%QeX4!_yjcAgz;6DaVe~#4~Cd1>dk2vs8YFzy1yy%s{m!Z60bl_ie;MZwf{Gp!{US+SBOEfP2 ztVF$E4*6?=e-82sF;4yxaMAT_V6N^P(DPyB|9ar8ue(EfrtA5I`+#2sJ=>v&`S}8H z>i-vT#)sz(a-ZN_T@EP|_vQ6yT;hBi{Fx7&`prJLa61~UtW2g4zarnes(~fddz-X@rQbN9t-tc2|e`x8xH&q2mZJN=W}`b`FqII&wpt=T;5@L z&dYTpZwAhFCS!rqZnMTkKleMdK%Up->A>mdOz7dd$`3)F>$2tor$1f5so(7L6+f>< zz0Zd{pPQTqoO(V1oa?fdYFza5xyctH&p5}~C&+OT_X)CIxKEIA<32&Icj7)l`onbs z)L+d$LF(Z?L9Ta-vrmxq8)u&&^NsriS&!T&$hdKzAoGp;1nCd=2~vMG`vj?n`vjS9 zTt~rt<32(9S(TG+r+zo%)q2Qtd~(0TuAY95`02vmqVcIOQ z_;TP6VLb3h;C}}`S?8_f&+CDI0Qt=P9{|qr^SRK&@$*HH=lJCk_# zL;m{?d2k6Lf9O@u1WiBl)e0(Ua{2#Rm7l81%6)iU*pBOXi~c^W|NRc!tg8>pXC3mqFJ^n; z^^5+mbLiRVz<;7~2_M`04u|~zZ}Hjgh|j*juTX<3lP7vwDA%7{h&-u>{O2KW@<-zT zIpFiOyyVH13OD_8A8=mR4gkIn>>i|X(f=`p8$ZVYUxR*_d49N(AF1WWL;gL`e>8A; zR%rY*`%1+BeId{5#RA}GX+0v(a(xmw%VowP;c|Uh%L~qOeFHelbvlWZF*P|K_ zm+ML3EY~lAvs~snD|%S2Cde~?j?}o6i+N(^8wF<`a-S6IeW^qL3g~BkJ^-9?GvyMy zS=8h2AiolM`y6n_c^7cT*(}Tp$C>v{Y!?UV>zDXLyNBYs#(H@>aMnu`^n4cntJKbY zMF0L6#~!M2@pBCD;TjkD1A*)1SGnuUmz93g9^VFe#=jN#Hy}Ttak2YF_{sTUmaCfn zVIA5v`-iuydbjltvewA-1MDAehMv8le_*-TKd@ZvA6PE-4=h(w{R8ug{li#CKFk45 z|L+0LcFJ~rE%N6P$g{j#fU~@2UOn7Se*^iiL;s(E(=Ny7Y^VRx@}i&l{3hT$SN|C3 zm$rAX{(FuCU!`%;Pd)cKIQ6_)`7NJty&oIExw>WjwmI;{4t%4=!}|Z%A#d_rY|<|01Bsun%O%)t$hT`8 z`0a=TmJj?Zc;4ByCD_E|-XnFCI<@zUZmdiJPcpoimUrl>t zy)dtO;J>UzH}ana&b+$D;b%2@wE_9Sy!yK%ul8}|)kf&q8}f?fVqURa8xUufi+ROz zC6!mNMLlwySr32MURW>euckwu`8EeQ^KB(?#^G+@Syk_*-}tGwY`jf4))UVwdqT_vzvO_;7s-<71u&iGIe%%%2O+`0%>J z_;CEm`0zcXjL$xzSbgLN)FzEj27Tz9?zoN?oP2=&|t zdA6^g0B77rz<;(cb1see$+)pzo+#(h57*;Gz&S3x8aV554RF>Y=Y{C!4m> z{!akTdVDYN-=iLn2hMRF+a1SsrazbXupZ}VJ%Y0yIj_QcH1jGFPqr^JuOc}8{51Sz zeZ5o3$w%z|5aSkO-Z-qZ* zUPWxOJ(}n8f-?`z_(9^samaxps6Ju*jlkJ1%sh#F&F2wEL7vYSJ^=hNuAE8{` z8kZlk2hhalV#xPG&t<@W40&_jl$7f+;G6p|Gxtsr(D1Hl>dW6-sR_?AWuJc0FUG6 zbDr{lamc&;d;#*+`1v>JiBqn>d&=+jl>fJ<{C^zsuJ*N$Sv08%%l7qa=ozB}A^G_X zaC2WK_%DHL@m&Aos;?KrZk+mZ`M)pp(Ene+ANv0@;PlhgAHEd&Dev;CXYc8J`irAr+#zRL0G@9|F3oE9|^n~ z{||&7`hO5`>i6~kb3YXQM0183Y^Hr;Ln&G8sJIg;e+spakv}!EZC+0bAbO9@#zHqJn-efsmH`g%KLrTT?P4j zfv*AnPv~C<{LjFL1Lt*?^&;yS&4=}JB=pp40rB%}vj|xI-T<8Xn}Ht#J(GYp0oQP@ z-evu#@q_*gzElg+e_79IK87cL%KA_9sn@><-U56Ka96o5fIQ1}6YNfb9{SS?d@S_L z0&dPo6lgJU>M`XO|33~r%OP*hG!tkg@Mg%b0)7N=4d>$Tx<7g=u4{4R-{z2a-A|2y zJnPY%Q6@H7Uv-eDKd$@GcS4@|^LF6W$K~Pd|?UPCc&r zN;%|RcE>`VcEF0FdMpr34r$C;1UW4%)^|;F03Oy{ZtN(ucpPo*#sM`uPFiar~SOdHVS;_`^K^5ag-f z70-`Ao_>B9cpN=*AWuDWfydF)4teV703JurKM^15;e2BpJsH@g9@ll>HQqP_dT7@r zztA!Mbk*az=uhb9iyU@46>j8)YloyCJ0E(OZ(jpW|6Trc!LG3*`Wu1A(Q_8$3dtPhUcM&i2&f>JJB@$HYVGYd&xjKf&h#XWU%+7eKxi z`WHI%Hvy;rzRwrVg&z992srh-o-era;V85(=I2YGpK*5SInJTye?0Yk6!P@veBg2X z`55G>XEE?NdM<=K^_&NsdR%$<3COb^F9Obb+==T5^}FK#N$8=U7XXi=XDQ^VX9;lX zarJwbIOJXae;V?%>s#-aCZy+bhn{7?83$Lnu7Ettbs6wDdOibr>hX=wXB~Qc+r{TS z^|;!_RnQZsUHsM2E?oM*=&64g?L!@dk5m799QtpC9_qgtIQ8EMoN@j+>@vuSv+x{b3h+&kZw3Av#9XFfdX$cK9&KMDFj>OU0v$G|SvpR?V)3G(#kHNff5A7GdM{1JF9{5izo&nm>3{(J>E z{o(pmmiJ7D{!gM`qW<3jr~a+L8ULq&({8uJ?sJf*-9H1T-6w$4?#odxwA<^jdlTeo z_h#U<`?$mIM<7qT{SLc-fF9cYBXHV%3^>a>(qVVNVRs4i(C!Z4wEJV=wEHXIEN|9f z_W}4xyAMMT?LGpWc7F(*?fOyR&2_;?#%Vu+Ka+q@gFjP%e;fB5t-${V{j-3#L(d%G zm!Um&0^bZh3xP9ki-Ers`j-OF0ACJ#F7V;N&p{m6zdZtpFmG1@Q0v>^}@Ir)50zMJ=V&K$c$}Qzu0{P{Tp9z0f0)GeO zR{>7}9}b-BJs9UPjy!og@OtQ}L;f?)-$VX4Kz<`|#`#>}lOTUTaQc6NqyPCR{2T>6 z=K-$=KFs0&y|7FFHvp&q-vvGi`tJii1^6wFdil7cT!E*7)eG0vFt4_v zT=f5^!0CSr%Ei1o7;$60^dZiym-j%=B*f=V=wV)c3jWalk3kRpzW_M>-`n!)Vn?}r z>*XNCjrDRU@LJRh*D0}H{*8KPz5E9_>*X=@pY;DO$kYG3fitf@3Y>X$4{+wyWsdmo zi~OPgF9A;fw>bR29d_ye9l+`TdBExaoxth;a)z)$-BBH;9YPsRUAhyTOjC;fjJ zaQeTe;=jV-|GVHP{ciwH|C=4xyYHahnLoDyXa1ZIocXgJIP-_=wb*`7g`f2QG~o3A zNQeJ7!7ly3894pF1vve`75J38;3MO)@1TEUxww9e<(dWmS*{NNuZRAl9Oe2p{9(Cn z0M2r)13n4*Zv@VAecMqkt{-E$e6JT%QQk4|=MAvSa=EVKM?(+Gbu09+Ubt?p8vjp% zUHX3r?8fo`Na&&e*Fz8e|B|DtguNa$N$v9{NA! zXh&azKP=a3;4IhIflq?|ZvbbxZg-UHTaG;Ry}ld>{bS%yJ#dyQsq4$yg#3R!{G|VH z1RlqK-|Nc_4*w@2f0$SA240Ui@2URzMu-0w!B6`CN#OKR1;FIctkBmdE2G0E9I(+(nDEy@VZvtKq z{dYM0|2*u{|CPY$|Hpw(g8r+3(|@l2r~hgAN&n{nr~k_xdHuw2W5vs_mIXSuEf&T`%0C>Qrfuv|Ux zpXKTW&T?JmDA%Xq56iU-ILmb@aF**b;4IgAN4dCPgXPM?f0k=LaF%PSqgg#0B5=ORR8t^hySDDC;fj5aQeTe`nN|M{?CP< z^uHZA{omXAw?`f2>Vp3)*O|asuDz{)`;ntu{qUdVIvY64wYT+ek2%V94*X}i76NCv z_J;ngPJd)v^a+exh|BwcOg~PX>n(||cj$Q%aijcS(GS<_FXa6!`V}-eqzSlwwMz~$ z{kF)zRLjVZ+4^_Ep}wvkIJ)_|CBW(aO5nI0)vX22Vr>9!-pwk|7U1HO`RvfY2=*!i zs-L@o^Hnr_kDhrKq==4|3REA_^P1dm!9UHw&AUhC8@`YJK*-O5yvbqtIt$#qLr3tX zz+WeT{#*_G^#)Ww&3mH7PxDSK`P#hyUGPH$(4Vc)W8QHoU&$Fw@)7wr=6=)v2%tXl zqh5Z|pOL^1HK6)A2KbwRoA+MH*KY>i3i;8%&3mup>$d=32>G`HUk3bbz*hku1N;`? zZwI~!_&b1a1O86nJAoetd>GzibvW=*z>ffa7;y9MZ25W;a5FX&d?xUe0Q%Dj+`Kza zzB&*1SR<@{E(dP<1o?V3@Ntk|4}3iEhk;K3z8!co@aKU~1U_6|Y^6RDR`ae#`TJnt zM+%@n4Zx2wp!zu(_|d>;0e=thZs6|)z8Lr<;46S11AGneV}aiV{5as7flmhh4Dc4< zyMP}Ld_TNj>;&NTz)jySUpE1t3i&C(PXs<2_%z`Cz^4OW0{kT4D}kR3d@b-(fNuca z3VaLjQ-SXQej4!Iz-Is-p)Y=tZ!>|927Ws5X5jAwJ{|b`fzJUx3wRdz2Y@dH{z2eZ z1OE{4b->LvTE5;0{KJsn3j8C$p9P)cN5FZNSF>p9}mb;O)R$fp-A! z0GCc;I{zp0=^0OnZUOJKMVLy;N8H74G;d1`1AlD1-uvdVZi%< zPXcbnTJrTw;Aca=6Zin|^MDTmUk*GAd^Pa-z}Ev`0DKE@^R89-dMEIOkRPE3krJOp zz()f=7kD%9j{=_#{5;^Dz|RM6*071)j{!H&GzEWNbLDHZHc9Xc1kfL|c31Gl22?+{ z!S02?&0ZCe|2XhEbuSaI;2B@QZ*?hMrFXH*=CA|0&>R?nv;Z zz?VbM#lX#80Fl20_y)*-8u%9A%Yg3$ekt%_FAx3@{g(kZ&twI^9JqN$gW$`7w?fYq zz|CF^k-rkSdH0aup8>uCdR728b6Fz)S>PKX|2g2>fqx$O^T1aEAF*HXhv>fw_-No? z06q!$7lE5K|Dxw=;Qf%l2KW--Ujn`g_?Lm-0(=$l&A`6`{2Ab11#Z@yi=STuK63xy z55ZRhZvg&v;O3dK$bSR)9LQe_{5;@mfUgApP2lDo7NY-Kz|A{Z1iudW7U)?E+`MZ~ z*FKLlR~d<^g#flmg06YyEUZw7Amf{FfHfG>sot-#G1 zA(8(M@b!?t4fqz|>w)h8emn4C2LykJ{yTt=0)8j(Cg67gp91`D;2ps40lpCUy}(xh z-vE3K@b3cO2>d?aTY-NM`18Ow0v|pi_(S4wKk(7O9{}DA{QJOX0^bC@6ZnI`mjHhV z_)6eE0DcSbhkANk7Q4~fHO;A4RQ2>4{+KL$Pv_+!Acz_$Ru z8u;VD*8%?t@P~mv0sL{`TY*0d{HMUpWR{foN#F;+D)>Y2p8;E178OGY2d4X{}T9J!2cKcX5h~Ne+KxkfbRnSYvB96I`~84^Bdsxz;^&| z0{&azt-yZ=yc_uMfiDIAEbyy={{i@V;C}@EFz`PC-vN9l@L?l^Kcu|R0j~%CXW&Nx z{|oR|;Lii^0R95-#lZgxdd;Qs*r4Df#f-vxX(@cmvB{2}rA z7w~%E{|4R!{6D~3f#)`->hHRN@3T*VuoU=r1pX4>`@J^s zLCX75;A4Of2YwXrmjRyzd_Um*z&n%;-Cfr$0p10CC2;YnUi~khhk=_pdBGnC{z};0 z4g6KW8x9m!a6k2G;2pq60$&OIHNYPR{#xK>1G4yjAn>M9IkUO@xKY5527VCm4&b88 zwBaSdUk~|9fgcQfHSj}#Ul05Zz&8SaBk)In*8_hB_@Ti60Q^nBhaFUi!<&Kc58OOk z5y{cO-var=fxi{_WZ-WDeiHC8z&n7y9e5A$cK}}k{GGrr1%4Rt)xZx2em(FbfNuxh z0Q`C2jlhS$t`N^A;0FUA2mCF-#{-`Nd;;)OftzPrVzCqWM97~F{N2Ep0vCVg1a8+| z0sKhFuK|7(@Ed_24SWl5@uyYme+u|}AYb?TKtS5odx5_U_$1)fj`cHqYXpAP&u z;HLwh416K*7T^~GKOXpM;8I_vyw?Li0rH!HPXYc@;8TI`1}^e*bUgPxxDdA!A%8G% zDX)=#3-D=>KMJ_S-^jNBH_uGPVkdBkzmY#1_({;e6u89G$X@~cWXP`pF8OBUZv=h{ z5yLvThO;;O~R{8sL&|8*m5Ezm;e-QW>;2#1$8~AMC3xR(a_zK`@;2VIq0e>ENJMb}Y zEcn?0d^Ye5@a4eI0DcwldB8UT?*#rM;9bD$>I?py3A_pTS-_75-UB=fychWS!25u& z2Hp?+df;aR-vV6ZH`E26r+^PYeiv}@XG0)fx6h%$FOnyNkUtps1?oG~PTvCDtmP05 zlYn0c`KiF??<11IrvtdyHe-Sw;O9X87T^nk-wj;k_3c32Gr-S<{D?ON_QmE$fgc21 z^t>$)tD6E`I2+_2^*I%|$WII4x_;p2L;oV+BL6`xzZUofklzY?G4Q8>i=F|kXT+O> zUtXksd>rye0hjOAy*Q9-0WNwz7r=E3fnNkYtAT$K_-5dr0{&CrqW{}k|FF@)FXGEm z$nOta>-z?TER5xD3vW04)e zuY~+_z(xKe`n#jvS}50NAm0L9l#OEuJeC-=W59B4_xG@Y57^ezYh6s;NJkg6!^8kR|8)Id;{=r z0^bJwTflb%zYh4QcNEIC7I+iz>w&id|2FV$;5PtY3Va>#)xd8Az5)16z_$Uv8Tc;X zw*YT=XQ5oT0-p$6>T7|nuPpG}AioOudf*QOza984;CBEYb6CNjyMU*Fi$6FH{$hZp?+F61Wy7x{O-IFRcEejnt| z1}^ePYx&i{zX$o@M-=RC1YQsPe&BBhF8U{H{r$infczTZ-v@ppaM6?1dUgTd1o?g5 zRq#{fuh#NYfIkTNrNAEoz6JOXfDdaZ=r?_yAg#b3f&4PyKLox8_@lt@0=^meR^UGZ z{xonY??w|J;6H}^eyM{0j{zS8d<*ataM8cX#1r`AkUtf;$eVSgoxnwYPT)q}*}z49 zv(~=?_)nn!8sH+oMayph{siP71TOMhwfwWdw?h5};3B_G%a3X-#OR)`DeBKYTzPo{J9>u$nVthn}JLG zjr>o6i@aF}yc4*@)5!lFxXAC)`bUfnJeF?l359P6{;WF)xXAC;@(sWxo<@EmaFMSY z7AR^3F72gN>;C|7ksqez`+-aT8~H`RMc%A$UJhLHd9&7k6>yQ?PwQU?T;gx!ZwD^& zBeeWx;6GEi`HX4`ev`Ou1AZuQ(KAx(=?4B3xPsm7z()gr8u%pO zzXU!NxcGUb_H!ZdXCQweaFIVr%WneyE66_!{MW!ojW78B8{kdAcK~k%{#)SPz<&pP z9dN0eN&5!&o&o*`$nOIFC*X%oDEPS(_&DGa2eW?tJmAkkek1Td10UU7(Ek_U{lLZl zo!b9Jz{T!19sjMs{|Y@%0~h(-T7JyLg5AGCJ_~#o@biI-o)Oxgjllm7`4R6f=>G@s z*}(q^d=2p3z_$bc7x3Q#7k|w9`=%occK;3eqk)V3a_#?O;QxXA#lS`W7A?O4c%4*? z{yYd=ix}yRC5#0y!qk+E&_$1&j2EGvZFyI#g7rQ1;)&YMBjgWp@w{~E}j2mH0bF9I%pHfTQ|27Vyq9|tb- zleB!@q=Ma1kbfC)kvID*Mgtf5{(xS0IB=1lrS(q%eh~Dp0RDR5*8mqi9a_&0;0Hs# z>6p6QN1!(VKN`5`IY;a123`;O`M^c~5-qV1$v$WE_%MC^^7?-=Vq=8 zcq`=R0Dl|swZP4uKGAS1aM3^crGehvz~2cy`yN-YEApLMehTozAb%=wkzc9huLk}u z$bTKU$eaBeJAtPl|99Xbf5`B_zsZveevXCwNx((^0xiD+_&CU416<_q)bh^&9}oFI z02g_)xwg5b;Lile9|K(E8(tR3Edws%t=jHqfs6bcEx#T3kMdwC$Y6!?3g{|ewD|DOE<`E9@_LH<|3MSi1}Z#W^~iRdwqp9oy!PuxF{ zTLSzz$X^Ovi4ZtTu{z2d(zt1ZI{UfIo{Aq#wA;3l6oE6>){CLQp4P4~+J0Q@z z3it_-|0Zyeze3Az1wIAxPXibE*NzDEkC});N|ZK z^k#sIo(8RF8SvAgXFc%u0pAY%{lJG$FZe$Tcmwbc0G|c?gTNO9{}Avsz-I&B0{p|k zp8_uBoutbu&x8Kwfp-EQbxOhiF5rg(7yU1LZ6G%VxQMSiJit!{F7mI_ z^2>mq1^w%QcLU!7ya)JGz(xP@TK{g~y^!CxwNNgRpQ+_X1Mh?U;lM?Ho|c~uydUzX z0~h)ET0RT>Y{;JvT;xBY<*x=l0Qs*27x~X=`HjE_A^!+)kzcLlp9P+U{0qQE{w6Iy z=F~#m%(EatQou!ip92HA4&u{7|F7hAH^3MSO1myn! zT;w~oeDjP#dCjvjL5=|~^3Q7d#lSCu{)>T&{L2ms^xg&hlaSv5{8PZ611@@IX+2Fd z3w|zz{1o691D_5265tu&qTj4DUIF~mklz5@oNXeWJP2I$d`tVe1Nf!T^Bi!IU$5my zoL(r`WspAzxX3@C<(q+D4*6q%i~JTXKL_}7$aeu3`Cn@JrNFO%{1w1Oey5gS2mDIN z-ws^l|E=Y>0{;x;p9U`S`@JrROWpel@mT@+mjM^~*J=6Xz`qXptALCA{jU%7ZUFub z$Ug{NG23%Kb2tkyr~Lxnip z3HcOok^hR8pAKB)O?giTF7nrF`F`McLH{D)B7eJsML>y>W-{$0r54P4~Eq4jSCF7k^5_v)So zF7h{N`Q58TW-UJxxX2rSJ`7ysw`uu>z&Aqwg}_CA zhn8Oh{C>#a2wdd%ePd9bZNNqU2=$$Oeg$0Q-=yXD`$+J;sLtuv@~;6d^6%C1lYl<} zf2IN#d9z-;6ZrQbe>QNDKTqpl349ae*8+bK_^rT2&(&H_UAj=Nhaf)&xb%l3ULDBQ z9Wl75C)+kx{mc#oKReBD1DWo&BeI!=*}5Y-+OlnRN6Z}@tjhsMq(6A_v>DlP?b${B znW^n9%^iK|bGkY*y)EqpfpK&D`UbP(J2Kg}uI|*h!Txl6-~8TerXxMKZ7?&TBctr} zEoxa%U`z`rsj-8Zfv&dhu5;V6U46Z&v0|mGBR#liFq`RVoS;0)^mZscf~UKB&*;nj zrX(6tP4hC@bVp|H{CT-AMEgLWc%O4w>u;Rf){$=OU6gKb8_YJH)7h47Ss>+49nq}B zO{vQ_}X2pLS)AGboaNlpVd6KtGA=8ci!OG_U^7!^9h;kG2PvL z?QJTkCuMs21{O`7+tRY&v}q^LNH@*Tc6Co|Z5wFonXHQ6(mHKHD?)8k*qEA}>CR*` zN$RvZdGd_xgmk)n;lflZrRrj^t39ovugW#GeMUBwYVT|tNM{Gyy0U{Rw`R1df8>*R zxrW#cdnlUP2721Yp466|+EJTACS}0tepd~uC9Y20TTEyhXz%P=kTD%is?YQunSrS% z&uB=e8W;9-r~9;6%gH+RQw;-|c>|fj!CV(}Y}=yDU{_o3XdM*%77eAza2XS<7`y63Y9<<}1pRg?FXee~ z5gn_ppW{3Gx;s=W>uQZICwcW08+cge$<(qGDf0k-!?`|6$%wOy!jd9_Q zG*)i|&FVtbewMm6wVYYF94F?!Pn-32J=N4TnC|cEUZh3_{heLytfHz*VEVI~Re&*2 zn+h=6Yf=G5c_I}MbS*W@|I+HK3w~+cRfWE^>KX<#|`s)t#^R~02w z%nFh^VmLG#UtLe)r@gv}m3F*lp~)w=XM2wq8l$}ip)sl}X_e(Vt6DV5By4(xF$sf7 zcBZj{T7x`~WjEpMk7LuTGRrl$I0j?1l+?KXfxda_p?C%rKnm-m7U+;otb)KYn;^ymH4mLmQ>)*$wi~HTHCEif9z7tEd;O$Oj+e`3|hu57;IaRX^|x+jg9&#bcgPi)#|TYuMR-F~6s0 z(S+W<-ro7$-MpLxbz3Z7Q8GtOl7R4PigScR-iv&-i)1HVd)wd<8d z^V-|fnT73{{%l$;WA4t#BA_74YG~AwA!V$o0eTSkiv7)Nuow?t%F3>V46g6yPTiRi z)#{DpL%wc`mwHc>8wRxmxvy7UG16tMHbz!<7MG@_CDkaa!Ml0~vu(ZYs*7wnIW-|~ zA$`t3TYrCMAX@0X$+<}6bW)dzO?1_3(MV3`U~(B`)(b}a@LC4bSlugY+Sj?tYdSPs z)Pwc}8g&`P5swq9>(XZTbY&;wT_kp~+qK=k$+l>3mXzX%$2F~OQ=YxEwtc;e#4dKF zL~c8iYu#m4N4!p`#>*Mr({-Mdf06iAUF#2#@~%aJI@&Y)^Qc0DkrF19NtL;?r*o;cUPoemvU!$UJcH9X&bd2(YVp&gmWl1^@pX1! zetWj%%yS)2c)gXIyWWJA$7ukiOzN3PkK)9!7+n2J%p}&to@Lf3bYeq{Brx@qWD$y| z|C~c3e`n1QFnMQ-HCrMZndd9FXeee7s?{6m4=U?>i%Vl>bj@SKme9@a5O=Y)aV`=$ z*LAtryqVDr$EH>pl-C>ax0W?+tnQUH?dx15an882XyvZLpzmpz>>HFP-=<=7b%zJ%8}g(@-^DP2N2REaZtI*DrOb0p5OvnYCrsBs=u zXfRU3gfgizclLBH)z<4stn)LvrMJ~own%gQ!v3~_!HldcPs`SamebVvvEvtH+OvHF zQ)f&_t5ZJJzb!4Hd0;(nIzf(AHOsNpxvJgW&hb*pA{#BL);m5}F{<`asWW49$J9>D z3=H%Q1c%CY^`05{r+l`kZ7IK!GZFokv4EVKS~$Vh9gAWycNoH_*19!Dj;f8W_|v^o z%A@c_ekL1Nt7=Md@YNr2#xQ!~_b)}KS%l^I6doULlM#uz)nzK-I7 zQ_*G%b#}8pKGE!lDN%;Xt*CtsatLH^TTiB@cGR)Uxx*%dqo?hiRrN7z>YFPaPg)&l ztv3gvLDa7Z=;pDWa}icB&+k!)r}amQVhWd^!E4^D=UkuD1LZh1Gdj zT-@R#ORl#zyBM8UZ&xp7i0JtZB#D*Z5m{BoZ#0%NB8S|oXJUTo8?Kf(hH@Jr3myMJ z=8VihMr|jlpxcaX&b^(~<4O?MTB=Yu|I1BWBaJD2Q5%Z*rK-Au#w}8+iVJA5ji7@z zm>En~T-6bE<$5c90W}Vk??Z|$RN0A`&efQ&y8IS}KG?1*ERE1OLf;ZqsH4p zxiaLhYsNzPdJIR(S(A}njpK6n$xaI{`JfEJ3t4h6TuJ5MqLTZw=>046d%L^N%5*OZ z%?ap*XFNcmk~s-%hPJJsO5RFQd)D)BMO&^L8`TS4TGe|{avNB4o3G!OJJqG4;+1}1 zN?B)8<4V(8;cH>=Y=%CB)XOLe@akSzh)vkoO3nmErK_JV*V?qnpP+ zWf+AQb!xwh?v7I9X5`)xIa3{~7aUAgdH@`}&{OU&`9jYmH0N(w)e%GS^p(D`sK(RM zn*BXZ{2s5G!X@rZC>flq0Muc#>P$7v&^VU`Sf16Y`72kGp4r*k*pxN{kLVNUMC=yj zdjdraJwaE+OUZd|mi9e!K|{K?sUeX9I;-FQWGR*R)XrK+anl`APDrRqO^U4;^&R&CVLA2=IoXK%^wE`IrZ4JX(` z>_O9(d^I&|8;o@J)+(7?73?0^Ih#i)Q=RRv0@apqC8^$)2o>m$pY)+nm8g1mu;N>@ z6|cr7EfrS6qPmwTmEW;5uF@-*(}1NI?(uY)F41YkRy|HDN#sK``}})>s?oWQUW2>!c!o>Q1BLGSZDmNM)Pwia+Rh24mC8-27^lnuIJMX=ks7Pc zChlIOb|swAHorSt*fvpkp+G$I@`{&0x2HswRQKvsHGQGz?_s4P*uf)vlD(*kjukWd^(2dQa=>n3qvA6Y5O_ zN+vhuIx$!1$!*!Tmey$tS{HZ}DOtmDT3E!QM_t9yUtCF5#W7?qm_duT9=3R0Tz)~U zd#$Qv+^R2DH8NT)u!H`<@Z{PlFMg`Q@OIsAXcO0 z%24Q;htjky9f#6>QT6Gm>(ZB3c^iUjR8%xVj;Y4qgG%Z<8K)DrY(~kYBeh42CREE6 z`d;D=sc;8YI%-mY!jxUOnT4)6wtg!$zG$Q)n{L!NwUPok1`ww98#=lM<^3t?t~2z3 zjVXE2TiZZSTW-h0)R}6R?gITTtyVP{X-TVvp%c@o)YQQl*^c+=9lcX*Qt74+HCjnE zPH7vQks0V}>+U)?Gj)bVR4p`BHV0+Vsrq_Gb2@BsMyes5`zrtDw3BDdOsB@mXlO8# zRZCaZn?00Y3L7`Iw|yYflj+U2_H}o)FKQ8WDssoC#}-z7m;xQqH8{|AMC16TI8{9|ak&3j$F9hrrxron9R{z-L?h5CD(dXH{fx16|jiqeo%(p_clK_6H?hgiuE?Biq#9)+M6||7gq@mv(P;j%c@3|I8nbDTTPx0whwgWUXyLvsHR8Rp{X=2Xks=as|MPZ{eJ4W zn)Xt|@0sbD4e6OFHPBS8t~sp+Y~#|_NF`~&QrAT*D4n~Ls+umd7R$OWvNrb1mD;k; zYlzC5wB>Rob;h@Nf-0d&afO%NpZz32+a65Tn z3uwF+m~B1<)d^>J)Ih@7ouC0%cGuKI zA{Adg-NIc%B4&N^&Cg&Y3k&C1R?BgGrp)kPh?b^%aw9zl4{K5h9m@g(~n_i4Gzr6sxQ?e(e}=^0eJ#DA)QuJhVwHmb6duzgOlh= z%@HcYGqS0au+!>5)~@Ve&KKiSi+YF~s@OsatC|KKpU#zAPIgvPn#zaqUA+T|T%$OJn7jw2E3%SVUVZI$7EN8)Rnf-RCb)C=aA*tmt$|g~80V^F%T#u5 zl*u}oI8{C6`1a0$zTUp(j`;(*S@Nmf>K-lk>(uGpsTTErL+&G+Hzmy)(lgZ4lJ;y$ z5^S>|u`xJ^{hY3Br|v{^$2(h6 z%~wP8&e)+L6?rTZ-@1kCv>SbR>fH7a8B#=CwB1RVwLM{WV?$SO?#YvhaPFECzmN`o zEedKkRjRPjsK$RJ9S&5qHl?2l79JMOvFJ>S+ODofJtCTTA)~{!>I>PfZ?r_=rNB9H+!;8nw>uGVR-)7nGI)a72k7{t|axkuN9t0jliYPj6nr&cg_r@Pc) zmTmIRkyaTK%fw5_c#z!9>J=sGJtJ!LP|0mtOH1p_wA`rV-gFW&V7u8#743^^pC8Z}5G;>_9Afb%!>ZL4nv0jJ+>^ucJ(-@qfkhMA+RvWfHISLwk&8|EoMk>_oG7>L z>2uU7@RmhJE|^hf*gN~ON2oS>j531g`TP!V*YM3^oFu z0-~8dqND1Xa*A_tbc_}ktm>(v`9yB^6TN`99xvTIJCN`$!05GnYV=yJAosOA7tT~; zZpD9}da$gzq}14+zK*UlR4wNIlxplgZAM?~w3+!@G?kI$aK+;;SshMtQhHuSy#=OM z4KA|j`Mq6d&sSrOzCklw$#=hc_!=JLyY4ts*GT-4CW0tSU;#tD6J#GCJT_|0Sh9_b4GEkX`QqM`$eP7o?l~c!shrmh3 za7H#)DrGT7gAe;Fb2jRQdeX+Doxv%pGnkfp+n)NZ#W&W;-HF5~S0rH^9hq+-Do&Uf zK8NdqxpTbEol{h`hT5N_7l_>EcudWdyz?46Fuymlj@;!$bMA&stwk@~!^!iE+9!ok)^`0KvqTH4)+16xU>zJCVf>-&1>l1TR?dsp~4P9>D zQtdeF%)M1%YU=`HW}5O#ZD4a;Omma#s=4R-M)P(^Oe?GGY|gE#PiOn4DorwX+o`PN zem_|)y-ulH(Y}uKKwIy;Oj^F_>Yb;w9g}WsNb9|P!IvGmZ_QWg0jqk6-9Sbd>hhJ_ zv6fReA)POTd4@B6ZbM7(e@fc=M0E)ah%G&*P3sBe*#AFqXiTX<6psUBPQRt6N8OXF zifPD2QqS`@rzL`stO*)JVHzOeC1L*eB5Hj`{)7_0=hD1f+9n?gcM{3!O<6Va};*f80p}pa9Jr6gh@f9|wnpc0(6l$%l6`FIB zmTdR_>PA_;k}9p5R8RWc%s^jm5=Y(r&sFu1zp1tm1D=u2rB80hy&NDg*K#*(UiX!s z2`Zk0D5)-#61*2vcjUpaa$0*OX&<=@QDZ`-F}Iqa-3$^--$+IF>g(IPiu@_IoiAE& z0m|K(=C-HgFZ!I5Q-g4s!D;IqOic*R7wc)us&SCoeAqTPwL>++!jT9I)SKEH)48Gi zY17nZHb%I-&aU46?zZ;a%%Ug?^h(83jhcASorlNs($H>UHQ%S^tj89)r}Ub2X;H=T zAKQg2seKj$nXFoda!%yVDVO}?)xjBOb@i#uw`~j50KV;P!;OYjJYEU!pYFaV(zFd_Ls)Zm4ht{I&$yAMs$qH4i%sTQbetugBlxqAw<7-~GD!EwYFLm)|4kOn# z#|&HHp}K9QoFaunq_1xkl_0m^EQy&mIXFnI^qZ;_o|v9-lH8x=E{`Y5wIZCbV~?9Y z75Bjv+?A@G-ZRx?mzsGkbZND>;%Ev<7AI70D7{e;vA9v(d4=aBtLe$g8Y_RZUXA&Zz1u`} zjXNcG8cIcvOLH4I)B`}Nrkd2N`P$X)hoJHYr>Yf~C#umIx{xK>AW~L|it2u#~^Y+Lpl69nH7nDlrw?rN%i@{D*i5M8q|65HsR7xTvEj@8@tEjar zl~hWX4oNj($hXdl9q39nBg)oG$Dti;lxN5Tsq5+V${V= zO+m=CX9btHmbBWBs{WI~MPy^DZTbbCg$8qb%#W_z?uH5jP&~R)Ra3fCZD{H3(EX}w zXSgkDsUlt|0rbRt@tH&u2i22#^<=fLSB)SW(v9OXa%g0SI-pXfE!C2XGx~DBb#+WN z(`2O{2diE#)u`8OX4`t(Gm(k)@?NAP=Zo~I^`Cl!vGTG}EdW^9)1B^X8))zBT99ek zbB-0CxnvwGoL8jls0I;Bjmtf^C>$uQ0+SD%dK46drtr0@7_}xK(kbYNDn{NMRGKP| zxLWLGPOB*dy?9166-?>(%{^0X(M`*=t-RnSl}p%!T5Cfsu?(i#_J2IRccqA7Q?ia9wmO}dm_K_dxIl_qAWF{KTu?If9jjA~6a zF4)-iZZ)Ztu6el%c808E>Je$XI(c=THG);Q0&`~55VZowJ85!lAi?A;VWtMDS;AVX zkT86hR!Pe)VWqKPCAqXLVJ|hdWKx#yM$9!P=oSMj29s55-F>#aO$GnqJtYEs`Z3}vA09wZj& z(AjrIqxSr;&oO#a!_u&KwHucfc~<6rqPRKikvoSWaG~5iLgFsOin__nJs9w+^aGY2K^E+^)1oTut_dFD1NbPFwa zhcnY>7H0n~Gkgi!3C&Enq8qsj4P8&;bYoRqG;MhcO9gO@+l(G1d>sQ3$rldxN#mXYLr(VN9=B{ht6wd)O z`mJK9Q2v@;BE+VH$yb(Nlp~20(O2tKs^kJt>~;PEkdHwqIcn0?$MnJE$I$o?t-ZwW zjAP7{xV)%oEQ*_JJ|_wn-XVxYOdp0e4yHEtY$RM>#EZpXwrxP|LJwVki)Z&6#|BSH zgWXK&F10c}(o=835tnci$yc2RJAe&{HDIr*ftUrHk6 zmmUj8;xg96WiYKyb#tGuU5?o3T1gh&5AHme+xF__8tyi?nJcm7+(gi_uq$O%RboL` zDiY3=Je2PUl2ct`{MT@{w~X)Y%c>J2a~t-o=OF8*UdDJ=3{5%~9(8MZ4R{T!)?%%~ znzd=NRczJm-kd9;7V*l-65)40;0%o1*J@j!oQya@ox3H6y{eRHNvBfj+*vrebGFpv zx^3&QBB`Tbr>5n*{MmvzLhhC4YF0heaU@zW|Cd{!fXBxwpxPFv3V34t0-AOmx?;Ev zCk?VTa=?gxi->dqmKRF|#+t%)Vj6O^{l!0PBaZp$m z2))~laqZoGy_v|RwH8j;U%26Lz_c0LwJ>fyTNgb0D7Jd6`{v@chvr_cxm#W^piXR* z(~1YX=JjSe)Df7)Z|Q1pIkUZ`v9YJEt5@}`y=uv_I^j6?3InxrIZ_kG-%#h#tOl7~ zYL#_ns=Au0f~uz|xfc_t&3rL-gR6ahVXtHlxY-Jx`$dkxYn_?y4)xY1Gs2aSDjHwN zC4OP<1W{Ro=;NAYW<$B9%9wXbJCr-UJa-_u0?hNJnKN>iwJ903oI=g0WTsBlVo^E*QEb=auo+-yS zrn`FjyK_~k&T;e~xaLo&vQ%V(77CsR_s*&2V^s#qxvsr~>af`}+U9r5t4DAimm|MC z=nr6TZ+(;wpA)k))B!233Jm;?sljPEe^F6K^<@UmP-m~D z%gqtS^r%A35l>4k5h}9^vHWbb>hjA)cu4F=N}aFQ1SaicR#+0x2gH=KES8KgPb5{# z&aZ1USlOB}F{(&!#LFt`IsD|TOu!Si6e)>`OHr@VS9shrqpw`f$JF4oT((Bc#CGy^ zZPy&}G%|hUxP2*=&!Gl`2p2t2%a_qI?2KIz#oa)~rlN6Z?CtB7xtH9maw>(t%4KnB zX2g=osj|6Iy#6+Bgep-BA9GE(Nd_CC^Gscr-%?Q_b-?S6lMFws{58=ONEli zyoXTupQAgI1k}gzIsPoHwGicEZi!M77UPtx>e=0Lmqw2o z3eRyl#v!?A#wlC;7{<0-)0*`2B2ENi*RFNyHMzDIE}6?*oHA8jt5&N+TBB|c;*{K3 zo3>|~$yJ_1dmNAB*OkpkO{>Po;QP$XmPco1y%1O`Mc%K{E%V$n-A3Yv(Q4Hd#}dUF zdW+8F4)-0Ut_reNpR=H8vl*4=$bus&(1z z#%ojZ$Sx*R@A+BXnwCAb`5`KO5c)k-cDwP~lsrazkN0%3roBM8B@DewF%q=aPL+8G z%#9AJXR4xGj%8?w(y@3Vx~6?lq$yZ!*QVT&^a}R@wN9?+NFd@;@$;&hRz*D9NmNCd zTp#+dm&?MT_o!TDROeBy+Zs2yEjzzw>cW<>y=}c}(%IY&1WBg9?I`}%%&6><;cab= zmr3kojEAqOv92GrG+m2QM{>8qVQod_j%|EMN*=zV)ULiG<+huyMX4jbr>XD4?Q0d? zRYh44aVgyJhT5S>^_UnHZg*%h7CN+^@xLmlu)KNrfqq4uX-HB{qIi9xG<$QoTNJTbGdJ(GLe zT$x1{#eyCWX4O*rOc~wowJC-iu@_$6XinTP7mr|tb8*UBA1ui3AKktx*6H*v)f{Xz z;Hyol@ytt~+p7umC)kOTTS8k|xKbYK+&&fCwmf*UR8;7|TSbcKmmPGeRPHVJoqgRM znSnB?XqAs>O%=a%zO=Vd;fOw0=9%Fla>hVvYOS={igh}@WA+(0s`1QApWCZk`Wb)1 z*=+FG;R>?Z&`PUw`&4|aIBq?@{a<;FZqI`5%4k6LRv5LEmqNE+A@im4#asu& zFF~1WUJ|h_&i9I2O&?+GHxa0I!U@RzjS( z;E1%`@gZeu+7cI=23W4(^a@v5D^mquisr0cR>DFBeyr_f4z+Q)1#5cNMeexA2lwVv z=a#!yi3*q0=U$0v>6-MJG(IjQrC-IgWI1MJ$Eo9nyE9W0*#hcQ!WvkPS<+YuRapg8 z7JyniR5C7QPbOi@2!td0qJ3M@0Z*00QXS&t=nu>@i^vM+jDDI0E!v;C3O#=1N%{;>L06aI#EqhdSR`Za`EV&gjei)}`LBl|b@@ zPA*BrT%k;rRX}n6s$D*PNhU|{5|avB z#fJx)naHwNqu@?GzeLC7PGZ`V@;JYytR@~)d%@$%dYp1ss!$CKecw_e2ZttZ`I_2W z{Tb<$r{A969JmmEElZp#|CUgy`sPXItU0hB5E<`zY&lhKU?Fa>HG*ChX zew;GI*o0)#J-_@VUOzJQ9dGg76wU#vk>}M$y1469{sv<*&)#h4<28)2@Ct?!;;M#wzfc>I*(6)I-}%=BI*( zzK1BzlYGzS%#*kt4pHRtl@-^oN=FbeuD@Y$qY%_1GgK!ScV992cz3%T&bvl!-Bo4% zO3cW4dzg6SOkc7$XI)}G4q5cP>$QfN=ZanuKAHoviw{__6vhaaKP@FpjvStD9->7L z&?rldo@P;&Qfw{XN-Se`r=w=clzsDhXp+r3N#Rr-o}x?6tw`4RIo4>lTAGMiwpyC6 zS}gmS{H*1-Hs)1Y0-+9O$Y-JDH6Rv-Gwk6SHG{?YyQH0}ExUqa=V)oSOpO|6?OSl2 zj^%6A@GUiJzDlr0^C~U%!x{~5)hW4cHJ=AzR_u+WP7Usjq-Coy-p0~M1#$C~eGg(u zN+mm|;s&Yf}2{7NOX1udM7rP@-lO~+=mNRnAD_0IRVgg0ne z8hc)UBJY6;8;nRiZBac4Bb9W@QX;h)70o8}QmTp#kt6M=D zLsy(`(aTgQE2@uCWi=en&3ukk@20CNiyg5%ydA>c$7E5V1FF=xbQy6frp$ODp=3$a zn*?(rPK07C>@d|<7|6t`w(4`bGXIM+-tzG5zsq|Qea}Wyee_*DO61}YzIcUNRmqD$ zl}7T7rKFL{@~F6+`8+DLf>1fDk9bY}%!jIaKVw&#$z5m6N>*FdX7WX@$V_oRV!3jL z>c5so5-y3UmqMRXld`zX#4Algt-(0q%)#p0LybMnhigxHTHF%yJ)tvu_HsY>zId7( z-TNcz^3*q`<{gBUHJwO8R^nFHya{n{@BuGpFP;J^n*NLq)?-Ja)EfJtibO0Q5{pD= z`GlVADwU{7$Ds-jY8-`FHIY!euty=52bD%4GITfnLwFES!)!>_hnhzsR(({K5wRl? z%ZJ1wVZUu1%8aPOgBnL6R!t<74fZG`=0U6}K-Bv9-0_Tq>5j}`cA#%jrlUn2(b(7p zz-QbL%R0&$-+HAP5M#tp=>%EQ*H6=H7ly@EdzM(#!dJDbJ*%uWMQSr~zbcJbj9z~a z#cU`%ix;(6y#xBD$cdF+EiO5036>6h-w>28mbG}Li*YX&T0s-cu_acWHFco2F^E+S z33Z6pN{Hn^r7?)~FX0i+-qP+DYHU_a0x3ZQKF9wM@Q08hB zvyCJ@UQWiVnqJ9bM#k+!r5PF-YlgbksvWB=Z)@&WrSU4)p!QI_YUtKL(OT2=2R|50 zx~9gr4fM37+tvHx((0x<)7CRpy|(7G8GWrY`dU&c;OZG_uoJU=Fq<0BznWc-SHpO) zz-;pSj~K|DafDi#V_t(EV-JmsYSvYz%r9y8>*XUlW@HOnAWQq2p0{veTD|>Yu&=kR zyDPgWy`Z7)i1xmoo=mSA=lAwyGe?|o^67^UX4~4&(wZ`z=`#k}dNOrK%p2&N-(Q!| z=fp?%se7eG*CdS%*FUfPpSrr9m(|q`(|?9Z z!Cz%(2fx9>zr=&z zY~g>}gFnf_U*^G|V&Pxv!Ed$jFZ1BfvhXkW;Low}mwWI#E&MAy`280Cl^*2Y%p(L@Yi_o$5{B^^x!vG_}}v2H(U7EdGIG$_-j4* zQ!M=JJ@~B_{1@Jos}g{B<7uP7D7=4}QOef0GA)p@o052Y<1Je~SlysfB;5 z2YXw-r(5_x^x)65@E`Ty z&(?g#Z?gx#)58C;2S01!Kjy(-Y~erd!Cz+KKjFb&Y2k16;IGzv-akC)!C!0P|ICAb zi-o_Z&-U}Q2Y-i!|0@sv^A`SZJox58 z-$=~=e$-?Bc%*(nNd9>q{4tt88urik;7_;kKjy*jxA=d72Y-o$zu1Gn(!#&cgTL0o z|F{Q#gN6SI5B?Sle~AZwhlPKU2Yt^XD25{wNFoOCJ2gEc`Ef@F!XLt33EKE&Q)|@H;L1uX^y$v+%#>!C!9SulC@t zw(!61!C$ZW?Ef$G=zlj_?0>_<{#MN&jsE*u5B_e8{WTu^5&FiL?dO{w{Lz|E|G(wI zpJL%(=fUr`_`lYJzgY8G|JQre|1t~z1`qy93;#wB{%Q;VW)J>43;$LR{#}~S{JGvE z{+liQZ+q~cvG8y3;P0}Of1^kFhpBsg`LO&lrj2|38fD?%=)pfs^O?Voc=+FJv44|? z{pl9_TRiN~vhaW6!SAr}w|ekpt+IR=zb8HTveq-q-{!%WwR&Ox&pr6E)+x;2?!lL} zB4Pe7J^1phT|UhJn?3SJo>hhUw|MZkSopVk@ON1F-|^t@w(xKB;EzzT4wrwu2Y8%e7KIw11}uU-~Nfu>5y<@ONrH^LMmI{B~RTZ}s30SF-Y< z{kM7WrLN^OD)^C`ziIK{A7{!H=UZ?M>(=E2`&;ZOJAZ`OSJf074(n}t8qgTKSVKiz}> zyoLWh558&mEdTpG`1@%h`@dNp{DUq04|(tp(|r2>VGn+@CbIwfhzGw_^ErMT^x$_` z{Fgo@Zu{@I*gwaEzr?~{?A7XJAj{JSjt3q1InEd0eD{4Ey# zMIQX^7XBwa_|IDSpYq`EvheTr82=30KNvV@HM#58Js$iK7XFnU{vT}N-|Jz2jD^3! zgWqJ~f6>GLNf!P!9{lMR{+B%Xvn>2Cd+<9f{8b+OehdFA9{lqx{I7cOmsyiH(E&S^}>~FU4zwN=_X5ru9!QWxwuk+wPulXE5 z+~*O$;jf7HpE4$oJAN2x;os`Pueb2Oq|`g)eh@apO0}!r$M6-(=yx!h=7_!au-+Ki$F~;lZC} z;lI*@-(lgu%7fo;;UDP1KhMG+<-uQS;UDC|Ut!_D&V#?o!hgL7f31ZtbJB71f4%0j z|3Aco|FFgWk38D%Rtvx0!~QcC{-GZHofiI^JovjU{5N~>hwDQL6(!$)zRiO_(!zhc z2fyCJe}@PEFbn^k9{gqtU!IA?&ELru{^1_{Rtx{f9{D@l!f)`f-)Z5G_26eM{0ScX z#TNcV5B@R>|40x1N(=vJ5B_Qk|2-c3b(+uqZ;}Upqs9I)9{kM~{;?kXZ5IAy5B?4d zzr}<9yyi20$9wRHzbfeW6eZvPo#4SAY2i=t;MZIDQ$6^HS@_dD_{|pnNgn*k7XHZ| z{8kJ96c7Gv3%}Ka-)Z4L=F$IVE&LfC_7_|Dr+e_1S@`es;IFjs-|xX+ZQ;-I;IFgr zKj^`~OY_%m`U;cxKZue9*L>%m`b z;os-MUuWUp@4>&z!hgVnzsbV?z6XDcg)eI=( zZQ*~$qx=mPe#*oCQ5Jr)2Y-r%Khc9f)51T}gFnZ@KgxsOZQ&p7!Cz?MPxjz1vG7|w z_{%N)<30FSTlgn<@Yh)QQ#|;$Sol*t_!}(z6FvA3TlmvF_**UfQ#|<3Sojxt@ON7H zpY-7Gw(vjY!5@BLwEvYo5pnz9krw{N9{hR>{}K=WVHW;4ilDKjXn)ruq6dF1P>erylcPt1R}P^x&_x@W18Z z|9T7mdJq0a3;)|5{LL2r4Icb$7XHsX;}iZU{@P-(|C9%RyT$&`J@`8;_J85Qf8JvMX%GHxi~V1E@P{81^!sc- z|LegYq516ppYh-yY_b0<5B_M2{a<_V8!YyJUr4 zjm7>89{hC{`+xP|-(|7?HxK?si~U_5{LL2ofA`>Twb=iM2mcw1{eOD!pSAFJd+?vP z`2Q~te%O4V;uy`^QIxEzwA_6b4}trWe{0O-cr( z@xDj~VM{VpEER*Wh-bXE6b-^kX}rWzm`E1IA}miBZ&^f(u%3S&|8w?S_qzAozw0^Y zeD?l4&)zd*zVrQE*E#o@_vvp3z9;a9#CLLSkDn6Y-^_uJ0)IOPelYO2ci@Kue+LIX z0sNag@MXZig#$kh__uW6Cj!6xO$yubuK@mz4tyH;J2~*PfPX6o{!ZZU?7(M%e`^Q6 z8u+(y;GY5hZ5{Y!!2h_z`cVt~+d25_fM5QmiS7Jb3;f+3_^*L~g+u*~z`uiozX|w@ z9rzACg7-f=Iq;o{_uv1#(|LMS|f&Y64eircm>cD4#{}G4&F9iO59Q=9W{jVRq<1l|} z0WW_O%Xa?M0sbNfz8>(C9QXp@FLdA=06)=zZv^}W4tx{fCphrl4^R8Yf4l=@G~6v zCct0mz=w7YKL5JPfiD7l+JO%P{%Qxl81UCP@DadY>%f-)ex?H-1^j6ad@0~hao}Ts z-^=0oXPkKd^Y5?&e zfq$R_zX|vUIq*fh1n>V2ap1$m``5q04t!7GKh%Nm1^kCO@KN9&;=q>zf6Rd&4*WwM z_>sVWxC37X{KFjhB=F1M^tN4pCj$Qw4*V40AK}2Kf&WMcz7qK34*Z?Kf0P417x<5M z;H!cE7zaKF{39LsWxzkmfnNdq$2#zJz(3l7uLu4v4*b`^FMreC_V`&3{Kq-)O~8M= z10UK|-GBJk{}UYe&cyp)KRwZb?*{xQIq(tSKiPpV0sd1Q`2N6O=D-gI{!<J(2|4avdCh#X6_*uYzmIGe}{O36ES>WH% zfnNyt?H%|UkpElcg2@Kb>Q5(hpF{F5E{O5mU3z~2e{mpbrsf&VfGz8d%| z9QYjYU+%y!1O6)<_!YoE)nWav1OCAd>sLMSf9SCOe+~S@9Q^Bne~p8`3HYZu^gpy) zsCo0R|I;1#&cyqlzg+3ScLV;b9QX+EU+ut`0RJ@(e1G7-)`1@k{4*W+IPhQZz$bwJ z1_yo&@K-wUED;=pHt|5gWnA@Kjp zfqw@0GY)(n_-}LIYk~iE2YwCk-{HWo1^zo7_y*v=%YknM{<|IcO~60ff$y+;@cyUD zfe#b!zyG<%fiDLBdmZ>*z(2=0ss9D{7B%R=fIx`{8fd4TEz6SUg zIPfcg|8WO?74R=~;Ol{Zkpo`<{?8pA|Evf8Cmj46fq$_BAKF9RfB4t`oC9A(y#M*n zlMZ}0;D5@2?+N@*JMbmI|BM441^y)t{9xdJ)`1@m{LeY?3E;1B;LCvjc?W(R@W0@| zPXzv@4txdhFLU72!2hBHKMVL@a^UX-{+Av2Eb!+Y_-f!^?!Z3-{I59h%Ygq?2fh~g zS2*x>!2g;9zZUpcI`Cfu|LYEXBkkCk@MD1geFwfA@UtDhKRN~QS311@ zo(6oKgMSv_?{(m-0RNZ+KOgWl4tx&q`#605ei`7GJNRn>-`l~z2Ji&jS2G4*n{@ zH#qp`1Ae0ep9B2W4*8b>zS4oO1$@CF{~Exrci;HZ zPY3+r4&zq|_+bwGoq*ruaQtTh|Ca;55b(!3xwfIrTGUjz7& z4*Xick89O}_)UQS!-4Nm5`6tQ=Fq>+fFJ6>cLV%k4t!6* z4{_jo0lvQj-y84;Iq>}f-`9a34ETNy{BXdJbXdPf0zU4*p9uKf9P*C={O%6?IKc1h zz)uAHE)M(@z;EHePY3*#4*X2OfA6q<%mVxm4*Z>f|I~q>3;53*`1yeU#erW4_+K6P zX8^y>fnNsrZyop*fdANmUj_J29QZYW|H*-03-}EV{MUg0(t%$O_^%xJjesBKuzqd= z{5%JLhkb(g|5*pVGvJ?e;JX3-DF?nM;1@dZy#T++f$vScK$xF(m#Jv#P^T=bD2C9ZhbZ+e`dCW_yu8gV+O_@<9?D+8P-DVd4tnCIa)f&eH!n z!xt?5$BLdHf1{;;A;X6*Xdd2>ss63S#NjU+*w{Bk>&#^M8MF1yp}%q5@6F&rJ*;CSEKrtv3Dm z+raP<;!X7@L_m~3O1!E5Cm23vS^rjBVSmE1{uIL}E$e@W;Zv6N@7EdUPZMt%|LYk( zL%eDHzhn3;@uu;Qi^t?>{By*c#(zG;=ZQDf|2MnPgLl>&U)|CHxh7S{O8ozHDK0>@{{EiR{3aUS9nSTMp$1L-A+!p&2mif;41NKLWH?1Gj7(Qm1|96H@ zSmu}i&ODkwNz43;89qh4Y5Y3wi2Z5H`Y&MkjAi|AFnrds{$AqWxkLTSS=N6g!{;sQ zFED(aW&J0K7w}O2f@S@$Gkl|E{+Rf8Dv&>PkvjfO$KU-7A12;({Qb%B5#mkj$LTxc z{87vN&og|?GJiMmJGH2P3CsMKGJMi9|Mv`^vdn+F_?<(PKTW)8{dkMvGnVxai(r4& zvi|27K4)3K{GBOOf8H{`{GA@e*AXx79$Ibs^WQHRzL9t_JzH%$zx(dkA5JMuygblq z)A@55K4Qr)WcVoY-s{X>2;Kjv;L+>X;Ue+Ej@Y6E%Ga-d7K?#bk9WI2GX4blP5nP> z58S^L@uvQN!0;L3y}VRL;PvBUdSQRol7EfibHsan;{18RqyEQ0|Nj8}KTLd20nUHR z`~wA#{3-H#`Q`Zk3H;+3f5Fl(zh{K}mB9ahz~9998!i36GX5;^{{{T1y>S0S7poCB z&A$r-kLs@h{=b3$ZN?wA^uNLQ>wteV5!9>4n-?1ye}w$)yopcyuy#JVH|}55l7Exo zW0w4Y66{Y{@((h6(vp{-Q$WXW%90<<@M%kaKEr2-7k7`XHhui&2_DVg2AV%nqUHM0 z3Cy25#-AsDq?JAR{?%KIzqn)Y{;M z@{8eZwdwvIf=B(YCx4u1+5hgq|2X5%S=Rpux5#PmMyg04*{{<$0ap&Ot+a2WJ z;Q-vf0{Q8m@oY(<`@0Gr^)F6-|NQF({1-9)(4|Ugs(%9G&w%>(0{+ei;`+nnH`TwT z;8Fc~P=5*VKgRf@mi5nP{6$*_$A4eo-zW>2d9er^BGnVz=DtJ_X6R5v0@ULh5SiAOFLE z|6Rr(wXA;? z|5C=^1nM6N{5?u>{RQ%yj{ok0NA<_H4L<%k7WkJk{zl9CpJn_h^84@q62O1@KwN*g zLM?En`cD=-s=o%*e?0KN!T2NOH;w-a#@_(yKN0u`48rxtEbH$pcvOG1YjFHe2LA6E zf5Ni#q_#s=pf4e;V+29*q5I%lfwzJo49r`o{qOG{&E` ztp8HRAK5NA{_?Z-MfA9#nDz%AitEo=*1xadQT++>`^P^C{9iHtI?MV$WBgU1{?rwU%&Y$&F^epyF;I*dZH|0&>qh5Y*Khdr)P zT6x?4O^%g+8z9~wk(cS;KZ_7=%HLP;D1Tgju|;hD{F6cc>&UO?KgKfu*G&F|W&Y2Z z{CSZ7QjovzFx5Xj|1`_|w-K-RKTW*p@!KrHqyCq653XOAgZ$qy{tWp|>(|$eznuL3 z^=lgN4;_x@U(T}r!Gaez8#sP)p#B-a{~6=YTh{+E<1c{vuLAyQN8tJkmi1pMcyY6V z`b%~Qj{nub|32eyw5)&9(qxzdb{r3R>T*eVFjY_aBY@dCU4s1dsgnp#H~ze-7iX zv#kGa#$VJkIR1|Vf5!x_ztOV(4uVJZC&=#~|3$#RjPZwNsP(s}+O_-*x13TZo@4xJ zQ2%1!zvwtze}w#9G@tIDAb3=NEvWxV;Qx&AM=k6BnDIA(`kw~=QOD!@6PESI1&`{F z?Hqjkvjq4zI|2KXmi2F9{3-JL@Bf|y{w0h*ZCQU#@TmS8Q2+D5zt@Sl{)}b)y9plo z8$kU_fqypR&so-gJL8Y;5*+^*fq&FVxcM62uiq{Q{<|4}^h%{Qtv|O39@U=*{eKnsUt#<)@|)J*7a4ye=>KcL{}ba+ zlAng5WeoKGf5-SscUAK*Po#YQ^E&V!eu^4@{q@67$uE2B-}KjSA0=LY{jkw;{2mm% zbm*@?H&Om5$z}dGLH@THf9NU&n#S)9#$OT%K7LpQ{J$~&2>DI(w~_Iu$nUTJZQzfT z;o~=IS$_|~qyA?>{dK^94C7Cb-!y+mF#ZPe=Y8Y<9`N5wetrI~CcmuBzv=V$KTQ6D zW&Yoo{MEY!kG~H<{!ypm_`|rO#0sbzh;rX8>|K_4L|E8~>odhp#Hc)?o{KW*z^=B>cPi6eMv;s~3 z6yt9K{?CB_Q^udS^w%@~@E&UX{q+}sf7t1`|8luG>FE#&@#LMG=gW{uk}3#@}E6M&Q4K@z;^xH2I9R-j2-vsLa5Aeqre}ep``F9B8FWW14|F;SFA7}hY@|%wT zM;L#K{Ql$rzrgx|JR1K7 z(EoP8KZ)^YE&byee`xRE_;&#Qj~IW>(*GXgF9!ZCfPchUxc_-e|4_lB{zrko2>732 z{B@T8#f(1={GEV*$Fp($1xtT7!K3<k3G}}w@HaC4Jo!!I{{!QX?GqgTU4Z}ibMg2WEXRM8 z;5&#hjx>R-(G8$kW?xBm6VAL|%@l>B?PE-Uc+179%y z=)S7|{`z|XfAM*^|4H(j=KpqrNBz%`-#`EN0{%GTPm$j=|A#UDJo)|WUkUI}CcpR^ zajR_>`R~%^)n;@pZ+{KLm)xMP_}W&jZnkCoJ^pU5{?=Cu{dl{&;0*0@kMl0R&8y$L zfc8cEsqrr&K(2qiLH!FnzgB1B4s}D~<;_-`e*gQh=hygfZ{@EbTKW$F{toA>`KQ1B z{TTUmpI-k(#Otpg=ZU|hRr=ul#{|Kn`CCc(lfL|YK>kgPKX#`AFEaT5VEhfh-w*h& zEyu@ij{K(juM|A0KfeE#&B>FLUyk2F!2c=ZkKUy~Q~mXfzZ&=l0DqtHxc)5pP4)K{ zJgUFwfMERtf&XU4AGzDE{_7ckIq)9>{GT)a4EfKZ@$+{2@$?DfuO+|#_&pT(CrrS{ z@6Y7defsgc#RYi$!n0N4{k-6`58R&M(fGvo8q{?D2GJ;<+S!9OKr4sb<-@y382dT<)#LMwNANWtZ3?IK^=P04+`2C1@ef(3z z|Nc+wn@{Qa-xECQU;bc~zucF90?0qG0_Q((u3i3Th!5l^-jsi_;8FgP(qR4zLH-_> zGx_hc%YQe+Pq5^-zXH$y6!8xk#xE>*RDWims=twVIsYyO^^YgNzW#1^zg_+BF#Had z{HSTT{s{4=<1a3FRDXI<@c5ew>R(KLz5WB{+10=Abeum%ylMRQ6guh*X?-gNw|7d)!JVo31#xdzl8v9?el_P=Mz zKf>@ITJl@W#Qsk#`3o5SGfVzmhX2x%A95Yezs{0>is8SvMj^%uy0V2fFu(EU#` ze0aXPzKQ>fc)d?Uh;Og?H>303{-jErKSBHkjo0%h1dsZcqW+bVNcL|I=-)i@2l79x z#HRe4-^k=AK4r)s5*E(8eu4(*{kui*sDJTzF#j_ke=U>$riCiF-Y+dqsN28r_-BYWYw|m0Q{{+KtVab==hW(u^`6(W+;k|CwWh z{jUZ7TN!_r{G$x@-^lnI$)6@(*8e8(cNFjQqy9I(Z&!Z@!K3<9iD3P!fd4kepIBq( zpT+p=fd6ga|AO)7Ed6U4fAqLu{dK^9a24)<_ybk{b%ycpBY4#R4EYPb@qZ8aA7uR5 z50(FZga1CppE^O+@At0({;uMEQZ)Z!^~!&b!N0ZOQT>UNl;3~+e+c~7GXBEH%73id zwfxnO|0@}P@)YGSCQ=@M^}zoEirI@kiDwkRHa;tpq>6k!1X}xPNuT57Ax#())Lm;8Filr>g$dl1TRN8<77g#vd-ImL2H@ zRc8Z_pB6Fx($kecL!9(~3;aJb{^S=5JezoLr`Nxp@z;_+Nucz92mIULhmXHk$ZtA+ zD~J!wf8r~=;I!BCPZm5HzmhSkfByNm9^_xm^M=#gkG>zzza;VFTG7Gd z=V-yB{B@Myt6%ni1IYg>`Ss&x1^Kto{9bNvKSaDwD^KhFuOt3^jo14>Nbo3s{0!B9 zfBs)U{zc^1^AGq+iB0|AIg9hhh&T1WSnw!+9_0TGB!YNt-y8j)-w(EZ%!K3l70shXwKb!H#Ed94L{s!RR2KfKO z_*3N9?-%v?_Z#Cc9^9>Mj;eo;o#@qdEgQT?S8RR5#C`nv=FGmJlF z>0iwF%YnZb_`5xd>(5&Hy9gfDUj_U-0smCSUuWr0G5%WM?+N_%j6d|N8aUJZd!O+) zk>5Z6b^-q5#1j;B|C_M%j}$!Wf9irQn+x#!BfwwF__LP&R~df;@b3=%gT(u!sQyOs zpG(J&x6_aRg9MN2Pfk?z`;Wg~z<&qhPi|Dk2Rt$Db^oo5KSTaJadQ3J3-}wz-&gZ& z_M5t(y?!~Jmpzl)j0L!VVdBqMS8MsJ=dTbv>R;l*;QZMKO@ z{QCj_*^Ix@(tifyk4*~Jzd!IVW&BC{;InvpwbiEg|5?UgL;fVua{e3${9VKgbh7{Y z{MkVMqE>cwU3rl=f6~P3kN-n|DDYN|*Yi&kJQ}~^i&X#e#LN7BLH-8DpCSL#2LD%# zzn=V!K7W7UKT5pMjrupNNr7E7zt=Z!zk+zZe@Wt3Y6r01zn2A%`d6D${fiPW`!@jO zKllliU-w5hso*AmAHgGk)8wFkAn;FT{N4;Rjo)RAzvMFI_mAHpz`v34=V^v7(Z)~j z{|3fiTtW2{FZ+Ke@bAAE_dmUvnjvR;6NPR^_m>DB^*>JjjL$y=_@^`eLOUhyXQ=-& z#$QkVVxNB~@OR1K`Xltgg`tM}I|&}u-$;J{`zOPI|2D>->Y&6^4fW4r{7sju@sIoJ zKLYrFXZ(%i?{297XT~49Liy``{v&~Z;*+@l;VqPSFN6Pl!K3~cPYe2w0{-=kKenY3 zUt{S1w~W7${QmwQ1N@_(!u8jYe_gxQ0m7}%hK?3Is=su)sy|D-JpM-k|L$Uela=c0 zZ@!bN{}Roo`*#*R^4DLf{1wDY|7hTUgYn0(6yj{y}Qj5<&M*7Cfpyd#&=PiI@Hpfd2)?-xyY4*A}xnq5GFG{>XL8A0=M;PXhi; zj6b}s@^>-#|6u$H;6DZUOT`_WH0kp%LjIlxe?P&a{-??BKmJYy{wa(_;-F5_rKAy|HXnw{jVXvzyD_f{~3%w+*Qp# zQ~%2tf9M8PzrX)y0sotfKS%z(Rg9KdpdWv)G5$RH{qNtL1Nf9gh6e@Be|CGj`u7q% zs=xN;VEyBPzl!lE=z))^{yP|d&8%Sk7XW|p^SJ)x4yu0B{M%0OsQ$>U%I}|l7Xp73 zwHhui>VElFeQvN8>a{gTe{D-}O>rd>c{J#{n(g)uE9VmEIe<-8;CBDZ$ z7X$yzoPT%a?_+rWdp+YXxn24F$KPb&FItN0&+MuEC$ugMi^IFsrjP$P#-Aj=|M|~l!2bi|&(Q;a)8n6YjKBO&Rev$1m-Fv(;J`{Uo!q$^844%n}EM-9``?bfa?FHYS)rNAOEcdkNO{;6P$mu zfPWDAwU-G()dwo^fh}frLOUEo2YG(&dS&Eqq|4>{c`NWADR^nppT8Bze}#6tdi{qB z9@QV88=QX`;J=3a`uE4iL{{;cChlB9zUKacr^a82UPu0>YSW^ zRlwir73>cUQ2x!d14FNWbHO8jiv0fd_g>(SGyd>E<^P=Wdpq4fjPX}I7##n(z~4ZA z{r-Cc`PHp>cGW9+PNfTlE_;>fAHDEpdj02_DtoM1KGGXC4Cnp|4?oWQbk;g9VTLMUMpQ ze;D}pSc(0in4NzY!6SbH_#XxS2F70?{~Lz>f5rH#$X~9?X#W1jW57S-bzFaLm;yz6 zTW$LIR|p=}AF5XUuOM2^|Hpy9hViF|EB|KR18%w<-TyS>uONSw3@0|}Uj+Q^YH|IU zk;-rS{OVtfKfFlQU$6Ad{>8xmG2;)9R(^UIMYj?>{?-T{^}m7qd7uAD;Q!(cTz@Q~ z{PZ>m>t8E)u(A;Qxa0*OEW#tN(f6KWr85fAo0O|6Xd>l0vV4px{ye zo5){9ygdGv0{;c8u|Ii&0+TIfbwc-_CwSz~JgLUtVFyd_k0`IpF2^3ruiQcJgPtZba4JJ2ma?6fA}QjKi*LPQ;ffi{2Ah9|6c|E1K+{* zr^s(Q{`M6-s=tB!{^Rd8;GfUh~XitAT%u_i+8u zGF886{oPFPsQ&14${+R3|961@Q1bWHj*3Q>5{`6ASKmYt$1N;-;$K#hiL-{}Q8b)5- zf4<<+_*IcVPn@j(L*V~6<4@8P$9uJg>;4ZJf7voszyI+|J@6m62G<`tTNS>*;NMs9 zsQxVZ{m=hD0sc!Fe{P)ePu0d-um57kU;U!0zrxr5wZQ*2o6KXRV((=yhQLa%>-;8FkUURM4_U;PE(uONTl7K1u*+4;)9op!mp^q=+P zRVIIi_>&Ct=Ore8KCklopZ|Xa@^Ahj?qB10m2`x`9}+z5-z&lK`v&-jl3(xN!4vKJ zcMFq0LHs^m!)YA!@vmg^r&p-_rNqnirvc=Di^+fag$itM82|1c;r^#R-q8PT1&{h) z^P0+^_T~Qpq`yVfctku8W z&G-xC&(M{ne*^HpM}B?&g;J`1`WSGFlG+*a_QUJd`00Gn#p)XCT1a)Gh|YWbQsVX3 z?;DA~$peVf=kK$EN8_KWRsD~5QJ}2KB5D6kk@$Hd-KNIpZ;$=|BA0x*EmY!z3JrfD~Z?VUyAs5wFOM?|8l{j`b$1l z^;d4L0?7LR0`-@y#r;oQrxJc=@b4jb1~ns&J&w zEl+xNd;6n4!}*iM-(tu=T<|D==tq^m!8d+efcz`Sujl{qc9n1+L;i$#gG^pipZ}3N z6o05;{v9KDl)vE@l|Sw4e@Br2ZSw2+&$wIp#~SjFE#Ull;yW4of2!b7{_;Om{%Uc| z$W6|l&LICc1?;c8SLN?)@D~J+{Nev9f7Unt+W`OZUtoWMe)!JhA0>F?&$U-air*gw z{#E4H$8Y_Es{U7H^L(4SRArVIkNQ%b*7@8+>Y4}nSb5Sre!bgypLl)#HWL4}2hi>4 z>&M%INA)KkUO8U>-}FTcvOGm9?Db@HOo!*eUWdo;us4-|E7iW1 zzv@!O$P3pJua94X_!ru>pv@=r@%u>dsDGJ5RDSPwJ>>Z92J$Dr#p4%VZ8v_W3m*CF z4h{Bi58(fT@#o%G{__mux0dnej!^!baLP^AzbEjY*MRGfe4_mC8~kSp9@U>574+{7 z{691P&=<=8fx*9?@rO?e`u73;Yrezv7rs^gFAei=hTu{C`7z4xpMU!S|2E%af8F=W zzp0}dKku(T|2qmE`9o(?{l4{kf8ej?{2P`39WihGo9=&z@#iKgf8{ocmh(BnJ{HFV_{REHdFP*0R{`;>!z(1e-`u*3PmRr&L z_c4<{RjI%zjlb+)e~`b+dfdP8wkp3^9$Rg?zmwom|FX9!e;v(#=|33w?_&I+t_sYy zvIpP)$T0rYoyuRJhD(1b@E;)FAd^?o??1AZ{(S_G>QCGq^bZ35*BO6oJ5~PxL;bHX z{%Do*`(M8q4E%figzHa}e}loli{MfH)#UfT|8W@bKg#%1-BkT02LFSMKX;F+KT5nD z{}}LZBMOA$Z|UzScvOD@_zwsE%NT#1rT-GfAHFwOzx*e4)TN=2_xi!Nj6bx!UH`vi z{4wAk0sNyIasQ*1{-Xtt`kw;+IPfoL{7FmyGRB_;{-c3^pPzC48S;zvw%Wq2&V@p~ z1dr;kBftOn8wvc27=OCE8vh40pYE?_{PlCxOv@85kH2GqzuPak{^$tNKm;uNZ&v{XzeUz+d(&?tgekJO2rS zNByq{{*!_KCB~m4|4c*wpJ)74^HlvA-~1~B{=GKh`eQq(`c3}b1dr-3$p-zW0sk$G zzs}NM$@pu4e+=+%WcIX@dtwQZ!GYi`WxAy4e@2u*-(@_7(f=BgNk>5Z6pd)&C~rFRxZ6fBlny|M)*~ z{dJc9QG!SH#}@?sDd7Kr@uzmP>wg{NFIgDu|0TeG#D8%8$=&Vx9}_&Pzv+o!{ZoLy zmhp%7u=Bsl`0H~)|E0ix%>Uu~v*bTU7U$da$DbnvkLs^^O8Mz!kmlDf9iZ}8X!-U2&1d|@waOnSUixPMf9x+@erazE+sYn%{i>hfQT=)H``6EFf&U%y z>+?5qkg9*I=GW)%nSZPNI-e%~42}2t@7>Nu;`P_h3dCd$_tOlcZG z+5a0r{nNyeD6{DKzZtCR*ABmy4Hc8k}s91K!wWw$)6O`{r_S7$;0gYzcKzIdgI#fzZLjz z6Ccn+;};sD{3Epby>avQd$q^?OAvpJaQZiW{B{#O>R-b*s#E^?cN@t66yq<9Q2E8f zqgI>lU&Q#!8K8P?w&1dr;k{8^c*eeWO0pH$KPS2F(a zDCIZZ|6I=aqyMK&aq6C&zq5hA`{ua*4EaA+F>1|0Uy3Tlzm`{H4Gzf6_s(|C}wD{*%AFeM{-hC-nZ0 z6+G&Hg8cL`*yhJ?^ML<##veM-ZvMT(_=~qx6W>4of zkLpj7-@ks!p9IkT-!T5jNveL6zrgro9aa5)|HHsPUfjXSB`R?LW$7O$cvOF6tDyf; z;NQUblPBBN|2^XmZ5{MK2K-Yy;`&3U*!fd}NA(xB3Hl!g{y!Oi*3!R`@#n)qzx+zP zKL2KP!u7}KgVUz@S0Q**f3|DTFTWD4``e4(`9<@uVCnxa<4<=B`sG)Wb^nc?Upvmz zr>gPae!JHHL0|u73ck7i)>jK9yDNVR{#f?!Tp9ekE1+Z_^p~KXReE!T-~4SNC@mJR1K7@<)VIZqhHmQmOkd;ruBj z7FerI_g~2Piw;xu`|p3B2ma1mW{`$ z|NZk%ekD!se+}bLOi_ON7*R_X^!`81_=|=rzyI;a>%iY3jO$Nbs{E$o|8K_MaCmV3 zy#f5!Gyb%t|7yXb{)dJI{ciz((YCn$4Ef(^>AX6j_rJa1k-wPy{`t2W_&;F$$;(v# z*Qs4g3f*7F_%r0s5-*RxcYyyw@jKh-{y%Yr0@t^gasB0jNA*WXsQyQ2{g(cBf&UT4 zADgE9UmN@nF#g1m$}b+CHgD4ZKJb6e_@mR6f3m^<3F9w|E5CpJ`vCX{Z-@JzBfshW zs{w*X{cj+D&R4(uN}|60EN1-K8LIw4#CvVf=idUxUv;#q-|znz_%|~C!j;N@iYKPM z?%%-p<0F+nN}L@3e*^!;;&;|%iTd-e*j37ZxWPYB@TmV4c{wzn1aWk5>Mex|!z3-`@cLBi)()&s5+=#CuK9>wiG-sQ<;s zE5CpJ{}%Xf*a7>~*DLXFhWf7&Jo49^sQmul5BLuFS9AVK<)7^pPJ6xnTE^dalJaMW zlgIxLz(1%M*B`l2`Ni8Stv20%kl<1M>64Y;zy8Uubn3_di=6)^<$s`+J^1*yhVe(s zl)svIS^oy$KS2D>zZ_zH{i`Ftss4QgkLs@{zrX&Ufqx0-zgg8!A0uz+g5Lie$_(6UpSRcP{ z1TSBs(B38p<;m||-;3d$_x1(P?_GiR5#X0{kMnZR)@+ zu9p8Aoue+$`{nt)D;_O))W1^7AEhhG@oNwAFCxF5KSut&JrV6A+WBvo{NmzUhjY2GXMF4NByq?`Q=xtz47zr&r&9Tf&3#4`HOdD z=FeO;e@Zmo^LrO>CwP>cnfw{zP4j;N zlRrFOtsnmR-v#9Vj>(@T|DIZ2J^!xa0k*u0(C1IBW&WK6kNO`2`MZMrCy`(8e}Vja z81mo92SQ{HKs#pZ^i^PcYL+`30o?ZW+5IoAC0sZd<^6x0#Adu^y-v1c+4>#nWNW7lE(lY<~f=BuDAphPV z|I1ANEcs6~}-wV&5B>9IM`d>!8K7Xn$^PeDi)c+wT%7}O;X#X9< zhaOPJuj%+7y*HkJWyG7t?`XlJ`l~?w{XzXp$gj`8H2HgJ_3HJ1&*ZPR%>NCOzZT>l z0P^ozg6ChJ{6h`-FD71}e?<@4t-limkNV#P@(%*}UuE(~$lpWDug`}KO#T@0ag7%d zT5aDm`Aa6MAb zqCcJseT@F;)$!r=YK2$26w^6U8{l-j=D&}Q~o^#kMfs; z{Ktd*v&pZ||1|ma@89VC-~2$FzhId^BzTm+7UY*di6#EmycN@aGWqrVkw;bkQgl6U z7x7Neej}4VL%gZ~8<_kh7X{}}8OT31isyfU{HJPp_57a`uh0KjwcY&rMDVEpl_3A= zApcQ)aQ-y;CmQmvBwo+oXqkVx;8Fetkbf-5Kddj#AA3yoFK);`mv}vYCGn>DGh6T| ze>@eOKWBmbzcKmqIs%JYmW|M(`+qHOM~>W1Ecx}vySl%(;8FcK@<)CCa^QcA@#o0z<@bu#{qq@rf&2;i z;)>X0{S$z{$3eLMvd7i@FH?BSU)|qb@TmUiWYzzABBfvcq@KqY)8)4^{v7#D{lAg% z7fn%qfBz=||4s+v`t#(kX{lVD@bY^XZ!dUMe<}IXzW%3xKg;+l7TWcH4&$$x8tnfi zz~5y6uD_1_rv7&lJgPr)X|VrOfPXgQFOc8V|JxaVp8Wp)Ukdy?mg4%W7UA_@+(fIb zo8VFXu?kgxHCkk^EkMuV`@-t+ow}zxZ-h zzkmIi4*cg0+^l&`(C2YQefs&W2Vp)-e56&{P)I-jl!4cM`uRSG{BOU0ef@l{ zjr{(D+vZ=;Mt+||+vcxsBfsZiZSz0aMt;DMw)x*|BY$SBZT{Le@_mN3&A+IP{62@b z&A+UTeCe>Z`JZVc-*0%^{I9i;uCe$E*7JecQ;75WIYftiOKi`L(aF2R{Ehfp|TC4L$xh zJ%2h^@aXwl`4z$EuZuGh9?$&a{jCU z`ByRdBjh)&KRr%l)*s?c^S`^`QU5cPKk3W=I>VN4BHUItnUk&o#$>dLy-?aX$VDe{)H_iW- znfz6hKkl19bs+ynCV!s%Lx}fw5$^=;ho6k+f9Pp7ey08p5j^UD0rdZUkpE8d>+?TG z{=r&aJ^vR>{xtEX{;y^7$F2a49JWBHBl^^H&hB_rIEW)BK+*c+~&sRl)V=bC7=(lfOXzn3h-1zw@d1_>C;F zyZmA~{1Ni^)bi_(Ctqjs z$1L-|!sJhb{PN$j)BC@X$)6;@@&4;{JpZ%Ao953D!K41yQvM|MPtO0JK>j<)uh0Ji z`HlBqO#aAocJpT~lfUHZ;QWz4iL3YjfH8Rf$H;HI{~}(W|7qe){hum$)c+La_xFDz z$iI@wpC^BW#?Ra7=l@{x7cBe#3zNSN^#2c#zvK+u|4@w@f8+fZ@p}K`#2foBc+~&m zYl8P*{{i_|G5OQvk9m!!z25(w$KvBRPkgb)d-K=3xLEKge+A`_(-r0M`xnSRiTr`% zm;A>2FD8HK^J@G|{a?l8&x8Jl#E^LPdwuDDCZ0cO^6&07iuMuh{Q1P|^QW44&*Nd9 z-#dS{;8Fi0*9O<0_8|YgO#VFi^}PD|x0w6|%ls>u{N*7379js7CV%J!HU6gWzYR>{ z`5z_T)c^j1NBz%%{2f95X^cN^>A#fmHv#`vz`u%V8YX}7QZ@fg`QKsk*MR);Cyl-Oz2jo1vvL1R$lpcF>+#;jgNWDrUrM~^ z@vg7)2MHeazX8mj9YFrmnEXld@8yYUAJNX=#^kRgUcbJce-@KJdYuR>ws`YjHGg&j z`D>Z{Ir5ucKW=35*IM@f2PS_7$iFklUwjUpKLzq1P4#=bhe}Vjg^_%?TwA+nn=T91k@BeBo^Ctw4 z`j-It_XPRhB)^`&K>lf3UOoTG=i>ay7wyLXIKiX*RUm%}$p0nz_55k_n~uLu=i&TS zmiadqJj!1H`S%0)`;uSJpC|uVL;oLO@<(1${V&ycef^uuudg2&%lt(8zi;QUGAP5s|V@F;)jjcWe*`yT`OZzaE;KW&-+FD8G%GJg}3KMnE^1NkRTWaj@X zs{aod=Fct{;{I0?Z|eV!f=B(Y1^GvS{B`8l`=2Mj>HD{XCgJ>%SMAo%g9MNAhi_8z zCrSO2uYVl{^3Nx~oXpQP6FkGL4;FOc8#`+w7k*Yg*>ruuJs{(YI?QU1`) zYX10NKaf9Zt>=G=$sZxVH-6qQM7$HU-|7-Pf69sX#@WL>zjuBM!K3_9%J2E*{FgsT z?eX62jw8Q5|I?QFUu5#vTIR1|@>hWT@+Y13{M{!r^N0L5dyS%fL_7Z!@%sEpt+YFS z7YQEqKM(Ss4)Py61?SI_-<1D*;`RK|*X{CuBY2d*XqE^oHvjyQKk2OZ|N5yof0F!X zYW7RZ0zr8s|q{9gTDY(4+W#OwJ>YVG>}g5Xj9Dv*C1 z$X|RJ&L1PcDgVX9>-j4!^G_5!%3lEa&j;L}=KgwSL^2?tD z(DTnFzdrx7MSeYhlKd5h<9D|- z&R=htzo+0){wk1Pek4K9zkvLD{?Oa1f2REXuEzN*i1*fMuMM8xJAZ)SQT_tRFW*w} zc<*+XkzdcBA;0PU!?jHQtY!X>nEWLf5msz*Dpaoj@+B=j|0X7Xp8WHP_jVEQ1nr-^ z2KT@G9lQCzQ1Gb#DUe@2CD8Mqcdhd4{ZEtsK`pPIf5(|Pe@UHP{%(Rt`D;Laxuoj( zSCL=OA0xl1|5sm!^EX)LpDuWmKXhAg{>Y2;{0Co;`yYB&_3tP{|1-qvj~^1md&ik~ zGoIf&f3x6G{y4~gC&>RjlRs^lfA|f!|8I|{(AE3`SX_fr{0M3C*HR^ep7-+`6IWBuwsi-zvTLP zAIRVJCOrSsSA&~zX^6T>_P5z^_e(U{T%jB=K%>NOSzX{}j1mr(>7M?$$4=mSD;`RBH zAl}sfn+1>hAG&-!y+l+=Ay%on`)^f=Br)LH>mx|AXY$=TGQE zyZQfLCVzr>Q~&>D^4Ed-oc<*yaCP@F;)j zT_UVD|6c<6EAPblW8^pG-}^2+f9fpr?=E~@+XM*c6$ByGX6aI>wW&Wfd3Q5 zA6~1*-{k**@mE!;`u+aZz<7U5>_GXA=`s{Um2 zD5&G_Bj8`i_-o1U@pLmSuitp*A7%Ve`D9mY{`Kc$;NS8d-2al#)c7ZxZ{?pq`tjdR z@TmW#_Xqv|2L54;ztYlw7~_x43;I6={w(8fu=LMi{BikYU2OjTe-8ZH+>84k|J<(s z9R-j2pLihX{{r|&GX84vo96$KjKAzb-L&sQ#P$FEjqQe6d4pe*d??-)RmW{}}mA{oh>hX#DHRpKMN{`u`p94`ux2 zGN+_ z!K3;!A2a^SFIE5JUg5OY>tDn8^YX<$ zu~ic%>;Dt@2i}kSUq}8h@!n4N_ZK|sfB6FC_vVlE{~z!#Wc&s4d-*y4ql~|b{0ZOq z{{{TJ&cpRrer4DHodl2SZ+KkQpQqrm{=b3$9>!ls{)AUJ?e+fO$@r_~i=|?#Cri)kY@Mj;y^~Wv!a|Dm-ugV4czZLLz zcnJG5mj1sPf7z2k|JJ}?&iLys{pScC)n6=MEEik8`LF7K7vS$QAJ-pQXE*+x1dsgn zz`rfg^=}9KeICa3=g4n5{(1`@)nE3E^81g!?ScO;#vl4t_21;r zF#hP0pnnJ8|C8}2$RDTqZP1?%4#_{Tqr>n~}rJO0KA9@QV0Z`Oz{-~3k{|GNVJI>w(OziIw`!T5`w z56-{cfd7_iTz}ruUnzK0e*yUS0RH}uVSo5LyW{Ub!6Sdo3&HyL1pdX0KWXV-!1yyu zgZ{mNzxM)Me~$d7<9~0#qx#F21?S&B!2bf{Z?g0+Vf-a82L1a1fBbP=f9!j^<8PSY zQT+|Tzd!I7EyVsx@|%vo_JT+LYWZfN*!=fD2Lk^}#$RvgU(Wc`F9-d7fdBeMxc-tK z?D~JT;8Fc$`QZ5X1O6Wvf6CIoj`0`EH#^0aZ~m*+--CcZ@dU2F#?pU`;8Fecz&`-^ zn;3s+y*k3jC88e?9q4$NzZ7Ur&Dj@jnFk-)H52Hxb~@rAbe z=NWjDe~+bY^FL{<${t2fh5i z{rd5)pMTfDo9e$H-!}i|%l|iT^519R^?LR517B&I|9u0m`}Fg}Ud8@Uqq_erX_-0d zL_|CPq=DCc`uW{fw9Wr71F!q^^Ic#2-+t5h-(lc&pMJjk%C`Au8+hHPpYQW}+x%}B zc-^O;A6eTr|7ruT`}FgPH`?ZZ*TC!Rt$zO8H~+U^&#RyR!N8Yj$E$w)Ui4Pm{6(w& zH*Y$A<{5asUj2OO>bCjU2wskf{`lEj|8$>z{vE-i$M41R!^&dw>X+}|r@`a*u5T-U z*XC>g^CwK}Z{(kgnooI;zrB5g;iJUIG~Uba?fVknUb|k3c<*}Nf7Z|MFZkyAy(`c@ z3hJK;>Ob1^tGk<)TdA=0AL02mJ`ViX1OIi5KW*txGyWv-R|5YVjK9*-zk=~s0RK(E z|2yN)So(iv{2Ab%1^m0eqvn6KW#rX~D)Q^UzwfP|-hMygH9WL}c>QvZ^Dd7OuT7s& zE%Bw=52)z#{}92W`Cm=-XA{aKkN*s)U*^%>%|t>Sk(J|A;yVO;p;%HpzqhW)RYpH{ mC13fBOce@!zkTal*X!R_TnF*-U4&3<$BFv +#include + +using namespace mlpack; +using namespace mlpack::regression; + + +BayesianRidge::BayesianRidge(const bool fitIntercept, + const bool normalize) : + fitIntercept(fitIntercept), + normalize(normalize){ + + Log::Info << "Baysian Ridge regression(fitIntercept=" + << this->fitIntercept + <<", normalize=" + <normalize + <<")" + <CenterNormalize(data, + responses, + this->fitIntercept, + this->normalize, + phi, + t, + this->data_offset, + this->data_scale, + this->responses_offset); + + vecphitT = phi * t.t(); + phiphiT = phi * phi.t(); + + // Compute the eigenvalues only once. + arma::eig_sym(eigval, eigvec, phiphiT); + + unsigned short p = data.n_rows, n = data.n_cols; + // Initialize the hyperparameters and + // begin with an infinitely broad prior. + this->alpha = 1e-6; + this->beta = 1 / (var(t) * 0.1); + + double tol = 1e-3; + unsigned short nIterMax = 50; + unsigned short i = 0; + double deltaAlpha = 1, deltaBeta = 1, crit = 1; + arma::mat matA = arma::eye(p, p); + arma::rowvec temp; + + while ((crit > tol) && (i < nIterMax)) + { + deltaAlpha = -this->alpha; + deltaBeta = -this->beta; + + // Compute the posterior statistics. + // with inv() + for (size_t k = 0; k < p; k++) {matA(k,k) = this->alpha;} + // inv is used instead of solve beacause we need matCovariance to + // compute the prediction uncertainties. If solve is used, matCovariance + // must be comptuted at the end of the loop. + this->matCovariance = inv_sympd(matA + phiphiT * this->beta); + this->omega = (this->matCovariance * vecphitT) * this->beta; + + // // with solve() + // for (size_t k = 0; k < p; k++) {matA(k,k) = this->alpha / this->beta;} + // this->omega = solve(matA + phiphiT, vecphitT); + + // Update alpha. + eigvali = eigval * this->beta; + gamma = sum(eigvali / (this->alpha + eigvali)); + this->alpha = gamma / dot(this->omega.t(), this->omega); + + // Update beta. + temp = t - this->omega.t() * phi; + this->beta = (n - gamma) / dot(temp, temp); + + // Comptute the stopping criterion. + deltaAlpha += this->alpha; + deltaBeta += this->beta; + crit = abs(deltaAlpha/this->alpha + deltaBeta/this->beta); + i++; + } + Timer::Stop("bayesian_ridge_regression"); +} + +void BayesianRidge::Predict(const arma::mat& points, + arma::rowvec& predictions) const +{ + arma::mat X = points; + + //Center and normalize the points before applying the model + X.each_col() -= this->data_offset; + X.each_col() /= this->data_scale; + predictions = this->omega.t() * X + this->responses_offset; +} + +void BayesianRidge::Predict(const arma::colvec& point, double& prediction) const +{ + arma::mat point_mat = arma::conv_to::from(point); + arma::rowvec prediction_vec(1); + this->Predict(point_mat, prediction_vec); + prediction = prediction_vec[0]; +} + + +void BayesianRidge::Predict(const arma::colvec& point, + double& prediction, + double& std) const +{ + arma::mat point_mat = arma::conv_to::from(point); + arma::rowvec prediction_vec(1); + arma::rowvec std_vec(1); + this->Predict(point_mat, prediction_vec, std_vec); + prediction = prediction_vec[0]; + std = std_vec[0]; +} + +void BayesianRidge::Predict(const arma::mat& points, + arma::rowvec& predictions, + arma::rowvec& std) const +{ + arma::mat X = points; + + //Center and normalize the points before applying the model + X.each_col() -= this->data_offset; + X.each_col() /= this->data_scale; + predictions = this->omega.t() * X + this->responses_offset; + + //Compute the standard deviation of each prediction + std = arma::zeros(X.n_cols); + arma::colvec phi(X.n_rows); + for (size_t i = 0; i < X.n_cols; i++) + { + phi = X.col(i); + std[i] = sqrt(this->getVariance() + + dot(phi.t() * this->matCovariance, phi)); + } +} + +double BayesianRidge::Rmse(const arma::mat& data, + const arma::rowvec& responses) const +{ + arma::rowvec predictions; + this->Predict(data, predictions); + return sqrt(mean(square(responses - predictions))); +} + +void BayesianRidge::CenterNormalize(const arma::mat& data, + const arma::rowvec& responses, + bool fit_intercept, + bool normalize, + arma::mat& data_proc, + arma::rowvec& responses_proc, + arma::colvec& data_offset, + arma::colvec& data_scale, + double& responses_offset) +{ + // Initialize the offsets to their neutral forms. + data_offset = arma::zeros(data.n_rows); + data_scale = arma::ones(data.n_rows); + responses_offset = 0.0; + + if (fit_intercept) + { + data_offset = mean(data, 1); + responses_offset = mean(responses); + } + if (normalize) + data_scale = stddev(data, 0, 1); + + // Copy data and response before the processing. + data_proc = data; + responses_proc = responses; + // Center the data. + data_proc.each_col() -= data_offset; + // Scale the data. + data_proc.each_col() /= data_scale; + // Center the responses. + responses_proc -= responses_offset; +} + + +// Copy construcor +BayesianRidge::BayesianRidge(const BayesianRidge& other): + fitIntercept(other.fitIntercept), + normalize(other.normalize), + data_offset(other.data_offset), + data_scale(other.data_scale), + responses_offset(other.responses_offset), + alpha(other.alpha), + beta(other.beta), + gamma(other.gamma), + omega(other.omega), + matCovariance(other.matCovariance) +{/* All is done */} + +// Move construcor +BayesianRidge::BayesianRidge(BayesianRidge&& other): + fitIntercept(other.fitIntercept), + normalize(other.normalize), + data_offset(std::move(other.data_offset)), + data_scale(std::move(other.data_scale)), + responses_offset(other.responses_offset), + alpha(other.alpha), + beta(other.beta), + gamma(other.gamma), + omega(std::move(other.omega)), + matCovariance(std::move(other.matCovariance)) +{ + // Clear the other object + if (this != &other) + { + other.fitIntercept = false; + other.normalize = false; + other.data_offset.reset(); + other.data_scale.reset(); + other.responses_offset = 0.0; + other.alpha = 0.0; + other.gamma = 0.0; + other.beta = 0.0; + other.omega.reset(); + other.matCovariance.reset(); + } +} + +BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) +{ + if (this == &other) + return *this; + + fitIntercept = other.fitIntercept; + normalize = other.normalize; + data_offset = other.data_offset; + data_scale = other.data_scale; + responses_offset = other.responses_offset; + alpha = other.alpha; + gamma = other.gamma; + beta = other.beta; + omega = other.omega; + matCovariance = other.matCovariance; + return *this; +} + +BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) +{ + if (this != &other ) + { + fitIntercept = other.fitIntercept; + normalize = other.normalize; + data_offset = other.data_offset; + data_scale = other.data_scale; + responses_offset = other.responses_offset; + alpha = other.alpha; + gamma = other.gamma; + beta = other.beta; + omega = other.omega; + matCovariance = other.matCovariance; + + // Clear the other object. + other.fitIntercept = false; + other.normalize = false; + other.data_offset.reset(); + other.data_scale.reset(); + other.responses_offset = 0.0; + other.alpha = 0.0; + other.gamma = 0.0; + other.beta = 0.0; + other.omega.reset(); + other.matCovariance.reset(); + } + return *this; +} + + + + diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp new file mode 100644 index 0000000000..22971b8666 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -0,0 +1,251 @@ +/** + * @file bayesridge.hpp + * @ Clement Mercier + * + * Definition of the BayesianRidge class, which performs the + * bayesian linear regression +**/ +#ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP +#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP + +#include + +namespace mlpack{ +namespace regression{ + +class BayesianRidge +{ +public: + /** + * Set the parameters of Bayesian Ridge regression object. The + * regulariation parameter is automaticaly set to its optimal value by + * maximmization of the marginal likelihood. + * + * @param fitIntercept Whether or not center the data according to the * + * examples. + * @param normalize Whether or to normalize the data according to the + * standard deviation of each feature. + **/ + BayesianRidge(const bool fitIntercept = true, + const bool normalize = false); + + /** + * Run BayesianRidge regression. The input matrix (like all mlpack matrices) + * should be + * column-major -- each column is an observation and each row is a dimension. + * + * @param data Column-major input data + * @param responses A vector of targets. + **/ + void Train(const arma::mat& data, + const arma::rowvec& responses); + + /** + * Predict \f$y_{i}\f$ for each data point in the given data matrix using the + * currently-trained Bayesian Ridge model. + * + * @param points The data points to apply the model. + * @param predictions y, which will contained calculated values on completion. + **/ + void Predict(const arma::mat& points, + arma::rowvec& predictions) const; + + /** + * Predict \f$y_{i}\f$ for one point using the + * currently-trained Bayesian Ridge model. + * + * @param point The data point to apply the model. + * @param prediction y, which will contained calculated value on completion. + **/ + + void Predict(const arma::colvec& point, double& prediction) const; + + /** + * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior + * distribution for each data point in the given data matrix using the + * currently-trained Bayesian Ridge estimator. + * + * @param points The data points to apply the model. + * @param predictions y, which will contained calculated values on completion. + * @param std Standard deviations of the predictions. + * @param rowMajor Should be true if the data points matrix is row-major and + * false otherwise. + */ + void Predict(const arma::mat& points, + arma::rowvec& predictions, + arma::rowvec& std) const; + + + /** + * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior + * distribution for point stored in a column vector using the + * currently-trained Bayesian Ridge estimator. + * + * @param point The data points to apply the model. + * @param prediction y, which will contained calculated values on completion. + * @param std Standard deviation of the prediction. + */ + void Predict(const arma::colvec& point, + double& prediction, + double& std) const; + + + /** + * Compute the Root Mean Square Error + * between the predictions returned by the model + * and the true repsonses + * @param Points Data points to predict + * @param responses A vector of targets. + * @return RMSE + **/ + double Rmse(const arma::mat& data, + const arma::rowvec& responses) const; + + /* + * Center and normalize the data. The last four arguments + * allow future modifation of new points. + * + * @param data Design matrix in column-major format, dim(P,N). + * @param responses A vector of targets. + * @param fit_interpept If true data will be centred according to the points. + * @param fit_interpept If true data will be scales by the standard deviations + * of the features computed according to the points. + * @param data_proc data processed, dim(N,P). + * @param responses_proc responses processed, dim(N). + * @param data_offset Mean vector of the design matrix according to the + * points, dim(P). + * @param data_scale Vector containg the standard deviations of the features + * dim(P). + * @param reponses_offset Mean of responses. + */ + void CenterNormalize(const arma::mat& data, + const arma::rowvec& responses, + const bool fit_intercept, + const bool normalize, + arma::mat& data_proc, + arma::rowvec& responses_proc, + arma::colvec& data_offset, + arma::colvec& data_scale, + double& responses_offset); + + + /** + * Copy constructor. Construct the BayesianRidge object by copying the + * given BayesianRidge object. + * + * @param other BayesianRidge to copy. + */ + BayesianRidge(const BayesianRidge& other); + + /** + * Move constructor . Construct the BayesianRidge object by taking ownership + * of the the given BayesianRidge object. + * + * @param other BayesianRidge to take the ownership. + */ + BayesianRidge(BayesianRidge&& other); + + /** + * Copy the given BayesianRidge object. + * + * @param other BayesianRidge object to copy. + */ + BayesianRidge& operator=(const BayesianRidge& other); + + /** + * Take ownershipof the given BayesianRidge object. + * + * @param other BayesianRidge object to copy. + */ + BayesianRidge& operator=(BayesianRidge&& other); + + + /** + * Get the solution vector + * @return omega Solution vector. + **/ + inline arma::colvec getCoefs() const{return this->omega;} + + + /** + * Get the precesion (or inverse variance) beta of the model. + * @return \f$ \beta \f$ + **/ + inline double getBeta() const {return this->beta;} + + + /** + * Get the estimated variance. + * @return 1.0 / \f$ \beta \f$ + **/ + inline double getVariance() const {return 1.0 / this->getBeta();} + + + /** + * Get the mean vector computed on the features over the training points. + * Vector of 0 if fitIntercept is false. + * @return responses_offset + **/ + inline arma::rowvec getdata_offset() const {return this->data_offset;} + + + /** + * Get the vector of standard deviations computed on the features over the + * training points. Vector of 1 if normalize is false. + * @return data_offset + **/ + inline arma::rowvec getdata_scale() const {return this->data_scale;} + + + /** + * Get the mean value of the train responses. + * @return responses_offset + **/ + inline double getresponses_offset() const + {return this->responses_offset;} + + + + template + void serialize(Archive& ar, const unsigned int /* version */); + +private: + //! Center the data if true + bool fitIntercept; + + //! Scale the data by standard deviations if true + bool normalize; + + //! Mean vector computed over the points + arma::colvec data_offset; + + //! Std vector computed over the points + arma::colvec data_scale; + + //! Mean of the response vector computed over the points + double responses_offset; + + //! Precision of the prio pdf (gaussian) + double alpha; + + //! Noise inverse variance + double beta; + + //! Effective number of parameters + double gamma; + + //! Solution vector + arma::colvec omega; + + //! Coavriance matrix of the solution vector omega + arma::mat matCovariance; +}; +} // namespace regression +} // namespace mlpack + +// Include implementation of serialize +#include "bayesian_ridge_impl.hpp" + +#endif + + diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp new file mode 100644 index 0000000000..5edf89f6bb --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp @@ -0,0 +1,42 @@ +/** + * @file bayesian_ridge_impl.hpp + * @author Ryan Curtin/Clement Mercier + * + * Implementation of templated BayesianRidge functions. + * + * 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_BAYESIAN_RIDGE_BAYESIAN_RIDGE_IMPL_HPP +#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_IMPL_HPP + +//! In case it hasn't been included yet. +#include "bayesian_ridge.hpp" + +namespace mlpack { +namespace regression { + +/** + * Serialize the Bayesian Ridge model. + */ +template +void BayesianRidge::serialize(Archive& ar, const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(fitIntercept); + ar & BOOST_SERIALIZATION_NVP(normalize); + ar & BOOST_SERIALIZATION_NVP(data_offset); + ar & BOOST_SERIALIZATION_NVP(data_scale); + ar & BOOST_SERIALIZATION_NVP(responses_offset); + ar & BOOST_SERIALIZATION_NVP(alpha); + ar & BOOST_SERIALIZATION_NVP(beta); + ar & BOOST_SERIALIZATION_NVP(gamma); + ar & BOOST_SERIALIZATION_NVP(omega); + ar & BOOST_SERIALIZATION_NVP(matCovariance); +} + +} // namespace regression +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp new file mode 100644 index 0000000000..b933a643d0 --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -0,0 +1,177 @@ +/** + * @file bayesian_ridge_main.cpp + * @author Clement Mercier + * + * Executable for BayesianRidge. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#include +#include +#include + +#include "bayesian_ridge.hpp" + +using namespace arma; +using namespace std; +using namespace mlpack; +using namespace mlpack::regression; +using namespace mlpack::util; + +PROGRAM_INFO("BayesianRidge", + // Short description. + " An implementation of the bayesian linear regression, also known" + "as the Bayesian Ridge regression. This can train a Bayesian Ridge model " + "and use that model or a pre-trained model to output regression predictions " + "for a test set.", + // Long description. + "An implementation of the bayesian linear regression, also known" + "as the Bayesian Ridge regression.\n " + "This is a probabilistic view and implementation of the Ridge regression. " + "Final solution is obtained by comptuting a posterior distribution from " + "gaussian likelihood and a gaussian isotropic prior distribution on the " + "weigths. " + "\n" + "Optimization is AUTOMATIC and does not require cross validation. " + "The optimization is performed by type II maximium likihood. Parameters " + "are tunned during the maximization of the marginal likelihood. This " + "procedure includes the Occam's razor that penalizes over complex solutions. " + "\n\n" + "This program is able to train a Baysian Ridge model or load a " + "model from file, output regression predictions for a test set, and save " + "the trained model to a file. The Bayesian Ridge algorithm is described in more " + "detail below:" + "\n\n" + "Let X be a matrix where each row is a point and each column is a " + "dimension, t is a vector of targets, alpha is the precision of the " + "gaussian prior distribtion of w, and w is solution to compute. " + "\n\n" + "The Bayesian Ridge comptute the posterior distribution of the parameters " + "by the Bayes's rule : " + "\n\n" + " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" + "\n\n" + "To train a BayesianRidge model, the " + + PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") + + "parameters must be given. The " + PRINT_PARAM_STRING("fitIntercept") + + "and " + PRINT_PARAM_STRING("normalize") + " parameters control the " + "centering and the normalizing options. A trained model can be saved with " + "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " + "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model") + + " parameter." + "\n\n" + "The program can also provide predictions for test data using either the " + "trained model or the given input model. Test points can be specified with" + " the " + PRINT_PARAM_STRING("test") + " parameter. Predicted responses " + "to the test points can be saved with the " + + PRINT_PARAM_STRING("output_predictions") + " output parameter." + "\n\n" + "For example, the following command trains a model on the data " + + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + + " with fitIntercept set to true and normalize set to false (so, Bayesian Ridge " + "is being solved, and then the model is saved to " + + PRINT_MODEL("bayesian_ridge_model") + ":" + "\n\n" + + PRINT_CALL("bayesian_ridge", "input", "data", "responses", "responses", + "fitIntercept", 1, "normalize", 0, "output_model", + "bayesian_ridge_model") + + "\n\n" + "The following command uses the " + PRINT_MODEL("bayesian_ridge_model") + + " to provide predicted responses for the data " + PRINT_DATASET("test") + + " and save those responses to " + PRINT_DATASET("test_predictions") + ": " + "\n\n" + + PRINT_CALL("bayesian_ridge", "input_model", "bayesian_ridge_model", "test", + "test", "output_predictions", "test_predictions")); + +PARAM_TMATRIX_IN("input", "Matrix of covariates (X).", "i"); +PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); + +PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained LARS model to use.", "m"); +PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output LARS model.", "M"); + +PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " + "points).", "t"); + +PARAM_TMATRIX_OUT("output_predictions", "If --test_file is specified, this " + "file is where the predicted responses will be saved.", "o"); + +PARAM_INT_IN("fitIntercept", "Center the data and fit the intercept", + "f", + 1); +PARAM_INT_IN("normalize", "Normlize each feature by their standard deviations.", + "n", + 0); + +static void mlpackMain() +{ + int fitIntercept = CLI::GetParam("fitIntercept"); + int normalize = CLI::GetParam("normalize"); + + // Check parameters -- make sure everything given makes sense. + RequireOnlyOnePassed({ "input", "input_model" }, true); + if (CLI::HasParam("input")) + { + RequireOnlyOnePassed({ "responses" }, true, "if input data is specified, " + "responses must also be specified"); + } + ReportIgnoredParam({{"input", false }}, "responses"); + + RequireAtLeastOnePassed({ "output_predictions", "output_model" }, false, + "no results will be saved"); + // Is this line really rigth ? It comes from lars_main.hpp. + // ReportIgnoredParam({{ "test", true }}, "output_predictions"); + + BayesianRidge* bayesRidge; + if (CLI::HasParam("input")) + { + Log::Info << "input detected " << std::endl; + // Initialize the object. + bayesRidge = new BayesianRidge(fitIntercept, normalize); + + // Load covariates. + mat matX = std::move(CLI::GetParam("input")); + + // Load responses. The responses should be a one-dimensional vector, and it + // seems more likely that these will be stored with one response per line + // (one per row). So we should not transpose upon loading. + mat matY = std::move(CLI::GetParam("responses")); + + // Make sure y is oriented the right way. + if (matY.n_cols == 1) + matY = trans(matY); + if (matY.n_rows > 1) + Log::Fatal << "Only one column or row allowed in responses file!" << endl; + + if (matY.n_elem != matX.n_rows) + Log::Fatal << "Number of responses must be equal to number of rows of X!" + << endl; + + arma::rowvec y = std::move(matY); + arma::rowvec predictionsTrain; + // The Train method is ready to take data in colomn-major format. + bayesRidge->Train(matX.t(), matY); + } + else // We must have --input_model_file. + { + bayesRidge = CLI::GetParam("input_model"); + } + + if (CLI::HasParam("test")) + { + Log::Info << "Regressing on test points." << endl; + // Load test points. + mat testPoints = std::move(CLI::GetParam("test")); + + arma::rowvec predictions; + bayesRidge->Predict(testPoints.t(), predictions); + + // Save test predictions (one per line). + CLI::GetParam("output_predictions") = std::move(predictions.t()); + Log::Info << predictions << std::endl; + } + + CLI::GetParam("output_model") = bayesRidge; +} diff --git a/src/mlpack/methods/bayesian_ridge/cmake_install.cmake b/src/mlpack/methods/bayesian_ridge/cmake_install.cmake new file mode 100644 index 0000000000..890ece009d --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/cmake_install.cmake @@ -0,0 +1,59 @@ +# Install script for directory: /home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +if("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "xUnspecifiedx" OR NOT CMAKE_INSTALL_COMPONENT) + if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge") + file(RPATH_CHECK + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge" + RPATH "") + endif() + file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" TYPE EXECUTABLE FILES "/home/cmercier/Documents/c++/mlpack-3.1.1/bin/mlpack_bayesian_ridge") + if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge") + file(RPATH_CHANGE + FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge" + OLD_RPATH "/home/cmercier/Documents/c++/mlpack-3.1.1/lib:" + NEW_RPATH "") + if(CMAKE_INSTALL_DO_STRIP) + execute_process(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/mlpack_bayesian_ridge") + endif() + endif() +endif() + diff --git a/src/mlpack/methods/bayesian_ridge/utils.cpp b/src/mlpack/methods/bayesian_ridge/utils.cpp new file mode 100644 index 0000000000..8a411c60af --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/utils.cpp @@ -0,0 +1,51 @@ +/** + * @file utils.cpp + * @author _____ + * + * Implementation of some usefull functions for proprocess the data. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#include "utils.hpp" +#include + +using namespace arma; + +void preprocess_data(const mat& data, + const rowvec& responses, + bool fit_intercept, + bool normalize, + mat& data_proc, + rowvec& responses_proc, + colvec& data_offset, + colvec& data_scale, + double& responses_offset) +{ + // Initialize the offsets to their neutral forms. + data_offset = zeros(data.n_rows); + data_scale = ones(data.n_rows); + responses_offset = 0.0; + + if (fit_intercept) + { + data_offset = mean(data, 1); + responses_offset = mean(responses); + } + if (normalize) + data_scale = stddev(data, 0, 1); + + // Copy data and response before the processing. + data_proc = data; + responses_proc = responses; + // Center the data. + data_proc.each_col() -= data_offset; + // Scale the data. + data_proc.each_col() /= data_scale; + // Center the responses. + responses_proc -= responses_offset; +} + + diff --git a/src/mlpack/methods/bayesian_ridge/utils.hpp b/src/mlpack/methods/bayesian_ridge/utils.hpp new file mode 100644 index 0000000000..d4d9ea3efd --- /dev/null +++ b/src/mlpack/methods/bayesian_ridge/utils.hpp @@ -0,0 +1,42 @@ +/** + * @file utils.hpp + * @ _____ + * + * Definition of some usefull function for preprocess the data +**/ + +#ifndef TATON_UTILS_HPP +#define TATON_UTILS_HPP + +#include + +/* + * Center and normalize the data. The last four arguments + * allow future modifation of new points. + * + * @param data Design matrix in column-major format, dim(P,N). + * @param responses A vector of targets. + * @param fit_interpept If true data will be centred according to the points. + * @param fit_interpept If true data will be scales by the standard deviations + * of the features computed according to the points. + * @param data_proc data processed, dim(N,P). + * @param responses_proc responses processed, dim(N). + * @param data_offset Mean vector of the design matrix according to the + * points, dim(P). + * @param data_scale Vector containg the standard deviations of the features + * dim(P). + * @param reponses_offset Mean of responses. + */ +void preprocess_data(const arma::mat& data, + const arma::rowvec& responses, + const bool fit_intercept, + const bool normalize, + arma::mat& data_proc, + arma::rowvec& responses_proc, + arma::colvec& data_offset, + arma::colvec& data_scale, + double& responses_offset); + + + +#endif diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index d443e3ec24..dd12a5baa0 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(mlpack_test augmented_rnns_tasks_test.cpp bias_svd_test.cpp binarize_test.cpp + bayesian_ridge_test.cpp block_krylov_svd_test.cpp cf_test.cpp cli_binding_test.cpp diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp new file mode 100644 index 0000000000..eaff58b81a --- /dev/null +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -0,0 +1,131 @@ +#include +// Includes all relevant components of mlpack. + +#include +#include + +#include + +// #define BOOST_TEST_DYN_LINK +// #define BOOST_TEST_MODULE BayesianRidgeTest +#include + +#include + +using namespace mlpack::regression; +using namespace mlpack::data; +using namespace std; +using namespace arma; + +BOOST_AUTO_TEST_SUITE(BayesianRidgeTest); + +void GenerateProblem(arma::mat& X, + arma::rowvec& y, + size_t nPoints, + size_t nDims, + float sigma=0.0) +{ + arma_rng::set_seed(4); + + X = arma::randn(nDims, nPoints); + arma::colvec omega = arma::randn(nDims); + arma::colvec noise = arma::randn(nPoints) * sigma; + y = (omega.t() * X); + y += noise; +} + +BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) +{ + // First, load the data. + mat Xtrain, Xtest; + rowvec ytrain, ytest; + + // The RMSE are set according to the results obtained by the current + // implementation on the following dataset. + // y = Xw + noise, noise->Normal(0,1/beta), where beta=40 is the + // precision and w vector/solution to recover with the seven first elements + // non zero. + const double RMSETRAIN = 0.14507, RMSETEST = 0.17961; + + Load("reg_x_train.csv", Xtrain, false, true); + Load("reg_x_test.csv", Xtest, false, true); + Load("reg_y_train.csv", ytrain, false, true); + Load("reg_y_test.csv", ytest, false, true); + + // Instanciate and train the estimator + BayesianRidge estimator(true, false); + estimator.Train(Xtrain, ytrain); + + // Check if the RMSE are still equal to the previously fixed values + BOOST_REQUIRE_SMALL(estimator.Rmse(Xtrain,ytrain) - RMSETRAIN, 0.05); + BOOST_REQUIRE_SMALL(estimator.Rmse(Xtest,ytest) - RMSETEST, 0.05); + +} + +BOOST_AUTO_TEST_CASE(TestCenterNormalize) +{ + arma::mat X; + arma::rowvec y; + size_t nDims = 30, nPoints = 100; + GenerateProblem(X, y, nPoints, nDims, 0.5); + + BayesianRidge estimator(false, false); + estimator.Train(X,y); + + // To be neutral data_offset must be all 0. + BOOST_TEST(sum(estimator.getdata_offset()) == 0); + + // To be neutral data_scale must be all 1. + BOOST_TEST(sum(estimator.getdata_scale()) == nDims); +} + +BOOST_AUTO_TEST_CASE(ColinearTest) +{ + arma::mat X; + arma::rowvec y; + + Load("lars_dependent_x.csv", X, false, true); + Load("lars_dependent_y.csv", y, false, true); + + BayesianRidge estimator(false, false); + estimator.Train(X,y); +} + +BOOST_AUTO_TEST_CASE(OnePointTest) +{ + arma::mat X; + arma::rowvec y; + arma::rowvec predictions, std; + double y_i, std_i; + + Load("reg_x_train.csv", X, false, true); + Load("reg_y_train.csv", y, false, true); + + BayesianRidge estimator(false, false); + estimator.Train(X,y); + + // Predict on all the points. + estimator.Predict(X, predictions); + + // Ensure that the single prediction from column vector are possible and + // equal to the matrix version. + for (size_t i = 0; i < y.size(); i++) + { + estimator.Predict(X.col(i), y_i); + BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); + } + + // Ensure that the single prediction from column vector are possible and + // equal to the matrix version. Idem for the std. + estimator.Predict(X, predictions, std); + for (size_t i = 0; i < y.size(); i++) + { + estimator.Predict(X.col(i), y_i, std_i); + BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); + BOOST_REQUIRE_CLOSE(std(i), std_i, 1e-5); + } + } + +BOOST_AUTO_TEST_SUITE_END(); + + From 3bac6a330f8d967b99a20abcd04e1085ae506c63 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 22 Sep 2019 22:36:25 +0200 Subject: [PATCH 002/297] Update the name of the file in the description --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index f164bd06e1..d816e15ad6 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -1,5 +1,5 @@ /** - * @file bayesridge.cpp + * @file bayesian_ridge.cpp * @author Clement Mercier * * Implementation of Bayesian Ridge regression. From 8c15e2843156b8a6fdf2ea56ca19448060e05c85 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 22 Sep 2019 22:37:14 +0200 Subject: [PATCH 003/297] Modify the name of the file in the description --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 22971b8666..e0d7b12966 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -1,9 +1,9 @@ /** - * @file bayesridge.hpp + * @file bayesian_ridge.hpp * @ Clement Mercier * * Definition of the BayesianRidge class, which performs the - * bayesian linear regression + * bayesian linear regression. **/ #ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP #define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP From 2ba7043b3c9d33f014182a49d6c3d4f3c554cd9f Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 22 Sep 2019 22:39:38 +0200 Subject: [PATCH 004/297] Add tests on randomly generated examples. --- src/mlpack/tests/bayesian_ridge_test.cpp | 102 ++++++++++++++--------- 1 file changed, 63 insertions(+), 39 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index eaff58b81a..a0fa971e1b 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -1,21 +1,23 @@ -#include -// Includes all relevant components of mlpack. +/** + * @file bayesian_ridge_test.cpp + * @author Clement Mercier + * + * Test for BayesianRidge. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ -#include -#include #include - -// #define BOOST_TEST_DYN_LINK -// #define BOOST_TEST_MODULE BayesianRidgeTest -#include - #include +#include + using namespace mlpack::regression; using namespace mlpack::data; -using namespace std; -using namespace arma; BOOST_AUTO_TEST_SUITE(BayesianRidgeTest); @@ -25,7 +27,7 @@ void GenerateProblem(arma::mat& X, size_t nDims, float sigma=0.0) { - arma_rng::set_seed(4); + arma::arma_rng::set_seed(4); X = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); @@ -34,35 +36,31 @@ void GenerateProblem(arma::mat& X, y += noise; } +// Ensure that predictions are close enough to the target +// for a free noise dataset. BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) { - // First, load the data. - mat Xtrain, Xtest; - rowvec ytrain, ytest; - - // The RMSE are set according to the results obtained by the current - // implementation on the following dataset. - // y = Xw + noise, noise->Normal(0,1/beta), where beta=40 is the - // precision and w vector/solution to recover with the seven first elements - // non zero. - const double RMSETRAIN = 0.14507, RMSETEST = 0.17961; + arma::mat X; + arma::rowvec y, predictions; - Load("reg_x_train.csv", Xtrain, false, true); - Load("reg_x_test.csv", Xtest, false, true); - Load("reg_y_train.csv", ytrain, false, true); - Load("reg_y_test.csv", ytest, false, true); - - // Instanciate and train the estimator - BayesianRidge estimator(true, false); - estimator.Train(Xtrain, ytrain); - - // Check if the RMSE are still equal to the previously fixed values - BOOST_REQUIRE_SMALL(estimator.Rmse(Xtrain,ytrain) - RMSETRAIN, 0.05); - BOOST_REQUIRE_SMALL(estimator.Rmse(Xtest,ytest) - RMSETEST, 0.05); + GenerateProblem(X, y, 200, 10); + // Instanciate and train the estimator. + BayesianRidge estimator(true); + estimator.Train(X,y); + estimator.Predict(X, predictions); + + for (size_t i = 0; i < y.size(); i++) + { + BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); + } + // Check that the estimated variance is zero. + BOOST_REQUIRE_SMALL(estimator.getVariance(), 1e-6); } -BOOST_AUTO_TEST_CASE(TestCenterNormalize) + +// Verify fitIntercept and normalize equal false do not affect the solution. +BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) { arma::mat X; arma::rowvec y; @@ -75,10 +73,37 @@ BOOST_AUTO_TEST_CASE(TestCenterNormalize) // To be neutral data_offset must be all 0. BOOST_TEST(sum(estimator.getdata_offset()) == 0); + // To be neutral responses_offset must be 0. + BOOST_TEST(estimator.getresponses_offset() == 0); + // To be neutral data_scale must be all 1. BOOST_TEST(sum(estimator.getdata_scale()) == nDims); } +// Verify that centering and normalization are correct. +BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) +{ + arma::mat X; + arma::rowvec y; + size_t nDims = 30, nPoints = 100; + GenerateProblem(X, y, nPoints, nDims, 0.5); + + BayesianRidge estimator(true, true); + estimator.Train(X, y); + + arma::colvec x_mean = arma::mean(X, 1); + arma::colvec x_std = arma::stddev(X, 0, 1); + double y_mean = arma::mean(y); + + BOOST_REQUIRE_SMALL(sum(estimator.getdata_offset() - x_mean), 1e-6); + + BOOST_REQUIRE_SMALL(abs(estimator.getresponses_offset() - y_mean), 1e-6); + + BOOST_REQUIRE_SMALL(sum(estimator.getdata_scale() - x_std), 1e-6); +} + + + BOOST_AUTO_TEST_CASE(ColinearTest) { arma::mat X; @@ -98,11 +123,10 @@ BOOST_AUTO_TEST_CASE(OnePointTest) arma::rowvec predictions, std; double y_i, std_i; - Load("reg_x_train.csv", X, false, true); - Load("reg_y_train.csv", y, false, true); - + GenerateProblem(X, y, 100, 10, 2.0); + BayesianRidge estimator(false, false); - estimator.Train(X,y); + estimator.Train(X, y); // Predict on all the points. estimator.Predict(X, predictions); From 6a39b05d8ea60e22698bd50b8446450fc67f9598 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 24 Sep 2019 20:35:56 +0200 Subject: [PATCH 005/297] Modify description --- .../methods/bayesian_ridge/bayesian_ridge_main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index b933a643d0..d3d3b8b3a4 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -32,8 +32,8 @@ PROGRAM_INFO("BayesianRidge", "as the Bayesian Ridge regression.\n " "This is a probabilistic view and implementation of the Ridge regression. " "Final solution is obtained by comptuting a posterior distribution from " - "gaussian likelihood and a gaussian isotropic prior distribution on the " - "weigths. " + "gaussian likelihood and a zero mean gaussian isotropic prior distribution " + "on the solution. " "\n" "Optimization is AUTOMATIC and does not require cross validation. " "The optimization is performed by type II maximium likihood. Parameters " @@ -42,14 +42,14 @@ PROGRAM_INFO("BayesianRidge", "\n\n" "This program is able to train a Baysian Ridge model or load a " "model from file, output regression predictions for a test set, and save " - "the trained model to a file. The Bayesian Ridge algorithm is described in more " + "the trained model to a file. The Bayesian Ridge algorithm is described in more " "detail below:" "\n\n" "Let X be a matrix where each row is a point and each column is a " "dimension, t is a vector of targets, alpha is the precision of the " - "gaussian prior distribtion of w, and w is solution to compute. " + "gaussian prior distribtion of w, and w is solution to determine. " "\n\n" - "The Bayesian Ridge comptute the posterior distribution of the parameters " + "The Bayesian Ridge comptutes the posterior distribution of the parameters " "by the Bayes's rule : " "\n\n" " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" From 88fc11c39c1f8df29cc31f933e5e2c7751163fd9 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 24 Sep 2019 20:36:45 +0200 Subject: [PATCH 006/297] Add short description and references --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index e0d7b12966..ed35b3c391 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -3,7 +3,8 @@ * @ Clement Mercier * * Definition of the BayesianRidge class, which performs the - * bayesian linear regression. + * bayesian linear regression. According to the armadillo standards, + * all the functions consider data in column-major format. **/ #ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP #define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP @@ -12,6 +13,19 @@ namespace mlpack{ namespace regression{ + /** + * This class implements the bayesian linear regression. "Bayesian treatment + * of linear regression, which will avoid the over-fitting problem of maximum + * likelihood, and which will also lead to automatic methods of determining + * model complexity using the training data alone.", C.Bishop. + * More details and description in : + * Christopher Bishop (2006), Pattern Recognition and Machine Learning. + * David J.C MacKay (1991), Bayesian Interpolation, Computation and Neural + * systems. + + * Model optimization is automatic and does not require cross validation + * procedure to be optimized. + */ class BayesianRidge { @@ -21,10 +35,10 @@ public: * regulariation parameter is automaticaly set to its optimal value by * maximmization of the marginal likelihood. * - * @param fitIntercept Whether or not center the data according to the * - * examples. + * @param fitIntercept Whether or not center the data according to the + * examples. * @param normalize Whether or to normalize the data according to the - * standard deviation of each feature. + * standard deviation of each feature. **/ BayesianRidge(const bool fitIntercept = true, const bool normalize = false); @@ -45,7 +59,7 @@ public: * currently-trained Bayesian Ridge model. * * @param points The data points to apply the model. - * @param predictions y, which will contained calculated values on completion. + * @param predictions y, which will contained predicted values on completion. **/ void Predict(const arma::mat& points, arma::rowvec& predictions) const; @@ -55,21 +69,19 @@ public: * currently-trained Bayesian Ridge model. * * @param point The data point to apply the model. - * @param prediction y, which will contained calculated value on completion. + * @param prediction y, which will contained predicted value on completion. **/ void Predict(const arma::colvec& point, double& prediction) const; /** * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior - * distribution for each data point in the given data matrix using the + * distribution for each data point in the given data matrix, using the * currently-trained Bayesian Ridge estimator. * - * @param points The data points to apply the model. + * @param points The data point to apply the model. * @param predictions y, which will contained calculated values on completion. * @param std Standard deviations of the predictions. - * @param rowMajor Should be true if the data points matrix is row-major and - * false otherwise. */ void Predict(const arma::mat& points, arma::rowvec& predictions, @@ -86,20 +98,21 @@ public: * @param std Standard deviation of the prediction. */ void Predict(const arma::colvec& point, - double& prediction, - double& std) const; + double& prediction, + double& std) const; /** * Compute the Root Mean Square Error * between the predictions returned by the model - * and the true repsonses + * and the true repsonses. + * * @param Points Data points to predict * @param responses A vector of targets. * @return RMSE **/ double Rmse(const arma::mat& data, - const arma::rowvec& responses) const; + const arma::rowvec& responses) const; /* * Center and normalize the data. The last four arguments @@ -138,7 +151,7 @@ public: BayesianRidge(const BayesianRidge& other); /** - * Move constructor . Construct the BayesianRidge object by taking ownership + * Move constructor. Construct the BayesianRidge object by taking ownership * of the the given BayesianRidge object. * * @param other BayesianRidge to take the ownership. @@ -153,7 +166,7 @@ public: BayesianRidge& operator=(const BayesianRidge& other); /** - * Take ownershipof the given BayesianRidge object. + * Take ownership of the given BayesianRidge object. * * @param other BayesianRidge object to copy. */ @@ -162,6 +175,7 @@ public: /** * Get the solution vector + * * @return omega Solution vector. **/ inline arma::colvec getCoefs() const{return this->omega;} @@ -169,6 +183,7 @@ public: /** * Get the precesion (or inverse variance) beta of the model. + * * @return \f$ \beta \f$ **/ inline double getBeta() const {return this->beta;} @@ -176,6 +191,7 @@ public: /** * Get the estimated variance. + * * @return 1.0 / \f$ \beta \f$ **/ inline double getVariance() const {return 1.0 / this->getBeta();} @@ -184,6 +200,7 @@ public: /** * Get the mean vector computed on the features over the training points. * Vector of 0 if fitIntercept is false. + * * @return responses_offset **/ inline arma::rowvec getdata_offset() const {return this->data_offset;} @@ -191,8 +208,9 @@ public: /** * Get the vector of standard deviations computed on the features over the - * training points. Vector of 1 if normalize is false. - * @return data_offset + * training points. Vector of 1 if normalize is false. + * + * return data_offset **/ inline arma::rowvec getdata_scale() const {return this->data_scale;} @@ -210,40 +228,40 @@ public: void serialize(Archive& ar, const unsigned int /* version */); private: - //! Center the data if true + //! Center the data if true. bool fitIntercept; - //! Scale the data by standard deviations if true + //! Scale the data by standard deviations if true. bool normalize; - //! Mean vector computed over the points + //! Mean vector computed over the points. arma::colvec data_offset; - //! Std vector computed over the points + //! Std vector computed over the points. arma::colvec data_scale; - //! Mean of the response vector computed over the points + //! Mean of the response vector computed over the points. double responses_offset; - //! Precision of the prio pdf (gaussian) + //! Precision of the prior pdf (gaussian). double alpha; - //! Noise inverse variance + //! Noise inverse variance. double beta; - //! Effective number of parameters + //! Effective number of parameters. double gamma; //! Solution vector arma::colvec omega; - //! Coavriance matrix of the solution vector omega + //! Covariance matrix of the solution vector omega. arma::mat matCovariance; }; } // namespace regression } // namespace mlpack -// Include implementation of serialize +// Include implementation of serialize. #include "bayesian_ridge_impl.hpp" #endif From ad91b0bda4312b7d2b5b6f171e7d4637374cc0c7 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 24 Sep 2019 21:00:45 +0200 Subject: [PATCH 007/297] Supress get for the getters --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index d816e15ad6..5910516af2 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -158,7 +158,7 @@ void BayesianRidge::Predict(const arma::mat& points, for (size_t i = 0; i < X.n_cols; i++) { phi = X.col(i); - std[i] = sqrt(this->getVariance() + std[i] = sqrt(this->Variance() + dot(phi.t() * this->matCovariance, phi)); } } diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp index 5edf89f6bb..c9954e124c 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp @@ -12,7 +12,6 @@ #ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_IMPL_HPP #define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_IMPL_HPP -//! In case it hasn't been included yet. #include "bayesian_ridge.hpp" namespace mlpack { From ffeb0ae383ea0b812d440fa1f37d9ed238aeed3b Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 24 Sep 2019 21:01:59 +0200 Subject: [PATCH 008/297] Supress the get of the getters --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index ed35b3c391..68e4f80c84 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -178,7 +178,7 @@ public: * * @return omega Solution vector. **/ - inline arma::colvec getCoefs() const{return this->omega;} + inline arma::colvec Omega() const{return this->omega;} /** @@ -186,7 +186,7 @@ public: * * @return \f$ \beta \f$ **/ - inline double getBeta() const {return this->beta;} + inline double Beta() const {return this->beta;} /** @@ -194,7 +194,7 @@ public: * * @return 1.0 / \f$ \beta \f$ **/ - inline double getVariance() const {return 1.0 / this->getBeta();} + inline double Variance() const {return 1.0 / this->Beta();} /** @@ -203,7 +203,7 @@ public: * * @return responses_offset **/ - inline arma::rowvec getdata_offset() const {return this->data_offset;} + inline arma::rowvec Data_offset() const {return this->data_offset;} /** @@ -212,14 +212,14 @@ public: * * return data_offset **/ - inline arma::rowvec getdata_scale() const {return this->data_scale;} + inline arma::rowvec Data_scale() const {return this->data_scale;} /** * Get the mean value of the train responses. * @return responses_offset **/ - inline double getresponses_offset() const + inline double Responses_offset() const {return this->responses_offset;} From 9c844815966a366846f66fb2d8a46138539d7c95 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 24 Sep 2019 21:02:14 +0200 Subject: [PATCH 009/297] Supress the get of the getters --- src/mlpack/tests/bayesian_ridge_test.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index a0fa971e1b..a29d49bb95 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); } // Check that the estimated variance is zero. - BOOST_REQUIRE_SMALL(estimator.getVariance(), 1e-6); + BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6); } @@ -71,13 +71,13 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) estimator.Train(X,y); // To be neutral data_offset must be all 0. - BOOST_TEST(sum(estimator.getdata_offset()) == 0); + BOOST_TEST(sum(estimator.Data_offset()) == 0); // To be neutral responses_offset must be 0. - BOOST_TEST(estimator.getresponses_offset() == 0); + BOOST_TEST(estimator.Responses_offset() == 0); // To be neutral data_scale must be all 1. - BOOST_TEST(sum(estimator.getdata_scale()) == nDims); + BOOST_TEST(sum(estimator.Data_scale()) == nDims); } // Verify that centering and normalization are correct. @@ -95,11 +95,11 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) arma::colvec x_std = arma::stddev(X, 0, 1); double y_mean = arma::mean(y); - BOOST_REQUIRE_SMALL(sum(estimator.getdata_offset() - x_mean), 1e-6); + BOOST_REQUIRE_SMALL(sum(estimator.Data_offset() - x_mean), 1e-6); - BOOST_REQUIRE_SMALL(abs(estimator.getresponses_offset() - y_mean), 1e-6); + BOOST_REQUIRE_SMALL(abs(estimator.Responses_offset() - y_mean), 1e-6); - BOOST_REQUIRE_SMALL(sum(estimator.getdata_scale() - x_std), 1e-6); + BOOST_REQUIRE_SMALL(sum(estimator.Data_scale() - x_std), 1e-6); } From 2b4f0fb551cbb8d6817cb066ffd99c3fd575942a Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 24 Sep 2019 21:20:20 +0200 Subject: [PATCH 010/297] Code formating --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 5910516af2..1eb566c289 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -20,15 +20,15 @@ using namespace mlpack::regression; BayesianRidge::BayesianRidge(const bool fitIntercept, const bool normalize) : fitIntercept(fitIntercept), - normalize(normalize){ - + normalize(normalize) +{ Log::Info << "Baysian Ridge regression(fitIntercept=" << this->fitIntercept <<", normalize=" <normalize <<")" <data_offset, this->data_scale, this->responses_offset); - vecphitT = phi * t.t(); phiphiT = phi * phi.t(); // Compute the eigenvalues only once. arma::eig_sym(eigval, eigvec, phiphiT); - + unsigned short p = data.n_rows, n = data.n_cols; // Initialize the hyperparameters and // begin with an infinitely broad prior. @@ -80,7 +79,7 @@ void BayesianRidge::Train(const arma::mat& data, // Compute the posterior statistics. // with inv() - for (size_t k = 0; k < p; k++) {matA(k,k) = this->alpha;} + for (size_t k = 0; k < p; k++) {matA(k, k) = this->alpha;} // inv is used instead of solve beacause we need matCovariance to // compute the prediction uncertainties. If solve is used, matCovariance // must be comptuted at the end of the loop. @@ -117,7 +116,7 @@ void BayesianRidge::Predict(const arma::mat& points, //Center and normalize the points before applying the model X.each_col() -= this->data_offset; X.each_col() /= this->data_scale; - predictions = this->omega.t() * X + this->responses_offset; + predictions = this->omega.t() * X + this->responses_offset; } void BayesianRidge::Predict(const arma::colvec& point, double& prediction) const @@ -147,12 +146,12 @@ void BayesianRidge::Predict(const arma::mat& points, { arma::mat X = points; - //Center and normalize the points before applying the model + // Center and normalize the points before applying the model. X.each_col() -= this->data_offset; X.each_col() /= this->data_scale; predictions = this->omega.t() * X + this->responses_offset; - //Compute the standard deviation of each prediction + // Compute the standard deviation of each prediction. std = arma::zeros(X.n_cols); arma::colvec phi(X.n_rows); for (size_t i = 0; i < X.n_cols; i++) @@ -295,8 +294,4 @@ BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) other.matCovariance.reset(); } return *this; -} - - - - +} From 16ae7d2ac948b3c738eb79231f164a7be47fc8a2 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 25 Sep 2019 17:08:14 +0200 Subject: [PATCH 011/297] Delete utils.cpp Unused file. --- src/mlpack/methods/bayesian_ridge/utils.cpp | 51 --------------------- 1 file changed, 51 deletions(-) delete mode 100644 src/mlpack/methods/bayesian_ridge/utils.cpp diff --git a/src/mlpack/methods/bayesian_ridge/utils.cpp b/src/mlpack/methods/bayesian_ridge/utils.cpp deleted file mode 100644 index 8a411c60af..0000000000 --- a/src/mlpack/methods/bayesian_ridge/utils.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file utils.cpp - * @author _____ - * - * Implementation of some usefull functions for proprocess the data. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#include "utils.hpp" -#include - -using namespace arma; - -void preprocess_data(const mat& data, - const rowvec& responses, - bool fit_intercept, - bool normalize, - mat& data_proc, - rowvec& responses_proc, - colvec& data_offset, - colvec& data_scale, - double& responses_offset) -{ - // Initialize the offsets to their neutral forms. - data_offset = zeros(data.n_rows); - data_scale = ones(data.n_rows); - responses_offset = 0.0; - - if (fit_intercept) - { - data_offset = mean(data, 1); - responses_offset = mean(responses); - } - if (normalize) - data_scale = stddev(data, 0, 1); - - // Copy data and response before the processing. - data_proc = data; - responses_proc = responses; - // Center the data. - data_proc.each_col() -= data_offset; - // Scale the data. - data_proc.each_col() /= data_scale; - // Center the responses. - responses_proc -= responses_offset; -} - - From 09d64e5a1a2703907d2a528140d881d45a0d6c15 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 25 Sep 2019 17:08:49 +0200 Subject: [PATCH 012/297] Delete utils.hpp Unused file. --- src/mlpack/methods/bayesian_ridge/utils.hpp | 42 --------------------- 1 file changed, 42 deletions(-) delete mode 100644 src/mlpack/methods/bayesian_ridge/utils.hpp diff --git a/src/mlpack/methods/bayesian_ridge/utils.hpp b/src/mlpack/methods/bayesian_ridge/utils.hpp deleted file mode 100644 index d4d9ea3efd..0000000000 --- a/src/mlpack/methods/bayesian_ridge/utils.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file utils.hpp - * @ _____ - * - * Definition of some usefull function for preprocess the data -**/ - -#ifndef TATON_UTILS_HPP -#define TATON_UTILS_HPP - -#include - -/* - * Center and normalize the data. The last four arguments - * allow future modifation of new points. - * - * @param data Design matrix in column-major format, dim(P,N). - * @param responses A vector of targets. - * @param fit_interpept If true data will be centred according to the points. - * @param fit_interpept If true data will be scales by the standard deviations - * of the features computed according to the points. - * @param data_proc data processed, dim(N,P). - * @param responses_proc responses processed, dim(N). - * @param data_offset Mean vector of the design matrix according to the - * points, dim(P). - * @param data_scale Vector containg the standard deviations of the features - * dim(P). - * @param reponses_offset Mean of responses. - */ -void preprocess_data(const arma::mat& data, - const arma::rowvec& responses, - const bool fit_intercept, - const bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset); - - - -#endif From d0f845b111f2a87eb9c9273a0f197a423d1f7ea5 Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 26 Sep 2019 18:31:35 +0200 Subject: [PATCH 013/297] Supress CMake folder and other files generated by cmake in mlpack/method/bayesian_ridge --- .../CMakeDirectoryInformation.cmake | 16 - .../DependInfo.cmake | 33 - .../cmake_clean.cmake | 12 - .../depend.make | 2 - .../flags.make | 10 - .../generate_pyx_bayesian_ridge.dir/link.txt | 1 - .../progress.make | 5 - .../CXX.includecache | 1186 ----------------- .../DependInfo.cmake | 32 - .../bayesian_ridge_main.cpp.o | Bin 955104 -> 0 bytes .../cmake_clean.cmake | 10 - .../mlpack_bayesian_ridge.dir/depend.internal | 146 -- .../mlpack_bayesian_ridge.dir/depend.make | 146 -- .../mlpack_bayesian_ridge.dir/flags.make | 10 - .../mlpack_bayesian_ridge.dir/link.txt | 1 - .../mlpack_bayesian_ridge.dir/progress.make | 3 - .../bayesian_ridge/CMakeFiles/progress.marks | 1 - .../bayesian_ridge/CTestTestfile.cmake | 6 - src/mlpack/methods/bayesian_ridge/Makefile | 334 ----- .../bayesian_ridge/cmake_install.cmake | 59 - src/mlpack/methods/bayesian_ridge/utils.cpp | 51 - src/mlpack/methods/bayesian_ridge/utils.hpp | 42 - 22 files changed, 2106 deletions(-) delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/cmake_clean.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/depend.internal delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/depend.make delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/flags.make delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/link.txt delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/progress.make delete mode 100644 src/mlpack/methods/bayesian_ridge/CMakeFiles/progress.marks delete mode 100644 src/mlpack/methods/bayesian_ridge/CTestTestfile.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/Makefile delete mode 100644 src/mlpack/methods/bayesian_ridge/cmake_install.cmake delete mode 100644 src/mlpack/methods/bayesian_ridge/utils.cpp delete mode 100644 src/mlpack/methods/bayesian_ridge/utils.hpp diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake deleted file mode 100644 index a6dbbd7d85..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/CMakeDirectoryInformation.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.10 - -# Relative path conversion top directories. -set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/cmercier/Documents/c++/mlpack-3.1.1") -set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/cmercier/Documents/c++/mlpack-3.1.1") - -# Force unix paths in dependencies. -set(CMAKE_FORCE_UNIX_PATHS 1) - - -# The C and CXX include file regular expressions for this directory. -set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") -set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") -set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) -set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake deleted file mode 100644 index 5b7578e156..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/DependInfo.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# The set of languages for which implicit dependencies are needed: -set(CMAKE_DEPENDS_LANGUAGES - "CXX" - ) -# The set of files for implicit dependencies of each language: -set(CMAKE_DEPENDS_CHECK_CXX - "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/bindings/python/generate_pyx_bayesian_ridge.cpp" "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/generate_pyx_bayesian_ridge.cpp.o" - "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/bindings/python/print_pyx.cpp" "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/print_pyx.cpp.o" - ) -set(CMAKE_CXX_COMPILER_ID "GNU") - -# Preprocessor definitions for this target. -set(CMAKE_TARGET_DEFINITIONS_CXX - "ARMA_NO_DEBUG" - "BOOST_TEST_DYN_LINK" - "HAS_OPENMP" - "NDEBUG" - ) - -# The include file search paths: -set(CMAKE_CXX_TARGET_INCLUDE_PATH - "src" - "deps/ensmallen-1.16.2/include" - "src/mlpack/.." - ) - -# Targets to which this target links. -set(CMAKE_TARGET_LINKED_INFO_FILES - "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/CMakeFiles/mlpack.dir/DependInfo.cmake" - ) - -# Fortran module output directory. -set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake deleted file mode 100644 index 527d4dc9a3..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean.cmake +++ /dev/null @@ -1,12 +0,0 @@ -file(REMOVE_RECURSE - "../../bindings/python/generate_pyx_bayesian_ridge.cpp" - "CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/generate_pyx_bayesian_ridge.cpp.o" - "CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/print_pyx.cpp.o" - "../../../../bin/generate_pyx_bayesian_ridge.pdb" - "../../../../bin/generate_pyx_bayesian_ridge" -) - -# Per-language clean rules from dependency scanning. -foreach(lang CXX) - include(CMakeFiles/generate_pyx_bayesian_ridge.dir/cmake_clean_${lang}.cmake OPTIONAL) -endforeach() diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make deleted file mode 100644 index 058a3ed7a2..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/depend.make +++ /dev/null @@ -1,2 +0,0 @@ -# Empty dependencies file for generate_pyx_bayesian_ridge. -# This may be replaced when dependencies are built. diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make deleted file mode 100644 index 17a2bd481b..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/flags.make +++ /dev/null @@ -1,10 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.10 - -# compile CXX with /usr/bin/c++ -CXX_FLAGS = -Wall -Wextra -ftemplate-depth=1000 -O3 -fopenmp -DBINDING_TYPE=BINDING_TYPE_PYX -std=gnu++11 - -CXX_DEFINES = -DARMA_NO_DEBUG -DBOOST_TEST_DYN_LINK -DHAS_OPENMP -DNDEBUG - -CXX_INCLUDES = -I/home/cmercier/Documents/c++/mlpack-3.1.1/src -I/home/cmercier/Documents/c++/mlpack-3.1.1/deps/ensmallen-1.16.2/include -I/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/.. - diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt deleted file mode 100644 index 918b8bbd23..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/link.txt +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/c++ -Wall -Wextra -ftemplate-depth=1000 -O3 -fopenmp -rdynamic CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/generate_pyx_bayesian_ridge.cpp.o CMakeFiles/generate_pyx_bayesian_ridge.dir/__/__/bindings/python/print_pyx.cpp.o -o ../../../../bin/generate_pyx_bayesian_ridge -Wl,-rpath,/home/cmercier/Documents/c++/mlpack-3.1.1/lib ../../../../lib/libmlpack.so.3.1 /usr/lib/libarmadillo.so /usr/lib/x86_64-linux-gnu/libboost_program_options.so /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so /usr/lib/x86_64-linux-gnu/libboost_serialization.so diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make b/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make deleted file mode 100644 index 3962a19c46..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/generate_pyx_bayesian_ridge.dir/progress.make +++ /dev/null @@ -1,5 +0,0 @@ -CMAKE_PROGRESS_1 = -CMAKE_PROGRESS_2 = -CMAKE_PROGRESS_3 = -CMAKE_PROGRESS_4 = 11 - diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache deleted file mode 100644 index 08004f3324..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/CXX.includecache +++ /dev/null @@ -1,1186 +0,0 @@ -#IncludeRegexLine: ^[ ]*[#%][ ]*(include|import)[ ]*[<"]([^">]+)([">]) - -#IncludeRegexScan: ^.*$ - -#IncludeRegexComplain: ^$ - -#IncludeRegexTransform: - -/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp -mlpack/prereqs.hpp -- -bayesian_ridge_impl.hpp -/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp - -/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp -bayesian_ridge.hpp -/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp - -/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp -mlpack/prereqs.hpp -- -mlpack/core/util/cli.hpp -- -mlpack/core/util/mlpack_main.hpp -- -bayesian_ridge.hpp -/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp - -src/mlpack/bindings/cli/add_to_po.hpp -mlpack/core/util/param_data.hpp -- -boost/program_options.hpp -- -mlpack/core/util/is_std_vector.hpp -- -map_parameter_name.hpp -src/mlpack/bindings/cli/map_parameter_name.hpp - -src/mlpack/bindings/cli/cli_option.hpp -string -- -mlpack/core/util/cli.hpp -- -parameter_type.hpp -src/mlpack/bindings/cli/parameter_type.hpp -add_to_po.hpp -src/mlpack/bindings/cli/add_to_po.hpp -default_param.hpp -src/mlpack/bindings/cli/default_param.hpp -output_param.hpp -src/mlpack/bindings/cli/output_param.hpp -get_printable_param.hpp -src/mlpack/bindings/cli/get_printable_param.hpp -string_type_param.hpp -src/mlpack/bindings/cli/string_type_param.hpp -get_param.hpp -src/mlpack/bindings/cli/get_param.hpp -get_raw_param.hpp -src/mlpack/bindings/cli/get_raw_param.hpp -map_parameter_name.hpp -src/mlpack/bindings/cli/map_parameter_name.hpp -set_param.hpp -src/mlpack/bindings/cli/set_param.hpp -get_printable_param_name.hpp -src/mlpack/bindings/cli/get_printable_param_name.hpp -get_printable_param_value.hpp -src/mlpack/bindings/cli/get_printable_param_value.hpp -get_allocated_memory.hpp -src/mlpack/bindings/cli/get_allocated_memory.hpp -delete_allocated_memory.hpp -src/mlpack/bindings/cli/delete_allocated_memory.hpp - -src/mlpack/bindings/cli/default_param.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- -mlpack/core/util/is_std_vector.hpp -- -default_param_impl.hpp -src/mlpack/bindings/cli/default_param_impl.hpp - -src/mlpack/bindings/cli/default_param_impl.hpp -default_param.hpp -src/mlpack/bindings/cli/default_param.hpp - -src/mlpack/bindings/cli/delete_allocated_memory.hpp -mlpack/core/util/param_data.hpp -- - -src/mlpack/bindings/cli/end_program.hpp -mlpack/core/util/cli.hpp -- - -src/mlpack/bindings/cli/get_allocated_memory.hpp -mlpack/core/util/param_data.hpp -- - -src/mlpack/bindings/cli/get_param.hpp -mlpack/prereqs.hpp -- -parameter_type.hpp -src/mlpack/bindings/cli/parameter_type.hpp - -src/mlpack/bindings/cli/get_printable_param.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- -mlpack/core/util/is_std_vector.hpp -- -get_printable_param_impl.hpp -src/mlpack/bindings/cli/get_printable_param_impl.hpp - -src/mlpack/bindings/cli/get_printable_param_impl.hpp -get_printable_param.hpp -src/mlpack/bindings/cli/get_printable_param.hpp - -src/mlpack/bindings/cli/get_printable_param_name.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- -get_printable_param_name_impl.hpp -src/mlpack/bindings/cli/get_printable_param_name_impl.hpp - -src/mlpack/bindings/cli/get_printable_param_name_impl.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- - -src/mlpack/bindings/cli/get_printable_param_value.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- -get_printable_param_value_impl.hpp -src/mlpack/bindings/cli/get_printable_param_value_impl.hpp - -src/mlpack/bindings/cli/get_printable_param_value_impl.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- - -src/mlpack/bindings/cli/get_printable_type.hpp -get_printable_type_impl.hpp -src/mlpack/bindings/cli/get_printable_type_impl.hpp - -src/mlpack/bindings/cli/get_printable_type_impl.hpp -get_printable_type.hpp -src/mlpack/bindings/cli/get_printable_type.hpp - -src/mlpack/bindings/cli/get_raw_param.hpp -mlpack/prereqs.hpp -- -parameter_type.hpp -src/mlpack/bindings/cli/parameter_type.hpp - -src/mlpack/bindings/cli/map_parameter_name.hpp -mlpack/core/util/param_data.hpp -- - -src/mlpack/bindings/cli/output_param.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- -mlpack/core/util/is_std_vector.hpp -- -output_param_impl.hpp -src/mlpack/bindings/cli/output_param_impl.hpp - -src/mlpack/bindings/cli/output_param_impl.hpp -output_param.hpp -src/mlpack/bindings/cli/output_param.hpp -mlpack/core/data/save.hpp -- -iostream -- - -src/mlpack/bindings/cli/parameter_type.hpp -mlpack/prereqs.hpp -- - -src/mlpack/bindings/cli/parse_command_line.hpp -mlpack/core.hpp -- -boost/program_options.hpp -- -print_help.hpp -src/mlpack/bindings/cli/print_help.hpp - -src/mlpack/bindings/cli/print_doc_functions.hpp -mlpack/core/util/hyphenate_string.hpp -- -print_doc_functions_impl.hpp -src/mlpack/bindings/cli/print_doc_functions_impl.hpp - -src/mlpack/bindings/cli/print_doc_functions_impl.hpp -mlpack/core/util/hyphenate_string.hpp -- - -src/mlpack/bindings/cli/print_help.hpp -mlpack/core.hpp -- - -src/mlpack/bindings/cli/set_param.hpp -mlpack/prereqs.hpp -- -parameter_type.hpp -src/mlpack/bindings/cli/parameter_type.hpp - -src/mlpack/bindings/cli/string_type_param.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/param_data.hpp -- -mlpack/core/util/is_std_vector.hpp -- -string_type_param_impl.hpp -src/mlpack/bindings/cli/string_type_param_impl.hpp - -src/mlpack/bindings/cli/string_type_param_impl.hpp -string_type_param.hpp -src/mlpack/bindings/cli/string_type_param.hpp - -src/mlpack/bindings/markdown/binding_info.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/program_doc.hpp -- - -src/mlpack/bindings/markdown/get_printable_type.hpp -binding_info.hpp -src/mlpack/bindings/markdown/binding_info.hpp -mlpack/bindings/cli/get_printable_type.hpp -- -mlpack/bindings/python/get_printable_type.hpp -- - -src/mlpack/bindings/markdown/is_serializable.hpp -mlpack/prereqs.hpp -- - -src/mlpack/bindings/markdown/md_option.hpp -mlpack/core/util/param_data.hpp -- -mlpack/core/util/cli.hpp -- -default_param.hpp -src/mlpack/bindings/markdown/default_param.hpp -get_param.hpp -src/mlpack/bindings/markdown/get_param.hpp -get_printable_param.hpp -src/mlpack/bindings/markdown/get_printable_param.hpp -get_printable_param_name.hpp -src/mlpack/bindings/markdown/get_printable_param_name.hpp -get_printable_param_value.hpp -src/mlpack/bindings/markdown/get_printable_param_value.hpp -get_printable_type.hpp -src/mlpack/bindings/markdown/get_printable_type.hpp -is_serializable.hpp -src/mlpack/bindings/markdown/is_serializable.hpp - -src/mlpack/bindings/markdown/print_doc_functions.hpp -mlpack/prereqs.hpp -- -print_doc_functions_impl.hpp -src/mlpack/bindings/markdown/print_doc_functions_impl.hpp - -src/mlpack/bindings/markdown/program_doc_wrapper.hpp -binding_info.hpp -src/mlpack/bindings/markdown/binding_info.hpp - -src/mlpack/bindings/python/get_arma_type.hpp -mlpack/prereqs.hpp -- - -src/mlpack/bindings/python/get_cython_type.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/is_std_vector.hpp -- - -src/mlpack/bindings/python/get_numpy_type.hpp -mlpack/prereqs.hpp -- - -src/mlpack/bindings/python/get_numpy_type_char.hpp -mlpack/prereqs.hpp -- - -src/mlpack/bindings/python/get_printable_type.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/is_std_vector.hpp -- -get_printable_type_impl.hpp -src/mlpack/bindings/python/get_printable_type_impl.hpp - -src/mlpack/bindings/python/import_decl.hpp -mlpack/prereqs.hpp -- -strip_type.hpp -src/mlpack/bindings/python/strip_type.hpp - -src/mlpack/bindings/python/print_class_defn.hpp -strip_type.hpp -src/mlpack/bindings/python/strip_type.hpp - -src/mlpack/bindings/python/print_defn.hpp -mlpack/prereqs.hpp -- - -src/mlpack/bindings/python/print_doc.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/hyphenate_string.hpp -- -get_printable_type.hpp -src/mlpack/bindings/python/get_printable_type.hpp - -src/mlpack/bindings/python/print_doc_functions.hpp -mlpack/core/util/hyphenate_string.hpp -- -print_doc_functions_impl.hpp -src/mlpack/bindings/python/print_doc_functions_impl.hpp - -src/mlpack/bindings/python/print_input_processing.hpp -mlpack/prereqs.hpp -- -get_arma_type.hpp -src/mlpack/bindings/python/get_arma_type.hpp -get_numpy_type.hpp -src/mlpack/bindings/python/get_numpy_type.hpp -get_numpy_type_char.hpp -src/mlpack/bindings/python/get_numpy_type_char.hpp -get_cython_type.hpp -src/mlpack/bindings/python/get_cython_type.hpp -strip_type.hpp -src/mlpack/bindings/python/strip_type.hpp - -src/mlpack/bindings/python/print_output_processing.hpp -mlpack/prereqs.hpp -- -get_arma_type.hpp -src/mlpack/bindings/python/get_arma_type.hpp -get_numpy_type_char.hpp -src/mlpack/bindings/python/get_numpy_type_char.hpp -get_cython_type.hpp -src/mlpack/bindings/python/get_cython_type.hpp - -src/mlpack/bindings/python/py_option.hpp -mlpack/core/util/param_data.hpp -- -default_param.hpp -src/mlpack/bindings/python/default_param.hpp -get_param.hpp -src/mlpack/bindings/python/get_param.hpp -get_printable_param.hpp -src/mlpack/bindings/python/get_printable_param.hpp -print_class_defn.hpp -src/mlpack/bindings/python/print_class_defn.hpp -print_defn.hpp -src/mlpack/bindings/python/print_defn.hpp -print_doc.hpp -src/mlpack/bindings/python/print_doc.hpp -print_input_processing.hpp -src/mlpack/bindings/python/print_input_processing.hpp -print_output_processing.hpp -src/mlpack/bindings/python/print_output_processing.hpp -import_decl.hpp -src/mlpack/bindings/python/import_decl.hpp - -src/mlpack/bindings/python/strip_type.hpp - -src/mlpack/bindings/tests/clean_memory.hpp - -src/mlpack/bindings/tests/ignore_check.hpp - -src/mlpack/bindings/tests/test_option.hpp -string -- -mlpack/core/util/cli.hpp -- -get_printable_param.hpp -src/mlpack/bindings/tests/get_printable_param.hpp -get_param.hpp -src/mlpack/bindings/tests/get_param.hpp -get_allocated_memory.hpp -src/mlpack/bindings/tests/get_allocated_memory.hpp -delete_allocated_memory.hpp -src/mlpack/bindings/tests/delete_allocated_memory.hpp - -src/mlpack/core.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/arma_traits.hpp -- -mlpack/core/util/log.hpp -- -mlpack/core/util/cli.hpp -- -mlpack/core/util/deprecated.hpp -- -mlpack/core/data/load.hpp -- -mlpack/core/data/save.hpp -- -mlpack/core/data/normalize_labels.hpp -- -mlpack/core/math/clamp.hpp -- -mlpack/core/math/random.hpp -- -mlpack/core/math/random_basis.hpp -- -mlpack/core/math/lin_alg.hpp -- -mlpack/core/math/range.hpp -- -mlpack/core/math/round.hpp -- -mlpack/core/math/shuffle_data.hpp -- -mlpack/core/math/ccov.hpp -- -mlpack/core/math/make_alias.hpp -- -mlpack/core/dists/discrete_distribution.hpp -- -mlpack/core/dists/gaussian_distribution.hpp -- -mlpack/core/dists/laplace_distribution.hpp -- -mlpack/core/dists/gamma_distribution.hpp -- -mlpack/core/dists/diagonal_gaussian_distribution.hpp -- -mlpack/core/data/confusion_matrix.hpp -- -mlpack/core/data/one_hot_encoding.hpp -- -mlpack/core/util/backtrace.hpp -- -mlpack/core/kernels/kernel_traits.hpp -- -mlpack/core/kernels/linear_kernel.hpp -- -mlpack/core/kernels/polynomial_kernel.hpp -- -mlpack/core/kernels/cosine_distance.hpp -- -mlpack/core/kernels/gaussian_kernel.hpp -- -mlpack/core/kernels/epanechnikov_kernel.hpp -- -mlpack/core/kernels/hyperbolic_tangent_kernel.hpp -- -mlpack/core/kernels/laplacian_kernel.hpp -- -mlpack/core/kernels/pspectrum_string_kernel.hpp -- -mlpack/core/kernels/spherical_kernel.hpp -- -mlpack/core/kernels/triangular_kernel.hpp -- -mlpack/core/kernels/cauchy_kernel.hpp -- -omp.h -- - -src/mlpack/core/arma_extend/arma_extend.hpp -boost/serialization/serialization.hpp -- -boost/serialization/nvp.hpp -- -boost/serialization/array.hpp -- -armadillo -- -hdf5_misc.hpp -src/mlpack/core/arma_extend/hdf5_misc.hpp -fn_inplace_reshape.hpp -src/mlpack/core/arma_extend/fn_inplace_reshape.hpp - -src/mlpack/core/arma_extend/fn_inplace_reshape.hpp - -src/mlpack/core/arma_extend/hdf5_misc.hpp - -src/mlpack/core/boost_backport/boost_backport_serialization.hpp -boost/version.hpp -- -mlpack/core/boost_backport/unordered_map.hpp -src/mlpack/core/boost_backport/mlpack/core/boost_backport/unordered_map.hpp -boost/serialization/unordered_map.hpp -- -mlpack/core/boost_backport/collections_load_imp.hpp -src/mlpack/core/boost_backport/mlpack/core/boost_backport/collections_load_imp.hpp -mlpack/core/boost_backport/collections_save_imp.hpp -src/mlpack/core/boost_backport/mlpack/core/boost_backport/collections_save_imp.hpp -mlpack/core/boost_backport/vector.hpp -src/mlpack/core/boost_backport/mlpack/core/boost_backport/vector.hpp -boost/serialization/vector.hpp -- - -src/mlpack/core/boost_backport/collections_load_imp.hpp -boost/assert.hpp -- -cstddef -- -boost/config.hpp -- -boost/detail/workaround.hpp -- -boost/archive/detail/basic_iarchive.hpp -- -boost/serialization/access.hpp -- -boost/serialization/nvp.hpp -- -boost/serialization/detail/stack_constructor.hpp -- -boost/serialization/collection_size_type.hpp -- -boost/serialization/item_version_type.hpp -- -boost/serialization/detail/is_default_constructible.hpp -- -boost/utility/enable_if.hpp -- - -src/mlpack/core/boost_backport/collections_save_imp.hpp -boost/config.hpp -- -boost/serialization/nvp.hpp -- -boost/serialization/serialization.hpp -- -boost/serialization/version.hpp -- -boost/serialization/collection_size_type.hpp -- -boost/serialization/item_version_type.hpp -- - -src/mlpack/core/boost_backport/unordered_collections_load_imp.hpp -boost/assert.hpp -- -cstddef -- -boost/config.hpp -- -boost/detail/workaround.hpp -- -boost/archive/detail/basic_iarchive.hpp -- -boost/serialization/access.hpp -- -boost/serialization/nvp.hpp -- -boost/serialization/detail/stack_constructor.hpp -- -boost/serialization/collection_size_type.hpp -- -boost/serialization/item_version_type.hpp -- - -src/mlpack/core/boost_backport/unordered_collections_save_imp.hpp -boost/config.hpp -- -boost/serialization/nvp.hpp -- -boost/serialization/serialization.hpp -- -boost/serialization/version.hpp -- -boost/serialization/collection_size_type.hpp -- -boost/serialization/item_version_type.hpp -- - -src/mlpack/core/boost_backport/unordered_map.hpp -boost/config.hpp -- -unordered_map -- -boost/serialization/utility.hpp -- -unordered_collections_save_imp.hpp -src/mlpack/core/boost_backport/unordered_collections_save_imp.hpp -unordered_collections_load_imp.hpp -src/mlpack/core/boost_backport/unordered_collections_load_imp.hpp -boost/serialization/split_free.hpp -- - -src/mlpack/core/boost_backport/vector.hpp -vector -- -boost/config.hpp -- -boost/detail/workaround.hpp -- -boost/archive/detail/basic_iarchive.hpp -- -boost/serialization/access.hpp -- -boost/serialization/nvp.hpp -- -boost/serialization/collection_size_type.hpp -- -boost/serialization/item_version_type.hpp -- -boost/serialization/collections_save_imp.hpp -- -boost/serialization/collections_load_imp.hpp -- -boost/serialization/split_free.hpp -- -boost/serialization/array.hpp -- -boost/serialization/detail/get_data.hpp -- -boost/serialization/detail/stack_constructor.hpp -- -boost/mpl/bool_fwd.hpp -- -boost/mpl/if.hpp -- -boost/serialization/collection_traits.hpp -- - -src/mlpack/core/data/confusion_matrix.hpp -mlpack/prereqs.hpp -- -confusion_matrix_impl.hpp -src/mlpack/core/data/confusion_matrix_impl.hpp - -src/mlpack/core/data/confusion_matrix_impl.hpp -confusion_matrix.hpp -src/mlpack/core/data/confusion_matrix.hpp - -src/mlpack/core/data/dataset_mapper.hpp -mlpack/prereqs.hpp -- -unordered_map -- -map_policies/increment_policy.hpp -src/mlpack/core/data/map_policies/increment_policy.hpp -dataset_mapper_impl.hpp -src/mlpack/core/data/dataset_mapper_impl.hpp - -src/mlpack/core/data/dataset_mapper_impl.hpp -dataset_mapper.hpp -src/mlpack/core/data/dataset_mapper.hpp - -src/mlpack/core/data/extension.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/data/format.hpp - -src/mlpack/core/data/has_serialize.hpp -mlpack/core/util/sfinae_utility.hpp -- -boost/serialization/serialization.hpp -- -boost/archive/xml_oarchive.hpp -- -type_traits -- - -src/mlpack/core/data/load.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/log.hpp -- -string -- -format.hpp -src/mlpack/core/data/format.hpp -dataset_mapper.hpp -src/mlpack/core/data/dataset_mapper.hpp -load_model_impl.hpp -src/mlpack/core/data/load_model_impl.hpp -load_vec_impl.hpp -src/mlpack/core/data/load_vec_impl.hpp - -src/mlpack/core/data/load_model_impl.hpp -load.hpp -src/mlpack/core/data/load.hpp -algorithm -- -mlpack/core/util/timers.hpp -- -extension.hpp -src/mlpack/core/data/extension.hpp -boost/serialization/serialization.hpp -- -boost/algorithm/string/trim.hpp -- -boost/archive/xml_iarchive.hpp -- -boost/archive/text_iarchive.hpp -- -boost/archive/binary_iarchive.hpp -- -boost/tokenizer.hpp -- -boost/algorithm/string.hpp -- - -src/mlpack/core/data/load_vec_impl.hpp -load.hpp -src/mlpack/core/data/load.hpp - -src/mlpack/core/data/map_policies/datatype.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/data/map_policies/increment_policy.hpp -mlpack/prereqs.hpp -- -unordered_map -- -mlpack/core/data/map_policies/datatype.hpp -- - -src/mlpack/core/data/normalize_labels.hpp -mlpack/prereqs.hpp -- -normalize_labels_impl.hpp -src/mlpack/core/data/normalize_labels_impl.hpp - -src/mlpack/core/data/normalize_labels_impl.hpp -normalize_labels.hpp -src/mlpack/core/data/normalize_labels.hpp - -src/mlpack/core/data/one_hot_encoding.hpp -mlpack/prereqs.hpp -- -one_hot_encoding_impl.hpp -src/mlpack/core/data/one_hot_encoding_impl.hpp - -src/mlpack/core/data/one_hot_encoding_impl.hpp -one_hot_encoding.hpp -src/mlpack/core/data/one_hot_encoding.hpp - -src/mlpack/core/data/save.hpp -mlpack/core/util/log.hpp -- -mlpack/core/arma_extend/arma_extend.hpp -- -string -- -format.hpp -src/mlpack/core/data/format.hpp -save_impl.hpp -src/mlpack/core/data/save_impl.hpp - -src/mlpack/core/data/save_impl.hpp -save.hpp -src/mlpack/core/data/save.hpp -extension.hpp -src/mlpack/core/data/extension.hpp -boost/serialization/serialization.hpp -- -boost/archive/xml_oarchive.hpp -- -boost/archive/text_oarchive.hpp -- -boost/archive/binary_oarchive.hpp -- - -src/mlpack/core/data/serialization_template_version.hpp - -src/mlpack/core/dists/diagonal_gaussian_distribution.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/dists/discrete_distribution.hpp -mlpack/prereqs.hpp -- -mlpack/core/util/log.hpp -- -mlpack/core/math/random.hpp -- - -src/mlpack/core/dists/gamma_distribution.hpp -mlpack/prereqs.hpp -- -mlpack/core/math/random.hpp -- -boost/program_options.hpp -- - -src/mlpack/core/dists/gaussian_distribution.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/dists/laplace_distribution.hpp - -src/mlpack/core/kernels/cauchy_kernel.hpp -mlpack/prereqs.hpp -- -mlpack/core/metrics/lmetric.hpp -- -mlpack/core/kernels/kernel_traits.hpp -- - -src/mlpack/core/kernels/cosine_distance.hpp -mlpack/prereqs.hpp -- -mlpack/core/kernels/kernel_traits.hpp -- -cosine_distance_impl.hpp -src/mlpack/core/kernels/cosine_distance_impl.hpp - -src/mlpack/core/kernels/cosine_distance_impl.hpp -cosine_distance.hpp -src/mlpack/core/kernels/cosine_distance.hpp - -src/mlpack/core/kernels/epanechnikov_kernel.hpp -mlpack/prereqs.hpp -- -mlpack/core/kernels/kernel_traits.hpp -- -epanechnikov_kernel_impl.hpp -src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp - -src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp -epanechnikov_kernel.hpp -src/mlpack/core/kernels/epanechnikov_kernel.hpp -mlpack/core/util/log.hpp -- -mlpack/core/metrics/lmetric.hpp -- - -src/mlpack/core/kernels/gaussian_kernel.hpp -mlpack/prereqs.hpp -- -mlpack/core/metrics/lmetric.hpp -- -mlpack/core/kernels/kernel_traits.hpp -- - -src/mlpack/core/kernels/hyperbolic_tangent_kernel.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/kernels/kernel_traits.hpp - -src/mlpack/core/kernels/laplacian_kernel.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/kernels/linear_kernel.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/kernels/polynomial_kernel.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/kernels/pspectrum_string_kernel.hpp -map -- -string -- -vector -- -mlpack/prereqs.hpp -- -mlpack/core/util/log.hpp -- -pspectrum_string_kernel_impl.hpp -src/mlpack/core/kernels/pspectrum_string_kernel_impl.hpp - -src/mlpack/core/kernels/pspectrum_string_kernel_impl.hpp -pspectrum_string_kernel.hpp -src/mlpack/core/kernels/pspectrum_string_kernel.hpp - -src/mlpack/core/kernels/spherical_kernel.hpp -boost/math/special_functions/gamma.hpp -- -mlpack/prereqs.hpp -- - -src/mlpack/core/kernels/triangular_kernel.hpp -mlpack/prereqs.hpp -- -mlpack/core/metrics/lmetric.hpp -- - -src/mlpack/core/math/ccov.hpp -mlpack/prereqs.hpp -- -ccov_impl.hpp -src/mlpack/core/math/ccov_impl.hpp - -src/mlpack/core/math/ccov_impl.hpp -ccov.hpp -src/mlpack/core/math/ccov.hpp - -src/mlpack/core/math/clamp.hpp -stdlib.h -- -math.h -- -float.h -- - -src/mlpack/core/math/lin_alg.hpp -mlpack/prereqs.hpp -- -lin_alg_impl.hpp -src/mlpack/core/math/lin_alg_impl.hpp - -src/mlpack/core/math/lin_alg_impl.hpp -lin_alg.hpp -src/mlpack/core/math/lin_alg.hpp - -src/mlpack/core/math/make_alias.hpp - -src/mlpack/core/math/random.hpp -mlpack/prereqs.hpp -- -mlpack/mlpack_export.hpp -- -random -- - -src/mlpack/core/math/random_basis.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/math/range.hpp -range_impl.hpp -src/mlpack/core/math/range_impl.hpp - -src/mlpack/core/math/range_impl.hpp -range.hpp -src/mlpack/core/math/range.hpp -float.h -- -sstream -- - -src/mlpack/core/math/round.hpp - -src/mlpack/core/math/shuffle_data.hpp -mlpack/prereqs.hpp -- - -src/mlpack/core/metrics/lmetric.hpp -mlpack/prereqs.hpp -- -lmetric_impl.hpp -src/mlpack/core/metrics/lmetric_impl.hpp - -src/mlpack/core/metrics/lmetric_impl.hpp -lmetric.hpp -src/mlpack/core/metrics/lmetric.hpp - -src/mlpack/core/util/arma_config.hpp - -src/mlpack/core/util/arma_config_check.hpp -arma_config.hpp -src/mlpack/core/util/arma_config.hpp - -src/mlpack/core/util/arma_traits.hpp - -src/mlpack/core/util/backtrace.hpp -string -- -vector -- - -src/mlpack/core/util/cli.hpp -list -- -iostream -- -map -- -string -- -boost/any.hpp -- -mlpack/prereqs.hpp -- -timers.hpp -src/mlpack/core/util/timers.hpp -program_doc.hpp -src/mlpack/core/util/program_doc.hpp -version.hpp -src/mlpack/core/util/version.hpp -param_data.hpp -src/mlpack/core/util/param_data.hpp -cli_impl.hpp -src/mlpack/core/util/cli_impl.hpp - -src/mlpack/core/util/cli_impl.hpp -cli.hpp -src/mlpack/core/util/cli.hpp -prefixedoutstream.hpp -src/mlpack/core/util/prefixedoutstream.hpp -mlpack/core/data/load.hpp -- -mlpack/core/data/save.hpp -- - -src/mlpack/core/util/deprecated.hpp - -src/mlpack/core/util/hyphenate_string.hpp - -src/mlpack/core/util/is_std_vector.hpp -vector -- - -src/mlpack/core/util/log.hpp -string -- -mlpack/mlpack_export.hpp -- -prefixedoutstream.hpp -src/mlpack/core/util/prefixedoutstream.hpp -nulloutstream.hpp -src/mlpack/core/util/nulloutstream.hpp - -src/mlpack/core/util/mlpack_main.hpp -mlpack/bindings/cli/cli_option.hpp -- -mlpack/bindings/cli/print_doc_functions.hpp -- -mlpack/core/util/param.hpp -- -mlpack/bindings/cli/parse_command_line.hpp -- -mlpack/bindings/cli/end_program.hpp -- -mlpack/bindings/tests/test_option.hpp -- -mlpack/bindings/tests/ignore_check.hpp -- -mlpack/bindings/tests/clean_memory.hpp -- -mlpack/core/util/param.hpp -- -mlpack/bindings/python/py_option.hpp -- -mlpack/bindings/python/print_doc_functions.hpp -- -mlpack/core/util/param.hpp -- -mlpack/bindings/markdown/md_option.hpp -- -mlpack/bindings/markdown/print_doc_functions.hpp -- -mlpack/core/util/param.hpp -- -mlpack/bindings/markdown/program_doc_wrapper.hpp -- -param_checks.hpp -src/mlpack/core/util/param_checks.hpp - -src/mlpack/core/util/nulloutstream.hpp -iostream -- -streambuf -- -string -- - -src/mlpack/core/util/param.hpp - -src/mlpack/core/util/param_checks.hpp -mlpack/prereqs.hpp -- -param_checks_impl.hpp -src/mlpack/core/util/param_checks_impl.hpp - -src/mlpack/core/util/param_checks_impl.hpp -param_checks.hpp -src/mlpack/core/util/param_checks.hpp - -src/mlpack/core/util/param_data.hpp -mlpack/prereqs.hpp -- -boost/any.hpp -- - -src/mlpack/core/util/prefixedoutstream.hpp -mlpack/prereqs.hpp -- -prefixedoutstream_impl.hpp -src/mlpack/core/util/prefixedoutstream_impl.hpp - -src/mlpack/core/util/prefixedoutstream_impl.hpp -prefixedoutstream.hpp -src/mlpack/core/util/prefixedoutstream.hpp -backtrace.hpp -src/mlpack/core/util/backtrace.hpp -iostream -- -sstream -- - -src/mlpack/core/util/program_doc.hpp - -src/mlpack/core/util/sfinae_utility.hpp -type_traits -- -cstring -- - -src/mlpack/core/util/timers.hpp -map -- -string -- -chrono -- -thread -- -mutex -- -list -- -atomic -- - -src/mlpack/core/util/version.hpp -string -- - -src/mlpack/mlpack_export.hpp - -src/mlpack/prereqs.hpp -cmath -- -cstdlib -- -cstdio -- -cstring -- -cctype -- -climits -- -cfloat -- -cstdint -- -stdexcept -- -tuple -- -utility -- -boost/serialization/serialization.hpp -- -boost/serialization/map.hpp -- -mlpack/core/boost_backport/boost_backport_serialization.hpp -src/mlpack/mlpack/core/boost_backport/boost_backport_serialization.hpp -mlpack/core/data/has_serialize.hpp -- -mlpack/core/data/serialization_template_version.hpp -- -mlpack/core/arma_extend/arma_extend.hpp -- -mlpack/core/util/arma_traits.hpp -- -mlpack/core/util/arma_config_check.hpp -- -mlpack/core/util/log.hpp -- -mlpack/core/util/timers.hpp -- -mlpack/core/util/deprecated.hpp -- - diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake deleted file mode 100644 index ae8bcc2000..0000000000 --- a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/DependInfo.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# The set of languages for which implicit dependencies are needed: -set(CMAKE_DEPENDS_LANGUAGES - "CXX" - ) -# The set of files for implicit dependencies of each language: -set(CMAKE_DEPENDS_CHECK_CXX - "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp" "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o" - ) -set(CMAKE_CXX_COMPILER_ID "GNU") - -# Preprocessor definitions for this target. -set(CMAKE_TARGET_DEFINITIONS_CXX - "ARMA_NO_DEBUG" - "BOOST_TEST_DYN_LINK" - "HAS_OPENMP" - "NDEBUG" - ) - -# The include file search paths: -set(CMAKE_CXX_TARGET_INCLUDE_PATH - "src" - "deps/ensmallen-1.16.2/include" - "src/mlpack/.." - ) - -# Targets to which this target links. -set(CMAKE_TARGET_LINKED_INFO_FILES - "/home/cmercier/Documents/c++/mlpack-3.1.1/src/mlpack/CMakeFiles/mlpack.dir/DependInfo.cmake" - ) - -# Fortran module output directory. -set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o b/src/mlpack/methods/bayesian_ridge/CMakeFiles/mlpack_bayesian_ridge.dir/bayesian_ridge_main.cpp.o deleted file mode 100644 index bc6546fcefed1def8fcb87d6a76e615aa7fddfd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 955104 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 U;_tnY6 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 mC13fBOce@!zkTal*X!R_TnF*-U4&3<$BFv - -using namespace arma; - -void preprocess_data(const mat& data, - const rowvec& responses, - bool fit_intercept, - bool normalize, - mat& data_proc, - rowvec& responses_proc, - colvec& data_offset, - colvec& data_scale, - double& responses_offset) -{ - // Initialize the offsets to their neutral forms. - data_offset = zeros(data.n_rows); - data_scale = ones(data.n_rows); - responses_offset = 0.0; - - if (fit_intercept) - { - data_offset = mean(data, 1); - responses_offset = mean(responses); - } - if (normalize) - data_scale = stddev(data, 0, 1); - - // Copy data and response before the processing. - data_proc = data; - responses_proc = responses; - // Center the data. - data_proc.each_col() -= data_offset; - // Scale the data. - data_proc.each_col() /= data_scale; - // Center the responses. - responses_proc -= responses_offset; -} - - diff --git a/src/mlpack/methods/bayesian_ridge/utils.hpp b/src/mlpack/methods/bayesian_ridge/utils.hpp deleted file mode 100644 index d4d9ea3efd..0000000000 --- a/src/mlpack/methods/bayesian_ridge/utils.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file utils.hpp - * @ _____ - * - * Definition of some usefull function for preprocess the data -**/ - -#ifndef TATON_UTILS_HPP -#define TATON_UTILS_HPP - -#include - -/* - * Center and normalize the data. The last four arguments - * allow future modifation of new points. - * - * @param data Design matrix in column-major format, dim(P,N). - * @param responses A vector of targets. - * @param fit_interpept If true data will be centred according to the points. - * @param fit_interpept If true data will be scales by the standard deviations - * of the features computed according to the points. - * @param data_proc data processed, dim(N,P). - * @param responses_proc responses processed, dim(N). - * @param data_offset Mean vector of the design matrix according to the - * points, dim(P). - * @param data_scale Vector containg the standard deviations of the features - * dim(P). - * @param reponses_offset Mean of responses. - */ -void preprocess_data(const arma::mat& data, - const arma::rowvec& responses, - const bool fit_intercept, - const bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset); - - - -#endif From 21ae8c699c4bd08699880f5469421e014f9a74ec Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 26 Sep 2019 19:20:33 +0200 Subject: [PATCH 014/297] Code formatting --- src/mlpack/tests/bayesian_ridge_test.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index a29d49bb95..675f9fa158 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -28,7 +28,7 @@ void GenerateProblem(arma::mat& X, float sigma=0.0) { arma::arma_rng::set_seed(4); - + X = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); arma::colvec noise = arma::randn(nPoints) * sigma; @@ -42,12 +42,12 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) { arma::mat X; arma::rowvec y, predictions; - + GenerateProblem(X, y, 200, 10); - + // Instanciate and train the estimator. BayesianRidge estimator(true); - estimator.Train(X,y); + estimator.Train(X, y); estimator.Predict(X, predictions); for (size_t i = 0; i < y.size(); i++) @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) GenerateProblem(X, y, nPoints, nDims, 0.5); BayesianRidge estimator(false, false); - estimator.Train(X,y); + estimator.Train(X, y); // To be neutral data_offset must be all 0. BOOST_TEST(sum(estimator.Data_offset()) == 0); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) double y_mean = arma::mean(y); BOOST_REQUIRE_SMALL(sum(estimator.Data_offset() - x_mean), 1e-6); - + BOOST_REQUIRE_SMALL(abs(estimator.Responses_offset() - y_mean), 1e-6); BOOST_REQUIRE_SMALL(sum(estimator.Data_scale() - x_std), 1e-6); @@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(ColinearTest) Load("lars_dependent_y.csv", y, false, true); BayesianRidge estimator(false, false); - estimator.Train(X,y); + estimator.Train(X, y); } BOOST_AUTO_TEST_CASE(OnePointTest) @@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(OnePointTest) double y_i, std_i; GenerateProblem(X, y, 100, 10, 2.0); - + BayesianRidge estimator(false, false); estimator.Train(X, y); @@ -136,9 +136,9 @@ BOOST_AUTO_TEST_CASE(OnePointTest) for (size_t i = 0; i < y.size(); i++) { estimator.Predict(X.col(i), y_i); - BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); + BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); } - + // Ensure that the single prediction from column vector are possible and // equal to the matrix version. Idem for the std. estimator.Predict(X, predictions, std); @@ -146,9 +146,9 @@ BOOST_AUTO_TEST_CASE(OnePointTest) { estimator.Predict(X.col(i), y_i, std_i); BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); - BOOST_REQUIRE_CLOSE(std(i), std_i, 1e-5); + BOOST_REQUIRE_CLOSE(std(i), std_i, 1e-5); } - } +} BOOST_AUTO_TEST_SUITE_END(); From 13a9bca01c415f2f97e56f06bcbf1e5ca38eb9a3 Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 26 Sep 2019 19:55:07 +0200 Subject: [PATCH 015/297] Code formatting --- .../bayesian_ridge/bayesian_ridge_main.cpp | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index d3d3b8b3a4..38361813f8 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -23,10 +23,10 @@ using namespace mlpack::util; PROGRAM_INFO("BayesianRidge", // Short description. - " An implementation of the bayesian linear regression, also known" + "An implementation of the bayesian linear regression, also known " "as the Bayesian Ridge regression. This can train a Bayesian Ridge model " - "and use that model or a pre-trained model to output regression predictions " - "for a test set.", + "and use that model or a pre-trained model to output regression " + "predictions for a test set.", // Long description. "An implementation of the bayesian linear regression, also known" "as the Bayesian Ridge regression.\n " @@ -38,12 +38,13 @@ PROGRAM_INFO("BayesianRidge", "Optimization is AUTOMATIC and does not require cross validation. " "The optimization is performed by type II maximium likihood. Parameters " "are tunned during the maximization of the marginal likelihood. This " - "procedure includes the Occam's razor that penalizes over complex solutions. " + "procedure includes the Occam's razor that penalizes over complex " + "solutions. " "\n\n" "This program is able to train a Baysian Ridge model or load a " "model from file, output regression predictions for a test set, and save " - "the trained model to a file. The Bayesian Ridge algorithm is described in more " - "detail below:" + "the trained model to a file. The Bayesian Ridge algorithm is described " + "in more detail below:" "\n\n" "Let X be a matrix where each row is a point and each column is a " "dimension, t is a vector of targets, alpha is the precision of the " @@ -60,7 +61,7 @@ PROGRAM_INFO("BayesianRidge", "and " + PRINT_PARAM_STRING("normalize") + " parameters control the " "centering and the normalizing options. A trained model can be saved with " "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " - "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model") + + "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model")+ " parameter." "\n\n" "The program can also provide predictions for test data using either the " @@ -71,8 +72,8 @@ PROGRAM_INFO("BayesianRidge", "\n\n" "For example, the following command trains a model on the data " + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + - " with fitIntercept set to true and normalize set to false (so, Bayesian Ridge " - "is being solved, and then the model is saved to " + + "with fitIntercept set to true and normalize set to false (so, Bayesian " + "Ridge is being solved, and then the model is saved to " + PRINT_MODEL("bayesian_ridge_model") + ":" "\n\n" + PRINT_CALL("bayesian_ridge", "input", "data", "responses", "responses", @@ -80,7 +81,7 @@ PROGRAM_INFO("BayesianRidge", "bayesian_ridge_model") + "\n\n" "The following command uses the " + PRINT_MODEL("bayesian_ridge_model") + - " to provide predicted responses for the data " + PRINT_DATASET("test") + + " to provide predicted responses for the data " + PRINT_DATASET("test") + " and save those responses to " + PRINT_DATASET("test_predictions") + ": " "\n\n" + PRINT_CALL("bayesian_ridge", "input_model", "bayesian_ridge_model", "test", @@ -93,13 +94,13 @@ PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained LARS model to use.", "m"); PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output LARS model.", "M"); PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " - "points).", "t"); + "points).", "t"); PARAM_TMATRIX_OUT("output_predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); PARAM_INT_IN("fitIntercept", "Center the data and fit the intercept", - "f", + "f", 1); PARAM_INT_IN("normalize", "Normlize each feature by their standard deviations.", "n", @@ -127,11 +128,11 @@ static void mlpackMain() BayesianRidge* bayesRidge; if (CLI::HasParam("input")) { - Log::Info << "input detected " << std::endl; + Log::Info << "input detected " << std::endl; // Initialize the object. bayesRidge = new BayesianRidge(fitIntercept, normalize); - // Load covariates. + // Load covariates. mat matX = std::move(CLI::GetParam("input")); // Load responses. The responses should be a one-dimensional vector, and it @@ -164,10 +165,10 @@ static void mlpackMain() Log::Info << "Regressing on test points." << endl; // Load test points. mat testPoints = std::move(CLI::GetParam("test")); - + arma::rowvec predictions; bayesRidge->Predict(testPoints.t(), predictions); - + // Save test predictions (one per line). CLI::GetParam("output_predictions") = std::move(predictions.t()); Log::Info << predictions << std::endl; From b1190969521149a4ff996fe85af2400c64bde52f Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 29 Sep 2019 20:58:08 +0200 Subject: [PATCH 016/297] Change BOOST_TEST for BOOST_REQUIRE --- src/mlpack/tests/bayesian_ridge_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 675f9fa158..f25af476bf 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -71,13 +71,13 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) estimator.Train(X, y); // To be neutral data_offset must be all 0. - BOOST_TEST(sum(estimator.Data_offset()) == 0); + BOOST_REQUIRE(sum(estimator.Data_offset()) == 0); // To be neutral responses_offset must be 0. - BOOST_TEST(estimator.Responses_offset() == 0); + BOOST_REQUIRE(estimator.Responses_offset() == 0); // To be neutral data_scale must be all 1. - BOOST_TEST(sum(estimator.Data_scale()) == nDims); + BOOST_REQUIRE(sum(estimator.Data_scale()) == nDims); } // Verify that centering and normalization are correct. From 619274ca3aa000fd99ace3fc67af1bdb4a90e66c Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 29 Sep 2019 22:28:26 +0200 Subject: [PATCH 017/297] Update documentation + Add an example of use. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 96 ++++++++++++++----- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 68e4f80c84..4175bef141 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -2,53 +2,101 @@ * @file bayesian_ridge.hpp * @ Clement Mercier * - * Definition of the BayesianRidge class, which performs the + * Definition of the BayesianRidge class, which performs the * bayesian linear regression. According to the armadillo standards, * all the functions consider data in column-major format. **/ -#ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP -#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP +#ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP +#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP #include namespace mlpack{ namespace regression{ - /** - * This class implements the bayesian linear regression. "Bayesian treatment - * of linear regression, which will avoid the over-fitting problem of maximum - * likelihood, and which will also lead to automatic methods of determining - * model complexity using the training data alone.", C.Bishop. - * More details and description in : - * Christopher Bishop (2006), Pattern Recognition and Machine Learning. - * David J.C MacKay (1991), Bayesian Interpolation, Computation and Neural - * systems. - - * Model optimization is automatic and does not require cross validation - * procedure to be optimized. - */ - +/** + * This class implements the bayesian linear regression. "Bayesian treatment + * of linear regression, which will avoid the over-fitting problem of maximum + * likelihood, and which will also lead to automatic methods of determining + * model complexity using the training data alone.", C.Bishop. + * + * More details and description in : + * Christopher Bishop (2006), Pattern Recognition and Machine Learning. + * David J.C MacKay (1991), Bayesian Interpolation, Computation and Neural + * systems. + + * Model optimization is automatic and does not require cross validation + * procedure to be optimized. + * + * @code + * @article{MacKay91bayesianinterpolation, + * author = {David J.C. MacKay}, + * title = {Bayesian Interpolation}, + * journal = {NEURAL COMPUTATION}, + * year = {1991}, + * volume = {4}, + * pages = {415--447} + * } + * @endcode + * + * @book{Bishop:2006:PRM:1162264, + * author = {Bishop, Christopher M.}, + * title = {Pattern Recognition and Machine Learning (Information Science + * and Statistics)}, + * chapter = {3} + * year = {2006}, + * isbn = {0387310738}, + * publisher = {Springer-Verlag}, + * address = {Berlin, Heidelberg}, + * } + * @encode + * + * Example of use: + * + * @code + * arma::mat Xtrain; // Train data matrix. Column-major. + * arma::rowvec ytrain; // Train target values. + + * // Train the model. Regularization strength is optimally tunned with the + * // training data alone by applying the Train method. + * BayesianRidge estimator(); // Instanciate the estimator with default option. + * estimator.Train(Xtrain, ytrain); + + * // Prediction on test points. + * arma::mat Xtest; // Test data matrix. Column-major. + * arma::rowvec predictions; + + * estimator.Predict(Xtest, prediction); + + * arma::rowvec ytest; // Test target values. + * estimator.Rmse(Xtest, ytest); // Evaluate using the RMSE score. + + * // Compute the standard deviations of the predictions. + * arma::rowvec stds; + * estimator.Predict(Xtest, responses, stds) + * @endcode + */ class BayesianRidge { public: /** * Set the parameters of Bayesian Ridge regression object. The - * regulariation parameter is automaticaly set to its optimal value by + * regulariation parameter is automaticaly set to its optimal value by * maximmization of the marginal likelihood. * - * @param fitIntercept Whether or not center the data according to the + * @param fitIntercept Whether or not center the data according to the * examples. - * @param normalize Whether or to normalize the data according to the + * @param normalize Whether or to normalize the data according to the * standard deviation of each feature. **/ BayesianRidge(const bool fitIntercept = true, const bool normalize = false); - /** - * Run BayesianRidge regression. The input matrix (like all mlpack matrices) + /** + * Run BayesianRidge regression. The input matrix (like all mlpack matrices) * should be * column-major -- each column is an observation and each row is a dimension. * - * @param data Column-major input data + * @param data Column-major input data * @param responses A vector of targets. **/ void Train(const arma::mat& data, @@ -59,7 +107,7 @@ public: * currently-trained Bayesian Ridge model. * * @param points The data points to apply the model. - * @param predictions y, which will contained predicted values on completion. + * @param predictions y, Contain the predicted values on completion. **/ void Predict(const arma::mat& points, arma::rowvec& predictions) const; From 4c63c3476f94df21066b3e9e30ab3fedef3dfc40 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 5 Oct 2019 11:58:29 +0200 Subject: [PATCH 018/297] Code formatting. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 1eb566c289..d4a1f8a611 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -23,11 +23,11 @@ BayesianRidge::BayesianRidge(const bool fitIntercept, normalize(normalize) { Log::Info << "Baysian Ridge regression(fitIntercept=" - << this->fitIntercept - <<", normalize=" - <normalize - <<")" - <fitIntercept + << ", normalize=" + << this->normalize + << ")" + << std::endl; } void BayesianRidge::Train(const arma::mat& data, @@ -42,7 +42,7 @@ void BayesianRidge::Train(const arma::mat& data, arma::colvec eigval; arma::mat eigvec; arma::colvec eigvali; - + // Preprocess the data. Center and normalize. this->CenterNormalize(data, responses, @@ -64,8 +64,8 @@ void BayesianRidge::Train(const arma::mat& data, // begin with an infinitely broad prior. this->alpha = 1e-6; this->beta = 1 / (var(t) * 0.1); - - double tol = 1e-3; + + double tol = 1e-3; unsigned short nIterMax = 50; unsigned short i = 0; double deltaAlpha = 1, deltaBeta = 1, crit = 1; @@ -113,7 +113,7 @@ void BayesianRidge::Predict(const arma::mat& points, { arma::mat X = points; - //Center and normalize the points before applying the model + // Center and normalize the points before applying the model X.each_col() -= this->data_offset; X.each_col() /= this->data_scale; predictions = this->omega.t() * X + this->responses_offset; From add250c241d93d7fdac33078c50ce87556e468f2 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 5 Oct 2019 11:58:45 +0200 Subject: [PATCH 019/297] Code formatting. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 4175bef141..f71ddbf6bd 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -77,7 +77,7 @@ namespace regression{ */ class BayesianRidge { -public: + public: /** * Set the parameters of Bayesian Ridge regression object. The * regulariation parameter is automaticaly set to its optimal value by @@ -161,8 +161,9 @@ public: **/ double Rmse(const arma::mat& data, const arma::rowvec& responses) const; + - /* + /** * Center and normalize the data. The last four arguments * allow future modifation of new points. * @@ -188,7 +189,7 @@ public: arma::colvec& data_offset, arma::colvec& data_scale, double& responses_offset); - + /** * Copy constructor. Construct the BayesianRidge object by copying the @@ -220,7 +221,7 @@ public: */ BayesianRidge& operator=(BayesianRidge&& other); - + /** * Get the solution vector * @@ -232,9 +233,9 @@ public: /** * Get the precesion (or inverse variance) beta of the model. * - * @return \f$ \beta \f$ + * @return \f$ \beta \f$ **/ - inline double Beta() const {return this->beta;} + inline double Beta() const {return this->beta;} /** @@ -270,12 +271,14 @@ public: inline double Responses_offset() const {return this->responses_offset;} - + /** + * Serialize the BayesianRidge model. + **/ template void serialize(Archive& ar, const unsigned int /* version */); -private: + private: //! Center the data if true. bool fitIntercept; @@ -313,5 +316,3 @@ private: #include "bayesian_ridge_impl.hpp" #endif - - From 2af5f864d1c00df376f6a0aa1bf394cca684dc71 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 5 Oct 2019 11:59:00 +0200 Subject: [PATCH 020/297] Code formatting. --- src/mlpack/tests/bayesian_ridge_test.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index f25af476bf..e732722d9f 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -42,9 +42,9 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) { arma::mat X; arma::rowvec y, predictions; - + GenerateProblem(X, y, 200, 10); - + // Instanciate and train the estimator. BayesianRidge estimator(true); estimator.Train(X, y); @@ -122,9 +122,8 @@ BOOST_AUTO_TEST_CASE(OnePointTest) arma::rowvec y; arma::rowvec predictions, std; double y_i, std_i; - - GenerateProblem(X, y, 100, 10, 2.0); + GenerateProblem(X, y, 100, 10, 2.0); BayesianRidge estimator(false, false); estimator.Train(X, y); @@ -138,7 +137,7 @@ BOOST_AUTO_TEST_CASE(OnePointTest) estimator.Predict(X.col(i), y_i); BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); } - + // Ensure that the single prediction from column vector are possible and // equal to the matrix version. Idem for the std. estimator.Predict(X, predictions, std); @@ -151,5 +150,3 @@ BOOST_AUTO_TEST_CASE(OnePointTest) } BOOST_AUTO_TEST_SUITE_END(); - - From d1d9ffdd46654d8bda48d529617f30ce7e4b111c Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 8 Oct 2019 17:22:54 +0200 Subject: [PATCH 021/297] Code formatting, use space only --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 118 +++++++++--------- 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index d4a1f8a611..92992788ba 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -12,7 +12,7 @@ #include "bayesian_ridge.hpp" #include #include - + using namespace mlpack; using namespace mlpack::regression; @@ -21,14 +21,7 @@ BayesianRidge::BayesianRidge(const bool fitIntercept, const bool normalize) : fitIntercept(fitIntercept), normalize(normalize) -{ - Log::Info << "Baysian Ridge regression(fitIntercept=" - << this->fitIntercept - << ", normalize=" - << this->normalize - << ")" - << std::endl; -} +{/* Nothing to do */} void BayesianRidge::Train(const arma::mat& data, const arma::rowvec& responses) @@ -44,15 +37,15 @@ void BayesianRidge::Train(const arma::mat& data, arma::colvec eigvali; // Preprocess the data. Center and normalize. - this->CenterNormalize(data, - responses, - this->fitIntercept, - this->normalize, - phi, - t, - this->data_offset, - this->data_scale, - this->responses_offset); + CenterNormalize(data, + responses, + fitIntercept, + normalize, + phi, + t, + data_offset, + data_scale, + responses_offset); vecphitT = phi * t.t(); phiphiT = phi * phi.t(); @@ -62,8 +55,8 @@ void BayesianRidge::Train(const arma::mat& data, unsigned short p = data.n_rows, n = data.n_cols; // Initialize the hyperparameters and // begin with an infinitely broad prior. - this->alpha = 1e-6; - this->beta = 1 / (var(t) * 0.1); + alpha = 1e-6; + beta = 1 / (var(t) * 0.1); double tol = 1e-3; unsigned short nIterMax = 50; @@ -74,82 +67,83 @@ void BayesianRidge::Train(const arma::mat& data, while ((crit > tol) && (i < nIterMax)) { - deltaAlpha = -this->alpha; - deltaBeta = -this->beta; + deltaAlpha = -alpha; + deltaBeta = -beta; // Compute the posterior statistics. // with inv() - for (size_t k = 0; k < p; k++) {matA(k, k) = this->alpha;} + for (size_t k = 0; k < p; k++) {matA(k, k) = alpha;} // inv is used instead of solve beacause we need matCovariance to // compute the prediction uncertainties. If solve is used, matCovariance // must be comptuted at the end of the loop. - this->matCovariance = inv_sympd(matA + phiphiT * this->beta); - this->omega = (this->matCovariance * vecphitT) * this->beta; + matCovariance = inv_sympd(matA + phiphiT * beta); + omega = (matCovariance * vecphitT) * beta; // // with solve() - // for (size_t k = 0; k < p; k++) {matA(k,k) = this->alpha / this->beta;} - // this->omega = solve(matA + phiphiT, vecphitT); + // for (size_t k = 0; k < p; k++) {matA(k,k) = alpha / beta;} + // omega = solve(matA + phiphiT, vecphitT); // Update alpha. - eigvali = eigval * this->beta; - gamma = sum(eigvali / (this->alpha + eigvali)); - this->alpha = gamma / dot(this->omega.t(), this->omega); + eigvali = eigval * beta; + gamma = sum(eigvali / (alpha + eigvali)); + alpha = gamma / dot(omega.t(), omega); // Update beta. - temp = t - this->omega.t() * phi; - this->beta = (n - gamma) / dot(temp, temp); + temp = t - omega.t() * phi; + beta = (n - gamma) / dot(temp, temp); // Comptute the stopping criterion. - deltaAlpha += this->alpha; - deltaBeta += this->beta; - crit = abs(deltaAlpha/this->alpha + deltaBeta/this->beta); + deltaAlpha += alpha; + deltaBeta += beta; + crit = abs(deltaAlpha/alpha + deltaBeta/beta); i++; } Timer::Stop("bayesian_ridge_regression"); } void BayesianRidge::Predict(const arma::mat& points, - arma::rowvec& predictions) const + arma::rowvec& predictions) const { arma::mat X = points; // Center and normalize the points before applying the model - X.each_col() -= this->data_offset; - X.each_col() /= this->data_scale; - predictions = this->omega.t() * X + this->responses_offset; + X.each_col() -= data_offset; + X.each_col() /= data_scale; + predictions = omega.t() * X + responses_offset; } -void BayesianRidge::Predict(const arma::colvec& point, double& prediction) const +void BayesianRidge::Predict(const arma::colvec& point, + double& prediction) const { arma::mat point_mat = arma::conv_to::from(point); arma::rowvec prediction_vec(1); - this->Predict(point_mat, prediction_vec); + Predict(point_mat, prediction_vec); prediction = prediction_vec[0]; } void BayesianRidge::Predict(const arma::colvec& point, - double& prediction, - double& std) const + double& prediction, + double& std) const { arma::mat point_mat = arma::conv_to::from(point); arma::rowvec prediction_vec(1); arma::rowvec std_vec(1); - this->Predict(point_mat, prediction_vec, std_vec); + Predict(point_mat, prediction_vec, std_vec); prediction = prediction_vec[0]; std = std_vec[0]; } void BayesianRidge::Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const + arma::rowvec& predictions, + arma::rowvec& std) const { arma::mat X = points; // Center and normalize the points before applying the model. - X.each_col() -= this->data_offset; - X.each_col() /= this->data_scale; - predictions = this->omega.t() * X + this->responses_offset; + X.each_col() -= data_offset; + X.each_col() /= data_scale; + predictions = omega.t() * X + responses_offset; // Compute the standard deviation of each prediction. std = arma::zeros(X.n_cols); @@ -157,28 +151,28 @@ void BayesianRidge::Predict(const arma::mat& points, for (size_t i = 0; i < X.n_cols; i++) { phi = X.col(i); - std[i] = sqrt(this->Variance() - + dot(phi.t() * this->matCovariance, phi)); + std[i] = sqrt(Variance() + + dot(phi.t() * matCovariance, phi)); } } double BayesianRidge::Rmse(const arma::mat& data, - const arma::rowvec& responses) const + const arma::rowvec& responses) const { arma::rowvec predictions; - this->Predict(data, predictions); + Predict(data, predictions); return sqrt(mean(square(responses - predictions))); } void BayesianRidge::CenterNormalize(const arma::mat& data, - const arma::rowvec& responses, - bool fit_intercept, - bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset) + const arma::rowvec& responses, + bool fit_intercept, + bool normalize, + arma::mat& data_proc, + arma::rowvec& responses_proc, + arma::colvec& data_offset, + arma::colvec& data_scale, + double& responses_offset) { // Initialize the offsets to their neutral forms. data_offset = arma::zeros(data.n_rows); @@ -268,7 +262,7 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) { - if (this != &other ) + if (this != &other) { fitIntercept = other.fitIntercept; normalize = other.normalize; From 45f362c36dda15f2f3b37c8ffdcafc47e22ebbb6 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 8 Oct 2019 17:26:02 +0200 Subject: [PATCH 022/297] Modify the call to BOOST_REQUIRE_SMALL. --- src/mlpack/tests/bayesian_ridge_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index e732722d9f..735be4f813 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -95,11 +95,11 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) arma::colvec x_std = arma::stddev(X, 0, 1); double y_mean = arma::mean(y); - BOOST_REQUIRE_SMALL(sum(estimator.Data_offset() - x_mean), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_offset() - x_mean)), 1e-6); - BOOST_REQUIRE_SMALL(abs(estimator.Responses_offset() - y_mean), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(estimator.Responses_offset() - y_mean), 1e-6); - BOOST_REQUIRE_SMALL(sum(estimator.Data_scale() - x_std), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_scale() - x_std)), 1e-6); } From 40956fcd3b1705275d90a22807b75a65dee05362 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 8 Oct 2019 18:08:55 +0200 Subject: [PATCH 023/297] Code formatting. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 92992788ba..4a8a94b3d4 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -38,14 +38,14 @@ void BayesianRidge::Train(const arma::mat& data, // Preprocess the data. Center and normalize. CenterNormalize(data, - responses, - fitIntercept, - normalize, - phi, - t, - data_offset, - data_scale, - responses_offset); + responses, + fitIntercept, + normalize, + phi, + t, + data_offset, + data_scale, + responses_offset); vecphitT = phi * t.t(); phiphiT = phi * phi.t(); From 8edc91acca20c369515c2e1f715322fa80a81e2a Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 14 Oct 2019 22:20:53 +0200 Subject: [PATCH 024/297] Code formatting. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 4a8a94b3d4..6c12e34107 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -12,19 +12,19 @@ #include "bayesian_ridge.hpp" #include #include - + using namespace mlpack; using namespace mlpack::regression; BayesianRidge::BayesianRidge(const bool fitIntercept, - const bool normalize) : + const bool normalize) : fitIntercept(fitIntercept), normalize(normalize) {/* Nothing to do */} void BayesianRidge::Train(const arma::mat& data, - const arma::rowvec& responses) + const arma::rowvec& responses) { Timer::Start("bayesian_ridge_regression"); @@ -32,32 +32,32 @@ void BayesianRidge::Train(const arma::mat& data, arma::rowvec t; arma::colvec vecphitT; arma::mat phiphiT; - arma::colvec eigval; + arma::colvec eigval; arma::mat eigvec; arma::colvec eigvali; - + // Preprocess the data. Center and normalize. CenterNormalize(data, - responses, - fitIntercept, - normalize, - phi, - t, - data_offset, - data_scale, - responses_offset); + responses, + fitIntercept, + normalize, + phi, + t, + data_offset, + data_scale, + responses_offset); vecphitT = phi * t.t(); phiphiT = phi * phi.t(); - + // Compute the eigenvalues only once. arma::eig_sym(eigval, eigvec, phiphiT); - + unsigned short p = data.n_rows, n = data.n_cols; // Initialize the hyperparameters and // begin with an infinitely broad prior. alpha = 1e-6; beta = 1 / (var(t) * 0.1); - + double tol = 1e-3; unsigned short nIterMax = 50; unsigned short i = 0; @@ -91,7 +91,7 @@ void BayesianRidge::Train(const arma::mat& data, // Update beta. temp = t - omega.t() * phi; beta = (n - gamma) / dot(temp, temp); - + // Comptute the stopping criterion. deltaAlpha += alpha; deltaBeta += beta; @@ -246,7 +246,7 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) { if (this == &other) return *this; - + fitIntercept = other.fitIntercept; normalize = other.normalize; data_offset = other.data_offset; From 607f4f484db8427952ba9475b52700fdf644155b Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 14 Oct 2019 22:21:06 +0200 Subject: [PATCH 025/297] Code formatting. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index f71ddbf6bd..59d7f51c46 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -89,7 +89,7 @@ class BayesianRidge * standard deviation of each feature. **/ BayesianRidge(const bool fitIntercept = true, - const bool normalize = false); + const bool normalize = false); /** * Run BayesianRidge regression. The input matrix (like all mlpack matrices) @@ -100,7 +100,7 @@ class BayesianRidge * @param responses A vector of targets. **/ void Train(const arma::mat& data, - const arma::rowvec& responses); + const arma::rowvec& responses); /** * Predict \f$y_{i}\f$ for each data point in the given data matrix using the @@ -133,7 +133,7 @@ class BayesianRidge */ void Predict(const arma::mat& points, arma::rowvec& predictions, - arma::rowvec& std) const; + arma::rowvec& std) const; /** @@ -146,11 +146,11 @@ class BayesianRidge * @param std Standard deviation of the prediction. */ void Predict(const arma::colvec& point, - double& prediction, - double& std) const; + double& prediction, + double& std) const; - - /** + + /** * Compute the Root Mean Square Error * between the predictions returned by the model * and the true repsonses. @@ -160,9 +160,9 @@ class BayesianRidge * @return RMSE **/ double Rmse(const arma::mat& data, - const arma::rowvec& responses) const; + const arma::rowvec& responses) const; + - /** * Center and normalize the data. The last four arguments * allow future modifation of new points. @@ -181,14 +181,14 @@ class BayesianRidge * @param reponses_offset Mean of responses. */ void CenterNormalize(const arma::mat& data, - const arma::rowvec& responses, - const bool fit_intercept, - const bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset); + const arma::rowvec& responses, + const bool fit_intercept, + const bool normalize, + arma::mat& data_proc, + arma::rowvec& responses_proc, + arma::colvec& data_offset, + arma::colvec& data_scale, + double& responses_offset); /** @@ -236,9 +236,9 @@ class BayesianRidge * @return \f$ \beta \f$ **/ inline double Beta() const {return this->beta;} - - /** + + /** * Get the estimated variance. * * @return 1.0 / \f$ \beta \f$ From e9c35342785696674deb38d826c63888bb82c20c Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 14 Oct 2019 22:21:14 +0200 Subject: [PATCH 026/297] Code formatting. --- .../bayesian_ridge/bayesian_ridge_main.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 38361813f8..195b77f149 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -77,15 +77,15 @@ PROGRAM_INFO("BayesianRidge", PRINT_MODEL("bayesian_ridge_model") + ":" "\n\n" + PRINT_CALL("bayesian_ridge", "input", "data", "responses", "responses", - "fitIntercept", 1, "normalize", 0, "output_model", - "bayesian_ridge_model") + + "fitIntercept", 1, "normalize", 0, "output_model", + "bayesian_ridge_model") + "\n\n" "The following command uses the " + PRINT_MODEL("bayesian_ridge_model") + " to provide predicted responses for the data " + PRINT_DATASET("test") + " and save those responses to " + PRINT_DATASET("test_predictions") + ": " "\n\n" + PRINT_CALL("bayesian_ridge", "input_model", "bayesian_ridge_model", "test", - "test", "output_predictions", "test_predictions")); + "test", "output_predictions", "test_predictions")); PARAM_TMATRIX_IN("input", "Matrix of covariates (X).", "i"); PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); @@ -94,17 +94,17 @@ PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained LARS model to use.", "m"); PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output LARS model.", "M"); PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " - "points).", "t"); + "points).", "t"); PARAM_TMATRIX_OUT("output_predictions", "If --test_file is specified, this " - "file is where the predicted responses will be saved.", "o"); + "file is where the predicted responses will be saved.", "o"); PARAM_INT_IN("fitIntercept", "Center the data and fit the intercept", "f", - 1); + 1); PARAM_INT_IN("normalize", "Normlize each feature by their standard deviations.", - "n", - 0); + "n", + 0); static void mlpackMain() { @@ -165,14 +165,14 @@ static void mlpackMain() Log::Info << "Regressing on test points." << endl; // Load test points. mat testPoints = std::move(CLI::GetParam("test")); - + arma::rowvec predictions; bayesRidge->Predict(testPoints.t(), predictions); - + // Save test predictions (one per line). CLI::GetParam("output_predictions") = std::move(predictions.t()); Log::Info << predictions << std::endl; } - + CLI::GetParam("output_model") = bayesRidge; } From a790bf69ad328794bd232a7edea46a8c9a79605e Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 14 Oct 2019 22:21:27 +0200 Subject: [PATCH 027/297] Code formatting. --- src/mlpack/tests/bayesian_ridge_test.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 735be4f813..f8752ce2a0 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -22,13 +22,13 @@ using namespace mlpack::data; BOOST_AUTO_TEST_SUITE(BayesianRidgeTest); void GenerateProblem(arma::mat& X, - arma::rowvec& y, - size_t nPoints, - size_t nDims, - float sigma=0.0) + arma::rowvec& y, + size_t nPoints, + size_t nDims, + float sigma = 0.0) { arma::arma_rng::set_seed(4); - + X = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); arma::colvec noise = arma::randn(nPoints) * sigma; @@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) BayesianRidge estimator(true); estimator.Train(X, y); estimator.Predict(X, predictions); - + for (size_t i = 0; i < y.size(); i++) { BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); @@ -95,15 +95,17 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) arma::colvec x_std = arma::stddev(X, 0, 1); double y_mean = arma::mean(y); - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_offset() - x_mean)), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_offset() - x_mean)), + 1e-6); - BOOST_REQUIRE_SMALL((double) abs(estimator.Responses_offset() - y_mean), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(estimator.Responses_offset() - y_mean), + 1e-6); - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_scale() - x_std)), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_scale() - x_std)), + 1e-6); } - BOOST_AUTO_TEST_CASE(ColinearTest) { arma::mat X; @@ -122,7 +124,7 @@ BOOST_AUTO_TEST_CASE(OnePointTest) arma::rowvec y; arma::rowvec predictions, std; double y_i, std_i; - + GenerateProblem(X, y, 100, 10, 2.0); BayesianRidge estimator(false, false); estimator.Train(X, y); From c30484a0217c72803b10e9b44364770250260f7c Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 15 Oct 2019 18:13:33 +0200 Subject: [PATCH 028/297] Code formatting --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 8 ++++---- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 6c12e34107..5c73ef1362 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -48,7 +48,7 @@ void BayesianRidge::Train(const arma::mat& data, responses_offset); vecphitT = phi * t.t(); phiphiT = phi * phi.t(); - + // Compute the eigenvalues only once. arma::eig_sym(eigval, eigvec, phiphiT); @@ -91,7 +91,7 @@ void BayesianRidge::Train(const arma::mat& data, // Update beta. temp = t - omega.t() * phi; beta = (n - gamma) / dot(temp, temp); - + // Comptute the stopping criterion. deltaAlpha += alpha; deltaBeta += beta; @@ -144,7 +144,7 @@ void BayesianRidge::Predict(const arma::mat& points, X.each_col() -= data_offset; X.each_col() /= data_scale; predictions = omega.t() * X + responses_offset; - + // Compute the standard deviation of each prediction. std = arma::zeros(X.n_cols); arma::colvec phi(X.n_rows); @@ -274,7 +274,7 @@ BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) beta = other.beta; omega = other.omega; matCovariance = other.matCovariance; - + // Clear the other object. other.fitIntercept = false; other.normalize = false; diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 195b77f149..38b1f90bcc 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -165,10 +165,10 @@ static void mlpackMain() Log::Info << "Regressing on test points." << endl; // Load test points. mat testPoints = std::move(CLI::GetParam("test")); - + arma::rowvec predictions; bayesRidge->Predict(testPoints.t(), predictions); - + // Save test predictions (one per line). CLI::GetParam("output_predictions") = std::move(predictions.t()); Log::Info << predictions << std::endl; From 097b1fd67171aed96bfa594707b07c727e4c86b2 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 16 Oct 2019 18:59:23 +0200 Subject: [PATCH 029/297] Stop the training in the case of colinear feature/Singular covariance matrix. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 16 +++++++++--- .../methods/bayesian_ridge/bayesian_ridge.hpp | 5 ++-- src/mlpack/tests/bayesian_ridge_test.cpp | 25 ++++++++++--------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 5c73ef1362..d89f516c43 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -23,8 +23,8 @@ BayesianRidge::BayesianRidge(const bool fitIntercept, normalize(normalize) {/* Nothing to do */} -void BayesianRidge::Train(const arma::mat& data, - const arma::rowvec& responses) +float BayesianRidge::Train(const arma::mat& data, + const arma::rowvec& responses) { Timer::Start("bayesian_ridge_regression"); @@ -32,7 +32,7 @@ void BayesianRidge::Train(const arma::mat& data, arma::rowvec t; arma::colvec vecphitT; arma::mat phiphiT; - arma::colvec eigval; + arma::colvec eigval; arma::mat eigvec; arma::colvec eigvali; @@ -49,9 +49,16 @@ void BayesianRidge::Train(const arma::mat& data, vecphitT = phi * t.t(); phiphiT = phi * phi.t(); - // Compute the eigenvalues only once. arma::eig_sym(eigval, eigvec, phiphiT); + // Detect singular matrix. + if (eigval[0] == 0) + { + Log::Warn << "Singular matrix. Two lines or more are colinear." + << std::endl; + return -1; + } + unsigned short p = data.n_rows, n = data.n_cols; // Initialize the hyperparameters and // begin with an infinitely broad prior. @@ -99,6 +106,7 @@ void BayesianRidge::Train(const arma::mat& data, i++; } Timer::Stop("bayesian_ridge_regression"); + return Rmse(data, responses); } void BayesianRidge::Predict(const arma::mat& points, diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 59d7f51c46..7f86cd5f2c 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -98,9 +98,10 @@ class BayesianRidge * * @param data Column-major input data * @param responses A vector of targets. + * @return score. Root Mean Square Error. **/ - void Train(const arma::mat& data, - const arma::rowvec& responses); + float Train(const arma::mat& data, + const arma::rowvec& responses); /** * Predict \f$y_{i}\f$ for each data point in the given data matrix using the diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index f8752ce2a0..739e3c1d2c 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -106,18 +106,6 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) } -BOOST_AUTO_TEST_CASE(ColinearTest) -{ - arma::mat X; - arma::rowvec y; - - Load("lars_dependent_x.csv", X, false, true); - Load("lars_dependent_y.csv", y, false, true); - - BayesianRidge estimator(false, false); - estimator.Train(X, y); -} - BOOST_AUTO_TEST_CASE(OnePointTest) { arma::mat X; @@ -151,4 +139,17 @@ BOOST_AUTO_TEST_CASE(OnePointTest) } } +// Verify that Train() return -1 for a singular matrices or colinear feature. +BOOST_AUTO_TEST_CASE(ColinearTest) +{ + arma::mat X; + arma::rowvec y; + + Load("lars_dependent_x.csv", X, false, true); + Load("lars_dependent_y.csv", y, false, true); + + BayesianRidge estimator(true, false); + BOOST_TEST(estimator.Train(X, y) == - 1); +} + BOOST_AUTO_TEST_SUITE_END(); From be4f94aafe5c2bb4024e52b8ae2db77e8edd9314 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 16 Oct 2019 23:40:08 +0200 Subject: [PATCH 030/297] Modification of the Train() documentation. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 7f86cd5f2c..69f90fc61c 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -98,7 +98,8 @@ class BayesianRidge * * @param data Column-major input data * @param responses A vector of targets. - * @return score. Root Mean Square Error. + * @return score. Root Mean Square Error. Equal to -1 of two feature vectors + * or more are colinear. **/ float Train(const arma::mat& data, const arma::rowvec& responses); From f17757a073f0cb6e2c3b83a2eda0b4bd8e454b78 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 16 Oct 2019 23:40:57 +0200 Subject: [PATCH 031/297] Change BOOST_TEST for BOOST_ASSERT. --- src/mlpack/tests/bayesian_ridge_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 739e3c1d2c..131753baa3 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(ColinearTest) Load("lars_dependent_y.csv", y, false, true); BayesianRidge estimator(true, false); - BOOST_TEST(estimator.Train(X, y) == - 1); + BOOST_ASSERT(estimator.Train(X, y) == -1); } BOOST_AUTO_TEST_SUITE_END(); From 5a935f13b7ee159a8c41fb9f3507de349aac204c Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 27 Oct 2019 11:02:37 +0100 Subject: [PATCH 032/297] Correction of wrong return types. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 69f90fc61c..3331da9dee 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -254,7 +254,7 @@ class BayesianRidge * * @return responses_offset **/ - inline arma::rowvec Data_offset() const {return this->data_offset;} + inline arma::colvec Data_offset() const {return this->data_offset;} /** @@ -263,7 +263,7 @@ class BayesianRidge * * return data_offset **/ - inline arma::rowvec Data_scale() const {return this->data_scale;} + inline arma::colvec Data_scale() const {return this->data_scale;} /** From 45a87b339a6ed5eb0b77eae43c44cf889905eb36 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 27 Oct 2019 11:03:34 +0100 Subject: [PATCH 033/297] Correction of errors occuring with option DEBUG=ON. --- src/mlpack/tests/bayesian_ridge_test.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 131753baa3..df40889046 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -33,7 +33,7 @@ void GenerateProblem(arma::mat& X, arma::colvec omega = arma::randn(nDims); arma::colvec noise = arma::randn(nPoints) * sigma; y = (omega.t() * X); - y += noise; + y += noise.t(); } // Ensure that predictions are close enough to the target @@ -50,6 +50,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) estimator.Train(X, y); estimator.Predict(X, predictions); + BOOST_REQUIRE(true); for (size_t i = 0; i < y.size(); i++) { BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); @@ -65,13 +66,15 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) arma::mat X; arma::rowvec y; size_t nDims = 30, nPoints = 100; + GenerateProblem(X, y, nPoints, nDims, 0.5); BayesianRidge estimator(false, false); + estimator.Train(X, y); // To be neutral data_offset must be all 0. - BOOST_REQUIRE(sum(estimator.Data_offset()) == 0); + BOOST_REQUIRE(sum(estimator.Data_offset()) == 0.0); // To be neutral responses_offset must be 0. BOOST_REQUIRE(estimator.Responses_offset() == 0); @@ -139,16 +142,17 @@ BOOST_AUTO_TEST_CASE(OnePointTest) } } -// Verify that Train() return -1 for a singular matrices or colinear feature. +// Verify that Train() return -1 for a singular matrice or colinear feature. BOOST_AUTO_TEST_CASE(ColinearTest) { arma::mat X; - arma::rowvec y; + arma::mat y; Load("lars_dependent_x.csv", X, false, true); Load("lars_dependent_y.csv", y, false, true); BayesianRidge estimator(true, false); + BOOST_ASSERT(estimator.Train(X, y) == -1); } From 869e41f63860ebc4f8cc5e2e0b4486ca15210d4f Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 14 Nov 2019 20:49:54 +0100 Subject: [PATCH 034/297] Remove singular case test. --- src/mlpack/tests/#bayesian_ridge_test.cpp# | 160 +++++++++++++++++++++ src/mlpack/tests/bayesian_ridge_test.cpp | 14 -- 2 files changed, 160 insertions(+), 14 deletions(-) create mode 100644 src/mlpack/tests/#bayesian_ridge_test.cpp# diff --git a/src/mlpack/tests/#bayesian_ridge_test.cpp# b/src/mlpack/tests/#bayesian_ridge_test.cpp# new file mode 100644 index 0000000000..5e57a1bdda --- /dev/null +++ b/src/mlpack/tests/#bayesian_ridge_test.cpp# @@ -0,0 +1,160 @@ +/** + * @file bayesian_ridge_test.cpp + * @author Clement Mercier + * + * Test for BayesianRidge. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ + + +#include +#include + +#include + +using namespace mlpack::regression; +using namespace mlpack::data; + +BOOST_AUTO_TEST_SUITE(BayesianRidgeTest); + +void GenerateProblem(arma::mat& X, + arma::rowvec& y, + size_t nPoints, + size_t nDims, + float sigma = 0.0) +{ + arma::arma_rng::set_seed(4); + + X = arma::randn(nDims, nPoints); + arma::colvec omega = arma::randn(nDims); + arma::colvec noise = arma::randn(nPoints) * sigma; + y = (omega.t() * X); + y += noise.t(); +} + +// Ensure that predictions are close enough to the target +// for a free noise dataset. +BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) +{ + arma::mat X; + arma::rowvec y, predictions; + + GenerateProblem(X, y, 200, 10); + + // Instanciate and train the estimator. + BayesianRidge estimator(true); + estimator.Train(X, y); + estimator.Predict(X, predictions); + + BOOST_REQUIRE(true); + for (size_t i = 0; i < y.size(); i++) + { + BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); + } + // Check that the estimated variance is zero. + BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6); +} + + +// Verify fitIntercept and normalize equal false do not affect the solution. +BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) +{ + arma::mat X; + arma::rowvec y; + size_t nDims = 30, nPoints = 100; + + GenerateProblem(X, y, nPoints, nDims, 0.5); + + BayesianRidge estimator(false, false); + + estimator.Train(X, y); + + // To be neutral data_offset must be all 0. + BOOST_REQUIRE(sum(estimator.Data_offset()) == 0.0); + + // To be neutral responses_offset must be 0. + BOOST_REQUIRE(estimator.Responses_offset() == 0); + + // To be neutral data_scale must be all 1. + BOOST_REQUIRE(sum(estimator.Data_scale()) == nDims); +} + +// Verify that centering and normalization are correct. +BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) +{ + arma::mat X; + arma::rowvec y; + size_t nDims = 30, nPoints = 100; + GenerateProblem(X, y, nPoints, nDims, 0.5); + + BayesianRidge estimator(true, true); + estimator.Train(X, y); + + arma::colvec x_mean = arma::mean(X, 1); + arma::colvec x_std = arma::stddev(X, 0, 1); + double y_mean = arma::mean(y); + + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_offset() - x_mean)), + 1e-6); + + BOOST_REQUIRE_SMALL((double) abs(estimator.Responses_offset() - y_mean), + 1e-6); + + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_scale() - x_std)), + 1e-6); +} + + +BOOST_AUTO_TEST_CASE(OnePointTest) +{ + arma::mat X; + arma::rowvec y; + arma::rowvec predictions, std; + double y_i, std_i; + + GenerateProblem(X, y, 100, 10, 2.0); + BayesianRidge estimator(false, false); + estimator.Train(X, y); + + // Predict on all the points. + estimator.Predict(X, predictions); + + // Ensure that the single prediction from column vector are possible and + // equal to the matrix version. + for (size_t i = 0; i < y.size(); i++) + { + estimator.Predict(X.col(i), y_i); + BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); + } + + // Ensure that the single prediction from column vector are possible and + // equal to the matrix version. Idem for the std. + estimator.Predict(X, predictions, std); + for (size_t i = 0; i < y.size(); i++) + { + estimator.Predict(X.col(i), y_i, std_i); + BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); + BOOST_REQUIRE_CLOSE(std(i), std_i, 1e-5); + } +} + +// Verify that Train() return -1 for a singular matrice or colinear feature. +BOOST_AUTO_TEST_CASE(ColinearTest) +{ + arma::mat X; + arma::mat y; + + Load("lars_dependent_x.csv", X, false, true); + Load("lars_dependent_y.csv", y, false, true); + + BayesianRidge estimator(true, false); + float test = estimator.Train(X, y); + + BOOST_ASSERT(estimator.Train(X, y) == -1); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index df40889046..67d798fafb 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -142,18 +142,4 @@ BOOST_AUTO_TEST_CASE(OnePointTest) } } -// Verify that Train() return -1 for a singular matrice or colinear feature. -BOOST_AUTO_TEST_CASE(ColinearTest) -{ - arma::mat X; - arma::mat y; - - Load("lars_dependent_x.csv", X, false, true); - Load("lars_dependent_y.csv", y, false, true); - - BayesianRidge estimator(true, false); - - BOOST_ASSERT(estimator.Train(X, y) == -1); -} - BOOST_AUTO_TEST_SUITE_END(); From 782690dc2a83ccb12426e2b6c929bf292ce77435 Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 2 Jan 2020 09:44:38 +0100 Subject: [PATCH 035/297] Small change to bypass the Travis timeout issue. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 3331da9dee..1ec7592cf1 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -116,7 +116,7 @@ class BayesianRidge /** * Predict \f$y_{i}\f$ for one point using the - * currently-trained Bayesian Ridge model. + * currently trained Bayesian Ridge model. * * @param point The data point to apply the model. * @param prediction y, which will contained predicted value on completion. From 895a756f0f89422233ee410b2fa533984e6fbd19 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 5 Jan 2020 22:42:53 +0100 Subject: [PATCH 036/297] OnePointTest vanishes at the same time of the Predict(arma::colvec X, ...) method. Add a singular test case. --- src/mlpack/tests/bayesian_ridge_test.cpp | 67 +++++++++--------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 67d798fafb..c0585bf699 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -27,13 +27,11 @@ void GenerateProblem(arma::mat& X, size_t nDims, float sigma = 0.0) { - arma::arma_rng::set_seed(4); - X = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); arma::colvec noise = arma::randn(nPoints) * sigma; - y = (omega.t() * X); - y += noise.t(); + // Compute y and add noise. + y = omega.t() * X + noise.t(); } // Ensure that predictions are close enough to the target @@ -50,11 +48,10 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) estimator.Train(X, y); estimator.Predict(X, predictions); - BOOST_REQUIRE(true); + // Check the predictions are close enough to the targets in a free noise case. for (size_t i = 0; i < y.size(); i++) - { - BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); - } + BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); + // Check that the estimated variance is zero. BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6); } @@ -74,13 +71,13 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) estimator.Train(X, y); // To be neutral data_offset must be all 0. - BOOST_REQUIRE(sum(estimator.Data_offset()) == 0.0); + BOOST_REQUIRE(sum(estimator.DataOffset()) == 0.0); // To be neutral responses_offset must be 0. - BOOST_REQUIRE(estimator.Responses_offset() == 0); + BOOST_REQUIRE(estimator.ResponsesOffset() == 0); // To be neutral data_scale must be all 1. - BOOST_REQUIRE(sum(estimator.Data_scale()) == nDims); + BOOST_REQUIRE(sum(estimator.DataScale()) == nDims); } // Verify that centering and normalization are correct. @@ -94,52 +91,38 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) BayesianRidge estimator(true, true); estimator.Train(X, y); - arma::colvec x_mean = arma::mean(X, 1); - arma::colvec x_std = arma::stddev(X, 0, 1); - double y_mean = arma::mean(y); + arma::colvec xMean = arma::mean(X, 1); + arma::colvec xStd = arma::stddev(X, 0, 1); + double yMean = arma::mean(y); - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_offset() - x_mean)), + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataOffset() - xMean)), 1e-6); - BOOST_REQUIRE_SMALL((double) abs(estimator.Responses_offset() - y_mean), + BOOST_REQUIRE_SMALL((double) abs(estimator.ResponsesOffset() - yMean), 1e-6); - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_scale() - x_std)), + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataScale() - xStd)), 1e-6); } -BOOST_AUTO_TEST_CASE(OnePointTest) + +// Check that Train() return -1 if X is singular. +BOOST_AUTO_TEST_CASE(SingularMatix) { arma::mat X; arma::rowvec y; - arma::rowvec predictions, std; - double y_i, std_i; - GenerateProblem(X, y, 100, 10, 2.0); + GenerateProblem(X, y, 200, 10); + // Now the first and the second rows are indentical. + X.row(1) = X.row(0); + BayesianRidge estimator(false, false); - estimator.Train(X, y); + double singular = estimator.Train(X, y); + BOOST_REQUIRE(singular == -1); + + - // Predict on all the points. - estimator.Predict(X, predictions); - - // Ensure that the single prediction from column vector are possible and - // equal to the matrix version. - for (size_t i = 0; i < y.size(); i++) - { - estimator.Predict(X.col(i), y_i); - BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); - } - - // Ensure that the single prediction from column vector are possible and - // equal to the matrix version. Idem for the std. - estimator.Predict(X, predictions, std); - for (size_t i = 0; i < y.size(); i++) - { - estimator.Predict(X.col(i), y_i, std_i); - BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); - BOOST_REQUIRE_CLOSE(std(i), std_i, 1e-5); - } } BOOST_AUTO_TEST_SUITE_END(); From 9f8d0c4dbe33a4b631f675cd00f2e7dafb874aa5 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 5 Jan 2020 22:46:55 +0100 Subject: [PATCH 037/297] Modifications according to the zoq's comments. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 283 ++++++++---------- 1 file changed, 130 insertions(+), 153 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index d89f516c43..60171c80bc 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -17,42 +17,42 @@ using namespace mlpack; using namespace mlpack::regression; -BayesianRidge::BayesianRidge(const bool fitIntercept, - const bool normalize) : - fitIntercept(fitIntercept), - normalize(normalize) +BayesianRidge::BayesianRidge(const bool centerData, + const bool scaleData) : + centerData(centerData), + scaleData(scaleData) {/* Nothing to do */} -float BayesianRidge::Train(const arma::mat& data, - const arma::rowvec& responses) +double BayesianRidge::Train(const arma::mat& data, + const arma::rowvec& responses) { Timer::Start("bayesian_ridge_regression"); arma::mat phi; arma::rowvec t; - arma::colvec vecphitT; - arma::mat phiphiT; arma::colvec eigval; arma::mat eigvec; arma::colvec eigvali; - // Preprocess the data. Center and normalize. - CenterNormalize(data, + // Preprocess the data. Center and scale. + CenterScaleData(data, responses, - fitIntercept, - normalize, + centerData, + scaleData, phi, t, - data_offset, - data_scale, - responses_offset); - vecphitT = phi * t.t(); - phiphiT = phi * phi.t(); + dataOffset, + dataScale, + responsesOffset); + + // Compute this quantities once and for all. + const arma::colvec vecphitT = phi * t.t(); + const arma::mat phiphiT = phi * phi.t(); arma::eig_sym(eigval, eigvec, phiphiT); // Detect singular matrix. - if (eigval[0] == 0) + if (eigval[0] < 1e-8) { Log::Warn << "Singular matrix. Two lines or more are colinear." << std::endl; @@ -70,41 +70,40 @@ float BayesianRidge::Train(const arma::mat& data, unsigned short i = 0; double deltaAlpha = 1, deltaBeta = 1, crit = 1; arma::mat matA = arma::eye(p, p); - arma::rowvec temp; while ((crit > tol) && (i < nIterMax)) - { - deltaAlpha = -alpha; - deltaBeta = -beta; + { + deltaAlpha = -alpha; + deltaBeta = -beta; - // Compute the posterior statistics. - // with inv() - for (size_t k = 0; k < p; k++) {matA(k, k) = alpha;} - // inv is used instead of solve beacause we need matCovariance to - // compute the prediction uncertainties. If solve is used, matCovariance - // must be comptuted at the end of the loop. - matCovariance = inv_sympd(matA + phiphiT * beta); - omega = (matCovariance * vecphitT) * beta; + // Compute the posterior statistics. + // with inv() + matA.diag().fill(alpha); + // inv is used instead of solve because we need the covariance matrix to + // compute the prediction uncertainties. If solve is used, matCovariance + // must be comptuted at the end of the loop. + matCovariance = inv_sympd(matA + phiphiT * beta); + omega = (matCovariance * vecphitT) * beta; - // // with solve() - // for (size_t k = 0; k < p; k++) {matA(k,k) = alpha / beta;} - // omega = solve(matA + phiphiT, vecphitT); + // // with solve() + // matA.diag().fill(alpha/ beta); + // omega = solve(matA + phiphiT, vecphitT); - // Update alpha. - eigvali = eigval * beta; - gamma = sum(eigvali / (alpha + eigvali)); - alpha = gamma / dot(omega.t(), omega); + // Update alpha. + eigvali = eigval * beta; + gamma = sum(eigvali / (alpha + eigvali)); + alpha = gamma / dot(omega.t(), omega); - // Update beta. - temp = t - omega.t() * phi; - beta = (n - gamma) / dot(temp, temp); + // Update beta. + const arma::rowvec temp = t - omega.t() * phi; + beta = (n - gamma) / dot(temp, temp); - // Comptute the stopping criterion. - deltaAlpha += alpha; - deltaBeta += beta; - crit = abs(deltaAlpha/alpha + deltaBeta/beta); - i++; - } + // Comptute the stopping criterion. + deltaAlpha += alpha; + deltaBeta += beta; + crit = abs(deltaAlpha/alpha + deltaBeta/beta); + i++; + } Timer::Stop("bayesian_ridge_regression"); return Rmse(data, responses); } @@ -114,32 +113,10 @@ void BayesianRidge::Predict(const arma::mat& points, { arma::mat X = points; - // Center and normalize the points before applying the model - X.each_col() -= data_offset; - X.each_col() /= data_scale; - predictions = omega.t() * X + responses_offset; -} - -void BayesianRidge::Predict(const arma::colvec& point, - double& prediction) const -{ - arma::mat point_mat = arma::conv_to::from(point); - arma::rowvec prediction_vec(1); - Predict(point_mat, prediction_vec); - prediction = prediction_vec[0]; -} - - -void BayesianRidge::Predict(const arma::colvec& point, - double& prediction, - double& std) const -{ - arma::mat point_mat = arma::conv_to::from(point); - arma::rowvec prediction_vec(1); - arma::rowvec std_vec(1); - Predict(point_mat, prediction_vec, std_vec); - prediction = prediction_vec[0]; - std = std_vec[0]; + // Center and scaleData the points before applying the model + X.each_col() -= dataOffset; + X.each_col() /= dataScale; + predictions = omega.t() * X + responsesOffset; } void BayesianRidge::Predict(const arma::mat& points, @@ -148,20 +125,20 @@ void BayesianRidge::Predict(const arma::mat& points, { arma::mat X = points; - // Center and normalize the points before applying the model. - X.each_col() -= data_offset; - X.each_col() /= data_scale; - predictions = omega.t() * X + responses_offset; + // Center and scaleData the points before applying the model. + X.each_col() -= dataOffset; + X.each_col() /= dataScale; + predictions = omega.t() * X + responsesOffset; // Compute the standard deviation of each prediction. std = arma::zeros(X.n_cols); arma::colvec phi(X.n_rows); for (size_t i = 0; i < X.n_cols; i++) - { - phi = X.col(i); - std[i] = sqrt(Variance() + { + phi = X.col(i); + std[i] = sqrt(Variance() + dot(phi.t() * matCovariance, phi)); - } + } } double BayesianRidge::Rmse(const arma::mat& data, @@ -172,48 +149,48 @@ double BayesianRidge::Rmse(const arma::mat& data, return sqrt(mean(square(responses - predictions))); } -void BayesianRidge::CenterNormalize(const arma::mat& data, +void BayesianRidge::CenterScaleData(const arma::mat& data, const arma::rowvec& responses, - bool fit_intercept, - bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset) + bool centerData, + bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale, + double& responsesOffset) { // Initialize the offsets to their neutral forms. - data_offset = arma::zeros(data.n_rows); - data_scale = arma::ones(data.n_rows); - responses_offset = 0.0; + dataOffset = arma::zeros(data.n_rows); + dataScale = arma::ones(data.n_rows); + responsesOffset = 0.0; - if (fit_intercept) - { - data_offset = mean(data, 1); - responses_offset = mean(responses); - } - if (normalize) - data_scale = stddev(data, 0, 1); + if (centerData) + { + dataOffset = mean(data, 1); + responsesOffset = mean(responses); + } + + if (scaleData) + dataScale = stddev(data, 0, 1); // Copy data and response before the processing. - data_proc = data; - responses_proc = responses; + dataProc = data; // Center the data. - data_proc.each_col() -= data_offset; + dataProc.each_col() -= dataOffset; // Scale the data. - data_proc.each_col() /= data_scale; + dataProc.each_col() /= dataScale; // Center the responses. - responses_proc -= responses_offset; + responsesProc = responses - responsesOffset; } // Copy construcor BayesianRidge::BayesianRidge(const BayesianRidge& other): - fitIntercept(other.fitIntercept), - normalize(other.normalize), - data_offset(other.data_offset), - data_scale(other.data_scale), - responses_offset(other.responses_offset), + centerData(other.centerData), + scaleData(other.scaleData), + dataOffset(other.dataOffset), + dataScale(other.dataScale), + responsesOffset(other.responsesOffset), alpha(other.alpha), beta(other.beta), gamma(other.gamma), @@ -223,11 +200,11 @@ BayesianRidge::BayesianRidge(const BayesianRidge& other): // Move construcor BayesianRidge::BayesianRidge(BayesianRidge&& other): - fitIntercept(other.fitIntercept), - normalize(other.normalize), - data_offset(std::move(other.data_offset)), - data_scale(std::move(other.data_scale)), - responses_offset(other.responses_offset), + centerData(other.centerData), + scaleData(other.scaleData), + dataOffset(std::move(other.dataOffset)), + dataScale(std::move(other.dataScale)), + responsesOffset(other.responsesOffset), alpha(other.alpha), beta(other.beta), gamma(other.gamma), @@ -236,18 +213,18 @@ BayesianRidge::BayesianRidge(BayesianRidge&& other): { // Clear the other object if (this != &other) - { - other.fitIntercept = false; - other.normalize = false; - other.data_offset.reset(); - other.data_scale.reset(); - other.responses_offset = 0.0; - other.alpha = 0.0; - other.gamma = 0.0; - other.beta = 0.0; - other.omega.reset(); - other.matCovariance.reset(); - } + { + other.centerData = false; + other.scaleData = false; + other.dataOffset.reset(); + other.dataScale.reset(); + other.responsesOffset = 0.0; + other.alpha = 0.0; + other.gamma = 0.0; + other.beta = 0.0; + other.omega.reset(); + other.matCovariance.reset(); + } } BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) @@ -255,11 +232,11 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) if (this == &other) return *this; - fitIntercept = other.fitIntercept; - normalize = other.normalize; - data_offset = other.data_offset; - data_scale = other.data_scale; - responses_offset = other.responses_offset; + centerData = other.centerData; + scaleData = other.scaleData; + dataOffset = other.dataOffset; + dataScale = other.dataScale; + responsesOffset = other.responsesOffset; alpha = other.alpha; gamma = other.gamma; beta = other.beta; @@ -271,29 +248,29 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) { if (this != &other) - { - fitIntercept = other.fitIntercept; - normalize = other.normalize; - data_offset = other.data_offset; - data_scale = other.data_scale; - responses_offset = other.responses_offset; - alpha = other.alpha; - gamma = other.gamma; - beta = other.beta; - omega = other.omega; - matCovariance = other.matCovariance; + { + centerData = other.centerData; + scaleData = other.scaleData; + dataOffset = other.dataOffset; + dataScale = other.dataScale; + responsesOffset = other.responsesOffset; + alpha = other.alpha; + gamma = other.gamma; + beta = other.beta; + omega = other.omega; + matCovariance = other.matCovariance; - // Clear the other object. - other.fitIntercept = false; - other.normalize = false; - other.data_offset.reset(); - other.data_scale.reset(); - other.responses_offset = 0.0; - other.alpha = 0.0; - other.gamma = 0.0; - other.beta = 0.0; - other.omega.reset(); - other.matCovariance.reset(); - } + // Clear the other object. + other.centerData = false; + other.scaleData = false; + other.dataOffset.reset(); + other.dataScale.reset(); + other.responsesOffset = 0.0; + other.alpha = 0.0; + other.gamma = 0.0; + other.beta = 0.0; + other.omega.reset(); + other.matCovariance.reset(); + } return *this; } From 50beeb4f2a30773bb243a204c3c749eb10399bd9 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 5 Jan 2020 22:47:11 +0100 Subject: [PATCH 038/297] Modifications according to the zoq's comments. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 108 ++++++------------ 1 file changed, 37 insertions(+), 71 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 1ec7592cf1..fa8305f69b 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -1,6 +1,6 @@ /** * @file bayesian_ridge.hpp - * @ Clement Mercier + * @author Clement Mercier * * Definition of the BayesianRidge class, which performs the * bayesian linear regression. According to the armadillo standards, @@ -83,13 +83,13 @@ class BayesianRidge * regulariation parameter is automaticaly set to its optimal value by * maximmization of the marginal likelihood. * - * @param fitIntercept Whether or not center the data according to the + * @param centerData Whether or not center the data according to the * examples. - * @param normalize Whether or to normalize the data according to the + * @param scaleData Whether or to scale the data according to the * standard deviation of each feature. **/ - BayesianRidge(const bool fitIntercept = true, - const bool normalize = false); + BayesianRidge(const bool centerData = true, + const bool scaleData = false); /** * Run BayesianRidge regression. The input matrix (like all mlpack matrices) @@ -101,8 +101,8 @@ class BayesianRidge * @return score. Root Mean Square Error. Equal to -1 of two feature vectors * or more are colinear. **/ - float Train(const arma::mat& data, - const arma::rowvec& responses); + double Train(const arma::mat& data, + const arma::rowvec& responses); /** * Predict \f$y_{i}\f$ for each data point in the given data matrix using the @@ -114,16 +114,6 @@ class BayesianRidge void Predict(const arma::mat& points, arma::rowvec& predictions) const; - /** - * Predict \f$y_{i}\f$ for one point using the - * currently trained Bayesian Ridge model. - * - * @param point The data point to apply the model. - * @param prediction y, which will contained predicted value on completion. - **/ - - void Predict(const arma::colvec& point, double& prediction) const; - /** * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior * distribution for each data point in the given data matrix, using the @@ -137,21 +127,6 @@ class BayesianRidge arma::rowvec& predictions, arma::rowvec& std) const; - - /** - * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior - * distribution for point stored in a column vector using the - * currently-trained Bayesian Ridge estimator. - * - * @param point The data points to apply the model. - * @param prediction y, which will contained calculated values on completion. - * @param std Standard deviation of the prediction. - */ - void Predict(const arma::colvec& point, - double& prediction, - double& std) const; - - /** * Compute the Root Mean Square Error * between the predictions returned by the model @@ -164,34 +139,32 @@ class BayesianRidge double Rmse(const arma::mat& data, const arma::rowvec& responses) const; - /** - * Center and normalize the data. The last four arguments + * Center and scaleData the data. The last four arguments * allow future modifation of new points. * * @param data Design matrix in column-major format, dim(P,N). * @param responses A vector of targets. - * @param fit_interpept If true data will be centred according to the points. - * @param fit_interpept If true data will be scales by the standard deviations + * @param centerData If true data will be centred according to the points. + * @param centerData If true data will be scales by the standard deviations * of the features computed according to the points. - * @param data_proc data processed, dim(N,P). - * @param responses_proc responses processed, dim(N). - * @param data_offset Mean vector of the design matrix according to the + * @param dataProc data processed, dim(N,P). + * @param responsesProc responses processed, dim(N). + * @param dataOffset Mean vector of the design matrix according to the * points, dim(P). - * @param data_scale Vector containg the standard deviations of the features + * @param dataScale Vector containg the standard deviations of the features * dim(P). * @param reponses_offset Mean of responses. */ - void CenterNormalize(const arma::mat& data, + void CenterScaleData(const arma::mat& data, const arma::rowvec& responses, - const bool fit_intercept, - const bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset); - + const bool centerData, + const bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale, + double& responsesOffset); /** * Copy constructor. Construct the BayesianRidge object by copying the @@ -223,7 +196,6 @@ class BayesianRidge */ BayesianRidge& operator=(BayesianRidge&& other); - /** * Get the solution vector * @@ -231,7 +203,6 @@ class BayesianRidge **/ inline arma::colvec Omega() const{return this->omega;} - /** * Get the precesion (or inverse variance) beta of the model. * @@ -239,40 +210,35 @@ class BayesianRidge **/ inline double Beta() const {return this->beta;} - - /** + /** * Get the estimated variance. * * @return 1.0 / \f$ \beta \f$ **/ inline double Variance() const {return 1.0 / this->Beta();} - /** * Get the mean vector computed on the features over the training points. - * Vector of 0 if fitIntercept is false. + * Vector of 0 if centerData is false. * - * @return responses_offset + * @return responsesOffset **/ - inline arma::colvec Data_offset() const {return this->data_offset;} - + inline arma::colvec DataOffset() const {return this->dataOffset;} /** * Get the vector of standard deviations computed on the features over the - * training points. Vector of 1 if normalize is false. + * training points. Vector of 1 if scaleData is false. * - * return data_offset + * return dataOffset **/ - inline arma::colvec Data_scale() const {return this->data_scale;} - + inline arma::colvec DataScale() const {return this->dataScale;} /** * Get the mean value of the train responses. - * @return responses_offset + * @return responsesOffset **/ - inline double Responses_offset() const - {return this->responses_offset;} - + inline double ResponsesOffset() const + {return this->responsesOffset;} /** * Serialize the BayesianRidge model. @@ -282,19 +248,19 @@ class BayesianRidge private: //! Center the data if true. - bool fitIntercept; + bool centerData; //! Scale the data by standard deviations if true. - bool normalize; + bool scaleData; //! Mean vector computed over the points. - arma::colvec data_offset; + arma::colvec dataOffset; //! Std vector computed over the points. - arma::colvec data_scale; + arma::colvec dataScale; //! Mean of the response vector computed over the points. - double responses_offset; + double responsesOffset; //! Precision of the prior pdf (gaussian). double alpha; From 8e05a4ad48c17fb0e0f7392c4cb1b561e159b93f Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 5 Jan 2020 22:47:30 +0100 Subject: [PATCH 039/297] Modifications according to the zoq's comments. --- .../methods/bayesian_ridge/bayesian_ridge_impl.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp index c9954e124c..ca17b78701 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp @@ -23,11 +23,11 @@ namespace regression { template void BayesianRidge::serialize(Archive& ar, const unsigned int /* version */) { - ar & BOOST_SERIALIZATION_NVP(fitIntercept); - ar & BOOST_SERIALIZATION_NVP(normalize); - ar & BOOST_SERIALIZATION_NVP(data_offset); - ar & BOOST_SERIALIZATION_NVP(data_scale); - ar & BOOST_SERIALIZATION_NVP(responses_offset); + ar & BOOST_SERIALIZATION_NVP(centerData); + ar & BOOST_SERIALIZATION_NVP(scaleData); + ar & BOOST_SERIALIZATION_NVP(dataOffset); + ar & BOOST_SERIALIZATION_NVP(dataScale); + ar & BOOST_SERIALIZATION_NVP(responsesOffset); ar & BOOST_SERIALIZATION_NVP(alpha); ar & BOOST_SERIALIZATION_NVP(beta); ar & BOOST_SERIALIZATION_NVP(gamma); From 431a62672e39cc2604f3c8d010f61d9f9987cb93 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 5 Jan 2020 22:53:01 +0100 Subject: [PATCH 040/297] Code formatting. --- src/mlpack/tests/bayesian_ridge_test.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index c0585bf699..87a8012725 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -30,7 +30,7 @@ void GenerateProblem(arma::mat& X, X = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); arma::colvec noise = arma::randn(nPoints) * sigma; - // Compute y and add noise. + // Compute y and add noise. y = omega.t() * X + noise.t(); } @@ -120,9 +120,6 @@ BOOST_AUTO_TEST_CASE(SingularMatix) BayesianRidge estimator(false, false); double singular = estimator.Train(X, y); BOOST_REQUIRE(singular == -1); - - - } BOOST_AUTO_TEST_SUITE_END(); From b11b31a991e0756c72fa60cdd46e1e2b0a7e1a4e Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 18:29:56 +0100 Subject: [PATCH 041/297] Suppress temp file. --- src/mlpack/tests/#bayesian_ridge_test.cpp# | 160 --------------------- 1 file changed, 160 deletions(-) delete mode 100644 src/mlpack/tests/#bayesian_ridge_test.cpp# diff --git a/src/mlpack/tests/#bayesian_ridge_test.cpp# b/src/mlpack/tests/#bayesian_ridge_test.cpp# deleted file mode 100644 index 5e57a1bdda..0000000000 --- a/src/mlpack/tests/#bayesian_ridge_test.cpp# +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @file bayesian_ridge_test.cpp - * @author Clement Mercier - * - * Test for BayesianRidge. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ - - -#include -#include - -#include - -using namespace mlpack::regression; -using namespace mlpack::data; - -BOOST_AUTO_TEST_SUITE(BayesianRidgeTest); - -void GenerateProblem(arma::mat& X, - arma::rowvec& y, - size_t nPoints, - size_t nDims, - float sigma = 0.0) -{ - arma::arma_rng::set_seed(4); - - X = arma::randn(nDims, nPoints); - arma::colvec omega = arma::randn(nDims); - arma::colvec noise = arma::randn(nPoints) * sigma; - y = (omega.t() * X); - y += noise.t(); -} - -// Ensure that predictions are close enough to the target -// for a free noise dataset. -BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) -{ - arma::mat X; - arma::rowvec y, predictions; - - GenerateProblem(X, y, 200, 10); - - // Instanciate and train the estimator. - BayesianRidge estimator(true); - estimator.Train(X, y); - estimator.Predict(X, predictions); - - BOOST_REQUIRE(true); - for (size_t i = 0; i < y.size(); i++) - { - BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6); - } - // Check that the estimated variance is zero. - BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6); -} - - -// Verify fitIntercept and normalize equal false do not affect the solution. -BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) -{ - arma::mat X; - arma::rowvec y; - size_t nDims = 30, nPoints = 100; - - GenerateProblem(X, y, nPoints, nDims, 0.5); - - BayesianRidge estimator(false, false); - - estimator.Train(X, y); - - // To be neutral data_offset must be all 0. - BOOST_REQUIRE(sum(estimator.Data_offset()) == 0.0); - - // To be neutral responses_offset must be 0. - BOOST_REQUIRE(estimator.Responses_offset() == 0); - - // To be neutral data_scale must be all 1. - BOOST_REQUIRE(sum(estimator.Data_scale()) == nDims); -} - -// Verify that centering and normalization are correct. -BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) -{ - arma::mat X; - arma::rowvec y; - size_t nDims = 30, nPoints = 100; - GenerateProblem(X, y, nPoints, nDims, 0.5); - - BayesianRidge estimator(true, true); - estimator.Train(X, y); - - arma::colvec x_mean = arma::mean(X, 1); - arma::colvec x_std = arma::stddev(X, 0, 1); - double y_mean = arma::mean(y); - - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_offset() - x_mean)), - 1e-6); - - BOOST_REQUIRE_SMALL((double) abs(estimator.Responses_offset() - y_mean), - 1e-6); - - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.Data_scale() - x_std)), - 1e-6); -} - - -BOOST_AUTO_TEST_CASE(OnePointTest) -{ - arma::mat X; - arma::rowvec y; - arma::rowvec predictions, std; - double y_i, std_i; - - GenerateProblem(X, y, 100, 10, 2.0); - BayesianRidge estimator(false, false); - estimator.Train(X, y); - - // Predict on all the points. - estimator.Predict(X, predictions); - - // Ensure that the single prediction from column vector are possible and - // equal to the matrix version. - for (size_t i = 0; i < y.size(); i++) - { - estimator.Predict(X.col(i), y_i); - BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); - } - - // Ensure that the single prediction from column vector are possible and - // equal to the matrix version. Idem for the std. - estimator.Predict(X, predictions, std); - for (size_t i = 0; i < y.size(); i++) - { - estimator.Predict(X.col(i), y_i, std_i); - BOOST_REQUIRE_CLOSE(predictions(i), y_i, 1e-5); - BOOST_REQUIRE_CLOSE(std(i), std_i, 1e-5); - } -} - -// Verify that Train() return -1 for a singular matrice or colinear feature. -BOOST_AUTO_TEST_CASE(ColinearTest) -{ - arma::mat X; - arma::mat y; - - Load("lars_dependent_x.csv", X, false, true); - Load("lars_dependent_y.csv", y, false, true); - - BayesianRidge estimator(true, false); - float test = estimator.Train(X, y); - - BOOST_ASSERT(estimator.Train(X, y) == -1); -} - -BOOST_AUTO_TEST_SUITE_END(); From 1cb91281163837bec506ebb46c09298cbb4abb71 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 18:31:00 +0100 Subject: [PATCH 042/297] Remove non camel in comments. --- src/mlpack/tests/bayesian_ridge_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 87a8012725..199e540811 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -70,13 +70,13 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) estimator.Train(X, y); - // To be neutral data_offset must be all 0. + // To be neutral dataOffset must be all 0. BOOST_REQUIRE(sum(estimator.DataOffset()) == 0.0); - // To be neutral responses_offset must be 0. + // To be neutral responseOffset must be 0. BOOST_REQUIRE(estimator.ResponsesOffset() == 0); - // To be neutral data_scale must be all 1. + // To be neutral dataScale must be all 1. BOOST_REQUIRE(sum(estimator.DataScale()) == nDims); } From 3688b1d3f7f997ba6f6cc2b57dbbdb79c6b56bd8 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 19:12:34 +0100 Subject: [PATCH 043/297] nIterMax and tol as default parameters in the constructor. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 60171c80bc..16892f9e17 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -18,9 +18,13 @@ using namespace mlpack::regression; BayesianRidge::BayesianRidge(const bool centerData, - const bool scaleData) : + const bool scaleData, + const int nIterMax, + const double tol) : centerData(centerData), - scaleData(scaleData) + scaleData(scaleData), + nIterMax(nIterMax), + tol(tol) {/* Nothing to do */} double BayesianRidge::Train(const arma::mat& data, @@ -65,7 +69,6 @@ double BayesianRidge::Train(const arma::mat& data, alpha = 1e-6; beta = 1 / (var(t) * 0.1); - double tol = 1e-3; unsigned short nIterMax = 50; unsigned short i = 0; double deltaAlpha = 1, deltaBeta = 1, crit = 1; From 15259ba4adf9c420bf069b8c4dba5b4aba57b934 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 19:12:49 +0100 Subject: [PATCH 044/297] nIterMax and tol as default parameters in the constructor. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index fa8305f69b..76813852ee 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -87,9 +87,14 @@ class BayesianRidge * examples. * @param scaleData Whether or to scale the data according to the * standard deviation of each feature. + * @param nIterMax Maximum number of iterations for convergency. + * @param tol Level from which the solution is considered sufficientlly + * stable. **/ BayesianRidge(const bool centerData = true, - const bool scaleData = false); + const bool scaleData = false, + const int nIterMax = 50, + const double tol = 1e-4); /** * Run BayesianRidge regression. The input matrix (like all mlpack matrices) @@ -253,6 +258,12 @@ class BayesianRidge //! Scale the data by standard deviations if true. bool scaleData; + //! Maximum number of iterations for convergency. + int nIterMax; + + //! Level from which the solution is considered sufficientlly stable. + double tol; + //! Mean vector computed over the points. arma::colvec dataOffset; From ec489645884c75bfc29ae4f46bda834921965e86 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 19:13:04 +0100 Subject: [PATCH 045/297] nIterMax and tol as default parameters in the constructor. --- src/mlpack/tests/bayesian_ridge_test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 199e540811..04e433ec7f 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -105,8 +105,6 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) 1e-6); } - - // Check that Train() return -1 if X is singular. BOOST_AUTO_TEST_CASE(SingularMatix) { @@ -117,7 +115,7 @@ BOOST_AUTO_TEST_CASE(SingularMatix) // Now the first and the second rows are indentical. X.row(1) = X.row(0); - BayesianRidge estimator(false, false); + BayesianRidge estimator; double singular = estimator.Train(X, y); BOOST_REQUIRE(singular == -1); } From 9574d290eea71b0967440dcfa62d9ad3cf9ce47c Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 19:18:37 +0100 Subject: [PATCH 046/297] Code formatting. --- src/mlpack/tests/bayesian_ridge_test.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 04e433ec7f..ed7996cbbe 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -95,14 +95,9 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) arma::colvec xStd = arma::stddev(X, 0, 1); double yMean = arma::mean(y); - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataOffset() - xMean)), - 1e-6); - - BOOST_REQUIRE_SMALL((double) abs(estimator.ResponsesOffset() - yMean), - 1e-6); - - BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataScale() - xStd)), - 1e-6); + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataOffset() - xMean)), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(estimator.ResponsesOffset() - yMean), 1e-6); + BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataScale() - xStd)), 1e-6); } // Check that Train() return -1 if X is singular. @@ -117,7 +112,7 @@ BOOST_AUTO_TEST_CASE(SingularMatix) BayesianRidge estimator; double singular = estimator.Train(X, y); - BOOST_REQUIRE(singular == -1); + BOOST_REQUIRE(singular == -1); } BOOST_AUTO_TEST_SUITE_END(); From c08beac8438f5064cb9fcf8a55d6b33cb79c95c4 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Jan 2020 19:25:54 +0100 Subject: [PATCH 047/297] Code formatting. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 76813852ee..16167f0a52 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -263,7 +263,7 @@ class BayesianRidge //! Level from which the solution is considered sufficientlly stable. double tol; - + //! Mean vector computed over the points. arma::colvec dataOffset; From 055ffc65b116e3e87e9d4581c28ef91fdbe8f656 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 20 Jan 2020 19:26:26 +0100 Subject: [PATCH 048/297] fitIntercept and normalize become center and scale. --- .../bayesian_ridge/bayesian_ridge_main.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 38b1f90bcc..077fee26f9 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -57,8 +57,8 @@ PROGRAM_INFO("BayesianRidge", "\n\n" "To train a BayesianRidge model, the " + PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") + - "parameters must be given. The " + PRINT_PARAM_STRING("fitIntercept") + - "and " + PRINT_PARAM_STRING("normalize") + " parameters control the " + "parameters must be given. The " + PRINT_PARAM_STRING("center") + + "and " + PRINT_PARAM_STRING("scale") + " parameters control the " "centering and the normalizing options. A trained model can be saved with " "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model")+ @@ -72,12 +72,12 @@ PROGRAM_INFO("BayesianRidge", "\n\n" "For example, the following command trains a model on the data " + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + - "with fitIntercept set to true and normalize set to false (so, Bayesian " + "with center set to true and scale set to false (so, Bayesian " "Ridge is being solved, and then the model is saved to " + PRINT_MODEL("bayesian_ridge_model") + ":" "\n\n" + PRINT_CALL("bayesian_ridge", "input", "data", "responses", "responses", - "fitIntercept", 1, "normalize", 0, "output_model", + "center", 1, "scale", 0, "output_model", "bayesian_ridge_model") + "\n\n" "The following command uses the " + PRINT_MODEL("bayesian_ridge_model") + @@ -99,17 +99,19 @@ PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " PARAM_TMATRIX_OUT("output_predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); -PARAM_INT_IN("fitIntercept", "Center the data and fit the intercept", - "f", +PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " + "disable", + "c", 1); -PARAM_INT_IN("normalize", "Normlize each feature by their standard deviations.", - "n", +PARAM_INT_IN("scale", "Scale each feature by their standard deviations. " + "set to 1 to scale.", + "s", 0); static void mlpackMain() { - int fitIntercept = CLI::GetParam("fitIntercept"); - int normalize = CLI::GetParam("normalize"); + int center = CLI::GetParam("center"); + int scale = CLI::GetParam("scale"); // Check parameters -- make sure everything given makes sense. RequireOnlyOnePassed({ "input", "input_model" }, true); @@ -130,7 +132,7 @@ static void mlpackMain() { Log::Info << "input detected " << std::endl; // Initialize the object. - bayesRidge = new BayesianRidge(fitIntercept, normalize); + bayesRidge = new BayesianRidge(center, scale); // Load covariates. mat matX = std::move(CLI::GetParam("input")); From b8c281ccb10fd0d1735bc01033dbb5925190615d Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 24 Jan 2020 17:27:25 +0100 Subject: [PATCH 049/297] Fuse two lines to suppress useless variable. --- src/mlpack/tests/bayesian_ridge_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index ed7996cbbe..64399f1cef 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -29,9 +29,8 @@ void GenerateProblem(arma::mat& X, { X = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); - arma::colvec noise = arma::randn(nPoints) * sigma; // Compute y and add noise. - y = omega.t() * X + noise.t(); + y = omega.t() * X + arma::randn(nPoints).t() * sigma; } // Ensure that predictions are close enough to the target From 71a0c64b5a2a8590b6ac454417f5ec7e559c9bb0 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 24 Jan 2020 18:01:32 +0100 Subject: [PATCH 050/297] Correction of typo. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 16167f0a52..9ff9d50fc3 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -103,7 +103,7 @@ class BayesianRidge * * @param data Column-major input data * @param responses A vector of targets. - * @return score. Root Mean Square Error. Equal to -1 of two feature vectors + * @return score. Root Mean Square Error. Equal to -1 if two feature vectors * or more are colinear. **/ double Train(const arma::mat& data, @@ -114,7 +114,7 @@ class BayesianRidge * currently-trained Bayesian Ridge model. * * @param points The data points to apply the model. - * @param predictions y, Contain the predicted values on completion. + * @param predictions y, Contains the predicted values on completion. **/ void Predict(const arma::mat& points, arma::rowvec& predictions) const; From b8b98939be0eb9a8a5476ccd2d553dc29e1b57a8 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 24 Jan 2020 18:23:42 +0100 Subject: [PATCH 051/297] Add main tests. --- src/mlpack/tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index dd12a5baa0..bfa42b0429 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -122,6 +122,7 @@ add_executable(mlpack_test main_tests/emst_test.cpp main_tests/adaboost_test.cpp main_tests/approx_kfn_test.cpp + main_tests/bayesian_ridge_test.cpp main_tests/cf_test.cpp main_tests/dbscan_test.cpp main_tests/det_test.cpp From 708eaf2f00d1b9c66ffbf73bb931c5305cf6cd05 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 24 Jan 2020 18:24:13 +0100 Subject: [PATCH 052/297] Change parameter names. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 077fee26f9..86b31fea16 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -88,9 +88,11 @@ PROGRAM_INFO("BayesianRidge", "test", "output_predictions", "test_predictions")); PARAM_TMATRIX_IN("input", "Matrix of covariates (X).", "i"); + PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained LARS model to use.", "m"); + PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output LARS model.", "M"); PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " @@ -103,6 +105,7 @@ PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " "disable", "c", 1); + PARAM_INT_IN("scale", "Scale each feature by their standard deviations. " "set to 1 to scale.", "s", From 7259ce9bd18419644423dd3ef3c9e4cba96c405d Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 10 Feb 2020 21:50:12 +0100 Subject: [PATCH 053/297] Add main tests. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 86b31fea16..8069304760 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -36,9 +36,9 @@ PROGRAM_INFO("BayesianRidge", "on the solution. " "\n" "Optimization is AUTOMATIC and does not require cross validation. " - "The optimization is performed by type II maximium likihood. Parameters " + "The optimization is performed by type II maximium likelihood. Parameters " "are tunned during the maximization of the marginal likelihood. This " - "procedure includes the Occam's razor that penalizes over complex " + "procedure includes the Ockham's razor that penalizes over complex " "solutions. " "\n\n" "This program is able to train a Baysian Ridge model or load a " @@ -91,9 +91,9 @@ PARAM_TMATRIX_IN("input", "Matrix of covariates (X).", "i"); PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); -PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained LARS model to use.", "m"); +PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained BayesianRidge model to use.", "m"); -PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output LARS model.", "M"); +PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output BayesianRidge model.", "M"); PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " "points).", "t"); From 1f67872fbb575970c4c2b65d6f7d2ec5b9c0839f Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 10 Feb 2020 22:22:54 +0100 Subject: [PATCH 054/297] Enforce the symmetry of the covariance matrix and check the failure of eig_sym. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 16892f9e17..04f9de0290 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -51,9 +51,15 @@ double BayesianRidge::Train(const arma::mat& data, // Compute this quantities once and for all. const arma::colvec vecphitT = phi * t.t(); - const arma::mat phiphiT = phi * phi.t(); + // Enforce symmetry of the covariance matrix before eig_sym. + const arma::mat phiphiT = arma::symmatu(phi * phi.t()); - arma::eig_sym(eigval, eigvec, phiphiT); + if (arma::eig_sym(eigval, eigvec, phiphiT) == false) + { + Log::Warn << "Eigen Decomposition failed as Eigen Value " + << "does not exists ." << std::endl; + return -1; + } // Detect singular matrix. if (eigval[0] < 1e-8) From 8d25d78af152a12ad903567e88b1bbc38c1df9b9 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 10 Feb 2020 22:29:21 +0100 Subject: [PATCH 055/297] Missing spaces and variable suppressions. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 04f9de0290..782b317e52 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -69,7 +69,6 @@ double BayesianRidge::Train(const arma::mat& data, return -1; } - unsigned short p = data.n_rows, n = data.n_cols; // Initialize the hyperparameters and // begin with an infinitely broad prior. alpha = 1e-6; @@ -78,7 +77,7 @@ double BayesianRidge::Train(const arma::mat& data, unsigned short nIterMax = 50; unsigned short i = 0; double deltaAlpha = 1, deltaBeta = 1, crit = 1; - arma::mat matA = arma::eye(p, p); + arma::mat matA = arma::eye(data.n_rows, data.n_rows); while ((crit > tol) && (i < nIterMax)) { @@ -95,7 +94,7 @@ double BayesianRidge::Train(const arma::mat& data, omega = (matCovariance * vecphitT) * beta; // // with solve() - // matA.diag().fill(alpha/ beta); + // matA.diag().fill(alpha / beta); // omega = solve(matA + phiphiT, vecphitT); // Update alpha. @@ -105,12 +104,12 @@ double BayesianRidge::Train(const arma::mat& data, // Update beta. const arma::rowvec temp = t - omega.t() * phi; - beta = (n - gamma) / dot(temp, temp); + beta = (data.n_cols - gamma) / dot(temp, temp); // Comptute the stopping criterion. deltaAlpha += alpha; deltaBeta += beta; - crit = abs(deltaAlpha/alpha + deltaBeta/beta); + crit = abs(deltaAlpha / alpha + deltaBeta / beta); i++; } Timer::Stop("bayesian_ridge_regression"); From d92a25614aff0bc23558fb0180fcccea7690bc94 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 11 Feb 2020 19:56:56 +0100 Subject: [PATCH 056/297] Add a unit test on the predictive variance. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 782b317e52..634ff66fd4 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -94,7 +94,7 @@ double BayesianRidge::Train(const arma::mat& data, omega = (matCovariance * vecphitT) * beta; // // with solve() - // matA.diag().fill(alpha / beta); + // matA.diag().fill(alpha/ beta); // omega = solve(matA + phiphiT, vecphitT); // Update alpha. @@ -119,35 +119,21 @@ double BayesianRidge::Train(const arma::mat& data, void BayesianRidge::Predict(const arma::mat& points, arma::rowvec& predictions) const { - arma::mat X = points; - - // Center and scaleData the points before applying the model - X.each_col() -= dataOffset; - X.each_col() /= dataScale; - predictions = omega.t() * X + responsesOffset; + // y_hat = w^T * (X - mu) / sigma + y_mean. + predictions = omega.t() * + ((points.each_col() - dataOffset).each_col() / dataScale) + responsesOffset; } void BayesianRidge::Predict(const arma::mat& points, arma::rowvec& predictions, arma::rowvec& std) const { - arma::mat X = points; - // Center and scaleData the points before applying the model. - X.each_col() -= dataOffset; - X.each_col() /= dataScale; + const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; + predictions = omega.t() * X + responsesOffset; - - // Compute the standard deviation of each prediction. - std = arma::zeros(X.n_cols); - arma::colvec phi(X.n_rows); - for (size_t i = 0; i < X.n_cols; i++) - { - phi = X.col(i); - std[i] = sqrt(Variance() - + dot(phi.t() * matCovariance, phi)); - } -} + std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); + } double BayesianRidge::Rmse(const arma::mat& data, const arma::rowvec& responses) const From a2f49a9d831c30d6597b97848e75b1259fe60059 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 11 Feb 2020 19:59:58 +0100 Subject: [PATCH 057/297] Remove a temprary matrix in Predict(mat, vec). Inline the calculation of the predictive uncertainties in Predict(mat, vec, vec). --- src/mlpack/tests/bayesian_ridge_test.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 64399f1cef..311fff895d 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -114,4 +114,23 @@ BOOST_AUTO_TEST_CASE(SingularMatix) BOOST_REQUIRE(singular == -1); } +// Check that std are well computed/coherent. At least higher than the +// estimated predictive variance. +BOOST_AUTO_TEST_CASE(PredictiveUncertainties) +{ + arma::mat X; + arma::rowvec y; + + GenerateProblem(X, y, 100, 10, 1); + + BayesianRidge estimator(true, true); + estimator.Train(X, y); + + arma::rowvec responses, std; + estimator.Predict(X, responses, std); + const double estStd = sqrt(estimator.Varaince()); + + for (size_t i = 0; i < X.n_cols; i++) BOOST_REQUIRE(std[i] > estStd); +} + BOOST_AUTO_TEST_SUITE_END(); From 52a4eb11ec0bdfc452d4e7cdb57e232fdfccd6e7 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 11 Feb 2020 20:16:53 +0100 Subject: [PATCH 058/297] resposesOffset is now returned by CenterDataScale(). --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 634ff66fd4..b4866ff1d0 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -39,18 +39,19 @@ double BayesianRidge::Train(const arma::mat& data, arma::colvec eigvali; // Preprocess the data. Center and scale. - CenterScaleData(data, - responses, - centerData, - scaleData, - phi, - t, - dataOffset, - dataScale, - responsesOffset); + responsesOffset = CenterScaleData(data, + responses, + centerData, + scaleData, + phi, + t, + dataOffset, + dataScale); + // Compute this quantities once and for all. const arma::colvec vecphitT = phi * t.t(); + // Enforce symmetry of the covariance matrix before eig_sym. const arma::mat phiphiT = arma::symmatu(phi * phi.t()); @@ -143,15 +144,14 @@ double BayesianRidge::Rmse(const arma::mat& data, return sqrt(mean(square(responses - predictions))); } -void BayesianRidge::CenterScaleData(const arma::mat& data, +double BayesianRidge::CenterScaleData(const arma::mat& data, const arma::rowvec& responses, bool centerData, bool scaleData, arma::mat& dataProc, arma::rowvec& responsesProc, arma::colvec& dataOffset, - arma::colvec& dataScale, - double& responsesOffset) + arma::colvec& dataScale) { // Initialize the offsets to their neutral forms. dataOffset = arma::zeros(data.n_rows); @@ -175,10 +175,12 @@ void BayesianRidge::CenterScaleData(const arma::mat& data, dataProc.each_col() /= dataScale; // Center the responses. responsesProc = responses - responsesOffset; + + return responsesOffset; } -// Copy construcor +// Copy construcor. BayesianRidge::BayesianRidge(const BayesianRidge& other): centerData(other.centerData), scaleData(other.scaleData), @@ -192,7 +194,7 @@ BayesianRidge::BayesianRidge(const BayesianRidge& other): matCovariance(other.matCovariance) {/* All is done */} -// Move construcor +// Move constructor. BayesianRidge::BayesianRidge(BayesianRidge&& other): centerData(other.centerData), scaleData(other.scaleData), @@ -205,7 +207,7 @@ BayesianRidge::BayesianRidge(BayesianRidge&& other): omega(std::move(other.omega)), matCovariance(std::move(other.matCovariance)) { - // Clear the other object + // Clear the other object. if (this != &other) { other.centerData = false; From 0db38f081cfbf45e009e6673411894be0f709462 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 11 Feb 2020 20:17:10 +0100 Subject: [PATCH 059/297] resposesOffset is now returned by CenterDataScale(). --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 9ff9d50fc3..49cff405aa 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -115,6 +115,8 @@ class BayesianRidge * * @param points The data points to apply the model. * @param predictions y, Contains the predicted values on completion. + * + * @return Root mean squared error computed on the train set. **/ void Predict(const arma::mat& points, arma::rowvec& predictions) const; @@ -159,17 +161,16 @@ class BayesianRidge * points, dim(P). * @param dataScale Vector containg the standard deviations of the features * dim(P). - * @param reponses_offset Mean of responses. + * @return reponsesOffset Mean of responses. */ - void CenterScaleData(const arma::mat& data, - const arma::rowvec& responses, - const bool centerData, - const bool scaleData, - arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale, - double& responsesOffset); + double CenterScaleData(const arma::mat& data, + const arma::rowvec& responses, + const bool centerData, + const bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale); /** * Copy constructor. Construct the BayesianRidge object by copying the From 2824dcb057539eb6b423a62aa22beb57e72bf110 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 14 Feb 2020 16:36:47 +0100 Subject: [PATCH 060/297] Typo. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 8069304760..f35ca89154 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -142,7 +142,7 @@ static void mlpackMain() // Load responses. The responses should be a one-dimensional vector, and it // seems more likely that these will be stored with one response per line - // (one per row). So we should not transpose upon loading. + // (one per row). So we should not transpose upon loading. mat matY = std::move(CLI::GetParam("responses")); // Make sure y is oriented the right way. From fd702f358c3d1825074dce851b83373feb580a7f Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 14 Feb 2020 16:37:35 +0100 Subject: [PATCH 061/297] m. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index b4866ff1d0..5282586819 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -55,7 +55,7 @@ double BayesianRidge::Train(const arma::mat& data, // Enforce symmetry of the covariance matrix before eig_sym. const arma::mat phiphiT = arma::symmatu(phi * phi.t()); - if (arma::eig_sym(eigval, eigvec, phiphiT) == false) + if (arma::eig_sym(eigval, eigvec, phiphiT) == false) { Log::Warn << "Eigen Decomposition failed as Eigen Value " << "does not exists ." << std::endl; From 795e6fd903320ef5de4f625567c6a7929b5eef77 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 14 Feb 2020 16:43:31 +0100 Subject: [PATCH 062/297] Typo. --- src/mlpack/tests/bayesian_ridge_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 311fff895d..25b858455e 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) arma::rowvec responses, std; estimator.Predict(X, responses, std); - const double estStd = sqrt(estimator.Varaince()); + const double estStd = sqrt(estimator.Variance()); for (size_t i = 0; i < X.n_cols; i++) BOOST_REQUIRE(std[i] > estStd); } From 26db95a7f94b7468bff987b97e481fb7390707e3 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 14 Feb 2020 17:01:57 +0100 Subject: [PATCH 063/297] Code formatting. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 4 +--- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 5282586819..adbe0f9983 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -47,7 +47,6 @@ double BayesianRidge::Train(const arma::mat& data, t, dataOffset, dataScale); - // Compute this quantities once and for all. const arma::colvec vecphitT = phi * t.t(); @@ -131,10 +130,9 @@ void BayesianRidge::Predict(const arma::mat& points, { // Center and scaleData the points before applying the model. const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; - predictions = omega.t() * X + responsesOffset; std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); - } +} double BayesianRidge::Rmse(const arma::mat& data, const arma::rowvec& responses) const diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index f35ca89154..d8e288af24 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -91,9 +91,11 @@ PARAM_TMATRIX_IN("input", "Matrix of covariates (X).", "i"); PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); -PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained BayesianRidge model to use.", "m"); +PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained BayesianRidge model " + "to use.", "m"); -PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output BayesianRidge model.", "M"); +PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output BayesianRidge model.", + "M"); PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " "points).", "t"); From 55d0519418b2e838f30214094b51f1549a1a0886 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 15 Feb 2020 11:55:17 +0100 Subject: [PATCH 064/297] Add tests in main_tests. --- .../tests/main_tests/bayesian_ridge_test.cpp | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/mlpack/tests/main_tests/bayesian_ridge_test.cpp diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp new file mode 100644 index 0000000000..d96aeafc56 --- /dev/null +++ b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp @@ -0,0 +1,106 @@ +/** + * @file bayesian_ridge_test.cpp + * @author Clement Mercier + * + * Test mlpackMain() of pca_main.cpp. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#include + +#define BINDING_TYPE BINDING_TYPE_TEST +static const std::string testName = "BayesianRidge"; + +#include +#include +#include "test_helper.hpp" +#include + +#include +#include "../test_tools.hpp" + +using namespace mlpack; + +struct BRTestFixture +{ + public: + BRTestFixture() + { + // Cache in the options for this program. + CLI::RestoreSettings(testName); + } + + ~BRTestFixture() + { + // Clear the settings. + bindings::tests::CleanMemory(); + CLI::ClearSettings(); + } +}; + +BOOST_FIXTURE_TEST_SUITE(BayesianRidgeMainTest, BRTestFixture); + +/** + * Check the center and scale options. +*/ +BOOST_AUTO_TEST_CASE(BRCenter0Scale0) +{ + int n = 50, m = 4; + arma::mat X = arma::randu(n, m); + arma::colvec omega = arma::randu(m); + arma::mat y = X * omega; + + SetInputParam("input", std::move(X)); + SetInputParam("responses", std::move(y)); + SetInputParam("center", 0); + + mlpackMain(); + + BayesianRidge* estimator = CLI::GetParam("output_model"); + + const arma::colvec dataScale = estimator->DataScale(); + const arma::colvec dataOffset = estimator->DataOffset(); + + BOOST_REQUIRE(sum(dataOffset) == 0); + BOOST_REQUIRE(sum(dataScale) == m); +} + +/** + * Check prediction of saved model and in code model are equal. +*/ +BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) +{ + int n = 10, m = 4; + arma::mat X = arma::randu(n, m); + arma::mat Xtest = arma::randu(2 * n, m); + const arma::colvec omega = arma::randu(m); + arma::mat y = X * omega; + + BayesianRidge model; + model.Train(X.t(), y.t()); + + arma::rowvec responses; + model.Predict(Xtest.t(), responses); + + SetInputParam("input", std::move(X)); + SetInputParam("responses", std::move(y)); + + mlpackMain(); + + CLI::GetSingleton().Parameters()["input"].wasPassed = false; + CLI::GetSingleton().Parameters()["responses"].wasPassed = false; + + SetInputParam("input_model", CLI::GetParam("output_model")); + SetInputParam("test", std::move(Xtest)); + + mlpackMain(); + + arma::mat ytest = std::move(responses).t(); + // Check that initial output and output using saved model are same. + CheckMatrices(ytest, CLI::GetParam("output_predictions")); +} + +BOOST_AUTO_TEST_SUITE_END(); From b908ae3b08dadc334e0e609c82e600573fbcb900 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 15 Feb 2020 12:00:09 +0100 Subject: [PATCH 065/297] Formatting. --- src/mlpack/tests/main_tests/bayesian_ridge_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp index d96aeafc56..4b50c920f2 100644 --- a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp @@ -48,7 +48,7 @@ BOOST_FIXTURE_TEST_SUITE(BayesianRidgeMainTest, BRTestFixture); */ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) { - int n = 50, m = 4; + int n = 50, m = 4; arma::mat X = arma::randu(n, m); arma::colvec omega = arma::randu(m); arma::mat y = X * omega; @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) } /** - * Check prediction of saved model and in code model are equal. + * Check predictions of saved model and in code model are equal. */ BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) { From f31ea8ea7a10f3517723d653c67db1c5b9c53734 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 15 Feb 2020 12:03:56 +0100 Subject: [PATCH 066/297] Formatting. --- src/mlpack/tests/main_tests/bayesian_ridge_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp index 4b50c920f2..ca932210be 100644 --- a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp @@ -28,7 +28,7 @@ struct BRTestFixture { public: BRTestFixture() - { + { // Cache in the options for this program. CLI::RestoreSettings(testName); } From fb9b243193c34ebb4e22d0de90d57fe43b751944 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 17 Feb 2020 20:57:11 +0100 Subject: [PATCH 067/297] Correct the behavior for colinear data. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index adbe0f9983..133460a15e 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -54,21 +54,13 @@ double BayesianRidge::Train(const arma::mat& data, // Enforce symmetry of the covariance matrix before eig_sym. const arma::mat phiphiT = arma::symmatu(phi * phi.t()); - if (arma::eig_sym(eigval, eigvec, phiphiT) == false) + if (arma::eig_sym(eigval, eigvec, phiphiT) == false) { Log::Warn << "Eigen Decomposition failed as Eigen Value " << "does not exists ." << std::endl; return -1; } - // Detect singular matrix. - if (eigval[0] < 1e-8) - { - Log::Warn << "Singular matrix. Two lines or more are colinear." - << std::endl; - return -1; - } - // Initialize the hyperparameters and // begin with an infinitely broad prior. alpha = 1e-6; From 1e938ae1960dc3f468dec819ed898629c95aaa57 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 17 Feb 2020 20:57:27 +0100 Subject: [PATCH 068/297] Correct the behavior for colinear data. --- src/mlpack/tests/bayesian_ridge_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 25b858455e..18c4516453 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataScale() - xStd)), 1e-6); } -// Check that Train() return -1 if X is singular. +// Check that Train() does not fail with two colinear vectors. BOOST_AUTO_TEST_CASE(SingularMatix) { arma::mat X; @@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(SingularMatix) BayesianRidge estimator; double singular = estimator.Train(X, y); - BOOST_REQUIRE(singular == -1); + BOOST_REQUIRE(singular != -1); } // Check that std are well computed/coherent. At least higher than the From c6b973909d3e00337e66d0f3b56e7bcdb5954245 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:25:13 +0200 Subject: [PATCH 069/297] Update src/mlpack/tests/main_tests/bayesian_ridge_test.cpp Co-Authored-By: Marcus Edel --- src/mlpack/tests/main_tests/bayesian_ridge_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp index ca932210be..a391331809 100644 --- a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) /** * Check predictions of saved model and in code model are equal. -*/ + */ BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) { int n = 10, m = 4; From a2ef2461c49c1e326797ecad57721deff9d12602 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:27:22 +0200 Subject: [PATCH 070/297] Update src/mlpack/tests/main_tests/bayesian_ridge_test.cpp Co-Authored-By: Marcus Edel --- src/mlpack/tests/main_tests/bayesian_ridge_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp index a391331809..e4500812af 100644 --- a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp @@ -45,7 +45,7 @@ BOOST_FIXTURE_TEST_SUITE(BayesianRidgeMainTest, BRTestFixture); /** * Check the center and scale options. -*/ + */ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) { int n = 50, m = 4; From 24a88dcfcdcd6b9fbcf45c2e7fbfcf729cdc634b Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:49:31 +0200 Subject: [PATCH 071/297] Update src/mlpack/tests/bayesian_ridge_test.cpp Co-Authored-By: Marcus Edel --- src/mlpack/tests/bayesian_ridge_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 18c4516453..678cf00931 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -10,7 +10,6 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ - #include #include From cc97b6a3af5c570fd578d735124023ee08786b5e Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:50:51 +0200 Subject: [PATCH 072/297] Update src/mlpack/tests/bayesian_ridge_test.cpp Co-Authored-By: Marcus Edel --- src/mlpack/tests/bayesian_ridge_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 678cf00931..bf5e6b649f 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -54,7 +54,6 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6); } - // Verify fitIntercept and normalize equal false do not affect the solution. BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) { From c72b008317dcce9e53b0f45d523686c63df75861 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:52:30 +0200 Subject: [PATCH 073/297] Update src/mlpack/tests/bayesian_ridge_test.cpp Co-Authored-By: Marcus Edel --- src/mlpack/tests/bayesian_ridge_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index bf5e6b649f..9143ee2c70 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -128,7 +128,8 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) estimator.Predict(X, responses, std); const double estStd = sqrt(estimator.Variance()); - for (size_t i = 0; i < X.n_cols; i++) BOOST_REQUIRE(std[i] > estStd); + for (size_t i = 0; i < X.n_cols; i++) + BOOST_REQUIRE(std[i] > estStd); } BOOST_AUTO_TEST_SUITE_END(); From bf6d04395ed6cab46817c024221d142c8b7b9d5a Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:52:51 +0200 Subject: [PATCH 074/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 49cff405aa..fd43f63900 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -213,7 +213,7 @@ class BayesianRidge * Get the precesion (or inverse variance) beta of the model. * * @return \f$ \beta \f$ - **/ + */ inline double Beta() const {return this->beta;} /** From b61bd6ee010472df702f468bd98a1f11bfcc69f1 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:53:09 +0200 Subject: [PATCH 075/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index fd43f63900..1f6d561cf0 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -220,7 +220,7 @@ class BayesianRidge * Get the estimated variance. * * @return 1.0 / \f$ \beta \f$ - **/ + */ inline double Variance() const {return 1.0 / this->Beta();} /** From 4383c43ab1a385a870ef48a48451029a191a56e1 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:54:50 +0200 Subject: [PATCH 076/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 1f6d561cf0..dc244274a3 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -207,7 +207,7 @@ class BayesianRidge * * @return omega Solution vector. **/ - inline arma::colvec Omega() const{return this->omega;} +arma::colvec& Omega() const { return this->omega; } /** * Get the precesion (or inverse variance) beta of the model. From d833953772ec13455779ad74e042394ef4c4ae24 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:55:48 +0200 Subject: [PATCH 077/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index dc244274a3..8571ab7ddb 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -214,7 +214,7 @@ arma::colvec& Omega() const { return this->omega; } * * @return \f$ \beta \f$ */ - inline double Beta() const {return this->beta;} + double Beta() const { return this->beta; } /** * Get the estimated variance. From d16a734653071d7c2626ff94acc0470a334db0b8 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:56:01 +0200 Subject: [PATCH 078/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 8571ab7ddb..2a1a195421 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -228,7 +228,7 @@ arma::colvec& Omega() const { return this->omega; } * Vector of 0 if centerData is false. * * @return responsesOffset - **/ + */ inline arma::colvec DataOffset() const {return this->dataOffset;} /** From 725302fab82f329673f2cae569be06ad77657dd5 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:58:55 +0200 Subject: [PATCH 079/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 2a1a195421..ec50d49558 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -221,7 +221,7 @@ arma::colvec& Omega() const { return this->omega; } * * @return 1.0 / \f$ \beta \f$ */ - inline double Variance() const {return 1.0 / this->Beta();} + double Variance() const { return 1.0 / this->Beta(); } /** * Get the mean vector computed on the features over the training points. From 7317112fc8d84ed93f54540fb507afb560ce009a Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:59:07 +0200 Subject: [PATCH 080/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index ec50d49558..b65b13ebb6 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -236,7 +236,7 @@ arma::colvec& Omega() const { return this->omega; } * training points. Vector of 1 if scaleData is false. * * return dataOffset - **/ + */ inline arma::colvec DataScale() const {return this->dataScale;} /** From cb688c04a3903e9b49a1ecac9136f4fbe2616ce8 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 21:59:16 +0200 Subject: [PATCH 081/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index b65b13ebb6..9d1eef6ab5 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -242,7 +242,7 @@ arma::colvec& Omega() const { return this->omega; } /** * Get the mean value of the train responses. * @return responsesOffset - **/ + */ inline double ResponsesOffset() const {return this->responsesOffset;} From a2c2d4609a392130ade377e30b837cc937ed9790 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:14:41 +0200 Subject: [PATCH 082/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 9d1eef6ab5..070b010716 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -229,7 +229,7 @@ arma::colvec& Omega() const { return this->omega; } * * @return responsesOffset */ - inline arma::colvec DataOffset() const {return this->dataOffset;} + arma::colvec& DataOffset() const { return this->dataOffset; } /** * Get the vector of standard deviations computed on the features over the From 1f302f97766a6f45bd0d63cdfb0e2ca171d465bc Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:16:57 +0200 Subject: [PATCH 083/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 070b010716..e2c844bffe 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -237,7 +237,7 @@ arma::colvec& Omega() const { return this->omega; } * * return dataOffset */ - inline arma::colvec DataScale() const {return this->dataScale;} + arma::colvec& DataScale() const { return this->dataScale; } /** * Get the mean value of the train responses. From c829d08c72011b822155ab3e21dbdb6c6d60c8aa Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:18:24 +0200 Subject: [PATCH 084/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index e2c844bffe..53dc44ebd7 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -243,8 +243,7 @@ arma::colvec& Omega() const { return this->omega; } * Get the mean value of the train responses. * @return responsesOffset */ - inline double ResponsesOffset() const - {return this->responsesOffset;} + double ResponsesOffset() const { return this->responsesOffset; } /** * Serialize the BayesianRidge model. From f9ce345e7bd58394a0fa9fb82c3aa3c116f02e01 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:19:11 +0200 Subject: [PATCH 085/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 53dc44ebd7..d2227705da 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -105,7 +105,7 @@ class BayesianRidge * @param responses A vector of targets. * @return score. Root Mean Square Error. Equal to -1 if two feature vectors * or more are colinear. - **/ + */ double Train(const arma::mat& data, const arma::rowvec& responses); From 8aa8bbe766666fbaee4ae31d0b38b4509b575e79 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:19:37 +0200 Subject: [PATCH 086/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index d2227705da..a32b980bd7 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -117,7 +117,7 @@ class BayesianRidge * @param predictions y, Contains the predicted values on completion. * * @return Root mean squared error computed on the train set. - **/ + */ void Predict(const arma::mat& points, arma::rowvec& predictions) const; From 94be103a32e3b6c3b19f495316780301c0117f91 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:20:40 +0200 Subject: [PATCH 087/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index a32b980bd7..aaf2a8bc1b 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -90,7 +90,7 @@ class BayesianRidge * @param nIterMax Maximum number of iterations for convergency. * @param tol Level from which the solution is considered sufficientlly * stable. - **/ + */ BayesianRidge(const bool centerData = true, const bool scaleData = false, const int nIterMax = 50, From c1d1e2ea4be5a6857b2c910514424c9814df7610 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:22:58 +0200 Subject: [PATCH 088/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index aaf2a8bc1b..8504768c33 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -13,6 +13,7 @@ namespace mlpack{ namespace regression{ + /** * This class implements the bayesian linear regression. "Bayesian treatment * of linear regression, which will avoid the over-fitting problem of maximum From 2cb87afe9ff020a399c35fcb85ef09f807dbf4b9 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:27:27 +0200 Subject: [PATCH 089/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 8504768c33..666da58d6a 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -6,6 +6,7 @@ * bayesian linear regression. According to the armadillo standards, * all the functions consider data in column-major format. **/ + #ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP #define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP From e49112f781f5e55852980d754e6afc3625b1cb2d Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:27:54 +0200 Subject: [PATCH 090/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 666da58d6a..544e890840 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -208,7 +208,7 @@ class BayesianRidge * Get the solution vector * * @return omega Solution vector. - **/ + */ arma::colvec& Omega() const { return this->omega; } /** From 3ab9e5f565e91023dc225d7f08ae5c0f61dc15f0 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:28:29 +0200 Subject: [PATCH 091/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp Co-Authored-By: Marcus Edel --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 133460a15e..f6406d015e 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -169,7 +169,6 @@ double BayesianRidge::CenterScaleData(const arma::mat& data, return responsesOffset; } - // Copy construcor. BayesianRidge::BayesianRidge(const BayesianRidge& other): centerData(other.centerData), From befa796501d90648f209f28b69845a33aeb969b7 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 15 Apr 2020 22:39:20 +0200 Subject: [PATCH 092/297] Return const references. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 544e890840..f4626e48dc 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -209,7 +209,7 @@ class BayesianRidge * * @return omega Solution vector. */ -arma::colvec& Omega() const { return this->omega; } + const arma::colvec& Omega() const { return this->omega; } /** * Get the precesion (or inverse variance) beta of the model. @@ -231,7 +231,7 @@ arma::colvec& Omega() const { return this->omega; } * * @return responsesOffset */ - arma::colvec& DataOffset() const { return this->dataOffset; } + const arma::colvec& DataOffset() const { return this->dataOffset; } /** * Get the vector of standard deviations computed on the features over the @@ -239,7 +239,7 @@ arma::colvec& Omega() const { return this->omega; } * * return dataOffset */ - arma::colvec& DataScale() const { return this->dataScale; } + const arma::colvec& DataScale() const { return this->dataScale; } /** * Get the mean value of the train responses. From a1977f1b78f3a3d0c2bda54f7ba2396cabc9f510 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:47:28 +0200 Subject: [PATCH 093/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index f6406d015e..907eb42e1f 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -56,8 +56,7 @@ double BayesianRidge::Train(const arma::mat& data, if (arma::eig_sym(eigval, eigvec, phiphiT) == false) { - Log::Warn << "Eigen Decomposition failed as Eigen Value " - << "does not exists ." << std::endl; + Log::Warn << "BayesianRidge::Train(): Eigendecomposition of covariance failed!" << std::endl; return -1; } From c15c1d0f62692111a4b1a7e456eb3d6f845a3232 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:51:19 +0200 Subject: [PATCH 094/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index f4626e48dc..6d98437cd1 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -16,7 +16,7 @@ namespace mlpack{ namespace regression{ /** - * This class implements the bayesian linear regression. "Bayesian treatment + * This class implements Bayesian linear regression. "Bayesian treatment * of linear regression, which will avoid the over-fitting problem of maximum * likelihood, and which will also lead to automatic methods of determining * model complexity using the training data alone.", C.Bishop. From cd3d503d78d6b4e841403e6b4c3ceee1e690feff Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 15 Apr 2020 22:51:35 +0200 Subject: [PATCH 095/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index d8e288af24..87bc637567 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -159,7 +159,7 @@ static void mlpackMain() arma::rowvec y = std::move(matY); arma::rowvec predictionsTrain; - // The Train method is ready to take data in colomn-major format. + // The Train method is ready to take data in column-major format. bayesRidge->Train(matX.t(), matY); } else // We must have --input_model_file. From 088c2c41f420275cbadb4492c4c2c1bec548e314 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 17 Apr 2020 23:06:00 +0200 Subject: [PATCH 096/297] Cut the message error line to respect the 79 spaces. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 907eb42e1f..a01bf1d93f 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -56,7 +56,9 @@ double BayesianRidge::Train(const arma::mat& data, if (arma::eig_sym(eigval, eigvec, phiphiT) == false) { - Log::Warn << "BayesianRidge::Train(): Eigendecomposition of covariance failed!" << std::endl; + Log::Warn << "BayesianRidge::Train(): Eigendecomposition " + << "of covariance failed!" + << std::endl; return -1; } From 6b082a0a97c348fd0d1e5e208af3898383c20e86 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 17 Apr 2020 23:07:08 +0200 Subject: [PATCH 097/297] Replace the Bishop citation by a short description of the algotithm. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 6d98437cd1..d9a1039c5e 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -16,19 +16,23 @@ namespace mlpack{ namespace regression{ /** - * This class implements Bayesian linear regression. "Bayesian treatment - * of linear regression, which will avoid the over-fitting problem of maximum - * likelihood, and which will also lead to automatic methods of determining - * model complexity using the training data alone.", C.Bishop. - * - * More details and description in : - * Christopher Bishop (2006), Pattern Recognition and Machine Learning. - * David J.C MacKay (1991), Bayesian Interpolation, Computation and Neural - * systems. - - * Model optimization is automatic and does not require cross validation - * procedure to be optimized. + * A Bayesian approach to the maximum likelihood estimation of the parameters + * \f$ \omega \f$ of the linear regression model. The Complexity is governed by + * the addition of a gaussian isotropic prior of precision \f$ \alpha \f$ over + * \f$ \omega \f$: * + * \f[ + * p(\omega|\alpha) = \mathcal{N}(\omega|0, \alpha^{-1}I) + * \f] + * + * The optimization procedure calculates the posterior distribution of + * \f$ \omega \f$ knowing the data by maximizing an approximation of the log + * marginal likelihood derived from a type II maximum likelihood approximation. + * The determination of \f$ alpha \f$ and of the noise precision \f$ beta \f$ + * is part of the optimization process, leading to an automatic determination of + * w. The model being entirely based on probabilty distributions, uncertainties + * are available and easly computed for both the parameters and the predictions. + * * @code * @article{MacKay91bayesianinterpolation, * author = {David J.C. MacKay}, From b24464f721ec17b75f4423de0cdec024354ec372 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 10:13:58 +0200 Subject: [PATCH 098/297] Code formatting. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index a01bf1d93f..1c15c588fb 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -58,7 +58,7 @@ double BayesianRidge::Train(const arma::mat& data, { Log::Warn << "BayesianRidge::Train(): Eigendecomposition " << "of covariance failed!" - << std::endl; + << std::endl; return -1; } From 6615553e2cf19110619692033211b1ad2f664445 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Sat, 18 Apr 2020 10:14:13 +0200 Subject: [PATCH 099/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index d9a1039c5e..2f6c40765b 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -149,7 +149,7 @@ class BayesianRidge * @param responses A vector of targets. * @return RMSE **/ - double Rmse(const arma::mat& data, + double RMSE(const arma::mat& data, const arma::rowvec& responses) const; /** From edf736522b8596bb103f602868780d8421e76177 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 10:35:35 +0200 Subject: [PATCH 100/297] Add precisions in the description of the method. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index d9a1039c5e..bf27fac96b 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -32,7 +32,11 @@ namespace regression{ * is part of the optimization process, leading to an automatic determination of * w. The model being entirely based on probabilty distributions, uncertainties * are available and easly computed for both the parameters and the predictions. - * + * + * The avantage over linear regression and ridge regression is that the + * regularization is determined from all the training data alone without any + * require to an holdout method. + * * @code * @article{MacKay91bayesianinterpolation, * author = {David J.C. MacKay}, From 4568ff4c6d5835e428ddc88754f0de188f377590 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 10:52:10 +0200 Subject: [PATCH 101/297] Modify documention. Now BayesianRidge::Train() throw an exception in the case eig_sym() fails. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index d540da9d60..74fed59ecd 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -78,7 +78,7 @@ namespace regression{ * estimator.Predict(Xtest, prediction); * arma::rowvec ytest; // Test target values. - * estimator.Rmse(Xtest, ytest); // Evaluate using the RMSE score. + * estimator.RMSE(Xtest, ytest); // Evaluate using the RMSE score. * // Compute the standard deviations of the predictions. * arma::rowvec stds; @@ -107,14 +107,12 @@ class BayesianRidge const double tol = 1e-4); /** - * Run BayesianRidge regression. The input matrix (like all mlpack matrices) - * should be + * Run BayesianRidge. The input matrix (like all mlpack matrices) should be * column-major -- each column is an observation and each row is a dimension. * * @param data Column-major input data * @param responses A vector of targets. - * @return score. Root Mean Square Error. Equal to -1 if two feature vectors - * or more are colinear. + * @return score. Root Mean Square Error. */ double Train(const arma::mat& data, const arma::rowvec& responses); From 8c49c1d01afcb6666d7b4d295431860b0e6ddd60 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 11:13:32 +0200 Subject: [PATCH 102/297] Throw std::runtime_error instead of returning -1 if eig_sym() fails. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 1c15c588fb..75f38089d7 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -59,7 +59,7 @@ double BayesianRidge::Train(const arma::mat& data, Log::Warn << "BayesianRidge::Train(): Eigendecomposition " << "of covariance failed!" << std::endl; - return -1; + throw std::runtime_error("eig_sym() failed."); } // Initialize the hyperparameters and @@ -106,7 +106,7 @@ double BayesianRidge::Train(const arma::mat& data, i++; } Timer::Stop("bayesian_ridge_regression"); - return Rmse(data, responses); + return RMSE(data, responses); } void BayesianRidge::Predict(const arma::mat& points, @@ -127,7 +127,7 @@ void BayesianRidge::Predict(const arma::mat& points, std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); } -double BayesianRidge::Rmse(const arma::mat& data, +double BayesianRidge::RMSE(const arma::mat& data, const arma::rowvec& responses) const { arma::rowvec predictions; From 209075f9ebe8c6d4b478ed294906b9d5b2304594 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 11:40:53 +0200 Subject: [PATCH 103/297] Integrate nIterMax and tol in the move constructor. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 75f38089d7..44e4763d87 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -210,6 +210,8 @@ BayesianRidge::BayesianRidge(BayesianRidge&& other): other.beta = 0.0; other.omega.reset(); other.matCovariance.reset(); + nIterMax = 0.0; + tol = 0.0; } } @@ -228,6 +230,8 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) beta = other.beta; omega = other.omega; matCovariance = other.matCovariance; + nIterMax = other.nIterMax; + tol = other.tol; return *this; } From cdfcaaab7328492b95accc6e5bee5e214428f7bf Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 11:41:05 +0200 Subject: [PATCH 104/297] Integrate nIterMax and tol in the move constructor. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp index ca17b78701..8a0d17ada5 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp @@ -1,6 +1,6 @@ /** * @file bayesian_ridge_impl.hpp - * @author Ryan Curtin/Clement Mercier + * @author Clement Mercier * * Implementation of templated BayesianRidge functions. * @@ -33,6 +33,8 @@ void BayesianRidge::serialize(Archive& ar, const unsigned int /* version */) ar & BOOST_SERIALIZATION_NVP(gamma); ar & BOOST_SERIALIZATION_NVP(omega); ar & BOOST_SERIALIZATION_NVP(matCovariance); + ar & BOOST_SERIALIZATION_NVP(nIterMax); + ar & BOOST_SERIALIZATION_NVP(tol); } } // namespace regression From 31758f5a12b293e999c81743d26b07dfdc8cc40d Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:44:06 +0200 Subject: [PATCH 105/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp Co-Authored-By: Ryan Curtin --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 44e4763d87..3036f10d67 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -136,13 +136,13 @@ double BayesianRidge::RMSE(const arma::mat& data, } double BayesianRidge::CenterScaleData(const arma::mat& data, - const arma::rowvec& responses, - bool centerData, - bool scaleData, - arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale) + const arma::rowvec& responses, + bool centerData, + bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale) { // Initialize the offsets to their neutral forms. dataOffset = arma::zeros(data.n_rows); From 1265a8ec15ea3533a73ceb97b2e34b69de84e81d Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:45:19 +0200 Subject: [PATCH 106/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 3036f10d67..2e2b1e4dcf 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -99,7 +99,7 @@ double BayesianRidge::Train(const arma::mat& data, const arma::rowvec temp = t - omega.t() * phi; beta = (data.n_cols - gamma) / dot(temp, temp); - // Comptute the stopping criterion. + // Compute the stopping criterion. deltaAlpha += alpha; deltaBeta += beta; crit = abs(deltaAlpha / alpha + deltaBeta / beta); From 3145bfef7a58b170fa68efdb0000b8ea56b98352 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 11:55:45 +0200 Subject: [PATCH 107/297] Suppress the arbitrary fixation of nIterMax. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 44e4763d87..54f82f2935 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -67,7 +67,6 @@ double BayesianRidge::Train(const arma::mat& data, alpha = 1e-6; beta = 1 / (var(t) * 0.1); - unsigned short nIterMax = 50; unsigned short i = 0; double deltaAlpha = 1, deltaBeta = 1, crit = 1; arma::mat matA = arma::eye(data.n_rows, data.n_rows); From 6905295c915da3725b75771cda1cad61ff370454 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sat, 18 Apr 2020 11:57:39 +0200 Subject: [PATCH 108/297] Avoid useless transposition dot(omega.t(), omega) -> dot(omega, omega). --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 54f82f2935..b26aa45577 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -92,7 +92,7 @@ double BayesianRidge::Train(const arma::mat& data, // Update alpha. eigvali = eigval * beta; gamma = sum(eigvali / (alpha + eigvali)); - alpha = gamma / dot(omega.t(), omega); + alpha = gamma / dot(omega, omega); // Update beta. const arma::rowvec temp = t - omega.t() * phi; From c784d6996b04f5a2f25637c88318a81c48a9decf Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 19 Apr 2020 11:25:54 +0200 Subject: [PATCH 109/297] Replace arma::abs() by std::abs(). arma::abs() was returning 0 and stopped the while loop --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index b26aa45577..79b283b8cc 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -65,10 +65,10 @@ double BayesianRidge::Train(const arma::mat& data, // Initialize the hyperparameters and // begin with an infinitely broad prior. alpha = 1e-6; - beta = 1 / (var(t) * 0.1); + beta = 1 / (var(t, 1) * 0.1); unsigned short i = 0; - double deltaAlpha = 1, deltaBeta = 1, crit = 1; + double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0; arma::mat matA = arma::eye(data.n_rows, data.n_rows); while ((crit > tol) && (i < nIterMax)) @@ -101,7 +101,7 @@ double BayesianRidge::Train(const arma::mat& data, // Comptute the stopping criterion. deltaAlpha += alpha; deltaBeta += beta; - crit = abs(deltaAlpha / alpha + deltaBeta / beta); + crit = std::abs(deltaAlpha / alpha + deltaBeta / beta); i++; } Timer::Stop("bayesian_ridge_regression"); From 69ca2d5abd057f0e8a237aec40e55c1463ea187e Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 19 Apr 2020 17:19:39 +0200 Subject: [PATCH 110/297] Use solve instead of inv_sympd(). --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 79b283b8cc..f722187abc 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -78,17 +78,17 @@ double BayesianRidge::Train(const arma::mat& data, // Compute the posterior statistics. // with inv() - matA.diag().fill(alpha); // inv is used instead of solve because we need the covariance matrix to // compute the prediction uncertainties. If solve is used, matCovariance // must be comptuted at the end of the loop. - matCovariance = inv_sympd(matA + phiphiT * beta); - omega = (matCovariance * vecphitT) * beta; + // matA.diag().fill(alpha); + // matCovariance = inv_sympd(matA + phiphiT * beta); + // omega = (matCovariance * vecphitT) * beta; // // with solve() - // matA.diag().fill(alpha/ beta); - // omega = solve(matA + phiphiT, vecphitT); - + matA.diag().fill(alpha / beta); + omega = solve(matA + phiphiT, vecphitT); + // Update alpha. eigvali = eigval * beta; gamma = sum(eigvali / (alpha + eigvali)); @@ -105,6 +105,10 @@ double BayesianRidge::Train(const arma::mat& data, i++; } Timer::Stop("bayesian_ridge_regression"); + + // Compute the covariance matrice for the uncertaities later. + matCovariance = inv_sympd(matA + phiphiT * beta); + return RMSE(data, responses); } From 147ff9f4ad45db7a4a3983079519ec8a68cdaf7d Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 20 Apr 2020 11:08:51 +0200 Subject: [PATCH 111/297] Add reference to the section 3.5.2 of the Bishop book. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 74fed59ecd..4803ef8cc6 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -8,7 +8,7 @@ **/ #ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP -#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP +#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP #include @@ -35,7 +35,11 @@ namespace regression{ * * The avantage over linear regression and ridge regression is that the * regularization is determined from all the training data alone without any - * require to an holdout method. + * require to an hold out method. + * + * The code below is an implementation of the maximization of the evidence + * function described in the section 3.5.2 of the C.Bishop book, Pattern + * Recognition and Machine Learning. * * @code * @article{MacKay91bayesianinterpolation, @@ -63,26 +67,26 @@ namespace regression{ * Example of use: * * @code - * arma::mat Xtrain; // Train data matrix. Column-major. - * arma::rowvec ytrain; // Train target values. + * arma::mat xTrain; // Train data matrix. Column-major. + * arma::rowvec yTrain; // Train target values. * // Train the model. Regularization strength is optimally tunned with the * // training data alone by applying the Train method. * BayesianRidge estimator(); // Instanciate the estimator with default option. - * estimator.Train(Xtrain, ytrain); + * estimator.Train(xTrain, yTrain); * // Prediction on test points. - * arma::mat Xtest; // Test data matrix. Column-major. + * arma::mat xTest; // Test data matrix. Column-major. * arma::rowvec predictions; - * estimator.Predict(Xtest, prediction); + * estimator.Predict(xTest, prediction); - * arma::rowvec ytest; // Test target values. - * estimator.RMSE(Xtest, ytest); // Evaluate using the RMSE score. + * arma::rowvec yTest; // Test target values. + * estimator.RMSE(xTest, yTest); // Evaluate using the RMSE score. * // Compute the standard deviations of the predictions. * arma::rowvec stds; - * estimator.Predict(Xtest, responses, stds) + * estimator.Predict(xTest, responses, stds) * @endcode */ class BayesianRidge From e12045dc77573f105e40992e5e80029589d131a0 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 20 Apr 2020 11:50:03 +0200 Subject: [PATCH 112/297] Set the argument in the right order in the move constructor. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 16 ++++++++++++---- .../bayesian_ridge/bayesian_ridge_impl.hpp | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 987e09bf2d..575c27da3c 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -177,6 +177,8 @@ double BayesianRidge::CenterScaleData(const arma::mat& data, BayesianRidge::BayesianRidge(const BayesianRidge& other): centerData(other.centerData), scaleData(other.scaleData), + nIterMax(other.nIterMax), + tol(other.tol), dataOffset(other.dataOffset), dataScale(other.dataScale), responsesOffset(other.responsesOffset), @@ -191,6 +193,8 @@ BayesianRidge::BayesianRidge(const BayesianRidge& other): BayesianRidge::BayesianRidge(BayesianRidge&& other): centerData(other.centerData), scaleData(other.scaleData), + nIterMax(other.nIterMax), + tol(other.tol), dataOffset(std::move(other.dataOffset)), dataScale(std::move(other.dataScale)), responsesOffset(other.responsesOffset), @@ -205,6 +209,8 @@ BayesianRidge::BayesianRidge(BayesianRidge&& other): { other.centerData = false; other.scaleData = false; + other.nIterMax = 0.0; + other.tol = 0.0; other.dataOffset.reset(); other.dataScale.reset(); other.responsesOffset = 0.0; @@ -213,8 +219,6 @@ BayesianRidge::BayesianRidge(BayesianRidge&& other): other.beta = 0.0; other.omega.reset(); other.matCovariance.reset(); - nIterMax = 0.0; - tol = 0.0; } } @@ -225,6 +229,8 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) centerData = other.centerData; scaleData = other.scaleData; + nIterMax = other.nIterMax; + tol = other.tol; dataOffset = other.dataOffset; dataScale = other.dataScale; responsesOffset = other.responsesOffset; @@ -233,8 +239,6 @@ BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) beta = other.beta; omega = other.omega; matCovariance = other.matCovariance; - nIterMax = other.nIterMax; - tol = other.tol; return *this; } @@ -244,6 +248,8 @@ BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) { centerData = other.centerData; scaleData = other.scaleData; + nIterMax = other.nIterMax; + tol = other.tol; dataOffset = other.dataOffset; dataScale = other.dataScale; responsesOffset = other.responsesOffset; @@ -256,6 +262,8 @@ BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) // Clear the other object. other.centerData = false; other.scaleData = false; + other.nIterMax = 0.0; + other.tol = 0.0; other.dataOffset.reset(); other.dataScale.reset(); other.responsesOffset = 0.0; diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp index 8a0d17ada5..a2191d45ad 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp @@ -25,6 +25,8 @@ void BayesianRidge::serialize(Archive& ar, const unsigned int /* version */) { ar & BOOST_SERIALIZATION_NVP(centerData); ar & BOOST_SERIALIZATION_NVP(scaleData); + ar & BOOST_SERIALIZATION_NVP(nIterMax); + ar & BOOST_SERIALIZATION_NVP(tol); ar & BOOST_SERIALIZATION_NVP(dataOffset); ar & BOOST_SERIALIZATION_NVP(dataScale); ar & BOOST_SERIALIZATION_NVP(responsesOffset); @@ -33,8 +35,6 @@ void BayesianRidge::serialize(Archive& ar, const unsigned int /* version */) ar & BOOST_SERIALIZATION_NVP(gamma); ar & BOOST_SERIALIZATION_NVP(omega); ar & BOOST_SERIALIZATION_NVP(matCovariance); - ar & BOOST_SERIALIZATION_NVP(nIterMax); - ar & BOOST_SERIALIZATION_NVP(tol); } } // namespace regression From 97136d36a2711cdc3a5b8c1f2b70796126907d6d Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 20 Apr 2020 11:53:34 +0200 Subject: [PATCH 113/297] Ignore output_predictions unless test is specified. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 87bc637567..06268d5ada 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -129,8 +129,9 @@ static void mlpackMain() RequireAtLeastOnePassed({ "output_predictions", "output_model" }, false, "no results will be saved"); - // Is this line really rigth ? It comes from lars_main.hpp. - // ReportIgnoredParam({{ "test", true }}, "output_predictions"); + + // Ignore out_predictions unless test is specified. + ReportIgnoredParam({{"test", true }}, "output_predictions"); BayesianRidge* bayesRidge; if (CLI::HasParam("input")) From af06919e5929a0424476e2737da3412eb3f2e2fc Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 21 Apr 2020 20:32:20 +0200 Subject: [PATCH 114/297] Code formatting in BayesianRidge//Predict(). --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 575c27da3c..193d7290e2 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -16,7 +16,6 @@ using namespace mlpack; using namespace mlpack::regression; - BayesianRidge::BayesianRidge(const bool centerData, const bool scaleData, const int nIterMax, @@ -104,11 +103,12 @@ double BayesianRidge::Train(const arma::mat& data, crit = std::abs(deltaAlpha / alpha + deltaBeta / beta); i++; } - Timer::Stop("bayesian_ridge_regression"); // Compute the covariance matrice for the uncertaities later. matCovariance = inv_sympd(matA + phiphiT * beta); + Timer::Stop("bayesian_ridge_regression"); + return RMSE(data, responses); } @@ -116,8 +116,9 @@ void BayesianRidge::Predict(const arma::mat& points, arma::rowvec& predictions) const { // y_hat = w^T * (X - mu) / sigma + y_mean. - predictions = omega.t() * - ((points.each_col() - dataOffset).each_col() / dataScale) + responsesOffset; + predictions = omega.t() * ((points.each_col() - dataOffset).each_col() + / dataScale); + predictions += responsesOffset; } void BayesianRidge::Predict(const arma::mat& points, @@ -126,7 +127,8 @@ void BayesianRidge::Predict(const arma::mat& points, { // Center and scaleData the points before applying the model. const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; - predictions = omega.t() * X + responsesOffset; + predictions = omega.t() * X; + predictions += responsesOffset; std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); } From 71f2fa28c9fd219b7ad36b8891036b7fea888556 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 21 Apr 2020 21:04:40 +0200 Subject: [PATCH 115/297] Use PARAM_MATRIX instead of PARAM_TMATRIX. --- .../bayesian_ridge/bayesian_ridge_main.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 06268d5ada..d6fc195085 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -87,7 +87,7 @@ PROGRAM_INFO("BayesianRidge", PRINT_CALL("bayesian_ridge", "input_model", "bayesian_ridge_model", "test", "test", "output_predictions", "test_predictions")); -PARAM_TMATRIX_IN("input", "Matrix of covariates (X).", "i"); +PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); @@ -97,10 +97,10 @@ PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained BayesianRidge model " PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output BayesianRidge model.", "M"); -PARAM_TMATRIX_IN("test", "Matrix containing points to regress on (test " +PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " "points).", "t"); -PARAM_TMATRIX_OUT("output_predictions", "If --test_file is specified, this " +PARAM_MATRIX_OUT("output_predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " @@ -125,13 +125,13 @@ static void mlpackMain() RequireOnlyOnePassed({ "responses" }, true, "if input data is specified, " "responses must also be specified"); } - ReportIgnoredParam({{"input", false }}, "responses"); + ReportIgnoredParam({{ "input", false }}, "responses"); RequireAtLeastOnePassed({ "output_predictions", "output_model" }, false, "no results will be saved"); // Ignore out_predictions unless test is specified. - ReportIgnoredParam({{"test", true }}, "output_predictions"); + ReportIgnoredParam({{ "test", true }}, "output_predictions"); BayesianRidge* bayesRidge; if (CLI::HasParam("input")) @@ -140,7 +140,8 @@ static void mlpackMain() // Initialize the object. bayesRidge = new BayesianRidge(center, scale); - // Load covariates. + // Load covariates. We can avoid LARS transposing our data by choosing to + // not transpose this data (that's why we used PARAM_TMATRIX_IN). mat matX = std::move(CLI::GetParam("input")); // Load responses. The responses should be a one-dimensional vector, and it @@ -154,14 +155,14 @@ static void mlpackMain() if (matY.n_rows > 1) Log::Fatal << "Only one column or row allowed in responses file!" << endl; - if (matY.n_elem != matX.n_rows) + if (matY.n_elem != matX.n_cols) Log::Fatal << "Number of responses must be equal to number of rows of X!" << endl; arma::rowvec y = std::move(matY); arma::rowvec predictionsTrain; // The Train method is ready to take data in column-major format. - bayesRidge->Train(matX.t(), matY); + bayesRidge->Train(matX, matY); } else // We must have --input_model_file. { @@ -175,10 +176,10 @@ static void mlpackMain() mat testPoints = std::move(CLI::GetParam("test")); arma::rowvec predictions; - bayesRidge->Predict(testPoints.t(), predictions); + bayesRidge->Predict(testPoints, predictions); // Save test predictions (one per line). - CLI::GetParam("output_predictions") = std::move(predictions.t()); + CLI::GetParam("output_predictions") = std::move(predictions); Log::Info << predictions << std::endl; } From 1d7f42ce349f20d073f260caaa97e17aabc9e87a Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 21 Apr 2020 22:53:32 +0200 Subject: [PATCH 116/297] Add option to save the predictive standard deviations. --- .../bayesian_ridge/bayesian_ridge_main.cpp | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index d6fc195085..8b6cbfd862 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -36,9 +36,9 @@ PROGRAM_INFO("BayesianRidge", "on the solution. " "\n" "Optimization is AUTOMATIC and does not require cross validation. " - "The optimization is performed by type II maximium likelihood. Parameters " - "are tunned during the maximization of the marginal likelihood. This " - "procedure includes the Ockham's razor that penalizes over complex " + "The optimization is performed by maximization of the evidence function. " + "Parameters are tunned during the maximization of the marginal likelihood. " + "This procedure includes the Ockham's razor that penalizes over complex " "solutions. " "\n\n" "This program is able to train a Baysian Ridge model or load a " @@ -68,7 +68,9 @@ PROGRAM_INFO("BayesianRidge", "trained model or the given input model. Test points can be specified with" " the " + PRINT_PARAM_STRING("test") + " parameter. Predicted responses " "to the test points can be saved with the " + - PRINT_PARAM_STRING("output_predictions") + " output parameter." + PRINT_PARAM_STRING("output_predictions") + " output parameter. The " + "corresponding standard deviation can be save by precising the " + + PRINT_PARAM_STRING("output_std") + " parameter." "\n\n" "For example, the following command trains a model on the data " + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + @@ -103,6 +105,10 @@ PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " PARAM_MATRIX_OUT("output_predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); +PARAM_MATRIX_OUT("output_std", "If --std_file is specified, this file is where " + "the standard deviations of the predictive distribution will " + "be saved.", "u"); + PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " "disable", "c", @@ -174,9 +180,19 @@ static void mlpackMain() Log::Info << "Regressing on test points." << endl; // Load test points. mat testPoints = std::move(CLI::GetParam("test")); - arma::rowvec predictions; - bayesRidge->Predict(testPoints, predictions); + + if (CLI::HasParam("output_std")) + { + arma::rowvec std; + bayesRidge->Predict(testPoints, predictions, std); + + // Save the standard deviation of the test points (one per line). + CLI::GetParam("output_std") = std::move(std); + } + + else + bayesRidge->Predict(testPoints, predictions); // Save test predictions (one per line). CLI::GetParam("output_predictions") = std::move(predictions); From 60337d1e3d0c3d8cbf1368358e11a73b89a39cf8 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 22 Apr 2020 16:07:02 +0200 Subject: [PATCH 117/297] Formatting. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 6 +++--- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 193d7290e2..9515b6da8c 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -16,6 +16,7 @@ using namespace mlpack; using namespace mlpack::regression; + BayesianRidge::BayesianRidge(const bool centerData, const bool scaleData, const int nIterMax, @@ -87,7 +88,7 @@ double BayesianRidge::Train(const arma::mat& data, // // with solve() matA.diag().fill(alpha / beta); omega = solve(matA + phiphiT, vecphitT); - + // Update alpha. eigvali = eigval * beta; gamma = sum(eigvali / (alpha + eigvali)); @@ -103,7 +104,6 @@ double BayesianRidge::Train(const arma::mat& data, crit = std::abs(deltaAlpha / alpha + deltaBeta / beta); i++; } - // Compute the covariance matrice for the uncertaities later. matCovariance = inv_sympd(matA + phiphiT * beta); @@ -117,7 +117,7 @@ void BayesianRidge::Predict(const arma::mat& points, { // y_hat = w^T * (X - mu) / sigma + y_mean. predictions = omega.t() * ((points.each_col() - dataOffset).each_col() - / dataScale); + / dataScale); predictions += responsesOffset; } diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 8b6cbfd862..0dc7d39c9d 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -70,7 +70,7 @@ PROGRAM_INFO("BayesianRidge", "to the test points can be saved with the " + PRINT_PARAM_STRING("output_predictions") + " output parameter. The " "corresponding standard deviation can be save by precising the " + - PRINT_PARAM_STRING("output_std") + " parameter." + PRINT_PARAM_STRING("output_std") + " parameter." "\n\n" "For example, the following command trains a model on the data " + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + @@ -186,12 +186,12 @@ static void mlpackMain() { arma::rowvec std; bayesRidge->Predict(testPoints, predictions, std); - + // Save the standard deviation of the test points (one per line). CLI::GetParam("output_std") = std::move(std); } - - else + + else bayesRidge->Predict(testPoints, predictions); // Save test predictions (one per line). From 7d8a45a033645f08d5ea0398bd5444118ad209f7 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Mon, 27 Apr 2020 10:30:39 +0200 Subject: [PATCH 118/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 4803ef8cc6..d19391c8ee 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -33,7 +33,7 @@ namespace regression{ * w. The model being entirely based on probabilty distributions, uncertainties * are available and easly computed for both the parameters and the predictions. * - * The avantage over linear regression and ridge regression is that the + * The advantage over linear regression and ridge regression is that the * regularization is determined from all the training data alone without any * require to an hold out method. * From 819b9a250f03bf777692b5d1f7ab68d2bccc7954 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 27 Apr 2020 10:40:49 +0200 Subject: [PATCH 119/297] Supress move constructors. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 103 ------------------ .../methods/bayesian_ridge/bayesian_ridge.hpp | 30 ----- 2 files changed, 133 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 9515b6da8c..23345ab3f2 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -16,7 +16,6 @@ using namespace mlpack; using namespace mlpack::regression; - BayesianRidge::BayesianRidge(const bool centerData, const bool scaleData, const int nIterMax, @@ -175,105 +174,3 @@ double BayesianRidge::CenterScaleData(const arma::mat& data, return responsesOffset; } -// Copy construcor. -BayesianRidge::BayesianRidge(const BayesianRidge& other): - centerData(other.centerData), - scaleData(other.scaleData), - nIterMax(other.nIterMax), - tol(other.tol), - dataOffset(other.dataOffset), - dataScale(other.dataScale), - responsesOffset(other.responsesOffset), - alpha(other.alpha), - beta(other.beta), - gamma(other.gamma), - omega(other.omega), - matCovariance(other.matCovariance) -{/* All is done */} - -// Move constructor. -BayesianRidge::BayesianRidge(BayesianRidge&& other): - centerData(other.centerData), - scaleData(other.scaleData), - nIterMax(other.nIterMax), - tol(other.tol), - dataOffset(std::move(other.dataOffset)), - dataScale(std::move(other.dataScale)), - responsesOffset(other.responsesOffset), - alpha(other.alpha), - beta(other.beta), - gamma(other.gamma), - omega(std::move(other.omega)), - matCovariance(std::move(other.matCovariance)) -{ - // Clear the other object. - if (this != &other) - { - other.centerData = false; - other.scaleData = false; - other.nIterMax = 0.0; - other.tol = 0.0; - other.dataOffset.reset(); - other.dataScale.reset(); - other.responsesOffset = 0.0; - other.alpha = 0.0; - other.gamma = 0.0; - other.beta = 0.0; - other.omega.reset(); - other.matCovariance.reset(); - } -} - -BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) -{ - if (this == &other) - return *this; - - centerData = other.centerData; - scaleData = other.scaleData; - nIterMax = other.nIterMax; - tol = other.tol; - dataOffset = other.dataOffset; - dataScale = other.dataScale; - responsesOffset = other.responsesOffset; - alpha = other.alpha; - gamma = other.gamma; - beta = other.beta; - omega = other.omega; - matCovariance = other.matCovariance; - return *this; -} - -BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) -{ - if (this != &other) - { - centerData = other.centerData; - scaleData = other.scaleData; - nIterMax = other.nIterMax; - tol = other.tol; - dataOffset = other.dataOffset; - dataScale = other.dataScale; - responsesOffset = other.responsesOffset; - alpha = other.alpha; - gamma = other.gamma; - beta = other.beta; - omega = other.omega; - matCovariance = other.matCovariance; - - // Clear the other object. - other.centerData = false; - other.scaleData = false; - other.nIterMax = 0.0; - other.tol = 0.0; - other.dataOffset.reset(); - other.dataScale.reset(); - other.responsesOffset = 0.0; - other.alpha = 0.0; - other.gamma = 0.0; - other.beta = 0.0; - other.omega.reset(); - other.matCovariance.reset(); - } - return *this; -} diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 4803ef8cc6..9120d5fde7 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -184,36 +184,6 @@ class BayesianRidge arma::colvec& dataOffset, arma::colvec& dataScale); - /** - * Copy constructor. Construct the BayesianRidge object by copying the - * given BayesianRidge object. - * - * @param other BayesianRidge to copy. - */ - BayesianRidge(const BayesianRidge& other); - - /** - * Move constructor. Construct the BayesianRidge object by taking ownership - * of the the given BayesianRidge object. - * - * @param other BayesianRidge to take the ownership. - */ - BayesianRidge(BayesianRidge&& other); - - /** - * Copy the given BayesianRidge object. - * - * @param other BayesianRidge object to copy. - */ - BayesianRidge& operator=(const BayesianRidge& other); - - /** - * Take ownership of the given BayesianRidge object. - * - * @param other BayesianRidge object to copy. - */ - BayesianRidge& operator=(BayesianRidge&& other); - /** * Get the solution vector * From e3b98f20b3ef35a099b22023be742752b1635a5f Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 27 Apr 2020 11:14:15 +0200 Subject: [PATCH 120/297] Modification of the main tests according to to the use of PARAL_MATRIX_IN etc... --- .../tests/main_tests/bayesian_ridge_test.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp index e4500812af..dfac7665e8 100644 --- a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp @@ -49,9 +49,9 @@ BOOST_FIXTURE_TEST_SUITE(BayesianRidgeMainTest, BRTestFixture); BOOST_AUTO_TEST_CASE(BRCenter0Scale0) { int n = 50, m = 4; - arma::mat X = arma::randu(n, m); - arma::colvec omega = arma::randu(m); - arma::mat y = X * omega; + arma::mat X = arma::randu(m, n); + arma::colvec omega = arma::randu(m); + arma::mat y = omega * X; SetInputParam("input", std::move(X)); SetInputParam("responses", std::move(y)); @@ -74,16 +74,16 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) { int n = 10, m = 4; - arma::mat X = arma::randu(n, m); - arma::mat Xtest = arma::randu(2 * n, m); - const arma::colvec omega = arma::randu(m); - arma::mat y = X * omega; + arma::mat X = arma::randu(m, n); + arma::mat Xtest = arma::randu(m, 2 * n); + const arma::colvec omega = arma::randu(m); + arma::mat y = omega * X; BayesianRidge model; - model.Train(X.t(), y.t()); + model.Train(X, y); arma::rowvec responses; - model.Predict(Xtest.t(), responses); + model.Predict(Xtest, responses); SetInputParam("input", std::move(X)); SetInputParam("responses", std::move(y)); @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) mlpackMain(); - arma::mat ytest = std::move(responses).t(); + arma::mat ytest = std::move(responses); // Check that initial output and output using saved model are same. CheckMatrices(ytest, CLI::GetParam("output_predictions")); } From f67969768ea8e45b41f4b5c9770bfae70c2b47ad Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Mon, 27 Apr 2020 11:15:06 +0200 Subject: [PATCH 121/297] Update src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp Co-Authored-By: Ryan Curtin --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index d19391c8ee..ccc58106b4 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -94,8 +94,8 @@ class BayesianRidge public: /** * Set the parameters of Bayesian Ridge regression object. The - * regulariation parameter is automaticaly set to its optimal value by - * maximmization of the marginal likelihood. + * regularization parameter is automatically set to its optimal value by + * maximization of the marginal likelihood. * * @param centerData Whether or not center the data according to the * examples. From 22694f9b917b6cefa5dd4d538a1c840a2b1bd95e Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 27 Apr 2020 11:54:49 +0200 Subject: [PATCH 122/297] Supress this->. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 4faefb13c6..0f6efdffc5 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -189,21 +189,21 @@ class BayesianRidge * * @return omega Solution vector. */ - const arma::colvec& Omega() const { return this->omega; } + const arma::colvec& Omega() const { return omega; } /** * Get the precesion (or inverse variance) beta of the model. * * @return \f$ \beta \f$ */ - double Beta() const { return this->beta; } + double Beta() const { return beta; } /** * Get the estimated variance. * * @return 1.0 / \f$ \beta \f$ */ - double Variance() const { return 1.0 / this->Beta(); } + double Variance() const { return 1.0 / Beta(); } /** * Get the mean vector computed on the features over the training points. @@ -211,7 +211,7 @@ class BayesianRidge * * @return responsesOffset */ - const arma::colvec& DataOffset() const { return this->dataOffset; } + const arma::colvec& DataOffset() const { return dataOffset; } /** * Get the vector of standard deviations computed on the features over the @@ -219,13 +219,13 @@ class BayesianRidge * * return dataOffset */ - const arma::colvec& DataScale() const { return this->dataScale; } + const arma::colvec& DataScale() const { return dataScale; } /** * Get the mean value of the train responses. * @return responsesOffset */ - double ResponsesOffset() const { return this->responsesOffset; } + double ResponsesOffset() const { return responsesOffset; } /** * Serialize the BayesianRidge model. From 6ba0f35b666f77afba3e6a838496a6cece0a5cb8 Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 30 Apr 2020 11:25:29 +0200 Subject: [PATCH 123/297] Fill the diag matrix with alpha before the inversion for the covariance matrix. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 23345ab3f2..8442cb6123 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -104,6 +104,7 @@ double BayesianRidge::Train(const arma::mat& data, i++; } // Compute the covariance matrice for the uncertaities later. + matA.diag().fill(alpha); matCovariance = inv_sympd(matA + phiphiT * beta); Timer::Stop("bayesian_ridge_regression"); From d05f1eb9d878e548a2698264a11bfd8488ceca5e Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 3 May 2020 13:58:35 +0200 Subject: [PATCH 124/297] Set the bolean in to false for ReportIgnoredParam(). --- src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp index 0dc7d39c9d..1d4f7fdc74 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp @@ -137,7 +137,7 @@ static void mlpackMain() "no results will be saved"); // Ignore out_predictions unless test is specified. - ReportIgnoredParam({{ "test", true }}, "output_predictions"); + ReportIgnoredParam({{ "test", false }}, "output_predictions"); BayesianRidge* bayesRidge; if (CLI::HasParam("input")) @@ -196,7 +196,6 @@ static void mlpackMain() // Save test predictions (one per line). CLI::GetParam("output_predictions") = std::move(predictions); - Log::Info << predictions << std::endl; } CLI::GetParam("output_model") = bayesRidge; From cfc3bd58129a56b9f0c782c7034dffd18cc21199 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 3 May 2020 16:47:19 +0200 Subject: [PATCH 125/297] Eigen decomposition for solving. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 8442cb6123..6c2a8f23ed 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -60,12 +60,13 @@ double BayesianRidge::Train(const arma::mat& data, << std::endl; throw std::runtime_error("eig_sym() failed."); } + const arma::mat eigvecInv = inv(eigvec); // Initialize the hyperparameters and // begin with an infinitely broad prior. alpha = 1e-6; beta = 1 / (var(t, 1) * 0.1); - + unsigned short i = 0; double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0; arma::mat matA = arma::eye(data.n_rows, data.n_rows); @@ -75,18 +76,15 @@ double BayesianRidge::Train(const arma::mat& data, deltaAlpha = -alpha; deltaBeta = -beta; - // Compute the posterior statistics. - // with inv() - // inv is used instead of solve because we need the covariance matrix to - // compute the prediction uncertainties. If solve is used, matCovariance - // must be comptuted at the end of the loop. - // matA.diag().fill(alpha); - // matCovariance = inv_sympd(matA + phiphiT * beta); - // omega = (matCovariance * vecphitT) * beta; + const double lambda = alpha / beta; + omega= 1 / (eigval + lambda); + omega *= lambda; + omega = (eigvec * diagmat(omega)) * eigvecInv * vecphitT; + omega /= lambda; // // with solve() - matA.diag().fill(alpha / beta); - omega = solve(matA + phiphiT, vecphitT); + // matA.diag().fill(alpha/beta); + // omega = solve(matA + phiphiT, vecphitT); // Update alpha. eigvali = eigval * beta; From 8ccb94c4cfc24ee267f9bd337fcac1f0bb25eb76 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 3 May 2020 17:04:47 +0200 Subject: [PATCH 126/297] Simplify the expressions and compute the covariance matrix with the eigen values and vectors. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 6c2a8f23ed..d2e66964e0 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -76,11 +76,8 @@ double BayesianRidge::Train(const arma::mat& data, deltaAlpha = -alpha; deltaBeta = -beta; - const double lambda = alpha / beta; - omega= 1 / (eigval + lambda); - omega *= lambda; + omega = 1 / (eigval + (alpha / beta)); omega = (eigvec * diagmat(omega)) * eigvecInv * vecphitT; - omega /= lambda; // // with solve() // matA.diag().fill(alpha/beta); @@ -102,8 +99,12 @@ double BayesianRidge::Train(const arma::mat& data, i++; } // Compute the covariance matrice for the uncertaities later. - matA.diag().fill(alpha); - matCovariance = inv_sympd(matA + phiphiT * beta); + matCovariance = eigvec * diagmat(1 / (beta * eigval + alpha)); + matCovariance *= eigvecInv; + + // with solve() + // matA.diag().fill(alpha); + // matCovariance = inv_sympd(matA + phiphiT * beta); Timer::Stop("bayesian_ridge_regression"); From 1ac3a82d77719a6eb44a61f3223c4764d1fe0a57 Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 3 May 2020 17:04:47 +0200 Subject: [PATCH 127/297] Simplify the expressions and compute the covariance matrix with the eigen values and vectors. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 6c2a8f23ed..199d6fc6e5 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -76,11 +76,8 @@ double BayesianRidge::Train(const arma::mat& data, deltaAlpha = -alpha; deltaBeta = -beta; - const double lambda = alpha / beta; - omega= 1 / (eigval + lambda); - omega *= lambda; + omega = 1 / (eigval + (alpha / beta)); omega = (eigvec * diagmat(omega)) * eigvecInv * vecphitT; - omega /= lambda; // // with solve() // matA.diag().fill(alpha/beta); @@ -102,8 +99,13 @@ double BayesianRidge::Train(const arma::mat& data, i++; } // Compute the covariance matrice for the uncertaities later. - matA.diag().fill(alpha); - matCovariance = inv_sympd(matA + phiphiT * beta); + matCovariance = eigvec; + matCovariance *= diagmat(1 / (beta * eigval + alpha)); + matCovariance *= eigvecInv; + + // with solve() + // matA.diag().fill(alpha); + // matCovariance = inv_sympd(matA + phiphiT * beta); Timer::Stop("bayesian_ridge_regression"); From 28fcb092f880384d5c92714a2140211c2c8c544d Mon Sep 17 00:00:00 2001 From: cmercier Date: Sun, 3 May 2020 17:18:12 +0200 Subject: [PATCH 128/297] Formatting. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 89f863117b..199d6fc6e5 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -99,12 +99,8 @@ double BayesianRidge::Train(const arma::mat& data, i++; } // Compute the covariance matrice for the uncertaities later. -<<<<<<< HEAD matCovariance = eigvec; matCovariance *= diagmat(1 / (beta * eigval + alpha)); -======= - matCovariance = eigvec * diagmat(1 / (beta * eigval + alpha)); ->>>>>>> 8ccb94c4cfc24ee267f9bd337fcac1f0bb25eb76 matCovariance *= eigvecInv; // with solve() From 9ab61b7d7f98a30af10b2ecdd5cc8086ff9c4911 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 4 May 2020 11:49:41 +0200 Subject: [PATCH 129/297] Comptute Vinv * phi * t once for all. Use std::move() for matCovariance. --- .../methods/bayesian_ridge/bayesian_ridge.cpp | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index 199d6fc6e5..a483777438 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -34,8 +34,7 @@ double BayesianRidge::Train(const arma::mat& data, arma::mat phi; arma::rowvec t; arma::colvec eigval; - arma::mat eigvec; - arma::colvec eigvali; + arma::mat V; // Preprocess the data. Center and scale. responsesOffset = CenterScaleData(data, @@ -47,45 +46,37 @@ double BayesianRidge::Train(const arma::mat& data, dataOffset, dataScale); - // Compute this quantities once and for all. - const arma::colvec vecphitT = phi * t.t(); - - // Enforce symmetry of the covariance matrix before eig_sym. - const arma::mat phiphiT = arma::symmatu(phi * phi.t()); - - if (arma::eig_sym(eigval, eigvec, phiphiT) == false) + if (arma::eig_sym(eigval, V, arma::symmatu(phi * phi.t())) == false) { Log::Warn << "BayesianRidge::Train(): Eigendecomposition " << "of covariance failed!" << std::endl; throw std::runtime_error("eig_sym() failed."); } - const arma::mat eigvecInv = inv(eigvec); + + // Compute this quantiies once and for all. + const arma::mat Vinv = inv(V); + const arma::colvec VinvPhitT = Vinv * phi * t.t(); // Initialize the hyperparameters and // begin with an infinitely broad prior. alpha = 1e-6; beta = 1 / (var(t, 1) * 0.1); - + unsigned short i = 0; double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0; - arma::mat matA = arma::eye(data.n_rows, data.n_rows); while ((crit > tol) && (i < nIterMax)) { deltaAlpha = -alpha; deltaBeta = -beta; + // Update the solution. omega = 1 / (eigval + (alpha / beta)); - omega = (eigvec * diagmat(omega)) * eigvecInv * vecphitT; - - // // with solve() - // matA.diag().fill(alpha/beta); - // omega = solve(matA + phiphiT, vecphitT); + omega = V * diagmat(omega) * VinvPhitT; // Update alpha. - eigvali = eigval * beta; - gamma = sum(eigvali / (alpha + eigvali)); + gamma = sum(eigval / (alpha / beta + eigval)); alpha = gamma / dot(omega, omega); // Update beta. @@ -99,13 +90,9 @@ double BayesianRidge::Train(const arma::mat& data, i++; } // Compute the covariance matrice for the uncertaities later. - matCovariance = eigvec; + matCovariance = std::move(V); matCovariance *= diagmat(1 / (beta * eigval + alpha)); - matCovariance *= eigvecInv; - - // with solve() - // matA.diag().fill(alpha); - // matCovariance = inv_sympd(matA + phiphiT * beta); + matCovariance *= Vinv; Timer::Stop("bayesian_ridge_regression"); From aaf98a5f72d52504ab780a445736522e9da7d521 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 4 May 2020 11:52:09 +0200 Subject: [PATCH 130/297] Add comment and correct typo. --- src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp index a483777438..145f7a0855 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp @@ -54,7 +54,7 @@ double BayesianRidge::Train(const arma::mat& data, throw std::runtime_error("eig_sym() failed."); } - // Compute this quantiies once and for all. + // Compute this quantities once and for all. const arma::mat Vinv = inv(V); const arma::colvec VinvPhitT = Vinv * phi * t.t(); From 8398e3c6c93bc8a599114870e802b9424b4c278c Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 4 May 2020 17:27:33 +0200 Subject: [PATCH 131/297] Test that the solution after optimization is equal than for a classical ridge set with the corresponding regularization, lambda = alpha / beta. --- .../methods/bayesian_ridge/bayesian_ridge.hpp | 7 +++++++ src/mlpack/tests/bayesian_ridge_test.cpp | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp index 0f6efdffc5..b2faa12fdd 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp @@ -191,6 +191,13 @@ class BayesianRidge */ const arma::colvec& Omega() const { return omega; } + /** + * Get the precision (or inverse variance) of the gaussian prior. + * + * @return \f$ \alpha \f$ + */ + double Alpha() const { return alpha; } + /** * Get the precesion (or inverse variance) beta of the model. * diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_ridge_test.cpp index 9143ee2c70..dbad414b73 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_ridge_test.cpp @@ -12,6 +12,7 @@ #include #include +#include #include @@ -132,4 +133,23 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) BOOST_REQUIRE(std[i] > estStd); } +// Check the solution is equal to the classical ridge. +BOOST_AUTO_TEST_CASE(EqualtoRidge) +{ + arma::mat X; + arma::rowvec y; + + GenerateProblem(X, y, 100, 10, 1); + + BayesianRidge bayesRidge(false, false); + bayesRidge.Train(X, y); + + LinearRegression classicalRidge(X, + y, + bayesRidge.Alpha() / bayesRidge.Beta(), + false); + double equalSol = arma::sum(bayesRidge.Omega() - classicalRidge.Parameters()); + BOOST_REQUIRE(equalSol < 1e-5); +} + BOOST_AUTO_TEST_SUITE_END(); From 77a687dcf66565d40a0f62bd01c5c4ba1d868409 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 7 May 2020 23:08:37 +0530 Subject: [PATCH 132/297] adding constructors and other class methods --- src/mlpack/methods/ann/layer/embedding.hpp | 207 ++++++++++++++++++ .../methods/ann/layer/embedding_impl.hpp | 123 +++++++++++ 2 files changed, 330 insertions(+) create mode 100644 src/mlpack/methods/ann/layer/embedding.hpp create mode 100644 src/mlpack/methods/ann/layer/embedding_impl.hpp diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp new file mode 100644 index 0000000000..b60d252999 --- /dev/null +++ b/src/mlpack/methods/ann/layer/embedding.hpp @@ -0,0 +1,207 @@ +/** + * @file embedding.hpp + * @author Mrityunjay Tripathi + * + * Definition of the Embedding 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_EMBEDDING_HPP +#define MLPACK_METHODS_ANN_LAYER_EMBEDDING_HPP + +#include +#include +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Description. + * + * @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, + typename InitializerType = RandomInitialization, + typename RegularizerType = NoRegularizer +> +class Embedding +{ + public: + /** + * Create the Embedding object. + */ + Embedding(); + + /** + * Create the Embedding layer object using specified parameters. + * + * @param dictionarySize The size of the dictionary i.e number of distinct + * words in the document. + * @param embeddingDim The size of each embedding vector. + * @param paddingIndex Whenever it encounters `paddingIndex`, it pads the + * output with embedding vector with zeros. + * @param initializer The initialization rule for embedding matrix. + * @param regularizer The regularization rule for embedding matrix. + * @param activationRegularizer The regularization rule for the output of + * embedding layer i.e. activation of embedding layer. + */ + Embedding(const size_t dictionarySize, + const size_t embeddingDim, + const int paddingIndex = NULL, + const InitializerType initializer = RandomInitialization, + const RegularizerType regularizer = RegularizerType(), + const RegularizerType activationRegularizer = RegularizerType()); + + /** + * Reset the layer parameters. + */ + void ResetParameters(); + + /** + * Load pretrained weights for embedding layer. + * + * @param weights The pre-trained weight matrix. + * @param deterministic Whether to calculate gradients of embedding layer. + * @param paddingIndex + */ + template + void LoadPretrained(const MatType weights, + const bool deterministic = true, + const int paddingIndex = NULL); + + /** + * 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 trough 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); + + /* + * Calculate the gradient using the output delta and the input activation. + * + * @param input The input parameter used for calculating the gradient. + * @param error The calculated error. + * @param gradient The calculated gradient. + */ + template + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); + + //! Get the value of dictionarySize. + OutputDataType& DictionarySize() const { return dictionarySize; } + //! Modify the dictionarySize. + OutputDataType& DictionarySize() { return dictionarySize; } + + //! Get the value of embeddingDim. + OutputDataType& EmbeddingDim() const { return embeddingDim; } + //! Modify the embeddingDim. + OutputDataType& EmbeddingDim() { return embeddingDim; } + + //! Get the value of paddingIndex. + OutputDataType& PaddingIndex() const { return paddingIndex; } + //! Modify the paddingIndex. + OutputDataType& PaddingIndex() { return paddingIndex; } + + //! Get the value of deterministic. + OutputDataType& Deterministic() const { return deterministic; } + //! Modify the deterministic. + OutputDataType& Deterministic() { return deterministic; } + + //! Get the parameters. + OutputDataType& Parameters() const { return weights; } + //! Modify the parameters. + OutputDataType& Parameters() { return weights; } + + //! Get the iutput parameter. + OutputDataType& InputParameter() const { return inputParameter; } + //! Modify the iutput parameter. + OutputDataType& InputParameter() { return inputParameter; } + + //! 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 size of the vocabulary. + size_t dictionarySize; + + //! Locally-stored size of each embedding vector. + size_t embeddingDim; + + //! Locally-stored value of padding index. + int paddingIndex; + + //! + bool deterministic; + + //! Locally-stored initialization rule. + InitializerType initializer; + + //! Locally-stored regularizer type. + RegularizerType regularizer; + + //! Locally-stored regularizer type for the output of embedding layer. + RegularizerType activationRegularizer; + + //! Locally-stored weight object. + OutputDataType weights; + + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored gradient object + OutputDataType gradient; + + //! Locally-stored input parameter object. + InputDataType inputParameter; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; +}; // class Embedding + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "embedding_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp new file mode 100644 index 0000000000..4952fa18b1 --- /dev/null +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -0,0 +1,123 @@ +/** + * @file embedding_impl.hpp + * @author Mrityunjay Tripathi + * + * Implementation of the Embedding 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_EMBEDDING_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_EMBEDDING_IMPL_HPP + +// In case it hasn't yet been included. +#include "embedding.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +Embedding +::Embedding() +{ + // Nothing to do here. +} + +template +Embedding +::Embedding(const size_t dictionarySize, + const size_t embeddingDim, + const int paddingIndex, + const InitializerType initializer, + const RegularizerType regularizer, + const RegularizerType activationRegularizer : + dictionarySize(dictionarySize), + embeddingDim(embeddingDim), + initializer(initializer), + regularizer(regularizer), + activationRegularizer(activationRegularizer) +{ + typedef typename InputDataType::elem_type ElemType; + if (paddingIndex) + { + if (paddingIndex > 0) + Log::Assert(paddingIndex < this->embeddingDim, + 'paddingIndex must be less than embeddingDim'); + else + { + Log::Assert(paddingIndex >= - this->embeddingDim, + 'paddingIndex must be less than embeddingDim'); + paddingIndex += this->embeddingDim; + } + } + this->paddingIndex = paddingIndex; + this->weights.set_size(dictionarySize, embeddingDim); + ResetParameters(); +} + +template +void Embedding +::ResetParameters() +{ + typedef typename InputDataType::elem_type ElemType; + InitializerType::Initialize(weights, weights.n_rows, weights.n_cols); + if (paddingIndex) + { + weights[paddingIndex] = arma::zeros>(weights.n_cols); + } +} + +template +template +void Embedding +::LoadPretrained(const MatType weights, + const bool deterministic = false, + const int paddingIndex = NULL) +{ + this->dictionarySize = weights.n_rows; + this->embeddingDim = weights.n_cols; + this->weights = weights; + this->deterministic = deterministic; + this->paddingIndex = paddingIndex; +} + +template +template +void Embedding +::Forward(const InputType& input, OutputType& output) +{ + +} + +template +template +void Embedding +::Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) +{ + +} + +template +template +void Embedding::serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here. +} + +} // namespace ann +} // namespace mlpack + +#endif From 00c163fdb97a7951888313201a71aef27c804284 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 8 May 2020 06:43:28 +0530 Subject: [PATCH 133/297] updated forward and backward function --- .../methods/ann/layer/embedding_impl.hpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp index 4952fa18b1..bb416f5c59 100644 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -93,7 +93,11 @@ template void Embedding ::Forward(const InputType& input, OutputType& output) { - + output.set_size(input.n_cols * embeddingDim, input.n_rows); + for (size_t i = 0; i < input.n_rows; ++i) + { + output.col(i) = arma::vectorise(weights.elem(input[i])); + } } template const arma::Mat& gy, arma::Mat& g) { - + g = gy % input; } template template -void Embedding::serialize( - Archive& /* ar */, - const unsigned int /* version */) +void Embedding +::serialize(Archive& /* ar */, const unsigned int /* version */) { - // Nothing to do here. + ar & BOOST_SERIALIZATION_NVP(dictionarySize); + ar & BOOST_SERIALIZATION_NVP(embeddingDim); + ar & BOOST_SERIALIZATION_NVP(paddingIndex); + ar & BOOST_SERIALIZATION_NVP(deterministic); } } // namespace ann From a139152b91b5653304abdb2f0d1300cf5cfb0c8c Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 8 May 2020 08:58:24 +0530 Subject: [PATCH 134/297] added to CMakeLists.txt and updated description --- src/mlpack/methods/ann/layer/CMakeLists.txt | 2 ++ src/mlpack/methods/ann/layer/embedding.hpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index 78b77b2a09..41ad5feaed 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -34,6 +34,8 @@ set(SOURCES dropout_impl.hpp elu.hpp elu_impl.hpp + embedding.hpp + embedding_impl.hpp fast_lstm.hpp fast_lstm_impl.hpp flexible_relu.hpp diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp index b60d252999..d071320ee7 100644 --- a/src/mlpack/methods/ann/layer/embedding.hpp +++ b/src/mlpack/methods/ann/layer/embedding.hpp @@ -20,7 +20,10 @@ namespace mlpack { namespace ann /** Artificial Neural Network. */ { /** - * Description. + * Word Embeddings, a featurized word-level representation capable of capturing + * the semantic meanings of words. It stores embeddings of a dictionary and can + * be retreived using their indices. It can only be used as first layer in an + * artificial neural network. * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). From fc2b3e3743c20d977321b0f4940d60904af5a502 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 8 May 2020 19:01:58 +0530 Subject: [PATCH 135/297] updated gradient function and corrected backward function --- .../methods/ann/layer/embedding_impl.hpp | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp index bb416f5c59..5ebb8e322a 100644 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -77,13 +77,25 @@ template void Embedding ::LoadPretrained(const MatType weights, - const bool deterministic = false, - const int paddingIndex = NULL) + const bool deterministic, + const int paddingIndex) { this->dictionarySize = weights.n_rows; this->embeddingDim = weights.n_cols; this->weights = weights; this->deterministic = deterministic; + if (paddingIndex) + { + if (paddingIndex > 0) + Log::Assert(paddingIndex < this->embeddingDim, + 'paddingIndex must be less than embeddingDim'); + else + { + Log::Assert(paddingIndex >= - this->embeddingDim, + 'paddingIndex must be less than embeddingDim'); + paddingIndex += this->embeddingDim; + } + } this->paddingIndex = paddingIndex; } @@ -108,7 +120,19 @@ void Embedding const arma::Mat& gy, arma::Mat& g) { - g = gy % input; + g = gy; +} + +template +template +void Embedding +::Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) +{ + gradient = arma::zeros>(weights.n_rows, weights.n_cols); + gradient.cols(input) = error; } template Date: Fri, 8 May 2020 19:51:19 +0530 Subject: [PATCH 136/297] added parameter 'freeze' and other slight changes --- src/mlpack/methods/ann/layer/embedding.hpp | 37 +++------------- .../methods/ann/layer/embedding_impl.hpp | 42 ++++--------------- 2 files changed, 13 insertions(+), 66 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp index d071320ee7..653269e63e 100644 --- a/src/mlpack/methods/ann/layer/embedding.hpp +++ b/src/mlpack/methods/ann/layer/embedding.hpp @@ -52,35 +52,21 @@ class Embedding * @param embeddingDim The size of each embedding vector. * @param paddingIndex Whenever it encounters `paddingIndex`, it pads the * output with embedding vector with zeros. + * @param freeze Specifies whether to update weight matrix after each forward + * pass. * @param initializer The initialization rule for embedding matrix. - * @param regularizer The regularization rule for embedding matrix. - * @param activationRegularizer The regularization rule for the output of - * embedding layer i.e. activation of embedding layer. */ Embedding(const size_t dictionarySize, const size_t embeddingDim, const int paddingIndex = NULL, - const InitializerType initializer = RandomInitialization, - const RegularizerType regularizer = RegularizerType(), - const RegularizerType activationRegularizer = RegularizerType()); + const bool freeze = false, + const InitializerType initializer = RandomInitialization); /** * Reset the layer parameters. */ void ResetParameters(); - /** - * Load pretrained weights for embedding layer. - * - * @param weights The pre-trained weight matrix. - * @param deterministic Whether to calculate gradients of embedding layer. - * @param paddingIndex - */ - template - void LoadPretrained(const MatType weights, - const bool deterministic = true, - const int paddingIndex = NULL); - /** * Ordinary feed forward pass of a neural network, evaluating the function * f(x) by propagating the activity forward through f. @@ -132,11 +118,6 @@ class Embedding //! Modify the paddingIndex. OutputDataType& PaddingIndex() { return paddingIndex; } - //! Get the value of deterministic. - OutputDataType& Deterministic() const { return deterministic; } - //! Modify the deterministic. - OutputDataType& Deterministic() { return deterministic; } - //! Get the parameters. OutputDataType& Parameters() const { return weights; } //! Modify the parameters. @@ -173,18 +154,12 @@ class Embedding //! Locally-stored value of padding index. int paddingIndex; - //! - bool deterministic; + //! Specifies whether to update weight matrix after each forward pass. + bool freeze; //! Locally-stored initialization rule. InitializerType initializer; - //! Locally-stored regularizer type. - RegularizerType regularizer; - - //! Locally-stored regularizer type for the output of embedding layer. - RegularizerType activationRegularizer; - //! Locally-stored weight object. OutputDataType weights; diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp index 5ebb8e322a..d47a65011e 100644 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -32,14 +32,12 @@ Embedding ::Embedding(const size_t dictionarySize, const size_t embeddingDim, const int paddingIndex, - const InitializerType initializer, - const RegularizerType regularizer, - const RegularizerType activationRegularizer : + const bool freeze, + const InitializerType initializer) : dictionarySize(dictionarySize), embeddingDim(embeddingDim), - initializer(initializer), - regularizer(regularizer), - activationRegularizer(activationRegularizer) + freeze(freeze), + initializer(initializer) { typedef typename InputDataType::elem_type ElemType; if (paddingIndex) @@ -72,33 +70,6 @@ void Embedding } } -template -template -void Embedding -::LoadPretrained(const MatType weights, - const bool deterministic, - const int paddingIndex) -{ - this->dictionarySize = weights.n_rows; - this->embeddingDim = weights.n_cols; - this->weights = weights; - this->deterministic = deterministic; - if (paddingIndex) - { - if (paddingIndex > 0) - Log::Assert(paddingIndex < this->embeddingDim, - 'paddingIndex must be less than embeddingDim'); - else - { - Log::Assert(paddingIndex >= - this->embeddingDim, - 'paddingIndex must be less than embeddingDim'); - paddingIndex += this->embeddingDim; - } - } - this->paddingIndex = paddingIndex; -} - template template @@ -132,7 +103,8 @@ void Embedding arma::Mat& gradient) { gradient = arma::zeros>(weights.n_rows, weights.n_cols); - gradient.cols(input) = error; + if (!freeze) + gradient.cols(input) = error; } template ar & BOOST_SERIALIZATION_NVP(dictionarySize); ar & BOOST_SERIALIZATION_NVP(embeddingDim); ar & BOOST_SERIALIZATION_NVP(paddingIndex); - ar & BOOST_SERIALIZATION_NVP(deterministic); + ar & BOOST_SERIALIZATION_NVP(freeze); } } // namespace ann From 21ba87aa06d35653d977520dc5dc630164bbebed Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 8 May 2020 19:54:37 +0530 Subject: [PATCH 137/297] corrections --- src/mlpack/methods/ann/layer/embedding.hpp | 3 +- .../methods/ann/layer/embedding_impl.hpp | 28 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp index 653269e63e..b47ff94fd8 100644 --- a/src/mlpack/methods/ann/layer/embedding.hpp +++ b/src/mlpack/methods/ann/layer/embedding.hpp @@ -33,8 +33,7 @@ namespace ann /** Artificial Neural Network. */ { template < typename InputDataType = arma::mat, typename OutputDataType = arma::mat, - typename InitializerType = RandomInitialization, - typename RegularizerType = NoRegularizer + typename InitializerType = RandomInitialization > class Embedding { diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp index d47a65011e..b756cefb04 100644 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -19,16 +19,16 @@ namespace mlpack { namespace ann /** Artificial Neural Network. */ { template -Embedding + typename InitializerType> +Embedding ::Embedding() { // Nothing to do here. } template -Embedding + typename InitializerType> +Embedding ::Embedding(const size_t dictionarySize, const size_t embeddingDim, const int paddingIndex, @@ -58,8 +58,8 @@ Embedding } template -void Embedding + typename InitializerType> +void Embedding ::ResetParameters() { typedef typename InputDataType::elem_type ElemType; @@ -71,9 +71,9 @@ void Embedding } template + typename InitializerType> template -void Embedding +void Embedding ::Forward(const InputType& input, OutputType& output) { output.set_size(input.n_cols * embeddingDim, input.n_rows); @@ -84,9 +84,9 @@ void Embedding } template + typename InitializerType> template -void Embedding +void Embedding ::Backward(const arma::Mat& input, const arma::Mat& gy, arma::Mat& g) @@ -95,9 +95,9 @@ void Embedding } template + typename InitializerType> template -void Embedding +void Embedding ::Gradient(const arma::Mat& input, const arma::Mat& error, arma::Mat& gradient) @@ -108,9 +108,9 @@ void Embedding } template + typename InitializerType> template -void Embedding +void Embedding ::serialize(Archive& /* ar */, const unsigned int /* version */) { ar & BOOST_SERIALIZATION_NVP(dictionarySize); From b417b33d1e87953d521241e3f9e6f7f62c952fa7 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sun, 10 May 2020 12:40:41 +0530 Subject: [PATCH 138/297] fixed error in constructor and fixed initialization --- src/mlpack/methods/ann/layer/embedding.hpp | 15 ++++------- .../methods/ann/layer/embedding_impl.hpp | 25 +++++++++++-------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp index b47ff94fd8..fd245d7ceb 100644 --- a/src/mlpack/methods/ann/layer/embedding.hpp +++ b/src/mlpack/methods/ann/layer/embedding.hpp @@ -51,15 +51,13 @@ class Embedding * @param embeddingDim The size of each embedding vector. * @param paddingIndex Whenever it encounters `paddingIndex`, it pads the * output with embedding vector with zeros. - * @param freeze Specifies whether to update weight matrix after each forward - * pass. - * @param initializer The initialization rule for embedding matrix. + * @param freeze Specifies whether to update weight matrix of embedding layer + * after each forward pass. */ Embedding(const size_t dictionarySize, const size_t embeddingDim, const int paddingIndex = NULL, - const bool freeze = false, - const InitializerType initializer = RandomInitialization); + const bool freeze = false); /** * Reset the layer parameters. @@ -86,7 +84,7 @@ class Embedding * @param g The calculated gradient. */ template - void Backward(const arma::Mat& input, + void Backward(const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g); @@ -141,7 +139,7 @@ class Embedding * Serialize the layer. */ template - void serialize(Archive& /* ar */, const unsigned int /* version */); + void serialize(Archive& ar, const unsigned int /* version */); private: //! Locally-stored size of the vocabulary. @@ -156,9 +154,6 @@ class Embedding //! Specifies whether to update weight matrix after each forward pass. bool freeze; - //! Locally-stored initialization rule. - InitializerType initializer; - //! Locally-stored weight object. OutputDataType weights; diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp index b756cefb04..12a4bf77fa 100644 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -32,27 +32,29 @@ Embedding ::Embedding(const size_t dictionarySize, const size_t embeddingDim, const int paddingIndex, - const bool freeze, - const InitializerType initializer) : + const bool freeze) : dictionarySize(dictionarySize), embeddingDim(embeddingDim), - freeze(freeze), - initializer(initializer) + freeze(freeze) { typedef typename InputDataType::elem_type ElemType; if (paddingIndex) { if (paddingIndex > 0) + { Log::Assert(paddingIndex < this->embeddingDim, - 'paddingIndex must be less than embeddingDim'); + "paddingIndex must be less than embeddingDim"); + this->paddingIndex = paddingIndex; + } else { Log::Assert(paddingIndex >= - this->embeddingDim, - 'paddingIndex must be less than embeddingDim'); - paddingIndex += this->embeddingDim; + "paddingIndex must be less than embeddingDim"); + this->paddingIndex = paddingIndex + this->embeddingDim; } } - this->paddingIndex = paddingIndex; + else + this->paddingIndex = paddingIndex; this->weights.set_size(dictionarySize, embeddingDim); ResetParameters(); } @@ -63,7 +65,8 @@ void Embedding ::ResetParameters() { typedef typename InputDataType::elem_type ElemType; - InitializerType::Initialize(weights, weights.n_rows, weights.n_cols); + InitializerType init; + init.Initialize(weights, weights.n_rows, weights.n_cols); if (paddingIndex) { weights[paddingIndex] = arma::zeros>(weights.n_cols); @@ -87,7 +90,7 @@ template template void Embedding -::Backward(const arma::Mat& input, +::Backward(const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { @@ -111,7 +114,7 @@ template template void Embedding -::serialize(Archive& /* ar */, const unsigned int /* version */) +::serialize(Archive& ar, const unsigned int /* version */) { ar & BOOST_SERIALIZATION_NVP(dictionarySize); ar & BOOST_SERIALIZATION_NVP(embeddingDim); From 2d39baccde6a61fb564ab5d3251234ada60d1df7 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sun, 10 May 2020 13:55:06 +0530 Subject: [PATCH 139/297] slight corrections --- src/mlpack/methods/ann/layer/embedding_impl.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp index 12a4bf77fa..dfcd95118a 100644 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ b/src/mlpack/methods/ann/layer/embedding_impl.hpp @@ -69,7 +69,7 @@ void Embedding init.Initialize(weights, weights.n_rows, weights.n_cols); if (paddingIndex) { - weights[paddingIndex] = arma::zeros>(weights.n_cols); + weights.row(paddingIndex) = arma::zeros>(weights.n_cols); } } @@ -82,7 +82,8 @@ void Embedding output.set_size(input.n_cols * embeddingDim, input.n_rows); for (size_t i = 0; i < input.n_rows; ++i) { - output.col(i) = arma::vectorise(weights.elem(input[i])); + output.col(i) = arma::vectorise(weights.rows( + arma::conv_to::from(input.row(i)))); } } From c06df7f77b232e7b5bec225455ed548eac816972 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 11 May 2020 15:12:31 +0530 Subject: [PATCH 140/297] correction --- src/mlpack/methods/ann/layer/embedding.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp index fd245d7ceb..0fa141f09f 100644 --- a/src/mlpack/methods/ann/layer/embedding.hpp +++ b/src/mlpack/methods/ann/layer/embedding.hpp @@ -120,9 +120,9 @@ class Embedding //! Modify the parameters. OutputDataType& Parameters() { return weights; } - //! Get the iutput parameter. + //! Get the input parameter. OutputDataType& InputParameter() const { return inputParameter; } - //! Modify the iutput parameter. + //! Modify the input parameter. OutputDataType& InputParameter() { return inputParameter; } //! Get the output parameter. From 072a6ede305af76ace3b0fe07237d9c16c733114 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 12 May 2020 08:35:08 +0200 Subject: [PATCH 141/297] Change BayesianRidge for BayesiabLinearRegression. --- src/mlpack/methods/CMakeLists.txt | 2 +- .../bayesian_linear_regression/CMakeLists.txt | 19 ++ .../CMakeLists.txt~} | 6 +- .../bayesian_linear_regression.cpp} | 54 ++-- .../bayesian_linear_regression.cpp~ | 262 ++++++++++++++++++ .../bayesian_linear_regression.hpp} | 18 +- .../bayesian_linear_regression_impl.hpp} | 15 +- .../bayesian_linear_regression_main.cpp | 205 ++++++++++++++ .../bayesian_linear_regression_main.cpp~} | 2 +- src/mlpack/tests/CMakeLists.txt | 4 +- ...pp => bayesian_linear_regression_test.cpp} | 32 +-- ...pp => bayesian_linear_regression_test.cpp} | 16 +- 12 files changed, 561 insertions(+), 74 deletions(-) create mode 100644 src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt rename src/mlpack/methods/{bayesian_ridge/CMakeLists.txt => bayesian_linear_regression/CMakeLists.txt~} (84%) rename src/mlpack/methods/{bayesian_ridge/bayesian_ridge.cpp => bayesian_linear_regression/bayesian_linear_regression.cpp} (68%) create mode 100644 src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ rename src/mlpack/methods/{bayesian_ridge/bayesian_ridge.hpp => bayesian_linear_regression/bayesian_linear_regression.hpp} (94%) rename src/mlpack/methods/{bayesian_ridge/bayesian_ridge_impl.hpp => bayesian_linear_regression/bayesian_linear_regression_impl.hpp} (68%) create mode 100644 src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp rename src/mlpack/methods/{bayesian_ridge/bayesian_ridge_main.cpp => bayesian_linear_regression/bayesian_linear_regression_main.cpp~} (99%) rename src/mlpack/tests/{bayesian_ridge_test.cpp => bayesian_linear_regression_test.cpp} (81%) rename src/mlpack/tests/main_tests/{bayesian_ridge_test.cpp => bayesian_linear_regression_test.cpp} (80%) diff --git a/src/mlpack/methods/CMakeLists.txt b/src/mlpack/methods/CMakeLists.txt index 21822cafb8..d548d9c769 100644 --- a/src/mlpack/methods/CMakeLists.txt +++ b/src/mlpack/methods/CMakeLists.txt @@ -6,7 +6,7 @@ set(DIRS ann approx_kfn bias_svd - bayesian_ridge + bayesian_linear_regression block_krylov_svd cf dbscan diff --git a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt new file mode 100644 index 0000000000..9b03b83136 --- /dev/null +++ b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt @@ -0,0 +1,19 @@ +# Define the files we need to compile +# Anything not in this list will not be compiled into the output library +set(SOURCES + bayesian_linear_regression.hpp + bayesian_linear_regression_impl.hpp + bayesian_linear_regression.cpp +) + +# add directory name to sources +set(DIR_SRCS) +foreach(file ${SOURCES}) + set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) +endforeach() +# append sources (with directory name) to list of all mlpack sources (used at the parent scope) +set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) + +add_cli_executable(bayesian_linear_regression) +add_python_binding(bayesian_linear_regression) +add_markdown_docs(bayesian_linear_regression "cli;python" "regression") diff --git a/src/mlpack/methods/bayesian_ridge/CMakeLists.txt b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ similarity index 84% rename from src/mlpack/methods/bayesian_ridge/CMakeLists.txt rename to src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ index 2f5eafb167..6145de27a9 100644 --- a/src/mlpack/methods/bayesian_ridge/CMakeLists.txt +++ b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ @@ -1,9 +1,9 @@ # Define the files we need to compile # Anything not in this list will not be compiled into the output library set(SOURCES - bayesian_ridge.hpp - bayesian_ridge_impl.hpp - bayesian_ridge.cpp + bayesian_linear_regression.hpp + bayesian_linear_regression_impl.hpp + bayesian_linear_regression.cpp ) # add directory name to sources diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp similarity index 68% rename from src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp rename to src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 145f7a0855..254f9c1fff 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -1,35 +1,35 @@ /** - * @file bayesian_ridge.cpp + * @file bayesian_linear_regression.cpp * @author Clement Mercier * - * Implementation of Bayesian Ridge regression. + * Implementation of Bayesian linear regression. * * mlpack is free software; you may redistribute it and/or modify it under the * terms of the 3-clause BSD license. You should have received a copy of the * 3-clause BSD license along with mlpack. If not, see * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ -#include "bayesian_ridge.hpp" +#include "bayesian_linear_regression.hpp" #include #include using namespace mlpack; using namespace mlpack::regression; -BayesianRidge::BayesianRidge(const bool centerData, - const bool scaleData, - const int nIterMax, - const double tol) : +BayesianLinearRegression::BayesianLinearRegression(const bool centerData, + const bool scaleData, + const int nIterMax, + const double tol) : centerData(centerData), scaleData(scaleData), nIterMax(nIterMax), tol(tol) {/* Nothing to do */} -double BayesianRidge::Train(const arma::mat& data, - const arma::rowvec& responses) +double BayesianLinearRegression::Train(const arma::mat& data, + const arma::rowvec& responses) { - Timer::Start("bayesian_ridge_regression"); + Timer::Start("bayesian_linear_regression"); arma::mat phi; arma::rowvec t; @@ -48,7 +48,7 @@ double BayesianRidge::Train(const arma::mat& data, if (arma::eig_sym(eigval, V, arma::symmatu(phi * phi.t())) == false) { - Log::Warn << "BayesianRidge::Train(): Eigendecomposition " + Log::Warn << "BayesianLinearRegression::Train(): Eigendecomposition " << "of covariance failed!" << std::endl; throw std::runtime_error("eig_sym() failed."); @@ -94,13 +94,13 @@ double BayesianRidge::Train(const arma::mat& data, matCovariance *= diagmat(1 / (beta * eigval + alpha)); matCovariance *= Vinv; - Timer::Stop("bayesian_ridge_regression"); + Timer::Stop("bayesian_linear_regression"); return RMSE(data, responses); } -void BayesianRidge::Predict(const arma::mat& points, - arma::rowvec& predictions) const +void BayesianLinearRegression::Predict(const arma::mat& points, + arma::rowvec& predictions) const { // y_hat = w^T * (X - mu) / sigma + y_mean. predictions = omega.t() * ((points.each_col() - dataOffset).each_col() @@ -108,9 +108,9 @@ void BayesianRidge::Predict(const arma::mat& points, predictions += responsesOffset; } -void BayesianRidge::Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const +void BayesianLinearRegression::Predict(const arma::mat& points, + arma::rowvec& predictions, + arma::rowvec& std) const { // Center and scaleData the points before applying the model. const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; @@ -119,22 +119,22 @@ void BayesianRidge::Predict(const arma::mat& points, std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); } -double BayesianRidge::RMSE(const arma::mat& data, - const arma::rowvec& responses) const +double BayesianLinearRegression::RMSE(const arma::mat& data, + const arma::rowvec& responses) const { arma::rowvec predictions; Predict(data, predictions); return sqrt(mean(square(responses - predictions))); } -double BayesianRidge::CenterScaleData(const arma::mat& data, - const arma::rowvec& responses, - bool centerData, - bool scaleData, - arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale) +double BayesianLinearRegression::CenterScaleData(const arma::mat& data, + const arma::rowvec& responses, + bool centerData, + bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale) { // Initialize the offsets to their neutral forms. dataOffset = arma::zeros(data.n_rows); diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ new file mode 100644 index 0000000000..1c15c588fb --- /dev/null +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ @@ -0,0 +1,262 @@ +/** + * @file bayesian_ridge.cpp + * @author Clement Mercier + * + * Implementation of Bayesian Ridge regression. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#include "bayesian_ridge.hpp" +#include +#include + +using namespace mlpack; +using namespace mlpack::regression; + + +BayesianRidge::BayesianRidge(const bool centerData, + const bool scaleData, + const int nIterMax, + const double tol) : + centerData(centerData), + scaleData(scaleData), + nIterMax(nIterMax), + tol(tol) +{/* Nothing to do */} + +double BayesianRidge::Train(const arma::mat& data, + const arma::rowvec& responses) +{ + Timer::Start("bayesian_ridge_regression"); + + arma::mat phi; + arma::rowvec t; + arma::colvec eigval; + arma::mat eigvec; + arma::colvec eigvali; + + // Preprocess the data. Center and scale. + responsesOffset = CenterScaleData(data, + responses, + centerData, + scaleData, + phi, + t, + dataOffset, + dataScale); + + // Compute this quantities once and for all. + const arma::colvec vecphitT = phi * t.t(); + + // Enforce symmetry of the covariance matrix before eig_sym. + const arma::mat phiphiT = arma::symmatu(phi * phi.t()); + + if (arma::eig_sym(eigval, eigvec, phiphiT) == false) + { + Log::Warn << "BayesianRidge::Train(): Eigendecomposition " + << "of covariance failed!" + << std::endl; + return -1; + } + + // Initialize the hyperparameters and + // begin with an infinitely broad prior. + alpha = 1e-6; + beta = 1 / (var(t) * 0.1); + + unsigned short nIterMax = 50; + unsigned short i = 0; + double deltaAlpha = 1, deltaBeta = 1, crit = 1; + arma::mat matA = arma::eye(data.n_rows, data.n_rows); + + while ((crit > tol) && (i < nIterMax)) + { + deltaAlpha = -alpha; + deltaBeta = -beta; + + // Compute the posterior statistics. + // with inv() + matA.diag().fill(alpha); + // inv is used instead of solve because we need the covariance matrix to + // compute the prediction uncertainties. If solve is used, matCovariance + // must be comptuted at the end of the loop. + matCovariance = inv_sympd(matA + phiphiT * beta); + omega = (matCovariance * vecphitT) * beta; + + // // with solve() + // matA.diag().fill(alpha/ beta); + // omega = solve(matA + phiphiT, vecphitT); + + // Update alpha. + eigvali = eigval * beta; + gamma = sum(eigvali / (alpha + eigvali)); + alpha = gamma / dot(omega.t(), omega); + + // Update beta. + const arma::rowvec temp = t - omega.t() * phi; + beta = (data.n_cols - gamma) / dot(temp, temp); + + // Comptute the stopping criterion. + deltaAlpha += alpha; + deltaBeta += beta; + crit = abs(deltaAlpha / alpha + deltaBeta / beta); + i++; + } + Timer::Stop("bayesian_ridge_regression"); + return Rmse(data, responses); +} + +void BayesianRidge::Predict(const arma::mat& points, + arma::rowvec& predictions) const +{ + // y_hat = w^T * (X - mu) / sigma + y_mean. + predictions = omega.t() * + ((points.each_col() - dataOffset).each_col() / dataScale) + responsesOffset; +} + +void BayesianRidge::Predict(const arma::mat& points, + arma::rowvec& predictions, + arma::rowvec& std) const +{ + // Center and scaleData the points before applying the model. + const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; + predictions = omega.t() * X + responsesOffset; + std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); +} + +double BayesianRidge::Rmse(const arma::mat& data, + const arma::rowvec& responses) const +{ + arma::rowvec predictions; + Predict(data, predictions); + return sqrt(mean(square(responses - predictions))); +} + +double BayesianRidge::CenterScaleData(const arma::mat& data, + const arma::rowvec& responses, + bool centerData, + bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale) +{ + // Initialize the offsets to their neutral forms. + dataOffset = arma::zeros(data.n_rows); + dataScale = arma::ones(data.n_rows); + responsesOffset = 0.0; + + if (centerData) + { + dataOffset = mean(data, 1); + responsesOffset = mean(responses); + } + + if (scaleData) + dataScale = stddev(data, 0, 1); + + // Copy data and response before the processing. + dataProc = data; + // Center the data. + dataProc.each_col() -= dataOffset; + // Scale the data. + dataProc.each_col() /= dataScale; + // Center the responses. + responsesProc = responses - responsesOffset; + + return responsesOffset; +} + +// Copy construcor. +BayesianRidge::BayesianRidge(const BayesianRidge& other): + centerData(other.centerData), + scaleData(other.scaleData), + dataOffset(other.dataOffset), + dataScale(other.dataScale), + responsesOffset(other.responsesOffset), + alpha(other.alpha), + beta(other.beta), + gamma(other.gamma), + omega(other.omega), + matCovariance(other.matCovariance) +{/* All is done */} + +// Move constructor. +BayesianRidge::BayesianRidge(BayesianRidge&& other): + centerData(other.centerData), + scaleData(other.scaleData), + dataOffset(std::move(other.dataOffset)), + dataScale(std::move(other.dataScale)), + responsesOffset(other.responsesOffset), + alpha(other.alpha), + beta(other.beta), + gamma(other.gamma), + omega(std::move(other.omega)), + matCovariance(std::move(other.matCovariance)) +{ + // Clear the other object. + if (this != &other) + { + other.centerData = false; + other.scaleData = false; + other.dataOffset.reset(); + other.dataScale.reset(); + other.responsesOffset = 0.0; + other.alpha = 0.0; + other.gamma = 0.0; + other.beta = 0.0; + other.omega.reset(); + other.matCovariance.reset(); + } +} + +BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) +{ + if (this == &other) + return *this; + + centerData = other.centerData; + scaleData = other.scaleData; + dataOffset = other.dataOffset; + dataScale = other.dataScale; + responsesOffset = other.responsesOffset; + alpha = other.alpha; + gamma = other.gamma; + beta = other.beta; + omega = other.omega; + matCovariance = other.matCovariance; + return *this; +} + +BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) +{ + if (this != &other) + { + centerData = other.centerData; + scaleData = other.scaleData; + dataOffset = other.dataOffset; + dataScale = other.dataScale; + responsesOffset = other.responsesOffset; + alpha = other.alpha; + gamma = other.gamma; + beta = other.beta; + omega = other.omega; + matCovariance = other.matCovariance; + + // Clear the other object. + other.centerData = false; + other.scaleData = false; + other.dataOffset.reset(); + other.dataScale.reset(); + other.responsesOffset = 0.0; + other.alpha = 0.0; + other.gamma = 0.0; + other.beta = 0.0; + other.omega.reset(); + other.matCovariance.reset(); + } + return *this; +} diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp similarity index 94% rename from src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp rename to src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index b2faa12fdd..9127e088cf 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -1,5 +1,5 @@ /** - * @file bayesian_ridge.hpp + * @file bayesian_linear_regression.hpp * @author Clement Mercier * * Definition of the BayesianRidge class, which performs the @@ -7,8 +7,8 @@ * all the functions consider data in column-major format. **/ -#ifndef MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP -#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_HPP +#ifndef MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_HPP +#define MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_HPP #include @@ -72,7 +72,7 @@ namespace regression{ * // Train the model. Regularization strength is optimally tunned with the * // training data alone by applying the Train method. - * BayesianRidge estimator(); // Instanciate the estimator with default option. + * BayesianLinearRegression estimator(); // Instanciate the estimator with default option. * estimator.Train(xTrain, yTrain); * // Prediction on test points. @@ -89,7 +89,7 @@ namespace regression{ * estimator.Predict(xTest, responses, stds) * @endcode */ -class BayesianRidge +class BayesianLinearRegression { public: /** @@ -105,13 +105,13 @@ class BayesianRidge * @param tol Level from which the solution is considered sufficientlly * stable. */ - BayesianRidge(const bool centerData = true, + BayesianLinearRegression(const bool centerData = true, const bool scaleData = false, const int nIterMax = 50, const double tol = 1e-4); /** - * Run BayesianRidge. The input matrix (like all mlpack matrices) should be + * Run BayesianLinearRegression. The input matrix (like all mlpack matrices) should be * column-major -- each column is an observation and each row is a dimension. * * @param data Column-major input data @@ -235,7 +235,7 @@ class BayesianRidge double ResponsesOffset() const { return responsesOffset; } /** - * Serialize the BayesianRidge model. + * Serialize the BayesianLinearRegression model. **/ template void serialize(Archive& ar, const unsigned int /* version */); @@ -281,6 +281,6 @@ class BayesianRidge } // namespace mlpack // Include implementation of serialize. -#include "bayesian_ridge_impl.hpp" +#include "bayesian_linear_regression_impl.hpp" #endif diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp similarity index 68% rename from src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp rename to src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp index a2191d45ad..3ef2cfce73 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_impl.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp @@ -1,27 +1,28 @@ /** - * @file bayesian_ridge_impl.hpp + * @file bayesian_linear_regression_impl.hpp * @author Clement Mercier * - * Implementation of templated BayesianRidge functions. + * Implementation of templated BayesianLinearRegression functions. * * 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_BAYESIAN_RIDGE_BAYESIAN_RIDGE_IMPL_HPP -#define MLPACK_METHODS_BAYESIAN_RIDGE_BAYESIAN_RIDGE_IMPL_HPP +#ifndef MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_IMPL_HPP +#define MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_IMPL_HPP -#include "bayesian_ridge.hpp" +#include "bayesian_linear_regression.hpp" namespace mlpack { namespace regression { /** - * Serialize the Bayesian Ridge model. + * Serialize the Bayesian linear regression model. */ template -void BayesianRidge::serialize(Archive& ar, const unsigned int /* version */) +void BayesianLinearRegression::serialize(Archive& ar, + const unsigned int /* version */) { ar & BOOST_SERIALIZATION_NVP(centerData); ar & BOOST_SERIALIZATION_NVP(scaleData); diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp new file mode 100644 index 0000000000..31771f5caf --- /dev/null +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -0,0 +1,205 @@ +/** + * @file bayesian_linear_regression_main.cpp + * @author Clement Mercier + * + * Executable for BayesianLinearRegression. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#include +#include +#include + +#include "bayesian_linear_regression.hpp" + +using namespace arma; +using namespace std; +using namespace mlpack; +using namespace mlpack::regression; +using namespace mlpack::util; + +PROGRAM_INFO("BayesianLinearRegression", + // Short description. + "An implementation of the bayesian linear regression, also known " + "as the Bayesian linear regression. This can train a Bayesian linear " + "regression model and use that model or a pre-trained model to output " + "regression " + "predictions for a test set.", + // Long description. + "An implementation of the bayesian linear regression, also known" + "as the Bayesian linear regression.\n " + "This is a probabilistic view and implementation of the linear regression. " + "Final solution is obtained by comptuting a posterior distribution from " + "gaussian likelihood and a zero mean gaussian isotropic prior distribution " + "on the solution. " + "\n" + "Optimization is AUTOMATIC and does not require cross validation. " + "The optimization is performed by maximization of the evidence function. " + "Parameters are tunned during the maximization of the marginal likelihood. " + "This procedure includes the Ockham's razor that penalizes over complex " + "solutions. " + "\n\n" + "This program is able to train a Bayesian linear regression model or load a " + "model from file, output regression predictions for a test set, and save " + "the trained model to a file. The Bayesian linear regression algorithm is " + "described in more detail below:" + "\n\n" + "Let X be a matrix where each row is a point and each column is a " + "dimension, t is a vector of targets, alpha is the precision of the " + "gaussian prior distribtion of w, and w is solution to determine. " + "\n\n" + "The Bayesian linear regression comptutes the posterior distribution of the " + "parameters by the Bayes's rule : " + "\n\n" + " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" + "\n\n" + "To train a BayesianLinearRegression model, the " + + PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") + + "parameters must be given. The " + PRINT_PARAM_STRING("center") + + "and " + PRINT_PARAM_STRING("scale") + " parameters control the " + "centering and the normalizing options. A trained model can be saved with " + "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " + "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model") + + " parameter." + "\n\n" + "The program can also provide predictions for test data using either the " + "trained model or the given input model. Test points can be specified with" + " the " + PRINT_PARAM_STRING("test") + " parameter. Predicted responses " + "to the test points can be saved with the " + + PRINT_PARAM_STRING("output_predictions") + " output parameter. The " + "corresponding standard deviation can be save by precising the " + + PRINT_PARAM_STRING("output_std") + " parameter." + "\n\n" + "For example, the following command trains a model on the data " + + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + + "with center set to true and scale set to false (so, Bayesian " + "linear regression is being solved, and then the model is saved to " + + PRINT_MODEL("bayesian_linear_regression_model") + ":" + "\n\n" + + PRINT_CALL("bayesian_linear_regression", "input", "data", "responses", + "responses", "center", 1, "scale", 0, "output_model", + "bayesian_linear_regression_model") + + "\n\n" + "The following command uses the " + + PRINT_MODEL("bayesian_linear_regression_model") + " to provide predicted " + + " responses for the data " + PRINT_DATASET("test") + " and save those " + + " responses to " + PRINT_DATASET("test_predictions") + ": " + "\n\n" + + PRINT_CALL("bayesian_linear_regression", "input_model", + "bayesian_linear_regression_model", "test", "test", + "output_predictions", "test_predictions")); + +PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); + +PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); + +PARAM_MODEL_IN(BayesianLinearRegression, "input_model", "Trained " + "BayesianLinearRegression model to use.", "m"); + +PARAM_MODEL_OUT(BayesianLinearRegression, "output_model", "Output " + "BayesianLinearRegression model.", "M"); + +PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " + "points).", "t"); + +PARAM_MATRIX_OUT("output_predictions", "If --test_file is specified, this " + "file is where the predicted responses will be saved.", "o"); + +PARAM_MATRIX_OUT("output_std", "If --std_file is specified, this file is where " + "the standard deviations of the predictive distribution will " + "be saved.", "u"); + +PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " + "disable", + "c", + 1); + +PARAM_INT_IN("scale", "Scale each feature by their standard deviations. " + "set to 1 to scale.", + "s", + 0); + +static void mlpackMain() +{ + int center = CLI::GetParam("center"); + int scale = CLI::GetParam("scale"); + + // Check parameters -- make sure everything given makes sense. + RequireOnlyOnePassed({ "input", "input_model" }, true); + if (CLI::HasParam("input")) + { + RequireOnlyOnePassed({ "responses" }, true, "if input data is specified, " + "responses must also be specified"); + } + ReportIgnoredParam({{ "input", false }}, "responses"); + + RequireAtLeastOnePassed({ "output_predictions", "output_model" }, false, + "no results will be saved"); + + // Ignore out_predictions unless test is specified. + ReportIgnoredParam({{ "test", false }}, "output_predictions"); + + BayesianLinearRegression* bayesLinReg; + if (CLI::HasParam("input")) + { + Log::Info << "input detected " << std::endl; + // Initialize the object. + bayesLinReg = new BayesianLinearRegression(center, scale); + + // Load covariates. We can avoid LARS transposing our data by choosing to + // not transpose this data (that's why we used PARAM_TMATRIX_IN). + mat matX = std::move(CLI::GetParam("input")); + + // Load responses. The responses should be a one-dimensional vector, and it + // seems more likely that these will be stored with one response per line + // (one per row). So we should not transpose upon loading. + mat matY = std::move(CLI::GetParam("responses")); + + // Make sure y is oriented the right way. + if (matY.n_cols == 1) + matY = trans(matY); + if (matY.n_rows > 1) + Log::Fatal << "Only one column or row allowed in responses file!" << endl; + + if (matY.n_elem != matX.n_cols) + Log::Fatal << "Number of responses must be equal to number of rows of X!" + << endl; + + arma::rowvec y = std::move(matY); + arma::rowvec predictionsTrain; + // The Train method is ready to take data in column-major format. + bayesLinReg->Train(matX, matY); + } + else // We must have --input_model_file. + { + bayesLinReg = CLI::GetParam("input_model"); + } + + if (CLI::HasParam("test")) + { + Log::Info << "Regressing on test points." << endl; + // Load test points. + mat testPoints = std::move(CLI::GetParam("test")); + arma::rowvec predictions; + + if (CLI::HasParam("output_std")) + { + arma::rowvec std; + bayesLinReg->Predict(testPoints, predictions, std); + + // Save the standard deviation of the test points (one per line). + CLI::GetParam("output_std") = std::move(std); + } + + else + bayesLinReg->Predict(testPoints, predictions); + + // Save test predictions (one per line). + CLI::GetParam("output_predictions") = std::move(predictions); + } + + CLI::GetParam("output_model") = bayesLinReg; +} diff --git a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ similarity index 99% rename from src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp rename to src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ index 1d4f7fdc74..ec41eaa1d8 100644 --- a/src/mlpack/methods/bayesian_ridge/bayesian_ridge_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ @@ -13,7 +13,7 @@ #include #include -#include "bayesian_ridge.hpp" +#include "bayesian_linear_regression.hpp" using namespace arma; using namespace std; diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index bfa42b0429..d9208bf789 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -15,7 +15,7 @@ add_executable(mlpack_test augmented_rnns_tasks_test.cpp bias_svd_test.cpp binarize_test.cpp - bayesian_ridge_test.cpp + bayesian_linear_regression_test.cpp block_krylov_svd_test.cpp cf_test.cpp cli_binding_test.cpp @@ -122,7 +122,7 @@ add_executable(mlpack_test main_tests/emst_test.cpp main_tests/adaboost_test.cpp main_tests/approx_kfn_test.cpp - main_tests/bayesian_ridge_test.cpp + main_tests/bayesian_linear_regression_test.cpp main_tests/cf_test.cpp main_tests/dbscan_test.cpp main_tests/det_test.cpp diff --git a/src/mlpack/tests/bayesian_ridge_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp similarity index 81% rename from src/mlpack/tests/bayesian_ridge_test.cpp rename to src/mlpack/tests/bayesian_linear_regression_test.cpp index dbad414b73..7252b51549 100644 --- a/src/mlpack/tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -1,8 +1,8 @@ /** - * @file bayesian_ridge_test.cpp + * @file bayesian_linear_regression_test.cpp * @author Clement Mercier * - * Test for BayesianRidge. + * Test for BayesianLinearRegression. * * 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 @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include @@ -19,7 +19,7 @@ using namespace mlpack::regression; using namespace mlpack::data; -BOOST_AUTO_TEST_SUITE(BayesianRidgeTest); +BOOST_AUTO_TEST_SUITE(BayesianLinearRegressionTest); void GenerateProblem(arma::mat& X, arma::rowvec& y, @@ -35,7 +35,7 @@ void GenerateProblem(arma::mat& X, // Ensure that predictions are close enough to the target // for a free noise dataset. -BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) +BOOST_AUTO_TEST_CASE(BayesianLinearRegressionRegressionTest) { arma::mat X; arma::rowvec y, predictions; @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeRegressionTest) GenerateProblem(X, y, 200, 10); // Instanciate and train the estimator. - BayesianRidge estimator(true); + BayesianLinearRegression estimator(true); estimator.Train(X, y); estimator.Predict(X, predictions); @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) GenerateProblem(X, y, nPoints, nDims, 0.5); - BayesianRidge estimator(false, false); + BayesianLinearRegression estimator(false, false); estimator.Train(X, y); @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) size_t nDims = 30, nPoints = 100; GenerateProblem(X, y, nPoints, nDims, 0.5); - BayesianRidge estimator(true, true); + BayesianLinearRegression estimator(true, true); estimator.Train(X, y); arma::colvec xMean = arma::mean(X, 1); @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(SingularMatix) // Now the first and the second rows are indentical. X.row(1) = X.row(0); - BayesianRidge estimator; + BayesianLinearRegression estimator; double singular = estimator.Train(X, y); BOOST_REQUIRE(singular != -1); } @@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) GenerateProblem(X, y, 100, 10, 1); - BayesianRidge estimator(true, true); + BayesianLinearRegression estimator(true, true); estimator.Train(X, y); arma::rowvec responses, std; @@ -141,14 +141,14 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) GenerateProblem(X, y, 100, 10, 1); - BayesianRidge bayesRidge(false, false); - bayesRidge.Train(X, y); + BayesianLinearRegression bayesLinReg(false, false); + bayesLinReg.Train(X, y); LinearRegression classicalRidge(X, - y, - bayesRidge.Alpha() / bayesRidge.Beta(), - false); - double equalSol = arma::sum(bayesRidge.Omega() - classicalRidge.Parameters()); + y, + bayesLinReg.Alpha() / bayesLinReg.Beta(), + false); + double equalSol = arma::sum(bayesLinReg.Omega() - classicalRidge.Parameters()); BOOST_REQUIRE(equalSol < 1e-5); } diff --git a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp similarity index 80% rename from src/mlpack/tests/main_tests/bayesian_ridge_test.cpp rename to src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index dfac7665e8..5f76203c9d 100644 --- a/src/mlpack/tests/main_tests/bayesian_ridge_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -1,5 +1,5 @@ /** - * @file bayesian_ridge_test.cpp + * @file bayesian_linear_regression_test.cpp * @author Clement Mercier * * Test mlpackMain() of pca_main.cpp. @@ -12,12 +12,12 @@ #include #define BINDING_TYPE BINDING_TYPE_TEST -static const std::string testName = "BayesianRidge"; +static const std::string testName = "BayesianLinearRegression"; #include #include #include "test_helper.hpp" -#include +#include #include #include "../test_tools.hpp" @@ -41,7 +41,7 @@ struct BRTestFixture } }; -BOOST_FIXTURE_TEST_SUITE(BayesianRidgeMainTest, BRTestFixture); +BOOST_FIXTURE_TEST_SUITE(BayesianLinearRegressionMainTest, BRTestFixture); /** * Check the center and scale options. @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) mlpackMain(); - BayesianRidge* estimator = CLI::GetParam("output_model"); + BayesianLinearRegression* estimator = CLI::GetParam("output_model"); const arma::colvec dataScale = estimator->DataScale(); const arma::colvec dataOffset = estimator->DataOffset(); @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) /** * Check predictions of saved model and in code model are equal. */ -BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) +BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) { int n = 10, m = 4; arma::mat X = arma::randu(m, n); @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) const arma::colvec omega = arma::randu(m); arma::mat y = omega * X; - BayesianRidge model; + BayesianLinearRegression model; model.Train(X, y); arma::rowvec responses; @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(BayesianRidgeSavedEqualCode) CLI::GetSingleton().Parameters()["input"].wasPassed = false; CLI::GetSingleton().Parameters()["responses"].wasPassed = false; - SetInputParam("input_model", CLI::GetParam("output_model")); + SetInputParam("input_model", CLI::GetParam("output_model")); SetInputParam("test", std::move(Xtest)); mlpackMain(); From 37fd0c3f585ec90d4abd4aa897cb0d30490ebe7e Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 12 May 2020 14:32:35 +0200 Subject: [PATCH 142/297] Formatting. --- .../bayesian_linear_regression_main.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 31771f5caf..31781c4bec 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -42,8 +42,8 @@ PROGRAM_INFO("BayesianLinearRegression", "This procedure includes the Ockham's razor that penalizes over complex " "solutions. " "\n\n" - "This program is able to train a Bayesian linear regression model or load a " - "model from file, output regression predictions for a test set, and save " + "This program is able to train a Bayesian linear regression model or load " + "a model from file, output regression predictions for a test set, and save " "the trained model to a file. The Bayesian linear regression algorithm is " "described in more detail below:" "\n\n" @@ -51,8 +51,8 @@ PROGRAM_INFO("BayesianLinearRegression", "dimension, t is a vector of targets, alpha is the precision of the " "gaussian prior distribtion of w, and w is solution to determine. " "\n\n" - "The Bayesian linear regression comptutes the posterior distribution of the " - "parameters by the Bayes's rule : " + "The Bayesian linear regression comptutes the posterior distribution of " + "the parameters by the Bayes's rule : " "\n\n" " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" "\n\n" @@ -62,13 +62,13 @@ PROGRAM_INFO("BayesianLinearRegression", "and " + PRINT_PARAM_STRING("scale") + " parameters control the " "centering and the normalizing options. A trained model can be saved with " "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " - "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model") + - " parameter." + "at all, a model can be passed via the " + + PRINT_PARAM_STRING("input_model") + " parameter." "\n\n" "The program can also provide predictions for test data using either the " - "trained model or the given input model. Test points can be specified with" - " the " + PRINT_PARAM_STRING("test") + " parameter. Predicted responses " - "to the test points can be saved with the " + + "trained model or the given input model. Test points can be specified " + "with the " + PRINT_PARAM_STRING("test") + " parameter. Predicted " + "responses to the test points can be saved with the " + PRINT_PARAM_STRING("output_predictions") + " output parameter. The " "corresponding standard deviation can be save by precising the " + PRINT_PARAM_STRING("output_std") + " parameter." @@ -89,7 +89,7 @@ PROGRAM_INFO("BayesianLinearRegression", " responses to " + PRINT_DATASET("test_predictions") + ": " "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", - "bayesian_linear_regression_model", "test", "test", + "bayesian_linear_regression_model", "test", "test", "output_predictions", "test_predictions")); PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); @@ -97,13 +97,13 @@ PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); PARAM_MODEL_IN(BayesianLinearRegression, "input_model", "Trained " - "BayesianLinearRegression model to use.", "m"); + "BayesianLinearRegression model to use.", "m"); PARAM_MODEL_OUT(BayesianLinearRegression, "output_model", "Output " - "BayesianLinearRegression model.", "M"); + "BayesianLinearRegression model.", "M"); PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " - "points).", "t"); + "points).", "t"); PARAM_MATRIX_OUT("output_predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); @@ -114,8 +114,8 @@ PARAM_MATRIX_OUT("output_std", "If --std_file is specified, this file is where " PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " "disable", - "c", - 1); + "c", + 1); PARAM_INT_IN("scale", "Scale each feature by their standard deviations. " "set to 1 to scale.", From 109254084081188cf67bc75931db52e760194c6d Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 12 May 2020 20:28:22 +0200 Subject: [PATCH 143/297] Formatting. --- .../bayesian_linear_regression_main.cpp | 2 +- src/mlpack/tests/bayesian_linear_regression_test.cpp | 3 ++- .../tests/main_tests/bayesian_linear_regression_test.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 31781c4bec..a1262c2a36 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -62,7 +62,7 @@ PROGRAM_INFO("BayesianLinearRegression", "and " + PRINT_PARAM_STRING("scale") + " parameters control the " "centering and the normalizing options. A trained model can be saved with " "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " - "at all, a model can be passed via the " + + "at all, a model can be passed via the " + PRINT_PARAM_STRING("input_model") + " parameter." "\n\n" "The program can also provide predictions for test data using either the " diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 7252b51549..fb73bef54d 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -148,7 +148,8 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) y, bayesLinReg.Alpha() / bayesLinReg.Beta(), false); - double equalSol = arma::sum(bayesLinReg.Omega() - classicalRidge.Parameters()); + double equalSol = arma::sum(bayesLinReg.Omega() + - classicalRidge.Parameters()); BOOST_REQUIRE(equalSol < 1e-5); } diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 5f76203c9d..b2c7495585 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -59,7 +59,8 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) mlpackMain(); - BayesianLinearRegression* estimator = CLI::GetParam("output_model"); + BayesianLinearRegression* estimator = + CLI::GetParam("output_model"); const arma::colvec dataScale = estimator->DataScale(); const arma::colvec dataOffset = estimator->DataOffset(); @@ -93,7 +94,8 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) CLI::GetSingleton().Parameters()["input"].wasPassed = false; CLI::GetSingleton().Parameters()["responses"].wasPassed = false; - SetInputParam("input_model", CLI::GetParam("output_model")); + SetInputParam("input_model", + CLI::GetParam("output_model")); SetInputParam("test", std::move(Xtest)); mlpackMain(); From 7d519cee8bd255aa02f82c5453ec86890d4abc26 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 13 May 2020 16:35:17 +0200 Subject: [PATCH 144/297] Formatting. --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 2 +- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index fb73bef54d..b93163398b 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) bayesLinReg.Alpha() / bayesLinReg.Beta(), false); double equalSol = arma::sum(bayesLinReg.Omega() - - classicalRidge.Parameters()); + - classicalRidge.Parameters()); BOOST_REQUIRE(equalSol < 1e-5); } diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index b2c7495585..284eb29bd1 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) mlpackMain(); - BayesianLinearRegression* estimator = + BayesianLinearRegression* estimator = CLI::GetParam("output_model"); const arma::colvec dataScale = estimator->DataScale(); From 4efb8b6730875bcf058f9f810e655d69fbc44f80 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 19 May 2020 11:07:22 +0200 Subject: [PATCH 145/297] Modification of the CMakeLists.txt for rmv regression. --- src/mlpack/methods/CMakeLists.txt | 1 + src/mlpack/tests/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/mlpack/methods/CMakeLists.txt b/src/mlpack/methods/CMakeLists.txt index d548d9c769..3674c4de15 100644 --- a/src/mlpack/methods/CMakeLists.txt +++ b/src/mlpack/methods/CMakeLists.txt @@ -46,6 +46,7 @@ set(DIRS rann regularized_svd reinforcement_learning + rvm_regression softmax_regression sparse_autoencoder sparse_coding diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index d9208bf789..6c91567bc6 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -92,6 +92,7 @@ add_executable(mlpack_test recurrent_network_test.cpp regularized_svd_test.cpp reward_clipping_test.cpp + rvm_regression_test.cpp rl_components_test.cpp serialization.cpp serialization.hpp From daab1ead13748cdef6a785504932ea59e5baf46a Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 19 May 2020 11:09:47 +0200 Subject: [PATCH 146/297] Add Relevance Vector Machine for regression. --- .../methods/rvm_regression/CMakeLists.txt | 19 ++ .../methods/rvm_regression/CMakeLists.txt~ | 19 ++ .../methods/rvm_regression/rvm_regression.hpp | 182 ++++++++++++ .../rvm_regression/rvm_regression_impl.hpp | 267 ++++++++++++++++++ .../rvm_regression/rvm_regression_test.cpp | 58 ++++ src/mlpack/methods/rvm_regression/utils.hpp | 83 ++++++ src/mlpack/tests/rvm_regression_test.cpp | 33 +++ 7 files changed, 661 insertions(+) create mode 100644 src/mlpack/methods/rvm_regression/CMakeLists.txt create mode 100644 src/mlpack/methods/rvm_regression/CMakeLists.txt~ create mode 100644 src/mlpack/methods/rvm_regression/rvm_regression.hpp create mode 100644 src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp create mode 100644 src/mlpack/methods/rvm_regression/rvm_regression_test.cpp create mode 100644 src/mlpack/methods/rvm_regression/utils.hpp create mode 100644 src/mlpack/tests/rvm_regression_test.cpp diff --git a/src/mlpack/methods/rvm_regression/CMakeLists.txt b/src/mlpack/methods/rvm_regression/CMakeLists.txt new file mode 100644 index 0000000000..9849f16af3 --- /dev/null +++ b/src/mlpack/methods/rvm_regression/CMakeLists.txt @@ -0,0 +1,19 @@ +# Define the files we need to compile +# Anything not in this list will not be compiled into the output library +set(SOURCES + rvm_regression.hpp + rvm_regression_impl.hpp + rvm_regression.cpp +) + +# add directory name to sources +set(DIR_SRCS) +foreach(file ${SOURCES}) + set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) +endforeach() +# append sources (with directory name) to list of all mlpack sources (used at the parent scope) +set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) + +add_cli_executable(rvm_regression) +add_python_binding(rvm_regression) +add_markdown_docs(rvm_regression "cli;python" "regression") diff --git a/src/mlpack/methods/rvm_regression/CMakeLists.txt~ b/src/mlpack/methods/rvm_regression/CMakeLists.txt~ new file mode 100644 index 0000000000..9b03b83136 --- /dev/null +++ b/src/mlpack/methods/rvm_regression/CMakeLists.txt~ @@ -0,0 +1,19 @@ +# Define the files we need to compile +# Anything not in this list will not be compiled into the output library +set(SOURCES + bayesian_linear_regression.hpp + bayesian_linear_regression_impl.hpp + bayesian_linear_regression.cpp +) + +# add directory name to sources +set(DIR_SRCS) +foreach(file ${SOURCES}) + set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) +endforeach() +# append sources (with directory name) to list of all mlpack sources (used at the parent scope) +set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) + +add_cli_executable(bayesian_linear_regression) +add_python_binding(bayesian_linear_regression) +add_markdown_docs(bayesian_linear_regression "cli;python" "regression") diff --git a/src/mlpack/methods/rvm_regression/rvm_regression.hpp b/src/mlpack/methods/rvm_regression/rvm_regression.hpp new file mode 100644 index 0000000000..1ac4190959 --- /dev/null +++ b/src/mlpack/methods/rvm_regression/rvm_regression.hpp @@ -0,0 +1,182 @@ +/** + * @file rvmr.hpp + * @ Clement Mercier + * + * Definition of the RVMR class, which performs the + * Relevance Vector Machine for regression +**/ +#ifndef TATON_RVMR_HPP +#define TATON_RVMR_HPP + +#include +#include "utils.hpp" + +namespace rvmr { + +template +class RVMR +{ +public: + + + /** + * Set the parameters of the RVMR (Relevance Vector Machine for regression) + * object for a given kernel. There are numerous available kernels in + * the mlpack::kernel namespace. + * Regulariation parameters are automaticaly set to their optimal values by + * maximizing the marginal likelihood. Optimization is done by Evidence + * Maximization. + * @param kernel Kernel to be used for computation. + * @param fitIntercept Whether or not center the data according to the * + * examples. + * @param normalize Whether or to normalize the data according to the + * standard deviation of each feature. + **/ + RVMR(const KernelType& kernel, + const bool fitIntercept, + const bool normalize); + + /** + * Set the parameters of the ARD regression (Automatic Relevance Determination) + * object without any kernel. The class Performs a linear regression with an ARD prior promoting + * sparsity in the final solution. + * Regulariation parameters are automaticaly set to their optimal values by + * the maximmization of the marginal likelihood. Optimization is done by + * Evidence Maximization. + * ARD regression is computed whatever the kernel type given for the + * initalization. + * + * @param fitIntercept Whether or not center the data according to the + * examples. + * @param normalize Whether or to normalize the data according to the + * standard deviation of each feature. + **/ + RVMR(const bool fitIntercept = true, + const bool normalize = false); + + + /** + * Run Relevance Vector Machine for regression. The input matrix + * (like all mlpack matrices) should be + * column-major -- each column is an observation and each row is + * a dimension. + * + * @param data Column-major input data (or row-major input data if rowMajor = + * true). + * @param responses Vector of targets. + **/ + void Train(const arma::mat& data, + const arma::rowvec& responses); + + /** + * Predict \f$\hat{y}_{i}\f$ for each data point in the given data matrix using the + * currently-trained RVM model. Only the coefficients of the active basis + * funcions are used for prediction. This allows fast predictions. + * @param points The data points to apply the model. + * @param predictions y, which will contained calculated values on completion. + */ + void Predict(const arma::mat& points, + arma::rowvec& predictions) const; + + /** + * Predict \f$\hat{y}_{i}\f$ and the standard deviation of the predictive posterior + * distribution for each data point in the given data matrix using the + * currently-trained RVM model. Only the coefficients of the active basis + * funcions are used for prediction. This allows fast predictions. + * @param points The data points to apply the model. + * @param predictions y, which will contained calculated values on completion. + * @param std Standard deviations of the predictions. + */ + void Predict(const arma::mat& points, + arma::rowvec& predictions, + arma::rowvec& std) const; + + /** + * Apply the kernel function between the column vectors of two matrices + * X and Y. If X=Y this function comptutes the Gramian matrix. + * @param X Matrix of dimension \f$ M \times N1 \f$. + * @param Y Matrix of dimension \f$ M \times N2 \f$. + * @param gramMatrix of dimension \f$N1 \times N2\f$. Elements are equal + * to kernel.Evaluate(\f$ x_{i} \f$,\f$ y_{j} \f$). + **/ + void applyKernel(const arma::mat& X, + const arma::mat& Y, + arma::mat& gramMatrix) const; + + + /** + * Compute the Root Mean Square Error + * between the predictions returned by the model + * and the true repsonses. + * @param Points Data points to predict. + * @param responses A vector of targets. + * @return RMSE + **/ + double Rmse(const arma::mat& data, + const arma::rowvec& responses) const; + + /** + * Get the coefficents of the full solution vector. + * The 0 are associated to the inactive basis functions. + **/ + arma::vec getCoefs() const; + + /** + * Get the precesion (or inverse variance) beta of the model. + * @return \f$ \beta \f$ + **/ + inline double getBeta() const {return this->beta;} + + /** + * Get the estimated variance. + * @return 1.0 / \f$ \beta \f$ + **/ + inline double getVariance() const {return 1.0 / this->getBeta();} + + + /** + * Get the indices of the active basis functions. + * + * @return activeSet + **/ + inline arma::uvec getActiveSet() const {return this->activeSet;} + + +private: + //! Center the data if true. + bool fitIntercept; + //! Scale the data by standard deviations if true. + bool normalize; + //! Mean vector computed over the points. + arma::colvec data_offset; + //! Std vector computed over the points. + arma::colvec data_scale; + //! Mean of the response vector computed over the points. + double responses_offset; + //! alpha_threshold limit to prune the basis functions. + float alpha_threshold; + //! kernel Kernel used. + KernelType kernel; + //! Indicates if ARD regression mode is used. + bool ardRegression; + //! Kernel length scale. + double gamma; + //! Train database. + arma::mat phi; + //! Precision of the prior pdfs (independant gaussian). + arma::rowvec alpha; + //! Noise inverse variance. + double beta; + //! Solution vector. + arma::colvec omega; + //! Coavriance matrix of the solution vector omega. + arma::mat matCovariance; + //! activeSetive Indices of active basis functions. + arma::uvec activeSet; + +}; +} // namespace rvmr +// include implementation. +#include "rvmr_impl.hpp" + +#endif diff --git a/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp b/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp new file mode 100644 index 0000000000..8b1b60ab29 --- /dev/null +++ b/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp @@ -0,0 +1,267 @@ +/** + * @file rvmr.cpp + * @author Clement Mercier + * + * Implementation of the Relevance Vector Machine. + * + * 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 TATON_RVMR_IMPL_HPP +#define TATON_RVMR_IMPL_HPP + +#include "rvmr.hpp" + +using namespace mlpack; +namespace rvmr { + +template +RVMR::RVMR(const KernelType& kernel, + const bool fitIntercept, + const bool normalize) : + + kernel(kernel), + fitIntercept(fitIntercept), + normalize(normalize), + ardRegression(false) { + + std::cout << "RVMR_kernel_mlpack(fitIntercept=" + << this->fitIntercept + << ", normalize=" + << this->normalize + << ")" + << std::endl; + } + + template + RVMR::RVMR(const bool fitIntercept, + const bool normalize) : + fitIntercept(fitIntercept), + normalize(normalize), + kernel(kernel::LinearKernel()), + ardRegression(true) { + + std::cout << "RVMR_ARD_Regresion(fitIntercept=" + << this->fitIntercept + << ", normalize=" + << this->normalize + << ")" + << std::endl; + } + +template +void RVMR::Train(const arma::mat& data, + const arma::rowvec& responses) +{ + arma::mat phi; + arma::rowvec t; + + // Manage the kernel. + if (this->ardRegression == false) + { + // We must keep the original training data for future predictions. + this->phi = data; + applyKernel(data, data, phi); + + //Preprocess the data. Center and normalize. + preprocess_data(phi, + responses, + this->fitIntercept, + this->normalize, + phi, + t, + this->data_offset, + this->data_scale, + this->responses_offset); + } + + else + { + //Preprocess the data. Center and normalize. + preprocess_data(data, + responses, + this->fitIntercept, + this->normalize, + phi, + t, + this->data_offset, + this->data_scale, + this->responses_offset); + } + + unsigned short p = phi.n_rows, n = phi.n_cols; + // Initialize the hyperparameters and + // begin with an infinitely broad prior. + this->alpha_threshold = 1e4; + this->alpha = arma::ones(p) * 1e-6; + this->beta = 1 / (arma::var(t) * 0.1); + + // Loop variables. + double tol = 1e-5; + double L = 1.0; + double crit = 1.0; + unsigned short nIterMax = 50; + unsigned short i = 0; + unsigned short ind_act; + + arma::rowvec gammai = arma::zeros(p); + arma::mat matA; + arma::rowvec temp(n); + arma::mat subPhi; + // Initiaze a vector of all the indices from the first + // to the last point. + arma::uvec allCols(n); + for (size_t i=0; i < n; i++) {allCols(i) = i;} + + while ((crit > tol) && (i < nIterMax)) + { + crit = -L; + activeSet = find(alpha < alpha_threshold); + // Prune out the inactive basis function. This procedure speeds up + // the algorithm. + subPhi = phi.submat(activeSet, allCols); + + // Compute the posterior statistics. + matA = diagmat(alpha.elem(activeSet)); + matCovariance = inv(matA + + (subPhi + * subPhi.t()) + * beta); + + this->omega = (matCovariance + * subPhi + * t.t()) * beta; + + // Update the alpha_i. + for (size_t k=0; kactiveSet.size(); k++) + { + ind_act = activeSet[k]; + gammai(ind_act) = 1 - matCovariance(k, k) * alpha(ind_act); + + alpha(ind_act) = gammai(ind_act) + / (omega(k) * omega(k)); + } + + // Update beta. + temp = t - omega.t() * subPhi; + beta = (n - sum(gammai.elem(activeSet))) / dot(temp, temp); + + // Comptute the stopping criterion. + L = norm(omega); + crit = abs(crit + L) / L; + i++; + } +} + + +template +void RVMR::Predict(const arma::mat& points, + arma::rowvec& predictions) const +{ + arma::mat X; + // Manage the kernel. + if (this->ardRegression == false) + applyKernel(this->phi, points, X); + else + X = points; + + arma::uvec allCols(X.n_cols); + for (size_t i=0; i < X.n_cols; i++) {allCols[i] = i;} + + // Center and normalize the points before applying the model. + X.each_col() -= this->data_offset; + X.each_col() /= this->data_scale; + predictions = this->omega.t() * X.submat(this->activeSet, allCols) + + this->responses_offset; +} + + +template +void RVMR::Predict(const arma::mat& points, + arma::rowvec& predictions, + arma::rowvec& std) const +{ + arma::mat X; + // Manage the kernel. + if (this->ardRegression == false) + applyKernel(this->phi, points, X); + else + X = points; + + arma::uvec allCols(X.n_cols); + for (size_t i=0; i < X.n_cols; i++) {allCols[i] = i;} + + // Center and normalize the points before applying the model. + X.each_col() -= this->data_offset; + X.each_col() /= this->data_scale; + predictions = this->omega.t() * X.submat(this->activeSet, allCols) + + this->responses_offset; + + // Comptute the standard deviations + arma::mat O(X.n_cols, X.n_cols); + O = X.submat(this->activeSet, allCols).t() + * this->matCovariance + * X.submat(this->activeSet, allCols); + std = sqrt(diagvec(1/this->beta + O).t()); +} + + +template +double RVMR::Rmse(const arma::mat& data, + const arma::rowvec& responses) const +{ + arma::rowvec predictions; + this->Predict(data, predictions); + return sqrt( + mean( + square(responses - predictions))); +} + + +template +arma::vec RVMR::getCoefs() const +{ + // Get the size of the full solution with the offset. + arma::colvec coefs = arma::zeros(this->data_offset.size()); + // omega[i] = 0 for the inactive basis functions + + // Now reconstruct the full solution. + for (size_t i=0; i < this->activeSet.size(); i++) + { + coefs[this->activeSet[i]] = this->omega[i]; + } + return coefs; +} + + +template +void RVMR::applyKernel(const arma::mat& X, + const arma::mat& Y, + arma::mat& gramMatrix) const { + + // Check if the dimensions are consistent. + if (X.n_rows != Y.n_rows) + { + std::cout << "error gramm" << std::endl; + throw std::invalid_argument("Number of features not consistent"); + } + + gramMatrix = arma::zeros(X.n_cols, Y.n_cols); + arma::colvec xi = arma::zeros(X.n_rows); + arma::colvec yj = arma::zeros(X.n_rows); + + for (size_t i=0; i < X.n_cols; i++) + { + xi = X.col(i); + for (size_t j=0; j < Y.n_cols; j++) + { + yj = Y.col(j); + gramMatrix(i, j) = this->kernel.Evaluate(xi, yj); + } + } +} + +} // namespace rvmr; +#endif diff --git a/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp b/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp new file mode 100644 index 0000000000..10628fd0ca --- /dev/null +++ b/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp @@ -0,0 +1,58 @@ +#include +// Includes all relevant components of mlpack. + +#include +#include + +#include +#include +#include +#include + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE Mytest +#include + + +#include "rvmr.hpp" + +using namespace mlpack; +using namespace rvmr; + + +BOOST_AUTO_TEST_CASE(RVMegressionTest) +{ + // First, load the data. + arma::mat Xtrain, Xtest; + arma::rowvec ytrain, ytest; + double RMSETRAIN = 0.112415, RMSETEST = 0.171325; + + + std::cout<< "Synthetic dataset.\n" + << "Only the first ten features are non equal to 0." + << std::endl; + data::Load("./data/synth_train.csv", Xtrain, false, true); + data::Load("./data/synth_test.csv", Xtest, false, true); + data::Load("./data/synth_y_train.csv", ytrain, false, true); + data::Load("./data/synth_y_test.csv", ytest, false, true); + + // Instanciate and train the estimator + RVMR estimator(true, false); + estimator.Train(Xtrain, ytrain); + + // Check if the RMSE are still equal to the previously fixed values + BOOST_REQUIRE_SMALL(estimator.Rmse(Xtrain,ytrain) - RMSETRAIN, 0.05); + BOOST_REQUIRE_SMALL(estimator.Rmse(Xtest,ytest) - RMSETEST, 0.05); + + //FIX ME TRain a LARS estimator + arma::vec predTestLars, solution; + regression::LARS lars(true); + lars.Train(Xtrain, ytrain.t(), solution); + lars.Predict(Xtest, predTestLars); + predTestLars.print(); + arma::rowvec predTestRvm; + estimator.Predict(Xtest, predTestRvm); + std::cout << "\n" << std::endl; + predTestRvm.print(); + std::cout << "end of the code" << std::endl; +} diff --git a/src/mlpack/methods/rvm_regression/utils.hpp b/src/mlpack/methods/rvm_regression/utils.hpp new file mode 100644 index 0000000000..0ccdeee383 --- /dev/null +++ b/src/mlpack/methods/rvm_regression/utils.hpp @@ -0,0 +1,83 @@ +/** + * @file utils.hpp + * @ _____ + * + * Definition of some usefull function for preprocess the data +**/ + +#ifndef TATON_UTILS_HPP +#define TATON_UTILS_HPP + +#include + +typedef double (*kernel)(arma::mat, arma::mat, double); + +/* + * Center and normalize the data. The last four arguments + * allow future modifation of new points. + * + * @param data Design matrix in column-major format, dim(P,N). + * @param responses A vector of targets. + * @param fit_interpept If true data will be centred according to the points. + * @param fit_interpept If true data will be scales by the standard deviations + * of the features computed according to the points. + * @param data_proc data processed, dim(N,P). + * @param responses_proc responses processed, dim(N). + * @param data_offset Mean vector of the design matrix according to the + * points, dim(P). + * @param data_scale Vector containg the standard deviations of the features + * dim(P). + * @param reponses_offset Mean of responses. + */ +void preprocess_data(const arma::mat& data, + const arma::rowvec& responses, + const bool fit_intercept, + const bool normalize, + arma::mat& data_proc, + arma::rowvec& responses_proc, + arma::colvec& data_offset, + arma::colvec& data_scale, + double& responses_offset); + +/* + * Compute gram matrix between two matrices X and Y. + * + * @param X Matrice dim(p,n1). + * @param Y Matrice dim(p,n2). + * @param kernelFunction Function pointer toward a kernel function. + * Available : linear, rbf. + * @param gamma Length scale parameter of the rbf kernel. + */ +void gramMatrix(const arma::mat& X, + const arma::mat& Y, + arma::mat& gramMatrix, + double (*kernelFunction)(arma::colvec&, arma::colvec&, double), + double gamma); + +/* + * Compute the Radial Basis Function between two vectors. + * + * @param x Vector. + * @param y Vector. + * @param gamma Length scale parameter of the rbf kernel. If gamma + * @return rbf Value of the kernel function. +*/ +double rbf(arma::colvec& x, + arma::colvec& y, + double gamma); + +/* + * Compute the linear kernel function between two vectors. + * + * @param x Vector. + * @param y Vector. + * @param gamma Length scale parameter of the rbf kernel. If gamma + * @return linear Value of the kernel function. +*/ +double linear(arma::colvec& x, + arma::colvec& y, + double gamma); + + + +#endif diff --git a/src/mlpack/tests/rvm_regression_test.cpp b/src/mlpack/tests/rvm_regression_test.cpp new file mode 100644 index 0000000000..d3fda17de3 --- /dev/null +++ b/src/mlpack/tests/rvm_regression_test.cpp @@ -0,0 +1,33 @@ +#include +// Includes all relevant components of mlpack. + +#include +#include + +#include +#include + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE Mytest +#include + + +#include "rvm_regression.hpp" + +using namespace mlpack; +using namespace rvmr; + + +BOOST_AUTO_TEST_CASE(RVMRegressionTest) +{ + // First, load the data. + arma::mat Xtrain, Xtest; + arma::rowvec ytrain, ytest; + + // Instanciate and train the estimator + RVMR estimator(true, false); + estimator.Train(Xtrain, ytrain); + + // Check if the RMSE are still equal to the previously fixed values + BOOST_REQUIRE(true); +} From 3fc845489682f665e6c4433453ed5ce98cce17a1 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 19 May 2020 11:21:37 +0200 Subject: [PATCH 147/297] Revert "Add Relevance Vector Machine for regression." This reverts commit daab1ead13748cdef6a785504932ea59e5baf46a. --- .../methods/rvm_regression/CMakeLists.txt | 19 -- .../methods/rvm_regression/CMakeLists.txt~ | 19 -- .../methods/rvm_regression/rvm_regression.hpp | 182 ------------ .../rvm_regression/rvm_regression_impl.hpp | 267 ------------------ .../rvm_regression/rvm_regression_test.cpp | 58 ---- src/mlpack/methods/rvm_regression/utils.hpp | 83 ------ src/mlpack/tests/rvm_regression_test.cpp | 33 --- 7 files changed, 661 deletions(-) delete mode 100644 src/mlpack/methods/rvm_regression/CMakeLists.txt delete mode 100644 src/mlpack/methods/rvm_regression/CMakeLists.txt~ delete mode 100644 src/mlpack/methods/rvm_regression/rvm_regression.hpp delete mode 100644 src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp delete mode 100644 src/mlpack/methods/rvm_regression/rvm_regression_test.cpp delete mode 100644 src/mlpack/methods/rvm_regression/utils.hpp delete mode 100644 src/mlpack/tests/rvm_regression_test.cpp diff --git a/src/mlpack/methods/rvm_regression/CMakeLists.txt b/src/mlpack/methods/rvm_regression/CMakeLists.txt deleted file mode 100644 index 9849f16af3..0000000000 --- a/src/mlpack/methods/rvm_regression/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Define the files we need to compile -# Anything not in this list will not be compiled into the output library -set(SOURCES - rvm_regression.hpp - rvm_regression_impl.hpp - rvm_regression.cpp -) - -# add directory name to sources -set(DIR_SRCS) -foreach(file ${SOURCES}) - set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) -endforeach() -# append sources (with directory name) to list of all mlpack sources (used at the parent scope) -set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - -add_cli_executable(rvm_regression) -add_python_binding(rvm_regression) -add_markdown_docs(rvm_regression "cli;python" "regression") diff --git a/src/mlpack/methods/rvm_regression/CMakeLists.txt~ b/src/mlpack/methods/rvm_regression/CMakeLists.txt~ deleted file mode 100644 index 9b03b83136..0000000000 --- a/src/mlpack/methods/rvm_regression/CMakeLists.txt~ +++ /dev/null @@ -1,19 +0,0 @@ -# Define the files we need to compile -# Anything not in this list will not be compiled into the output library -set(SOURCES - bayesian_linear_regression.hpp - bayesian_linear_regression_impl.hpp - bayesian_linear_regression.cpp -) - -# add directory name to sources -set(DIR_SRCS) -foreach(file ${SOURCES}) - set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) -endforeach() -# append sources (with directory name) to list of all mlpack sources (used at the parent scope) -set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - -add_cli_executable(bayesian_linear_regression) -add_python_binding(bayesian_linear_regression) -add_markdown_docs(bayesian_linear_regression "cli;python" "regression") diff --git a/src/mlpack/methods/rvm_regression/rvm_regression.hpp b/src/mlpack/methods/rvm_regression/rvm_regression.hpp deleted file mode 100644 index 1ac4190959..0000000000 --- a/src/mlpack/methods/rvm_regression/rvm_regression.hpp +++ /dev/null @@ -1,182 +0,0 @@ -/** - * @file rvmr.hpp - * @ Clement Mercier - * - * Definition of the RVMR class, which performs the - * Relevance Vector Machine for regression -**/ -#ifndef TATON_RVMR_HPP -#define TATON_RVMR_HPP - -#include -#include "utils.hpp" - -namespace rvmr { - -template -class RVMR -{ -public: - - - /** - * Set the parameters of the RVMR (Relevance Vector Machine for regression) - * object for a given kernel. There are numerous available kernels in - * the mlpack::kernel namespace. - * Regulariation parameters are automaticaly set to their optimal values by - * maximizing the marginal likelihood. Optimization is done by Evidence - * Maximization. - * @param kernel Kernel to be used for computation. - * @param fitIntercept Whether or not center the data according to the * - * examples. - * @param normalize Whether or to normalize the data according to the - * standard deviation of each feature. - **/ - RVMR(const KernelType& kernel, - const bool fitIntercept, - const bool normalize); - - /** - * Set the parameters of the ARD regression (Automatic Relevance Determination) - * object without any kernel. The class Performs a linear regression with an ARD prior promoting - * sparsity in the final solution. - * Regulariation parameters are automaticaly set to their optimal values by - * the maximmization of the marginal likelihood. Optimization is done by - * Evidence Maximization. - * ARD regression is computed whatever the kernel type given for the - * initalization. - * - * @param fitIntercept Whether or not center the data according to the - * examples. - * @param normalize Whether or to normalize the data according to the - * standard deviation of each feature. - **/ - RVMR(const bool fitIntercept = true, - const bool normalize = false); - - - /** - * Run Relevance Vector Machine for regression. The input matrix - * (like all mlpack matrices) should be - * column-major -- each column is an observation and each row is - * a dimension. - * - * @param data Column-major input data (or row-major input data if rowMajor = - * true). - * @param responses Vector of targets. - **/ - void Train(const arma::mat& data, - const arma::rowvec& responses); - - /** - * Predict \f$\hat{y}_{i}\f$ for each data point in the given data matrix using the - * currently-trained RVM model. Only the coefficients of the active basis - * funcions are used for prediction. This allows fast predictions. - * @param points The data points to apply the model. - * @param predictions y, which will contained calculated values on completion. - */ - void Predict(const arma::mat& points, - arma::rowvec& predictions) const; - - /** - * Predict \f$\hat{y}_{i}\f$ and the standard deviation of the predictive posterior - * distribution for each data point in the given data matrix using the - * currently-trained RVM model. Only the coefficients of the active basis - * funcions are used for prediction. This allows fast predictions. - * @param points The data points to apply the model. - * @param predictions y, which will contained calculated values on completion. - * @param std Standard deviations of the predictions. - */ - void Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const; - - /** - * Apply the kernel function between the column vectors of two matrices - * X and Y. If X=Y this function comptutes the Gramian matrix. - * @param X Matrix of dimension \f$ M \times N1 \f$. - * @param Y Matrix of dimension \f$ M \times N2 \f$. - * @param gramMatrix of dimension \f$N1 \times N2\f$. Elements are equal - * to kernel.Evaluate(\f$ x_{i} \f$,\f$ y_{j} \f$). - **/ - void applyKernel(const arma::mat& X, - const arma::mat& Y, - arma::mat& gramMatrix) const; - - - /** - * Compute the Root Mean Square Error - * between the predictions returned by the model - * and the true repsonses. - * @param Points Data points to predict. - * @param responses A vector of targets. - * @return RMSE - **/ - double Rmse(const arma::mat& data, - const arma::rowvec& responses) const; - - /** - * Get the coefficents of the full solution vector. - * The 0 are associated to the inactive basis functions. - **/ - arma::vec getCoefs() const; - - /** - * Get the precesion (or inverse variance) beta of the model. - * @return \f$ \beta \f$ - **/ - inline double getBeta() const {return this->beta;} - - /** - * Get the estimated variance. - * @return 1.0 / \f$ \beta \f$ - **/ - inline double getVariance() const {return 1.0 / this->getBeta();} - - - /** - * Get the indices of the active basis functions. - * - * @return activeSet - **/ - inline arma::uvec getActiveSet() const {return this->activeSet;} - - -private: - //! Center the data if true. - bool fitIntercept; - //! Scale the data by standard deviations if true. - bool normalize; - //! Mean vector computed over the points. - arma::colvec data_offset; - //! Std vector computed over the points. - arma::colvec data_scale; - //! Mean of the response vector computed over the points. - double responses_offset; - //! alpha_threshold limit to prune the basis functions. - float alpha_threshold; - //! kernel Kernel used. - KernelType kernel; - //! Indicates if ARD regression mode is used. - bool ardRegression; - //! Kernel length scale. - double gamma; - //! Train database. - arma::mat phi; - //! Precision of the prior pdfs (independant gaussian). - arma::rowvec alpha; - //! Noise inverse variance. - double beta; - //! Solution vector. - arma::colvec omega; - //! Coavriance matrix of the solution vector omega. - arma::mat matCovariance; - //! activeSetive Indices of active basis functions. - arma::uvec activeSet; - -}; -} // namespace rvmr -// include implementation. -#include "rvmr_impl.hpp" - -#endif diff --git a/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp b/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp deleted file mode 100644 index 8b1b60ab29..0000000000 --- a/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp +++ /dev/null @@ -1,267 +0,0 @@ -/** - * @file rvmr.cpp - * @author Clement Mercier - * - * Implementation of the Relevance Vector Machine. - * - * 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 TATON_RVMR_IMPL_HPP -#define TATON_RVMR_IMPL_HPP - -#include "rvmr.hpp" - -using namespace mlpack; -namespace rvmr { - -template -RVMR::RVMR(const KernelType& kernel, - const bool fitIntercept, - const bool normalize) : - - kernel(kernel), - fitIntercept(fitIntercept), - normalize(normalize), - ardRegression(false) { - - std::cout << "RVMR_kernel_mlpack(fitIntercept=" - << this->fitIntercept - << ", normalize=" - << this->normalize - << ")" - << std::endl; - } - - template - RVMR::RVMR(const bool fitIntercept, - const bool normalize) : - fitIntercept(fitIntercept), - normalize(normalize), - kernel(kernel::LinearKernel()), - ardRegression(true) { - - std::cout << "RVMR_ARD_Regresion(fitIntercept=" - << this->fitIntercept - << ", normalize=" - << this->normalize - << ")" - << std::endl; - } - -template -void RVMR::Train(const arma::mat& data, - const arma::rowvec& responses) -{ - arma::mat phi; - arma::rowvec t; - - // Manage the kernel. - if (this->ardRegression == false) - { - // We must keep the original training data for future predictions. - this->phi = data; - applyKernel(data, data, phi); - - //Preprocess the data. Center and normalize. - preprocess_data(phi, - responses, - this->fitIntercept, - this->normalize, - phi, - t, - this->data_offset, - this->data_scale, - this->responses_offset); - } - - else - { - //Preprocess the data. Center and normalize. - preprocess_data(data, - responses, - this->fitIntercept, - this->normalize, - phi, - t, - this->data_offset, - this->data_scale, - this->responses_offset); - } - - unsigned short p = phi.n_rows, n = phi.n_cols; - // Initialize the hyperparameters and - // begin with an infinitely broad prior. - this->alpha_threshold = 1e4; - this->alpha = arma::ones(p) * 1e-6; - this->beta = 1 / (arma::var(t) * 0.1); - - // Loop variables. - double tol = 1e-5; - double L = 1.0; - double crit = 1.0; - unsigned short nIterMax = 50; - unsigned short i = 0; - unsigned short ind_act; - - arma::rowvec gammai = arma::zeros(p); - arma::mat matA; - arma::rowvec temp(n); - arma::mat subPhi; - // Initiaze a vector of all the indices from the first - // to the last point. - arma::uvec allCols(n); - for (size_t i=0; i < n; i++) {allCols(i) = i;} - - while ((crit > tol) && (i < nIterMax)) - { - crit = -L; - activeSet = find(alpha < alpha_threshold); - // Prune out the inactive basis function. This procedure speeds up - // the algorithm. - subPhi = phi.submat(activeSet, allCols); - - // Compute the posterior statistics. - matA = diagmat(alpha.elem(activeSet)); - matCovariance = inv(matA - + (subPhi - * subPhi.t()) - * beta); - - this->omega = (matCovariance - * subPhi - * t.t()) * beta; - - // Update the alpha_i. - for (size_t k=0; kactiveSet.size(); k++) - { - ind_act = activeSet[k]; - gammai(ind_act) = 1 - matCovariance(k, k) * alpha(ind_act); - - alpha(ind_act) = gammai(ind_act) - / (omega(k) * omega(k)); - } - - // Update beta. - temp = t - omega.t() * subPhi; - beta = (n - sum(gammai.elem(activeSet))) / dot(temp, temp); - - // Comptute the stopping criterion. - L = norm(omega); - crit = abs(crit + L) / L; - i++; - } -} - - -template -void RVMR::Predict(const arma::mat& points, - arma::rowvec& predictions) const -{ - arma::mat X; - // Manage the kernel. - if (this->ardRegression == false) - applyKernel(this->phi, points, X); - else - X = points; - - arma::uvec allCols(X.n_cols); - for (size_t i=0; i < X.n_cols; i++) {allCols[i] = i;} - - // Center and normalize the points before applying the model. - X.each_col() -= this->data_offset; - X.each_col() /= this->data_scale; - predictions = this->omega.t() * X.submat(this->activeSet, allCols) - + this->responses_offset; -} - - -template -void RVMR::Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const -{ - arma::mat X; - // Manage the kernel. - if (this->ardRegression == false) - applyKernel(this->phi, points, X); - else - X = points; - - arma::uvec allCols(X.n_cols); - for (size_t i=0; i < X.n_cols; i++) {allCols[i] = i;} - - // Center and normalize the points before applying the model. - X.each_col() -= this->data_offset; - X.each_col() /= this->data_scale; - predictions = this->omega.t() * X.submat(this->activeSet, allCols) - + this->responses_offset; - - // Comptute the standard deviations - arma::mat O(X.n_cols, X.n_cols); - O = X.submat(this->activeSet, allCols).t() - * this->matCovariance - * X.submat(this->activeSet, allCols); - std = sqrt(diagvec(1/this->beta + O).t()); -} - - -template -double RVMR::Rmse(const arma::mat& data, - const arma::rowvec& responses) const -{ - arma::rowvec predictions; - this->Predict(data, predictions); - return sqrt( - mean( - square(responses - predictions))); -} - - -template -arma::vec RVMR::getCoefs() const -{ - // Get the size of the full solution with the offset. - arma::colvec coefs = arma::zeros(this->data_offset.size()); - // omega[i] = 0 for the inactive basis functions - - // Now reconstruct the full solution. - for (size_t i=0; i < this->activeSet.size(); i++) - { - coefs[this->activeSet[i]] = this->omega[i]; - } - return coefs; -} - - -template -void RVMR::applyKernel(const arma::mat& X, - const arma::mat& Y, - arma::mat& gramMatrix) const { - - // Check if the dimensions are consistent. - if (X.n_rows != Y.n_rows) - { - std::cout << "error gramm" << std::endl; - throw std::invalid_argument("Number of features not consistent"); - } - - gramMatrix = arma::zeros(X.n_cols, Y.n_cols); - arma::colvec xi = arma::zeros(X.n_rows); - arma::colvec yj = arma::zeros(X.n_rows); - - for (size_t i=0; i < X.n_cols; i++) - { - xi = X.col(i); - for (size_t j=0; j < Y.n_cols; j++) - { - yj = Y.col(j); - gramMatrix(i, j) = this->kernel.Evaluate(xi, yj); - } - } -} - -} // namespace rvmr; -#endif diff --git a/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp b/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp deleted file mode 100644 index 10628fd0ca..0000000000 --- a/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -// Includes all relevant components of mlpack. - -#include -#include - -#include -#include -#include -#include - -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE Mytest -#include - - -#include "rvmr.hpp" - -using namespace mlpack; -using namespace rvmr; - - -BOOST_AUTO_TEST_CASE(RVMegressionTest) -{ - // First, load the data. - arma::mat Xtrain, Xtest; - arma::rowvec ytrain, ytest; - double RMSETRAIN = 0.112415, RMSETEST = 0.171325; - - - std::cout<< "Synthetic dataset.\n" - << "Only the first ten features are non equal to 0." - << std::endl; - data::Load("./data/synth_train.csv", Xtrain, false, true); - data::Load("./data/synth_test.csv", Xtest, false, true); - data::Load("./data/synth_y_train.csv", ytrain, false, true); - data::Load("./data/synth_y_test.csv", ytest, false, true); - - // Instanciate and train the estimator - RVMR estimator(true, false); - estimator.Train(Xtrain, ytrain); - - // Check if the RMSE are still equal to the previously fixed values - BOOST_REQUIRE_SMALL(estimator.Rmse(Xtrain,ytrain) - RMSETRAIN, 0.05); - BOOST_REQUIRE_SMALL(estimator.Rmse(Xtest,ytest) - RMSETEST, 0.05); - - //FIX ME TRain a LARS estimator - arma::vec predTestLars, solution; - regression::LARS lars(true); - lars.Train(Xtrain, ytrain.t(), solution); - lars.Predict(Xtest, predTestLars); - predTestLars.print(); - arma::rowvec predTestRvm; - estimator.Predict(Xtest, predTestRvm); - std::cout << "\n" << std::endl; - predTestRvm.print(); - std::cout << "end of the code" << std::endl; -} diff --git a/src/mlpack/methods/rvm_regression/utils.hpp b/src/mlpack/methods/rvm_regression/utils.hpp deleted file mode 100644 index 0ccdeee383..0000000000 --- a/src/mlpack/methods/rvm_regression/utils.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file utils.hpp - * @ _____ - * - * Definition of some usefull function for preprocess the data -**/ - -#ifndef TATON_UTILS_HPP -#define TATON_UTILS_HPP - -#include - -typedef double (*kernel)(arma::mat, arma::mat, double); - -/* - * Center and normalize the data. The last four arguments - * allow future modifation of new points. - * - * @param data Design matrix in column-major format, dim(P,N). - * @param responses A vector of targets. - * @param fit_interpept If true data will be centred according to the points. - * @param fit_interpept If true data will be scales by the standard deviations - * of the features computed according to the points. - * @param data_proc data processed, dim(N,P). - * @param responses_proc responses processed, dim(N). - * @param data_offset Mean vector of the design matrix according to the - * points, dim(P). - * @param data_scale Vector containg the standard deviations of the features - * dim(P). - * @param reponses_offset Mean of responses. - */ -void preprocess_data(const arma::mat& data, - const arma::rowvec& responses, - const bool fit_intercept, - const bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset); - -/* - * Compute gram matrix between two matrices X and Y. - * - * @param X Matrice dim(p,n1). - * @param Y Matrice dim(p,n2). - * @param kernelFunction Function pointer toward a kernel function. - * Available : linear, rbf. - * @param gamma Length scale parameter of the rbf kernel. - */ -void gramMatrix(const arma::mat& X, - const arma::mat& Y, - arma::mat& gramMatrix, - double (*kernelFunction)(arma::colvec&, arma::colvec&, double), - double gamma); - -/* - * Compute the Radial Basis Function between two vectors. - * - * @param x Vector. - * @param y Vector. - * @param gamma Length scale parameter of the rbf kernel. If gamma - * @return rbf Value of the kernel function. -*/ -double rbf(arma::colvec& x, - arma::colvec& y, - double gamma); - -/* - * Compute the linear kernel function between two vectors. - * - * @param x Vector. - * @param y Vector. - * @param gamma Length scale parameter of the rbf kernel. If gamma - * @return linear Value of the kernel function. -*/ -double linear(arma::colvec& x, - arma::colvec& y, - double gamma); - - - -#endif diff --git a/src/mlpack/tests/rvm_regression_test.cpp b/src/mlpack/tests/rvm_regression_test.cpp deleted file mode 100644 index d3fda17de3..0000000000 --- a/src/mlpack/tests/rvm_regression_test.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -// Includes all relevant components of mlpack. - -#include -#include - -#include -#include - -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE Mytest -#include - - -#include "rvm_regression.hpp" - -using namespace mlpack; -using namespace rvmr; - - -BOOST_AUTO_TEST_CASE(RVMRegressionTest) -{ - // First, load the data. - arma::mat Xtrain, Xtest; - arma::rowvec ytrain, ytest; - - // Instanciate and train the estimator - RVMR estimator(true, false); - estimator.Train(Xtrain, ytrain); - - // Check if the RMSE are still equal to the previously fixed values - BOOST_REQUIRE(true); -} From e86b1b3f7105c091a860bfb8348bce1d6b07af9a Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 19 May 2020 11:21:37 +0200 Subject: [PATCH 148/297] Revert "Add Relevance Vector Machine for regression." This reverts commit daab1ead13748cdef6a785504932ea59e5baf46a. --- .../methods/rvm_regression/CMakeLists.txt | 19 -- .../methods/rvm_regression/CMakeLists.txt~ | 19 -- .../methods/rvm_regression/rvm_regression.hpp | 182 ------------ .../rvm_regression/rvm_regression_impl.hpp | 267 ------------------ .../rvm_regression/rvm_regression_test.cpp | 58 ---- src/mlpack/methods/rvm_regression/utils.hpp | 83 ------ src/mlpack/tests/rvm_regression_test.cpp | 33 --- 7 files changed, 661 deletions(-) delete mode 100644 src/mlpack/methods/rvm_regression/CMakeLists.txt delete mode 100644 src/mlpack/methods/rvm_regression/CMakeLists.txt~ delete mode 100644 src/mlpack/methods/rvm_regression/rvm_regression.hpp delete mode 100644 src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp delete mode 100644 src/mlpack/methods/rvm_regression/rvm_regression_test.cpp delete mode 100644 src/mlpack/methods/rvm_regression/utils.hpp delete mode 100644 src/mlpack/tests/rvm_regression_test.cpp diff --git a/src/mlpack/methods/rvm_regression/CMakeLists.txt b/src/mlpack/methods/rvm_regression/CMakeLists.txt deleted file mode 100644 index 9849f16af3..0000000000 --- a/src/mlpack/methods/rvm_regression/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Define the files we need to compile -# Anything not in this list will not be compiled into the output library -set(SOURCES - rvm_regression.hpp - rvm_regression_impl.hpp - rvm_regression.cpp -) - -# add directory name to sources -set(DIR_SRCS) -foreach(file ${SOURCES}) - set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) -endforeach() -# append sources (with directory name) to list of all mlpack sources (used at the parent scope) -set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - -add_cli_executable(rvm_regression) -add_python_binding(rvm_regression) -add_markdown_docs(rvm_regression "cli;python" "regression") diff --git a/src/mlpack/methods/rvm_regression/CMakeLists.txt~ b/src/mlpack/methods/rvm_regression/CMakeLists.txt~ deleted file mode 100644 index 9b03b83136..0000000000 --- a/src/mlpack/methods/rvm_regression/CMakeLists.txt~ +++ /dev/null @@ -1,19 +0,0 @@ -# Define the files we need to compile -# Anything not in this list will not be compiled into the output library -set(SOURCES - bayesian_linear_regression.hpp - bayesian_linear_regression_impl.hpp - bayesian_linear_regression.cpp -) - -# add directory name to sources -set(DIR_SRCS) -foreach(file ${SOURCES}) - set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) -endforeach() -# append sources (with directory name) to list of all mlpack sources (used at the parent scope) -set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - -add_cli_executable(bayesian_linear_regression) -add_python_binding(bayesian_linear_regression) -add_markdown_docs(bayesian_linear_regression "cli;python" "regression") diff --git a/src/mlpack/methods/rvm_regression/rvm_regression.hpp b/src/mlpack/methods/rvm_regression/rvm_regression.hpp deleted file mode 100644 index 1ac4190959..0000000000 --- a/src/mlpack/methods/rvm_regression/rvm_regression.hpp +++ /dev/null @@ -1,182 +0,0 @@ -/** - * @file rvmr.hpp - * @ Clement Mercier - * - * Definition of the RVMR class, which performs the - * Relevance Vector Machine for regression -**/ -#ifndef TATON_RVMR_HPP -#define TATON_RVMR_HPP - -#include -#include "utils.hpp" - -namespace rvmr { - -template -class RVMR -{ -public: - - - /** - * Set the parameters of the RVMR (Relevance Vector Machine for regression) - * object for a given kernel. There are numerous available kernels in - * the mlpack::kernel namespace. - * Regulariation parameters are automaticaly set to their optimal values by - * maximizing the marginal likelihood. Optimization is done by Evidence - * Maximization. - * @param kernel Kernel to be used for computation. - * @param fitIntercept Whether or not center the data according to the * - * examples. - * @param normalize Whether or to normalize the data according to the - * standard deviation of each feature. - **/ - RVMR(const KernelType& kernel, - const bool fitIntercept, - const bool normalize); - - /** - * Set the parameters of the ARD regression (Automatic Relevance Determination) - * object without any kernel. The class Performs a linear regression with an ARD prior promoting - * sparsity in the final solution. - * Regulariation parameters are automaticaly set to their optimal values by - * the maximmization of the marginal likelihood. Optimization is done by - * Evidence Maximization. - * ARD regression is computed whatever the kernel type given for the - * initalization. - * - * @param fitIntercept Whether or not center the data according to the - * examples. - * @param normalize Whether or to normalize the data according to the - * standard deviation of each feature. - **/ - RVMR(const bool fitIntercept = true, - const bool normalize = false); - - - /** - * Run Relevance Vector Machine for regression. The input matrix - * (like all mlpack matrices) should be - * column-major -- each column is an observation and each row is - * a dimension. - * - * @param data Column-major input data (or row-major input data if rowMajor = - * true). - * @param responses Vector of targets. - **/ - void Train(const arma::mat& data, - const arma::rowvec& responses); - - /** - * Predict \f$\hat{y}_{i}\f$ for each data point in the given data matrix using the - * currently-trained RVM model. Only the coefficients of the active basis - * funcions are used for prediction. This allows fast predictions. - * @param points The data points to apply the model. - * @param predictions y, which will contained calculated values on completion. - */ - void Predict(const arma::mat& points, - arma::rowvec& predictions) const; - - /** - * Predict \f$\hat{y}_{i}\f$ and the standard deviation of the predictive posterior - * distribution for each data point in the given data matrix using the - * currently-trained RVM model. Only the coefficients of the active basis - * funcions are used for prediction. This allows fast predictions. - * @param points The data points to apply the model. - * @param predictions y, which will contained calculated values on completion. - * @param std Standard deviations of the predictions. - */ - void Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const; - - /** - * Apply the kernel function between the column vectors of two matrices - * X and Y. If X=Y this function comptutes the Gramian matrix. - * @param X Matrix of dimension \f$ M \times N1 \f$. - * @param Y Matrix of dimension \f$ M \times N2 \f$. - * @param gramMatrix of dimension \f$N1 \times N2\f$. Elements are equal - * to kernel.Evaluate(\f$ x_{i} \f$,\f$ y_{j} \f$). - **/ - void applyKernel(const arma::mat& X, - const arma::mat& Y, - arma::mat& gramMatrix) const; - - - /** - * Compute the Root Mean Square Error - * between the predictions returned by the model - * and the true repsonses. - * @param Points Data points to predict. - * @param responses A vector of targets. - * @return RMSE - **/ - double Rmse(const arma::mat& data, - const arma::rowvec& responses) const; - - /** - * Get the coefficents of the full solution vector. - * The 0 are associated to the inactive basis functions. - **/ - arma::vec getCoefs() const; - - /** - * Get the precesion (or inverse variance) beta of the model. - * @return \f$ \beta \f$ - **/ - inline double getBeta() const {return this->beta;} - - /** - * Get the estimated variance. - * @return 1.0 / \f$ \beta \f$ - **/ - inline double getVariance() const {return 1.0 / this->getBeta();} - - - /** - * Get the indices of the active basis functions. - * - * @return activeSet - **/ - inline arma::uvec getActiveSet() const {return this->activeSet;} - - -private: - //! Center the data if true. - bool fitIntercept; - //! Scale the data by standard deviations if true. - bool normalize; - //! Mean vector computed over the points. - arma::colvec data_offset; - //! Std vector computed over the points. - arma::colvec data_scale; - //! Mean of the response vector computed over the points. - double responses_offset; - //! alpha_threshold limit to prune the basis functions. - float alpha_threshold; - //! kernel Kernel used. - KernelType kernel; - //! Indicates if ARD regression mode is used. - bool ardRegression; - //! Kernel length scale. - double gamma; - //! Train database. - arma::mat phi; - //! Precision of the prior pdfs (independant gaussian). - arma::rowvec alpha; - //! Noise inverse variance. - double beta; - //! Solution vector. - arma::colvec omega; - //! Coavriance matrix of the solution vector omega. - arma::mat matCovariance; - //! activeSetive Indices of active basis functions. - arma::uvec activeSet; - -}; -} // namespace rvmr -// include implementation. -#include "rvmr_impl.hpp" - -#endif diff --git a/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp b/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp deleted file mode 100644 index 8b1b60ab29..0000000000 --- a/src/mlpack/methods/rvm_regression/rvm_regression_impl.hpp +++ /dev/null @@ -1,267 +0,0 @@ -/** - * @file rvmr.cpp - * @author Clement Mercier - * - * Implementation of the Relevance Vector Machine. - * - * 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 TATON_RVMR_IMPL_HPP -#define TATON_RVMR_IMPL_HPP - -#include "rvmr.hpp" - -using namespace mlpack; -namespace rvmr { - -template -RVMR::RVMR(const KernelType& kernel, - const bool fitIntercept, - const bool normalize) : - - kernel(kernel), - fitIntercept(fitIntercept), - normalize(normalize), - ardRegression(false) { - - std::cout << "RVMR_kernel_mlpack(fitIntercept=" - << this->fitIntercept - << ", normalize=" - << this->normalize - << ")" - << std::endl; - } - - template - RVMR::RVMR(const bool fitIntercept, - const bool normalize) : - fitIntercept(fitIntercept), - normalize(normalize), - kernel(kernel::LinearKernel()), - ardRegression(true) { - - std::cout << "RVMR_ARD_Regresion(fitIntercept=" - << this->fitIntercept - << ", normalize=" - << this->normalize - << ")" - << std::endl; - } - -template -void RVMR::Train(const arma::mat& data, - const arma::rowvec& responses) -{ - arma::mat phi; - arma::rowvec t; - - // Manage the kernel. - if (this->ardRegression == false) - { - // We must keep the original training data for future predictions. - this->phi = data; - applyKernel(data, data, phi); - - //Preprocess the data. Center and normalize. - preprocess_data(phi, - responses, - this->fitIntercept, - this->normalize, - phi, - t, - this->data_offset, - this->data_scale, - this->responses_offset); - } - - else - { - //Preprocess the data. Center and normalize. - preprocess_data(data, - responses, - this->fitIntercept, - this->normalize, - phi, - t, - this->data_offset, - this->data_scale, - this->responses_offset); - } - - unsigned short p = phi.n_rows, n = phi.n_cols; - // Initialize the hyperparameters and - // begin with an infinitely broad prior. - this->alpha_threshold = 1e4; - this->alpha = arma::ones(p) * 1e-6; - this->beta = 1 / (arma::var(t) * 0.1); - - // Loop variables. - double tol = 1e-5; - double L = 1.0; - double crit = 1.0; - unsigned short nIterMax = 50; - unsigned short i = 0; - unsigned short ind_act; - - arma::rowvec gammai = arma::zeros(p); - arma::mat matA; - arma::rowvec temp(n); - arma::mat subPhi; - // Initiaze a vector of all the indices from the first - // to the last point. - arma::uvec allCols(n); - for (size_t i=0; i < n; i++) {allCols(i) = i;} - - while ((crit > tol) && (i < nIterMax)) - { - crit = -L; - activeSet = find(alpha < alpha_threshold); - // Prune out the inactive basis function. This procedure speeds up - // the algorithm. - subPhi = phi.submat(activeSet, allCols); - - // Compute the posterior statistics. - matA = diagmat(alpha.elem(activeSet)); - matCovariance = inv(matA - + (subPhi - * subPhi.t()) - * beta); - - this->omega = (matCovariance - * subPhi - * t.t()) * beta; - - // Update the alpha_i. - for (size_t k=0; kactiveSet.size(); k++) - { - ind_act = activeSet[k]; - gammai(ind_act) = 1 - matCovariance(k, k) * alpha(ind_act); - - alpha(ind_act) = gammai(ind_act) - / (omega(k) * omega(k)); - } - - // Update beta. - temp = t - omega.t() * subPhi; - beta = (n - sum(gammai.elem(activeSet))) / dot(temp, temp); - - // Comptute the stopping criterion. - L = norm(omega); - crit = abs(crit + L) / L; - i++; - } -} - - -template -void RVMR::Predict(const arma::mat& points, - arma::rowvec& predictions) const -{ - arma::mat X; - // Manage the kernel. - if (this->ardRegression == false) - applyKernel(this->phi, points, X); - else - X = points; - - arma::uvec allCols(X.n_cols); - for (size_t i=0; i < X.n_cols; i++) {allCols[i] = i;} - - // Center and normalize the points before applying the model. - X.each_col() -= this->data_offset; - X.each_col() /= this->data_scale; - predictions = this->omega.t() * X.submat(this->activeSet, allCols) - + this->responses_offset; -} - - -template -void RVMR::Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const -{ - arma::mat X; - // Manage the kernel. - if (this->ardRegression == false) - applyKernel(this->phi, points, X); - else - X = points; - - arma::uvec allCols(X.n_cols); - for (size_t i=0; i < X.n_cols; i++) {allCols[i] = i;} - - // Center and normalize the points before applying the model. - X.each_col() -= this->data_offset; - X.each_col() /= this->data_scale; - predictions = this->omega.t() * X.submat(this->activeSet, allCols) - + this->responses_offset; - - // Comptute the standard deviations - arma::mat O(X.n_cols, X.n_cols); - O = X.submat(this->activeSet, allCols).t() - * this->matCovariance - * X.submat(this->activeSet, allCols); - std = sqrt(diagvec(1/this->beta + O).t()); -} - - -template -double RVMR::Rmse(const arma::mat& data, - const arma::rowvec& responses) const -{ - arma::rowvec predictions; - this->Predict(data, predictions); - return sqrt( - mean( - square(responses - predictions))); -} - - -template -arma::vec RVMR::getCoefs() const -{ - // Get the size of the full solution with the offset. - arma::colvec coefs = arma::zeros(this->data_offset.size()); - // omega[i] = 0 for the inactive basis functions - - // Now reconstruct the full solution. - for (size_t i=0; i < this->activeSet.size(); i++) - { - coefs[this->activeSet[i]] = this->omega[i]; - } - return coefs; -} - - -template -void RVMR::applyKernel(const arma::mat& X, - const arma::mat& Y, - arma::mat& gramMatrix) const { - - // Check if the dimensions are consistent. - if (X.n_rows != Y.n_rows) - { - std::cout << "error gramm" << std::endl; - throw std::invalid_argument("Number of features not consistent"); - } - - gramMatrix = arma::zeros(X.n_cols, Y.n_cols); - arma::colvec xi = arma::zeros(X.n_rows); - arma::colvec yj = arma::zeros(X.n_rows); - - for (size_t i=0; i < X.n_cols; i++) - { - xi = X.col(i); - for (size_t j=0; j < Y.n_cols; j++) - { - yj = Y.col(j); - gramMatrix(i, j) = this->kernel.Evaluate(xi, yj); - } - } -} - -} // namespace rvmr; -#endif diff --git a/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp b/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp deleted file mode 100644 index 10628fd0ca..0000000000 --- a/src/mlpack/methods/rvm_regression/rvm_regression_test.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -// Includes all relevant components of mlpack. - -#include -#include - -#include -#include -#include -#include - -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE Mytest -#include - - -#include "rvmr.hpp" - -using namespace mlpack; -using namespace rvmr; - - -BOOST_AUTO_TEST_CASE(RVMegressionTest) -{ - // First, load the data. - arma::mat Xtrain, Xtest; - arma::rowvec ytrain, ytest; - double RMSETRAIN = 0.112415, RMSETEST = 0.171325; - - - std::cout<< "Synthetic dataset.\n" - << "Only the first ten features are non equal to 0." - << std::endl; - data::Load("./data/synth_train.csv", Xtrain, false, true); - data::Load("./data/synth_test.csv", Xtest, false, true); - data::Load("./data/synth_y_train.csv", ytrain, false, true); - data::Load("./data/synth_y_test.csv", ytest, false, true); - - // Instanciate and train the estimator - RVMR estimator(true, false); - estimator.Train(Xtrain, ytrain); - - // Check if the RMSE are still equal to the previously fixed values - BOOST_REQUIRE_SMALL(estimator.Rmse(Xtrain,ytrain) - RMSETRAIN, 0.05); - BOOST_REQUIRE_SMALL(estimator.Rmse(Xtest,ytest) - RMSETEST, 0.05); - - //FIX ME TRain a LARS estimator - arma::vec predTestLars, solution; - regression::LARS lars(true); - lars.Train(Xtrain, ytrain.t(), solution); - lars.Predict(Xtest, predTestLars); - predTestLars.print(); - arma::rowvec predTestRvm; - estimator.Predict(Xtest, predTestRvm); - std::cout << "\n" << std::endl; - predTestRvm.print(); - std::cout << "end of the code" << std::endl; -} diff --git a/src/mlpack/methods/rvm_regression/utils.hpp b/src/mlpack/methods/rvm_regression/utils.hpp deleted file mode 100644 index 0ccdeee383..0000000000 --- a/src/mlpack/methods/rvm_regression/utils.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @file utils.hpp - * @ _____ - * - * Definition of some usefull function for preprocess the data -**/ - -#ifndef TATON_UTILS_HPP -#define TATON_UTILS_HPP - -#include - -typedef double (*kernel)(arma::mat, arma::mat, double); - -/* - * Center and normalize the data. The last four arguments - * allow future modifation of new points. - * - * @param data Design matrix in column-major format, dim(P,N). - * @param responses A vector of targets. - * @param fit_interpept If true data will be centred according to the points. - * @param fit_interpept If true data will be scales by the standard deviations - * of the features computed according to the points. - * @param data_proc data processed, dim(N,P). - * @param responses_proc responses processed, dim(N). - * @param data_offset Mean vector of the design matrix according to the - * points, dim(P). - * @param data_scale Vector containg the standard deviations of the features - * dim(P). - * @param reponses_offset Mean of responses. - */ -void preprocess_data(const arma::mat& data, - const arma::rowvec& responses, - const bool fit_intercept, - const bool normalize, - arma::mat& data_proc, - arma::rowvec& responses_proc, - arma::colvec& data_offset, - arma::colvec& data_scale, - double& responses_offset); - -/* - * Compute gram matrix between two matrices X and Y. - * - * @param X Matrice dim(p,n1). - * @param Y Matrice dim(p,n2). - * @param kernelFunction Function pointer toward a kernel function. - * Available : linear, rbf. - * @param gamma Length scale parameter of the rbf kernel. - */ -void gramMatrix(const arma::mat& X, - const arma::mat& Y, - arma::mat& gramMatrix, - double (*kernelFunction)(arma::colvec&, arma::colvec&, double), - double gamma); - -/* - * Compute the Radial Basis Function between two vectors. - * - * @param x Vector. - * @param y Vector. - * @param gamma Length scale parameter of the rbf kernel. If gamma - * @return rbf Value of the kernel function. -*/ -double rbf(arma::colvec& x, - arma::colvec& y, - double gamma); - -/* - * Compute the linear kernel function between two vectors. - * - * @param x Vector. - * @param y Vector. - * @param gamma Length scale parameter of the rbf kernel. If gamma - * @return linear Value of the kernel function. -*/ -double linear(arma::colvec& x, - arma::colvec& y, - double gamma); - - - -#endif diff --git a/src/mlpack/tests/rvm_regression_test.cpp b/src/mlpack/tests/rvm_regression_test.cpp deleted file mode 100644 index d3fda17de3..0000000000 --- a/src/mlpack/tests/rvm_regression_test.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -// Includes all relevant components of mlpack. - -#include -#include - -#include -#include - -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE Mytest -#include - - -#include "rvm_regression.hpp" - -using namespace mlpack; -using namespace rvmr; - - -BOOST_AUTO_TEST_CASE(RVMRegressionTest) -{ - // First, load the data. - arma::mat Xtrain, Xtest; - arma::rowvec ytrain, ytest; - - // Instanciate and train the estimator - RVMR estimator(true, false); - estimator.Train(Xtrain, ytrain); - - // Check if the RMSE are still equal to the previously fixed values - BOOST_REQUIRE(true); -} From 80ce046bb9f18c780e3b755c7f725c8b904c9dd4 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 19 May 2020 11:38:32 +0200 Subject: [PATCH 149/297] Revert "Modification of the CMakeLists.txt for rmv regression." This reverts commit 4efb8b6730875bcf058f9f810e655d69fbc44f80. --- src/mlpack/methods/CMakeLists.txt | 1 - src/mlpack/tests/CMakeLists.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/src/mlpack/methods/CMakeLists.txt b/src/mlpack/methods/CMakeLists.txt index 3674c4de15..d548d9c769 100644 --- a/src/mlpack/methods/CMakeLists.txt +++ b/src/mlpack/methods/CMakeLists.txt @@ -46,7 +46,6 @@ set(DIRS rann regularized_svd reinforcement_learning - rvm_regression softmax_regression sparse_autoencoder sparse_coding diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 6c91567bc6..d9208bf789 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -92,7 +92,6 @@ add_executable(mlpack_test recurrent_network_test.cpp regularized_svd_test.cpp reward_clipping_test.cpp - rvm_regression_test.cpp rl_components_test.cpp serialization.cpp serialization.hpp From 0d1fe0413f1a631f5ef9be6889d49710f318bc3c Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:20:43 +0200 Subject: [PATCH 150/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 254f9c1fff..ef4f576873 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -46,7 +46,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, dataOffset, dataScale); - if (arma::eig_sym(eigval, V, arma::symmatu(phi * phi.t())) == false) + if (!arma::eig_sym(eigval, V, arma::symmatu(phi * phi.t()))) { Log::Warn << "BayesianLinearRegression::Train(): Eigendecomposition " << "of covariance failed!" @@ -161,4 +161,3 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, return responsesOffset; } - From 083cb402f855dc6bc1b19389e5829542918d0328 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:20:55 +0200 Subject: [PATCH 151/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index ef4f576873..c56be14a36 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -89,7 +89,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, crit = std::abs(deltaAlpha / alpha + deltaBeta / beta); i++; } - // Compute the covariance matrice for the uncertaities later. + // Compute the covariance matrix for the uncertainties later. matCovariance = std::move(V); matCovariance *= diagmat(1 / (beta * eigval + alpha)); matCovariance *= Vinv; From 240b2ed15f472c4b3e7d1fb707f40ac0c5c5b0f9 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:21:37 +0200 Subject: [PATCH 152/297] Update src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt Co-authored-by: Ryan Curtin --- src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt index 9b03b83136..59c71a80fa 100644 --- a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt +++ b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt @@ -16,4 +16,5 @@ set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) add_cli_executable(bayesian_linear_regression) add_python_binding(bayesian_linear_regression) -add_markdown_docs(bayesian_linear_regression "cli;python" "regression") +add_julia_binding(bayesian_linear_regression) +add_markdown_docs(bayesian_linear_regression "cli;python;julia" "regression") From 28a048721c017416288dddf9b51e30f5c29c8bf0 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:22:00 +0200 Subject: [PATCH 153/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index c56be14a36..479401c213 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -112,7 +112,7 @@ void BayesianLinearRegression::Predict(const arma::mat& points, arma::rowvec& predictions, arma::rowvec& std) const { - // Center and scaleData the points before applying the model. + // Center and scale the points before applying the model. const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; predictions = omega.t() * X; predictions += responsesOffset; From 0e37aeeca947b1127ac787ea5982a2e93ecece43 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:22:57 +0200 Subject: [PATCH 154/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 9127e088cf..f8bd08e906 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -12,8 +12,8 @@ #include -namespace mlpack{ -namespace regression{ +namespace mlpack { +namespace regression { /** * A Bayesian approach to the maximum likelihood estimation of the parameters From be0d3d6a446d794b4c8898ef9a6c0f585775fd05 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:23:14 +0200 Subject: [PATCH 155/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index f8bd08e906..9c20e1d01a 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -106,9 +106,9 @@ class BayesianLinearRegression * stable. */ BayesianLinearRegression(const bool centerData = true, - const bool scaleData = false, - const int nIterMax = 50, - const double tol = 1e-4); + const bool scaleData = false, + const int nIterMax = 50, + const double tol = 1e-4); /** * Run BayesianLinearRegression. The input matrix (like all mlpack matrices) should be From 21d96818e968ba6d24ca065bfe1bac236ca42d74 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:23:33 +0200 Subject: [PATCH 156/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 9c20e1d01a..a71a343922 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -159,8 +159,8 @@ class BayesianLinearRegression const arma::rowvec& responses) const; /** - * Center and scaleData the data. The last four arguments - * allow future modifation of new points. + * Center and scale the data. The last four arguments + * allow future modification of new points. * * @param data Design matrix in column-major format, dim(P,N). * @param responses A vector of targets. From 0ca2780e006ee34dac90a30e03732aae6eee8f58 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:24:01 +0200 Subject: [PATCH 157/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index a71a343922..433201d812 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -199,7 +199,7 @@ class BayesianLinearRegression double Alpha() const { return alpha; } /** - * Get the precesion (or inverse variance) beta of the model. + * Get the precision (or inverse variance) beta of the model. * * @return \f$ \beta \f$ */ From 9e3e07bd3dbf0c5abe81c5d32894d5b86c685dd1 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:24:25 +0200 Subject: [PATCH 158/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index a1262c2a36..c65f2ba2ba 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -32,7 +32,7 @@ PROGRAM_INFO("BayesianLinearRegression", "An implementation of the bayesian linear regression, also known" "as the Bayesian linear regression.\n " "This is a probabilistic view and implementation of the linear regression. " - "Final solution is obtained by comptuting a posterior distribution from " + "The final solution is obtained by computing a posterior distribution from " "gaussian likelihood and a zero mean gaussian isotropic prior distribution " "on the solution. " "\n" From d38bac2ccb582a0d4aedd6a54bbf2851b98944cd Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:25:25 +0200 Subject: [PATCH 159/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index c65f2ba2ba..0e8ab633e9 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -38,7 +38,7 @@ PROGRAM_INFO("BayesianLinearRegression", "\n" "Optimization is AUTOMATIC and does not require cross validation. " "The optimization is performed by maximization of the evidence function. " - "Parameters are tunned during the maximization of the marginal likelihood. " + "Parameters are tuned during the maximization of the marginal likelihood. " "This procedure includes the Ockham's razor that penalizes over complex " "solutions. " "\n\n" From c115dc86ab01fe5ba466af3dc55296803772a27f Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:25:45 +0200 Subject: [PATCH 160/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 0e8ab633e9..1a0cafdc1e 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -49,7 +49,7 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" "Let X be a matrix where each row is a point and each column is a " "dimension, t is a vector of targets, alpha is the precision of the " - "gaussian prior distribtion of w, and w is solution to determine. " + "gaussian prior distribtion of w, and w is the solution to determine. " "\n\n" "The Bayesian linear regression comptutes the posterior distribution of " "the parameters by the Bayes's rule : " From 4ad323970f389e863fcb34d8a02aa81387fda14d Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:26:02 +0200 Subject: [PATCH 161/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 1a0cafdc1e..be7dac1d9c 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -51,7 +51,7 @@ PROGRAM_INFO("BayesianLinearRegression", "dimension, t is a vector of targets, alpha is the precision of the " "gaussian prior distribtion of w, and w is the solution to determine. " "\n\n" - "The Bayesian linear regression comptutes the posterior distribution of " + "The Bayesian linear regression computes the posterior distribution of " "the parameters by the Bayes's rule : " "\n\n" " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" From b224702729096618deaa3f475da79f3dbe912103 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 20 May 2020 07:28:41 +0200 Subject: [PATCH 162/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index be7dac1d9c..d25ac65459 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -193,9 +193,10 @@ static void mlpackMain() // Save the standard deviation of the test points (one per line). CLI::GetParam("output_std") = std::move(std); } - else + { bayesLinReg->Predict(testPoints, predictions); + } // Save test predictions (one per line). CLI::GetParam("output_predictions") = std::move(predictions); From 1aa4a10808cccc97a0da1e9695ef4cdbababa20e Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 20 May 2020 09:32:05 +0200 Subject: [PATCH 163/297] Inline operations and change variables names. --- .../CMakeLists.txt~ | 19 -- .../bayesian_linear_regression.cpp | 19 +- .../bayesian_linear_regression.cpp~ | 262 ------------------ .../bayesian_linear_regression_main.cpp~ | 202 -------------- 4 files changed, 8 insertions(+), 494 deletions(-) delete mode 100644 src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ delete mode 100644 src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ delete mode 100644 src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ diff --git a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ deleted file mode 100644 index 6145de27a9..0000000000 --- a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt~ +++ /dev/null @@ -1,19 +0,0 @@ -# Define the files we need to compile -# Anything not in this list will not be compiled into the output library -set(SOURCES - bayesian_linear_regression.hpp - bayesian_linear_regression_impl.hpp - bayesian_linear_regression.cpp -) - -# add directory name to sources -set(DIR_SRCS) -foreach(file ${SOURCES}) - set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) -endforeach() -# append sources (with directory name) to list of all mlpack sources (used at the parent scope) -set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - -add_cli_executable(bayesian_ridge) -add_python_binding(bayesian_ridge) -add_markdown_docs(bayesian_ridge "cli;python" "regression") diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 479401c213..75e1914307 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -33,8 +33,8 @@ double BayesianLinearRegression::Train(const arma::mat& data, arma::mat phi; arma::rowvec t; - arma::colvec eigval; - arma::mat V; + arma::colvec eigVal; + arma::mat eigVec; // Preprocess the data. Center and scale. responsesOffset = CenterScaleData(data, @@ -46,7 +46,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, dataOffset, dataScale); - if (!arma::eig_sym(eigval, V, arma::symmatu(phi * phi.t()))) + if (!arma::eig_sym(eigVal, eigVec, arma::symmatu(phi * phi.t()))) { Log::Warn << "BayesianLinearRegression::Train(): Eigendecomposition " << "of covariance failed!" @@ -55,8 +55,8 @@ double BayesianLinearRegression::Train(const arma::mat& data, } // Compute this quantities once and for all. - const arma::mat Vinv = inv(V); - const arma::colvec VinvPhitT = Vinv * phi * t.t(); + const arma::mat eigVecInv = inv(eigVec); + const arma::colvec eigVecInvPhitT = eigVecInv * phi * t.t(); // Initialize the hyperparameters and // begin with an infinitely broad prior. @@ -72,11 +72,10 @@ double BayesianLinearRegression::Train(const arma::mat& data, deltaBeta = -beta; // Update the solution. - omega = 1 / (eigval + (alpha / beta)); - omega = V * diagmat(omega) * VinvPhitT; + omega = eigVec * diagmat(1 / (eigVal + (alpha / beta))) * eigVecInvPhitT; // Update alpha. - gamma = sum(eigval / (alpha / beta + eigval)); + gamma = sum(eigVal / (alpha / beta + eigVal)); alpha = gamma / dot(omega, omega); // Update beta. @@ -90,9 +89,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, i++; } // Compute the covariance matrix for the uncertainties later. - matCovariance = std::move(V); - matCovariance *= diagmat(1 / (beta * eigval + alpha)); - matCovariance *= Vinv; + matCovariance = eigVec * diagmat(1 / (beta * eigVal + alpha)) * eigVecInv; Timer::Stop("bayesian_linear_regression"); diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ deleted file mode 100644 index 1c15c588fb..0000000000 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp~ +++ /dev/null @@ -1,262 +0,0 @@ -/** - * @file bayesian_ridge.cpp - * @author Clement Mercier - * - * Implementation of Bayesian Ridge regression. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#include "bayesian_ridge.hpp" -#include -#include - -using namespace mlpack; -using namespace mlpack::regression; - - -BayesianRidge::BayesianRidge(const bool centerData, - const bool scaleData, - const int nIterMax, - const double tol) : - centerData(centerData), - scaleData(scaleData), - nIterMax(nIterMax), - tol(tol) -{/* Nothing to do */} - -double BayesianRidge::Train(const arma::mat& data, - const arma::rowvec& responses) -{ - Timer::Start("bayesian_ridge_regression"); - - arma::mat phi; - arma::rowvec t; - arma::colvec eigval; - arma::mat eigvec; - arma::colvec eigvali; - - // Preprocess the data. Center and scale. - responsesOffset = CenterScaleData(data, - responses, - centerData, - scaleData, - phi, - t, - dataOffset, - dataScale); - - // Compute this quantities once and for all. - const arma::colvec vecphitT = phi * t.t(); - - // Enforce symmetry of the covariance matrix before eig_sym. - const arma::mat phiphiT = arma::symmatu(phi * phi.t()); - - if (arma::eig_sym(eigval, eigvec, phiphiT) == false) - { - Log::Warn << "BayesianRidge::Train(): Eigendecomposition " - << "of covariance failed!" - << std::endl; - return -1; - } - - // Initialize the hyperparameters and - // begin with an infinitely broad prior. - alpha = 1e-6; - beta = 1 / (var(t) * 0.1); - - unsigned short nIterMax = 50; - unsigned short i = 0; - double deltaAlpha = 1, deltaBeta = 1, crit = 1; - arma::mat matA = arma::eye(data.n_rows, data.n_rows); - - while ((crit > tol) && (i < nIterMax)) - { - deltaAlpha = -alpha; - deltaBeta = -beta; - - // Compute the posterior statistics. - // with inv() - matA.diag().fill(alpha); - // inv is used instead of solve because we need the covariance matrix to - // compute the prediction uncertainties. If solve is used, matCovariance - // must be comptuted at the end of the loop. - matCovariance = inv_sympd(matA + phiphiT * beta); - omega = (matCovariance * vecphitT) * beta; - - // // with solve() - // matA.diag().fill(alpha/ beta); - // omega = solve(matA + phiphiT, vecphitT); - - // Update alpha. - eigvali = eigval * beta; - gamma = sum(eigvali / (alpha + eigvali)); - alpha = gamma / dot(omega.t(), omega); - - // Update beta. - const arma::rowvec temp = t - omega.t() * phi; - beta = (data.n_cols - gamma) / dot(temp, temp); - - // Comptute the stopping criterion. - deltaAlpha += alpha; - deltaBeta += beta; - crit = abs(deltaAlpha / alpha + deltaBeta / beta); - i++; - } - Timer::Stop("bayesian_ridge_regression"); - return Rmse(data, responses); -} - -void BayesianRidge::Predict(const arma::mat& points, - arma::rowvec& predictions) const -{ - // y_hat = w^T * (X - mu) / sigma + y_mean. - predictions = omega.t() * - ((points.each_col() - dataOffset).each_col() / dataScale) + responsesOffset; -} - -void BayesianRidge::Predict(const arma::mat& points, - arma::rowvec& predictions, - arma::rowvec& std) const -{ - // Center and scaleData the points before applying the model. - const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; - predictions = omega.t() * X + responsesOffset; - std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); -} - -double BayesianRidge::Rmse(const arma::mat& data, - const arma::rowvec& responses) const -{ - arma::rowvec predictions; - Predict(data, predictions); - return sqrt(mean(square(responses - predictions))); -} - -double BayesianRidge::CenterScaleData(const arma::mat& data, - const arma::rowvec& responses, - bool centerData, - bool scaleData, - arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale) -{ - // Initialize the offsets to their neutral forms. - dataOffset = arma::zeros(data.n_rows); - dataScale = arma::ones(data.n_rows); - responsesOffset = 0.0; - - if (centerData) - { - dataOffset = mean(data, 1); - responsesOffset = mean(responses); - } - - if (scaleData) - dataScale = stddev(data, 0, 1); - - // Copy data and response before the processing. - dataProc = data; - // Center the data. - dataProc.each_col() -= dataOffset; - // Scale the data. - dataProc.each_col() /= dataScale; - // Center the responses. - responsesProc = responses - responsesOffset; - - return responsesOffset; -} - -// Copy construcor. -BayesianRidge::BayesianRidge(const BayesianRidge& other): - centerData(other.centerData), - scaleData(other.scaleData), - dataOffset(other.dataOffset), - dataScale(other.dataScale), - responsesOffset(other.responsesOffset), - alpha(other.alpha), - beta(other.beta), - gamma(other.gamma), - omega(other.omega), - matCovariance(other.matCovariance) -{/* All is done */} - -// Move constructor. -BayesianRidge::BayesianRidge(BayesianRidge&& other): - centerData(other.centerData), - scaleData(other.scaleData), - dataOffset(std::move(other.dataOffset)), - dataScale(std::move(other.dataScale)), - responsesOffset(other.responsesOffset), - alpha(other.alpha), - beta(other.beta), - gamma(other.gamma), - omega(std::move(other.omega)), - matCovariance(std::move(other.matCovariance)) -{ - // Clear the other object. - if (this != &other) - { - other.centerData = false; - other.scaleData = false; - other.dataOffset.reset(); - other.dataScale.reset(); - other.responsesOffset = 0.0; - other.alpha = 0.0; - other.gamma = 0.0; - other.beta = 0.0; - other.omega.reset(); - other.matCovariance.reset(); - } -} - -BayesianRidge& BayesianRidge::operator=(const BayesianRidge& other) -{ - if (this == &other) - return *this; - - centerData = other.centerData; - scaleData = other.scaleData; - dataOffset = other.dataOffset; - dataScale = other.dataScale; - responsesOffset = other.responsesOffset; - alpha = other.alpha; - gamma = other.gamma; - beta = other.beta; - omega = other.omega; - matCovariance = other.matCovariance; - return *this; -} - -BayesianRidge& BayesianRidge::operator=(BayesianRidge&& other) -{ - if (this != &other) - { - centerData = other.centerData; - scaleData = other.scaleData; - dataOffset = other.dataOffset; - dataScale = other.dataScale; - responsesOffset = other.responsesOffset; - alpha = other.alpha; - gamma = other.gamma; - beta = other.beta; - omega = other.omega; - matCovariance = other.matCovariance; - - // Clear the other object. - other.centerData = false; - other.scaleData = false; - other.dataOffset.reset(); - other.dataScale.reset(); - other.responsesOffset = 0.0; - other.alpha = 0.0; - other.gamma = 0.0; - other.beta = 0.0; - other.omega.reset(); - other.matCovariance.reset(); - } - return *this; -} diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ deleted file mode 100644 index ec41eaa1d8..0000000000 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp~ +++ /dev/null @@ -1,202 +0,0 @@ -/** - * @file bayesian_ridge_main.cpp - * @author Clement Mercier - * - * Executable for BayesianRidge. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#include -#include -#include - -#include "bayesian_linear_regression.hpp" - -using namespace arma; -using namespace std; -using namespace mlpack; -using namespace mlpack::regression; -using namespace mlpack::util; - -PROGRAM_INFO("BayesianRidge", - // Short description. - "An implementation of the bayesian linear regression, also known " - "as the Bayesian Ridge regression. This can train a Bayesian Ridge model " - "and use that model or a pre-trained model to output regression " - "predictions for a test set.", - // Long description. - "An implementation of the bayesian linear regression, also known" - "as the Bayesian Ridge regression.\n " - "This is a probabilistic view and implementation of the Ridge regression. " - "Final solution is obtained by comptuting a posterior distribution from " - "gaussian likelihood and a zero mean gaussian isotropic prior distribution " - "on the solution. " - "\n" - "Optimization is AUTOMATIC and does not require cross validation. " - "The optimization is performed by maximization of the evidence function. " - "Parameters are tunned during the maximization of the marginal likelihood. " - "This procedure includes the Ockham's razor that penalizes over complex " - "solutions. " - "\n\n" - "This program is able to train a Baysian Ridge model or load a " - "model from file, output regression predictions for a test set, and save " - "the trained model to a file. The Bayesian Ridge algorithm is described " - "in more detail below:" - "\n\n" - "Let X be a matrix where each row is a point and each column is a " - "dimension, t is a vector of targets, alpha is the precision of the " - "gaussian prior distribtion of w, and w is solution to determine. " - "\n\n" - "The Bayesian Ridge comptutes the posterior distribution of the parameters " - "by the Bayes's rule : " - "\n\n" - " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" - "\n\n" - "To train a BayesianRidge model, the " + - PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") + - "parameters must be given. The " + PRINT_PARAM_STRING("center") + - "and " + PRINT_PARAM_STRING("scale") + " parameters control the " - "centering and the normalizing options. A trained model can be saved with " - "the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired " - "at all, a model can be passed via the "+ PRINT_PARAM_STRING("input_model")+ - " parameter." - "\n\n" - "The program can also provide predictions for test data using either the " - "trained model or the given input model. Test points can be specified with" - " the " + PRINT_PARAM_STRING("test") + " parameter. Predicted responses " - "to the test points can be saved with the " + - PRINT_PARAM_STRING("output_predictions") + " output parameter. The " - "corresponding standard deviation can be save by precising the " + - PRINT_PARAM_STRING("output_std") + " parameter." - "\n\n" - "For example, the following command trains a model on the data " + - PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + - "with center set to true and scale set to false (so, Bayesian " - "Ridge is being solved, and then the model is saved to " + - PRINT_MODEL("bayesian_ridge_model") + ":" - "\n\n" + - PRINT_CALL("bayesian_ridge", "input", "data", "responses", "responses", - "center", 1, "scale", 0, "output_model", - "bayesian_ridge_model") + - "\n\n" - "The following command uses the " + PRINT_MODEL("bayesian_ridge_model") + - " to provide predicted responses for the data " + PRINT_DATASET("test") + - " and save those responses to " + PRINT_DATASET("test_predictions") + ": " - "\n\n" + - PRINT_CALL("bayesian_ridge", "input_model", "bayesian_ridge_model", "test", - "test", "output_predictions", "test_predictions")); - -PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); - -PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); - -PARAM_MODEL_IN(BayesianRidge, "input_model", "Trained BayesianRidge model " - "to use.", "m"); - -PARAM_MODEL_OUT(BayesianRidge, "output_model", "Output BayesianRidge model.", - "M"); - -PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " - "points).", "t"); - -PARAM_MATRIX_OUT("output_predictions", "If --test_file is specified, this " - "file is where the predicted responses will be saved.", "o"); - -PARAM_MATRIX_OUT("output_std", "If --std_file is specified, this file is where " - "the standard deviations of the predictive distribution will " - "be saved.", "u"); - -PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " - "disable", - "c", - 1); - -PARAM_INT_IN("scale", "Scale each feature by their standard deviations. " - "set to 1 to scale.", - "s", - 0); - -static void mlpackMain() -{ - int center = CLI::GetParam("center"); - int scale = CLI::GetParam("scale"); - - // Check parameters -- make sure everything given makes sense. - RequireOnlyOnePassed({ "input", "input_model" }, true); - if (CLI::HasParam("input")) - { - RequireOnlyOnePassed({ "responses" }, true, "if input data is specified, " - "responses must also be specified"); - } - ReportIgnoredParam({{ "input", false }}, "responses"); - - RequireAtLeastOnePassed({ "output_predictions", "output_model" }, false, - "no results will be saved"); - - // Ignore out_predictions unless test is specified. - ReportIgnoredParam({{ "test", false }}, "output_predictions"); - - BayesianRidge* bayesRidge; - if (CLI::HasParam("input")) - { - Log::Info << "input detected " << std::endl; - // Initialize the object. - bayesRidge = new BayesianRidge(center, scale); - - // Load covariates. We can avoid LARS transposing our data by choosing to - // not transpose this data (that's why we used PARAM_TMATRIX_IN). - mat matX = std::move(CLI::GetParam("input")); - - // Load responses. The responses should be a one-dimensional vector, and it - // seems more likely that these will be stored with one response per line - // (one per row). So we should not transpose upon loading. - mat matY = std::move(CLI::GetParam("responses")); - - // Make sure y is oriented the right way. - if (matY.n_cols == 1) - matY = trans(matY); - if (matY.n_rows > 1) - Log::Fatal << "Only one column or row allowed in responses file!" << endl; - - if (matY.n_elem != matX.n_cols) - Log::Fatal << "Number of responses must be equal to number of rows of X!" - << endl; - - arma::rowvec y = std::move(matY); - arma::rowvec predictionsTrain; - // The Train method is ready to take data in column-major format. - bayesRidge->Train(matX, matY); - } - else // We must have --input_model_file. - { - bayesRidge = CLI::GetParam("input_model"); - } - - if (CLI::HasParam("test")) - { - Log::Info << "Regressing on test points." << endl; - // Load test points. - mat testPoints = std::move(CLI::GetParam("test")); - arma::rowvec predictions; - - if (CLI::HasParam("output_std")) - { - arma::rowvec std; - bayesRidge->Predict(testPoints, predictions, std); - - // Save the standard deviation of the test points (one per line). - CLI::GetParam("output_std") = std::move(std); - } - - else - bayesRidge->Predict(testPoints, predictions); - - // Save test predictions (one per line). - CLI::GetParam("output_predictions") = std::move(predictions); - } - - CLI::GetParam("output_model") = bayesRidge; -} From 3bf6cea01c9373c359543bdd634b2a7df77a74fc Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 20 May 2020 19:04:43 +0200 Subject: [PATCH 164/297] Rename some variables to follow the guidelines. --- .../bayesian_linear_regression.cpp | 13 ++--- .../tests/bayesian_linear_regression_test.cpp | 56 +++++++++---------- .../bayesian_linear_regression_test.cpp | 22 ++++---- 3 files changed, 45 insertions(+), 46 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 75e1914307..3111c45365 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -48,10 +48,8 @@ double BayesianLinearRegression::Train(const arma::mat& data, if (!arma::eig_sym(eigVal, eigVec, arma::symmatu(phi * phi.t()))) { - Log::Warn << "BayesianLinearRegression::Train(): Eigendecomposition " - << "of covariance failed!" - << std::endl; - throw std::runtime_error("eig_sym() failed."); + Log::Fatal << "BayesianLinearRegression::Train(): Eigendecomposition " + << "of covariance failed!"; } // Compute this quantities once and for all. @@ -110,10 +108,11 @@ void BayesianLinearRegression::Predict(const arma::mat& points, arma::rowvec& std) const { // Center and scale the points before applying the model. - const arma::mat X = (points.each_col() - dataOffset).each_col() / dataScale; - predictions = omega.t() * X; + const arma::mat matX = (points.each_col() - dataOffset).each_col() + / dataScale; + predictions = omega.t() * matX; predictions += responsesOffset; - std = sqrt(Variance() + sum((X % (matCovariance * X)), 0)); + std = sqrt(Variance() + sum((matX % (matCovariance * matX)), 0)); } double BayesianLinearRegression::RMSE(const arma::mat& data, diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index b93163398b..70ab673757 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -21,31 +21,31 @@ using namespace mlpack::data; BOOST_AUTO_TEST_SUITE(BayesianLinearRegressionTest); -void GenerateProblem(arma::mat& X, +void GenerateProblem(arma::mat& matX, arma::rowvec& y, size_t nPoints, size_t nDims, float sigma = 0.0) { - X = arma::randn(nDims, nPoints); + matX = arma::randn(nDims, nPoints); arma::colvec omega = arma::randn(nDims); // Compute y and add noise. - y = omega.t() * X + arma::randn(nPoints).t() * sigma; + y = omega.t() * matX + arma::randn(nPoints).t() * sigma; } // Ensure that predictions are close enough to the target // for a free noise dataset. BOOST_AUTO_TEST_CASE(BayesianLinearRegressionRegressionTest) { - arma::mat X; + arma::mat matX; arma::rowvec y, predictions; - GenerateProblem(X, y, 200, 10); + GenerateProblem(matX, y, 200, 10); // Instanciate and train the estimator. BayesianLinearRegression estimator(true); - estimator.Train(X, y); - estimator.Predict(X, predictions); + estimator.Train(matX, y); + estimator.Predict(matX, predictions); // Check the predictions are close enough to the targets in a free noise case. for (size_t i = 0; i < y.size(); i++) @@ -58,15 +58,15 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionRegressionTest) // Verify fitIntercept and normalize equal false do not affect the solution. BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) { - arma::mat X; + arma::mat matX; arma::rowvec y; size_t nDims = 30, nPoints = 100; - GenerateProblem(X, y, nPoints, nDims, 0.5); + GenerateProblem(matX, y, nPoints, nDims, 0.5); BayesianLinearRegression estimator(false, false); - estimator.Train(X, y); + estimator.Train(matX, y); // To be neutral dataOffset must be all 0. BOOST_REQUIRE(sum(estimator.DataOffset()) == 0.0); @@ -81,16 +81,16 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) // Verify that centering and normalization are correct. BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) { - arma::mat X; + arma::mat matX; arma::rowvec y; size_t nDims = 30, nPoints = 100; - GenerateProblem(X, y, nPoints, nDims, 0.5); + GenerateProblem(matX, y, nPoints, nDims, 0.5); BayesianLinearRegression estimator(true, true); - estimator.Train(X, y); + estimator.Train(matX, y); - arma::colvec xMean = arma::mean(X, 1); - arma::colvec xStd = arma::stddev(X, 0, 1); + arma::colvec xMean = arma::mean(matX, 1); + arma::colvec xStd = arma::stddev(matX, 0, 1); double yMean = arma::mean(y); BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataOffset() - xMean)), 1e-6); @@ -101,15 +101,15 @@ BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) // Check that Train() does not fail with two colinear vectors. BOOST_AUTO_TEST_CASE(SingularMatix) { - arma::mat X; + arma::mat matX; arma::rowvec y; - GenerateProblem(X, y, 200, 10); + GenerateProblem(matX, y, 200, 10); // Now the first and the second rows are indentical. - X.row(1) = X.row(0); + matX.row(1) = matX.row(0); BayesianLinearRegression estimator; - double singular = estimator.Train(X, y); + double singular = estimator.Train(matX, y); BOOST_REQUIRE(singular != -1); } @@ -117,34 +117,34 @@ BOOST_AUTO_TEST_CASE(SingularMatix) // estimated predictive variance. BOOST_AUTO_TEST_CASE(PredictiveUncertainties) { - arma::mat X; + arma::mat matX; arma::rowvec y; - GenerateProblem(X, y, 100, 10, 1); + GenerateProblem(matX, y, 100, 10, 1); BayesianLinearRegression estimator(true, true); - estimator.Train(X, y); + estimator.Train(matX, y); arma::rowvec responses, std; - estimator.Predict(X, responses, std); + estimator.Predict(matX, responses, std); const double estStd = sqrt(estimator.Variance()); - for (size_t i = 0; i < X.n_cols; i++) + for (size_t i = 0; i < matX.n_cols; i++) BOOST_REQUIRE(std[i] > estStd); } // Check the solution is equal to the classical ridge. BOOST_AUTO_TEST_CASE(EqualtoRidge) { - arma::mat X; + arma::mat matX; arma::rowvec y; - GenerateProblem(X, y, 100, 10, 1); + GenerateProblem(matX, y, 100, 10, 1); BayesianLinearRegression bayesLinReg(false, false); - bayesLinReg.Train(X, y); + bayesLinReg.Train(matX, y); - LinearRegression classicalRidge(X, + LinearRegression classicalRidge(matX, y, bayesLinReg.Alpha() / bayesLinReg.Beta(), false); diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 284eb29bd1..2d01cc00a0 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -49,11 +49,11 @@ BOOST_FIXTURE_TEST_SUITE(BayesianLinearRegressionMainTest, BRTestFixture); BOOST_AUTO_TEST_CASE(BRCenter0Scale0) { int n = 50, m = 4; - arma::mat X = arma::randu(m, n); - arma::colvec omega = arma::randu(m); - arma::mat y = omega * X; + arma::mat matX = arma::randu(m, n); + arma::rowvec omega = arma::randu(m); + arma::mat y = omega * matX; - SetInputParam("input", std::move(X)); + SetInputParam("input", std::move(matX)); SetInputParam("responses", std::move(y)); SetInputParam("center", 0); @@ -75,18 +75,18 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) { int n = 10, m = 4; - arma::mat X = arma::randu(m, n); - arma::mat Xtest = arma::randu(m, 2 * n); + arma::mat matX = arma::randu(m, n); + arma::mat matXtest = arma::randu(m, 2 * n); const arma::colvec omega = arma::randu(m); - arma::mat y = omega * X; + arma::mat y = omega * matX; BayesianLinearRegression model; - model.Train(X, y); + model.Train(matX, y); arma::rowvec responses; - model.Predict(Xtest, responses); + model.Predict(matXtest, responses); - SetInputParam("input", std::move(X)); + SetInputParam("input", std::move(matX)); SetInputParam("responses", std::move(y)); mlpackMain(); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) SetInputParam("input_model", CLI::GetParam("output_model")); - SetInputParam("test", std::move(Xtest)); + SetInputParam("test", std::move(matXtest)); mlpackMain(); From 8b7b253c1a8212b3250b036c39e6544d955d1047 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 09:17:26 +0200 Subject: [PATCH 165/297] CenterScaleData becomes private. --- .../bayesian_linear_regression.hpp | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 433201d812..f48c0c599e 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -147,9 +147,8 @@ class BayesianLinearRegression arma::rowvec& std) const; /** - * Compute the Root Mean Square Error - * between the predictions returned by the model - * and the true repsonses. + * Compute the Root Mean Square Error between the predictions returned by the + * model and the true repsonses. * * @param Points Data points to predict * @param responses A vector of targets. @@ -158,32 +157,6 @@ class BayesianLinearRegression double RMSE(const arma::mat& data, const arma::rowvec& responses) const; - /** - * Center and scale the data. The last four arguments - * allow future modification of new points. - * - * @param data Design matrix in column-major format, dim(P,N). - * @param responses A vector of targets. - * @param centerData If true data will be centred according to the points. - * @param centerData If true data will be scales by the standard deviations - * of the features computed according to the points. - * @param dataProc data processed, dim(N,P). - * @param responsesProc responses processed, dim(N). - * @param dataOffset Mean vector of the design matrix according to the - * points, dim(P). - * @param dataScale Vector containg the standard deviations of the features - * dim(P). - * @return reponsesOffset Mean of responses. - */ - double CenterScaleData(const arma::mat& data, - const arma::rowvec& responses, - const bool centerData, - const bool scaleData, - arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale); - /** * Get the solution vector * @@ -276,6 +249,33 @@ class BayesianLinearRegression //! Covariance matrix of the solution vector omega. arma::mat matCovariance; + + /** + * Center and scale the data. The last four arguments + * allow future modification of new points. + * + * @param data Design matrix in column-major format, dim(P,N). + * @param responses A vector of targets. + * @param centerData If true data will be centred according to the points. + * @param centerData If true data will be scales by the standard deviations + * of the features computed according to the points. + * @param dataProc data processed, dim(N,P). + * @param responsesProc responses processed, dim(N). + * @param dataOffset Mean vector of the design matrix according to the + * points, dim(P). + * @param dataScale Vector containg the standard deviations of the features + * dim(P). + * @return reponsesOffset Mean of responses. + */ + double CenterScaleData(const arma::mat& data, + const arma::rowvec& responses, + const bool centerData, + const bool scaleData, + arma::mat& dataProc, + arma::rowvec& responsesProc, + arma::colvec& dataOffset, + arma::colvec& dataScale); + }; } // namespace regression } // namespace mlpack From 3f1be30f7e5f7e61051b0f96af6e58afc6313f8e Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 09:28:42 +0200 Subject: [PATCH 166/297] Precise to call Train() before to call Beta(), Variance() and Alpha(). --- .../bayesian_linear_regression.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index f48c0c599e..7c86ff2c1a 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -158,28 +158,30 @@ class BayesianLinearRegression const arma::rowvec& responses) const; /** - * Get the solution vector + * Get the solution vector. * * @return omega Solution vector. */ const arma::colvec& Omega() const { return omega; } /** - * Get the precision (or inverse variance) of the gaussian prior. + * Get the precision (or inverse variance) of the gaussian prior. Train() + * must be called before. * * @return \f$ \alpha \f$ */ double Alpha() const { return alpha; } /** - * Get the precision (or inverse variance) beta of the model. + * Get the precision (or inverse variance) beta of the model. Train() must be + * called before. * * @return \f$ \beta \f$ */ double Beta() const { return beta; } /** - * Get the estimated variance. + * Get the estimated variance. Train() must be called before. * * @return 1.0 / \f$ \beta \f$ */ From 425c184aba627aad1176ea2d1ae32675a0bb65f3 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 10:27:07 +0200 Subject: [PATCH 167/297] Add a comand line example for the uncertainties. --- .../bayesian_linear_regression_main.cpp | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index d25ac65459..d237d39449 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -23,11 +23,9 @@ using namespace mlpack::util; PROGRAM_INFO("BayesianLinearRegression", // Short description. - "An implementation of the bayesian linear regression, also known " - "as the Bayesian linear regression. This can train a Bayesian linear " - "regression model and use that model or a pre-trained model to output " - "regression " - "predictions for a test set.", + "An implementation of the bayesian linear regression. This can train a " + "Bayesian linear regression model and use that model or a pre-trained " + "model to output regression predictions for a test set.", // Long description. "An implementation of the bayesian linear regression, also known" "as the Bayesian linear regression.\n " @@ -44,17 +42,7 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" "This program is able to train a Bayesian linear regression model or load " "a model from file, output regression predictions for a test set, and save " - "the trained model to a file. The Bayesian linear regression algorithm is " - "described in more detail below:" - "\n\n" - "Let X be a matrix where each row is a point and each column is a " - "dimension, t is a vector of targets, alpha is the precision of the " - "gaussian prior distribtion of w, and w is the solution to determine. " - "\n\n" - "The Bayesian linear regression computes the posterior distribution of " - "the parameters by the Bayes's rule : " - "\n\n" - " p(w|X) = p(X,t|w) * p(w|alpha) / p(X)" + "the trained model to a file." "\n\n" "To train a BayesianLinearRegression model, the " + PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") + @@ -90,7 +78,16 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", - "output_predictions", "test_predictions")); + "output_predictions", "test_predictions") + + "\n\n" + "Because the estimator computes a predictive distribution instead of simple " + "point estimate, the " + PRINT_PARAM_STRING("output_std") + " parameter " + "allows to save the prediction uncertainties with one standard deviation " + "from the mean :" + "\n\n" + + PRINT_CALL("bayesian_linear_regression", "input_model", + "bayesian_linear_regression_model", "test", "test", + "output_predictions", "test_predictions", "output_std", "stds")); PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); From 0b533e0a8173559ae23abe5985bc12c72dd8787c Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 10:31:00 +0200 Subject: [PATCH 168/297] output_predictions and output_std parameters become predictions and stds. --- .../bayesian_linear_regression_main.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index d237d39449..7dc4fa3669 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -57,9 +57,9 @@ PROGRAM_INFO("BayesianLinearRegression", "trained model or the given input model. Test points can be specified " "with the " + PRINT_PARAM_STRING("test") + " parameter. Predicted " "responses to the test points can be saved with the " + - PRINT_PARAM_STRING("output_predictions") + " output parameter. The " + PRINT_PARAM_STRING("predictions") + " output parameter. The " "corresponding standard deviation can be save by precising the " + - PRINT_PARAM_STRING("output_std") + " parameter." + PRINT_PARAM_STRING("stds") + " parameter." "\n\n" "For example, the following command trains a model on the data " + PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") + @@ -78,16 +78,16 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", - "output_predictions", "test_predictions") + + "predictions", "test_predictions") + "\n\n" "Because the estimator computes a predictive distribution instead of simple " - "point estimate, the " + PRINT_PARAM_STRING("output_std") + " parameter " + "point estimate, the " + PRINT_PARAM_STRING("stds") + " parameter " "allows to save the prediction uncertainties with one standard deviation " "from the mean :" "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", - "output_predictions", "test_predictions", "output_std", "stds")); + "predictions", "test_predictions", "stds", "stds")); PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); @@ -102,10 +102,10 @@ PARAM_MODEL_OUT(BayesianLinearRegression, "output_model", "Output " PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " "points).", "t"); -PARAM_MATRIX_OUT("output_predictions", "If --test_file is specified, this " +PARAM_MATRIX_OUT("predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); -PARAM_MATRIX_OUT("output_std", "If --std_file is specified, this file is where " +PARAM_MATRIX_OUT("stds", "If --std_file is specified, this file is where " "the standard deviations of the predictive distribution will " "be saved.", "u"); @@ -133,11 +133,11 @@ static void mlpackMain() } ReportIgnoredParam({{ "input", false }}, "responses"); - RequireAtLeastOnePassed({ "output_predictions", "output_model" }, false, + RequireAtLeastOnePassed({ "predictions", "output_model" }, false, "no results will be saved"); // Ignore out_predictions unless test is specified. - ReportIgnoredParam({{ "test", false }}, "output_predictions"); + ReportIgnoredParam({{ "test", false }}, "predictions"); BayesianLinearRegression* bayesLinReg; if (CLI::HasParam("input")) @@ -182,13 +182,13 @@ static void mlpackMain() mat testPoints = std::move(CLI::GetParam("test")); arma::rowvec predictions; - if (CLI::HasParam("output_std")) + if (CLI::HasParam("stds")) { arma::rowvec std; bayesLinReg->Predict(testPoints, predictions, std); // Save the standard deviation of the test points (one per line). - CLI::GetParam("output_std") = std::move(std); + CLI::GetParam("stds") = std::move(std); } else { @@ -196,7 +196,7 @@ static void mlpackMain() } // Save test predictions (one per line). - CLI::GetParam("output_predictions") = std::move(predictions); + CLI::GetParam("predictions") = std::move(predictions); } CLI::GetParam("output_model") = bayesLinReg; From b24d45a90ae9bc37c23acbe9c4cf200c9751ed33 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 11:29:51 +0200 Subject: [PATCH 169/297] Center and scale the data with the -c and -s flags. --- .../bayesian_linear_regression_main.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 7dc4fa3669..0c9be69263 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -109,20 +109,15 @@ PARAM_MATRIX_OUT("stds", "If --std_file is specified, this file is where " "the standard deviations of the predictive distribution will " "be saved.", "u"); -PARAM_INT_IN("center", "Center the data and fit the intercept. Set to 0 to " - "disable", - "c", - 1); +PARAM_FLAG("center", "Center the data and fit the intercept if enabled.", "c"); -PARAM_INT_IN("scale", "Scale each feature by their standard deviations. " - "set to 1 to scale.", - "s", - 0); +PARAM_FLAG("scale", "Scale each feature by their standard deviations if " + "enabled.", "s"); static void mlpackMain() { - int center = CLI::GetParam("center"); - int scale = CLI::GetParam("scale"); + bool center = CLI::GetParam("center"); + bool scale = CLI::GetParam("scale"); // Check parameters -- make sure everything given makes sense. RequireOnlyOnePassed({ "input", "input_model" }, true); From beccf2b1f7d9e15743b64512f89000e3e8c7f4e7 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 11:52:05 +0200 Subject: [PATCH 170/297] Use PARAM_ROW_IN() for responses and delete the estimator if (data, responses) dims are not coherent. --- .../bayesian_linear_regression_main.cpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 0c9be69263..ad963c0462 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -91,7 +91,7 @@ PROGRAM_INFO("BayesianLinearRegression", PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); -PARAM_MATRIX_IN("responses", "Matrix of responses/observations (y).", "r"); +PARAM_ROW_IN("responses", "Matrix of responses/observations (y).", "r"); PARAM_MODEL_IN(BayesianLinearRegression, "input_model", "Trained " "BayesianLinearRegression model to use.", "m"); @@ -128,7 +128,7 @@ static void mlpackMain() } ReportIgnoredParam({{ "input", false }}, "responses"); - RequireAtLeastOnePassed({ "predictions", "output_model" }, false, + RequireAtLeastOnePassed({ "predictions", "output_model", "stds" }, false, "no results will be saved"); // Ignore out_predictions unless test is specified. @@ -148,22 +148,18 @@ static void mlpackMain() // Load responses. The responses should be a one-dimensional vector, and it // seems more likely that these will be stored with one response per line // (one per row). So we should not transpose upon loading. - mat matY = std::move(CLI::GetParam("responses")); + arma::rowvec responses = std::move(CLI::GetParam("responses")); - // Make sure y is oriented the right way. - if (matY.n_cols == 1) - matY = trans(matY); - if (matY.n_rows > 1) - Log::Fatal << "Only one column or row allowed in responses file!" << endl; - - if (matY.n_elem != matX.n_cols) + if (responses.n_elem != matX.n_cols) + { + delete bayesLinReg; Log::Fatal << "Number of responses must be equal to number of rows of X!" << endl; + } - arma::rowvec y = std::move(matY); arma::rowvec predictionsTrain; // The Train method is ready to take data in column-major format. - bayesLinReg->Train(matX, matY); + bayesLinReg->Train(matX, responses); } else // We must have --input_model_file. { From c23cc1cb886893ac0be8624792eb6b3b31e0a9b5 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Mon, 25 May 2020 12:13:15 +0200 Subject: [PATCH 171/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 2d01cc00a0..0b2a796162 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) mlpackMain(); BayesianLinearRegression* estimator = - CLI::GetParam("output_model"); + CLI::GetParam("output_model"); const arma::colvec dataScale = estimator->DataScale(); const arma::colvec dataOffset = estimator->DataOffset(); From 204986230e0731ac0833962fbf5c3c1853dcd1e0 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 12:27:06 +0200 Subject: [PATCH 172/297] Change paramters name and types from the changes in main.cpp. --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 9 ++++----- .../main_tests/bayesian_linear_regression_test.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 70ab673757..53d9b565e8 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -55,8 +55,8 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionRegressionTest) BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6); } -// Verify fitIntercept and normalize equal false do not affect the solution. -BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) +// Verify centerData and scaleData equal false do not affect the solution. +BOOST_AUTO_TEST_CASE(TestCenter0ScaleData0) { arma::mat matX; arma::rowvec y; @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(TestCenter0Normalize0) } // Verify that centering and normalization are correct. -BOOST_AUTO_TEST_CASE(TestCenter1Normalize1) +BOOST_AUTO_TEST_CASE(TestCenterDataTrueScaleDataTrue) { arma::mat matX; arma::rowvec y; @@ -109,8 +109,7 @@ BOOST_AUTO_TEST_CASE(SingularMatix) matX.row(1) = matX.row(0); BayesianLinearRegression estimator; - double singular = estimator.Train(matX, y); - BOOST_REQUIRE(singular != -1); + estimator.Train(matX, y); } // Check that std are well computed/coherent. At least higher than the diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 0b2a796162..1828b66145 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -51,11 +51,11 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) int n = 50, m = 4; arma::mat matX = arma::randu(m, n); arma::rowvec omega = arma::randu(m); - arma::mat y = omega * matX; + arma::rowvec y = omega * matX; SetInputParam("input", std::move(matX)); SetInputParam("responses", std::move(y)); - SetInputParam("center", 0); + SetInputParam("center", false); mlpackMain(); @@ -77,8 +77,8 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) int n = 10, m = 4; arma::mat matX = arma::randu(m, n); arma::mat matXtest = arma::randu(m, 2 * n); - const arma::colvec omega = arma::randu(m); - arma::mat y = omega * matX; + const arma::rowvec omega = arma::randu(m); + arma::rowvec y = omega * matX; BayesianLinearRegression model; model.Train(matX, y); @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) arma::mat ytest = std::move(responses); // Check that initial output and output using saved model are same. - CheckMatrices(ytest, CLI::GetParam("output_predictions")); + CheckMatrices(ytest, CLI::GetParam("predictions")); } BOOST_AUTO_TEST_SUITE_END(); From f57711ca9bbf02f0704ed5a8db69a486289bbc43 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 17:40:19 +0200 Subject: [PATCH 173/297] Replace REQUIRE_CLOSE() instead of REQUIRE_CLOSE(). --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 53d9b565e8..02f4476052 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -94,8 +94,8 @@ BOOST_AUTO_TEST_CASE(TestCenterDataTrueScaleDataTrue) double yMean = arma::mean(y); BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataOffset() - xMean)), 1e-6); - BOOST_REQUIRE_SMALL((double) abs(estimator.ResponsesOffset() - yMean), 1e-6); BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataScale() - xStd)), 1e-6); + BOOST_REQUIRE_CLOSE(estimator.ResponsesOffset(), yMean, 1e-6); } // Check that Train() does not fail with two colinear vectors. From 734832b32b11278daddc8905b8f6be1dc660e3e0 Mon Sep 17 00:00:00 2001 From: cmercier Date: Mon, 25 May 2020 17:54:06 +0200 Subject: [PATCH 174/297] Add test for the estimatior of standard deviation of the responses. --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 02f4476052..55ad6f966c 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -129,7 +129,10 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) const double estStd = sqrt(estimator.Variance()); for (size_t i = 0; i < matX.n_cols; i++) - BOOST_REQUIRE(std[i] > estStd); + BOOST_REQUIRE_GT(std[i], estStd); + + // Check that the estimated variance is close to 1. + BOOST_REQUIRE_CLOSE(estStd, 1, 10); } // Check the solution is equal to the classical ridge. From 3b31ffc4219bbe8b4e8b680304fbd1c3e3cd1b8d Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 29 May 2020 08:51:29 +0200 Subject: [PATCH 175/297] Add serialization test. --- .../tests/bayesian_linear_regression_test.cpp | 4 +-- src/mlpack/tests/serialization_test.cpp | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 55ad6f966c..226f5ff4b5 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -130,9 +130,9 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) for (size_t i = 0; i < matX.n_cols; i++) BOOST_REQUIRE_GT(std[i], estStd); - + // Check that the estimated variance is close to 1. - BOOST_REQUIRE_CLOSE(estStd, 1, 10); + BOOST_REQUIRE_CLOSE(estStd, 1, 20); } // Check the solution is equal to the classical ridge. diff --git a/src/mlpack/tests/serialization_test.cpp b/src/mlpack/tests/serialization_test.cpp index ac2edddac7..c6fbe9b5cf 100644 --- a/src/mlpack/tests/serialization_test.cpp +++ b/src/mlpack/tests/serialization_test.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1604,4 +1605,34 @@ BOOST_AUTO_TEST_CASE(ssRBMTest) CheckMatrices(Rbm.Weight(), RbmBinary.Weight()); } +// Make sure serialization works for BayesianLinearRegression. +BOOST_AUTO_TEST_CASE(BayesianLinearRegressionTest) +{ + using namespace mlpack::regression; + + // Create a dataset. + arma::mat X = arma::randn(75, 250); + arma::vec omega = arma::randn(75, 1); + arma::rowvec y = omega.t() * X; + + BayesianLinearRegression blr(false, false); + blr.Train(X, y); + arma::vec omegaOpt = blr.Omega(); + + // Now, serialize. + BayesianLinearRegression xmlBlr(false, false), binaryBlr(false, false), + textBlr(false, false); + + SerializeObjectAll(blr, xmlBlr, binaryBlr, textBlr); + + // Now, check that predictions are the same. + arma::rowvec pred, xmlPred, textPred, binaryPred; + blr.Predict(X, pred); + xmlBlr.Predict(X, xmlPred); + textBlr.Predict(X, textPred); + binaryBlr.Predict(X, binaryPred); + + CheckMatrices(pred, xmlPred, textPred, binaryPred); +} + BOOST_AUTO_TEST_SUITE_END(); From 23b41c66a5fca38c48e589521a1dffc4d0dd9db8 Mon Sep 17 00:00:00 2001 From: cmercier Date: Fri, 29 May 2020 09:59:23 +0200 Subject: [PATCH 176/297] Check model are different with the option specified. Add test for input and input_model in main_test. --- .../tests/bayesian_linear_regression_test.cpp | 47 +++++++++++++++---- .../bayesian_linear_regression_test.cpp | 38 +++++++++++++++ src/mlpack/tests/serialization_test.cpp | 14 +++--- 3 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 226f5ff4b5..4ce150de97 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(TestCenterDataTrueScaleDataTrue) { arma::mat matX; arma::rowvec y; - size_t nDims = 30, nPoints = 100; + size_t nDims = 5, nPoints = 100; GenerateProblem(matX, y, nPoints, nDims, 0.5); BayesianLinearRegression estimator(true, true); @@ -98,6 +98,28 @@ BOOST_AUTO_TEST_CASE(TestCenterDataTrueScaleDataTrue) BOOST_REQUIRE_CLOSE(estimator.ResponsesOffset(), yMean, 1e-6); } +// Make sure a model with center ans scale option set is different than a model +// without it set. +BOOST_AUTO_TEST_CASE(OptionsMakeModelDifferent) +{ + arma::mat matX; + arma::rowvec y; + size_t nDims = 10, nPoints = 100; + GenerateProblem(matX, y, nPoints, nDims, 0.5); + + BayesianLinearRegression blr(false, false), blrC(true, false), + blrCS(true, true); + + blr.Train(matX, y); + blrC.Train(matX, y); + blrCS.Train(matX, y); + + for (size_t i = 0; i < nDims; ++i) + BOOST_REQUIRE((blr.Omega()(i) != blrC.Omega()(i)) && + (blr.Omega()(i) != blrCS.Omega()(i)) && + (blrC.Omega()(i) != blrCS.Omega()(i))); +} + // Check that Train() does not fail with two colinear vectors. BOOST_AUTO_TEST_CASE(SingularMatix) { @@ -143,16 +165,21 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) GenerateProblem(matX, y, 100, 10, 1); - BayesianLinearRegression bayesLinReg(false, false); - bayesLinReg.Train(matX, y); + BayesianLinearRegression blr(false, false); + blr.Train(matX, y); - LinearRegression classicalRidge(matX, - y, - bayesLinReg.Alpha() / bayesLinReg.Beta(), - false); - double equalSol = arma::sum(bayesLinReg.Omega() - - classicalRidge.Parameters()); - BOOST_REQUIRE(equalSol < 1e-5); + LinearRegression ridge(matX, + y, + blr.Alpha() / blr.Beta(), + false); + + arma::rowvec blrPred, ridgePred; + blr.Predict(matX, blrPred); + ridge.Predict(matX, ridgePred); + + // Check the predictions are close enough between ridge an or tested model. + for (size_t i = 0; i < y.size(); ++i) + BOOST_REQUIRE_CLOSE(blrPred[i], ridgePred[i], 1); } BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 1828b66145..15a56be9f5 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -105,4 +105,42 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) CheckMatrices(ytest, CLI::GetParam("predictions")); } +/** + * Check a crash happens if neither input or input_model are specified. + * Check a crash happens if both input and input_model are specified. + */ +BOOST_AUTO_TEST_CASE(CheckParamsPassed) +{ + int n = 10, m = 4; + arma::mat matX = arma::randu(m, n); + arma::mat matXtest = arma::randu(m, 2 * n); + const arma::rowvec omega = arma::randu(m); + arma::rowvec y = omega * matX; + + BayesianLinearRegression model; + model.Train(matX, y); + + arma::rowvec responses; + model.Predict(matXtest, responses); + + // Check that std::runtime_error is thrown if neither input or input_model + // is specified. + SetInputParam("responses", std::move(y)); + + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + + // Continue only with input passed. + SetInputParam("input", std::move(matX)); + mlpackMain(); + + // Now pass the previous trained model and one input matrix at the same time. + // An error should occur. + SetInputParam("input", std::move(matX)); + SetInputParam("input_model", + CLI::GetParam("output_model")); + SetInputParam("test", std::move(matXtest)); + + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); +} + BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/serialization_test.cpp b/src/mlpack/tests/serialization_test.cpp index c6fbe9b5cf..a7f2eef430 100644 --- a/src/mlpack/tests/serialization_test.cpp +++ b/src/mlpack/tests/serialization_test.cpp @@ -1611,12 +1611,12 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionTest) using namespace mlpack::regression; // Create a dataset. - arma::mat X = arma::randn(75, 250); + arma::mat matX = arma::randn(75, 250); arma::vec omega = arma::randn(75, 1); - arma::rowvec y = omega.t() * X; + arma::rowvec y = omega.t() * matX; BayesianLinearRegression blr(false, false); - blr.Train(X, y); + blr.Train(matX, y); arma::vec omegaOpt = blr.Omega(); // Now, serialize. @@ -1627,10 +1627,10 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionTest) // Now, check that predictions are the same. arma::rowvec pred, xmlPred, textPred, binaryPred; - blr.Predict(X, pred); - xmlBlr.Predict(X, xmlPred); - textBlr.Predict(X, textPred); - binaryBlr.Predict(X, binaryPred); + blr.Predict(matX, pred); + xmlBlr.Predict(matX, xmlPred); + textBlr.Predict(matX, textPred); + binaryBlr.Predict(matX, binaryPred); CheckMatrices(pred, xmlPred, textPred, binaryPred); } From 127260221f98dec71e853582f0455e1d273e465f Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 4 Jun 2020 21:10:50 +0200 Subject: [PATCH 177/297] Rewrite the CenterScaleData() method to avoid 2 vectors of size nDims if centerData and scaleData are false. --- .../bayesian_linear_regression.cpp | 79 +++++++++++-------- .../bayesian_linear_regression.hpp | 13 +-- .../tests/bayesian_linear_regression_test.cpp | 8 +- .../bayesian_linear_regression_test.cpp | 7 +- 4 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 3111c45365..16caa604af 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -39,12 +39,8 @@ double BayesianLinearRegression::Train(const arma::mat& data, // Preprocess the data. Center and scale. responsesOffset = CenterScaleData(data, responses, - centerData, - scaleData, phi, - t, - dataOffset, - dataScale); + t); if (!arma::eig_sym(eigVal, eigVec, arma::symmatu(phi * phi.t()))) { @@ -97,10 +93,10 @@ double BayesianLinearRegression::Train(const arma::mat& data, void BayesianLinearRegression::Predict(const arma::mat& points, arma::rowvec& predictions) const { - // y_hat = w^T * (X - mu) / sigma + y_mean. - predictions = omega.t() * ((points.each_col() - dataOffset).each_col() - / dataScale); - predictions += responsesOffset; + // Center and scale the points before applying the model. + arma::mat matX; + CenterScaleDataPred(points, matX); + predictions = omega.t() * matX + responsesOffset; } void BayesianLinearRegression::Predict(const arma::mat& points, @@ -108,10 +104,10 @@ void BayesianLinearRegression::Predict(const arma::mat& points, arma::rowvec& std) const { // Center and scale the points before applying the model. - const arma::mat matX = (points.each_col() - dataOffset).each_col() - / dataScale; - predictions = omega.t() * matX; - predictions += responsesOffset; + arma::mat matX; + CenterScaleDataPred(points, matX); + predictions = omega.t() * matX + responsesOffset; + // Compute the standard deviation dor each points. std = sqrt(Variance() + sum((matX % (matCovariance * matX)), 0)); } @@ -125,35 +121,56 @@ double BayesianLinearRegression::RMSE(const arma::mat& data, double BayesianLinearRegression::CenterScaleData(const arma::mat& data, const arma::rowvec& responses, - bool centerData, - bool scaleData, arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale) + arma::rowvec& responsesProc) { // Initialize the offsets to their neutral forms. - dataOffset = arma::zeros(data.n_rows); - dataScale = arma::ones(data.n_rows); responsesOffset = 0.0; + if (!centerData && !scaleData) + { + dataProc = data; + responsesProc = responses; + } - if (centerData) + else if (centerData && !scaleData) { dataOffset = mean(data, 1); responsesOffset = mean(responses); + dataProc = data.each_col() - dataOffset; + responsesProc = responses - responsesOffset; } - if (scaleData) + else if (!centerData && scaleData) + { dataScale = stddev(data, 0, 1); + dataProc = data.each_col() / dataScale; + } - // Copy data and response before the processing. - dataProc = data; - // Center the data. - dataProc.each_col() -= dataOffset; - // Scale the data. - dataProc.each_col() /= dataScale; - // Center the responses. - responsesProc = responses - responsesOffset; - + else + { + dataOffset = mean(data, 1); + dataScale = stddev(data, 1, 1); + responsesOffset = mean(responses); + dataProc = (data.each_col() - dataOffset).each_col() / dataScale; + responsesProc = responses - responsesOffset; + } return responsesOffset; } + +void BayesianLinearRegression::CenterScaleDataPred( + const arma::mat& data, + arma::mat& dataProc) const +{ + if (!centerData && !scaleData) + dataProc = data; + + else if (centerData && !scaleData) + dataProc = data.each_col() - dataOffset; + + else if (!centerData && scaleData) + dataProc = data.each_col() / dataScale; + + else + dataProc = (data.each_col() - dataOffset).each_col() / dataScale; +} + diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 7c86ff2c1a..6220b08edd 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -271,12 +271,15 @@ class BayesianLinearRegression */ double CenterScaleData(const arma::mat& data, const arma::rowvec& responses, - const bool centerData, - const bool scaleData, arma::mat& dataProc, - arma::rowvec& responsesProc, - arma::colvec& dataOffset, - arma::colvec& dataScale); + arma::rowvec& responsesProc); + + /** + * Add the documentation + */ + void CenterScaleDataPred(const arma::mat& data, + arma::mat& dataProc) const; + }; } // namespace regression diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 4ce150de97..6b141bf9d9 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -68,14 +68,14 @@ BOOST_AUTO_TEST_CASE(TestCenter0ScaleData0) estimator.Train(matX, y); - // To be neutral dataOffset must be all 0. - BOOST_REQUIRE(sum(estimator.DataOffset()) == 0.0); + // Check dataOffset is empty. + BOOST_REQUIRE(estimator.DataOffset().n_elem == 0); // To be neutral responseOffset must be 0. BOOST_REQUIRE(estimator.ResponsesOffset() == 0); - // To be neutral dataScale must be all 1. - BOOST_REQUIRE(sum(estimator.DataScale()) == nDims); + // Check dataScale is empty. + BOOST_REQUIRE(estimator.DataScale().n_elem == 0); } // Verify that centering and normalization are correct. diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 15a56be9f5..08f766b18e 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -62,11 +62,8 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) BayesianLinearRegression* estimator = CLI::GetParam("output_model"); - const arma::colvec dataScale = estimator->DataScale(); - const arma::colvec dataOffset = estimator->DataOffset(); - - BOOST_REQUIRE(sum(dataOffset) == 0); - BOOST_REQUIRE(sum(dataScale) == m); + BOOST_REQUIRE(estimator->DataOffset().n_elem == 0); + BOOST_REQUIRE(estimator->DataScale().n_elem == 0); } /** From 612a66b50a6bac584724f1aa0235394967eb192a Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 17 Jun 2020 09:11:12 +0200 Subject: [PATCH 178/297] Add documentation for CenterScaleDataPred() and fix bug with stddev(). --- .../bayesian_linear_regression.cpp | 2 +- .../bayesian_linear_regression.hpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 16caa604af..7e619c7912 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -149,7 +149,7 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, else { dataOffset = mean(data, 1); - dataScale = stddev(data, 1, 1); + dataScale = stddev(data, 0, 1); responsesOffset = mean(responses); dataProc = (data.each_col() - dataOffset).each_col() / dataScale; responsesProc = responses - responsesOffset; diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 6220b08edd..f9f5c2ac70 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -127,7 +127,6 @@ class BayesianLinearRegression * * @param points The data points to apply the model. * @param predictions y, Contains the predicted values on completion. - * * @return Root mean squared error computed on the train set. */ void Predict(const arma::mat& points, @@ -256,12 +255,12 @@ class BayesianLinearRegression * Center and scale the data. The last four arguments * allow future modification of new points. * - * @param data Design matrix in column-major format, dim(P,N). + * @param data Design matrix in column-major format, dim(P, N). * @param responses A vector of targets. * @param centerData If true data will be centred according to the points. * @param centerData If true data will be scales by the standard deviations * of the features computed according to the points. - * @param dataProc data processed, dim(N,P). + * @param dataProc data processed, dim(P, N). * @param responsesProc responses processed, dim(N). * @param dataOffset Mean vector of the design matrix according to the * points, dim(P). @@ -275,12 +274,14 @@ class BayesianLinearRegression arma::rowvec& responsesProc); /** - * Add the documentation + * Center and scale the points before prediction. + * + * @param data Design matrix in column-major format, dim(P, N). + * @param responsesProc responses processed, dim(N). */ void CenterScaleDataPred(const arma::mat& data, arma::mat& dataProc) const; - }; } // namespace regression } // namespace mlpack From 4542f8c16f69fed40bb65072c4f83c2efb609db6 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 17 Jun 2020 09:16:24 +0200 Subject: [PATCH 179/297] Fix documentation. --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index f9f5c2ac70..5d60e0acc9 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -198,7 +198,7 @@ class BayesianLinearRegression * Get the vector of standard deviations computed on the features over the * training points. Vector of 1 if scaleData is false. * - * return dataOffset + * @return dataOffset */ const arma::colvec& DataScale() const { return dataScale; } From d5669f0f136961e7adb624f156409add583ce96f Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 17 Jun 2020 11:23:33 +0200 Subject: [PATCH 180/297] Formatting. --- .../bayesian_linear_regression.cpp | 7 ++-- .../bayesian_linear_regression.hpp | 34 +++++++------------ .../bayesian_linear_regression_main.cpp | 13 +++---- .../tests/bayesian_linear_regression_test.cpp | 6 ++-- .../bayesian_linear_regression_test.cpp | 2 +- 5 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 7e619c7912..8c3c7563cd 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -127,7 +127,7 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, // Initialize the offsets to their neutral forms. responsesOffset = 0.0; if (!centerData && !scaleData) - { + { dataProc = data; responsesProc = responses; } @@ -163,14 +163,13 @@ void BayesianLinearRegression::CenterScaleDataPred( { if (!centerData && !scaleData) dataProc = data; - + else if (centerData && !scaleData) dataProc = data.each_col() - dataOffset; else if (!centerData && scaleData) dataProc = data.each_col() / dataScale; - else + else dataProc = (data.each_col() - dataOffset).each_col() / dataScale; } - diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 5d60e0acc9..54856d74cc 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -114,8 +114,8 @@ class BayesianLinearRegression * Run BayesianLinearRegression. The input matrix (like all mlpack matrices) should be * column-major -- each column is an observation and each row is a dimension. * - * @param data Column-major input data - * @param responses A vector of targets. + * @param data Column-major input data, dim(P, N). + * @param responses A vector of targets, dim(N). * @return score. Root Mean Square Error. */ double Train(const arma::mat& data, @@ -149,7 +149,7 @@ class BayesianLinearRegression * Compute the Root Mean Square Error between the predictions returned by the * model and the true repsonses. * - * @param Points Data points to predict + * @param data Data points to predict * @param responses A vector of targets. * @return RMSE **/ @@ -188,22 +188,22 @@ class BayesianLinearRegression /** * Get the mean vector computed on the features over the training points. - * Vector of 0 if centerData is false. - * + * * @return responsesOffset */ const arma::colvec& DataOffset() const { return dataOffset; } /** * Get the vector of standard deviations computed on the features over the - * training points. Vector of 1 if scaleData is false. - * + * training points. + * * @return dataOffset */ const arma::colvec& DataScale() const { return dataScale; } /** * Get the mean value of the train responses. + * * @return responsesOffset */ double ResponsesOffset() const { return responsesOffset; } @@ -252,20 +252,13 @@ class BayesianLinearRegression arma::mat matCovariance; /** - * Center and scale the data. The last four arguments - * allow future modification of new points. + * Center and scale the data accordind to centerData and scaleData. + * Allows future modifications of new points. * * @param data Design matrix in column-major format, dim(P, N). * @param responses A vector of targets. - * @param centerData If true data will be centred according to the points. - * @param centerData If true data will be scales by the standard deviations - * of the features computed according to the points. * @param dataProc data processed, dim(P, N). * @param responsesProc responses processed, dim(N). - * @param dataOffset Mean vector of the design matrix according to the - * points, dim(P). - * @param dataScale Vector containg the standard deviations of the features - * dim(P). * @return reponsesOffset Mean of responses. */ double CenterScaleData(const arma::mat& data, @@ -275,13 +268,12 @@ class BayesianLinearRegression /** * Center and scale the points before prediction. - * + * * @param data Design matrix in column-major format, dim(P, N). - * @param responsesProc responses processed, dim(N). - */ - void CenterScaleDataPred(const arma::mat& data, + * @param dataProc data processed, dim(P, N). + */ + void CenterScaleDataPred(const arma::mat& data, arma::mat& dataProc) const; - }; } // namespace regression } // namespace mlpack diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index ad963c0462..9ea469b473 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -42,7 +42,7 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" "This program is able to train a Bayesian linear regression model or load " "a model from file, output regression predictions for a test set, and save " - "the trained model to a file." + "the trained model to a file." "\n\n" "To train a BayesianLinearRegression model, the " + PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") + @@ -80,10 +80,10 @@ PROGRAM_INFO("BayesianLinearRegression", "bayesian_linear_regression_model", "test", "test", "predictions", "test_predictions") + "\n\n" - "Because the estimator computes a predictive distribution instead of simple " - "point estimate, the " + PRINT_PARAM_STRING("stds") + " parameter " + "Because the estimator computes a predictive distribution instead of " + "simple point estimate, the " + PRINT_PARAM_STRING("stds") + " parameter " "allows to save the prediction uncertainties with one standard deviation " - "from the mean :" + "from the mean :" "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", @@ -112,7 +112,7 @@ PARAM_MATRIX_OUT("stds", "If --std_file is specified, this file is where " PARAM_FLAG("center", "Center the data and fit the intercept if enabled.", "c"); PARAM_FLAG("scale", "Scale each feature by their standard deviations if " - "enabled.", "s"); + "enabled.", "s"); static void mlpackMain() { @@ -148,7 +148,8 @@ static void mlpackMain() // Load responses. The responses should be a one-dimensional vector, and it // seems more likely that these will be stored with one response per line // (one per row). So we should not transpose upon loading. - arma::rowvec responses = std::move(CLI::GetParam("responses")); + arma::rowvec responses = std::move( + CLI::GetParam("responses")); if (responses.n_elem != matX.n_cols) { diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 6b141bf9d9..0c1bc9105d 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -109,13 +109,13 @@ BOOST_AUTO_TEST_CASE(OptionsMakeModelDifferent) BayesianLinearRegression blr(false, false), blrC(true, false), blrCS(true, true); - + blr.Train(matX, y); blrC.Train(matX, y); blrCS.Train(matX, y); - + for (size_t i = 0; i < nDims; ++i) - BOOST_REQUIRE((blr.Omega()(i) != blrC.Omega()(i)) && + BOOST_REQUIRE((blr.Omega()(i) != blrC.Omega()(i)) && (blr.Omega()(i) != blrCS.Omega()(i)) && (blrC.Omega()(i) != blrCS.Omega()(i))); } diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 08f766b18e..eb94d76fc9 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE(CheckParamsPassed) arma::rowvec responses; model.Predict(matXtest, responses); - // Check that std::runtime_error is thrown if neither input or input_model + // Check that std::runtime_error is thrown if neither input or input_model // is specified. SetInputParam("responses", std::move(y)); From f60f5d91b6d67ef541e6a90e6ce9402ff9af2ed8 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:40:07 +0200 Subject: [PATCH 181/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 54856d74cc..6c22827c86 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -52,6 +52,7 @@ namespace regression { * } * @endcode * + * @code * @book{Bishop:2006:PRM:1162264, * author = {Bishop, Christopher M.}, * title = {Pattern Recognition and Machine Learning (Information Science @@ -62,7 +63,7 @@ namespace regression { * publisher = {Springer-Verlag}, * address = {Berlin, Heidelberg}, * } - * @encode + * @endcode * * Example of use: * From ff5cd8337cd4df5f5c16e23163618bc77464f29b Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:55:23 +0200 Subject: [PATCH 182/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 8c3c7563cd..3ffb6cf192 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -45,7 +45,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, if (!arma::eig_sym(eigVal, eigVec, arma::symmatu(phi * phi.t()))) { Log::Fatal << "BayesianLinearRegression::Train(): Eigendecomposition " - << "of covariance failed!"; + << "of covariance failed!" << std::endl; } // Compute this quantities once and for all. From ff55cc5ab6f22f53d905a63df8fa8b3000dd19aa Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:55:43 +0200 Subject: [PATCH 183/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 3ffb6cf192..7514d103d5 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -52,8 +52,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, const arma::mat eigVecInv = inv(eigVec); const arma::colvec eigVecInvPhitT = eigVecInv * phi * t.t(); - // Initialize the hyperparameters and - // begin with an infinitely broad prior. + // Initialize the hyperparameters and begin with an infinitely broad prior. alpha = 1e-6; beta = 1 / (var(t, 1) * 0.1); From d873b03213429f12983f0dcc2da354ca80bf45f6 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:56:09 +0200 Subject: [PATCH 184/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 7514d103d5..7be2555063 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -106,7 +106,7 @@ void BayesianLinearRegression::Predict(const arma::mat& points, arma::mat matX; CenterScaleDataPred(points, matX); predictions = omega.t() * matX + responsesOffset; - // Compute the standard deviation dor each points. + // Compute the standard deviation for each point. std = sqrt(Variance() + sum((matX % (matCovariance * matX)), 0)); } From 6dc928d0bef947d9d2e6c6bea93b3131958b47c4 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:56:23 +0200 Subject: [PATCH 185/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 7be2555063..d2c18e2734 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -127,8 +127,8 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, responsesOffset = 0.0; if (!centerData && !scaleData) { - dataProc = data; - responsesProc = responses; + dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, data.n_cols, false, true); + responsesProc = arma::rowvec(const_cast(responses.memptr()), responses.n_elem, false, true); } else if (centerData && !scaleData) From 8ea252a00e3f973d6d1f774e75381e4a4a51ba25 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:56:33 +0200 Subject: [PATCH 186/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 9ea469b473..b12549c0e5 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -105,9 +105,8 @@ PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test " PARAM_MATRIX_OUT("predictions", "If --test_file is specified, this " "file is where the predicted responses will be saved.", "o"); -PARAM_MATRIX_OUT("stds", "If --std_file is specified, this file is where " - "the standard deviations of the predictive distribution will " - "be saved.", "u"); +PARAM_MATRIX_OUT("stds", "If specified, this is where the standard deviations " + "of the predictive distribution will be saved.", "u"); PARAM_FLAG("center", "Center the data and fit the intercept if enabled.", "c"); From ec6ff27fdebd95360c6165b97bd43e505f6748bd Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:57:57 +0200 Subject: [PATCH 187/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index d2c18e2734..00ce0ab525 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -161,7 +161,7 @@ void BayesianLinearRegression::CenterScaleDataPred( arma::mat& dataProc) const { if (!centerData && !scaleData) - dataProc = data; + dataProc = data; else if (centerData && !scaleData) dataProc = data.each_col() - dataOffset; From 5fd99980892d176fe37dbef29913c25767c91956 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 23 Jun 2020 10:37:26 +0200 Subject: [PATCH 188/297] Do not copy the data if centerData and scaleData are false. --- .../bayesian_linear_regression.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 00ce0ab525..59b5e0a720 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -127,8 +127,11 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, responsesOffset = 0.0; if (!centerData && !scaleData) { - dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, data.n_cols, false, true); - responsesProc = arma::rowvec(const_cast(responses.memptr()), responses.n_elem, false, true); + dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, + data.n_cols, false, true); + responsesProc = arma::rowvec(const_cast(responses.memptr()), + responses.n_elem, false, + true); } else if (centerData && !scaleData) @@ -161,7 +164,8 @@ void BayesianLinearRegression::CenterScaleDataPred( arma::mat& dataProc) const { if (!centerData && !scaleData) - dataProc = data; + dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, + data.n_cols, false, true); else if (centerData && !scaleData) dataProc = data.each_col() - dataOffset; From 4808ee2a528158d48a7bdee35b5d241ea2acbc61 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 23 Jun 2020 10:38:07 +0200 Subject: [PATCH 189/297] Fix rare failures. --- .../tests/bayesian_linear_regression_test.cpp | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 0c1bc9105d..0e66de2dea 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -154,32 +154,42 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) BOOST_REQUIRE_GT(std[i], estStd); // Check that the estimated variance is close to 1. - BOOST_REQUIRE_CLOSE(estStd, 1, 20); + BOOST_REQUIRE_CLOSE(estStd, 1, 30); } // Check the solution is equal to the classical ridge. BOOST_AUTO_TEST_CASE(EqualtoRidge) { - arma::mat matX; - arma::rowvec y; + arma::mat matX; + arma::rowvec y, blrPred, ridgePred; - GenerateProblem(matX, y, 100, 10, 1); + for (size_t trial = 0; trial < 3; ++trial) + { + GenerateProblem(matX, y, 100, 10, 1); - BayesianLinearRegression blr(false, false); - blr.Train(matX, y); + BayesianLinearRegression blr(false, false); + blr.Train(matX, y); - LinearRegression ridge(matX, - y, - blr.Alpha() / blr.Beta(), - false); + LinearRegression ridge(matX, + y, + blr.Alpha() / blr.Beta(), + false); - arma::rowvec blrPred, ridgePred; - blr.Predict(matX, blrPred); - ridge.Predict(matX, ridgePred); + blr.Predict(matX, blrPred); + ridge.Predict(matX, ridgePred); - // Check the predictions are close enough between ridge an or tested model. - for (size_t i = 0; i < y.size(); ++i) - BOOST_REQUIRE_CLOSE(blrPred[i], ridgePred[i], 1); + // If the predictions seem far off, just try again. + if (arma::norm(blrPred - ridgePred) > 1e-5) + continue; + + // Check the predictions are close enough between ridge an or tested model. + for (size_t i = 0; i < y.size(); ++i) + BOOST_REQUIRE_CLOSE(blrPred[i], ridgePred[i], 1); + + // Exit once a test case has completed. + break; + } } + BOOST_AUTO_TEST_SUITE_END(); From 21b8e058fc97bcc6ecb3c85cc9e553574e079922 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 23 Jun 2020 10:38:33 +0200 Subject: [PATCH 190/297] Update doc. --- .../bayesian_linear_regression_main.cpp | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index b12549c0e5..8a1a29d530 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -23,16 +23,14 @@ using namespace mlpack::util; PROGRAM_INFO("BayesianLinearRegression", // Short description. - "An implementation of the bayesian linear regression. This can train a " - "Bayesian linear regression model and use that model or a pre-trained " - "model to output regression predictions for a test set.", + "An implementation of the bayesian linear regression.", // Long description. - "An implementation of the bayesian linear regression, also known" - "as the Bayesian linear regression.\n " - "This is a probabilistic view and implementation of the linear regression. " - "The final solution is obtained by computing a posterior distribution from " - "gaussian likelihood and a zero mean gaussian isotropic prior distribution " - "on the solution. " + "An implementation of the bayesian linear regression." + "\n" + "This model is a probabilistic view and implementation of the linear " + "regression. The final solution is obtained by computing a posterior " + "distribution from gaussian likelihood and a zero mean gaussian isotropic " + " prior distribution on the solution. " "\n" "Optimization is AUTOMATIC and does not require cross validation. " "The optimization is performed by maximization of the evidence function. " @@ -82,8 +80,7 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" "Because the estimator computes a predictive distribution instead of " "simple point estimate, the " + PRINT_PARAM_STRING("stds") + " parameter " - "allows to save the prediction uncertainties with one standard deviation " - "from the mean :" + "allows to save the prediction uncertainties: " "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", @@ -119,19 +116,19 @@ static void mlpackMain() bool scale = CLI::GetParam("scale"); // Check parameters -- make sure everything given makes sense. - RequireOnlyOnePassed({ "input", "input_model" }, true); + RequireOnlyOnePassed({"input", "input_model"}, true); if (CLI::HasParam("input")) { - RequireOnlyOnePassed({ "responses" }, true, "if input data is specified, " + RequireOnlyOnePassed({"responses"}, true, "if input data is specified, " "responses must also be specified"); } - ReportIgnoredParam({{ "input", false }}, "responses"); + ReportIgnoredParam({{"input", false }}, "responses"); - RequireAtLeastOnePassed({ "predictions", "output_model", "stds" }, false, + RequireAtLeastOnePassed({"predictions", "output_model", "stds"}, false, "no results will be saved"); // Ignore out_predictions unless test is specified. - ReportIgnoredParam({{ "test", false }}, "predictions"); + ReportIgnoredParam({{"test", false}}, "predictions"); BayesianLinearRegression* bayesLinReg; if (CLI::HasParam("input")) From 70e2c20f8379611ea07318f463c761775feed2c8 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 23 Jun 2020 10:43:56 +0200 Subject: [PATCH 191/297] Formatting --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 0e66de2dea..ec764510d4 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -191,5 +191,4 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) } } - BOOST_AUTO_TEST_SUITE_END(); From b9cd19eeb8ce0a641d9a3bcd6f4b057070cfb537 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:39:44 +0200 Subject: [PATCH 192/297] Update src/mlpack/tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index ec764510d4..25ef5c4385 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -160,10 +160,10 @@ BOOST_AUTO_TEST_CASE(PredictiveUncertainties) // Check the solution is equal to the classical ridge. BOOST_AUTO_TEST_CASE(EqualtoRidge) { - arma::mat matX; - arma::rowvec y, blrPred, ridgePred; + arma::mat matX; + arma::rowvec y, blrPred, ridgePred; - for (size_t trial = 0; trial < 3; ++trial) + for (size_t trial = 0; trial < 3; ++trial) { GenerateProblem(matX, y, 100, 10, 1); From 7355f797c43783e0b85c8a56a8cc2689fc90eb59 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:39:54 +0200 Subject: [PATCH 193/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 59b5e0a720..404e96ece8 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -107,7 +107,7 @@ void BayesianLinearRegression::Predict(const arma::mat& points, CenterScaleDataPred(points, matX); predictions = omega.t() * matX + responsesOffset; // Compute the standard deviation for each point. - std = sqrt(Variance() + sum((matX % (matCovariance * matX)), 0)); + std = sqrt(Variance() + sum(matX % (matCovariance * matX), 0)); } double BayesianLinearRegression::RMSE(const arma::mat& data, From 08bbe7c7828677e1b98890c0c41202eac11d2442 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:41:45 +0200 Subject: [PATCH 194/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 404e96ece8..e51acf0a27 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -37,10 +37,7 @@ double BayesianLinearRegression::Train(const arma::mat& data, arma::mat eigVec; // Preprocess the data. Center and scale. - responsesOffset = CenterScaleData(data, - responses, - phi, - t); + responsesOffset = CenterScaleData(data, responses, phi, t); if (!arma::eig_sym(eigVal, eigVec, arma::symmatu(phi * phi.t()))) { From 47d5d1f6e7422b4ce8a49847177265fb400b1569 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:41:54 +0200 Subject: [PATCH 195/297] Update src/mlpack/tests/bayesian_linear_regression_test.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 25ef5c4385..dc76fd6289 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) if (arma::norm(blrPred - ridgePred) > 1e-5) continue; - // Check the predictions are close enough between ridge an or tested model. + // Check the predictions are close enough between ridge and our tested model. for (size_t i = 0; i < y.size(); ++i) BOOST_REQUIRE_CLOSE(blrPred[i], ridgePred[i], 1); From 342ccdbaecb234e9a8401e06d2a7010bd06115a5 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:42:03 +0200 Subject: [PATCH 196/297] Update src/mlpack/tests/bayesian_linear_regression_test.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index dc76fd6289..c2fecc2077 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -170,10 +170,7 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) BayesianLinearRegression blr(false, false); blr.Train(matX, y); - LinearRegression ridge(matX, - y, - blr.Alpha() / blr.Beta(), - false); + LinearRegression ridge(matX, y, blr.Alpha() / blr.Beta(), false); blr.Predict(matX, blrPred); ridge.Predict(matX, ridgePred); From c6363401baf5acc32c9fb0afb95145cf094b44da Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 23 Jun 2020 17:54:54 +0200 Subject: [PATCH 197/297] Add {} for each if-else statement of CenterScaleDataPred(). --- .../bayesian_linear_regression.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index e51acf0a27..ffaf304763 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -161,15 +161,23 @@ void BayesianLinearRegression::CenterScaleDataPred( arma::mat& dataProc) const { if (!centerData && !scaleData) + { dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, - data.n_cols, false, true); + data.n_cols, false, true); + } else if (centerData && !scaleData) + { dataProc = data.each_col() - dataOffset; + } else if (!centerData && scaleData) + { dataProc = data.each_col() / dataScale; + } else + { dataProc = (data.each_col() - dataOffset).each_col() / dataScale; + } } From 9dc801c1a8f8f634f87851bf53985d095dc4db97 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Wed, 24 Jun 2020 08:39:04 +0200 Subject: [PATCH 198/297] Update src/mlpack/tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index c2fecc2077..19c5507dae 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -163,7 +163,8 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) arma::mat matX; arma::rowvec y, blrPred, ridgePred; - for (size_t trial = 0; trial < 3; ++trial) + size_t trial = 0; + for ( ; trial < 3; ++trial) { GenerateProblem(matX, y, 100, 10, 1); @@ -186,6 +187,8 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) // Exit once a test case has completed. break; } + + BOOST_REQUIRE_LT(trial, 3); } BOOST_AUTO_TEST_SUITE_END(); From c25cb6e0e15ca85fb84b57de1eda603975159d40 Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 25 Jun 2020 10:07:12 +0200 Subject: [PATCH 199/297] Set responsesProc when centerData is false and scaleData is true in CenterScaleData. --- .../bayesian_linear_regression.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index ffaf304763..87e42f834d 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -126,8 +126,8 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, { dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, data.n_cols, false, true); - responsesProc = arma::rowvec(const_cast(responses.memptr()), - responses.n_elem, false, + responsesProc = arma::rowvec(const_cast(responses.memptr()), + responses.n_elem, false, true); } @@ -143,6 +143,9 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, { dataScale = stddev(data, 0, 1); dataProc = data.each_col() / dataScale; + responsesProc = arma::rowvec(const_cast(responses.memptr()), + responses.n_elem, false, + true); } else From c237368e746d040eda2147f6bfd3c10fc54b1cc0 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Tue, 30 Jun 2020 12:04:01 +0530 Subject: [PATCH 200/297] Initial commit. Soft Margin Loss function. --- .../methods/ann/loss_functions/CMakeLists.txt | 2 + .../ann/loss_functions/soft_margin_loss.hpp | 100 ++++++++++++++++++ .../loss_functions/soft_margin_loss_impl.hpp | 72 +++++++++++++ src/mlpack/tests/loss_functions_test.cpp | 56 ++++++++++ 4 files changed, 230 insertions(+) create mode 100644 src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp create mode 100644 src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp diff --git a/src/mlpack/methods/ann/loss_functions/CMakeLists.txt b/src/mlpack/methods/ann/loss_functions/CMakeLists.txt index 3c813eda8f..f58cdfe8a5 100644 --- a/src/mlpack/methods/ann/loss_functions/CMakeLists.txt +++ b/src/mlpack/methods/ann/loss_functions/CMakeLists.txt @@ -31,6 +31,8 @@ set(SOURCES reconstruction_loss_impl.hpp sigmoid_cross_entropy_error.hpp sigmoid_cross_entropy_error_impl.hpp + soft_margin_loss.hpp + soft_margin_loss_impl.hpp hinge_embedding_loss.hpp hinge_embedding_loss_impl.hpp ) diff --git a/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp b/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp new file mode 100644 index 0000000000..149fe7b059 --- /dev/null +++ b/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp @@ -0,0 +1,100 @@ +/** + * @file methods/ann/loss_functions/soft_margin_loss.hpp + * @author Anjishnu Mukherjee + * + * Definition of the Soft Margin Loss function. + * + * It is a criterion that optimizes a two-class classification logistic loss, + * between input x and target y, both having the same shape, with the target + * containing only the values 1 or -1. + * + * 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_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_HPP +#define MLPACK_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * @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 SoftMarginLoss +{ + public: + /** + * Create the SoftMarginLoss object. + * + * @param reduction Specifies the reduction to apply to the output. If false, + * 'mean' reduction is used, where sum of the output will be + * divided by the number of elements in the output. If + * true, 'sum' reduction is used and the output will be + * summed. It is set to true by default. + */ + SoftMarginLoss(const bool reduction = true); + + /** + * Computes the Soft Margin Loss function. + * + * @param input Input data used for evaluating the specified function. + * @param target The target vector with same shape as input. + */ + template + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); + + /** + * Ordinary feed backward pass of a neural network. + * + * @param input The propagated input activation. + * @param target The target vector. + * @param output The calculated error. + */ + template + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); + + //! Get the output parameter. + OutputDataType& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the type of reduction used. + bool Reduction() const { return reduction; } + //! Modify the type of reduction used. + bool& Reduction() { return reduction; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! The boolean value that tells if reduction is sum or mean. + bool reduction; +}; // class SoftMarginLoss + +} // namespace ann +} // namespace mlpack + +// include implementation. +#include "soft_margin_loss_impl.hpp" + +#endif \ No newline at end of file diff --git a/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp new file mode 100644 index 0000000000..82059ce586 --- /dev/null +++ b/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp @@ -0,0 +1,72 @@ +/** + * @file methods/ann/loss_functions/soft_margin_loss_impl.hpp + * @author Anjishnu Mukherjee + * + * Implementation of the Soft Margin Loss function. + * + * 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_LOSS_FUNCTION_SOFT_MARGIN_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_IMPL_HPP + +// In case it hasn't been included. +#include "soft_margin_loss.hpp" + +namespace mlpack { +namespace ann /** Artifical Neural Network. */ { + +template +SoftMarginLoss:: +SoftMarginLoss(const bool reduction) : reduction(reduction) +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +SoftMarginLoss::Forward( + const InputType& input, const TargetType& target) +{ + InputType loss = arma::log(1 + arma::exp(-target % input)); + typename InputType::elem_type lossSum = arma::accu(loss); + + if (reduction) + return lossSum; + + return lossSum / input.n_elem; +} + +template +template +void SoftMarginLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + output.set_size(size(input)); + InputType temp = arma::exp(-target % input); + InputType numerator = -target % temp; + InputType denominator = 1 + temp; + output = numerator / denominator; + + if (!reduction) + output = output / input.n_elem; +} + +template +template +void SoftMarginLoss::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(reduction); +} + +} // namespace ann +} // namespace mlpack + +#endif \ No newline at end of file diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index 75485fda5c..8eeb42ed36 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -748,4 +749,59 @@ BOOST_AUTO_TEST_CASE(MarginRankingLossTest) "-0.753830 1.336900 0.000000 0.000000 -0.207000 0.328810"), 1e-6); } +/** + * Simple test for the Softmargin Loss function. + */ +BOOST_AUTO_TEST_CASE(SoftMarginLossTest) +{ + arma::mat input, target, output, expectedOutput; + double loss; + SoftMarginLoss<> module1; + SoftMarginLoss<> module2(false); + + input = arma::mat("0.1778 0.0957 0.1397 0.1203 0.2403 0.1925 -0.2264 -0.3400 " + "-0.3336"); + target = arma::mat("1 1 -1 1 -1 1 -1 1 1"); + input.reshape(3, 3); + target.reshape(3, 3); + + // Test for sum reduction. + + // Calculated using torch.nn.SoftMarginLoss(reduction='sum'). + expectedOutput = arma::mat("-0.4557 -0.4761 0.5349 -0.4700 0.5598 -0.4520 " + "0.4436 -0.5842 -0.5826"); + expectedOutput.reshape(3, 3); + + // Test the Forward function. Loss should be 6.41456. + // Value calculated using torch.nn.SoftMarginLoss(reduction='sum'). + loss = module1.Forward(input, target); + BOOST_REQUIRE_CLOSE(loss, 6.41456, 1e-3); + + // Test the Backward function. + module1.Backward(input, target, output); + BOOST_REQUIRE_CLOSE(arma::as_scalar(arma::accu(output)), -1.48227, 1e-3); + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + CheckMatrices(output, expectedOutput, 0.1); + + // Test for mean reduction. + + // Calculated using torch.nn.SoftMarginLoss(reduction='mean'). + expectedOutput = arma::mat("-0.0506 -0.0529 0.0594 -0.0522 0.0622 -0.0502 " + "0.0493 -0.0649 -0.0647"); + expectedOutput.reshape(3, 3); + + // Test the Forward function. Loss should be 0.712729. + // Value calculated using torch.nn.SoftMarginLoss(reduction='mean'). + loss = module2.Forward(input, target); + BOOST_REQUIRE_CLOSE(loss, 0.712729, 1e-3); + + // Test the Backward function. + module2.Backward(input, target, output); + BOOST_REQUIRE_CLOSE(arma::as_scalar(arma::accu(output)), -0.164697, 1e-3); + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + CheckMatrices(output, expectedOutput, 0.1); +} + BOOST_AUTO_TEST_SUITE_END(); From be400f36d9b57ace4c5e8291533816a4a8b1dc69 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Thu, 2 Jul 2020 18:20:27 +0530 Subject: [PATCH 201/297] Fix style issues in my files. --- src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp | 2 +- src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp b/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp index 149fe7b059..6050875113 100644 --- a/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/soft_margin_loss.hpp @@ -97,4 +97,4 @@ class SoftMarginLoss // include implementation. #include "soft_margin_loss_impl.hpp" -#endif \ No newline at end of file +#endif diff --git a/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp index 82059ce586..87fdb3f801 100644 --- a/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/soft_margin_loss_impl.hpp @@ -69,4 +69,4 @@ void SoftMarginLoss::serialize( } // namespace ann } // namespace mlpack -#endif \ No newline at end of file +#endif From 84e00489b49a530338150e2f80c30979320cc385 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 10 Jul 2020 15:48:52 +0530 Subject: [PATCH 202/297] some changes --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 42 ++++++++++++++-- src/mlpack/tests/ann_layer_test.cpp | 50 ++++++++++++-------- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 2e94496d82..9049661583 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -34,7 +34,21 @@ template void Lookup::Forward( const arma::Mat& input, arma::Mat& output) { - output = weights.cols(arma::conv_to::from(input) - 1); + Log::Assert((size_t) input.n_rows % inSize == 0); + + const size_t seqLength = input.n_rows / inSize; + const size_t batchSize = input.n_cols; + + arma::Cube inputTemp(const_cast&>(input).memptr(), inSize, + inSize, seqLength, batchSize, true, false); + + output.set_size(outSize * seqLength, batchSize); + + for (size_t i = 0; i < batchSize; ++i) + { + output.col(i) = arma::vectorise(weights.cols( + arma::conv_to::from(inputTemp.slice(i)) - 1)); + } } template @@ -54,8 +68,25 @@ void Lookup::Gradient( const arma::Mat& error, arma::Mat& gradient) { - gradient = arma::zeros >(weights.n_rows, weights.n_cols); - gradient.cols(arma::conv_to::from(input) - 1) = error; + Log::Assert((size_t) input.n_rows % inSize == 0); + + const size_t seqLength = input.n_rows / inSize; + const size_t batchSize = input.n_cols; + + arma::Cube inputTemp(const_cast&>(input).memptr(), inSize, + seqLength, batchSize, true, false); + arma::Cube errorTemp(const_cast&>(error).memptr(), outSize, + seqLength, batchSize, true, false); + + arma::Cube dW(weights.n_rows, weights.n_cols, batchSize); + + for (size_t i = 0; i < batchSize; ++i) + { + dW.slice(i).cols(arma::conv_to::from(inputTemp.slice(i)) - 1) + = errorTemp.slice(i); + } + + gradient = arma::mean(dW, 2); } template @@ -65,6 +96,11 @@ void Lookup::serialize( { ar & BOOST_SERIALIZATION_NVP(inSize); ar & BOOST_SERIALIZATION_NVP(outSize); + + // This is inefficient, but we have to allocate this memory so that + // WeightSetVisitor gets the right size. + if (Archive::is_loading::value) + weights.set_size(outSize, inSize); } } // namespace ann diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 6ab8036984..484c45e566 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1650,40 +1650,48 @@ BOOST_AUTO_TEST_CASE(GradientConcatenateLayerTest) */ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) { + const size_t inSize = 4; + const size_t outSize = 2; + const size_t seqLength = 3; + arma::mat output, input, delta, gradient; - Lookup<> module(10, 5); + + Lookup<> module(inSize, outSize); module.Parameters().randu(); // Test the Forward function. - input = arma::zeros(2, 1); - input(0) = 1; - input(1) = 3; + input = arma::zeros(inSize * seqLength, 1); + for (size_t i = 0; i < input.n_rows; ++i) + { + int token = math::RandInt(1, inSize); + input(i) = token; + } module.Forward(input, output); + output.print("Forward:"); - // The Lookup module uses index - 1 for the cols. - const double outputSum = arma::accu(module.Parameters().col(0)) + - arma::accu(module.Parameters().col(2)); + // // The Lookup module uses index - 1 for the cols. + // const double outputSum = arma::accu(module.Parameters().cols()); - BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output), 1e-3); + // BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output), 1e-3); - // Test the Backward function. - module.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(input)); + // // Test the Backward function. + // module.Backward(input, input, delta); + // BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(input)); - // Test the Gradient function. - arma::mat error = arma::ones(2, 5); - error = error.t(); - error.col(1) *= 0.5; + // // Test the Gradient function. + // arma::mat error = arma::ones(2, 5); + // error = error.t(); + // error.col(1) *= 0.5; - module.Gradient(input, error, gradient); + // module.Gradient(input, error, gradient); - // The Lookup module uses index - 1 for the cols. - const double gradientSum = arma::accu(gradient.col(0)) + - arma::accu(gradient.col(2)); + // // The Lookup module uses index - 1 for the cols. + // const double gradientSum = arma::accu(gradient.col(0)) + + // arma::accu(gradient.col(2)); - BOOST_REQUIRE_CLOSE(gradientSum, arma::accu(error), 1e-3); - BOOST_REQUIRE_CLOSE(arma::accu(gradient), arma::accu(error), 1e-3); + // BOOST_REQUIRE_CLOSE(gradientSum, arma::accu(error), 1e-3); + // BOOST_REQUIRE_CLOSE(arma::accu(gradient), arma::accu(error), 1e-3); } /** From 726ab0923cd7e5582f733e4089a69f1403b7386b Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sat, 11 Jul 2020 23:33:21 +0530 Subject: [PATCH 203/297] correcting lookup layer --- src/mlpack/methods/ann/layer/lookup.hpp | 14 ++--- src/mlpack/methods/ann/layer/lookup_impl.hpp | 46 +++++++--------- src/mlpack/tests/ann_layer_test.cpp | 56 +++++++++----------- 3 files changed, 50 insertions(+), 66 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index 93e70712ae..a2487f8d12 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -39,10 +39,10 @@ class Lookup * Create the Lookup object using the specified number of input and output * units. * - * @param inSize The number of input units. - * @param outSize The number of output units. + * @param vocabSize The number of input units. + * @param embeddingSize The number of output units. */ - Lookup(const size_t inSize = 0, const size_t outSize = 0); + Lookup(const size_t vocabSize = 0, const size_t embeddingSize = 0); /** * Ordinary feed forward pass of a neural network, evaluating the function @@ -101,10 +101,10 @@ class Lookup OutputDataType& Gradient() { return gradient; } //! Get the number of input units. - size_t InSize() const { return inSize; } + size_t VocabSize() const { return vocabSize; } //! Get the number of output units. - size_t OutSize() const { return outSize; } + size_t EmbeddingSize() const { return embeddingSize; } /** * Serialize the layer @@ -114,10 +114,10 @@ class Lookup private: //! Locally-stored number of input units. - size_t inSize; + size_t vocabSize; //! Locally-stored number of output units. - size_t outSize; + size_t embeddingSize; //! Locally-stored weight object. OutputDataType weights; diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 9049661583..e52ed37762 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -21,12 +21,12 @@ namespace ann /** Artificial Neural Network. */ { template Lookup::Lookup( - const size_t inSize, - const size_t outSize) : - inSize(inSize), - outSize(outSize) + const size_t vocabSize, + const size_t embeddingSize) : + vocabSize(vocabSize), + embeddingSize(embeddingSize) { - weights.set_size(outSize, inSize); + weights.set_size(embeddingSize, vocabSize); } template @@ -34,20 +34,15 @@ template void Lookup::Forward( const arma::Mat& input, arma::Mat& output) { - Log::Assert((size_t) input.n_rows % inSize == 0); - - const size_t seqLength = input.n_rows / inSize; + const size_t seqLength = input.n_rows; const size_t batchSize = input.n_cols; - arma::Cube inputTemp(const_cast&>(input).memptr(), inSize, - inSize, seqLength, batchSize, true, false); - - output.set_size(outSize * seqLength, batchSize); + output.set_size(embeddingSize * seqLength, batchSize); for (size_t i = 0; i < batchSize; ++i) { output.col(i) = arma::vectorise(weights.cols( - arma::conv_to::from(inputTemp.slice(i)) - 1)); + arma::conv_to::from(input.col(i)) - 1)); } } @@ -68,25 +63,20 @@ void Lookup::Gradient( const arma::Mat& error, arma::Mat& gradient) { - Log::Assert((size_t) input.n_rows % inSize == 0); - - const size_t seqLength = input.n_rows / inSize; + const size_t seqLength = input.n_rows; const size_t batchSize = input.n_cols; - arma::Cube inputTemp(const_cast&>(input).memptr(), inSize, - seqLength, batchSize, true, false); - arma::Cube errorTemp(const_cast&>(error).memptr(), outSize, - seqLength, batchSize, true, false); + arma::Cube errorTemp(const_cast&>(error).memptr(), + embeddingSize, seqLength, batchSize, true, false); - arma::Cube dW(weights.n_rows, weights.n_cols, batchSize); + gradient.set_size(arma::size(weights)); + gradient.zeros(); for (size_t i = 0; i < batchSize; ++i) { - dW.slice(i).cols(arma::conv_to::from(inputTemp.slice(i)) - 1) - = errorTemp.slice(i); + gradient.cols(arma::conv_to::from(input.col(i)) - 1) + += errorTemp.slice(i); } - - gradient = arma::mean(dW, 2); } template @@ -94,13 +84,13 @@ template void Lookup::serialize( Archive& ar, const unsigned int /* version */) { - ar & BOOST_SERIALIZATION_NVP(inSize); - ar & BOOST_SERIALIZATION_NVP(outSize); + ar & BOOST_SERIALIZATION_NVP(vocabSize); + ar & BOOST_SERIALIZATION_NVP(embeddingSize); // This is inefficient, but we have to allocate this memory so that // WeightSetVisitor gets the right size. if (Archive::is_loading::value) - weights.set_size(outSize, inSize); + weights.set_size(embeddingSize, vocabSize); } } // namespace ann diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 484c45e566..54763e569d 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1650,48 +1650,42 @@ BOOST_AUTO_TEST_CASE(GradientConcatenateLayerTest) */ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) { - const size_t inSize = 4; - const size_t outSize = 2; + const size_t vocabSize = 10; + const size_t embeddingSize = 2; const size_t seqLength = 3; + const size_t batchSize = 4; - arma::mat output, input, delta, gradient; + arma::mat output, input, gy, g, gradient; - Lookup<> module(inSize, outSize); + Lookup<> module(vocabSize, embeddingSize); module.Parameters().randu(); // Test the Forward function. - input = arma::zeros(inSize * seqLength, 1); - for (size_t i = 0; i < input.n_rows; ++i) + input = arma::zeros(seqLength, batchSize); + for (size_t i = 0; i < input.n_elem; ++i) { - int token = math::RandInt(1, inSize); + int token = math::RandInt(1, vocabSize); input(i) = token; } module.Forward(input, output); - output.print("Forward:"); + for (size_t i = 0; i < batchSize; ++i) + { + // The Lookup module uses index - 1 for the cols. + const double outputSum = arma::accu(module.Parameters().cols( + arma::conv_to::from(input.col(i)) - 1)); - // // The Lookup module uses index - 1 for the cols. - // const double outputSum = arma::accu(module.Parameters().cols()); + BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output.col(i)), 1e-3); + } - // BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output), 1e-3); + // Test the Backward function. + gy = 0.3 * arma::randu(embeddingSize * seqLength, batchSize); + module.Backward(input, gy, g); + BOOST_REQUIRE_EQUAL(arma::accu(gy), arma::accu(g)); - // // Test the Backward function. - // module.Backward(input, input, delta); - // BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(input)); - - // // Test the Gradient function. - // arma::mat error = arma::ones(2, 5); - // error = error.t(); - // error.col(1) *= 0.5; - - // module.Gradient(input, error, gradient); - - // // The Lookup module uses index - 1 for the cols. - // const double gradientSum = arma::accu(gradient.col(0)) + - // arma::accu(gradient.col(2)); - - // BOOST_REQUIRE_CLOSE(gradientSum, arma::accu(error), 1e-3); - // BOOST_REQUIRE_CLOSE(arma::accu(gradient), arma::accu(error), 1e-3); + // Test the Gradient function. + arma::mat error = 0.01 * arma::randu(embeddingSize * seqLength, batchSize); + module.Gradient(input, error, gradient); } /** @@ -1701,11 +1695,11 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) BOOST_AUTO_TEST_CASE(LookupLayerParametersTest) { // Parameter order : inSize, outSize. - Lookup<> layer(5, 7); + Lookup<> layer(100, 8); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.InSize(), 5); - BOOST_REQUIRE_EQUAL(layer.OutSize(), 7); + BOOST_REQUIRE_EQUAL(layer.VocabSize(), 100); + BOOST_REQUIRE_EQUAL(layer.EmbeddingSize(), 8); } /** From 7d7ff19cd787a1228ebf469aef3317b6b7972ff4 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sat, 11 Jul 2020 23:36:01 +0530 Subject: [PATCH 204/297] remove embedding file --- src/mlpack/methods/ann/layer/CMakeLists.txt | 2 - src/mlpack/methods/ann/layer/embedding.hpp | 179 ------------------ .../methods/ann/layer/embedding_impl.hpp | 129 ------------- 3 files changed, 310 deletions(-) delete mode 100644 src/mlpack/methods/ann/layer/embedding.hpp delete mode 100644 src/mlpack/methods/ann/layer/embedding_impl.hpp diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index b79ac980ed..c3ae086c87 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -34,8 +34,6 @@ set(SOURCES dropout_impl.hpp elu.hpp elu_impl.hpp - embedding.hpp - embedding_impl.hpp fast_lstm.hpp fast_lstm_impl.hpp flexible_relu.hpp diff --git a/src/mlpack/methods/ann/layer/embedding.hpp b/src/mlpack/methods/ann/layer/embedding.hpp deleted file mode 100644 index 0fa141f09f..0000000000 --- a/src/mlpack/methods/ann/layer/embedding.hpp +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @file embedding.hpp - * @author Mrityunjay Tripathi - * - * Definition of the Embedding 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_EMBEDDING_HPP -#define MLPACK_METHODS_ANN_LAYER_EMBEDDING_HPP - -#include -#include -#include - -namespace mlpack { -namespace ann /** Artificial Neural Network. */ { - -/** - * Word Embeddings, a featurized word-level representation capable of capturing - * the semantic meanings of words. It stores embeddings of a dictionary and can - * be retreived using their indices. It can only be used as first layer in an - * artificial neural network. - * - * @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, - typename InitializerType = RandomInitialization -> -class Embedding -{ - public: - /** - * Create the Embedding object. - */ - Embedding(); - - /** - * Create the Embedding layer object using specified parameters. - * - * @param dictionarySize The size of the dictionary i.e number of distinct - * words in the document. - * @param embeddingDim The size of each embedding vector. - * @param paddingIndex Whenever it encounters `paddingIndex`, it pads the - * output with embedding vector with zeros. - * @param freeze Specifies whether to update weight matrix of embedding layer - * after each forward pass. - */ - Embedding(const size_t dictionarySize, - const size_t embeddingDim, - const int paddingIndex = NULL, - const bool freeze = false); - - /** - * Reset the layer parameters. - */ - void ResetParameters(); - - /** - * 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 trough 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); - - /* - * Calculate the gradient using the output delta and the input activation. - * - * @param input The input parameter used for calculating the gradient. - * @param error The calculated error. - * @param gradient The calculated gradient. - */ - template - void Gradient(const arma::Mat& input, - const arma::Mat& error, - arma::Mat& gradient); - - //! Get the value of dictionarySize. - OutputDataType& DictionarySize() const { return dictionarySize; } - //! Modify the dictionarySize. - OutputDataType& DictionarySize() { return dictionarySize; } - - //! Get the value of embeddingDim. - OutputDataType& EmbeddingDim() const { return embeddingDim; } - //! Modify the embeddingDim. - OutputDataType& EmbeddingDim() { return embeddingDim; } - - //! Get the value of paddingIndex. - OutputDataType& PaddingIndex() const { return paddingIndex; } - //! Modify the paddingIndex. - OutputDataType& PaddingIndex() { return paddingIndex; } - - //! Get the parameters. - OutputDataType& Parameters() const { return weights; } - //! Modify the parameters. - OutputDataType& Parameters() { return weights; } - - //! Get the input parameter. - OutputDataType& InputParameter() const { return inputParameter; } - //! Modify the input parameter. - OutputDataType& InputParameter() { return inputParameter; } - - //! 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 size of the vocabulary. - size_t dictionarySize; - - //! Locally-stored size of each embedding vector. - size_t embeddingDim; - - //! Locally-stored value of padding index. - int paddingIndex; - - //! Specifies whether to update weight matrix after each forward pass. - bool freeze; - - //! Locally-stored weight object. - OutputDataType weights; - - //! Locally-stored delta object. - OutputDataType delta; - - //! Locally-stored gradient object - OutputDataType gradient; - - //! Locally-stored input parameter object. - InputDataType inputParameter; - - //! Locally-stored output parameter object. - OutputDataType outputParameter; -}; // class Embedding - -} // namespace ann -} // namespace mlpack - -// Include implementation. -#include "embedding_impl.hpp" - -#endif diff --git a/src/mlpack/methods/ann/layer/embedding_impl.hpp b/src/mlpack/methods/ann/layer/embedding_impl.hpp deleted file mode 100644 index dfcd95118a..0000000000 --- a/src/mlpack/methods/ann/layer/embedding_impl.hpp +++ /dev/null @@ -1,129 +0,0 @@ -/** - * @file embedding_impl.hpp - * @author Mrityunjay Tripathi - * - * Implementation of the Embedding 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_EMBEDDING_IMPL_HPP -#define MLPACK_METHODS_ANN_LAYER_EMBEDDING_IMPL_HPP - -// In case it hasn't yet been included. -#include "embedding.hpp" - -namespace mlpack { -namespace ann /** Artificial Neural Network. */ { - -template -Embedding -::Embedding() -{ - // Nothing to do here. -} - -template -Embedding -::Embedding(const size_t dictionarySize, - const size_t embeddingDim, - const int paddingIndex, - const bool freeze) : - dictionarySize(dictionarySize), - embeddingDim(embeddingDim), - freeze(freeze) -{ - typedef typename InputDataType::elem_type ElemType; - if (paddingIndex) - { - if (paddingIndex > 0) - { - Log::Assert(paddingIndex < this->embeddingDim, - "paddingIndex must be less than embeddingDim"); - this->paddingIndex = paddingIndex; - } - else - { - Log::Assert(paddingIndex >= - this->embeddingDim, - "paddingIndex must be less than embeddingDim"); - this->paddingIndex = paddingIndex + this->embeddingDim; - } - } - else - this->paddingIndex = paddingIndex; - this->weights.set_size(dictionarySize, embeddingDim); - ResetParameters(); -} - -template -void Embedding -::ResetParameters() -{ - typedef typename InputDataType::elem_type ElemType; - InitializerType init; - init.Initialize(weights, weights.n_rows, weights.n_cols); - if (paddingIndex) - { - weights.row(paddingIndex) = arma::zeros>(weights.n_cols); - } -} - -template -template -void Embedding -::Forward(const InputType& input, OutputType& output) -{ - output.set_size(input.n_cols * embeddingDim, input.n_rows); - for (size_t i = 0; i < input.n_rows; ++i) - { - output.col(i) = arma::vectorise(weights.rows( - arma::conv_to::from(input.row(i)))); - } -} - -template -template -void Embedding -::Backward(const arma::Mat& /* input */, - const arma::Mat& gy, - arma::Mat& g) -{ - g = gy; -} - -template -template -void Embedding -::Gradient(const arma::Mat& input, - const arma::Mat& error, - arma::Mat& gradient) -{ - gradient = arma::zeros>(weights.n_rows, weights.n_cols); - if (!freeze) - gradient.cols(input) = error; -} - -template -template -void Embedding -::serialize(Archive& ar, const unsigned int /* version */) -{ - ar & BOOST_SERIALIZATION_NVP(dictionarySize); - ar & BOOST_SERIALIZATION_NVP(embeddingDim); - ar & BOOST_SERIALIZATION_NVP(paddingIndex); - ar & BOOST_SERIALIZATION_NVP(freeze); -} - -} // namespace ann -} // namespace mlpack - -#endif From a7fce359ec612437946a18efd2f3cf9d9779c4e2 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sun, 12 Jul 2020 11:58:24 +0530 Subject: [PATCH 205/297] test for gradient function --- src/mlpack/tests/ann_layer_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 54763e569d..21dc7d3d59 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1686,6 +1686,8 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) // Test the Gradient function. arma::mat error = 0.01 * arma::randu(embeddingSize * seqLength, batchSize); module.Gradient(input, error, gradient); + + BOOST_CHECK_CLOSE_FRACTION(arma::accu(error), arma::accu(gradient), 1e-05); } /** From f5f399491dd0b2074f8b18ee8c74a50ab5ad682b Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sun, 12 Jul 2020 12:29:11 +0530 Subject: [PATCH 206/297] slight corrections in description of parameters --- src/mlpack/methods/ann/layer/lookup.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index a2487f8d12..c78ca16799 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -39,8 +39,8 @@ class Lookup * Create the Lookup object using the specified number of input and output * units. * - * @param vocabSize The number of input units. - * @param embeddingSize The number of output units. + * @param vocabSize The size of the vocabulary. + * @param embeddingSize The length of each embedding vector. */ Lookup(const size_t vocabSize = 0, const size_t embeddingSize = 0); @@ -100,10 +100,10 @@ class Lookup //! Modify the gradient. OutputDataType& Gradient() { return gradient; } - //! Get the number of input units. + //! Get the size of the vocabulary. size_t VocabSize() const { return vocabSize; } - //! Get the number of output units. + //! Get the length of each embedding vector. size_t EmbeddingSize() const { return embeddingSize; } /** @@ -113,10 +113,10 @@ class Lookup void serialize(Archive& ar, const unsigned int /* version */); private: - //! Locally-stored number of input units. + //! Locally-stored size of the vocabulary. size_t vocabSize; - //! Locally-stored number of output units. + //! Locally-stored length of each embedding vector. size_t embeddingSize; //! Locally-stored weight object. From 9306df291a9f32ac8fcf3ae1b2f1006b4c346405 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 17 Jul 2020 17:36:52 +0530 Subject: [PATCH 207/297] set copy_aux_mem to false --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index e52ed37762..8e5e1410d4 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -67,7 +67,7 @@ void Lookup::Gradient( const size_t batchSize = input.n_cols; arma::Cube errorTemp(const_cast&>(error).memptr(), - embeddingSize, seqLength, batchSize, true, false); + embeddingSize, seqLength, batchSize, false, false); gradient.set_size(arma::size(weights)); gradient.zeros(); From b5a405fd802ed3df60e01323ad8cc98f5f4c3f6d Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Sun, 19 Jul 2020 12:30:06 +0530 Subject: [PATCH 208/297] apply suggestions from code review Co-authored-by: Ryan Curtin --- src/mlpack/tests/ann_layer_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 612eb4f2a0..57a5846cf7 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1673,7 +1673,7 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) { // The Lookup module uses index - 1 for the cols. const double outputSum = arma::accu(module.Parameters().cols( - arma::conv_to::from(input.col(i)) - 1)); + arma::conv_to::from(input.col(i)) - 1)); BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output.col(i)), 1e-3); } From d5a37f28c1afc5e5e866ea6a201eb9f8389ed783 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 25 Jun 2020 10:33:53 +0530 Subject: [PATCH 209/297] adding bleu metric --- src/mlpack/core/metrics/CMakeLists.txt | 2 + src/mlpack/core/metrics/bleu_score.hpp | 121 +++++++++++++++ src/mlpack/core/metrics/bleu_score_impl.hpp | 159 ++++++++++++++++++++ src/mlpack/tests/metric_test.cpp | 60 +++++++- 4 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 src/mlpack/core/metrics/bleu_score.hpp create mode 100644 src/mlpack/core/metrics/bleu_score_impl.hpp diff --git a/src/mlpack/core/metrics/CMakeLists.txt b/src/mlpack/core/metrics/CMakeLists.txt index 5296f6124f..069f925640 100644 --- a/src/mlpack/core/metrics/CMakeLists.txt +++ b/src/mlpack/core/metrics/CMakeLists.txt @@ -1,6 +1,8 @@ # Define the files we need to compile. # Anything not in this list will not be compiled into mlpack. set(SOURCES + bleu_score.hpp + bleu_score_impl.hpp ip_metric.hpp ip_metric_impl.hpp iou_metric.hpp diff --git a/src/mlpack/core/metrics/bleu_score.hpp b/src/mlpack/core/metrics/bleu_score.hpp new file mode 100644 index 0000000000..e8edbb7998 --- /dev/null +++ b/src/mlpack/core/metrics/bleu_score.hpp @@ -0,0 +1,121 @@ +/** + * @file core/metrics/bleu_score.hpp + * @author Mrityunjay Tripathi + * + * BLEU, or the Bilingual Evaluation Understudy, is an algorithm for evaluating + * the quality of text which has been machine translated from one natural + * language to another. It can also be used to evaluate text generated for a + * suite of natural language processing tasks. + * + * 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_CORE_METRICS_BLEU_SCORE_HPP +#define MLPACK_CORE_METRICS_BLEU_SCORE_HPP + +#include + +namespace mlpack { +namespace metric { + +/** + * @tparam ElemType Type of the quantities in BLEU, eg. (long double, + * double, float) + * @tparam PrecisionType Container type for precision for corresponding order. + */ +template +> +class BLEU +{ + public: + /** + * Create an instance of BLEU class. + * + * @param maxOrder The maximum length of tokens in n-grams. + */ + BLEU(const size_t maxOrder = 4); + + /** + * Computes the BLEU Score. + * + * @tparam ReferenceCorpusType Type of reference corpus. + * @tparam TranslationCorpusType Type of translation corpus. + * @param referenceCorpus Reference corpus. + * @param translationCorpus Translation corpus. + * @param smooth Whether or not to apply Lin et al. 2004 smoothing. + */ + template + ElemType Evaluate(const ReferenceCorpusType& referenceCorpus, + const TranslationCorpusType& translationCorpus, + const bool smooth = false); + + //! Serialize the metric (nothing to do). + template + void serialize(Archive& /* ar */, const unsigned int /* version */) { } + + //! Get the value of maximum length of tokens in n-grams. + size_t MaxOrder() const { return maxOrder; } + //! Modify the value of maximum length of tokens in n-grams. + size_t& MaxOrder() { return maxOrder; } + + //! Get the BLEU Score. + ElemType BLEUScore() const { return bleuScore; } + + //! Get the brevity penalty. + ElemType BrevityPenalty() const { return brevityPenalty; } + + //! Get the value of translation length. + size_t TranslationLength() const { return translationLength; } + + //! Get the value of reference length. + size_t ReferenceLength() const { return referenceLength; } + + //! Get the ratio of translation to reference length ratio. + ElemType Ratio() const { return ratio; } + + //! Get the precisions for corresponding order. + PrecisionType const& Precisions() const { return precisions; } + + private: + /** + * Extracts all the n-grams. + * + * @tparam WordVector Type of the tokenized vector. + * @param segment Tokenized sequence represented in form of vector. + */ + template > + std::map GetNGrams(const WordVector& segment); + + //! Locally-stored value of maximum length of tokens in n-grams. + size_t maxOrder; + + //! Locally-stored BLEU score. + ElemType bleuScore; + + //! Locally-stored brevity penalty. It is a penalty for short machine + //! translation. + ElemType brevityPenalty; + + //! Locally-stored translation length. + size_t translationLength; + + //! Locally-stored reference length. + size_t referenceLength; + + //! Locally-stored translation to reference length ratio. + ElemType ratio; + + //! Locally stored precision for corresponding order. + PrecisionType precisions; +}; + +} // namespace metric +} // namespace mlpack + +// Include implementation. +#include "bleu_score_impl.hpp" + +#endif diff --git a/src/mlpack/core/metrics/bleu_score_impl.hpp b/src/mlpack/core/metrics/bleu_score_impl.hpp new file mode 100644 index 0000000000..5d3b52d144 --- /dev/null +++ b/src/mlpack/core/metrics/bleu_score_impl.hpp @@ -0,0 +1,159 @@ +/** + * @file core/metrics/bleu_score_impl.hpp + * @author Mrityunjay Tripathi + * + * Implementation of BLEUScore 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_CORE_METRICS_BLEU_SCORE_IMPLHPP +#define MLPACK_CORE_METRICS_BLEU_SCORE_IMPLHPP + +// In case it hasn't been included. +#include "bleu_score.hpp" + +namespace mlpack { +namespace metric { + +template +BLEU::BLEU(const size_t maxOrder) : + maxOrder(maxOrder), + translationLength(0), + referenceLength(0) +{ + // Nothing to do here. +} + +template +template +std::map BLEU::GetNGrams( + const WordVector& segment) +{ + std::map ngramsCount; + for (size_t order = 1; order < maxOrder + 1; ++order) + { + for (size_t i = 0; i < segment.size() - order + 1; ++i) + { + WordVector seq = WordVector(segment.begin() + i, + segment.begin() + i + order); + ngramsCount[seq]++; + } + } + return ngramsCount; +} + +template +template +ElemType BLEU::Evaluate( + const ReferenceCorpusType& referenceCorpus, + const TranslationCorpusType& translationCorpus, + const bool smooth) +{ + typedef typename TranslationCorpusType::value_type WordVector; + std::vector matchesByOrder(maxOrder, 0); + std::vector possibleMatchesByOrder(maxOrder, 0); + referenceLength = 0, translationLength = 0; + + auto refIt = referenceCorpus.cbegin(); + auto trIt = translationCorpus.cbegin(); + for (; refIt != referenceCorpus.cend(), trIt != translationCorpus.cend(); + ++refIt, ++trIt) + { + size_t min = std::numeric_limits::max(); + for (auto t: *refIt) + { + if (min > t.size()) + { + min = t.size(); + } + } + referenceLength += min; + translationLength += trIt->size(); + + std::map mergedRefNGramCounts; + for (auto t: *refIt) + { + const std::map ngrams = GetNGrams(t); + for (auto it = ngrams.cbegin(); it != ngrams.cend(); ++it) + { + if (!mergedRefNGramCounts[it->first]) + mergedRefNGramCounts[it->first] = it->second; + else + mergedRefNGramCounts[it->first] + = std::max(mergedRefNGramCounts[it->first], it->second); + } + } + + std::map translationNGramCounts = GetNGrams(*trIt); + std::map overlap; + for (auto it = mergedRefNGramCounts.cbegin(); + it != mergedRefNGramCounts.cend(); + ++it) + { + if (translationNGramCounts[it->first]) + { + overlap[it->first] = std::min(translationNGramCounts[it->first], + it->second); + } + } + + for (auto it = overlap.cbegin(); it != overlap.cend(); ++it) + { + matchesByOrder[it->first.size() - 1] += it->second; + } + + for (size_t order = 1; order < maxOrder + 1; ++order) + { + size_t possibleMatches = trIt->size() - order + 1; + if (possibleMatches > 0) + { + possibleMatchesByOrder[order - 1] += possibleMatches; + } + } + } + + precisions = PrecisionType(maxOrder, 0.0); + ElemType minPrecision = std::numeric_limits::max(); + for (size_t i = 0; i < maxOrder; ++i) + { + if (smooth) + precisions[i] + = (matchesByOrder[i] + 1.0) / (possibleMatchesByOrder[i] + 1.0); + else + { + if (possibleMatchesByOrder[i] > 0.0) + { + precisions[i] = ElemType(matchesByOrder[i]) / possibleMatchesByOrder[i]; + } + else + precisions[i] = 0.0; + } + if (minPrecision > precisions[i]) + minPrecision = precisions[i]; + } + + ElemType geoMean; + if (minPrecision > 0) + { + ElemType pLogSum = 0.0; + for (size_t i = 0; i < precisions.size(); ++i) + { + pLogSum += (1.0 / maxOrder) * std::log(precisions[i]); + } + geoMean = std::exp(pLogSum); + } + else + geoMean = 0.0; + ratio = ElemType(translationLength) / referenceLength; + brevityPenalty = (ratio > 1.0) ? 1.0 : std::exp(1.0 - 1.0 / ratio); + bleuScore = geoMean * brevityPenalty; + return bleuScore; +} + +} // namespace metric +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/metric_test.cpp b/src/mlpack/tests/metric_test.cpp index 92e6834bc3..09f897136f 100644 --- a/src/mlpack/tests/metric_test.cpp +++ b/src/mlpack/tests/metric_test.cpp @@ -13,12 +13,13 @@ #include #include #include +#include #include "test_tools.hpp" using namespace std; using namespace mlpack::metric; -BOOST_AUTO_TEST_SUITE(LMetricTest); +BOOST_AUTO_TEST_SUITE(MetricTest); /** * Simple test for L-1 metric. @@ -301,4 +302,61 @@ BOOST_AUTO_TEST_CASE(NMSMetricTest) CheckMatrices(desiredBoundingBox, selectedBoundingBox); } +/** + * + */ +BOOST_AUTO_TEST_CASE(BLEUScoreTest) +{ + typedef typename std::vector WordVector; + std::vector> referenceCorpus + = {{{"this", "is", "my", "house"}, + {"this", "is", "my", "car"}, + {"this", "is", "my", "bike"}}, + + {{"this", "is", "my", "table"}, + {"this", "is", "my", "chair"}, + {"this", "is", "my", "laptop"}}, + + {{"this", "is", "my", "table"}, + {"this", "is", "your", "car"}, + {"this", "is", "my", "notebook"}}}; + + std::vector translationCorpus + = {{"this", "is", "my", "book"}, + {"this", "is", "your", "car"}, + {"this", "is", "my", "watch"}}; + + BLEU<> bleu(4); + + //! We are not using smoothing function here. + bleu.Evaluate(referenceCorpus, translationCorpus); + BOOST_REQUIRE_CLOSE_FRACTION(bleu.BLEUScore(), 0.0, 1e-05); + BOOST_REQUIRE_EQUAL(bleu.BrevityPenalty(), 1.0); + BOOST_REQUIRE_EQUAL(bleu.Ratio(), 1.0); + BOOST_REQUIRE_EQUAL(bleu.TranslationLength(), 12); + BOOST_REQUIRE_EQUAL(bleu.ReferenceLength(), 12); + + std::vector expectedPrecision = {0.666666, 0.5555555, 0.3333333, 0}; + for (size_t i = 0; i < bleu.Precisions().size(); ++i) + { + BOOST_REQUIRE_CLOSE_FRACTION(bleu.Precisions()[i], + expectedPrecision[i], 1e-04); + } + + //! We will use smoothing function here by setting smooth to true. + bleu.Evaluate(referenceCorpus, translationCorpus, true); + BOOST_REQUIRE_CLOSE_FRACTION(bleu.BLEUScore(), 0.459307, 1e-05); + BOOST_REQUIRE_EQUAL(bleu.BrevityPenalty(), 1.0); + BOOST_REQUIRE_EQUAL(bleu.Ratio(), 1.0); + BOOST_REQUIRE_EQUAL(bleu.TranslationLength(), 12); + BOOST_REQUIRE_EQUAL(bleu.ReferenceLength(), 12); + + expectedPrecision = {0.692308, 0.6, 0.428571, 0.25}; + for (size_t i = 0; i < bleu.Precisions().size(); ++i) + { + BOOST_REQUIRE_CLOSE_FRACTION(bleu.Precisions()[i], + expectedPrecision[i], 1e-04); + } +} + BOOST_AUTO_TEST_SUITE_END(); From 92f9adfc07687fe6647c5a0cdd5bb85d98106aac Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 26 Jun 2020 10:13:42 +0530 Subject: [PATCH 210/297] adding comments and documentation --- src/mlpack/core/metrics/CMakeLists.txt | 4 +- .../core/metrics/{bleu_score.hpp => bleu.hpp} | 80 +++++-- src/mlpack/core/metrics/bleu_impl.hpp | 200 ++++++++++++++++++ src/mlpack/core/metrics/bleu_score_impl.hpp | 159 -------------- src/mlpack/tests/metric_test.cpp | 2 +- 5 files changed, 267 insertions(+), 178 deletions(-) rename src/mlpack/core/metrics/{bleu_score.hpp => bleu.hpp} (54%) create mode 100644 src/mlpack/core/metrics/bleu_impl.hpp delete mode 100644 src/mlpack/core/metrics/bleu_score_impl.hpp diff --git a/src/mlpack/core/metrics/CMakeLists.txt b/src/mlpack/core/metrics/CMakeLists.txt index 069f925640..843ac642d2 100644 --- a/src/mlpack/core/metrics/CMakeLists.txt +++ b/src/mlpack/core/metrics/CMakeLists.txt @@ -1,8 +1,8 @@ # Define the files we need to compile. # Anything not in this list will not be compiled into mlpack. set(SOURCES - bleu_score.hpp - bleu_score_impl.hpp + bleu.hpp + bleu_impl.hpp ip_metric.hpp ip_metric_impl.hpp iou_metric.hpp diff --git a/src/mlpack/core/metrics/bleu_score.hpp b/src/mlpack/core/metrics/bleu.hpp similarity index 54% rename from src/mlpack/core/metrics/bleu_score.hpp rename to src/mlpack/core/metrics/bleu.hpp index e8edbb7998..97f8d3614e 100644 --- a/src/mlpack/core/metrics/bleu_score.hpp +++ b/src/mlpack/core/metrics/bleu.hpp @@ -1,19 +1,16 @@ /** - * @file core/metrics/bleu_score.hpp + * @file core/metrics/bleu.hpp * @author Mrityunjay Tripathi * - * BLEU, or the Bilingual Evaluation Understudy, is an algorithm for evaluating - * the quality of text which has been machine translated from one natural - * language to another. It can also be used to evaluate text generated for a - * suite of natural language processing tasks. + * Definition of BLEU 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_CORE_METRICS_BLEU_SCORE_HPP -#define MLPACK_CORE_METRICS_BLEU_SCORE_HPP +#ifndef MLPACK_CORE_METRICS_BLEU_HPP +#define MLPACK_CORE_METRICS_BLEU_HPP #include @@ -21,12 +18,37 @@ namespace mlpack { namespace metric { /** - * @tparam ElemType Type of the quantities in BLEU, eg. (long double, - * double, float) + * BLEU, or the Bilingual Evaluation Understudy, is an algorithm for evaluating + * the quality of text which has been machine translated from one natural + * language to another. It can also be used to evaluate text generated for a + * suite of natural language processing tasks. + * + * The BLEU score is calculated using the following formula: + * + * \f{eqnarray*}{ + * \text{B} &=& bp \cdot \exp \left(\sum_{n=1}^{N} w \log p_n \right) \\ + * \text{where,} \\ + * bp &=& \text{brevity penalty} = + * \begin{cases} + * 1 & \text{if ratio} > 1 \\ + * \exp \left(1-\frac{1}{ratio}\right) & \text{otherwise} + * \end{cases} \\ + * p_n &=& \text{modified precision for n-gram,} \\ + * w &=& \frac {1}{maxOrder}, \\ + * ratio &=& \text{translation to reference length ratio,} \\ + * maxOrder &=& \text{maximum length of tokens in n-grams.} + * \f} + * + * The value of BLEU Score lies in between 0 and 1. + * + * @tparam ElemType Type of the quantities in BLEU, e.g. (long double, + * double, float). * @tparam PrecisionType Container type for precision for corresponding order. + * e.g. (std::vector, std::vector, or any such boost or + * armadillo container). */ template + typename PrecisionType = std::vector > class BLEU { @@ -43,18 +65,44 @@ class BLEU * * @tparam ReferenceCorpusType Type of reference corpus. * @tparam TranslationCorpusType Type of translation corpus. - * @param referenceCorpus Reference corpus. - * @param translationCorpus Translation corpus. + * @param referenceCorpus It is an array of various references or documents. + * So, the \f$ referenceCorpus = \{reference_1, reference_2, \ldots \} \f$ + * and each reference is an array of paragraphs. So, + * \f$ reference_i = \{paragraph_1, paragraph_2, \ldots \} \f$ + * and then each paragraph is an array of tokenized words/string. Like, + * \f$ paragraph_i = \{word_1, word_2, \ldots \} \f$. + * For ex. + * ``` + * refCorpus = {{{"this", "is", "paragraph", "1", "from", "document", "1"}, + * {"this", "is", "paragraph", "2", "from", "document", "1"}}, + * + * {{"this", "is", "paragraph", "1", "from", "document", "2"}, + * {"this", "is", "paragraph", "2", "from", "document", "2"}}} + * ``` + * @param translationCorpus It is an array of paragraphs which has been + * machine translated or generated for any natural language processing task. + * Like, \f$ translationCorpus = \{paragraph_1, paragraph_2, \ldots \} \f$. + * And then, each paragraph is an array of words. The ith paragraph from the + * corpus is \f$ paragraph_i = \{word_1, word_2, \ldots \} \f$. + * For ex. + * ``` + * transCorpus = {{"this", "is", "generated", "paragraph", "1"}, + * {"this", "is", "generated", "paragraph", "2"}} + * ``` * @param smooth Whether or not to apply Lin et al. 2004 smoothing. + * @return The Evaluate method returns the BLEU Score. This method also + * calculates other BLEU metrics (brevity penalty, translation length, reference + * length, ratio and precisions) which can be accessed by their corresponding + * accessor methods. */ template ElemType Evaluate(const ReferenceCorpusType& referenceCorpus, const TranslationCorpusType& translationCorpus, const bool smooth = false); - //! Serialize the metric (nothing to do). + //! Serialize the metric. template - void serialize(Archive& /* ar */, const unsigned int /* version */) { } + void serialize(Archive& ar, const unsigned int /* version */); //! Get the value of maximum length of tokens in n-grams. size_t MaxOrder() const { return maxOrder; } @@ -86,7 +134,7 @@ class BLEU * @tparam WordVector Type of the tokenized vector. * @param segment Tokenized sequence represented in form of vector. */ - template > + template std::map GetNGrams(const WordVector& segment); //! Locally-stored value of maximum length of tokens in n-grams. @@ -116,6 +164,6 @@ class BLEU } // namespace mlpack // Include implementation. -#include "bleu_score_impl.hpp" +#include "bleu_impl.hpp" #endif diff --git a/src/mlpack/core/metrics/bleu_impl.hpp b/src/mlpack/core/metrics/bleu_impl.hpp new file mode 100644 index 0000000000..ab64ae4373 --- /dev/null +++ b/src/mlpack/core/metrics/bleu_impl.hpp @@ -0,0 +1,200 @@ +/** + * @file core/metrics/bleu_impl.hpp + * @author Mrityunjay Tripathi + * + * Implementation of BLEU 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_CORE_METRICS_BLEU_IMPL_HPP +#define MLPACK_CORE_METRICS_BLEU_IMPL_HPP + +// In case it hasn't been included. +#include "bleu.hpp" + +namespace mlpack { +namespace metric { + +template +BLEU::BLEU(const size_t maxOrder) : + maxOrder(maxOrder), + translationLength(0), + referenceLength(0) +{ + // Nothing to do here. +} + +template +template +std::map BLEU::GetNGrams( + const WordVector& segment) +{ + std::map ngramsCount; + for (size_t order = 1; order < maxOrder + 1; ++order) + { + for (size_t i = 0; i + order < segment.size() + 1; ++i) + { + WordVector seq = WordVector(segment.cbegin() + i, + segment.cbegin() + i + order); + ngramsCount[seq]++; + } + } + return ngramsCount; +} + +template +template +ElemType BLEU::Evaluate( + const ReferenceCorpusType& referenceCorpus, + const TranslationCorpusType& translationCorpus, + const bool smooth) +{ + // WordVector is a string container type. + // Also, TranslationCorpusType is an array of such containers. + typedef typename TranslationCorpusType::value_type WordVector; + + // matchesByOrder: It catches how many times sequence of a particular order + // is encountered in both reference corpus and translation corpus. + std::vector matchesByOrder(maxOrder, 0); + + // possibleMatchesByOrder: It tracks how many possible matches can be in the + // translation corpus. + std::vector possibleMatchesByOrder(maxOrder, 0); + + // referenceLength: It is the sum of minimum length of the paragraph from + // various documents. + // translationLength: It is the sum of length of each paragraphs. + referenceLength = 0, translationLength = 0; + + auto refIt = referenceCorpus.cbegin(); + auto trIt = translationCorpus.cbegin(); + for (; refIt != referenceCorpus.cend(), trIt != translationCorpus.cend(); + ++refIt, ++trIt) + { + size_t min = std::numeric_limits::max(); + for (const auto& t : *refIt) + { + if (min > t.size()) + { + min = t.size(); + } + } + + if (min == std::numeric_limits::max()) + min = 0; + + referenceLength += min; + translationLength += trIt->size(); + + // mergedRefNGramCounts: It accumulates all the similar n-grams from + // various references or documents, so that there is no repetition of + // any key (sequence of order n). + std::map mergedRefNGramCounts; + for (const auto& t : *refIt) + { + // ngram: It holds the n-grams of each document/reference. + const std::map ngrams = GetNGrams(t); + for (auto it = ngrams.cbegin(); it != ngrams.cend(); ++it) + { + mergedRefNGramCounts[it->first] = std::max(it->second, + mergedRefNGramCounts[it->first]); + } + } + // translationNGramCounts: It extracts the n-grams of the generated text + // sequence. + const std::map translationNGramCounts + = GetNGrams(*trIt); + + // overlap: It holds those keys (sequence of order n) which are common to + // reference corpus and translation corpus. + std::map overlap; + for (auto it = translationNGramCounts.cbegin(); + it != translationNGramCounts.cend(); + ++it) + { + auto mergedIt = mergedRefNGramCounts.find(it->first); + if (mergedIt != mergedRefNGramCounts.end()) + { + // If the key (sequence of order n) is present in both translation + // corpus as well as reference corpus, then the minimum number of + // counts it has occurred in any is considered. + overlap[it->first] = std::min(mergedIt->second, it->second); + } + } + + for (auto it = overlap.cbegin(); it != overlap.cend(); ++it) + { + matchesByOrder[it->first.size() - 1] += it->second; + } + + for (size_t order = 1; order < maxOrder + 1; ++order) + { + if (order < trIt->size() + 1) + possibleMatchesByOrder[order - 1] += trIt->size() - order + 1; + } + } + + precisions = PrecisionType(maxOrder, 0.0); + + if (smooth) + { + for (size_t i = 0; i < maxOrder; ++i) + { + precisions[i] + = (matchesByOrder[i] + 1.0) / (possibleMatchesByOrder[i] + 1.0); + } + } + else + { + for (size_t i = 0; i < maxOrder; ++i) + { + if (possibleMatchesByOrder[i] > 0) + precisions[i] = ElemType(matchesByOrder[i]) / possibleMatchesByOrder[i]; + else + precisions[i] = 0.0; + } + } + + ElemType minPrecision = std::numeric_limits::max(); + for (size_t i = 0; i < maxOrder; ++i) + { + if (minPrecision > precisions[i]) + minPrecision = precisions[i]; + } + + ElemType geometricMean; + if (minPrecision > 0) + { + ElemType pLogSum = 0.0; + for (const auto& t : precisions) + { + pLogSum += (1.0 / maxOrder) * std::log(t); + } + geometricMean = std::exp(pLogSum); + } + else + geometricMean = 0.0; + + ratio = ElemType(translationLength) / referenceLength; + brevityPenalty = (ratio > 1.0) ? 1.0 : std::exp(1.0 - 1.0 / ratio); + bleuScore = geometricMean * brevityPenalty; + + return bleuScore; +} + +template +template +void BLEU::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(maxOrder); +} + +} // namespace metric +} // namespace mlpack + +#endif diff --git a/src/mlpack/core/metrics/bleu_score_impl.hpp b/src/mlpack/core/metrics/bleu_score_impl.hpp deleted file mode 100644 index 5d3b52d144..0000000000 --- a/src/mlpack/core/metrics/bleu_score_impl.hpp +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file core/metrics/bleu_score_impl.hpp - * @author Mrityunjay Tripathi - * - * Implementation of BLEUScore 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_CORE_METRICS_BLEU_SCORE_IMPLHPP -#define MLPACK_CORE_METRICS_BLEU_SCORE_IMPLHPP - -// In case it hasn't been included. -#include "bleu_score.hpp" - -namespace mlpack { -namespace metric { - -template -BLEU::BLEU(const size_t maxOrder) : - maxOrder(maxOrder), - translationLength(0), - referenceLength(0) -{ - // Nothing to do here. -} - -template -template -std::map BLEU::GetNGrams( - const WordVector& segment) -{ - std::map ngramsCount; - for (size_t order = 1; order < maxOrder + 1; ++order) - { - for (size_t i = 0; i < segment.size() - order + 1; ++i) - { - WordVector seq = WordVector(segment.begin() + i, - segment.begin() + i + order); - ngramsCount[seq]++; - } - } - return ngramsCount; -} - -template -template -ElemType BLEU::Evaluate( - const ReferenceCorpusType& referenceCorpus, - const TranslationCorpusType& translationCorpus, - const bool smooth) -{ - typedef typename TranslationCorpusType::value_type WordVector; - std::vector matchesByOrder(maxOrder, 0); - std::vector possibleMatchesByOrder(maxOrder, 0); - referenceLength = 0, translationLength = 0; - - auto refIt = referenceCorpus.cbegin(); - auto trIt = translationCorpus.cbegin(); - for (; refIt != referenceCorpus.cend(), trIt != translationCorpus.cend(); - ++refIt, ++trIt) - { - size_t min = std::numeric_limits::max(); - for (auto t: *refIt) - { - if (min > t.size()) - { - min = t.size(); - } - } - referenceLength += min; - translationLength += trIt->size(); - - std::map mergedRefNGramCounts; - for (auto t: *refIt) - { - const std::map ngrams = GetNGrams(t); - for (auto it = ngrams.cbegin(); it != ngrams.cend(); ++it) - { - if (!mergedRefNGramCounts[it->first]) - mergedRefNGramCounts[it->first] = it->second; - else - mergedRefNGramCounts[it->first] - = std::max(mergedRefNGramCounts[it->first], it->second); - } - } - - std::map translationNGramCounts = GetNGrams(*trIt); - std::map overlap; - for (auto it = mergedRefNGramCounts.cbegin(); - it != mergedRefNGramCounts.cend(); - ++it) - { - if (translationNGramCounts[it->first]) - { - overlap[it->first] = std::min(translationNGramCounts[it->first], - it->second); - } - } - - for (auto it = overlap.cbegin(); it != overlap.cend(); ++it) - { - matchesByOrder[it->first.size() - 1] += it->second; - } - - for (size_t order = 1; order < maxOrder + 1; ++order) - { - size_t possibleMatches = trIt->size() - order + 1; - if (possibleMatches > 0) - { - possibleMatchesByOrder[order - 1] += possibleMatches; - } - } - } - - precisions = PrecisionType(maxOrder, 0.0); - ElemType minPrecision = std::numeric_limits::max(); - for (size_t i = 0; i < maxOrder; ++i) - { - if (smooth) - precisions[i] - = (matchesByOrder[i] + 1.0) / (possibleMatchesByOrder[i] + 1.0); - else - { - if (possibleMatchesByOrder[i] > 0.0) - { - precisions[i] = ElemType(matchesByOrder[i]) / possibleMatchesByOrder[i]; - } - else - precisions[i] = 0.0; - } - if (minPrecision > precisions[i]) - minPrecision = precisions[i]; - } - - ElemType geoMean; - if (minPrecision > 0) - { - ElemType pLogSum = 0.0; - for (size_t i = 0; i < precisions.size(); ++i) - { - pLogSum += (1.0 / maxOrder) * std::log(precisions[i]); - } - geoMean = std::exp(pLogSum); - } - else - geoMean = 0.0; - ratio = ElemType(translationLength) / referenceLength; - brevityPenalty = (ratio > 1.0) ? 1.0 : std::exp(1.0 - 1.0 / ratio); - bleuScore = geoMean * brevityPenalty; - return bleuScore; -} - -} // namespace metric -} // namespace mlpack - -#endif diff --git a/src/mlpack/tests/metric_test.cpp b/src/mlpack/tests/metric_test.cpp index 09f897136f..6eaabe3ebc 100644 --- a/src/mlpack/tests/metric_test.cpp +++ b/src/mlpack/tests/metric_test.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "test_tools.hpp" using namespace std; From 1024073670861abba316de9eeaa5f10aa5c2ae41 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 21 Jul 2020 21:31:06 +0530 Subject: [PATCH 211/297] documentation fix --- src/mlpack/methods/ann/layer/lookup.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index c78ca16799..1aa70bf648 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -68,7 +68,7 @@ class Lookup const arma::Mat& gy, arma::Mat& g); - /* + /** * Calculate the gradient using the output delta and the input activation. * * @param input The input parameter used for calculating the gradient. From 248d7d37901886d0fc3176b9f38956c781f16336 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 21 Jul 2020 23:21:17 +0530 Subject: [PATCH 212/297] add gradient test --- src/mlpack/tests/ann_layer_test.cpp | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 57a5846cf7..3c92e2f72b 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -1690,6 +1692,59 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) BOOST_CHECK_CLOSE_FRACTION(arma::accu(error), arma::accu(gradient), 1e-05); } +/** + * Lookup layer numerical gradient test. + */ +BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) +{ + // Lookup function gradient instantiation. + struct GradientFunction + { + GradientFunction() + { + const size_t seqLength = 10; + const size_t embeddingSize = 8; + const size_t vocabSize = 20; + const size_t batchSize = 1; + + input.set_size(seqLength, batchSize); + for (size_t i = 0; i < input.n_elem; ++i) + { + input(i) = math::RandInt(1, 20); + } + target.set_size(vocabSize, batchSize); + target(vocabSize - 1) = 1; + + model = new FFN, GlorotInitialization>(); + model->Predictors() = input; + model->Responses() = target; + model->Add >(); + model->Add >(vocabSize, embeddingSize); + model->Add >(embeddingSize * seqLength, vocabSize); + model->Add >(); + } + + ~GradientFunction() + { + delete model; + } + + double Gradient(arma::mat& gradient) const + { + double error = model->Evaluate(model->Parameters(), 0, 1); + model->Gradient(model->Parameters(), 0, gradient, 1); + return error; + } + + arma::mat& Parameters() { return model->Parameters(); } + + FFN, GlorotInitialization>* model; + arma::mat input, target; + } function; + + BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); +} + /** * Test that the functions that can access the parameters of the * Lookup layer work. From e525bbdcfa3a5bd03952f4449a57d1658e54a096 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Wed, 22 Jul 2020 09:07:28 +0530 Subject: [PATCH 213/297] some changes --- src/mlpack/tests/ann_layer_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 3c92e2f72b..cdb665a0e9 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1712,7 +1712,7 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) { input(i) = math::RandInt(1, 20); } - target.set_size(vocabSize, batchSize); + target = arma::zeros(vocabSize, batchSize); target(vocabSize - 1) = 1; model = new FFN, GlorotInitialization>(); @@ -1742,7 +1742,7 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + BOOST_REQUIRE_LE(CheckGradient(function), 1e-5); } /** From 24739671d280cc16c6d99d34408f32f86f646ba6 Mon Sep 17 00:00:00 2001 From: cmercier Date: Wed, 22 Jul 2020 09:22:09 +0200 Subject: [PATCH 214/297] Initialization of class member arguments in the constructor. --- .../bayesian_linear_regression.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 87e42f834d..44146753fe 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -23,7 +23,11 @@ BayesianLinearRegression::BayesianLinearRegression(const bool centerData, centerData(centerData), scaleData(scaleData), nIterMax(nIterMax), - tol(tol) + tol(tol), + responsesOffset(0.0), + alpha(0.0), + beta(0.0), + gamma(0.0) {/* Nothing to do */} double BayesianLinearRegression::Train(const arma::mat& data, @@ -121,7 +125,6 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, arma::rowvec& responsesProc) { // Initialize the offsets to their neutral forms. - responsesOffset = 0.0; if (!centerData && !scaleData) { dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, From eedbbf69a766892944b74a7a84744d1f43aaeade Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Wed, 22 Jul 2020 20:40:49 +0530 Subject: [PATCH 215/297] apply suggestions from code review Co-authored-by: Mikhail Lozhnikov --- src/mlpack/core/metrics/bleu_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/metrics/bleu_impl.hpp b/src/mlpack/core/metrics/bleu_impl.hpp index ab64ae4373..ac7389cf29 100644 --- a/src/mlpack/core/metrics/bleu_impl.hpp +++ b/src/mlpack/core/metrics/bleu_impl.hpp @@ -71,7 +71,7 @@ ElemType BLEU::Evaluate( auto refIt = referenceCorpus.cbegin(); auto trIt = translationCorpus.cbegin(); - for (; refIt != referenceCorpus.cend(), trIt != translationCorpus.cend(); + for (; refIt != referenceCorpus.cend() && trIt != translationCorpus.cend(); ++refIt, ++trIt) { size_t min = std::numeric_limits::max(); From 7fca30afc0da44d65d4f481b875ff22b82c6b491 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Thu, 23 Jul 2020 07:12:26 +0530 Subject: [PATCH 216/297] apply suggestions from code review Co-authored-by: Mikhail Lozhnikov --- src/mlpack/tests/ann_layer_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index cdb665a0e9..f08dcdf5b1 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1710,7 +1710,7 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) input.set_size(seqLength, batchSize); for (size_t i = 0; i < input.n_elem; ++i) { - input(i) = math::RandInt(1, 20); + input(i) = math::RandInt(1, vocabSize); } target = arma::zeros(vocabSize, batchSize); target(vocabSize - 1) = 1; @@ -1731,8 +1731,8 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) double Gradient(arma::mat& gradient) const { - double error = model->Evaluate(model->Parameters(), 0, 1); - model->Gradient(model->Parameters(), 0, gradient, 1); + double error = model->Evaluate(model->Parameters(), 0, batchSize); + model->Gradient(model->Parameters(), 0, gradient, batchSize); return error; } From 232de366429633935ea4c523695c1d99974a2d91 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 23 Jul 2020 07:53:07 +0530 Subject: [PATCH 217/297] gradient test with batch size > 1 --- src/mlpack/tests/ann_layer_test.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index f08dcdf5b1..5e6fae6776 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1702,18 +1702,17 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) { GradientFunction() { - const size_t seqLength = 10; - const size_t embeddingSize = 8; - const size_t vocabSize = 20; - const size_t batchSize = 1; - input.set_size(seqLength, batchSize); for (size_t i = 0; i < input.n_elem; ++i) { input(i) = math::RandInt(1, vocabSize); } target = arma::zeros(vocabSize, batchSize); - target(vocabSize - 1) = 1; + for (size_t i = 0; i < batchSize; ++i) + { + const size_t predictedWord = math::RandInt(1, vocabSize); + target(predictedWord, i) = 1; + } model = new FFN, GlorotInitialization>(); model->Predictors() = input; @@ -1740,6 +1739,11 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) FFN, GlorotInitialization>* model; arma::mat input, target; + + const size_t seqLength = 10; + const size_t embeddingSize = 8; + const size_t vocabSize = 20; + const size_t batchSize = 4; } function; BOOST_REQUIRE_LE(CheckGradient(function), 1e-5); From f583b0ab282c2021589f16d8dcd9175a27a8ea47 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 23 Jul 2020 10:07:47 +0530 Subject: [PATCH 218/297] rename variable [ci skip] --- src/mlpack/tests/ann_layer_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 5e6fae6776..bd23cc5646 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1710,8 +1710,8 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) target = arma::zeros(vocabSize, batchSize); for (size_t i = 0; i < batchSize; ++i) { - const size_t predictedWord = math::RandInt(1, vocabSize); - target(predictedWord, i) = 1; + const size_t targetWord = math::RandInt(1, vocabSize); + target(targetWord, i) = 1; } model = new FFN, GlorotInitialization>(); From ebf63a5edb564f211ed9cc60bc88406454ef1d2b Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:17:49 +0200 Subject: [PATCH 219/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 8a1a29d530..c9250a5173 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -10,7 +10,7 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ #include -#include +#include #include #include "bayesian_linear_regression.hpp" From ebbe6938005b1ea5d7cfd6cd92bf27f6ad0d6bf7 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:18:05 +0200 Subject: [PATCH 220/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index c9250a5173..4e740d64aa 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -112,8 +112,8 @@ PARAM_FLAG("scale", "Scale each feature by their standard deviations if " static void mlpackMain() { - bool center = CLI::GetParam("center"); - bool scale = CLI::GetParam("scale"); + bool center = IO::GetParam("center"); + bool scale = IO::GetParam("scale"); // Check parameters -- make sure everything given makes sense. RequireOnlyOnePassed({"input", "input_model"}, true); From 730a59db0387ec4a186fc6a3f3caf816b12d8996 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:18:18 +0200 Subject: [PATCH 221/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 4e740d64aa..078b31b98e 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -117,7 +117,7 @@ static void mlpackMain() // Check parameters -- make sure everything given makes sense. RequireOnlyOnePassed({"input", "input_model"}, true); - if (CLI::HasParam("input")) + if (IO::HasParam("input")) { RequireOnlyOnePassed({"responses"}, true, "if input data is specified, " "responses must also be specified"); From 003dab21c816c7f5d2eea3d5c225f5f36bb08cfc Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:18:27 +0200 Subject: [PATCH 222/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 078b31b98e..cdabcc1b3a 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -145,7 +145,7 @@ static void mlpackMain() // seems more likely that these will be stored with one response per line // (one per row). So we should not transpose upon loading. arma::rowvec responses = std::move( - CLI::GetParam("responses")); + IO::GetParam("responses")); if (responses.n_elem != matX.n_cols) { From 4468ff9359e9dd81ba71233777c1c6197792f859 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:18:44 +0200 Subject: [PATCH 223/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index cdabcc1b3a..5527b541a2 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -131,7 +131,7 @@ static void mlpackMain() ReportIgnoredParam({{"test", false}}, "predictions"); BayesianLinearRegression* bayesLinReg; - if (CLI::HasParam("input")) + if (IO::HasParam("input")) { Log::Info << "input detected " << std::endl; // Initialize the object. From cfea46a8be0ade26c919f703be34a623e2eac31e Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:18:53 +0200 Subject: [PATCH 224/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index eb94d76fc9..232334f9bb 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -37,7 +37,7 @@ struct BRTestFixture { // Clear the settings. bindings::tests::CleanMemory(); - CLI::ClearSettings(); + IO::ClearSettings(); } }; From 926366981fcf32c0276ae03c746a9a6d3281d7e1 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:19:03 +0200 Subject: [PATCH 225/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 232334f9bb..4da8828798 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(BRCenter0Scale0) mlpackMain(); BayesianLinearRegression* estimator = - CLI::GetParam("output_model"); + IO::GetParam("output_model"); BOOST_REQUIRE(estimator->DataOffset().n_elem == 0); BOOST_REQUIRE(estimator->DataScale().n_elem == 0); From cfc299f7fc3fde4cc3ae7b96cb586e4d24487c7a Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:19:19 +0200 Subject: [PATCH 226/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 4da8828798..e1943f68a1 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) CLI::GetSingleton().Parameters()["responses"].wasPassed = false; SetInputParam("input_model", - CLI::GetParam("output_model")); + IO::GetParam("output_model")); SetInputParam("test", std::move(matXtest)); mlpackMain(); From 077387aa0820b6919bee7a729294f59cb3002d56 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:19:31 +0200 Subject: [PATCH 227/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index e1943f68a1..b2a9d288f4 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) arma::mat ytest = std::move(responses); // Check that initial output and output using saved model are same. - CheckMatrices(ytest, CLI::GetParam("predictions")); + CheckMatrices(ytest, IO::GetParam("predictions")); } /** From e24a693a388a45cfbe2ee575ecd0f1cf69067144 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:19:43 +0200 Subject: [PATCH 228/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index b2a9d288f4..bdfbf91118 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(CheckParamsPassed) // An error should occur. SetInputParam("input", std::move(matX)); SetInputParam("input_model", - CLI::GetParam("output_model")); + IO::GetParam("output_model")); SetInputParam("test", std::move(matXtest)); BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); From 31c03b3b2f28de3ba99dee26b6692e8d009fc3e5 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:19:54 +0200 Subject: [PATCH 229/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 5527b541a2..b9fe3cab16 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -160,7 +160,7 @@ static void mlpackMain() } else // We must have --input_model_file. { - bayesLinReg = CLI::GetParam("input_model"); + bayesLinReg = IO::GetParam("input_model"); } if (CLI::HasParam("test")) From de86fb980853809356c223d057464d2f2ff6819a Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:20:13 +0200 Subject: [PATCH 230/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index b9fe3cab16..53deaf1449 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -167,7 +167,7 @@ static void mlpackMain() { Log::Info << "Regressing on test points." << endl; // Load test points. - mat testPoints = std::move(CLI::GetParam("test")); + mat testPoints = std::move(IO::GetParam("test")); arma::rowvec predictions; if (CLI::HasParam("stds")) From 26f7cd76119a175f83fa2307392f79b2fac40fc7 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:20:26 +0200 Subject: [PATCH 231/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 53deaf1449..6ed33ad972 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -176,7 +176,7 @@ static void mlpackMain() bayesLinReg->Predict(testPoints, predictions, std); // Save the standard deviation of the test points (one per line). - CLI::GetParam("stds") = std::move(std); + IO::GetParam("stds") = std::move(std); } else { From 54bda4b53629b611437737cdbfc650e1fef157a2 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:20:41 +0200 Subject: [PATCH 232/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 6ed33ad972..c33f41d92e 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -184,7 +184,7 @@ static void mlpackMain() } // Save test predictions (one per line). - CLI::GetParam("predictions") = std::move(predictions); + IO::GetParam("predictions") = std::move(predictions); } CLI::GetParam("output_model") = bayesLinReg; From 2e10320324780313be10c9012007c350251922a2 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:20:57 +0200 Subject: [PATCH 233/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index c33f41d92e..4509c3e4c9 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -187,5 +187,5 @@ static void mlpackMain() IO::GetParam("predictions") = std::move(predictions); } - CLI::GetParam("output_model") = bayesLinReg; + IO::GetParam("output_model") = bayesLinReg; } From ab74c6e8a94ad83a0116299fe61a332f3a85e87b Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:21:10 +0200 Subject: [PATCH 234/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 4509c3e4c9..39c04fc4b4 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -139,7 +139,7 @@ static void mlpackMain() // Load covariates. We can avoid LARS transposing our data by choosing to // not transpose this data (that's why we used PARAM_TMATRIX_IN). - mat matX = std::move(CLI::GetParam("input")); + mat matX = std::move(IO::GetParam("input")); // Load responses. The responses should be a one-dimensional vector, and it // seems more likely that these will be stored with one response per line From 7d2bbb574ba8d3f34b73a3d220ac8791c2b6d215 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:21:24 +0200 Subject: [PATCH 235/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index bdfbf91118..8b9c599530 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -30,7 +30,7 @@ struct BRTestFixture BRTestFixture() { // Cache in the options for this program. - CLI::RestoreSettings(testName); + IO::RestoreSettings(testName); } ~BRTestFixture() From 3ee8375e48040bccdbf8317e70e5157841ec0ff5 Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 23 Jul 2020 09:27:32 +0200 Subject: [PATCH 236/297] Suppress comment. --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 44146753fe..472c1638d9 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -124,7 +124,6 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, arma::mat& dataProc, arma::rowvec& responsesProc) { - // Initialize the offsets to their neutral forms. if (!centerData && !scaleData) { dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, From 469ef5cea5dad3d3ced18eaa3909f87f781f50af Mon Sep 17 00:00:00 2001 From: cmercier Date: Thu, 23 Jul 2020 11:22:16 +0200 Subject: [PATCH 237/297] Formatting. --- .../bayesian_linear_regression.cpp | 6 +++--- src/mlpack/tests/bayesian_linear_regression_test.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index 472c1638d9..f9af417729 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -126,7 +126,7 @@ double BayesianLinearRegression::CenterScaleData(const arma::mat& data, { if (!centerData && !scaleData) { - dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, + dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, data.n_cols, false, true); responsesProc = arma::rowvec(const_cast(responses.memptr()), responses.n_elem, false, @@ -167,7 +167,7 @@ void BayesianLinearRegression::CenterScaleDataPred( { if (!centerData && !scaleData) { - dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, + dataProc = arma::mat(const_cast(data.memptr()), data.n_rows, data.n_cols, false, true); } @@ -177,7 +177,7 @@ void BayesianLinearRegression::CenterScaleDataPred( } else if (!centerData && scaleData) - { + { dataProc = data.each_col() / dataScale; } diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 19c5507dae..344a3130c1 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -180,14 +180,14 @@ BOOST_AUTO_TEST_CASE(EqualtoRidge) if (arma::norm(blrPred - ridgePred) > 1e-5) continue; - // Check the predictions are close enough between ridge and our tested model. + // Check the predictions are close enough between ridge and our blr. for (size_t i = 0; i < y.size(); ++i) BOOST_REQUIRE_CLOSE(blrPred[i], ridgePred[i], 1); // Exit once a test case has completed. break; } - + BOOST_REQUIRE_LT(trial, 3); } From 4d56993b3cfa458e64c31f010ce0e2fe4f7b7385 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Thu, 23 Jul 2020 15:06:29 +0530 Subject: [PATCH 238/297] migrate KFNN, KNN and related test from boost to catch2 --- src/mlpack/tests/CMakeLists.txt | 12 +- src/mlpack/tests/akfn_test.cpp | 27 +- src/mlpack/tests/aknn_test.cpp | 60 +- src/mlpack/tests/kfn_test.cpp | 498 ++++++++-------- src/mlpack/tests/knn_test.cpp | 728 +++++++++++------------ src/mlpack/tests/main_tests/kfn_test.cpp | 118 ++-- src/mlpack/tests/main_tests/knn_test.cpp | 117 ++-- 7 files changed, 782 insertions(+), 778 deletions(-) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 4a094d6a9a..e67bf363f7 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -1,8 +1,6 @@ # mlpack test executable. add_executable(mlpack_test adaboost_test.cpp - akfn_test.cpp - aknn_test.cpp ann_dist_test.cpp ann_layer_test.cpp ann_regularizer_test.cpp @@ -46,9 +44,7 @@ add_executable(mlpack_test kernel_pca_test.cpp kernel_test.cpp kernel_traits_test.cpp - kfn_test.cpp kmeans_test.cpp - knn_test.cpp krann_search_test.cpp ksinit_test.cpp lars_test.cpp @@ -139,9 +135,7 @@ add_executable(mlpack_test main_tests/hoeffding_tree_test.cpp main_tests/kde_test.cpp main_tests/kernel_pca_test.cpp - main_tests/kfn_test.cpp main_tests/kmeans_test.cpp - main_tests/knn_test.cpp main_tests/krann_test.cpp main_tests/linear_regression_test.cpp main_tests/linear_svm_test.cpp @@ -169,12 +163,18 @@ add_executable(mlpack_test add_executable(mlpack_catch_test activation_functions_test.cpp + akfn_test.cpp + aknn_test.cpp + kfn_test.cpp + knn_test.cpp main.cpp serialization_catch.cpp serialization_catch.hpp test_catch_tools.hpp image_load_test.cpp main_tests/image_converter_test.cpp + main_tests/kfn_test.cpp + main_tests/knn_test.cpp main_tests/test_helper.hpp ) diff --git a/src/mlpack/tests/akfn_test.cpp b/src/mlpack/tests/akfn_test.cpp index 48d3022939..162817656c 100644 --- a/src/mlpack/tests/akfn_test.cpp +++ b/src/mlpack/tests/akfn_test.cpp @@ -11,8 +11,8 @@ #include #include #include -#include -#include "test_tools.hpp" +#include "test_catch_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::neighbor; @@ -20,20 +20,18 @@ using namespace mlpack::tree; using namespace mlpack::metric; using namespace mlpack::bound; -BOOST_AUTO_TEST_SUITE(AKFNTest); - /** * Test the dual-tree furthest-neighbors method with different values for * epsilon. This uses both a query and reference dataset. * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(ApproxVsExact1) +TEST_CASE("AKFNApproxVsExact1", "[AKFNTest]") { arma::mat dataset; if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KFN exact(dataset); arma::Mat neighborsExact; @@ -81,12 +79,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact1) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(ApproxVsExact2) +TEST_CASE("AKFNApproxVsExact2", "[AKFNTest]") { arma::mat dataset; if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KFN exact(dataset); arma::Mat neighborsExact; @@ -108,12 +106,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact2) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleTreeVsExact) +TEST_CASE("AKFNSingleTreeVsExact", "[AKFNTest]") { arma::mat dataset; if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KFN exact(dataset); arma::Mat neighborsExact; @@ -135,7 +133,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsExact) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) +TEST_CASE("AKFNSingleCoverTreeTest", "[AKFNTest]") { arma::mat dataset; dataset.randu(75, 1000); // 75 dimensional, 1000 points. @@ -165,7 +163,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(DualCoverTreeTest) +TEST_CASE("AKFNDualCoverTreeTest", "[AKFNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -195,7 +193,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleBallTreeTest) +TEST_CASE("AKFNSingleBallTreeTest", "[AKFNTest]") { arma::mat dataset; dataset.randu(75, 1000); // 75 dimensional, 1000 points. @@ -222,7 +220,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(DualBallTreeTest) +TEST_CASE("AKFNDualBallTreeTest", "[AKFNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -242,4 +240,3 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest) REQUIRE_RELATIVE_ERR(distancesBallTree(i), distancesExact(i), 0.05); } -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/aknn_test.cpp b/src/mlpack/tests/aknn_test.cpp index c9a584883e..e77721ceac 100644 --- a/src/mlpack/tests/aknn_test.cpp +++ b/src/mlpack/tests/aknn_test.cpp @@ -14,8 +14,8 @@ #include #include #include -#include -#include "test_tools.hpp" +#include "test_catch_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::neighbor; @@ -23,20 +23,18 @@ using namespace mlpack::tree; using namespace mlpack::metric; using namespace mlpack::bound; -BOOST_AUTO_TEST_SUITE(AKNNTest); - /** * Test the dual-tree nearest-neighbors method with different values for * epsilon. This uses both a query and reference dataset. * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(ApproxVsExact1) +TEST_CASE("AKNNApproxVsExact1", "[AKNNTest]") { arma::mat dataset; if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KNN exact(dataset); arma::Mat neighborsExact; @@ -84,12 +82,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact1) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(ApproxVsExact2) +TEST_CASE("AKNNApproxVsExact2", "[AKNNTest]") { arma::mat dataset; if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KNN exact(dataset); arma::Mat neighborsExact; @@ -111,12 +109,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact2) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleTreeApproxVsExact) +TEST_CASE("AKNNSingleTreeApproxVsExact", "[AKNNTest]") { arma::mat dataset; if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KNN exact(dataset); arma::Mat neighborsExact; @@ -138,7 +136,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeApproxVsExact) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) +TEST_CASE("AKNNSingleCoverTreeTest", "[AKNNTest]") { arma::mat dataset; dataset.randu(75, 1000); // 75 dimensional, 1000 points. @@ -168,7 +166,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(DualCoverTreeTest) +TEST_CASE("AKNNDualCoverTreeTest", "[AKNNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -195,7 +193,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleBallTreeTest) +TEST_CASE("AKNNSingleBallTreeTest", "[AKNNTest]") { arma::mat dataset; dataset.randu(50, 300); // 50 dimensional, 300 points. @@ -222,7 +220,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(DualBallTreeTest) +TEST_CASE("AKNNDualBallTreeTest", "[AKNNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -249,7 +247,7 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest) * * Errors are produced if the results are not according to relative error. */ -BOOST_AUTO_TEST_CASE(SingleSpillTreeTest) +TEST_CASE("AKNNSingleSpillTreeTest", "[AKNNTest]") { arma::mat dataset; dataset.randu(50, 300); // 50 dimensional, 300 points. @@ -286,7 +284,7 @@ BOOST_AUTO_TEST_CASE(SingleSpillTreeTest) /** * Make sure sparse nearest neighbors works with kd trees. */ -BOOST_AUTO_TEST_CASE(SparseKNNKDTreeTest) +TEST_CASE("AKNNSparseKNNKDTreeTest", "[AKNNTest]") { // The dimensionality of these datasets must be high so that the probability // of a completely empty point is very low. In this case, with dimensionality @@ -321,7 +319,7 @@ BOOST_AUTO_TEST_CASE(SparseKNNKDTreeTest) * Ensure that we can build an NSModel and get correct * results. */ -BOOST_AUTO_TEST_CASE(KNNModelTest) +TEST_CASE("AKNNModelTest", "[AKNNTest]") { typedef NSModel KNNModel; @@ -385,12 +383,12 @@ BOOST_AUTO_TEST_CASE(KNNModelTest) models[i].Search(std::move(queryCopy), 3, neighborsApprox, distancesApprox); - BOOST_REQUIRE_EQUAL(neighborsApprox.n_rows, neighborsExact.n_rows); - BOOST_REQUIRE_EQUAL(neighborsApprox.n_cols, neighborsExact.n_cols); - BOOST_REQUIRE_EQUAL(neighborsApprox.n_elem, neighborsExact.n_elem); - BOOST_REQUIRE_EQUAL(distancesApprox.n_rows, distancesExact.n_rows); - BOOST_REQUIRE_EQUAL(distancesApprox.n_cols, distancesExact.n_cols); - BOOST_REQUIRE_EQUAL(distancesApprox.n_elem, distancesExact.n_elem); + REQUIRE(neighborsApprox.n_rows == neighborsExact.n_rows); + REQUIRE(neighborsApprox.n_cols == neighborsExact.n_cols); + REQUIRE(neighborsApprox.n_elem == neighborsExact.n_elem); + REQUIRE(distancesApprox.n_rows == distancesExact.n_rows); + REQUIRE(distancesApprox.n_cols == distancesExact.n_cols); + REQUIRE(distancesApprox.n_elem == distancesExact.n_elem); for (size_t k = 0; k < distancesApprox.n_elem; ++k) REQUIRE_RELATIVE_ERR(distancesApprox[k], distancesExact[k], 0.05); } @@ -401,7 +399,7 @@ BOOST_AUTO_TEST_CASE(KNNModelTest) * Ensure that we can build an NSModel and get correct * results, in the case where the reference set is the same as the query set. */ -BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) +TEST_CASE("AKNNModelMonochromaticTest", "[AKNNTest]") { typedef NSModel KNNModel; @@ -460,16 +458,14 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) models[i].Search(3, neighborsApprox, distancesApprox); - BOOST_REQUIRE_EQUAL(neighborsApprox.n_rows, neighborsExact.n_rows); - BOOST_REQUIRE_EQUAL(neighborsApprox.n_cols, neighborsExact.n_cols); - BOOST_REQUIRE_EQUAL(neighborsApprox.n_elem, neighborsExact.n_elem); - BOOST_REQUIRE_EQUAL(distancesApprox.n_rows, distancesExact.n_rows); - BOOST_REQUIRE_EQUAL(distancesApprox.n_cols, distancesExact.n_cols); - BOOST_REQUIRE_EQUAL(distancesApprox.n_elem, distancesExact.n_elem); + REQUIRE(neighborsApprox.n_rows == neighborsExact.n_rows); + REQUIRE(neighborsApprox.n_cols == neighborsExact.n_cols); + REQUIRE(neighborsApprox.n_elem == neighborsExact.n_elem); + REQUIRE(distancesApprox.n_rows == distancesExact.n_rows); + REQUIRE(distancesApprox.n_cols == distancesExact.n_cols); + REQUIRE(distancesApprox.n_elem == distancesExact.n_elem); for (size_t k = 0; k < distancesApprox.n_elem; ++k) REQUIRE_RELATIVE_ERR(distancesApprox[k], distancesExact[k], 0.05); } } } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/kfn_test.cpp b/src/mlpack/tests/kfn_test.cpp index a9a9654ff1..f3fefadb7a 100644 --- a/src/mlpack/tests/kfn_test.cpp +++ b/src/mlpack/tests/kfn_test.cpp @@ -11,8 +11,8 @@ #include #include #include -#include -#include "test_tools.hpp" +#include "test_catch_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::neighbor; @@ -20,8 +20,6 @@ using namespace mlpack::tree; using namespace mlpack::metric; using namespace mlpack::bound; -BOOST_AUTO_TEST_SUITE(KFNTest); - /** * Simple furthest-neighbors test with small, synthetic dataset. This is an * exhaustive test, which checks that each method for performing the calculation @@ -30,7 +28,7 @@ BOOST_AUTO_TEST_SUITE(KFNTest); * is in one dimension for simplicity -- the correct functionality of distance * functions is not tested here. */ -BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest) +TEST_CASE("KFNExhaustiveSyntheticTest", "[KFNTest]") { // Set up our data. arma::mat data(1, 11); @@ -82,246 +80,246 @@ BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest) // readability. // Neighbors of point 0. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[0]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[0]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[0]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[0]), 0.27, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[0]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[0]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[0]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[0]), 0.40, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[0]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[0]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[0]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[0]), 0.95, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[0]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[0]), 1.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[0]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[0]), 1.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[0]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[0]), 2.05, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[0]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[0]), 5.00, 1e-5); + REQUIRE(neighbors(9, newFromOld[0]) == newFromOld[2]); + REQUIRE(distances(9, newFromOld[0]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[0]) == newFromOld[5]); + REQUIRE(distances(8, newFromOld[0]) == Approx(0.27).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[0]) == newFromOld[1]); + REQUIRE(distances(7, newFromOld[0]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[0]) == newFromOld[8]); + REQUIRE(distances(6, newFromOld[0]) == Approx(0.40).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[0]) == newFromOld[9]); + REQUIRE(distances(5, newFromOld[0]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[0]) == newFromOld[10]); + REQUIRE(distances(4, newFromOld[0]) == Approx(0.95).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[0]) == newFromOld[3]); + REQUIRE(distances(3, newFromOld[0]) == Approx(1.20).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[0]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[0]) == Approx(1.35).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[0]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[0]) == Approx(2.05).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[0]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[0]) == Approx(5.00).epsilon(1e-7)); // Neighbors of point 1. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[1]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[1]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[1]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[1]), 0.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[1]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[1]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[1]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[1]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[1]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[1]), 0.57, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[1]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[1]), 0.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[1]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[1]), 0.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[1]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[1]), 1.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[1]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[1]), 2.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[1]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[1]), 4.70, 1e-5); + REQUIRE(neighbors(9, newFromOld[1]) == newFromOld[8]); + REQUIRE(distances(9, newFromOld[1]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[1]) == newFromOld[2]); + REQUIRE(distances(8, newFromOld[1]) == Approx(0.20).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[1]) == newFromOld[0]); + REQUIRE(distances(7, newFromOld[1]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[1]) == newFromOld[9]); + REQUIRE(distances(6, newFromOld[1]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[1]) == newFromOld[5]); + REQUIRE(distances(5, newFromOld[1]) == Approx(0.57).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[1]) == newFromOld[10]); + REQUIRE(distances(4, newFromOld[1]) == Approx(0.65).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[1]) == newFromOld[3]); + REQUIRE(distances(3, newFromOld[1]) == Approx(0.90).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[1]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[1]) == Approx(1.65).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[1]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[1]) == Approx(2.35).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[1]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[1]) == Approx(4.70).epsilon(1e-7)); // Neighbors of point 2. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[2]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[2]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[2]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[2]), 0.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[2]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[2]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[2]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[2]), 0.37, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[2]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[2]), 0.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[2]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[2]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[2]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[2]), 1.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[2]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[2]), 1.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[2]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[2]), 2.15, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[2]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[2]), 4.90, 1e-5); + REQUIRE(neighbors(9, newFromOld[2]) == newFromOld[0]); + REQUIRE(distances(9, newFromOld[2]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[2]) == newFromOld[1]); + REQUIRE(distances(8, newFromOld[2]) == Approx(0.20).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[2]) == newFromOld[8]); + REQUIRE(distances(7, newFromOld[2]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[2]) == newFromOld[5]); + REQUIRE(distances(6, newFromOld[2]) == Approx(0.37).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[2]) == newFromOld[9]); + REQUIRE(distances(5, newFromOld[2]) == Approx(0.75).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[2]) == newFromOld[10]); + REQUIRE(distances(4, newFromOld[2]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[2]) == newFromOld[3]); + REQUIRE(distances(3, newFromOld[2]) == Approx(1.10).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[2]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[2]) == Approx(1.45).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[2]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[2]) == Approx(2.15).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[2]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[2]) == Approx(4.90).epsilon(1e-7)); // Neighbors of point 3. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[3]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[3]), 0.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[3]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[3]), 0.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[3]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[3]), 0.80, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[3]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[3]), 0.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[3]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[3]), 1.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[3]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[3]), 1.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[3]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[3]), 1.47, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[3]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[3]), 2.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[3]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[3]), 3.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[3]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[3]), 3.80, 1e-5); + REQUIRE(neighbors(9, newFromOld[3]) == newFromOld[10]); + REQUIRE(distances(9, newFromOld[3]) == Approx(0.25).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[3]) == newFromOld[9]); + REQUIRE(distances(8, newFromOld[3]) == Approx(0.35).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[3]) == newFromOld[8]); + REQUIRE(distances(7, newFromOld[3]) == Approx(0.80).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[3]) == newFromOld[1]); + REQUIRE(distances(6, newFromOld[3]) == Approx(0.90).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[3]) == newFromOld[2]); + REQUIRE(distances(5, newFromOld[3]) == Approx(1.10).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[3]) == newFromOld[0]); + REQUIRE(distances(4, newFromOld[3]) == Approx(1.20).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[3]) == newFromOld[5]); + REQUIRE(distances(3, newFromOld[3]) == Approx(1.47).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[3]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[3]) == Approx(2.55).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[3]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[3]) == Approx(3.25).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[3]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[3]) == Approx(3.80).epsilon(1e-7)); // Neighbors of point 4. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[4]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[4]), 3.80, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[4]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[4]), 4.05, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[4]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[4]), 4.15, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[4]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[4]), 4.60, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[4]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[4]), 4.70, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[4]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[4]), 4.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[4]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[4]), 5.00, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[4]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[4]), 5.27, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[4]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[4]), 6.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[4]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[4]), 7.05, 1e-5); + REQUIRE(neighbors(9, newFromOld[4]) == newFromOld[3]); + REQUIRE(distances(9, newFromOld[4]) == Approx(3.80).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[4]) == newFromOld[10]); + REQUIRE(distances(8, newFromOld[4]) == Approx(4.05).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[4]) == newFromOld[9]); + REQUIRE(distances(7, newFromOld[4]) == Approx(4.15).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[4]) == newFromOld[8]); + REQUIRE(distances(6, newFromOld[4]) == Approx(4.60).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[4]) == newFromOld[1]); + REQUIRE(distances(5, newFromOld[4]) == Approx(4.70).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[4]) == newFromOld[2]); + REQUIRE(distances(4, newFromOld[4]) == Approx(4.90).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[4]) == newFromOld[0]); + REQUIRE(distances(3, newFromOld[4]) == Approx(5.00).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[4]) == newFromOld[5]); + REQUIRE(distances(2, newFromOld[4]) == Approx(5.27).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[4]) == newFromOld[7]); + REQUIRE(distances(1, newFromOld[4]) == Approx(6.35).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[4]) == newFromOld[6]); + REQUIRE(distances(0, newFromOld[4]) == Approx(7.05).epsilon(1e-7)); // Neighbors of point 5. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[5]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[5]), 0.27, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[5]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[5]), 0.37, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[5]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[5]), 0.57, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[5]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[5]), 0.67, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[5]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[5]), 1.08, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[5]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[5]), 1.12, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[5]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[5]), 1.22, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[5]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[5]), 1.47, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[5]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[5]), 1.78, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[5]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[5]), 5.27, 1e-5); + REQUIRE(neighbors(9, newFromOld[5]) == newFromOld[0]); + REQUIRE(distances(9, newFromOld[5]) == Approx(0.27).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[5]) == newFromOld[2]); + REQUIRE(distances(8, newFromOld[5]) == Approx(0.37).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[5]) == newFromOld[1]); + REQUIRE(distances(7, newFromOld[5]) == Approx(0.57).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[5]) == newFromOld[8]); + REQUIRE(distances(6, newFromOld[5]) == Approx(0.67).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[5]) == newFromOld[7]); + REQUIRE(distances(5, newFromOld[5]) == Approx(1.08).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[5]) == newFromOld[9]); + REQUIRE(distances(4, newFromOld[5]) == Approx(1.12).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[5]) == newFromOld[10]); + REQUIRE(distances(3, newFromOld[5]) == Approx(1.22).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[5]) == newFromOld[3]); + REQUIRE(distances(2, newFromOld[5]) == Approx(1.47).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[5]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[5]) == Approx(1.78).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[5]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[5]) == Approx(5.27).epsilon(1e-7)); // Neighbors of point 6. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[6]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[6]), 0.70, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[6]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[6]), 1.78, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[6]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[6]), 2.05, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[6]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[6]), 2.15, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[6]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[6]), 2.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[6]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[6]), 2.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[6]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[6]), 2.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[6]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[6]), 3.00, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[6]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[6]), 3.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[6]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[6]), 7.05, 1e-5); + REQUIRE(neighbors(9, newFromOld[6]) == newFromOld[7]); + REQUIRE(distances(9, newFromOld[6]) == Approx(0.70).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[6]) == newFromOld[5]); + REQUIRE(distances(8, newFromOld[6]) == Approx(1.78).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[6]) == newFromOld[0]); + REQUIRE(distances(7, newFromOld[6]) == Approx(2.05).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[6]) == newFromOld[2]); + REQUIRE(distances(6, newFromOld[6]) == Approx(2.15).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[6]) == newFromOld[1]); + REQUIRE(distances(5, newFromOld[6]) == Approx(2.35).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[6]) == newFromOld[8]); + REQUIRE(distances(4, newFromOld[6]) == Approx(2.45).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[6]) == newFromOld[9]); + REQUIRE(distances(3, newFromOld[6]) == Approx(2.90).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[6]) == newFromOld[10]); + REQUIRE(distances(2, newFromOld[6]) == Approx(3.00).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[6]) == newFromOld[3]); + REQUIRE(distances(1, newFromOld[6]) == Approx(3.25).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[6]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[6]) == Approx(7.05).epsilon(1e-7)); // Neighbors of point 7. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[7]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[7]), 0.70, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[7]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[7]), 1.08, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[7]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[7]), 1.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[7]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[7]), 1.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[7]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[7]), 1.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[7]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[7]), 1.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[7]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[7]), 2.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[7]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[7]), 2.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[7]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[7]), 2.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[7]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[7]), 6.35, 1e-5); + REQUIRE(neighbors(9, newFromOld[7]) == newFromOld[6]); + REQUIRE(distances(9, newFromOld[7]) == Approx(0.70).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[7]) == newFromOld[5]); + REQUIRE(distances(8, newFromOld[7]) == Approx(1.08).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[7]) == newFromOld[0]); + REQUIRE(distances(7, newFromOld[7]) == Approx(1.35).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[7]) == newFromOld[2]); + REQUIRE(distances(6, newFromOld[7]) == Approx(1.45).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[7]) == newFromOld[1]); + REQUIRE(distances(5, newFromOld[7]) == Approx(1.65).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[7]) == newFromOld[8]); + REQUIRE(distances(4, newFromOld[7]) == Approx(1.75).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[7]) == newFromOld[9]); + REQUIRE(distances(3, newFromOld[7]) == Approx(2.20).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[7]) == newFromOld[10]); + REQUIRE(distances(2, newFromOld[7]) == Approx(2.30).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[7]) == newFromOld[3]); + REQUIRE(distances(1, newFromOld[7]) == Approx(2.55).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[7]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[7]) == Approx(6.35).epsilon(1e-7)); // Neighbors of point 8. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[8]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[8]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[8]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[8]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[8]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[8]), 0.40, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[8]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[8]), 0.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[8]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[8]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[8]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[8]), 0.67, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[8]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[8]), 0.80, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[8]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[8]), 1.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[8]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[8]), 2.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[8]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[8]), 4.60, 1e-5); + REQUIRE(neighbors(9, newFromOld[8]) == newFromOld[1]); + REQUIRE(distances(9, newFromOld[8]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[8]) == newFromOld[2]); + REQUIRE(distances(8, newFromOld[8]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[8]) == newFromOld[0]); + REQUIRE(distances(7, newFromOld[8]) == Approx(0.40).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[8]) == newFromOld[9]); + REQUIRE(distances(6, newFromOld[8]) == Approx(0.45).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[8]) == newFromOld[10]); + REQUIRE(distances(5, newFromOld[8]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[8]) == newFromOld[5]); + REQUIRE(distances(4, newFromOld[8]) == Approx(0.67).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[8]) == newFromOld[3]); + REQUIRE(distances(3, newFromOld[8]) == Approx(0.80).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[8]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[8]) == Approx(1.75).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[8]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[8]) == Approx(2.45).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[8]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[8]) == Approx(4.60).epsilon(1e-7)); // Neighbors of point 9. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[9]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[9]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[9]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[9]), 0.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[9]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[9]), 0.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[9]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[9]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[9]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[9]), 0.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[9]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[9]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[9]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[9]), 1.12, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[9]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[9]), 2.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[9]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[9]), 2.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[9]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[9]), 4.15, 1e-5); + REQUIRE(neighbors(9, newFromOld[9]) == newFromOld[10]); + REQUIRE(distances(9, newFromOld[9]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[9]) == newFromOld[3]); + REQUIRE(distances(8, newFromOld[9]) == Approx(0.35).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[9]) == newFromOld[8]); + REQUIRE(distances(7, newFromOld[9]) == Approx(0.45).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[9]) == newFromOld[1]); + REQUIRE(distances(6, newFromOld[9]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[9]) == newFromOld[2]); + REQUIRE(distances(5, newFromOld[9]) == Approx(0.75).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[9]) == newFromOld[0]); + REQUIRE(distances(4, newFromOld[9]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[9]) == newFromOld[5]); + REQUIRE(distances(3, newFromOld[9]) == Approx(1.12).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[9]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[9]) == Approx(2.20).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[9]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[9]) == Approx(2.90).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[9]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[9]) == Approx(4.15).epsilon(1e-7)); // Neighbors of point 10. - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[10]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[10]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[10]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[10]), 0.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[10]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[10]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[10]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[10]), 0.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[10]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[10]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[10]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[10]), 0.95, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[10]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[10]), 1.22, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[10]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[10]), 2.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[10]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[10]), 3.00, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[10]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[10]), 4.05, 1e-5); + REQUIRE(neighbors(9, newFromOld[10]) == newFromOld[9]); + REQUIRE(distances(9, newFromOld[10]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[10]) == newFromOld[3]); + REQUIRE(distances(8, newFromOld[10]) == Approx(0.25).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[10]) == newFromOld[8]); + REQUIRE(distances(7, newFromOld[10]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[10]) == newFromOld[1]); + REQUIRE(distances(6, newFromOld[10]) == Approx(0.65).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[10]) == newFromOld[2]); + REQUIRE(distances(5, newFromOld[10]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[10]) == newFromOld[0]); + REQUIRE(distances(4, newFromOld[10]) == Approx(0.95).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[10]) == newFromOld[5]); + REQUIRE(distances(3, newFromOld[10]) == Approx(1.22).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[10]) == newFromOld[7]); + REQUIRE(distances(2, newFromOld[10]) == Approx(2.30).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[10]) == newFromOld[6]); + REQUIRE(distances(1, newFromOld[10]) == Approx(3.00).epsilon(1e-7)); + REQUIRE(neighbors(0, newFromOld[10]) == newFromOld[4]); + REQUIRE(distances(0, newFromOld[10]) == Approx(4.05).epsilon(1e-7)); } } @@ -331,13 +329,13 @@ BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(DualTreeVsNaive1) +TEST_CASE("KFNDualTreeVsNaive1", "[KFNTest]") { arma::mat dataset; // Hard-coded filename: bad? if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KFN kfn(dataset); @@ -353,8 +351,8 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive1) for (size_t i = 0; i < neighborsTree.n_elem; ++i) { - BOOST_REQUIRE(neighborsTree[i] == neighborsNaive[i]); - BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5); + REQUIRE(neighborsTree[i] == neighborsNaive[i]); + REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7)); } } @@ -364,14 +362,14 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive1) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(DualTreeVsNaive2) +TEST_CASE("KFNDualTreeVsNaive2", "[KFNTest]") { arma::mat dataset; // Hard-coded filename: bad? // Code duplication: also bad! if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KFN kfn(dataset); @@ -387,8 +385,8 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive2) for (size_t i = 0; i < neighborsTree.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsTree[i], neighborsNaive[i]); - BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5); + REQUIRE(neighborsTree[i] == neighborsNaive[i]); + REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7)); } } @@ -398,14 +396,14 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive2) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(SingleTreeVsNaive) +TEST_CASE("KFNSingleTreeVsNaive", "[KFNTest]") { arma::mat dataset; // Hard-coded filename: bad! // Code duplication: also bad! if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KFN kfn(dataset, SINGLE_TREE_MODE); @@ -421,8 +419,8 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsNaive) for (size_t i = 0; i < neighborsTree.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsTree[i], neighborsNaive[i]); - BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5); + REQUIRE(neighborsTree[i] == neighborsNaive[i]); + REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7)); } } @@ -432,7 +430,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsNaive) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) +TEST_CASE("KFNSingleCoverTreeTest", "[KFNTest]") { arma::mat data; data.randu(75, 1000); // 75 dimensional, 1000 points. @@ -456,8 +454,8 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) for (size_t i = 0; i < coverTreeNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(coverTreeNeighbors[i], naiveNeighbors[i]); - BOOST_REQUIRE_CLOSE(coverTreeDistances[i], naiveDistances[i], 1e-5); + REQUIRE(coverTreeNeighbors[i] == naiveNeighbors[i]); + REQUIRE(coverTreeDistances[i] == Approx(naiveDistances[i]).epsilon(1e-7)); } } @@ -465,7 +463,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) * Test the cover tree dual-tree furthest neighbors method against the naive * method. */ -BOOST_AUTO_TEST_CASE(DualCoverTreeTest) +TEST_CASE("KFNDualCoverTreeTest", "[KFNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -490,8 +488,8 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest) for (size_t i = 0; i < coverNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(coverNeighbors(i), kdNeighbors(i)); - BOOST_REQUIRE_CLOSE(coverDistances(i), kdDistances(i), 1e-5); + REQUIRE(coverNeighbors(i) == kdNeighbors(i)); + REQUIRE(coverDistances(i) == Approx(kdDistances(i)).epsilon(1e-7)); } } @@ -501,7 +499,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(SingleBallTreeTest) +TEST_CASE("KFNSingleBallTreeTest", "[KFNTest]") { arma::mat data; data.randu(75, 1000); // 75 dimensional, 1000 points. @@ -528,8 +526,8 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest) for (size_t i = 0; i < ballTreeNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(ballTreeNeighbors[i], naiveNeighbors[i]); - BOOST_REQUIRE_CLOSE(ballTreeDistances[i], naiveDistances[i], 1e-5); + REQUIRE(ballTreeNeighbors[i] == naiveNeighbors[i]); + REQUIRE(ballTreeDistances[i] == Approx(naiveDistances[i]).epsilon(1e-7)); } } @@ -537,7 +535,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest) * Test the ball tree dual-tree furthest neighbors method against the naive * method. */ -BOOST_AUTO_TEST_CASE(DualBallTreeTest) +TEST_CASE("KFNDualBallTreeTest", "[KFNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -557,9 +555,7 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest) for (size_t i = 0; i < ballNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(ballNeighbors(i), kdNeighbors(i)); - BOOST_REQUIRE_CLOSE(ballDistances(i), kdDistances(i), 1e-5); + REQUIRE(ballNeighbors(i) == kdNeighbors(i)); + REQUIRE(ballDistances(i) == Approx(kdDistances(i)).epsilon(1e-7)); } } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/knn_test.cpp b/src/mlpack/tests/knn_test.cpp index ac6f429627..767abdb484 100644 --- a/src/mlpack/tests/knn_test.cpp +++ b/src/mlpack/tests/knn_test.cpp @@ -14,8 +14,8 @@ #include #include #include -#include -#include "test_tools.hpp" +#include "test_catch_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::neighbor; @@ -23,12 +23,10 @@ using namespace mlpack::tree; using namespace mlpack::metric; using namespace mlpack::bound; -BOOST_AUTO_TEST_SUITE(KNNTest); - /** * Test that Unmap() works in the dual-tree case (see unmap.hpp). */ -BOOST_AUTO_TEST_CASE(DualTreeUnmapTest) +TEST_CASE("KNNDualTreeUnmapTest", "[KNNTest]") { std::vector refMap; refMap.push_back(3); @@ -88,8 +86,8 @@ BOOST_AUTO_TEST_CASE(DualTreeUnmapTest) for (size_t i = 0; i < correctNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsOut[i], correctNeighbors[i]); - BOOST_REQUIRE_CLOSE(distancesOut[i], correctDistances[i], 1e-5); + REQUIRE(neighborsOut[i] ==correctNeighbors[i]); + REQUIRE(distancesOut[i] == Approx(correctDistances[i]).epsilon(1e-7)); } // Now try taking the square root. @@ -98,15 +96,15 @@ BOOST_AUTO_TEST_CASE(DualTreeUnmapTest) for (size_t i = 0; i < correctNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsOut[i], correctNeighbors[i]); - BOOST_REQUIRE_CLOSE(distancesOut[i], sqrt(correctDistances[i]), 1e-5); + REQUIRE(neighborsOut[i] ==correctNeighbors[i]); + REQUIRE(distancesOut[i] == Approx(sqrt(correctDistances[i])).epsilon(1e-7)); } } /** * Check that Unmap() works in the single-tree case. */ -BOOST_AUTO_TEST_CASE(SingleTreeUnmapTest) +TEST_CASE("KNNSingleTreeUnmapTest", "[KNNTest]") { std::vector refMap; refMap.push_back(3); @@ -152,8 +150,8 @@ BOOST_AUTO_TEST_CASE(SingleTreeUnmapTest) for (size_t i = 0; i < correctNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsOut[i], correctNeighbors[i]); - BOOST_REQUIRE_CLOSE(distancesOut[i], correctDistances[i], 1e-5); + REQUIRE(neighborsOut[i] ==correctNeighbors[i]); + REQUIRE(distancesOut[i] == Approx(correctDistances[i]).epsilon(1e-7)); } // Now try taking the square root. @@ -161,8 +159,8 @@ BOOST_AUTO_TEST_CASE(SingleTreeUnmapTest) for (size_t i = 0; i < correctNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsOut[i], correctNeighbors[i]); - BOOST_REQUIRE_CLOSE(distancesOut[i], sqrt(correctDistances[i]), 1e-5); + REQUIRE(neighborsOut[i] ==correctNeighbors[i]); + REQUIRE(distancesOut[i] == Approx(sqrt(correctDistances[i])).epsilon(1e-7)); } } @@ -170,7 +168,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeUnmapTest) * Test that an empty KNN object will throw exceptions when Search() is * called. */ -BOOST_AUTO_TEST_CASE(EmptySearchTest) +TEST_CASE("KNNEmptySearchTest", "[KNNTest]") { KNN empty; @@ -179,18 +177,18 @@ BOOST_AUTO_TEST_CASE(EmptySearchTest) arma::Mat neighbors; arma::mat distances; - BOOST_REQUIRE_THROW(empty.Search(dataset, 5, neighbors, distances), + REQUIRE_THROWS_AS(empty.Search(dataset, 5, neighbors, distances), std::invalid_argument); - BOOST_REQUIRE_THROW(empty.Search(5, neighbors, distances), + REQUIRE_THROWS_AS(empty.Search(5, neighbors, distances), std::invalid_argument); - BOOST_REQUIRE_THROW(empty.Search(queryTree, 5, neighbors, distances), + REQUIRE_THROWS_AS(empty.Search(queryTree, 5, neighbors, distances), std::invalid_argument); } /** * Test that when training is performed, the results are the same. */ -BOOST_AUTO_TEST_CASE(TrainTest) +TEST_CASE("KNNTrainTest", "[KNNTest]") { KNN empty; @@ -205,26 +203,26 @@ BOOST_AUTO_TEST_CASE(TrainTest) empty.Search(5, neighbors, distances); baseline.Search(5, baselineNeighbors, baselineDistances); - BOOST_REQUIRE_EQUAL(neighbors.n_rows, baselineNeighbors.n_rows); - BOOST_REQUIRE_EQUAL(neighbors.n_cols, baselineNeighbors.n_cols); - BOOST_REQUIRE_EQUAL(distances.n_rows, baselineDistances.n_rows); - BOOST_REQUIRE_EQUAL(distances.n_cols, baselineDistances.n_cols); + REQUIRE(neighbors.n_rows ==baselineNeighbors.n_rows); + REQUIRE(neighbors.n_cols ==baselineNeighbors.n_cols); + REQUIRE(distances.n_rows ==baselineDistances.n_rows); + REQUIRE(distances.n_cols ==baselineDistances.n_cols); for (size_t i = 0; i < distances.n_elem; ++i) { if (std::abs(baselineDistances[i]) < 1e-5) - BOOST_REQUIRE_SMALL(distances[i], 1e-5); + REQUIRE(distances[i] == Approx(0.0).margin(1e-7)); else - BOOST_REQUIRE_CLOSE(distances[i], baselineDistances[i], 1e-5); + REQUIRE(distances[i] == Approx(baselineDistances[i]).epsilon(1e-7)); - BOOST_REQUIRE_EQUAL(neighbors[i], baselineNeighbors[i]); + REQUIRE(neighbors[i] ==baselineNeighbors[i]); } } /** * Test that when training is performed with a tree, the results are the same. */ -BOOST_AUTO_TEST_CASE(TrainTreeTest) +TEST_CASE("KNNTrainTreeTest", "[KNNTest]") { KNN empty; @@ -241,11 +239,11 @@ BOOST_AUTO_TEST_CASE(TrainTreeTest) empty.Search(5, neighbors, distances); baseline.Search(5, baselineNeighbors, baselineDistances); - BOOST_REQUIRE_EQUAL(neighbors.n_rows, baselineNeighbors.n_rows); - BOOST_REQUIRE_EQUAL(neighbors.n_cols, baselineNeighbors.n_cols); - BOOST_REQUIRE_EQUAL(distances.n_rows, baselineDistances.n_rows); - BOOST_REQUIRE_EQUAL(distances.n_cols, baselineDistances.n_cols); - BOOST_REQUIRE_EQUAL(oldFromNewReferences.size(), distances.n_cols); + REQUIRE(neighbors.n_rows ==baselineNeighbors.n_rows); + REQUIRE(neighbors.n_cols ==baselineNeighbors.n_cols); + REQUIRE(distances.n_rows ==baselineDistances.n_rows); + REQUIRE(distances.n_cols ==baselineDistances.n_cols); + REQUIRE(oldFromNewReferences.size() ==distances.n_cols); // We have to unmap the results. arma::mat tmpDistances(distances.n_rows, distances.n_cols); @@ -263,31 +261,31 @@ BOOST_AUTO_TEST_CASE(TrainTreeTest) for (size_t i = 0; i < distances.n_elem; ++i) { if (std::abs(baselineDistances[i]) < 1e-5) - BOOST_REQUIRE_SMALL(tmpDistances[i], 1e-5); + REQUIRE(tmpDistances[i] == Approx(0.0).margin(1e-7)); else - BOOST_REQUIRE_CLOSE(tmpDistances[i], baselineDistances[i], 1e-5); + REQUIRE(tmpDistances[i] == Approx(baselineDistances[i]).epsilon(1e-7)); - BOOST_REQUIRE_EQUAL(tmpNeighbors[i], baselineNeighbors[i]); + REQUIRE(tmpNeighbors[i] ==baselineNeighbors[i]); } } /** * Test that training with a tree throws an exception when in naive mode. */ -BOOST_AUTO_TEST_CASE(NaiveTrainTreeTest) +TEST_CASE("KNNNaiveTrainTreeTest", "[KNNTest]") { KNN empty(NAIVE_MODE); arma::mat dataset = arma::randu(5, 100); KNN::Tree tree(dataset); - BOOST_REQUIRE_THROW(empty.Train(std::move(tree)), std::invalid_argument); + REQUIRE_THROWS_AS(empty.Train(std::move(tree)), std::invalid_argument); } /** * Test that the rvalue reference move constructor works. */ -BOOST_AUTO_TEST_CASE(DatasetMoveConstructorTest) +TEST_CASE("KNNDatasetMoveConstructorTest", "[KNNTest]") { arma::mat dataset = arma::randu(3, 200); arma::mat copy(dataset); @@ -295,9 +293,9 @@ BOOST_AUTO_TEST_CASE(DatasetMoveConstructorTest) KNN moveknn(std::move(copy)); KNN knn(dataset); - BOOST_REQUIRE_EQUAL(copy.n_elem, 0); - BOOST_REQUIRE_EQUAL(moveknn.ReferenceSet().n_rows, 3); - BOOST_REQUIRE_EQUAL(moveknn.ReferenceSet().n_cols, 200); + REQUIRE(copy.n_elem ==0); + REQUIRE(moveknn.ReferenceSet().n_rows ==3); + REQUIRE(moveknn.ReferenceSet().n_cols ==200); arma::mat moveDistances, distances; arma::Mat moveNeighbors, neighbors; @@ -305,24 +303,24 @@ BOOST_AUTO_TEST_CASE(DatasetMoveConstructorTest) moveknn.Search(1, moveNeighbors, moveDistances); knn.Search(1, neighbors, distances); - BOOST_REQUIRE_EQUAL(moveNeighbors.n_rows, neighbors.n_rows); - BOOST_REQUIRE_EQUAL(moveNeighbors.n_cols, neighbors.n_cols); - BOOST_REQUIRE_EQUAL(moveDistances.n_rows, distances.n_rows); - BOOST_REQUIRE_EQUAL(moveDistances.n_cols, distances.n_cols); + REQUIRE(moveNeighbors.n_rows ==neighbors.n_rows); + REQUIRE(moveNeighbors.n_cols ==neighbors.n_cols); + REQUIRE(moveDistances.n_rows ==distances.n_rows); + REQUIRE(moveDistances.n_cols ==distances.n_cols); for (size_t i = 0; i < moveDistances.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(moveNeighbors[i], neighbors[i]); + REQUIRE(moveNeighbors[i] ==neighbors[i]); if (std::abs(distances[i]) < 1e-5) - BOOST_REQUIRE_SMALL(moveDistances[i], 1e-5); + REQUIRE(moveDistances[i] == Approx(0.0).margin(1e-7)); else - BOOST_REQUIRE_CLOSE(moveDistances[i], distances[i], 1e-5); + REQUIRE(moveDistances[i] == Approx(distances[i]).epsilon(1e-7)); } } /** * Test that the dataset can be retrained with the move Train() function. */ -BOOST_AUTO_TEST_CASE(MoveTrainTest) +TEST_CASE("KNNMoveTrainTest", "[KNNTest]") { arma::mat dataset = arma::randu(3, 200); @@ -334,18 +332,18 @@ BOOST_AUTO_TEST_CASE(MoveTrainTest) arma::Mat neighbors; knn.Search(1, neighbors, distances); - BOOST_REQUIRE_EQUAL(dataset.n_elem, 0); - BOOST_REQUIRE_EQUAL(neighbors.n_cols, 200); - BOOST_REQUIRE_EQUAL(distances.n_cols, 200); + REQUIRE(dataset.n_elem ==0); + REQUIRE(neighbors.n_cols ==200); + REQUIRE(distances.n_cols ==200); dataset = arma::randu(3, 300); knn.SearchMode() = NAIVE_MODE; knn.Train(std::move(dataset)); knn.Search(1, neighbors, distances); - BOOST_REQUIRE_EQUAL(dataset.n_elem, 0); - BOOST_REQUIRE_EQUAL(neighbors.n_cols, 300); - BOOST_REQUIRE_EQUAL(distances.n_cols, 300); + REQUIRE(dataset.n_elem ==0); + REQUIRE(neighbors.n_cols ==300); + REQUIRE(distances.n_cols ==300); } /** @@ -356,7 +354,7 @@ BOOST_AUTO_TEST_CASE(MoveTrainTest) * in one dimension for simplicity -- the correct functionality of distance * functions is not tested here. */ -BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest) +TEST_CASE("KNNExhaustiveSyntheticTest", "[KNNTest]") { // Set up our data. arma::mat data(1, 11); @@ -409,246 +407,246 @@ BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest) // readability. // Neighbors of point 0. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[0]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[0]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[0]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[0]), 0.27, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[0]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[0]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[0]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[0]), 0.40, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[0]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[0]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[0]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[0]), 0.95, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[0]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[0]), 1.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[0]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[0]), 1.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[0]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[0]), 2.05, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[0]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[0]), 5.00, 1e-5); + REQUIRE(neighbors(0, newFromOld[0]) ==newFromOld[2]); + REQUIRE(distances(0, newFromOld[0]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[0]) ==newFromOld[5]); + REQUIRE(distances(1, newFromOld[0]) == Approx(0.27).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[0]) ==newFromOld[1]); + REQUIRE(distances(2, newFromOld[0]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[0]) ==newFromOld[8]); + REQUIRE(distances(3, newFromOld[0]) == Approx(0.40).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[0]) ==newFromOld[9]); + REQUIRE(distances(4, newFromOld[0]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[0]) ==newFromOld[10]); + REQUIRE(distances(5, newFromOld[0]) == Approx(0.95).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[0]) ==newFromOld[3]); + REQUIRE(distances(6, newFromOld[0]) == Approx(1.20).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[0]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[0]) == Approx(1.35).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[0]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[0]) == Approx(2.05).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[0]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[0]) == Approx(5.00).epsilon(1e-7)); // Neighbors of point 1. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[1]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[1]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[1]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[1]), 0.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[1]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[1]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[1]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[1]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[1]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[1]), 0.57, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[1]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[1]), 0.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[1]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[1]), 0.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[1]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[1]), 1.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[1]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[1]), 2.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[1]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[1]), 4.70, 1e-5); + REQUIRE(neighbors(0, newFromOld[1]) ==newFromOld[8]); + REQUIRE(distances(0, newFromOld[1]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[1]) ==newFromOld[2]); + REQUIRE(distances(1, newFromOld[1]) == Approx(0.20).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[1]) ==newFromOld[0]); + REQUIRE(distances(2, newFromOld[1]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[1]) ==newFromOld[9]); + REQUIRE(distances(3, newFromOld[1]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[1]) ==newFromOld[5]); + REQUIRE(distances(4, newFromOld[1]) == Approx(0.57).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[1]) ==newFromOld[10]); + REQUIRE(distances(5, newFromOld[1]) == Approx(0.65).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[1]) ==newFromOld[3]); + REQUIRE(distances(6, newFromOld[1]) == Approx(0.90).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[1]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[1]) == Approx(1.65).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[1]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[1]) == Approx(2.35).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[1]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[1]) == Approx(4.70).epsilon(1e-7)); // Neighbors of point 2. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[2]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[2]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[2]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[2]), 0.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[2]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[2]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[2]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[2]), 0.37, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[2]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[2]), 0.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[2]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[2]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[2]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[2]), 1.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[2]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[2]), 1.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[2]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[2]), 2.15, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[2]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[2]), 4.90, 1e-5); + REQUIRE(neighbors(0, newFromOld[2]) ==newFromOld[0]); + REQUIRE(distances(0, newFromOld[2]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[2]) ==newFromOld[1]); + REQUIRE(distances(1, newFromOld[2]) == Approx(0.20).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[2]) ==newFromOld[8]); + REQUIRE(distances(2, newFromOld[2]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[2]) ==newFromOld[5]); + REQUIRE(distances(3, newFromOld[2]) == Approx(0.37).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[2]) ==newFromOld[9]); + REQUIRE(distances(4, newFromOld[2]) == Approx(0.75).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[2]) ==newFromOld[10]); + REQUIRE(distances(5, newFromOld[2]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[2]) ==newFromOld[3]); + REQUIRE(distances(6, newFromOld[2]) == Approx(1.10).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[2]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[2]) == Approx(1.45).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[2]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[2]) == Approx(2.15).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[2]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[2]) == Approx(4.90).epsilon(1e-7)); // Neighbors of point 3. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[3]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[3]), 0.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[3]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[3]), 0.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[3]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[3]), 0.80, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[3]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[3]), 0.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[3]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[3]), 1.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[3]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[3]), 1.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[3]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[3]), 1.47, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[3]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[3]), 2.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[3]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[3]), 3.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[3]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[3]), 3.80, 1e-5); + REQUIRE(neighbors(0, newFromOld[3]) ==newFromOld[10]); + REQUIRE(distances(0, newFromOld[3]) == Approx(0.25).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[3]) ==newFromOld[9]); + REQUIRE(distances(1, newFromOld[3]) == Approx(0.35).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[3]) ==newFromOld[8]); + REQUIRE(distances(2, newFromOld[3]) == Approx(0.80).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[3]) ==newFromOld[1]); + REQUIRE(distances(3, newFromOld[3]) == Approx(0.90).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[3]) ==newFromOld[2]); + REQUIRE(distances(4, newFromOld[3]) == Approx(1.10).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[3]) ==newFromOld[0]); + REQUIRE(distances(5, newFromOld[3]) == Approx(1.20).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[3]) ==newFromOld[5]); + REQUIRE(distances(6, newFromOld[3]) == Approx(1.47).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[3]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[3]) == Approx(2.55).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[3]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[3]) == Approx(3.25).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[3]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[3]) == Approx(3.80).epsilon(1e-7)); // Neighbors of point 4. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[4]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[4]), 3.80, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[4]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[4]), 4.05, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[4]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[4]), 4.15, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[4]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[4]), 4.60, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[4]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[4]), 4.70, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[4]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[4]), 4.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[4]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[4]), 5.00, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[4]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[4]), 5.27, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[4]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[4]), 6.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[4]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[4]), 7.05, 1e-5); + REQUIRE(neighbors(0, newFromOld[4]) ==newFromOld[3]); + REQUIRE(distances(0, newFromOld[4]) == Approx(3.80).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[4]) ==newFromOld[10]); + REQUIRE(distances(1, newFromOld[4]) == Approx(4.05).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[4]) ==newFromOld[9]); + REQUIRE(distances(2, newFromOld[4]) == Approx(4.15).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[4]) ==newFromOld[8]); + REQUIRE(distances(3, newFromOld[4]) == Approx(4.60).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[4]) ==newFromOld[1]); + REQUIRE(distances(4, newFromOld[4]) == Approx(4.70).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[4]) ==newFromOld[2]); + REQUIRE(distances(5, newFromOld[4]) == Approx(4.90).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[4]) ==newFromOld[0]); + REQUIRE(distances(6, newFromOld[4]) == Approx(5.00).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[4]) ==newFromOld[5]); + REQUIRE(distances(7, newFromOld[4]) == Approx(5.27).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[4]) ==newFromOld[7]); + REQUIRE(distances(8, newFromOld[4]) == Approx(6.35).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[4]) ==newFromOld[6]); + REQUIRE(distances(9, newFromOld[4]) == Approx(7.05).epsilon(1e-7)); // Neighbors of point 5. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[5]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[5]), 0.27, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[5]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[5]), 0.37, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[5]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[5]), 0.57, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[5]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[5]), 0.67, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[5]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[5]), 1.08, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[5]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[5]), 1.12, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[5]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[5]), 1.22, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[5]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[5]), 1.47, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[5]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[5]), 1.78, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[5]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[5]), 5.27, 1e-5); + REQUIRE(neighbors(0, newFromOld[5]) ==newFromOld[0]); + REQUIRE(distances(0, newFromOld[5]) == Approx(0.27).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[5]) ==newFromOld[2]); + REQUIRE(distances(1, newFromOld[5]) == Approx(0.37).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[5]) ==newFromOld[1]); + REQUIRE(distances(2, newFromOld[5]) == Approx(0.57).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[5]) ==newFromOld[8]); + REQUIRE(distances(3, newFromOld[5]) == Approx(0.67).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[5]) ==newFromOld[7]); + REQUIRE(distances(4, newFromOld[5]) == Approx(1.08).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[5]) ==newFromOld[9]); + REQUIRE(distances(5, newFromOld[5]) == Approx(1.12).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[5]) ==newFromOld[10]); + REQUIRE(distances(6, newFromOld[5]) == Approx(1.22).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[5]) ==newFromOld[3]); + REQUIRE(distances(7, newFromOld[5]) == Approx(1.47).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[5]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[5]) == Approx(1.78).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[5]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[5]) == Approx(5.27).epsilon(1e-7)); // Neighbors of point 6. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[6]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[6]), 0.70, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[6]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[6]), 1.78, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[6]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[6]), 2.05, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[6]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[6]), 2.15, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[6]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[6]), 2.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[6]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[6]), 2.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[6]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[6]), 2.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[6]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[6]), 3.00, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[6]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[6]), 3.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[6]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[6]), 7.05, 1e-5); + REQUIRE(neighbors(0, newFromOld[6]) ==newFromOld[7]); + REQUIRE(distances(0, newFromOld[6]) == Approx(0.70).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[6]) ==newFromOld[5]); + REQUIRE(distances(1, newFromOld[6]) == Approx(1.78).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[6]) ==newFromOld[0]); + REQUIRE(distances(2, newFromOld[6]) == Approx(2.05).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[6]) ==newFromOld[2]); + REQUIRE(distances(3, newFromOld[6]) == Approx(2.15).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[6]) ==newFromOld[1]); + REQUIRE(distances(4, newFromOld[6]) == Approx(2.35).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[6]) ==newFromOld[8]); + REQUIRE(distances(5, newFromOld[6]) == Approx(2.45).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[6]) ==newFromOld[9]); + REQUIRE(distances(6, newFromOld[6]) == Approx(2.90).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[6]) ==newFromOld[10]); + REQUIRE(distances(7, newFromOld[6]) == Approx(3.00).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[6]) ==newFromOld[3]); + REQUIRE(distances(8, newFromOld[6]) == Approx(3.25).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[6]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[6]) == Approx(7.05).epsilon(1e-7)); // Neighbors of point 7. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[7]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[7]), 0.70, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[7]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[7]), 1.08, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[7]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[7]), 1.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[7]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[7]), 1.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[7]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[7]), 1.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[7]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[7]), 1.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[7]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[7]), 2.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[7]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[7]), 2.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[7]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[7]), 2.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[7]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[7]), 6.35, 1e-5); + REQUIRE(neighbors(0, newFromOld[7]) ==newFromOld[6]); + REQUIRE(distances(0, newFromOld[7]) == Approx(0.70).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[7]) ==newFromOld[5]); + REQUIRE(distances(1, newFromOld[7]) == Approx(1.08).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[7]) ==newFromOld[0]); + REQUIRE(distances(2, newFromOld[7]) == Approx(1.35).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[7]) ==newFromOld[2]); + REQUIRE(distances(3, newFromOld[7]) == Approx(1.45).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[7]) ==newFromOld[1]); + REQUIRE(distances(4, newFromOld[7]) == Approx(1.65).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[7]) ==newFromOld[8]); + REQUIRE(distances(5, newFromOld[7]) == Approx(1.75).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[7]) ==newFromOld[9]); + REQUIRE(distances(6, newFromOld[7]) == Approx(2.20).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[7]) ==newFromOld[10]); + REQUIRE(distances(7, newFromOld[7]) == Approx(2.30).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[7]) ==newFromOld[3]); + REQUIRE(distances(8, newFromOld[7]) == Approx(2.55).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[7]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[7]) == Approx(6.35).epsilon(1e-7)); // Neighbors of point 8. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[8]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[8]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[8]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[8]), 0.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[8]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[8]), 0.40, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[8]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[8]), 0.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[8]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[8]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[8]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[8]), 0.67, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[8]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[8]), 0.80, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[8]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[8]), 1.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[8]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[8]), 2.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[8]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[8]), 4.60, 1e-5); + REQUIRE(neighbors(0, newFromOld[8]) ==newFromOld[1]); + REQUIRE(distances(0, newFromOld[8]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[8]) ==newFromOld[2]); + REQUIRE(distances(1, newFromOld[8]) == Approx(0.30).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[8]) ==newFromOld[0]); + REQUIRE(distances(2, newFromOld[8]) == Approx(0.40).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[8]) ==newFromOld[9]); + REQUIRE(distances(3, newFromOld[8]) == Approx(0.45).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[8]) ==newFromOld[10]); + REQUIRE(distances(4, newFromOld[8]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[8]) ==newFromOld[5]); + REQUIRE(distances(5, newFromOld[8]) == Approx(0.67).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[8]) ==newFromOld[3]); + REQUIRE(distances(6, newFromOld[8]) == Approx(0.80).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[8]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[8]) == Approx(1.75).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[8]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[8]) == Approx(2.45).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[8]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[8]) == Approx(4.60).epsilon(1e-7)); // Neighbors of point 9. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[9]), newFromOld[10]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[9]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[9]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[9]), 0.35, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[9]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[9]), 0.45, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[9]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[9]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[9]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[9]), 0.75, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[9]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[9]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[9]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[9]), 1.12, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[9]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[9]), 2.20, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[9]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[9]), 2.90, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[9]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[9]), 4.15, 1e-5); + REQUIRE(neighbors(0, newFromOld[9]) ==newFromOld[10]); + REQUIRE(distances(0, newFromOld[9]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[9]) ==newFromOld[3]); + REQUIRE(distances(1, newFromOld[9]) == Approx(0.35).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[9]) ==newFromOld[8]); + REQUIRE(distances(2, newFromOld[9]) == Approx(0.45).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[9]) ==newFromOld[1]); + REQUIRE(distances(3, newFromOld[9]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[9]) ==newFromOld[2]); + REQUIRE(distances(4, newFromOld[9]) == Approx(0.75).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[9]) ==newFromOld[0]); + REQUIRE(distances(5, newFromOld[9]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[9]) ==newFromOld[5]); + REQUIRE(distances(6, newFromOld[9]) == Approx(1.12).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[9]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[9]) == Approx(2.20).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[9]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[9]) == Approx(2.90).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[9]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[9]) == Approx(4.15).epsilon(1e-7)); // Neighbors of point 10. - BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[10]), newFromOld[9]); - BOOST_REQUIRE_CLOSE(distances(0, newFromOld[10]), 0.10, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[10]), newFromOld[3]); - BOOST_REQUIRE_CLOSE(distances(1, newFromOld[10]), 0.25, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[10]), newFromOld[8]); - BOOST_REQUIRE_CLOSE(distances(2, newFromOld[10]), 0.55, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[10]), newFromOld[1]); - BOOST_REQUIRE_CLOSE(distances(3, newFromOld[10]), 0.65, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[10]), newFromOld[2]); - BOOST_REQUIRE_CLOSE(distances(4, newFromOld[10]), 0.85, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[10]), newFromOld[0]); - BOOST_REQUIRE_CLOSE(distances(5, newFromOld[10]), 0.95, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[10]), newFromOld[5]); - BOOST_REQUIRE_CLOSE(distances(6, newFromOld[10]), 1.22, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[10]), newFromOld[7]); - BOOST_REQUIRE_CLOSE(distances(7, newFromOld[10]), 2.30, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[10]), newFromOld[6]); - BOOST_REQUIRE_CLOSE(distances(8, newFromOld[10]), 3.00, 1e-5); - BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[10]), newFromOld[4]); - BOOST_REQUIRE_CLOSE(distances(9, newFromOld[10]), 4.05, 1e-5); + REQUIRE(neighbors(0, newFromOld[10]) ==newFromOld[9]); + REQUIRE(distances(0, newFromOld[10]) == Approx(0.10).epsilon(1e-7)); + REQUIRE(neighbors(1, newFromOld[10]) ==newFromOld[3]); + REQUIRE(distances(1, newFromOld[10]) == Approx(0.25).epsilon(1e-7)); + REQUIRE(neighbors(2, newFromOld[10]) ==newFromOld[8]); + REQUIRE(distances(2, newFromOld[10]) == Approx(0.55).epsilon(1e-7)); + REQUIRE(neighbors(3, newFromOld[10]) ==newFromOld[1]); + REQUIRE(distances(3, newFromOld[10]) == Approx(0.65).epsilon(1e-7)); + REQUIRE(neighbors(4, newFromOld[10]) ==newFromOld[2]); + REQUIRE(distances(4, newFromOld[10]) == Approx(0.85).epsilon(1e-7)); + REQUIRE(neighbors(5, newFromOld[10]) ==newFromOld[0]); + REQUIRE(distances(5, newFromOld[10]) == Approx(0.95).epsilon(1e-7)); + REQUIRE(neighbors(6, newFromOld[10]) ==newFromOld[5]); + REQUIRE(distances(6, newFromOld[10]) == Approx(1.22).epsilon(1e-7)); + REQUIRE(neighbors(7, newFromOld[10]) ==newFromOld[7]); + REQUIRE(distances(7, newFromOld[10]) == Approx(2.30).epsilon(1e-7)); + REQUIRE(neighbors(8, newFromOld[10]) ==newFromOld[6]); + REQUIRE(distances(8, newFromOld[10]) == Approx(3.00).epsilon(1e-7)); + REQUIRE(neighbors(9, newFromOld[10]) ==newFromOld[4]); + REQUIRE(distances(9, newFromOld[10]) == Approx(4.05).epsilon(1e-7)); } } @@ -658,13 +656,13 @@ BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(DualTreeVsNaive1) +TEST_CASE("KNNDualTreeVsNaive", "[KNNTest]") { arma::mat dataset; // Hard-coded filename: bad? if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KNN knn(dataset); @@ -680,8 +678,8 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive1) for (size_t i = 0; i < neighborsTree.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsTree(i), neighborsNaive(i)); - BOOST_REQUIRE_CLOSE(distancesTree(i), distancesNaive(i), 1e-5); + REQUIRE(neighborsTree(i) ==neighborsNaive(i)); + REQUIRE(distancesTree(i) == Approx(distancesNaive(i)).epsilon(1e-7)); } } @@ -691,14 +689,14 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive1) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(DualTreeVsNaive2) +TEST_CASE("KNNDualTreeVsNaive2", "[KNNTest]") { arma::mat dataset; // Hard-coded filename: bad? // Code duplication: also bad! if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KNN knn(dataset); @@ -715,8 +713,8 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive2) for (size_t i = 0; i < neighborsTree.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsTree[i], neighborsNaive[i]); - BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5); + REQUIRE(neighborsTree[i] ==neighborsNaive[i]); + REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7)); } } @@ -726,14 +724,14 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive2) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(SingleTreeVsNaive) +TEST_CASE("KNNSingleTreeVsNaive", "[KNNTest]") { arma::mat dataset; // Hard-coded filename: bad? // Code duplication: also bad! if (!data::Load("test_data_3_1000.csv", dataset)) - BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv!"); KNN knn(dataset, SINGLE_TREE_MODE); @@ -750,8 +748,8 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsNaive) for (size_t i = 0; i < neighborsTree.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsTree[i], neighborsNaive[i]); - BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5); + REQUIRE(neighborsTree[i] ==neighborsNaive[i]); + REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7)); } } @@ -761,7 +759,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsNaive) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) +TEST_CASE("KNNSingleCoverTreeTest", "[KNNTest]") { arma::mat data; data.randu(75, 1000); // 75 dimensional, 1000 points. @@ -784,8 +782,8 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) for (size_t i = 0; i < coverTreeNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(coverTreeNeighbors[i], naiveNeighbors[i]); - BOOST_REQUIRE_CLOSE(coverTreeDistances[i], naiveDistances[i], 1e-5); + REQUIRE(coverTreeNeighbors[i] ==naiveNeighbors[i]); + REQUIRE(coverTreeDistances[i] == Approx(naiveDistances[i]).epsilon(1e-7)); } } @@ -793,7 +791,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest) * Test the cover tree dual-tree nearest neighbors method against the naive * method. */ -BOOST_AUTO_TEST_CASE(DualCoverTreeTest) +TEST_CASE("KNNDualCoverTreeTest", "[KNNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -816,8 +814,8 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest) for (size_t i = 0; i < coverNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(coverNeighbors(i), kdNeighbors(i)); - BOOST_REQUIRE_CLOSE(coverDistances(i), kdDistances(i), 1e-5); + REQUIRE(coverNeighbors(i) ==kdNeighbors(i)); + REQUIRE(coverDistances(i) == Approx(kdDistances(i)).epsilon(1e-7)); } } @@ -827,7 +825,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest) * * Errors are produced if the results are not identical. */ -BOOST_AUTO_TEST_CASE(SingleBallTreeTest) +TEST_CASE("KNNSingleBallTreeTest", "[KNNTest]") { arma::mat data; data.randu(50, 300); // 50 dimensional, 300 points. @@ -855,8 +853,8 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest) for (size_t i = 0; i < ballTreeNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(ballTreeNeighbors[i], naiveNeighbors[i]); - BOOST_REQUIRE_CLOSE(ballTreeDistances[i], naiveDistances[i], 1e-5); + REQUIRE(ballTreeNeighbors[i] ==naiveNeighbors[i]); + REQUIRE(ballTreeDistances[i] == Approx(naiveDistances[i]).epsilon(1e-7)); } } @@ -864,7 +862,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest) * Test the ball tree dual-tree nearest neighbors method against the naive * method. */ -BOOST_AUTO_TEST_CASE(DualBallTreeTest) +TEST_CASE("KNNDualBallTreeTest", "[KNNTest]") { arma::mat dataset; data::Load("test_data_3_1000.csv", dataset); @@ -884,8 +882,8 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest) for (size_t i = 0; i < ballNeighbors.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(ballNeighbors(i), kdNeighbors(i)); - BOOST_REQUIRE_CLOSE(ballDistances(i), kdDistances(i), 1e-5); + REQUIRE(ballNeighbors(i) ==kdNeighbors(i)); + REQUIRE(ballDistances(i) == Approx(kdDistances(i)).epsilon(1e-7)); } } @@ -894,7 +892,7 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest) * nodes, and backtracking in non-overlapping nodes) against the naive method. * This uses only a random reference dataset. */ -BOOST_AUTO_TEST_CASE(HybridSpillSearchTest) +TEST_CASE("KNNHybridSpillSearchTest", "[KNNTest]") { arma::mat dataset; dataset.randu(50, 300); // 50 dimensional, 300 points. @@ -928,8 +926,8 @@ BOOST_AUTO_TEST_CASE(HybridSpillSearchTest) for (size_t i = 0; i < neighborsSPTree.n_elem; ++i) { - BOOST_REQUIRE_EQUAL(neighborsSPTree(i), neighborsNaive(i)); - BOOST_REQUIRE_CLOSE(distancesSPTree(i), distancesNaive(i), 1e-5); + REQUIRE(neighborsSPTree(i) ==neighborsNaive(i)); + REQUIRE(distancesSPTree(i) == Approx(distancesNaive(i)).epsilon(1e-7)); } } } @@ -938,7 +936,7 @@ BOOST_AUTO_TEST_CASE(HybridSpillSearchTest) * Test hybrid sp-tree search doesn't repeat points. * This uses only a random reference dataset. */ -BOOST_AUTO_TEST_CASE(DuplicatedSpillSearchTest) +TEST_CASE("KNNDuplicatedSpillSearchTest", "[KNNTest]") { arma::mat dataset; dataset.randu(50, 300); // 50 dimensional, 300 points. @@ -965,7 +963,7 @@ BOOST_AUTO_TEST_CASE(DuplicatedSpillSearchTest) for (size_t i = 0; i < neighborsSPTree.n_cols; ++i) { // Test that at least one point was found. - BOOST_REQUIRE(distancesSPTree(0, i) != DBL_MAX); + REQUIRE(distancesSPTree(0, i) != DBL_MAX); for (size_t j = 0; j < neighborsSPTree.n_rows; ++j) { @@ -974,7 +972,7 @@ BOOST_AUTO_TEST_CASE(DuplicatedSpillSearchTest) // All candidates with same distances must be different points. for (size_t k = j + 1; k < neighborsSPTree.n_rows && distancesSPTree(k, i) == distancesSPTree(j, i); ++k) - BOOST_REQUIRE(neighborsSPTree(k, i) != neighborsSPTree(j, i)); + REQUIRE(neighborsSPTree(k, i) != neighborsSPTree(j, i)); } } } @@ -984,7 +982,7 @@ BOOST_AUTO_TEST_CASE(DuplicatedSpillSearchTest) /** * Make sure sparse nearest neighbors works with kd trees. */ -BOOST_AUTO_TEST_CASE(SparseKNNKDTreeTest) +TEST_CASE("SparseKNNKDTreeTest", "[KNNTest]") { // The dimensionality of these datasets must be high so that the probability // of a completely empty point is very low. In this case, with dimensionality @@ -1015,14 +1013,15 @@ BOOST_AUTO_TEST_CASE(SparseKNNKDTreeTest) { for (size_t j = 0; j < naiveNeighbors.n_rows; ++j) { - BOOST_REQUIRE_EQUAL(naiveNeighbors(j, i), sparseNeighbors(j, i)); - BOOST_REQUIRE_CLOSE(naiveDistances(j, i), sparseDistances(j, i), 1e-5); + REQUIRE(naiveNeighbors(j, i) == sparseNeighbors(j, i)); + REQUIRE(naiveDistances(j, i) == + Approx(sparseDistances(j, i)).epsilon(1e-7)); } } } /* -BOOST_AUTO_TEST_CASE(SparseKNNCoverTreeTest) +TEST_CASE("SparseKNNCoverTreeTest", "[KNNTest]") { typedef CoverTree, FirstPointIsRoot, NeighborSearchStat, arma::sp_mat> SparseCoverTree; @@ -1053,14 +1052,14 @@ BOOST_AUTO_TEST_CASE(SparseKNNCoverTreeTest) { for (size_t j = 0; j < naiveNeighbors.n_rows; ++j) { - BOOST_REQUIRE_EQUAL(naiveNeighbors(j, i), sparseNeighbors(j, i)); - BOOST_REQUIRE_CLOSE(naiveDistances(j, i), sparseDistances(j, i), 1e-5); + REQUIRE(naiveNeighbors(j, i) == sparseNeighbors(j, i)); + REQUIRE(naiveDistances(j, i) == Approx(sparseDistances(j, i)).epsilon(1e-7)); } } } */ -BOOST_AUTO_TEST_CASE(KNNModelTest) +TEST_CASE("KNNModelTest", "[KNNTest]") { // Ensure that we can build an NSModel and get correct // results. @@ -1126,25 +1125,25 @@ BOOST_AUTO_TEST_CASE(KNNModelTest) models[i].Search(std::move(queryCopy), 3, neighbors, distances); - BOOST_REQUIRE_EQUAL(neighbors.n_rows, baselineNeighbors.n_rows); - BOOST_REQUIRE_EQUAL(neighbors.n_cols, baselineNeighbors.n_cols); - BOOST_REQUIRE_EQUAL(neighbors.n_elem, baselineNeighbors.n_elem); - BOOST_REQUIRE_EQUAL(distances.n_rows, baselineDistances.n_rows); - BOOST_REQUIRE_EQUAL(distances.n_cols, baselineDistances.n_cols); - BOOST_REQUIRE_EQUAL(distances.n_elem, baselineDistances.n_elem); + REQUIRE(neighbors.n_rows ==baselineNeighbors.n_rows); + REQUIRE(neighbors.n_cols ==baselineNeighbors.n_cols); + REQUIRE(neighbors.n_elem ==baselineNeighbors.n_elem); + REQUIRE(distances.n_rows ==baselineDistances.n_rows); + REQUIRE(distances.n_cols ==baselineDistances.n_cols); + REQUIRE(distances.n_elem ==baselineDistances.n_elem); for (size_t k = 0; k < distances.n_elem; ++k) { - BOOST_REQUIRE_EQUAL(neighbors[k], baselineNeighbors[k]); + REQUIRE(neighbors[k] ==baselineNeighbors[k]); if (std::abs(baselineDistances[k]) < 1e-5) - BOOST_REQUIRE_SMALL(distances[k], 1e-5); + REQUIRE(distances[k] == Approx(0.0).margin(1e-7)); else - BOOST_REQUIRE_CLOSE(distances[k], baselineDistances[k], 1e-5); + REQUIRE(distances[k] == Approx(baselineDistances[k]).epsilon(1e-7)); } } } } -BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) +TEST_CASE("KNNModelMonochromaticTest", "[KNNTest]") { // Ensure that we can build an NSModel and get correct // results, in the case where the reference set is the same as the query set. @@ -1208,19 +1207,19 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) models[i].Search(3, neighbors, distances); - BOOST_REQUIRE_EQUAL(neighbors.n_rows, baselineNeighbors.n_rows); - BOOST_REQUIRE_EQUAL(neighbors.n_cols, baselineNeighbors.n_cols); - BOOST_REQUIRE_EQUAL(neighbors.n_elem, baselineNeighbors.n_elem); - BOOST_REQUIRE_EQUAL(distances.n_rows, baselineDistances.n_rows); - BOOST_REQUIRE_EQUAL(distances.n_cols, baselineDistances.n_cols); - BOOST_REQUIRE_EQUAL(distances.n_elem, baselineDistances.n_elem); + REQUIRE(neighbors.n_rows ==baselineNeighbors.n_rows); + REQUIRE(neighbors.n_cols ==baselineNeighbors.n_cols); + REQUIRE(neighbors.n_elem ==baselineNeighbors.n_elem); + REQUIRE(distances.n_rows ==baselineDistances.n_rows); + REQUIRE(distances.n_cols ==baselineDistances.n_cols); + REQUIRE(distances.n_elem ==baselineDistances.n_elem); for (size_t k = 0; k < distances.n_elem; ++k) { - BOOST_REQUIRE_EQUAL(neighbors[k], baselineNeighbors[k]); + REQUIRE(neighbors[k] ==baselineNeighbors[k]); if (std::abs(baselineDistances[k]) < 1e-5) - BOOST_REQUIRE_SMALL(distances[k], 1e-5); + REQUIRE(distances[k] == Approx(0.0).margin(1e-7)); else - BOOST_REQUIRE_CLOSE(distances[k], baselineDistances[k], 1e-5); + REQUIRE(distances[k] == Approx(baselineDistances[k]).epsilon(1e-7)); } } } @@ -1231,7 +1230,7 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest) * before the second search. This test ensures that that happens, by making * sure the number of scores and base cases are equivalent for each search. */ -BOOST_AUTO_TEST_CASE(DoubleReferenceSearchTest) +TEST_CASE("KNNDoubleReferenceSearchTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 500); KNN knn(std::move(dataset)); @@ -1244,15 +1243,15 @@ BOOST_AUTO_TEST_CASE(DoubleReferenceSearchTest) knn.Search(3, secondNeighbors, secondDistances); - BOOST_REQUIRE_EQUAL(knn.BaseCases(), baseCases); - BOOST_REQUIRE_EQUAL(knn.Scores(), scores); + REQUIRE(knn.BaseCases() ==baseCases); + REQUIRE(knn.Scores() ==scores); } /** * Make sure that the neighborPtr matrix isn't accidentally deleted. * See issue #478. */ -BOOST_AUTO_TEST_CASE(NeighborPtrDeleteTest) +TEST_CASE("KNNNeighborPtrDeleteTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 100); @@ -1269,16 +1268,16 @@ BOOST_AUTO_TEST_CASE(NeighborPtrDeleteTest) // These will (hopefully) fail is either the neighbors or the distances matrix // has been accidentally deleted. - BOOST_REQUIRE_EQUAL(neighbors.n_cols, 50); - BOOST_REQUIRE_EQUAL(neighbors.n_rows, 3); - BOOST_REQUIRE_EQUAL(distances.n_cols, 50); - BOOST_REQUIRE_EQUAL(distances.n_rows, 3); + REQUIRE(neighbors.n_cols ==50); + REQUIRE(neighbors.n_rows ==3); + REQUIRE(distances.n_cols ==50); + REQUIRE(distances.n_rows ==3); } /** * Test the copy constructor and copy operator. */ -BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorTest) +TEST_CASE("KNNCopyConstructorAndOperatorTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 500); KNN knn(std::move(dataset)); @@ -1304,7 +1303,7 @@ BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorTest) /** * Test the copy constructor and copy operator using the RectangleTree. */ -BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorRTreeTest) +TEST_CASE("KNNCopyConstructorAndOperatorRTreeTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); KNN* knn = new KNN(std::move(dataset)); @@ -1469,7 +1468,7 @@ BOOST_AUTO_TEST_CASE(MoveConstructorTest) /** * Test the move constructor & move assignment using R trees. */ -BOOST_AUTO_TEST_CASE(MoveConstructorRTreeTest) +TEST_CASE("KNNMoveConstructorRTreeTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); typedef NeighborSearch(5, 500); KNN* knn = new KNN(std::move(dataset)); @@ -1661,7 +1660,7 @@ BOOST_AUTO_TEST_CASE(MoveOperatorTest) * Test the copy constructor and copy operator in naive mode (so there is no * tree). */ -BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorNaiveTest) +TEST_CASE("KNNCopyConstructorAndOperatorNaiveTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 50); KNN knn(std::move(dataset), NAIVE_MODE); @@ -1670,8 +1669,8 @@ BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorNaiveTest) KNN knn2(knn); KNN knn3 = knn; - BOOST_REQUIRE_EQUAL(knn2.SearchMode(), NAIVE_MODE); - BOOST_REQUIRE_EQUAL(knn3.SearchMode(), NAIVE_MODE); + REQUIRE(knn2.SearchMode() ==NAIVE_MODE); + REQUIRE(knn3.SearchMode() ==NAIVE_MODE); // Get results. arma::mat distances, distances2, distances3; @@ -1690,7 +1689,7 @@ BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorNaiveTest) /** * Test the move constructor in naive mode (so there is no tree). */ -BOOST_AUTO_TEST_CASE(MoveConstructorNaiveTest) +TEST_CASE("KNNMoveConstructorNaiveTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 50); KNN* knn = new KNN(std::move(dataset), NAIVE_MODE); @@ -1706,7 +1705,7 @@ BOOST_AUTO_TEST_CASE(MoveConstructorNaiveTest) delete knn; - BOOST_REQUIRE_EQUAL(knn2.SearchMode(), NAIVE_MODE); + REQUIRE(knn2.SearchMode() ==NAIVE_MODE); knn2.Search(3, neighbors2, distances2); @@ -1717,7 +1716,7 @@ BOOST_AUTO_TEST_CASE(MoveConstructorNaiveTest) /** * Test the move operator in naive mode (so there is no tree). */ -BOOST_AUTO_TEST_CASE(MoveOperatorNaiveTest) +TEST_CASE("KNNMoveOperatorNaiveTest", "[KNNTest]") { arma::mat dataset = arma::randu(5, 500); KNN* knn = new KNN(std::move(dataset), NAIVE_MODE); @@ -1733,7 +1732,7 @@ BOOST_AUTO_TEST_CASE(MoveOperatorNaiveTest) delete knn; - BOOST_REQUIRE_EQUAL(knn2.SearchMode(), NAIVE_MODE); + REQUIRE(knn2.SearchMode() ==NAIVE_MODE); knn2.Search(3, neighbors2, distances2); @@ -1745,7 +1744,7 @@ BOOST_AUTO_TEST_CASE(MoveOperatorNaiveTest) * Check that no garbage value is returned when greedy tree traversal * is performed over kd-tree. */ -BOOST_AUTO_TEST_CASE(GreedyTreeSearch) +TEST_CASE("KNNGreedyTreeSearch", "[KNNTest]") { // Initalize dataset. arma::mat dataset = arma::randu(3, 100); @@ -1765,12 +1764,9 @@ BOOST_AUTO_TEST_CASE(GreedyTreeSearch) // Check that all neighbour values are between 0 and 100, as only 100 points // are present in dataset. - BOOST_REQUIRE_EQUAL(arma::accu(neighbors < 0 || neighbors >= 100), 0); + REQUIRE(arma::accu(neighbors < 0 || neighbors >= 100) ==0); // Check that all distances values are between 0.0 and 1.0 as arma::randu // generates a uniform distribution in [0, 1]. - BOOST_REQUIRE_EQUAL(arma::accu(distances < 0.0 || distances > std::sqrt(3.0)), - 0); + REQUIRE(arma::accu(distances < 0.0 || distances > std::sqrt(3.0)) == 0); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/main_tests/kfn_test.cpp b/src/mlpack/tests/main_tests/kfn_test.cpp index 3d6999f4b0..2446c85fce 100644 --- a/src/mlpack/tests/main_tests/kfn_test.cpp +++ b/src/mlpack/tests/main_tests/kfn_test.cpp @@ -20,8 +20,8 @@ static const std::string testName = "K-FurthestNeighborsSearch"; #include "test_helper.hpp" #include -#include -#include "../test_tools.hpp" +#include "../test_catch_tools.hpp" +#include "../catch.hpp" using namespace mlpack; @@ -42,13 +42,12 @@ struct KFNTestFixture } }; -BOOST_FIXTURE_TEST_SUITE(KFNMainTest, KFNTestFixture); - /* * Check that we can't provide reference and query matrices * with different dimensions. */ -BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNEqualDimensionTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -65,7 +64,7 @@ BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest) SetInputParam("k", (int) 10); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -73,7 +72,8 @@ BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest) * Check that we can't specify an invalid k when only reference * matrix is given. */ -BOOST_AUTO_TEST_CASE(KFNInvalidKTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidKTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest) SetInputParam("k", (int) 101); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); delete IO::GetParam("output_model"); IO::GetParam("output_model") = NULL; @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest) // SetInputParam("reference", referenceData); // SetInputParam("k", (int) 0); // Invalid. - // BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + // REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); // IO::GetSingleton().Parameters()["reference"].wasPassed = false; // IO::GetSingleton().Parameters()["k"].wasPassed = false; @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("k", (int) -1); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -110,7 +110,8 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest) * Check that we can't specify an invalid k when both reference * and query matrices are given. */ -BOOST_AUTO_TEST_CASE(KFNInvalidKQueryDataTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidKQueryDataTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -124,14 +125,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKQueryDataTest) SetInputParam("k", (int) 101); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Check that we can't specify a negative leaf size. */ -BOOST_AUTO_TEST_CASE(KFNLeafSizeTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNLeafSizeTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -141,14 +143,15 @@ BOOST_AUTO_TEST_CASE(KFNLeafSizeTest) SetInputParam("leaf_size", (int) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass both input_model and reference matrix. */ -BOOST_AUTO_TEST_CASE(KFNRefModelTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNRefModelTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -164,14 +167,15 @@ BOOST_AUTO_TEST_CASE(KFNRefModelTest) std::move(IO::GetParam("output_model"))); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid tree type. */ -BOOST_AUTO_TEST_CASE(KFNInvalidTreeTypeTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidTreeTypeTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -182,14 +186,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidTreeTypeTest) SetInputParam("tree_type", (string) "min-rp"); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid algorithm. */ -BOOST_AUTO_TEST_CASE(KFNInvalidAlgoTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidAlgoTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -200,14 +205,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidAlgoTest) SetInputParam("algorithm", (string) "triple_tree"); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid value of epsilon. */ -BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidEpsilonTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -218,7 +224,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest) SetInputParam("epsilon", (double) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); IO::GetSingleton().Parameters()["reference"].wasPassed = false; IO::GetSingleton().Parameters()["epsilon"].wasPassed = false; @@ -226,7 +232,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("epsilon", (double) 2); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); IO::GetSingleton().Parameters()["reference"].wasPassed = false; IO::GetSingleton().Parameters()["epsilon"].wasPassed = false; @@ -234,14 +240,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("epsilon", (double) 1); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid value of percentage. */ -BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidPercentageTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -252,7 +259,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest) SetInputParam("percentage", (double) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); IO::GetSingleton().Parameters()["reference"].wasPassed = false; IO::GetSingleton().Parameters()["percentage"].wasPassed = false; @@ -260,7 +267,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("percentage", (double) 0); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); IO::GetSingleton().Parameters()["reference"].wasPassed = false; IO::GetSingleton().Parameters()["epsilon"].wasPassed = false; @@ -268,7 +275,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("percentage", (double) 2); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -276,7 +283,8 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest) * Make sure that dimensions of the neighbors and distances * matrices are correct given a value of k. */ -BOOST_AUTO_TEST_CASE(KFNOutputDimensionTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNOutputDimensionTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -288,20 +296,19 @@ BOOST_AUTO_TEST_CASE(KFNOutputDimensionTest) mlpackMain(); // Check the neighbors matrix has 4 points for each input point. - BOOST_REQUIRE_EQUAL(IO::GetParam> - ("neighbors").n_rows, 10); - BOOST_REQUIRE_EQUAL(IO::GetParam> - ("neighbors").n_cols, 100); + REQUIRE(IO::GetParam>("neighbors").n_rows == 10); + REQUIRE(IO::GetParam>("neighbors").n_cols == 100); // Check the distances matrix has 4 points for each input point. - BOOST_REQUIRE_EQUAL(IO::GetParam("distances").n_rows, 10); - BOOST_REQUIRE_EQUAL(IO::GetParam("distances").n_cols, 100); + REQUIRE(IO::GetParam("distances").n_rows == 10); + REQUIRE(IO::GetParam("distances").n_cols == 100); } /** * Ensure that saved model can be used again. */ -BOOST_AUTO_TEST_CASE(KFNModelReuseTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNModelReuseTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -344,7 +351,8 @@ BOOST_AUTO_TEST_CASE(KFNModelReuseTest) * Ensure that changing the value of epsilon gives us different * approximate KFN results. */ -BOOST_AUTO_TEST_CASE(KFNDifferentEpsilonTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNDifferentEpsilonTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 1000); // 1000 points in 3 dimensions. @@ -381,7 +389,8 @@ BOOST_AUTO_TEST_CASE(KFNDifferentEpsilonTest) * Ensure that changing the value of percentage gives us different * approximate KFN results. */ -BOOST_AUTO_TEST_CASE(KFNDifferentPercentageTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNDifferentPercentageTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 1000); // 1000 points in 3 dimensions. @@ -418,7 +427,8 @@ BOOST_AUTO_TEST_CASE(KFNDifferentPercentageTest) * Ensure that we get different results on running twice in greedy * search mode when random_basis is specified. */ -BOOST_AUTO_TEST_CASE(KFNRandomBasisTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNRandomBasisTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 1000); // 1000 points in 3 dimensions. @@ -434,8 +444,7 @@ BOOST_AUTO_TEST_CASE(KFNRandomBasisTest) arma::mat distances; neighbors = std::move(IO::GetParam>("neighbors")); distances = std::move(IO::GetParam("distances")); - BOOST_REQUIRE_EQUAL(IO::GetParam("output_model")->RandomBasis(), - true); + REQUIRE(IO::GetParam("output_model")->RandomBasis() == true); bindings::tests::CleanMemory(); @@ -448,15 +457,15 @@ BOOST_AUTO_TEST_CASE(KFNRandomBasisTest) CheckMatrices(neighbors, IO::GetParam>("neighbors")); CheckMatrices(distances, IO::GetParam("distances")); - BOOST_REQUIRE_EQUAL(IO::GetParam("output_model")->RandomBasis(), - false); + REQUIRE(IO::GetParam("output_model")->RandomBasis() == false); } /* * Ensure that the program runs successfully when we pass true_neighbors * and/or true_distances and fails when those matrices have the wrong shape. */ -BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNTrueNeighborDistanceTest", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -480,7 +489,7 @@ BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest) SetInputParam("true_distances", distances); SetInputParam("epsilon", (double) 0.5); - BOOST_REQUIRE_NO_THROW(mlpackMain()); + REQUIRE_NOTHROW(mlpackMain()); // True output matrices have incorrect shape. arma::Mat dummyNeighbors; @@ -500,7 +509,7 @@ BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest) SetInputParam("true_distances", std::move(dummyDistances)); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -508,7 +517,8 @@ BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest) * Ensure that different search algorithms give same result. * We do not consider greedy because it is an approximate algorithm. */ -BOOST_AUTO_TEST_CASE(KFNAllAlgorithmsTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNAllAlgorithmsTest", + "[KFNMainTest][BindingTests]") { string algorithms[] = {"dual_tree", "naive", "single_tree"}; const int nofalgorithms = 3; @@ -566,7 +576,8 @@ BOOST_AUTO_TEST_CASE(KFNAllAlgorithmsTest) /* * Ensure that different tree types give same result. */ -BOOST_AUTO_TEST_CASE(KFNAllTreeTypesTest) +TEST_CASE_METHOD(KFNTestFixture, "KFNAllTreeTypesTest", + "[KFNMainTest][BindingTests]") { string treetypes[] = {"kd", "vp", "rp", "max-rp", "ub", "cover", "r", "r-star", "x", "ball", "hilbert-r", "r-plus", "r-plus-plus", @@ -626,7 +637,8 @@ BOOST_AUTO_TEST_CASE(KFNAllTreeTypesTest) /** * Ensure that different leaf sizes give different results. */ -BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes) +TEST_CASE_METHOD(KFNTestFixture, "KFNDifferentLeafSizes", + "[KFNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -638,8 +650,7 @@ BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes) mlpackMain(); - BOOST_CHECK_EQUAL(IO::GetParam("output_model")->LeafSize(), - (int) 1); + REQUIRE(IO::GetParam("output_model")->LeafSize() == (int) 1); bindings::tests::CleanMemory(); @@ -655,8 +666,5 @@ BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes) // Check that initial output matrices and the output matrices using // saved model are equal. - BOOST_CHECK_EQUAL(IO::GetParam("output_model")->LeafSize(), - (int) 10); + REQUIRE(IO::GetParam("output_model")->LeafSize() == (int) 10); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/main_tests/knn_test.cpp b/src/mlpack/tests/main_tests/knn_test.cpp index 522f96aa44..f6096b2d80 100644 --- a/src/mlpack/tests/main_tests/knn_test.cpp +++ b/src/mlpack/tests/main_tests/knn_test.cpp @@ -20,8 +20,8 @@ static const std::string testName = "K-NearestNeighborsSearch"; #include "test_helper.hpp" #include -#include -#include "../test_tools.hpp" +#include "../test_catch_tools.hpp" +#include "../catch.hpp" using namespace mlpack; @@ -42,13 +42,12 @@ struct KNNTestFixture } }; -BOOST_FIXTURE_TEST_SUITE(KNNMainTest, KNNTestFixture); - /* * Check that we can't provide reference and query matrices * with different dimensions. */ -BOOST_AUTO_TEST_CASE(KNNEqualDimensionTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNEqualDimensionTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -65,7 +64,7 @@ BOOST_AUTO_TEST_CASE(KNNEqualDimensionTest) SetInputParam("k", (int) 10); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -73,7 +72,8 @@ BOOST_AUTO_TEST_CASE(KNNEqualDimensionTest) * Check that we can't specify an invalid k when only reference * matrix is given. */ -BOOST_AUTO_TEST_CASE(KNNInvalidKTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidKTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKTest) SetInputParam("k", (int) 101); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); IO::GetSingleton().Parameters()["reference"].wasPassed = false; IO::GetSingleton().Parameters()["k"].wasPassed = false; @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("k", (int) -1); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -99,7 +99,8 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKTest) * Check that we can't specify an invalid k when both reference * and query matrices are given. */ -BOOST_AUTO_TEST_CASE(KNNInvalidKQueryDataTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidKQueryDataTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -113,14 +114,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKQueryDataTest) SetInputParam("k", (int) 101); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Check that we can't specify a negative leaf size. */ -BOOST_AUTO_TEST_CASE(KNNLeafSizeTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNLeafSizeTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -130,14 +132,15 @@ BOOST_AUTO_TEST_CASE(KNNLeafSizeTest) SetInputParam("leaf_size", (int) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass both input_model and reference matrix. */ -BOOST_AUTO_TEST_CASE(KNNRefModelTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNRefModelTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -153,14 +156,15 @@ BOOST_AUTO_TEST_CASE(KNNRefModelTest) std::move(IO::GetParam("output_model"))); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid tree type. */ -BOOST_AUTO_TEST_CASE(KNNInvalidTreeTypeTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidTreeTypeTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -171,14 +175,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidTreeTypeTest) SetInputParam("tree_type", (string) "min-rp"); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid algorithm. */ -BOOST_AUTO_TEST_CASE(KNNInvalidAlgoTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidAlgoTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -189,14 +194,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidAlgoTest) SetInputParam("algorithm", (string) "triple_tree"); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid value of epsilon. */ -BOOST_AUTO_TEST_CASE(KNNInvalidEpsilonTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidEpsilonTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -207,14 +213,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidEpsilonTest) SetInputParam("epsilon", (double) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid value of tau. */ -BOOST_AUTO_TEST_CASE(KNNInvalidTauTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidTauTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -225,14 +232,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidTauTest) SetInputParam("tau", (double) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /* * Check that we can't pass an invalid value of rho. */ -BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidRhoTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -245,7 +253,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest) SetInputParam("rho", (double) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); // Reset passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -254,7 +262,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest) SetInputParam("reference", std::move(referenceData)); SetInputParam("rho", (double) 1.5); // Invalid. - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -262,7 +270,8 @@ BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest) * Make sure that dimensions of the neighbors and distances matrices are correct * given a value of k. */ -BOOST_AUTO_TEST_CASE(KNNOutputDimensionTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNOutputDimensionTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -274,20 +283,19 @@ BOOST_AUTO_TEST_CASE(KNNOutputDimensionTest) mlpackMain(); // Check the neighbors matrix has 10 points for each input point. - BOOST_REQUIRE_EQUAL(IO::GetParam> - ("neighbors").n_rows, 10); - BOOST_REQUIRE_EQUAL(IO::GetParam> - ("neighbors").n_cols, 100); + REQUIRE(IO::GetParam>("neighbors").n_rows == 10); + REQUIRE(IO::GetParam>("neighbors").n_cols == 100); // Check the distances matrix has 10 points for each input point. - BOOST_REQUIRE_EQUAL(IO::GetParam("distances").n_rows, 10); - BOOST_REQUIRE_EQUAL(IO::GetParam("distances").n_cols, 100); + REQUIRE(IO::GetParam("distances").n_rows == 10); + REQUIRE(IO::GetParam("distances").n_cols == 100); } /** * Ensure that saved model can be used again. */ -BOOST_AUTO_TEST_CASE(KNNModelReuseTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNModelReuseTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -329,7 +337,8 @@ BOOST_AUTO_TEST_CASE(KNNModelReuseTest) * Ensure that changing the value of tau gives us different greedy * spill tree results. */ -BOOST_AUTO_TEST_CASE(KNNDifferentTauTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentTauTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(6, 1000); // 1000 points in 6 dimensions. @@ -368,7 +377,8 @@ BOOST_AUTO_TEST_CASE(KNNDifferentTauTest) * Ensure that changing the value of rho gives us different greedy * spill tree results. */ -BOOST_AUTO_TEST_CASE(KNNDifferentRhoTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentRhoTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 1000); // 1000 points in 3 dimensions. @@ -408,7 +418,8 @@ BOOST_AUTO_TEST_CASE(KNNDifferentRhoTest) * Ensure that changing the value of epslion gives us different * approximate KNN results. */ -BOOST_AUTO_TEST_CASE(KNNDifferentEpsilonTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentEpsilonTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 1000); // 1000 points in 3 dimensions. @@ -445,7 +456,8 @@ BOOST_AUTO_TEST_CASE(KNNDifferentEpsilonTest) * Ensure that we get same results on running twice in dual-tree mode * search mode when random_basis is specified. */ -BOOST_AUTO_TEST_CASE(KNNRandomBasisTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNRandomBasisTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 1000); // 1000 points in 3 dimensions. @@ -462,8 +474,7 @@ BOOST_AUTO_TEST_CASE(KNNRandomBasisTest) arma::mat distances; neighbors = std::move(IO::GetParam>("neighbors")); distances = std::move(IO::GetParam("distances")); - BOOST_REQUIRE_EQUAL(IO::GetParam("output_model")->RandomBasis(), - true); + REQUIRE(IO::GetParam("output_model")->RandomBasis() == true); bindings::tests::CleanMemory(); @@ -476,15 +487,15 @@ BOOST_AUTO_TEST_CASE(KNNRandomBasisTest) CheckMatrices(neighbors, IO::GetParam>("neighbors")); CheckMatrices(distances, IO::GetParam("distances")); - BOOST_REQUIRE_EQUAL(IO::GetParam("output_model")->RandomBasis(), - false); + REQUIRE(IO::GetParam("output_model")->RandomBasis() == false); } /* * Ensure that the program runs successfully when we pass true_neighbors * and/or true_distances and fails when those matrices have the wrong shape. */ -BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNTrueNeighborDistanceTest", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -509,7 +520,7 @@ BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest) SetInputParam("true_distances", distances); SetInputParam("epsilon", (double) 0.5); - BOOST_REQUIRE_NO_THROW(mlpackMain()); + REQUIRE_NOTHROW(mlpackMain()); // True output matrices have incorrect shape. arma::Mat dummyNeighbors; @@ -526,7 +537,7 @@ BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest) SetInputParam("true_distances", std::move(dummyDistances)); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -534,7 +545,8 @@ BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest) * Ensure that different search algorithms give same result. * We do not consider greedy because it is an approximate algorithm. */ -BOOST_AUTO_TEST_CASE(KNNAllAlgorithmsTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNAllAlgorithmsTest", + "[KNNMainTest][BindingTests]") { string algorithms[] = {"dual_tree", "naive", "single_tree"}; const int nofalgorithms = 3; @@ -592,7 +604,8 @@ BOOST_AUTO_TEST_CASE(KNNAllAlgorithmsTest) /* * Ensure that different tree types give same result. */ -BOOST_AUTO_TEST_CASE(KNNAllTreeTypesTest) +TEST_CASE_METHOD(KNNTestFixture, "KNNAllTreeTypesTest", + "[KNNMainTest][BindingTests]") { // Not including spill for now. string treetypes[] = {"kd", "vp", "rp", "max-rp", "ub", "cover", "r", @@ -653,7 +666,8 @@ BOOST_AUTO_TEST_CASE(KNNAllTreeTypesTest) /** * Ensure that different leaf sizes give different results. */ -BOOST_AUTO_TEST_CASE(KNNDifferentLeafSizes) +TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentLeafSizes", + "[KNNMainTest][BindingTests]") { arma::mat referenceData; referenceData.randu(3, 100); // 100 points in 3 dimensions. @@ -680,10 +694,7 @@ BOOST_AUTO_TEST_CASE(KNNDifferentLeafSizes) // Check that initial output matrices and the output matrices using // saved model are equal. - BOOST_CHECK_EQUAL(output_model->LeafSize(), (int) 1); - BOOST_CHECK_EQUAL(IO::GetParam("output_model")->LeafSize(), - (int) 10); + REQUIRE(output_model->LeafSize() == (int) 1); + REQUIRE(IO::GetParam("output_model")->LeafSize() == (int) 10); delete output_model; } - -BOOST_AUTO_TEST_SUITE_END(); From 24aa7be3f5112ba0485d5c782fc693e7e98a40c1 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 23 Jul 2020 19:02:24 +0530 Subject: [PATCH 239/297] add documentation [ci skip] --- src/mlpack/methods/ann/layer/lookup.hpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index 1aa70bf648..e1492b64c8 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -17,11 +17,17 @@ #include namespace mlpack { -namespace ann /** Artificial Neural Network. */ { +namespace ann /* Artificial Neural Network. */ { /** - * Implementation of the Lookup class. The Lookup class is a particular - * convolution, where the width of the convolution is 1. + * The Lookup class stores word embeddings and retrieves them using tokens. The + * Lookup layer is always the first layer of the network. The input to the + * Lookup class is a matrix of shape (sequenceLength, batchSize). The matrix + * consists of tokens which are used to lookup the table (i.e. weights) to find + * the embeddings of those tokens. + * + * The input shape : (sequenceLength, batchSize). + * The output shape : (embeddingSize * sequenceLength, batchSize). * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). @@ -36,8 +42,7 @@ class Lookup { public: /** - * Create the Lookup object using the specified number of input and output - * units. + * Create the Lookup object using the specified vocabulary and embedding size. * * @param vocabSize The size of the vocabulary. * @param embeddingSize The length of each embedding vector. From e9fc410238aab62fc115f5b5606d26de89f89f0f Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 23 Jul 2020 20:14:02 +0530 Subject: [PATCH 240/297] backward function is meaningless for lookup layer, so removing it. [ci skip] --- src/mlpack/methods/ann/layer/lookup.hpp | 4 ++-- src/mlpack/methods/ann/layer/lookup_impl.hpp | 6 +++--- src/mlpack/tests/ann_layer_test.cpp | 5 ----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index e1492b64c8..f5d9e58095 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -70,8 +70,8 @@ class Lookup */ template void Backward(const arma::Mat& /* input */, - const arma::Mat& gy, - arma::Mat& g); + const arma::Mat& /* gy */, + arma::Mat& /* g */); /** * Calculate the gradient using the output delta and the input activation. diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 8e5e1410d4..81387fd359 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -50,10 +50,10 @@ template template void Lookup::Backward( const arma::Mat& /* input */, - const arma::Mat& gy, - arma::Mat& g) + const arma::Mat& /* gy */, + arma::Mat& /* g */) { - g = gy; + // Nothing to do here. } template diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index bd23cc5646..6bca11243b 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1680,11 +1680,6 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output.col(i)), 1e-3); } - // Test the Backward function. - gy = 0.3 * arma::randu(embeddingSize * seqLength, batchSize); - module.Backward(input, gy, g); - BOOST_REQUIRE_EQUAL(arma::accu(gy), arma::accu(g)); - // Test the Gradient function. arma::mat error = 0.01 * arma::randu(embeddingSize * seqLength, batchSize); module.Gradient(input, error, gradient); From 47c691e0c7cf472473868cb4d5af339d8e44c6ef Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Thu, 23 Jul 2020 20:16:44 +0530 Subject: [PATCH 241/297] fix latex documentation failure --- src/mlpack/methods/ann/layer/lookup.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index f5d9e58095..bc61a9b3d8 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -65,8 +65,8 @@ class Lookup * forward pass. * * @param * (input) The propagated input activation. - * @param gy The backpropagated error. - * @param g The calculated gradient. + * @param * (gy) The backpropagated error. + * @param * (g) The calculated gradient. */ template void Backward(const arma::Mat& /* input */, From 78e28a4a1544846a7d9dd22ec8a16c6f2dd51ef9 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Thu, 23 Jul 2020 21:21:56 +0530 Subject: [PATCH 242/297] migrate load and save test from boost to catch2 --- src/mlpack/tests/CMakeLists.txt | 2 +- src/mlpack/tests/load_save_test.cpp | 1424 +++++++++++++-------------- 2 files changed, 711 insertions(+), 715 deletions(-) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 4a094d6a9a..a701f9a3cd 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -57,7 +57,6 @@ add_executable(mlpack_test linear_regression_test.cpp linear_svm_test.cpp lmnn_test.cpp - load_save_test.cpp local_coordinate_coding_test.cpp log_test.cpp logistic_regression_test.cpp @@ -174,6 +173,7 @@ add_executable(mlpack_catch_test serialization_catch.hpp test_catch_tools.hpp image_load_test.cpp + load_save_test.cpp main_tests/image_converter_test.cpp main_tests/test_helper.hpp ) diff --git a/src/mlpack/tests/load_save_test.cpp b/src/mlpack/tests/load_save_test.cpp index db2e24a29f..12429e43ed 100644 --- a/src/mlpack/tests/load_save_test.cpp +++ b/src/mlpack/tests/load_save_test.cpp @@ -14,46 +14,44 @@ #include #include #include -#include -#include "test_tools.hpp" +#include "catch.hpp" +#include "test_catch_tools.hpp" using namespace mlpack; using namespace mlpack::data; using namespace std; -BOOST_AUTO_TEST_SUITE(LoadSaveTest); - /** * Make sure failure occurs when no extension given. */ -BOOST_AUTO_TEST_CASE(NoExtensionLoad) +TEST_CASE("NoExtensionLoad", "[LoadSaveTest]") { arma::mat out; - BOOST_REQUIRE(data::Load("noextension", out) == false); + REQUIRE(data::Load("noextension", out) == false); } /** * Make sure failure occurs when no extension given. */ -BOOST_AUTO_TEST_CASE(NoExtensionSave) +TEST_CASE("NoExtensionSave", "[LoadSaveTest]") { arma::mat out; - BOOST_REQUIRE(data::Save("noextension", out) == false); + REQUIRE(data::Save("noextension", out) == false); } /** * Make sure load fails if the file does not exist. */ -BOOST_AUTO_TEST_CASE(NotExistLoad) +TEST_CASE("NotExistLoad", "[LoadSaveTest]") { arma::mat out; - BOOST_REQUIRE(data::Load("nonexistentfile_______________.csv", out) == false); + REQUIRE(data::Load("nonexistentfile_______________.csv", out) == false); } /** * Make sure a CSV is loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadCSVTest) +TEST_CASE("LoadCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -64,13 +62,13 @@ BOOST_AUTO_TEST_CASE(LoadCSVTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.csv", test) == true); + REQUIRE(data::Load("test_file.csv", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -79,7 +77,7 @@ BOOST_AUTO_TEST_CASE(LoadCSVTest) /** * Make sure a TSV is loaded correctly to a sparse matrix. */ -BOOST_AUTO_TEST_CASE(LoadSparseTSVTest) +TEST_CASE("LoadSparseTSVTest", "[LoadSaveTest]") { fstream f; f.open("test_sparse_file.tsv", fstream::out); @@ -96,11 +94,11 @@ BOOST_AUTO_TEST_CASE(LoadSparseTSVTest) arma::sp_mat test; - BOOST_REQUIRE(data::Load( + REQUIRE(data::Load( "test_sparse_file.tsv", test, true, false) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 8); - BOOST_REQUIRE_EQUAL(test.n_cols, 9); + REQUIRE(test.n_rows == 8); + REQUIRE(test.n_cols == 9); arma::sp_mat::const_iterator it = test.begin(); arma::sp_mat::const_iterator it_end = test.end(); @@ -108,9 +106,9 @@ BOOST_AUTO_TEST_CASE(LoadSparseTSVTest) double temp = 0.1; for (int i = 0; it != it_end; ++it, temp += 0.1, ++i) { - BOOST_REQUIRE_CLOSE((double)(*it), temp, 1e-5); - BOOST_REQUIRE_EQUAL((int)(it.row()), i + 1); - BOOST_REQUIRE_EQUAL((int)it.col(), i + 2); + REQUIRE((double)(*it) == Approx(temp).epsilon(1e-7)); + REQUIRE((int)(it.row()) == i + 1); + REQUIRE((int)it.col() == i + 2); } // Remove the file. remove("test_sparse_file.tsv"); @@ -119,7 +117,7 @@ BOOST_AUTO_TEST_CASE(LoadSparseTSVTest) /** * Make sure a CSV in text format is loaded correctly to a sparse matrix. */ -BOOST_AUTO_TEST_CASE(LoadSparseTXTTest) +TEST_CASE("LoadSparseTXTTest", "[LoadSaveTest]") { fstream f; f.open("test_sparse_file.txt", fstream::out); @@ -136,10 +134,10 @@ BOOST_AUTO_TEST_CASE(LoadSparseTXTTest) arma::sp_mat test; - BOOST_REQUIRE(data::Load("test_sparse_file.txt", test, true, false) == true); + REQUIRE(data::Load("test_sparse_file.txt", test, true, false) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 8); - BOOST_REQUIRE_EQUAL(test.n_cols, 9); + REQUIRE(test.n_rows == 8); + REQUIRE(test.n_cols == 9); arma::sp_mat::const_iterator it = test.begin(); arma::sp_mat::const_iterator it_end = test.end(); @@ -147,9 +145,9 @@ BOOST_AUTO_TEST_CASE(LoadSparseTXTTest) double temp = 0.1; for (int i = 0; it != it_end; ++it, temp += 0.1, ++i) { - BOOST_REQUIRE_CLOSE((double)(*it), temp, 1e-5); - BOOST_REQUIRE_EQUAL((int)(it.row()), i + 1); - BOOST_REQUIRE_EQUAL((int)it.col(), i + 2); + REQUIRE((double)(*it) == Approx(temp).epsilon(1e-7)); + REQUIRE((int)(it.row()) == i + 1); + REQUIRE((int)it.col() == i + 2); } // Remove the file. remove("test_sparse_file.txt"); @@ -158,7 +156,7 @@ BOOST_AUTO_TEST_CASE(LoadSparseTXTTest) /** * Make sure a TSV is loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadTSVTest) +TEST_CASE("LoadTSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -169,13 +167,13 @@ BOOST_AUTO_TEST_CASE(LoadTSVTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.csv", test) == true); + REQUIRE(data::Load("test_file.csv", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -184,7 +182,7 @@ BOOST_AUTO_TEST_CASE(LoadTSVTest) /** * Test TSV loading with .tsv extension. */ -BOOST_AUTO_TEST_CASE(LoadTSVExtensionTest) +TEST_CASE("LoadTSVExtensionTest", "[LoadSaveTest]") { fstream f; f.open("test_file.tsv", fstream::out); @@ -195,13 +193,13 @@ BOOST_AUTO_TEST_CASE(LoadTSVExtensionTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.tsv", test) == true); + REQUIRE(data::Load("test_file.tsv", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.tsv"); @@ -210,24 +208,24 @@ BOOST_AUTO_TEST_CASE(LoadTSVExtensionTest) /** * Make sure a CSV is saved correctly. */ -BOOST_AUTO_TEST_CASE(SaveCSVTest) +TEST_CASE("SaveCSVTest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" "3 7;" "4 8;"; - BOOST_REQUIRE(data::Save("test_file.csv", test) == true); + REQUIRE(data::Save("test_file.csv", test) == true); // Load it in and make sure it is the same. arma::mat test2; - BOOST_REQUIRE(data::Load("test_file.csv", test2) == true); + REQUIRE(data::Load("test_file.csv", test2) == true); - BOOST_REQUIRE_EQUAL(test2.n_rows, 4); - BOOST_REQUIRE_EQUAL(test2.n_cols, 2); + REQUIRE(test2.n_rows == 4); + REQUIRE(test2.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test2[i], (double) (i + 1), 1e-5); + REQUIRE(test2[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -236,21 +234,21 @@ BOOST_AUTO_TEST_CASE(SaveCSVTest) /** * Make sure a TSV is saved correctly for a sparse matrix */ -BOOST_AUTO_TEST_CASE(SaveSparseTSVTest) +TEST_CASE("SaveSparseTSVTest", "[LoadSaveTest]") { arma::sp_mat test = "0.1\t0\t0\t0;" "0\t0.2\t0\t0;" "0\t0\t0.3\t0;" "0\t0\t0\t0.4;"; - BOOST_REQUIRE(data::Save("test_sparse_file.tsv", test, true, false) == true); + REQUIRE(data::Save("test_sparse_file.tsv", test, true, false) == true); // Load it in and make sure it is the same. arma::sp_mat test2; - BOOST_REQUIRE(data::Load("test_sparse_file.tsv", test2, true, false) == true); + REQUIRE(data::Load("test_sparse_file.tsv", test2, true, false) == true); - BOOST_REQUIRE_EQUAL(test2.n_rows, 4); - BOOST_REQUIRE_EQUAL(test2.n_cols, 4); + REQUIRE(test2.n_rows == 4); + REQUIRE(test2.n_cols == 4); arma::sp_mat::const_iterator it = test2.begin(); arma::sp_mat::const_iterator it_end = test2.end(); @@ -259,9 +257,9 @@ BOOST_AUTO_TEST_CASE(SaveSparseTSVTest) for (int i = 0; it != it_end; ++it, temp += 0.1, ++i) { double val = (*it); - BOOST_REQUIRE_CLOSE(val, temp, 1e-5); - BOOST_REQUIRE_EQUAL((int)(it.row()), i); - BOOST_REQUIRE_EQUAL((int)it.col(), i); + REQUIRE(val == Approx(temp).epsilon(1e-7)); + REQUIRE((int)(it.row()) == i); + REQUIRE((int)it.col() == i); } // Remove the file. @@ -271,21 +269,21 @@ BOOST_AUTO_TEST_CASE(SaveSparseTSVTest) /** * Make sure a TSV is saved correctly for a sparse matrix */ -BOOST_AUTO_TEST_CASE(SaveSparseTXTTest) +TEST_CASE("SaveSparseTXTTest", "[LoadSaveTest]") { arma::sp_mat test = "0.1 0 0 0;" "0 0.2 0 0;" "0 0 0.3 0;" "0 0 0 0.4;"; - BOOST_REQUIRE(data::Save("test_sparse_file.txt", test, true, true) == true); + REQUIRE(data::Save("test_sparse_file.txt", test, true, true) == true); // Load it in and make sure it is the same. arma::sp_mat test2; - BOOST_REQUIRE(data::Load("test_sparse_file.txt", test2, true, true) == true); + REQUIRE(data::Load("test_sparse_file.txt", test2, true, true) == true); - BOOST_REQUIRE_EQUAL(test2.n_rows, 4); - BOOST_REQUIRE_EQUAL(test2.n_cols, 4); + REQUIRE(test2.n_rows == 4); + REQUIRE(test2.n_cols == 4); arma::sp_mat::const_iterator it = test2.begin(); arma::sp_mat::const_iterator it_end = test2.end(); @@ -294,9 +292,9 @@ BOOST_AUTO_TEST_CASE(SaveSparseTXTTest) for (int i = 0; it != it_end; ++it, temp += 0.1, ++i) { double val = (*it); - BOOST_REQUIRE_CLOSE(val, temp, 1e-5); - BOOST_REQUIRE_EQUAL((int)(it.row()), i); - BOOST_REQUIRE_EQUAL((int)it.col(), i); + REQUIRE(val == Approx(temp).epsilon(1e-7)); + REQUIRE((int)(it.row()) == i); + REQUIRE((int)it.col() == i); } // Remove the file. @@ -306,21 +304,21 @@ BOOST_AUTO_TEST_CASE(SaveSparseTXTTest) /** * Make sure a Sparse Matrix is saved and loaded correctly in binary format */ -BOOST_AUTO_TEST_CASE(SaveSparseBinaryTest) +TEST_CASE("SaveSparseBinaryTest", "[LoadSaveTest]") { arma::sp_mat test = "0.1 0 0 0;" "0 0.2 0 0;" "0 0 0.3 0;" "0 0 0 0.4;"; - BOOST_REQUIRE(data::Save("test_sparse_file.bin", test, true, false) == true); + REQUIRE(data::Save("test_sparse_file.bin", test, true, false) == true); // Load it in and make sure it is the same. arma::sp_mat test2; - BOOST_REQUIRE(data::Load("test_sparse_file.bin", test2, true, false) == true); + REQUIRE(data::Load("test_sparse_file.bin", test2, true, false) == true); - BOOST_REQUIRE_EQUAL(test2.n_rows, 4); - BOOST_REQUIRE_EQUAL(test2.n_cols, 4); + REQUIRE(test2.n_rows == 4); + REQUIRE(test2.n_cols == 4); arma::sp_mat::const_iterator it = test2.begin(); arma::sp_mat::const_iterator it_end = test2.end(); @@ -329,9 +327,9 @@ BOOST_AUTO_TEST_CASE(SaveSparseBinaryTest) for (int i = 0; it != it_end; ++it, temp += 0.1, ++i) { double val = (*it); - BOOST_REQUIRE_CLOSE(val, temp, 1e-5); - BOOST_REQUIRE_EQUAL((int)(it.row()), i); - BOOST_REQUIRE_EQUAL((int)it.col(), i); + REQUIRE(val == Approx(temp).epsilon(1e-7)); + REQUIRE((int)(it.row()) == i); + REQUIRE((int)it.col() == i); } // Remove the file. @@ -341,7 +339,7 @@ BOOST_AUTO_TEST_CASE(SaveSparseBinaryTest) /** * Make sure CSVs can be loaded in transposed form. */ -BOOST_AUTO_TEST_CASE(LoadTransposedCSVTest) +TEST_CASE("LoadTransposedCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -352,13 +350,13 @@ BOOST_AUTO_TEST_CASE(LoadTransposedCSVTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false, true) == true); + REQUIRE(data::Load("test_file.csv", test, false, true) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); + REQUIRE(test.n_cols == 2); + REQUIRE(test.n_rows == 4); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -367,7 +365,7 @@ BOOST_AUTO_TEST_CASE(LoadTransposedCSVTest) /** * Make sure ColVec can be loaded. */ -BOOST_AUTO_TEST_CASE(LoadColVecCSVTest) +TEST_CASE("LoadColVecCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -378,13 +376,13 @@ BOOST_AUTO_TEST_CASE(LoadColVecCSVTest) f.close(); arma::colvec test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false) == true); + REQUIRE(data::Load("test_file.csv", test, false) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 1); - BOOST_REQUIRE_EQUAL(test.n_rows, 8); + REQUIRE(test.n_cols == 1); + REQUIRE(test.n_rows == 8); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) i, 1e-5); + REQUIRE(test[i] == Approx((double) i).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -393,7 +391,7 @@ BOOST_AUTO_TEST_CASE(LoadColVecCSVTest) /** * Make sure we can load a transposed column vector. */ -BOOST_AUTO_TEST_CASE(LoadColVecTransposedCSVTest) +TEST_CASE("LoadColVecTransposedCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -404,13 +402,13 @@ BOOST_AUTO_TEST_CASE(LoadColVecTransposedCSVTest) f.close(); arma::colvec test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false) == true); + REQUIRE(data::Load("test_file.csv", test, false) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 1); - BOOST_REQUIRE_EQUAL(test.n_rows, 9); + REQUIRE(test.n_cols == 1); + REQUIRE(test.n_rows == 9); for (size_t i = 0; i < 9; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) i, 1e-5); + REQUIRE(test[i] == Approx((double) i).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -420,7 +418,7 @@ BOOST_AUTO_TEST_CASE(LoadColVecTransposedCSVTest) * Make sure besides numeric data "quoted strings" or * 'quoted strings' in csv files are loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadQuotedStringInCSVTest) +TEST_CASE("LoadQuotedStringInCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -442,21 +440,21 @@ BOOST_AUTO_TEST_CASE(LoadQuotedStringInCSVTest) arma::mat test; data::DatasetInfo info; - BOOST_REQUIRE(data::Load("test_file.csv", test, info, false, true) == true); + REQUIRE(data::Load("test_file.csv", test, info, false, true) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 3); - BOOST_REQUIRE_EQUAL(test.n_cols, 5); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 3); + REQUIRE(test.n_rows == 3); + REQUIRE(test.n_cols == 5); + REQUIRE(info.Dimensionality() == 3); // Check each element for equality/ closeness. for (size_t i = 0; i < 5; ++i) - BOOST_REQUIRE_CLOSE(test.at(0, i), (double) (i + 1), 1e-5); + REQUIRE(test.at(0, i) == Approx((double) (i + 1)).epsilon(1e-7)); for (size_t i = 0; i < 5; ++i) - BOOST_REQUIRE_EQUAL(info.UnmapString(test.at(1, i), 1, 0), elements[i]); + REQUIRE(info.UnmapString(test.at(1, i), 1, 0) == elements[i]); for (size_t i = 0; i < 5; ++i) - BOOST_REQUIRE_EQUAL(info.UnmapString(test.at(2, i), 2, 0), "field 3"); + REQUIRE(info.UnmapString(test.at(2, i), 2, 0) == "field 3"); // Clear the vector to free the space. elements.clear(); @@ -468,7 +466,7 @@ BOOST_AUTO_TEST_CASE(LoadQuotedStringInCSVTest) * Make sure besides numeric data "quoted strings" or * 'quoted strings' in txt files are loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadQuotedStringInTXTTest) +TEST_CASE("LoadQuotedStringInTXTTest", "[LoadSaveTest]") { fstream f; f.open("test_file.txt", fstream::out); @@ -484,21 +482,21 @@ BOOST_AUTO_TEST_CASE(LoadQuotedStringInTXTTest) arma::mat test; data::DatasetInfo info; - BOOST_REQUIRE(data::Load("test_file.txt", test, info, false, true) == true); + REQUIRE(data::Load("test_file.txt", test, info, false, true) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 3); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 3); + REQUIRE(test.n_rows == 3); + REQUIRE(test.n_cols == 2); + REQUIRE(info.Dimensionality() == 3); // Check each element for equality/ closeness. for (size_t i = 0; i < 2; ++i) - BOOST_REQUIRE_CLOSE(test.at(0, i), (double) (i + 1), 1e-5); + REQUIRE(test.at(0, i) == Approx((double) (i + 1)).epsilon(1e-7)); for (size_t i = 0; i < 2; ++i) - BOOST_REQUIRE_EQUAL(info.UnmapString(test.at(1, i), 1, 0), elements[i]); + REQUIRE(info.UnmapString(test.at(1, i), 1, 0) == elements[i]); for (size_t i = 0; i < 2; ++i) - BOOST_REQUIRE_EQUAL(info.UnmapString(test.at(2, i), 2, 0), "field3"); + REQUIRE(info.UnmapString(test.at(2, i), 2, 0) == "field3"); // Clear the vector to free the space. elements.clear(); @@ -510,7 +508,7 @@ BOOST_AUTO_TEST_CASE(LoadQuotedStringInTXTTest) * Make sure besides numeric data "quoted strings" or * 'quoted strings' in tsv files are loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadQuotedStringInTSVTest) +TEST_CASE("LoadQuotedStringInTSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.tsv", fstream::out); @@ -532,21 +530,21 @@ BOOST_AUTO_TEST_CASE(LoadQuotedStringInTSVTest) arma::mat test; data::DatasetInfo info; - BOOST_REQUIRE(data::Load("test_file.tsv", test, info, false, true) == true); + REQUIRE(data::Load("test_file.tsv", test, info, false, true) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 3); - BOOST_REQUIRE_EQUAL(test.n_cols, 5); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 3); + REQUIRE(test.n_rows == 3); + REQUIRE(test.n_cols == 5); + REQUIRE(info.Dimensionality() == 3); // Check each element for equality/ closeness. for (size_t i = 0; i < 5; ++i) - BOOST_REQUIRE_CLOSE(test.at(0, i), (double) (i + 1), 1e-5); + REQUIRE(test.at(0, i) == Approx((double) (i + 1)).epsilon(1e-7)); for (size_t i = 0; i < 5; ++i) - BOOST_REQUIRE_EQUAL(info.UnmapString(test.at(1, i), 1, 0), elements[i]); + REQUIRE(info.UnmapString(test.at(1, i), 1, 0) == elements[i]); for (size_t i = 0; i < 5; ++i) - BOOST_REQUIRE_EQUAL(info.UnmapString(test.at(2, i), 2, 0), "field 3"); + REQUIRE(info.UnmapString(test.at(2, i), 2, 0) == "field 3"); // Clear the vector to free the space. elements.clear(); @@ -558,7 +556,7 @@ BOOST_AUTO_TEST_CASE(LoadQuotedStringInTSVTest) * Make sure Load() throws an exception when trying to load a matrix into a * colvec or rowvec. */ -BOOST_AUTO_TEST_CASE(LoadMatinVec) +TEST_CASE("LoadMatinVec", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -573,11 +571,11 @@ BOOST_AUTO_TEST_CASE(LoadMatinVec) */ Log::Fatal.ignoreInput = true; arma::vec coltest; - BOOST_REQUIRE_THROW(data::Load("test_file.csv", coltest, true), + REQUIRE_THROWS_AS(data::Load("test_file.csv", coltest, true), std::runtime_error); arma::rowvec rowtest; - BOOST_REQUIRE_THROW(data::Load("test_file.csv", rowtest, true), + REQUIRE_THROWS_AS(data::Load("test_file.csv", rowtest, true), std::runtime_error); Log::Fatal.ignoreInput = false; @@ -587,7 +585,7 @@ BOOST_AUTO_TEST_CASE(LoadMatinVec) /** * Make sure that rowvecs can be loaded successfully. */ -BOOST_AUTO_TEST_CASE(LoadRowVecCSVTest) +TEST_CASE("LoadRowVecCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -600,13 +598,13 @@ BOOST_AUTO_TEST_CASE(LoadRowVecCSVTest) f.close(); arma::rowvec test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false) == true); + REQUIRE(data::Load("test_file.csv", test, false) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 8); - BOOST_REQUIRE_EQUAL(test.n_rows, 1); + REQUIRE(test.n_cols == 8); + REQUIRE(test.n_rows == 1); for (size_t i = 0; i < 8 ; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) i , 1e-5); + REQUIRE(test[i] == Approx((double) i).epsilon(1e-7)); remove("test_file.csv"); } @@ -614,7 +612,7 @@ BOOST_AUTO_TEST_CASE(LoadRowVecCSVTest) /** * Make sure that we can load transposed row vectors. */ -BOOST_AUTO_TEST_CASE(LoadRowVecTransposedCSVTest) +TEST_CASE("LoadRowVecTransposedCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -625,13 +623,13 @@ BOOST_AUTO_TEST_CASE(LoadRowVecTransposedCSVTest) f.close(); arma::rowvec test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false) == true); + REQUIRE(data::Load("test_file.csv", test, false) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 1); - BOOST_REQUIRE_EQUAL(test.n_cols, 8); + REQUIRE(test.n_rows == 1); + REQUIRE(test.n_cols == 8); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) i, 1e-5); + REQUIRE(test[i] == Approx((double) i).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -640,7 +638,7 @@ BOOST_AUTO_TEST_CASE(LoadRowVecTransposedCSVTest) /** * Make sure TSVs can be loaded in transposed form. */ -BOOST_AUTO_TEST_CASE(LoadTransposedTSVTest) +TEST_CASE("LoadTransposedTSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -651,13 +649,13 @@ BOOST_AUTO_TEST_CASE(LoadTransposedTSVTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false, true) == true); + REQUIRE(data::Load("test_file.csv", test, false, true) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); + REQUIRE(test.n_cols == 2); + REQUIRE(test.n_rows == 4); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -666,7 +664,7 @@ BOOST_AUTO_TEST_CASE(LoadTransposedTSVTest) /** * Check TSV loading with .tsv extension. */ -BOOST_AUTO_TEST_CASE(LoadTransposedTSVExtensionTest) +TEST_CASE("LoadTransposedTSVExtensionTest", "[LoadSaveTest]") { fstream f; f.open("test_file.tsv", fstream::out); @@ -677,13 +675,13 @@ BOOST_AUTO_TEST_CASE(LoadTransposedTSVExtensionTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.tsv", test, false, true) == true); + REQUIRE(data::Load("test_file.tsv", test, false, true) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); + REQUIRE(test.n_cols == 2); + REQUIRE(test.n_rows == 4); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.tsv"); @@ -692,7 +690,7 @@ BOOST_AUTO_TEST_CASE(LoadTransposedTSVExtensionTest) /** * Make sure CSVs can be loaded in non-transposed form. */ -BOOST_AUTO_TEST_CASE(LoadNonTransposedCSVTest) +TEST_CASE("LoadNonTransposedCSVTest", "[LoadSaveTest]") { fstream f; f.open("test_file.csv", fstream::out); @@ -703,13 +701,13 @@ BOOST_AUTO_TEST_CASE(LoadNonTransposedCSVTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.csv", test, false, false) == true); + REQUIRE(data::Load("test_file.csv", test, false, false) == true); - BOOST_REQUIRE_EQUAL(test.n_cols, 4); - BOOST_REQUIRE_EQUAL(test.n_rows, 2); + REQUIRE(test.n_cols == 4); + REQUIRE(test.n_rows == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -718,24 +716,24 @@ BOOST_AUTO_TEST_CASE(LoadNonTransposedCSVTest) /** * Make sure CSVs can be saved in non-transposed form. */ -BOOST_AUTO_TEST_CASE(SaveNonTransposedCSVTest) +TEST_CASE("SaveNonTransposedCSVTest", "[LoadSaveTest]") { arma::mat test = "1 2;" "3 4;" "5 6;" "7 8;"; - BOOST_REQUIRE(data::Save("test_file.csv", test, false, false) == true); + REQUIRE(data::Save("test_file.csv", test, false, false) == true); // Load it in and make sure it is in the same. arma::mat test2; - BOOST_REQUIRE(data::Load("test_file.csv", test2, false, false) == true); + REQUIRE(data::Load("test_file.csv", test2, false, false) == true); - BOOST_REQUIRE_EQUAL(test2.n_rows, 4); - BOOST_REQUIRE_EQUAL(test2.n_cols, 2); + REQUIRE(test2.n_rows == 4); + REQUIRE(test2.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], test2[i], 1e-5); + REQUIRE(test[i] == Approx(test2[i]).epsilon(1e-7)); // Remove the file. remove("test_file.csv"); @@ -744,7 +742,7 @@ BOOST_AUTO_TEST_CASE(SaveNonTransposedCSVTest) /** * Make sure arma_ascii is loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadArmaASCIITest) +TEST_CASE("LoadArmaASCIITest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" @@ -752,15 +750,15 @@ BOOST_AUTO_TEST_CASE(LoadArmaASCIITest) "4 8;"; arma::mat testTrans = trans(test); - BOOST_REQUIRE(testTrans.save("test_file.txt", arma::arma_ascii)); + REQUIRE(testTrans.save("test_file.txt", arma::arma_ascii)); - BOOST_REQUIRE(data::Load("test_file.txt", test) == true); + REQUIRE(data::Load("test_file.txt", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.txt"); @@ -769,23 +767,23 @@ BOOST_AUTO_TEST_CASE(LoadArmaASCIITest) /** * Make sure a CSV is saved correctly. */ -BOOST_AUTO_TEST_CASE(SaveArmaASCIITest) +TEST_CASE("SaveArmaASCIITest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" "3 7;" "4 8;"; - BOOST_REQUIRE(data::Save("test_file.txt", test) == true); + REQUIRE(data::Save("test_file.txt", test) == true); // Load it in and make sure it is the same. - BOOST_REQUIRE(data::Load("test_file.txt", test) == true); + REQUIRE(data::Load("test_file.txt", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.txt"); @@ -794,7 +792,7 @@ BOOST_AUTO_TEST_CASE(SaveArmaASCIITest) /** * Make sure raw_ascii is loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadRawASCIITest) +TEST_CASE("LoadRawASCIITest", "[LoadSaveTest]") { fstream f; f.open("test_file.txt", fstream::out); @@ -805,13 +803,13 @@ BOOST_AUTO_TEST_CASE(LoadRawASCIITest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.txt", test) == true); + REQUIRE(data::Load("test_file.txt", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.txt"); @@ -820,7 +818,7 @@ BOOST_AUTO_TEST_CASE(LoadRawASCIITest) /** * Make sure CSV is loaded correctly as .txt. */ -BOOST_AUTO_TEST_CASE(LoadCSVTxtTest) +TEST_CASE("LoadCSVTxtTest", "[LoadSaveTest]") { fstream f; f.open("test_file.txt", fstream::out); @@ -831,13 +829,13 @@ BOOST_AUTO_TEST_CASE(LoadCSVTxtTest) f.close(); arma::mat test; - BOOST_REQUIRE(data::Load("test_file.txt", test) == true); + REQUIRE(data::Load("test_file.txt", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.txt"); @@ -846,7 +844,7 @@ BOOST_AUTO_TEST_CASE(LoadCSVTxtTest) /** * Make sure arma_binary is loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadArmaBinaryTest) +TEST_CASE("LoadArmaBinaryTest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" @@ -854,17 +852,17 @@ BOOST_AUTO_TEST_CASE(LoadArmaBinaryTest) "4 8;"; arma::mat testTrans = trans(test); - BOOST_REQUIRE(testTrans.quiet_save("test_file.bin", arma::arma_binary) + REQUIRE(testTrans.quiet_save("test_file.bin", arma::arma_binary) == true); // Now reload through our interface. - BOOST_REQUIRE(data::Load("test_file.bin", test) == true); + REQUIRE(data::Load("test_file.bin", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.bin"); @@ -873,22 +871,22 @@ BOOST_AUTO_TEST_CASE(LoadArmaBinaryTest) /** * Make sure arma_binary is saved correctly. */ -BOOST_AUTO_TEST_CASE(SaveArmaBinaryTest) +TEST_CASE("SaveArmaBinaryTest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" "3 7;" "4 8;"; - BOOST_REQUIRE(data::Save("test_file.bin", test) == true); + REQUIRE(data::Save("test_file.bin", test) == true); - BOOST_REQUIRE(data::Load("test_file.bin", test) == true); + REQUIRE(data::Load("test_file.bin", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.bin"); @@ -897,7 +895,7 @@ BOOST_AUTO_TEST_CASE(SaveArmaBinaryTest) /** * Make sure raw_binary is loaded correctly. */ -BOOST_AUTO_TEST_CASE(LoadRawBinaryTest) +TEST_CASE("LoadRawBinaryTest", "[LoadSaveTest]") { arma::mat test = "1 2;" "3 4;" @@ -905,17 +903,17 @@ BOOST_AUTO_TEST_CASE(LoadRawBinaryTest) "7 8;"; arma::mat testTrans = trans(test); - BOOST_REQUIRE(testTrans.quiet_save("test_file.bin", arma::raw_binary) + REQUIRE(testTrans.quiet_save("test_file.bin", arma::raw_binary) == true); // Now reload through our interface. - BOOST_REQUIRE(data::Load("test_file.bin", test) == true); + REQUIRE(data::Load("test_file.bin", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 1); - BOOST_REQUIRE_EQUAL(test.n_cols, 8); + REQUIRE(test.n_rows == 1); + REQUIRE(test.n_cols == 8); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.bin"); @@ -924,7 +922,7 @@ BOOST_AUTO_TEST_CASE(LoadRawBinaryTest) /** * Make sure load as PGM is successful. */ -BOOST_AUTO_TEST_CASE(LoadPGMBinaryTest) +TEST_CASE("LoadPGMBinaryTest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" @@ -932,17 +930,17 @@ BOOST_AUTO_TEST_CASE(LoadPGMBinaryTest) "4 8;"; arma::mat testTrans = trans(test); - BOOST_REQUIRE(testTrans.quiet_save("test_file.pgm", arma::pgm_binary) + REQUIRE(testTrans.quiet_save("test_file.pgm", arma::pgm_binary) == true); // Now reload through our interface. - BOOST_REQUIRE(data::Load("test_file.pgm", test) == true); + REQUIRE(data::Load("test_file.pgm", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.pgm"); @@ -951,23 +949,23 @@ BOOST_AUTO_TEST_CASE(LoadPGMBinaryTest) /** * Make sure save as PGM is successful. */ -BOOST_AUTO_TEST_CASE(SavePGMBinaryTest) +TEST_CASE("SavePGMBinaryTest", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" "3 7;" "4 8;"; - BOOST_REQUIRE(data::Save("test_file.pgm", test) == true); + REQUIRE(data::Save("test_file.pgm", test) == true); // Now reload through our interface. - BOOST_REQUIRE(data::Load("test_file.pgm", test) == true); + REQUIRE(data::Load("test_file.pgm", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Remove the file. remove("test_file.pgm"); @@ -977,55 +975,55 @@ BOOST_AUTO_TEST_CASE(SavePGMBinaryTest) /** * Make sure load as HDF5 is successful. */ -BOOST_AUTO_TEST_CASE(LoadHDF5Test) +TEST_CASE("LoadHDF5Test", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" "3 7;" "4 8;"; arma::mat testTrans = trans(test); - BOOST_REQUIRE(testTrans.quiet_save("test_file.h5", arma::hdf5_binary) + REQUIRE(testTrans.quiet_save("test_file.h5", arma::hdf5_binary) == true); - BOOST_REQUIRE(testTrans.quiet_save("test_file.hdf5", arma::hdf5_binary) + REQUIRE(testTrans.quiet_save("test_file.hdf5", arma::hdf5_binary) == true); - BOOST_REQUIRE(testTrans.quiet_save("test_file.hdf", arma::hdf5_binary) + REQUIRE(testTrans.quiet_save("test_file.hdf", arma::hdf5_binary) == true); - BOOST_REQUIRE(testTrans.quiet_save("test_file.he5", arma::hdf5_binary) + REQUIRE(testTrans.quiet_save("test_file.he5", arma::hdf5_binary) == true); // Now reload through our interface. - BOOST_REQUIRE(data::Load("test_file.h5", test) == true); + REQUIRE(data::Load("test_file.h5", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Make sure the other extensions work too. - BOOST_REQUIRE(data::Load("test_file.hdf5", test) == true); + REQUIRE(data::Load("test_file.hdf5", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); - BOOST_REQUIRE(data::Load("test_file.hdf", test) == true); + REQUIRE(data::Load("test_file.hdf", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); - BOOST_REQUIRE(data::Load("test_file.he5", test) == true); + REQUIRE(data::Load("test_file.he5", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); remove("test_file.h5"); remove("test_file.hdf"); @@ -1036,50 +1034,50 @@ BOOST_AUTO_TEST_CASE(LoadHDF5Test) /** * Make sure save as HDF5 is successful. */ -BOOST_AUTO_TEST_CASE(SaveHDF5Test) +TEST_CASE("SaveHDF5Test", "[LoadSaveTest]") { arma::mat test = "1 5;" "2 6;" "3 7;" "4 8;"; - BOOST_REQUIRE(data::Save("test_file.h5", test) == true); - BOOST_REQUIRE(data::Save("test_file.hdf5", test) == true); - BOOST_REQUIRE(data::Save("test_file.hdf", test) == true); - BOOST_REQUIRE(data::Save("test_file.he5", test) == true); + REQUIRE(data::Save("test_file.h5", test) == true); + REQUIRE(data::Save("test_file.hdf5", test) == true); + REQUIRE(data::Save("test_file.hdf", test) == true); + REQUIRE(data::Save("test_file.he5", test) == true); // Now load them all and verify they were saved okay. - BOOST_REQUIRE(data::Load("test_file.h5", test) == true); + REQUIRE(data::Load("test_file.h5", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); // Make sure the other extensions work too. - BOOST_REQUIRE(data::Load("test_file.hdf5", test) == true); + REQUIRE(data::Load("test_file.hdf5", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); - BOOST_REQUIRE(data::Load("test_file.hdf", test) == true); + REQUIRE(data::Load("test_file.hdf", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); - BOOST_REQUIRE(data::Load("test_file.he5", test) == true); + REQUIRE(data::Load("test_file.he5", test) == true); - BOOST_REQUIRE_EQUAL(test.n_rows, 4); - BOOST_REQUIRE_EQUAL(test.n_cols, 2); + REQUIRE(test.n_rows == 4); + REQUIRE(test.n_cols == 2); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(test[i], (double) (i + 1), 1e-5); + REQUIRE(test[i] == Approx((double) (i + 1)).epsilon(1e-7)); remove("test_file.h5"); remove("test_file.hdf"); @@ -1092,7 +1090,7 @@ BOOST_AUTO_TEST_CASE(SaveHDF5Test) /** * Test one hot encoding. */ -BOOST_AUTO_TEST_CASE(OneHotEncodingTest) +TEST_CASE("OneHotEncodingTest", "[LoadSaveTest]") { arma::Mat matrix; matrix = "1 0;" @@ -1108,15 +1106,15 @@ BOOST_AUTO_TEST_CASE(OneHotEncodingTest) arma::irowvec labels("-1 1 -1 -1 -1 -1 1 -1"); data::OneHotEncoding(labels, output); - BOOST_REQUIRE_EQUAL(matrix.n_cols, output.n_cols); - BOOST_REQUIRE_EQUAL(matrix.n_rows, output.n_rows); + REQUIRE(matrix.n_cols == output.n_cols); + REQUIRE(matrix.n_rows == output.n_rows); CheckMatrices(output, matrix); } /** * Test normalization of labels. */ -BOOST_AUTO_TEST_CASE(NormalizeLabelSmallDatasetTest) +TEST_CASE("NormalizeLabelSmallDatasetTest", "[LoadSaveTest]") { arma::irowvec labels("-1 1 1 -1 -1 -1 1 1"); arma::Row newLabels; @@ -1124,30 +1122,30 @@ BOOST_AUTO_TEST_CASE(NormalizeLabelSmallDatasetTest) data::NormalizeLabels(labels, newLabels, mappings); - BOOST_REQUIRE_EQUAL(mappings[0], -1); - BOOST_REQUIRE_EQUAL(mappings[1], 1); + REQUIRE(mappings[0] == -1); + REQUIRE(mappings[1] == 1); - BOOST_REQUIRE_EQUAL(newLabels[0], 0); - BOOST_REQUIRE_EQUAL(newLabels[1], 1); - BOOST_REQUIRE_EQUAL(newLabels[2], 1); - BOOST_REQUIRE_EQUAL(newLabels[3], 0); - BOOST_REQUIRE_EQUAL(newLabels[4], 0); - BOOST_REQUIRE_EQUAL(newLabels[5], 0); - BOOST_REQUIRE_EQUAL(newLabels[6], 1); - BOOST_REQUIRE_EQUAL(newLabels[7], 1); + REQUIRE(newLabels[0] == 0); + REQUIRE(newLabels[1] == 1); + REQUIRE(newLabels[2] == 1); + REQUIRE(newLabels[3] == 0); + REQUIRE(newLabels[4] == 0); + REQUIRE(newLabels[5] == 0); + REQUIRE(newLabels[6] == 1); + REQUIRE(newLabels[7] == 1); arma::irowvec revertedLabels; data::RevertLabels(newLabels, mappings, revertedLabels); for (size_t i = 0; i < labels.n_elem; ++i) - BOOST_REQUIRE_EQUAL(labels[i], revertedLabels[i]); + REQUIRE(labels[i] == revertedLabels[i]); } /** * Harder label normalization test. */ -BOOST_AUTO_TEST_CASE(NormalizeLabelTest) +TEST_CASE("NormalizeLabelTest", "[LoadSaveTest]") { arma::rowvec randLabels(5000); for (size_t i = 0; i < 5000; ++i) @@ -1164,7 +1162,7 @@ BOOST_AUTO_TEST_CASE(NormalizeLabelTest) data::RevertLabels(newLabels, mappings, revertedLabels); for (size_t i = 0; i < 5000; ++i) - BOOST_REQUIRE_EQUAL(randLabels[i], revertedLabels[i]); + REQUIRE(randLabels[i] == revertedLabels[i]); } // Test structures. @@ -1209,81 +1207,81 @@ class Test /** * Make sure we can load and save. */ -BOOST_AUTO_TEST_CASE(LoadBinaryTest) +TEST_CASE("LoadBinaryTest", "[LoadSaveTest]") { Test x(10, 12); - BOOST_REQUIRE_EQUAL(data::Save("test.bin", "x", x, false), true); + REQUIRE(data::Save("test.bin", "x", x, false) == true); // Now reload. Test y(11, 14); - BOOST_REQUIRE_EQUAL(data::Load("test.bin", "x", y, false), true); + REQUIRE(data::Load("test.bin", "x", y, false) == true); - BOOST_REQUIRE_EQUAL(y.x, x.x); - BOOST_REQUIRE_EQUAL(y.y, x.y); - BOOST_REQUIRE_EQUAL(y.ina.c, x.ina.c); - BOOST_REQUIRE_EQUAL(y.ina.s, x.ina.s); - BOOST_REQUIRE_EQUAL(y.inb.c, x.inb.c); - BOOST_REQUIRE_EQUAL(y.inb.s, x.inb.s); + REQUIRE(y.x == x.x); + REQUIRE(y.y == x.y); + REQUIRE(y.ina.c == x.ina.c); + REQUIRE(y.ina.s == x.ina.s); + REQUIRE(y.inb.c == x.inb.c); + REQUIRE(y.inb.s == x.inb.s); } /** * Make sure we can load and save. */ -BOOST_AUTO_TEST_CASE(LoadXMLTest) +TEST_CASE("LoadXMLTest", "[LoadSaveTest]") { Test x(10, 12); - BOOST_REQUIRE_EQUAL(data::Save("test.xml", "x", x, false), true); + REQUIRE(data::Save("test.xml", "x", x, false) == true); // Now reload. Test y(11, 14); - BOOST_REQUIRE_EQUAL(data::Load("test.xml", "x", y, false), true); + REQUIRE(data::Load("test.xml", "x", y, false) == true); - BOOST_REQUIRE_EQUAL(y.x, x.x); - BOOST_REQUIRE_EQUAL(y.y, x.y); - BOOST_REQUIRE_EQUAL(y.ina.c, x.ina.c); - BOOST_REQUIRE_EQUAL(y.ina.s, x.ina.s); - BOOST_REQUIRE_EQUAL(y.inb.c, x.inb.c); - BOOST_REQUIRE_EQUAL(y.inb.s, x.inb.s); + REQUIRE(y.x == x.x); + REQUIRE(y.y == x.y); + REQUIRE(y.ina.c == x.ina.c); + REQUIRE(y.ina.s == x.ina.s); + REQUIRE(y.inb.c == x.inb.c); + REQUIRE(y.inb.s == x.inb.s); } /** * Make sure we can load and save. */ -BOOST_AUTO_TEST_CASE(LoadTextTest) +TEST_CASE("LoadTextTest", "[LoadSaveTest]") { Test x(10, 12); - BOOST_REQUIRE_EQUAL(data::Save("test.txt", "x", x, false), true); + REQUIRE(data::Save("test.txt", "x", x, false) == true); // Now reload. Test y(11, 14); - BOOST_REQUIRE_EQUAL(data::Load("test.txt", "x", y, false), true); + REQUIRE(data::Load("test.txt", "x", y, false) == true); - BOOST_REQUIRE_EQUAL(y.x, x.x); - BOOST_REQUIRE_EQUAL(y.y, x.y); - BOOST_REQUIRE_EQUAL(y.ina.c, x.ina.c); - BOOST_REQUIRE_EQUAL(y.ina.s, x.ina.s); - BOOST_REQUIRE_EQUAL(y.inb.c, x.inb.c); - BOOST_REQUIRE_EQUAL(y.inb.s, x.inb.s); + REQUIRE(y.x == x.x); + REQUIRE(y.y == x.y); + REQUIRE(y.ina.c == x.ina.c); + REQUIRE(y.ina.s == x.ina.s); + REQUIRE(y.inb.c == x.inb.c); + REQUIRE(y.inb.s == x.inb.s); } /** * Test DatasetInfo by making a map for a dimension. */ -BOOST_AUTO_TEST_CASE(DatasetInfoTest) +TEST_CASE("DatasetInfoTest", "[LoadSaveTest]") { DatasetInfo di(100); // Do all types default to numeric? for (size_t i = 0; i < 100; ++i) { - BOOST_REQUIRE(di.Type(i) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(di.NumMappings(i), 0); + REQUIRE(di.Type(i) == Datatype::numeric); + REQUIRE(di.NumMappings(i) == 0); } // Okay. Add some mappings for dimension 3. @@ -1291,22 +1289,22 @@ BOOST_AUTO_TEST_CASE(DatasetInfoTest) const size_t second = di.MapString("test_mapping_2", 3); const size_t third = di.MapString("test_mapping_3", 3); - BOOST_REQUIRE_EQUAL(first, 0); - BOOST_REQUIRE_EQUAL(second, 1); - BOOST_REQUIRE_EQUAL(third, 2); + REQUIRE(first == 0); + REQUIRE(second == 1); + REQUIRE(third == 2); // Now dimension 3 should be categorical. for (size_t i = 0; i < 100; ++i) { if (i == 3) { - BOOST_REQUIRE(di.Type(i) == Datatype::categorical); - BOOST_REQUIRE_EQUAL(di.NumMappings(i), 3); + REQUIRE(di.Type(i) == Datatype::categorical); + REQUIRE(di.NumMappings(i) == 3); } else { - BOOST_REQUIRE(di.Type(i) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(di.NumMappings(i), 0); + REQUIRE(di.Type(i) == Datatype::numeric); + REQUIRE(di.NumMappings(i) == 0); } } @@ -1315,15 +1313,15 @@ BOOST_AUTO_TEST_CASE(DatasetInfoTest) const string& strSecond = di.UnmapString(second, 3); const string& strThird = di.UnmapString(third, 3); - BOOST_REQUIRE_EQUAL(strFirst, "test_mapping_1"); - BOOST_REQUIRE_EQUAL(strSecond, "test_mapping_2"); - BOOST_REQUIRE_EQUAL(strThird, "test_mapping_3"); + REQUIRE(strFirst == "test_mapping_1"); + REQUIRE(strSecond == "test_mapping_2"); + REQUIRE(strThird == "test_mapping_3"); } /** * Test loading regular CSV with DatasetInfo. Everything should be numeric. */ -BOOST_AUTO_TEST_CASE(RegularCSVDatasetInfoLoad) +TEST_CASE("RegularCSVDatasetInfoLoad", "[LoadSaveTest]") { vector testFiles; testFiles.push_back("fake.csv"); @@ -1342,20 +1340,20 @@ BOOST_AUTO_TEST_CASE(RegularCSVDatasetInfoLoad) data::Load(testFiles[i], two, info); // Check that the matrices contain the same information. - BOOST_REQUIRE_EQUAL(one.n_elem, two.n_elem); - BOOST_REQUIRE_EQUAL(one.n_rows, two.n_rows); - BOOST_REQUIRE_EQUAL(one.n_cols, two.n_cols); + REQUIRE(one.n_elem == two.n_elem); + REQUIRE(one.n_rows == two.n_rows); + REQUIRE(one.n_cols == two.n_cols); for (size_t i = 0; i < one.n_elem; ++i) { if (std::abs(one[i]) < 1e-8) - BOOST_REQUIRE_SMALL(two[i], 1e-8); + REQUIRE(two[i] == Approx(.0).margin(1e-10)); else - BOOST_REQUIRE_CLOSE(one[i], two[i], 1e-8); + REQUIRE(one[i] == Approx(two[i]).epsilon(1e-7)); } // Check that all dimensions are numeric. for (size_t i = 0; i < two.n_rows; ++i) - BOOST_REQUIRE(info.Type(i) == Datatype::numeric); + REQUIRE(info.Type(i) == Datatype::numeric); } } @@ -1363,7 +1361,7 @@ BOOST_AUTO_TEST_CASE(RegularCSVDatasetInfoLoad) * Test non-transposed loading of regular CSVs with DatasetInfo. Everything * should be numeric. */ -BOOST_AUTO_TEST_CASE(NontransposedCSVDatasetInfoLoad) +TEST_CASE("NontransposedCSVDatasetInfoLoad", "[LoadSaveTest]") { vector testFiles; testFiles.push_back("fake.csv"); @@ -1382,27 +1380,27 @@ BOOST_AUTO_TEST_CASE(NontransposedCSVDatasetInfoLoad) data::Load(testFiles[i], two, info, true, false); // Check that the matrices contain the same information. - BOOST_REQUIRE_EQUAL(one.n_elem, two.n_elem); - BOOST_REQUIRE_EQUAL(one.n_rows, two.n_rows); - BOOST_REQUIRE_EQUAL(one.n_cols, two.n_cols); + REQUIRE(one.n_elem == two.n_elem); + REQUIRE(one.n_rows == two.n_rows); + REQUIRE(one.n_cols == two.n_cols); for (size_t i = 0; i < one.n_elem; ++i) { if (std::abs(one[i]) < 1e-8) - BOOST_REQUIRE_SMALL(two[i], 1e-8); + REQUIRE(two[i] == Approx(.0).margin(1e-10)); else - BOOST_REQUIRE_CLOSE(one[i], two[i], 1e-8); + REQUIRE(one[i] == Approx(two[i]).epsilon(1e-7)); } // Check that all dimensions are numeric. for (size_t i = 0; i < two.n_rows; ++i) - BOOST_REQUIRE(info.Type(i) == Datatype::numeric); + REQUIRE(info.Type(i) == Datatype::numeric); } } /** * Create a file with a categorical string feature, then load it. */ -BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest00) +TEST_CASE("CategoricalCSVLoadTest00", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1420,49 +1418,49 @@ BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest00) DatasetInfo info; data::Load("test.csv", matrix, info); - BOOST_REQUIRE_EQUAL(matrix.n_cols, 7); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 3); + REQUIRE(matrix.n_cols == 7); + REQUIRE(matrix.n_rows == 3); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 2); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 3); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 4); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 5); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 6); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 2); - BOOST_REQUIRE_EQUAL(matrix(0, 3), 7); - BOOST_REQUIRE_EQUAL(matrix(1, 3), 8); - BOOST_REQUIRE_EQUAL(matrix(2, 3), 3); - BOOST_REQUIRE_EQUAL(matrix(0, 4), 9); - BOOST_REQUIRE_EQUAL(matrix(1, 4), 10); - BOOST_REQUIRE_EQUAL(matrix(2, 4), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 5), 11); - BOOST_REQUIRE_EQUAL(matrix(1, 5), 12); - BOOST_REQUIRE_EQUAL(matrix(2, 5), 3); - BOOST_REQUIRE_EQUAL(matrix(0, 6), 13); - BOOST_REQUIRE_EQUAL(matrix(1, 6), 14); - BOOST_REQUIRE_EQUAL(matrix(2, 6), 3); + REQUIRE(matrix(0, 0) == 1); + REQUIRE(matrix(1, 0) == 2); + REQUIRE(matrix(2, 0) == 0); + REQUIRE(matrix(0, 1) == 3); + REQUIRE(matrix(1, 1) == 4); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(0, 2) == 5); + REQUIRE(matrix(1, 2) == 6); + REQUIRE(matrix(2, 2) == 2); + REQUIRE(matrix(0, 3) == 7); + REQUIRE(matrix(1, 3) == 8); + REQUIRE(matrix(2, 3) == 3); + REQUIRE(matrix(0, 4) == 9); + REQUIRE(matrix(1, 4) == 10); + REQUIRE(matrix(2, 4) == 0); + REQUIRE(matrix(0, 5) == 11); + REQUIRE(matrix(1, 5) == 12); + REQUIRE(matrix(2, 5) == 3); + REQUIRE(matrix(0, 6) == 13); + REQUIRE(matrix(1, 6) == 14); + REQUIRE(matrix(2, 6) == 3); - BOOST_REQUIRE(info.Type(0) == Datatype::numeric); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::categorical); + REQUIRE(info.Type(0) == Datatype::numeric); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::categorical); - BOOST_REQUIRE_EQUAL(info.MapString("hello", 2), 0); - BOOST_REQUIRE_EQUAL(info.MapString("goodbye", 2), 1); - BOOST_REQUIRE_EQUAL(info.MapString("coffee", 2), 2); - BOOST_REQUIRE_EQUAL(info.MapString("confusion", 2), 3); + REQUIRE(info.MapString("hello", 2) == 0); + REQUIRE(info.MapString("goodbye", 2) == 1); + REQUIRE(info.MapString("coffee", 2) == 2); + REQUIRE(info.MapString("confusion", 2) == 3); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 2), "hello"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 2), "goodbye"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 2), "coffee"); - BOOST_REQUIRE_EQUAL(info.UnmapString(3, 2), "confusion"); + REQUIRE(info.UnmapString(0, 2) == "hello"); + REQUIRE(info.UnmapString(1, 2) == "goodbye"); + REQUIRE(info.UnmapString(2, 2) == "coffee"); + REQUIRE(info.UnmapString(3, 2) == "confusion"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest01) +TEST_CASE("CategoricalCSVLoadTest01", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1477,37 +1475,37 @@ BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest01) DatasetInfo info; data::Load("test.csv", matrix, info, true); - BOOST_REQUIRE_EQUAL(matrix.n_cols, 4); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 3); + REQUIRE(matrix.n_cols == 4); + REQUIRE(matrix.n_rows == 3); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 3), 0); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 3), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 3), 1); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 0); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(0, 3) == 0); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(1, 3) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(2, 3) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE(info.Type(3) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(3) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("1", 0), 0); - BOOST_REQUIRE_EQUAL(info.MapString("", 0), 1); + REQUIRE(info.MapString("1", 0) == 0); + REQUIRE(info.MapString("", 0) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 0), "1"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 0), ""); + REQUIRE(info.UnmapString(0, 0) == "1"); + REQUIRE(info.UnmapString(1, 0) == ""); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest02) +TEST_CASE("CategoricalCSVLoadTest02", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1522,36 +1520,36 @@ BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest02) DatasetInfo info; data::Load("test.csv", matrix, info, true); - BOOST_REQUIRE_EQUAL(matrix.n_cols, 4); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 3); + REQUIRE(matrix.n_cols == 4); + REQUIRE(matrix.n_rows == 3); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 3), 0); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 3), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 3), 1); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 0); + REQUIRE(matrix(0, 3) == 0); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(1, 3) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(2, 3) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("", 0), 1); - BOOST_REQUIRE_EQUAL(info.MapString("1", 0), 0); + REQUIRE(info.MapString("", 0) == 1); + REQUIRE(info.MapString("1", 0) == 0); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 0), "1"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 0), ""); + REQUIRE(info.UnmapString(0, 0) == "1"); + REQUIRE(info.UnmapString(1, 0) == ""); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest03) +TEST_CASE("CategoricalCSVLoadTest03", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1566,36 +1564,36 @@ BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest03) DatasetInfo info; data::Load("test.csv", matrix, info, true); - BOOST_REQUIRE_EQUAL(matrix.n_cols, 4); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 3); + REQUIRE(matrix.n_cols == 4); + REQUIRE(matrix.n_rows == 3); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 3), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 3), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 3), 1); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(0, 3) == 1); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(1, 3) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(2, 3) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("", 0), 0); - BOOST_REQUIRE_EQUAL(info.MapString("1", 0), 1); + REQUIRE(info.MapString("", 0) == 0); + REQUIRE(info.MapString("1", 0) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 0), ""); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 0), "1"); + REQUIRE(info.UnmapString(0, 0) == ""); + REQUIRE(info.UnmapString(1, 0) == "1"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest04) +TEST_CASE("CategoricalCSVLoadTest04", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1610,36 +1608,36 @@ BOOST_AUTO_TEST_CASE(CategoricalCSVLoadTest04) DatasetInfo info; data::Load("test.csv", matrix, info, true); - BOOST_REQUIRE_EQUAL(matrix.n_cols, 4); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 3); + REQUIRE(matrix.n_cols == 4); + REQUIRE(matrix.n_rows == 3); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 3), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 3), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 3), 1); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(0, 3) == 1); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(1, 3) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(2, 3) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("200-DM", 0), 0); - BOOST_REQUIRE_EQUAL(info.MapString("1", 0), 1); + REQUIRE(info.MapString("200-DM", 0) == 0); + REQUIRE(info.MapString("1", 0) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 0), "200-DM"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 0), "1"); + REQUIRE(info.UnmapString(0, 0) == "200-DM"); + REQUIRE(info.UnmapString(1, 0) == "1"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest00) +TEST_CASE("CategoricalNontransposedCSVLoadTest00", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1657,81 +1655,81 @@ BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest00) DatasetInfo info; data::Load("test.csv", matrix, info, true, false); // No transpose. - BOOST_REQUIRE_EQUAL(matrix.n_cols, 3); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 7); + REQUIRE(matrix.n_cols == 3); + REQUIRE(matrix.n_rows == 7); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 2); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 2); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 2); - BOOST_REQUIRE_EQUAL(matrix(3, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(3, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 2), 2); - BOOST_REQUIRE_EQUAL(matrix(4, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(4, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(4, 2), 2); - BOOST_REQUIRE_EQUAL(matrix(5, 0), 11); - BOOST_REQUIRE_EQUAL(matrix(5, 1), 12); - BOOST_REQUIRE_EQUAL(matrix(5, 2), 15); - BOOST_REQUIRE_EQUAL(matrix(6, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(6, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(6, 2), 2); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 2); + REQUIRE(matrix(1, 0) == 0); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 2); + REQUIRE(matrix(2, 0) == 0); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 2); + REQUIRE(matrix(3, 0) == 0); + REQUIRE(matrix(3, 1) == 1); + REQUIRE(matrix(3, 2) == 2); + REQUIRE(matrix(4, 0) == 0); + REQUIRE(matrix(4, 1) == 1); + REQUIRE(matrix(4, 2) == 2); + REQUIRE(matrix(5, 0) == 11); + REQUIRE(matrix(5, 1) == 12); + REQUIRE(matrix(5, 2) == 15); + REQUIRE(matrix(6, 0) == 0); + REQUIRE(matrix(6, 1) == 1); + REQUIRE(matrix(6, 2) == 2); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::categorical); - BOOST_REQUIRE(info.Type(2) == Datatype::categorical); - BOOST_REQUIRE(info.Type(3) == Datatype::categorical); - BOOST_REQUIRE(info.Type(4) == Datatype::categorical); - BOOST_REQUIRE(info.Type(5) == Datatype::numeric); - BOOST_REQUIRE(info.Type(6) == Datatype::categorical); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::categorical); + REQUIRE(info.Type(2) == Datatype::categorical); + REQUIRE(info.Type(3) == Datatype::categorical); + REQUIRE(info.Type(4) == Datatype::categorical); + REQUIRE(info.Type(5) == Datatype::numeric); + REQUIRE(info.Type(6) == Datatype::categorical); - BOOST_REQUIRE_EQUAL(info.MapString("1", 0), 0); - BOOST_REQUIRE_EQUAL(info.MapString("2", 0), 1); - BOOST_REQUIRE_EQUAL(info.MapString("hello", 0), 2); - BOOST_REQUIRE_EQUAL(info.MapString("3", 1), 0); - BOOST_REQUIRE_EQUAL(info.MapString("4", 1), 1); - BOOST_REQUIRE_EQUAL(info.MapString("goodbye", 1), 2); - BOOST_REQUIRE_EQUAL(info.MapString("5", 2), 0); - BOOST_REQUIRE_EQUAL(info.MapString("6", 2), 1); - BOOST_REQUIRE_EQUAL(info.MapString("coffee", 2), 2); - BOOST_REQUIRE_EQUAL(info.MapString("7", 3), 0); - BOOST_REQUIRE_EQUAL(info.MapString("8", 3), 1); - BOOST_REQUIRE_EQUAL(info.MapString("confusion", 3), 2); - BOOST_REQUIRE_EQUAL(info.MapString("9", 4), 0); - BOOST_REQUIRE_EQUAL(info.MapString("10", 4), 1); - BOOST_REQUIRE_EQUAL(info.MapString("hello", 4), 2); - BOOST_REQUIRE_EQUAL(info.MapString("13", 6), 0); - BOOST_REQUIRE_EQUAL(info.MapString("14", 6), 1); - BOOST_REQUIRE_EQUAL(info.MapString("confusion", 6), 2); + REQUIRE(info.MapString("1", 0) == 0); + REQUIRE(info.MapString("2", 0) == 1); + REQUIRE(info.MapString("hello", 0) == 2); + REQUIRE(info.MapString("3", 1) == 0); + REQUIRE(info.MapString("4", 1) == 1); + REQUIRE(info.MapString("goodbye", 1) == 2); + REQUIRE(info.MapString("5", 2) == 0); + REQUIRE(info.MapString("6", 2) == 1); + REQUIRE(info.MapString("coffee", 2) == 2); + REQUIRE(info.MapString("7", 3) == 0); + REQUIRE(info.MapString("8", 3) == 1); + REQUIRE(info.MapString("confusion", 3) == 2); + REQUIRE(info.MapString("9", 4) == 0); + REQUIRE(info.MapString("10", 4) == 1); + REQUIRE(info.MapString("hello", 4) == 2); + REQUIRE(info.MapString("13", 6) == 0); + REQUIRE(info.MapString("14", 6) == 1); + REQUIRE(info.MapString("confusion", 6) == 2); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 0), "1"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 0), "2"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 0), "hello"); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 1), "3"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 1), "4"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 1), "goodbye"); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 2), "5"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 2), "6"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 2), "coffee"); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 3), "7"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 3), "8"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 3), "confusion"); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 4), "9"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 4), "10"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 4), "hello"); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 6), "13"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 6), "14"); - BOOST_REQUIRE_EQUAL(info.UnmapString(2, 6), "confusion"); + REQUIRE(info.UnmapString(0, 0) == "1"); + REQUIRE(info.UnmapString(1, 0) == "2"); + REQUIRE(info.UnmapString(2, 0) == "hello"); + REQUIRE(info.UnmapString(0, 1) == "3"); + REQUIRE(info.UnmapString(1, 1) == "4"); + REQUIRE(info.UnmapString(2, 1) == "goodbye"); + REQUIRE(info.UnmapString(0, 2) == "5"); + REQUIRE(info.UnmapString(1, 2) == "6"); + REQUIRE(info.UnmapString(2, 2) == "coffee"); + REQUIRE(info.UnmapString(0, 3) == "7"); + REQUIRE(info.UnmapString(1, 3) == "8"); + REQUIRE(info.UnmapString(2, 3) == "confusion"); + REQUIRE(info.UnmapString(0, 4) == "9"); + REQUIRE(info.UnmapString(1, 4) == "10"); + REQUIRE(info.UnmapString(2, 4) == "hello"); + REQUIRE(info.UnmapString(0, 6) == "13"); + REQUIRE(info.UnmapString(1, 6) == "14"); + REQUIRE(info.UnmapString(2, 6) == "confusion"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest01) +TEST_CASE("CategoricalNontransposedCSVLoadTest01", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1746,37 +1744,37 @@ BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest01) DatasetInfo info; data::Load("test.csv", matrix, info, true, false); // No transpose. - BOOST_REQUIRE_EQUAL(matrix.n_cols, 3); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 4); + REQUIRE(matrix.n_cols == 3); + REQUIRE(matrix.n_rows == 4); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 2), 1); + REQUIRE(matrix(0, 0) == 1); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(2, 0) == 0); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(3, 0) == 1); + REQUIRE(matrix(3, 1) == 1); + REQUIRE(matrix(3, 2) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::numeric); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::categorical); - BOOST_REQUIRE(info.Type(3) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::numeric); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::categorical); + REQUIRE(info.Type(3) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("", 2), 0); - BOOST_REQUIRE_EQUAL(info.MapString("1", 2), 1); + REQUIRE(info.MapString("", 2) == 0); + REQUIRE(info.MapString("1", 2) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 2), ""); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 2), "1"); + REQUIRE(info.UnmapString(0, 2) == ""); + REQUIRE(info.UnmapString(1, 2) == "1"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest02) +TEST_CASE("CategoricalNontransposedCSVLoadTest02", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1791,37 +1789,37 @@ BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest02) DatasetInfo info; data::Load("test.csv", matrix, info, true, false); // No transpose. - BOOST_REQUIRE_EQUAL(matrix.n_cols, 3); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 4); + REQUIRE(matrix.n_cols == 3); + REQUIRE(matrix.n_rows == 4); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 2), 1); + REQUIRE(matrix(0, 0) == 1); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(1, 0) == 0); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(3, 0) == 1); + REQUIRE(matrix(3, 1) == 1); + REQUIRE(matrix(3, 2) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::numeric); - BOOST_REQUIRE(info.Type(1) == Datatype::categorical); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE(info.Type(3) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::numeric); + REQUIRE(info.Type(1) == Datatype::categorical); + REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(3) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("", 1), 0); - BOOST_REQUIRE_EQUAL(info.MapString("1", 1), 1); + REQUIRE(info.MapString("", 1) == 0); + REQUIRE(info.MapString("1", 1) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 1), ""); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 1), "1"); + REQUIRE(info.UnmapString(0, 1) == ""); + REQUIRE(info.UnmapString(1, 1) == "1"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest03) +TEST_CASE("CategoricalNontransposedCSVLoadTest03", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1836,37 +1834,37 @@ BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest03) DatasetInfo info; data::Load("test.csv", matrix, info, true, false); // No transpose. - BOOST_REQUIRE_EQUAL(matrix.n_cols, 3); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 4); + REQUIRE(matrix.n_cols == 3); + REQUIRE(matrix.n_rows == 4); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 2), 1); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(3, 0) == 1); + REQUIRE(matrix(3, 1) == 1); + REQUIRE(matrix(3, 2) == 1); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE(info.Type(3) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(3) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(info.MapString("", 1), 0); - BOOST_REQUIRE_EQUAL(info.MapString("1", 1), 1); + REQUIRE(info.MapString("", 1) == 0); + REQUIRE(info.MapString("1", 1) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 1), ""); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 1), "1"); + REQUIRE(info.UnmapString(0, 1) == ""); + REQUIRE(info.UnmapString(1, 1) == "1"); remove("test.csv"); } -BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest04) +TEST_CASE("CategoricalNontransposedCSVLoadTest04", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1881,32 +1879,32 @@ BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest04) DatasetInfo info; data::Load("test.csv", matrix, info, true, false); // No transpose. - BOOST_REQUIRE_EQUAL(matrix.n_cols, 3); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 4); + REQUIRE(matrix.n_cols == 3); + REQUIRE(matrix.n_rows == 4); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE(info.Type(3) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(3) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(matrix(0, 0), 0); - BOOST_REQUIRE_EQUAL(matrix(0, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(0, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(1, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(2, 2), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 0), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 1), 1); - BOOST_REQUIRE_EQUAL(matrix(3, 2), 1); + REQUIRE(matrix(0, 0) == 0); + REQUIRE(matrix(0, 1) == 1); + REQUIRE(matrix(0, 2) == 1); + REQUIRE(matrix(1, 0) == 1); + REQUIRE(matrix(1, 1) == 1); + REQUIRE(matrix(1, 2) == 1); + REQUIRE(matrix(2, 0) == 1); + REQUIRE(matrix(2, 1) == 1); + REQUIRE(matrix(2, 2) == 1); + REQUIRE(matrix(3, 0) == 1); + REQUIRE(matrix(3, 1) == 1); + REQUIRE(matrix(3, 2) == 1); - BOOST_REQUIRE_EQUAL(info.MapString("200-DM", 1), 0); - BOOST_REQUIRE_EQUAL(info.MapString("1", 1), 1); + REQUIRE(info.MapString("200-DM", 1) == 0); + REQUIRE(info.MapString("1", 1) == 1); - BOOST_REQUIRE_EQUAL(info.UnmapString(0, 1), "200-DM"); - BOOST_REQUIRE_EQUAL(info.UnmapString(1, 1), "1"); + REQUIRE(info.UnmapString(0, 1) == "200-DM"); + REQUIRE(info.UnmapString(1, 1) == "1"); remove("test.csv"); } @@ -1914,7 +1912,7 @@ BOOST_AUTO_TEST_CASE(CategoricalNontransposedCSVLoadTest04) /** * A harder test CSV based on the concerns in #658. */ -BOOST_AUTO_TEST_CASE(HarderKeonTest) +TEST_CASE("HarderKeonTest", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -1929,28 +1927,28 @@ BOOST_AUTO_TEST_CASE(HarderKeonTest) data::DatasetInfo info; data::Load("test.csv", dataset, info, true, true); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 5); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 4); + REQUIRE(dataset.n_rows == 5); + REQUIRE(dataset.n_cols == 4); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 5); - BOOST_REQUIRE_EQUAL(info.NumMappings(0), 3); - BOOST_REQUIRE_EQUAL(info.NumMappings(1), 4); - BOOST_REQUIRE_EQUAL(info.NumMappings(2), 0); - BOOST_REQUIRE_EQUAL(info.NumMappings(3), 2); // \t and "" are equivalent. - BOOST_REQUIRE_EQUAL(info.NumMappings(4), 4); + REQUIRE(info.Dimensionality() == 5); + REQUIRE(info.NumMappings(0) == 3); + REQUIRE(info.NumMappings(1) == 4); + REQUIRE(info.NumMappings(2) == 0); + REQUIRE(info.NumMappings(3) == 2); // \t and "" are equivalent. + REQUIRE(info.NumMappings(4) == 4); // Now load non-transposed. data::DatasetInfo ntInfo; data::Load("test.csv", dataset, ntInfo, true, false); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 4); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 5); + REQUIRE(dataset.n_rows == 4); + REQUIRE(dataset.n_cols == 5); - BOOST_REQUIRE_EQUAL(ntInfo.Dimensionality(), 4); - BOOST_REQUIRE_EQUAL(ntInfo.NumMappings(0), 4); - BOOST_REQUIRE_EQUAL(ntInfo.NumMappings(1), 5); - BOOST_REQUIRE_EQUAL(ntInfo.NumMappings(2), 5); - BOOST_REQUIRE_EQUAL(ntInfo.NumMappings(3), 3); + REQUIRE(ntInfo.Dimensionality() == 4); + REQUIRE(ntInfo.NumMappings(0) == 4); + REQUIRE(ntInfo.NumMappings(1) == 5); + REQUIRE(ntInfo.NumMappings(2) == 5); + REQUIRE(ntInfo.NumMappings(3) == 3); remove("test.csv"); } @@ -1958,7 +1956,7 @@ BOOST_AUTO_TEST_CASE(HarderKeonTest) /** * A simple ARFF load test. Two attributes, both numeric. */ -BOOST_AUTO_TEST_CASE(SimpleARFFTest) +TEST_CASE("SimpleARFFTest", "[LoadSaveTest]") { fstream f; f.open("test.arff", fstream::out); @@ -1978,15 +1976,15 @@ BOOST_AUTO_TEST_CASE(SimpleARFFTest) DatasetInfo info; data::Load("test.arff", dataset, info); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 2); - BOOST_REQUIRE(info.Type(0) == Datatype::numeric); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Dimensionality() == 2); + REQUIRE(info.Type(0) == Datatype::numeric); + REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 2); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 4); + REQUIRE(dataset.n_rows == 2); + REQUIRE(dataset.n_cols == 4); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_CLOSE(dataset[i], double(i + 1), 1e-5); + REQUIRE(dataset[i] == Approx(double(i + 1)).epsilon(1e-7)); remove("test.arff"); } @@ -1995,7 +1993,7 @@ BOOST_AUTO_TEST_CASE(SimpleARFFTest) * Another simple ARFF load test. Three attributes, two categorical, one * numeric. */ -BOOST_AUTO_TEST_CASE(SimpleARFFCategoricalTest) +TEST_CASE("SimpleARFFCategoricalTest", "[LoadSaveTest]") { fstream f; f.open("test.arff", fstream::out); @@ -2019,32 +2017,32 @@ BOOST_AUTO_TEST_CASE(SimpleARFFCategoricalTest) DatasetInfo info; data::Load("test.arff", dataset, info); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 3); + REQUIRE(info.Dimensionality() == 3); - BOOST_REQUIRE(info.Type(0) == Datatype::categorical); - BOOST_REQUIRE_EQUAL(info.NumMappings(0), 3); - BOOST_REQUIRE(info.Type(1) == Datatype::numeric); - BOOST_REQUIRE(info.Type(2) == Datatype::categorical); - BOOST_REQUIRE_EQUAL(info.NumMappings(2), 2); + REQUIRE(info.Type(0) == Datatype::categorical); + REQUIRE(info.NumMappings(0) == 3); + REQUIRE(info.Type(1) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::categorical); + REQUIRE(info.NumMappings(2) == 2); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 3); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 4); + REQUIRE(dataset.n_rows == 3); + REQUIRE(dataset.n_cols == 4); // The first dimension must all be different (except the ones that are the // same). - BOOST_REQUIRE_EQUAL(dataset(0, 0), dataset(0, 3)); - BOOST_REQUIRE_NE(dataset(0, 0), dataset(0, 1)); - BOOST_REQUIRE_NE(dataset(0, 1), dataset(0, 2)); - BOOST_REQUIRE_NE(dataset(0, 2), dataset(0, 0)); + REQUIRE(dataset(0, 0) == dataset(0, 3)); + REQUIRE(dataset(0, 0) != dataset(0, 1)); + REQUIRE(dataset(0, 1) != dataset(0, 2)); + REQUIRE(dataset(0, 2) != dataset(0, 0)); - BOOST_REQUIRE_CLOSE(dataset(1, 0), 1.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(1, 1), 2.34, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(1, 2), 1.03e5, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(1, 3), -1.3, 1e-5); + REQUIRE(dataset(1, 0) == Approx(1.0).epsilon(1e-7)); + REQUIRE(dataset(1, 1) == Approx(2.34).epsilon(1e-7)); + REQUIRE(dataset(1, 2) == Approx(1.03e5).epsilon(1e-7)); + REQUIRE(dataset(1, 3) == Approx(-1.3).epsilon(1e-7)); - BOOST_REQUIRE_EQUAL(dataset(2, 0), dataset(2, 2)); - BOOST_REQUIRE_EQUAL(dataset(2, 1), dataset(2, 3)); - BOOST_REQUIRE_NE(dataset(2, 0), dataset(2, 1)); + REQUIRE(dataset(2, 0) == dataset(2, 2)); + REQUIRE(dataset(2, 1) == dataset(2, 3)); + REQUIRE(dataset(2, 0) != dataset(2, 1)); remove("test.arff"); } @@ -2053,7 +2051,7 @@ BOOST_AUTO_TEST_CASE(SimpleARFFCategoricalTest) * A harder ARFF test, where we have each type of supported value, and some * random whitespace too. */ -BOOST_AUTO_TEST_CASE(HarderARFFTest) +TEST_CASE("HarderARFFTest", "[LoadSaveTest]") { fstream f; f.open("test.arff", fstream::out); @@ -2078,39 +2076,39 @@ BOOST_AUTO_TEST_CASE(HarderARFFTest) DatasetInfo info; data::Load("test.arff", dataset, info); - BOOST_REQUIRE_EQUAL(info.Dimensionality(), 5); + REQUIRE(info.Dimensionality() == 5); - BOOST_REQUIRE(info.Type(0) == Datatype::numeric); + REQUIRE(info.Type(0) == Datatype::numeric); - BOOST_REQUIRE(info.Type(1) == Datatype::categorical); - BOOST_REQUIRE_EQUAL(info.NumMappings(1), 3); + REQUIRE(info.Type(1) == Datatype::categorical); + REQUIRE(info.NumMappings(1) == 3); - BOOST_REQUIRE(info.Type(2) == Datatype::numeric); - BOOST_REQUIRE(info.Type(3) == Datatype::numeric); - BOOST_REQUIRE(info.Type(4) == Datatype::numeric); + REQUIRE(info.Type(2) == Datatype::numeric); + REQUIRE(info.Type(3) == Datatype::numeric); + REQUIRE(info.Type(4) == Datatype::numeric); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 5); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 3); + REQUIRE(dataset.n_rows == 5); + REQUIRE(dataset.n_cols == 3); - BOOST_REQUIRE_CLOSE(dataset(0, 0), 1.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(0, 1), 2.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(0, 2), 3.0, 1e-5); + REQUIRE(dataset(0, 0) == Approx(1.0).epsilon(1e-7)); + REQUIRE(dataset(0, 1) == Approx(2.0).epsilon(1e-7)); + REQUIRE(dataset(0, 2) == Approx(3.0).epsilon(1e-7)); - BOOST_REQUIRE_NE(dataset(1, 0), dataset(1, 1)); - BOOST_REQUIRE_NE(dataset(1, 1), dataset(1, 2)); - BOOST_REQUIRE_NE(dataset(1, 0), dataset(1, 2)); + REQUIRE(dataset(1, 0) != dataset(1, 1)); + REQUIRE(dataset(1, 1) != dataset(1, 2)); + REQUIRE(dataset(1, 0) != dataset(1, 2)); - BOOST_REQUIRE_CLOSE(dataset(2, 0), 3.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(2, 1), 4.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(2, 2), 5.0, 1e-5); + REQUIRE(dataset(2, 0) == Approx(3.0).epsilon(1e-7)); + REQUIRE(dataset(2, 1) == Approx(4.0).epsilon(1e-7)); + REQUIRE(dataset(2, 2) == Approx(5.0).epsilon(1e-7)); - BOOST_REQUIRE_CLOSE(dataset(3, 0), 4.5, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(3, 1), 5.5, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(3, 2), 6.5, 1e-5); + REQUIRE(dataset(3, 0) == Approx(4.5).epsilon(1e-7)); + REQUIRE(dataset(3, 1) == Approx(5.5).epsilon(1e-7)); + REQUIRE(dataset(3, 2) == Approx(6.5).epsilon(1e-7)); - BOOST_REQUIRE_CLOSE(dataset(4, 0), 6.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(4, 1), 7.0, 1e-5); - BOOST_REQUIRE_CLOSE(dataset(4, 2), 8.0, 1e-5); + REQUIRE(dataset(4, 0) == Approx(6.0).epsilon(1e-7)); + REQUIRE(dataset(4, 1) == Approx(7.0).epsilon(1e-7)); + REQUIRE(dataset(4, 2) == Approx(8.0).epsilon(1e-7)); remove("test.arff"); } @@ -2118,7 +2116,7 @@ BOOST_AUTO_TEST_CASE(HarderARFFTest) /** * If we pass a bad DatasetInfo, it should throw. */ -BOOST_AUTO_TEST_CASE(BadDatasetInfoARFFTest) +TEST_CASE("BadDatasetInfoARFFTest", "[LoadSaveTest]") { fstream f; f.open("test.arff", fstream::out); @@ -2142,7 +2140,7 @@ BOOST_AUTO_TEST_CASE(BadDatasetInfoARFFTest) arma::mat dataset; DatasetInfo info(6); - BOOST_REQUIRE_THROW(data::LoadARFF("test.arff", dataset, info), + REQUIRE_THROWS_AS(data::LoadARFF("test.arff", dataset, info), std::invalid_argument); remove("test.arff"); @@ -2151,13 +2149,13 @@ BOOST_AUTO_TEST_CASE(BadDatasetInfoARFFTest) /** * If file is not found, it should throw. */ -BOOST_AUTO_TEST_CASE(NonExistentFileARFFTest) +TEST_CASE("NonExistentFileARFFTest", "[LoadSaveTest]") { arma::mat dataset; DatasetInfo info; Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(data::LoadARFF("nonexistentfile.arff", dataset, info), + REQUIRE_THROWS_AS(data::LoadARFF("nonexistentfile.arff", dataset, info), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -2166,7 +2164,7 @@ BOOST_AUTO_TEST_CASE(NonExistentFileARFFTest) * A test to check whether the arff loader is case insensitive to declarations: * @relation, @attribute, @data. */ -BOOST_AUTO_TEST_CASE(CaseTest) +TEST_CASE("CaseTest", "[LoadSaveTest]") { arma::mat dataset; @@ -2174,15 +2172,15 @@ BOOST_AUTO_TEST_CASE(CaseTest) LoadARFF("casecheck.arff", dataset, info); - BOOST_CHECK_EQUAL(dataset.n_rows, 2); - BOOST_CHECK_EQUAL(dataset.n_cols, 3); + REQUIRE(dataset.n_rows == 2); + REQUIRE(dataset.n_cols == 3); } /** * Ensure that a failure happens if we set a category to use capital letters but * it receives them in lowercase. */ -BOOST_AUTO_TEST_CASE(CategoryCaseTest) +TEST_CASE("CategoryCaseTest", "[LoadSaveTest]") { fstream f; f.open("test.arff", fstream::out); @@ -2209,7 +2207,7 @@ BOOST_AUTO_TEST_CASE(CategoryCaseTest) // Make sure to parse with fatal errors (that's what the `true` parameter // means). Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(data::Load("test.arff", dataset, info, true), + REQUIRE_THROWS_AS(data::Load("test.arff", dataset, info, true), std::runtime_error); Log::Fatal.ignoreInput = false; @@ -2219,7 +2217,7 @@ BOOST_AUTO_TEST_CASE(CategoryCaseTest) /** * Test that a CSV with the wrong number of columns fails. */ -BOOST_AUTO_TEST_CASE(MalformedCSVTest) +TEST_CASE("MalformedCSVTest", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -2231,7 +2229,7 @@ BOOST_AUTO_TEST_CASE(MalformedCSVTest) arma::mat dataset; DatasetInfo di; - BOOST_REQUIRE(!data::Load("test.csv", dataset, di, false)); + REQUIRE(!data::Load("test.csv", dataset, di, false)); remove("test.csv"); } @@ -2239,7 +2237,7 @@ BOOST_AUTO_TEST_CASE(MalformedCSVTest) /** * Test that a TSV can load with LoadCSV. */ -BOOST_AUTO_TEST_CASE(LoadCSVTSVTest) +TEST_CASE("LoadCSVTSVTest", "[LoadSaveTest]") { fstream f; f.open("test.tsv", fstream::out); @@ -2250,13 +2248,13 @@ BOOST_AUTO_TEST_CASE(LoadCSVTSVTest) arma::mat dataset; DatasetInfo di; - BOOST_REQUIRE(data::Load("test.tsv", dataset, di, false)); + REQUIRE(data::Load("test.tsv", dataset, di, false)); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 2); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 4); + REQUIRE(dataset.n_cols == 2); + REQUIRE(dataset.n_rows == 4); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_EQUAL(dataset[i], i + 1); + REQUIRE(dataset[i] == i + 1); remove("test.tsv"); } @@ -2264,7 +2262,7 @@ BOOST_AUTO_TEST_CASE(LoadCSVTSVTest) /** * Test that a text file can load with LoadCSV. */ -BOOST_AUTO_TEST_CASE(LoadCSVTXTTest) +TEST_CASE("LoadCSVTXTTest", "[LoadSaveTest]") { fstream f; f.open("test.txt", fstream::out); @@ -2275,13 +2273,13 @@ BOOST_AUTO_TEST_CASE(LoadCSVTXTTest) arma::mat dataset; DatasetInfo di; - BOOST_REQUIRE(data::Load("test.txt", dataset, di, false)); + REQUIRE(data::Load("test.txt", dataset, di, false)); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 2); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 4); + REQUIRE(dataset.n_cols == 2); + REQUIRE(dataset.n_rows == 4); for (size_t i = 0; i < 8; ++i) - BOOST_REQUIRE_EQUAL(dataset[i], i + 1); + REQUIRE(dataset[i] == i + 1); remove("test.txt"); } @@ -2289,7 +2287,7 @@ BOOST_AUTO_TEST_CASE(LoadCSVTXTTest) /** * Test that a non-transposed CSV with the wrong number of columns fails. */ -BOOST_AUTO_TEST_CASE(MalformedNoTransposeCSVTest) +TEST_CASE("MalformedNoTransposeCSVTest", "[LoadSaveTest]") { fstream f; f.open("test.csv", fstream::out); @@ -2301,7 +2299,7 @@ BOOST_AUTO_TEST_CASE(MalformedNoTransposeCSVTest) arma::mat dataset; DatasetInfo di; - BOOST_REQUIRE(!data::Load("test.csv", dataset, di, false, false)); + REQUIRE(!data::Load("test.csv", dataset, di, false, false)); remove("test.csv"); } @@ -2309,7 +2307,7 @@ BOOST_AUTO_TEST_CASE(MalformedNoTransposeCSVTest) /** * Test that a non-transposed TSV can load with LoadCSV. */ -BOOST_AUTO_TEST_CASE(LoadCSVNoTransposeTSVTest) +TEST_CASE("LoadCSVNoTransposeTSVTest", "[LoadSaveTest]") { fstream f; f.open("test.tsv", fstream::out); @@ -2320,19 +2318,19 @@ BOOST_AUTO_TEST_CASE(LoadCSVNoTransposeTSVTest) arma::mat dataset; DatasetInfo di; - BOOST_REQUIRE(data::Load("test.tsv", dataset, di, false, false)); + REQUIRE(data::Load("test.tsv", dataset, di, false, false)); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 4); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 2); + REQUIRE(dataset.n_cols == 4); + REQUIRE(dataset.n_rows == 2); - BOOST_REQUIRE_EQUAL(dataset[0], 1); - BOOST_REQUIRE_EQUAL(dataset[1], 5); - BOOST_REQUIRE_EQUAL(dataset[2], 2); - BOOST_REQUIRE_EQUAL(dataset[3], 6); - BOOST_REQUIRE_EQUAL(dataset[4], 3); - BOOST_REQUIRE_EQUAL(dataset[5], 7); - BOOST_REQUIRE_EQUAL(dataset[6], 4); - BOOST_REQUIRE_EQUAL(dataset[7], 8); + REQUIRE(dataset[0] == 1); + REQUIRE(dataset[1] == 5); + REQUIRE(dataset[2] == 2); + REQUIRE(dataset[3] == 6); + REQUIRE(dataset[4] == 3); + REQUIRE(dataset[5] == 7); + REQUIRE(dataset[6] == 4); + REQUIRE(dataset[7] == 8); remove("test.tsv"); } @@ -2340,7 +2338,7 @@ BOOST_AUTO_TEST_CASE(LoadCSVNoTransposeTSVTest) /** * Test that a non-transposed text file can load with LoadCSV. */ -BOOST_AUTO_TEST_CASE(LoadCSVNoTransposeTXTTest) +TEST_CASE("LoadCSVNoTransposeTXTTest", "[LoadSaveTest]") { fstream f; f.open("test.txt", fstream::out); @@ -2351,19 +2349,19 @@ BOOST_AUTO_TEST_CASE(LoadCSVNoTransposeTXTTest) arma::mat dataset; DatasetInfo di; - BOOST_REQUIRE(data::Load("test.txt", dataset, di, false, false)); + REQUIRE(data::Load("test.txt", dataset, di, false, false)); - BOOST_REQUIRE_EQUAL(dataset.n_cols, 4); - BOOST_REQUIRE_EQUAL(dataset.n_rows, 2); + REQUIRE(dataset.n_cols == 4); + REQUIRE(dataset.n_rows == 2); - BOOST_REQUIRE_EQUAL(dataset[0], 1); - BOOST_REQUIRE_EQUAL(dataset[1], 5); - BOOST_REQUIRE_EQUAL(dataset[2], 2); - BOOST_REQUIRE_EQUAL(dataset[3], 6); - BOOST_REQUIRE_EQUAL(dataset[4], 3); - BOOST_REQUIRE_EQUAL(dataset[5], 7); - BOOST_REQUIRE_EQUAL(dataset[6], 4); - BOOST_REQUIRE_EQUAL(dataset[7], 8); + REQUIRE(dataset[0] == 1); + REQUIRE(dataset[1] == 5); + REQUIRE(dataset[2] == 2); + REQUIRE(dataset[3] == 6); + REQUIRE(dataset[4] == 3); + REQUIRE(dataset[5] == 7); + REQUIRE(dataset[6] == 4); + REQUIRE(dataset[7] == 8); remove("test.txt"); } @@ -2371,7 +2369,7 @@ BOOST_AUTO_TEST_CASE(LoadCSVNoTransposeTXTTest) /** * Make sure DatasetMapper properly unmaps from non-unique strings. */ -BOOST_AUTO_TEST_CASE(DatasetMapperNonUniqueTest) +TEST_CASE("DatasetMapperNonUniqueTest", "[LoadSaveTest]") { DatasetMapper dm(1); @@ -2382,13 +2380,11 @@ BOOST_AUTO_TEST_CASE(DatasetMapperNonUniqueTest) dm.MapString("cheese", 0); double nan = std::numeric_limits::quiet_NaN(); - BOOST_REQUIRE_EQUAL(dm.NumMappings(0), 3); - BOOST_REQUIRE_EQUAL(dm.NumUnmappings(nan, 0), 3); + REQUIRE(dm.NumMappings(0) == 3); + REQUIRE(dm.NumUnmappings(nan, 0) == 3); - BOOST_REQUIRE_EQUAL(dm.UnmapString(nan, 0), "hello"); - BOOST_REQUIRE_EQUAL(dm.UnmapString(nan, 0, 0), "hello"); - BOOST_REQUIRE_EQUAL(dm.UnmapString(nan, 0, 1), "goodbye"); - BOOST_REQUIRE_EQUAL(dm.UnmapString(nan, 0, 2), "cheese"); + REQUIRE(dm.UnmapString(nan, 0) == "hello"); + REQUIRE(dm.UnmapString(nan, 0, 0) == "hello"); + REQUIRE(dm.UnmapString(nan, 0, 1) == "goodbye"); + REQUIRE(dm.UnmapString(nan, 0, 2) == "cheese"); } - -BOOST_AUTO_TEST_SUITE_END(); From 10e3c964bc00f5537a250044ef219a13cf7e0bf7 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Fri, 24 Jul 2020 00:20:00 +0530 Subject: [PATCH 243/297] fix order of test --- src/mlpack/tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 276b75f994..ffd0959edb 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -163,9 +163,9 @@ add_executable(mlpack_catch_test activation_functions_test.cpp akfn_test.cpp aknn_test.cpp + image_load_test.cpp kfn_test.cpp knn_test.cpp - image_load_test.cpp linear_regression_test.cpp main.cpp serialization_catch.cpp From 64cecce59dd998ab4f86e488172a7729b7d452ff Mon Sep 17 00:00:00 2001 From: nishantkr18 Date: Sun, 26 Jul 2020 12:18:21 +0530 Subject: [PATCH 244/297] changes to the network initialization method in simpledqn --- .../q_networks/simple_dqn.hpp | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp index 211df0649d..cf853a60ef 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp @@ -26,8 +26,11 @@ using namespace mlpack::ann; /** * @tparam NetworkType The type of network used for simple dqn. */ -template , - GaussianInitialization>> +template< + typename OutputLayerType = MeanSquaredError<>, + typename InitType = GaussianInitialization, + typename NetworkType = FFN +> class SimpleDQN { public: @@ -45,13 +48,18 @@ class SimpleDQN * @param h2 Number of neurons in hiddenlayer-2. * @param outputDim Number of neurons in output layer. * @param isNoisy Specifies whether the network needs to be of type noisy. + * @param init Specifies the initilization rule for the network. + * @param outputLayer Specifies the output layer type for network. */ SimpleDQN(const int inputDim, const int h1, const int h2, const int outputDim, - const bool isNoisy = false): - network(MeanSquaredError<>(), GaussianInitialization(0, 0.001)), + const bool isNoisy = false, + InitType init = GaussianInitialization(0, 0.001), + OutputLayerType outputLayer = OutputLayerType() + ): + network(outputLayer, init), isNoisy(isNoisy) { network.Add(new Linear<>(inputDim, h1)); @@ -72,8 +80,14 @@ class SimpleDQN } } - SimpleDQN(NetworkType network, const bool isNoisy = false): - network(std::move(network)), + /** + * Construct an instance of SimpleDQN class from a pre-constructed network. + * + * @param network The network to be used by SimpleDQN class. + * @param isNoisy Specifies whether the network needs to be of type noisy. + */ + SimpleDQN(NetworkType& network, const bool isNoisy = false): + network(network), isNoisy(isNoisy) { /* Nothing to do here. */ } From 5323ee392d9c45a21b6e470818c82810ace14055 Mon Sep 17 00:00:00 2001 From: nishantkr18 Date: Sun, 26 Jul 2020 12:40:03 +0530 Subject: [PATCH 245/297] made network init changes in duelingdqn, along with reference passing in network construction --- .../q_networks/dueling_dqn.hpp | 30 +++++++++++++------ .../q_networks/simple_dqn.hpp | 3 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp index 9d22940457..cff91d010f 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp @@ -44,7 +44,9 @@ using namespace mlpack::ann; * @tparam ValueNetworkType The type of network used for value network. */ template < - typename CompleteNetworkType = FFN, GaussianInitialization>, + typename OutputLayerType = EmptyLoss<>, + typename InitType = GaussianInitialization, + typename CompleteNetworkType = FFN, typename FeatureNetworkType = Sequential<>, typename AdvantageNetworkType = Sequential<>, typename ValueNetworkType = Sequential<> @@ -80,8 +82,10 @@ class DuelingDQN const int h1, const int h2, const int outputDim, - const bool isNoisy = false): - completeNetwork(EmptyLoss<>(), GaussianInitialization(0, 0.001)), + const bool isNoisy = false, + InitType init = GaussianInitialization(0, 0.001), + OutputLayerType outputLayer = OutputLayerType()): + completeNetwork(outputLayer, init), isNoisy(isNoisy) { featureNetwork = new Sequential<>(); @@ -125,13 +129,21 @@ class DuelingDQN this->ResetParameters(); } - DuelingDQN(FeatureNetworkType featureNetwork, - AdvantageNetworkType advantageNetwork, - ValueNetworkType valueNetwork, + /** + * Construct an instance of DuelingDQN class from a pre-constructed network. + * + * @param featureNetwork The festure network to be used by DuelingDQN class. + * @param advantageNetwork The advantage network to be used by DuelingDQN class. + * @param valueNetwork The value network to be used by DuelingDQN class. + * @param isNoisy Specifies whether the network needs to be of type noisy. + */ + DuelingDQN(FeatureNetworkType& featureNetwork, + AdvantageNetworkType& advantageNetwork, + ValueNetworkType& valueNetwork, const bool isNoisy = false): - featureNetwork(std::move(featureNetwork)), - advantageNetwork(std::move(advantageNetwork)), - valueNetwork(std::move(valueNetwork)), + featureNetwork(featureNetwork), + advantageNetwork(advantageNetwork), + valueNetwork(valueNetwork), isNoisy(isNoisy) { concat = new Concat<>(true); diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp index cf853a60ef..78c310e8d7 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp @@ -57,8 +57,7 @@ class SimpleDQN const int outputDim, const bool isNoisy = false, InitType init = GaussianInitialization(0, 0.001), - OutputLayerType outputLayer = OutputLayerType() - ): + OutputLayerType outputLayer = OutputLayerType()): network(outputLayer, init), isNoisy(isNoisy) { From b14c36d67865af419ede96c918b3ed679c611bc7 Mon Sep 17 00:00:00 2001 From: nishantkr18 Date: Sun, 26 Jul 2020 12:42:12 +0530 Subject: [PATCH 246/297] minor doc addition for parameter --- .../methods/reinforcement_learning/q_networks/dueling_dqn.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp index cff91d010f..cbacb295ab 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp @@ -77,6 +77,8 @@ class DuelingDQN * @param h2 Number of neurons in hiddenlayer-2. * @param outputDim Number of neurons in output layer. * @param isNoisy Specifies whether the network needs to be of type noisy. + * @param init Specifies the initilization rule for the network. + * @param outputLayer Specifies the output layer type for network. */ DuelingDQN(const int inputDim, const int h1, From 4586363840127471ed6d981743c169c1c07ca059 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Sun, 26 Jul 2020 10:29:51 +0200 Subject: [PATCH 247/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 39c04fc4b4..2c56f97acd 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -163,7 +163,7 @@ static void mlpackMain() bayesLinReg = IO::GetParam("input_model"); } - if (CLI::HasParam("test")) + if (IO::HasParam("test")) { Log::Info << "Regressing on test points." << endl; // Load test points. From 4cc3d0555fec23ea69496ecbd5b5d9acde4bfe12 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Sun, 26 Jul 2020 10:30:01 +0200 Subject: [PATCH 248/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Ryan Curtin --- .../tests/main_tests/bayesian_linear_regression_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 8b9c599530..0634408875 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -88,8 +88,8 @@ BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode) mlpackMain(); - CLI::GetSingleton().Parameters()["input"].wasPassed = false; - CLI::GetSingleton().Parameters()["responses"].wasPassed = false; + IO::GetSingleton().Parameters()["input"].wasPassed = false; + IO::GetSingleton().Parameters()["responses"].wasPassed = false; SetInputParam("input_model", IO::GetParam("output_model")); From e502fbce8ba83b81d64e79889769ac5dc6a6bd35 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Sun, 26 Jul 2020 10:30:11 +0200 Subject: [PATCH 249/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Ryan Curtin --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 2c56f97acd..55a41ff323 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -170,7 +170,7 @@ static void mlpackMain() mat testPoints = std::move(IO::GetParam("test")); arma::rowvec predictions; - if (CLI::HasParam("stds")) + if (IO::HasParam("stds")) { arma::rowvec std; bayesLinReg->Predict(testPoints, predictions, std); From b73a220a9196ce8bd05519a9da24f7b22e0ea4d4 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 26 Jul 2020 11:29:09 -0400 Subject: [PATCH 250/297] Fix sample point to be column-major. --- doc/guide/sample_ml_app.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/doc/guide/sample_ml_app.hpp b/doc/guide/sample_ml_app.hpp index 28ae6ad737..6a1b1aa30a 100644 --- a/doc/guide/sample_ml_app.hpp +++ b/doc/guide/sample_ml_app.hpp @@ -94,7 +94,7 @@ copy "mlpack/tests/data/german.csv" and paste into a new "data" folder in your p mat dataset; bool loaded = mlpack::data::Load("data/german.csv", dataset); if (!loaded) - return -1; + return -1; @endcode Then we need to extract the labels from the last dimension of the dataset and remove the @@ -121,7 +121,7 @@ const size_t numTrees = 10; RandomForest rf; rf = RandomForest(dataset, labels, - numClasses, numTrees, minimumLeafSize); + numClasses, numTrees, minimumLeafSize); @endcode Now that the training is completed, we quickly compute the training accuracy: @@ -143,7 +143,7 @@ to assess the quality of the trained model. @code const size_t k = 10; KFoldCV, Accuracy> cv(k, - dataset, labels, numClasses); + dataset, labels, numClasses); double cvAcc = cv.Evaluate(numTrees, minimumLeafSize); cout << "\nKFoldCV Accuracy: " << cvAcc; @endcode @@ -188,12 +188,16 @@ Finally, the ultimate goal is to classify a new sample using the previously trai Random Forest classifier provides both predictions and probabilities, we obtain both. @code -mat sample("2 12 2 13 1 2 2 1 3 24 3 1 1 1 1 1 0 1 0 1 0 0 0"); +// Create a test sample containing only one point. Because Armadillo is +// column-major, this matrix has one column (one point) and the number of rows +// is equal to the dimensionality of the point (23). +mat sample("2; 12; 2; 13; 1; 2; 2; 1; 3; 24; 3; 1; 1; 1; 1; 1; 0; 1; 0; 1;" + " 0; 0; 0"); mat probabilities; rf.Classify(sample, predictions, probabilities); u64 result = predictions.at(0); cout << "\nClassification result: " << result << " , Probabilities: " << - probabilities.at(0) << "/" << probabilities.at(1); + probabilities.at(0) << "/" << probabilities.at(1); @endcode @section sample_app_conclussion Final thoughts From 69098c3b4acf0ff3c468aa3995545fd52034e8c1 Mon Sep 17 00:00:00 2001 From: Mikhail Lozhnikov Date: Mon, 27 Jul 2020 15:32:49 +0300 Subject: [PATCH 251/297] Trying to fix the AppVeyor build. --- src/mlpack/tests/metric_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/metric_test.cpp b/src/mlpack/tests/metric_test.cpp index 6eaabe3ebc..dffe3211fc 100644 --- a/src/mlpack/tests/metric_test.cpp +++ b/src/mlpack/tests/metric_test.cpp @@ -336,7 +336,8 @@ BOOST_AUTO_TEST_CASE(BLEUScoreTest) BOOST_REQUIRE_EQUAL(bleu.TranslationLength(), 12); BOOST_REQUIRE_EQUAL(bleu.ReferenceLength(), 12); - std::vector expectedPrecision = {0.666666, 0.5555555, 0.3333333, 0}; + std::vector expectedPrecision = {0.666666f, 0.5555555f, + 0.3333333f, 0.0f}; for (size_t i = 0; i < bleu.Precisions().size(); ++i) { BOOST_REQUIRE_CLOSE_FRACTION(bleu.Precisions()[i], @@ -351,7 +352,7 @@ BOOST_AUTO_TEST_CASE(BLEUScoreTest) BOOST_REQUIRE_EQUAL(bleu.TranslationLength(), 12); BOOST_REQUIRE_EQUAL(bleu.ReferenceLength(), 12); - expectedPrecision = {0.692308, 0.6, 0.428571, 0.25}; + expectedPrecision = {0.692308f, 0.6f, 0.428571f, 0.25f}; for (size_t i = 0; i < bleu.Precisions().size(); ++i) { BOOST_REQUIRE_CLOSE_FRACTION(bleu.Precisions()[i], From 08918dd5a3bdeead8f78cbf1d9b86e871264bc73 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:56:38 +0200 Subject: [PATCH 252/297] Update src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt Co-authored-by: Yashwant Singh Parihar --- src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt index 59c71a80fa..5cdae4274d 100644 --- a/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt +++ b/src/mlpack/methods/bayesian_linear_regression/CMakeLists.txt @@ -17,4 +17,5 @@ set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) add_cli_executable(bayesian_linear_regression) add_python_binding(bayesian_linear_regression) add_julia_binding(bayesian_linear_regression) -add_markdown_docs(bayesian_linear_regression "cli;python;julia" "regression") +add_go_binding(bayesian_linear_regression) +add_markdown_docs(bayesian_linear_regression "cli;python;julia;go" "regression") From f8fe6acab35a92ed7a60cc45d12a64ad5cba419c Mon Sep 17 00:00:00 2001 From: nishantkr18 Date: Mon, 27 Jul 2020 22:23:50 +0530 Subject: [PATCH 253/297] doc changes and inittype fixed --- .../reinforcement_learning/q_networks/dueling_dqn.hpp | 8 +++++--- .../reinforcement_learning/q_networks/simple_dqn.hpp | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp index cbacb295ab..6a160a48ac 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp @@ -38,6 +38,8 @@ using namespace mlpack::ann; * } * @endcode * + * @tparam OutputLayerType The output layer type of the network. + * @tparam InitType The initialization type used for the network. * @tparam CompleteNetworkType The type of network used for full dueling dqn. * @tparam FeatureNetworkType The type of network used for feature network. * @tparam AdvantageNetworkType The type of network used for advantage network. @@ -77,7 +79,7 @@ class DuelingDQN * @param h2 Number of neurons in hiddenlayer-2. * @param outputDim Number of neurons in output layer. * @param isNoisy Specifies whether the network needs to be of type noisy. - * @param init Specifies the initilization rule for the network. + * @param init Specifies the initialization rule for the network. * @param outputLayer Specifies the output layer type for network. */ DuelingDQN(const int inputDim, @@ -85,7 +87,7 @@ class DuelingDQN const int h2, const int outputDim, const bool isNoisy = false, - InitType init = GaussianInitialization(0, 0.001), + InitType init = InitType(), OutputLayerType outputLayer = OutputLayerType()): completeNetwork(outputLayer, init), isNoisy(isNoisy) @@ -134,7 +136,7 @@ class DuelingDQN /** * Construct an instance of DuelingDQN class from a pre-constructed network. * - * @param featureNetwork The festure network to be used by DuelingDQN class. + * @param featureNetwork The feature network to be used by DuelingDQN class. * @param advantageNetwork The advantage network to be used by DuelingDQN class. * @param valueNetwork The value network to be used by DuelingDQN class. * @param isNoisy Specifies whether the network needs to be of type noisy. diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp index 78c310e8d7..818e004a4d 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp @@ -24,6 +24,8 @@ namespace rl { using namespace mlpack::ann; /** + * @tparam OutputLayerType The output layer type of the network. + * @tparam InitType The initialization type used for the network. * @tparam NetworkType The type of network used for simple dqn. */ template< @@ -48,7 +50,7 @@ class SimpleDQN * @param h2 Number of neurons in hiddenlayer-2. * @param outputDim Number of neurons in output layer. * @param isNoisy Specifies whether the network needs to be of type noisy. - * @param init Specifies the initilization rule for the network. + * @param init Specifies the initialization rule for the network. * @param outputLayer Specifies the output layer type for network. */ SimpleDQN(const int inputDim, @@ -56,7 +58,7 @@ class SimpleDQN const int h2, const int outputDim, const bool isNoisy = false, - InitType init = GaussianInitialization(0, 0.001), + InitType init = InitType(), OutputLayerType outputLayer = OutputLayerType()): network(outputLayer, init), isNoisy(isNoisy) From 54b1342c938e93d78a21205eab5d1a79f23cee14 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 27 Jul 2020 23:14:29 +0530 Subject: [PATCH 254/297] fix documentation --- src/mlpack/methods/ann/layer/lookup.hpp | 8 ++++---- src/mlpack/methods/ann/layer/lookup_impl.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index bc61a9b3d8..e1492b64c8 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -65,13 +65,13 @@ class Lookup * forward pass. * * @param * (input) The propagated input activation. - * @param * (gy) The backpropagated error. - * @param * (g) The calculated gradient. + * @param gy The backpropagated error. + * @param g The calculated gradient. */ template void Backward(const arma::Mat& /* input */, - const arma::Mat& /* gy */, - arma::Mat& /* g */); + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activation. diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 81387fd359..0711615cda 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -50,8 +50,8 @@ template template void Lookup::Backward( const arma::Mat& /* input */, - const arma::Mat& /* gy */, - arma::Mat& /* g */) + const arma::Mat& gy, + arma::Mat& g) { // Nothing to do here. } From a13844d3fbd283cf8603e526c75d05d4b8924e2f Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 27 Jul 2020 23:22:23 +0530 Subject: [PATCH 255/297] correcting --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 0711615cda..81387fd359 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -50,8 +50,8 @@ template template void Lookup::Backward( const arma::Mat& /* input */, - const arma::Mat& gy, - arma::Mat& g) + const arma::Mat& /* gy */, + arma::Mat& /* g */) { // Nothing to do here. } From dc43f0a2b4da185162ef50397c564258c2f113af Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 28 Jul 2020 08:46:47 +0530 Subject: [PATCH 256/297] add log::fatal in backward --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 2 +- src/mlpack/tests/ann_layer_test.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 81387fd359..20bcd076d0 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -53,7 +53,7 @@ void Lookup::Backward( const arma::Mat& /* gy */, arma::Mat& /* g */) { - // Nothing to do here. + Log::Fatal << "Lookup cannot be used as an intermediate layer." << std::endl; } template diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 6bca11243b..d8fe002414 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1712,7 +1712,6 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) model = new FFN, GlorotInitialization>(); model->Predictors() = input; model->Responses() = target; - model->Add >(); model->Add >(vocabSize, embeddingSize); model->Add >(embeddingSize * seqLength, vocabSize); model->Add >(); From be7e95824aed80de25533aca44ae994d36b50e18 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 28 Jul 2020 15:14:56 +0200 Subject: [PATCH 257/297] Doc correction. --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 6c22827c86..ef87f2e13c 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -100,7 +100,7 @@ class BayesianLinearRegression * * @param centerData Whether or not center the data according to the * examples. - * @param scaleData Whether or to scale the data according to the + * @param scaleData Whether or not scale the data according to the * standard deviation of each feature. * @param nIterMax Maximum number of iterations for convergency. * @param tol Level from which the solution is considered sufficientlly From ee3af5cf46cba45950df96d00bbb0a48101d5136 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 28 Jul 2020 15:15:24 +0200 Subject: [PATCH 258/297] Add SEE_ALSO(). --- .../bayesian_linear_regression_main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 55a41ff323..ed7efdb9e2 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -84,7 +84,13 @@ PROGRAM_INFO("BayesianLinearRegression", "\n\n" + PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", - "predictions", "test_predictions", "stds", "stds")); + "predictions", "test_predictions", "stds", "stds"), + SEE_ALSO("MacKay 1992"), + SEE_ALSO("MLA Bishop, Christopher M. Pattern Recognition and Machine " + " Learning. New York :Springer, 2006, section 3.3."), + SEE_ALSO("mlpack::regression::BayesianLinearRegression C++ class + documentation", + "@doxygen/classmlpack_1_1regression_1_1BayesianLinearRegression.html")); PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); From 5321ab5ae0acb2b3b6a84b9357f747716d65da26 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 28 Jul 2020 15:45:39 +0200 Subject: [PATCH 259/297] Add SEE_ALSO(). --- .../bayesian_linear_regression_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index ed7efdb9e2..0e6438816f 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -88,8 +88,8 @@ PROGRAM_INFO("BayesianLinearRegression", SEE_ALSO("MacKay 1992"), SEE_ALSO("MLA Bishop, Christopher M. Pattern Recognition and Machine " " Learning. New York :Springer, 2006, section 3.3."), - SEE_ALSO("mlpack::regression::BayesianLinearRegression C++ class - documentation", + SEE_ALSO("mlpack::regression::BayesianLinearRegression C++ class " + "documentation", "@doxygen/classmlpack_1_1regression_1_1BayesianLinearRegression.html")); PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i"); From 19adb0d3f99576f303554283599e4df147a22346 Mon Sep 17 00:00:00 2001 From: cmercier Date: Tue, 28 Jul 2020 16:03:57 +0200 Subject: [PATCH 260/297] SEE_ALSO(desc, link). --- .../bayesian_linear_regression_main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index 0e6438816f..bc10f901bb 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -85,9 +85,11 @@ PROGRAM_INFO("BayesianLinearRegression", PRINT_CALL("bayesian_linear_regression", "input_model", "bayesian_linear_regression_model", "test", "test", "predictions", "test_predictions", "stds", "stds"), - SEE_ALSO("MacKay 1992"), - SEE_ALSO("MLA Bishop, Christopher M. Pattern Recognition and Machine " - " Learning. New York :Springer, 2006, section 3.3."), + SEE_ALSO("Bayesian Interpolation", + "https://authors.library.caltech.edu/13792/1/MACnc92a.pdf"), + SEE_ALSO("Bayesian Linear Regression, Section 3.3", + "MLA Bishop, Christopher M. Pattern Recognition and Machine " + "Learning. New York :Springer, 2006, section 3.3."), SEE_ALSO("mlpack::regression::BayesianLinearRegression C++ class " "documentation", "@doxygen/classmlpack_1_1regression_1_1BayesianLinearRegression.html")); From d992ddcbedbdc09b4ad7f6443f87ba6823cca816 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Tue, 28 Jul 2020 21:13:30 +0530 Subject: [PATCH 261/297] migrate decision_* and related test from boost to catch2 --- src/mlpack/tests/CMakeLists.txt | 8 +- src/mlpack/tests/decision_stump_test.cpp | 111 +++--- src/mlpack/tests/decision_tree_test.cpp | 348 +++++++++--------- .../tests/main_tests/decision_stump_test.cpp | 68 ++-- .../tests/main_tests/decision_tree_test.cpp | 147 ++++---- 5 files changed, 332 insertions(+), 350 deletions(-) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 6ec5a68fd8..9a73d41644 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -20,8 +20,6 @@ add_executable(mlpack_test cv_test.cpp dbscan_test.cpp dcgan_test.cpp - decision_stump_test.cpp - decision_tree_test.cpp det_test.cpp distribution_test.cpp drusilla_select_test.cpp @@ -111,8 +109,6 @@ add_executable(mlpack_test wgan_test.cpp main_tests/cf_test.cpp main_tests/dbscan_test.cpp - main_tests/decision_stump_test.cpp - main_tests/decision_tree_test.cpp main_tests/det_test.cpp main_tests/emst_test.cpp main_tests/fastmks_test.cpp @@ -158,6 +154,8 @@ add_executable(mlpack_catch_test aknn_test.cpp convolutional_network_test.cpp convolution_test.cpp + decision_stump_test.cpp + decision_tree_test.cpp image_load_test.cpp kfn_test.cpp knn_test.cpp @@ -170,6 +168,8 @@ add_executable(mlpack_catch_test test_catch_tools.hpp main_tests/adaboost_test.cpp main_tests/approx_kfn_test.cpp + main_tests/decision_stump_test.cpp + main_tests/decision_tree_test.cpp main_tests/image_converter_test.cpp main_tests/kfn_test.cpp main_tests/knn_test.cpp diff --git a/src/mlpack/tests/decision_stump_test.cpp b/src/mlpack/tests/decision_stump_test.cpp index 58418ff416..d2fe36cc08 100644 --- a/src/mlpack/tests/decision_stump_test.cpp +++ b/src/mlpack/tests/decision_stump_test.cpp @@ -12,22 +12,19 @@ #include #include -#include -#include "test_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::decision_stump; using namespace arma; using namespace mlpack::distribution; -BOOST_AUTO_TEST_SUITE(DecisionStumpTest); - /** * This tests handles the case wherein only one class exists in the input * labels. It checks whether the only class supplied was the only class * predicted. */ -BOOST_AUTO_TEST_CASE(OneClass) +TEST_CASE("OneClass", "[DecisionStumpTest]") { const size_t numClasses = 2; const size_t inpBucketSize = 6; @@ -50,7 +47,7 @@ BOOST_AUTO_TEST_CASE(OneClass) ds.Classify(testingData, predictedLabels); for (size_t i = 0; i < predictedLabels.size(); ++i) - BOOST_CHECK_EQUAL(predictedLabels(i), 1); + REQUIRE(predictedLabels(i) == 1); } /** @@ -58,7 +55,7 @@ BOOST_AUTO_TEST_CASE(OneClass) * correct value of the splitting column value. This test is for an * inpBucketSize of 4 and the correct value of the splitting dimension is 0. */ -BOOST_AUTO_TEST_CASE(CorrectDimensionChosen) +TEST_CASE("CorrectDimensionChosen", "[DecisionStumpTest]") { const size_t numClasses = 2; const size_t inpBucketSize = 4; @@ -84,7 +81,7 @@ BOOST_AUTO_TEST_CASE(CorrectDimensionChosen) // Only need to check the value of the splitting column, no need of // classification. - BOOST_CHECK_EQUAL(ds.SplitDimension(), 0); + REQUIRE(ds.SplitDimension() == 0); } /** @@ -93,7 +90,7 @@ BOOST_AUTO_TEST_CASE(CorrectDimensionChosen) * if testinput > 0 - class 1 * An almost perfect split on zero. */ -BOOST_AUTO_TEST_CASE(PerfectSplitOnZero) +TEST_CASE("PerfectSplitOnZero", "[DecisionStumpTest]") { const size_t numClasses = 2; const size_t inpBucketSize = 2; @@ -113,18 +110,18 @@ BOOST_AUTO_TEST_CASE(PerfectSplitOnZero) Row predictedLabels; ds.Classify(testingData, predictedLabels); - BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 1), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 2), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 3), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1); + REQUIRE(predictedLabels(0, 0) == 0); + REQUIRE(predictedLabels(0, 1) == 1); + REQUIRE(predictedLabels(0, 2) == 0); + REQUIRE(predictedLabels(0, 3) == 0); + REQUIRE(predictedLabels(0, 4) == 1); } /** * This tests the binning function for the case when a dataset with cardinality * of input < inpBucketSize is provided. */ -BOOST_AUTO_TEST_CASE(BinningTesting) +TEST_CASE("BinningTesting", "[DecisionStumpTest]") { const size_t numClasses = 2; const size_t inpBucketSize = 10; @@ -144,7 +141,7 @@ BOOST_AUTO_TEST_CASE(BinningTesting) Row predictedLabels; ds.Classify(testingData, predictedLabels); - BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0); + REQUIRE(predictedLabels(0, 0) == 0); } /** @@ -152,7 +149,7 @@ BOOST_AUTO_TEST_CASE(BinningTesting) * provided. It tests for a perfect split due to the non-overlapping nature of * the input classes. */ -BOOST_AUTO_TEST_CASE(PerfectMultiClassSplit) +TEST_CASE("PerfectMultiClassSplit", "[DecisionStumpTest]") { const size_t numClasses = 4; const size_t inpBucketSize = 3; @@ -174,10 +171,10 @@ BOOST_AUTO_TEST_CASE(PerfectMultiClassSplit) Row predictedLabels; ds.Classify(testingData, predictedLabels); - BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 1), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 2), 2); - BOOST_CHECK_EQUAL(predictedLabels(0, 3), 3); + REQUIRE(predictedLabels(0, 0) == 0); + REQUIRE(predictedLabels(0, 1) == 1); + REQUIRE(predictedLabels(0, 2) == 2); + REQUIRE(predictedLabels(0, 3) == 3); } /** @@ -186,7 +183,7 @@ BOOST_AUTO_TEST_CASE(PerfectMultiClassSplit) * with a reasonable amount of error due to the overlapping nature of input * classes. */ -BOOST_AUTO_TEST_CASE(MultiClassSplit) +TEST_CASE("MultiClassSplit", "[DecisionStumpTest]") { const size_t numClasses = 3; const size_t inpBucketSize = 3; @@ -209,21 +206,21 @@ BOOST_AUTO_TEST_CASE(MultiClassSplit) Row predictedLabels; ds.Classify(testingData, predictedLabels); - BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 1), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 2), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 3), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 5), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 6), 2); - BOOST_CHECK_EQUAL(predictedLabels(0, 7), 2); + REQUIRE(predictedLabels(0, 0) == 0); + REQUIRE(predictedLabels(0, 1) == 0); + REQUIRE(predictedLabels(0, 2) == 1); + REQUIRE(predictedLabels(0, 3) == 1); + REQUIRE(predictedLabels(0, 4) == 1); + REQUIRE(predictedLabels(0, 5) == 1); + REQUIRE(predictedLabels(0, 6) == 2); + REQUIRE(predictedLabels(0, 7) == 2); } /** * This tests that the decision stump can learn a good split on a dataset with * four dimensions that have progressing levels of separation. */ -BOOST_AUTO_TEST_CASE(DimensionSelectionTest) +TEST_CASE("DimensionSelectionTest", "[DecisionStumpTest]") { const size_t numClasses = 2; const size_t inpBucketSize = 2500; @@ -299,16 +296,16 @@ BOOST_AUTO_TEST_CASE(DimensionSelectionTest) DecisionStump<> ds(dataset, labels, numClasses, inpBucketSize); // Make sure it split on the dimension that is most separable. - BOOST_CHECK_EQUAL(ds.SplitDimension(), 1); + REQUIRE(ds.SplitDimension() == 1); // Make sure every bin below -1 classifies as label 0, and every bin above 1 // classifies as label 1 (What happens in [-1, 1] isn't that big a deal.). for (size_t i = 0; i < ds.Split().n_elem; ++i) { if (ds.Split()[i] <= -3.0) - BOOST_CHECK_EQUAL(ds.BinLabels()[i], 0); + REQUIRE(ds.BinLabels()[i] == 0); else if (ds.Split()[i] >= 3.0) - BOOST_CHECK_EQUAL(ds.BinLabels()[i], 1); + REQUIRE(ds.BinLabels()[i] == 1); } } @@ -316,7 +313,7 @@ BOOST_AUTO_TEST_CASE(DimensionSelectionTest) * Ensure that the default constructor works and that it classifies things as 0 * always. */ -BOOST_AUTO_TEST_CASE(EmptyConstructorTest) +TEST_CASE("EmptyConstructorTest", "[DecisionStumpTest]") { DecisionStump<> d; @@ -326,7 +323,7 @@ BOOST_AUTO_TEST_CASE(EmptyConstructorTest) d.Classify(data, labels); for (size_t i = 0; i < 10; ++i) - BOOST_REQUIRE_EQUAL(labels[i], 0); + REQUIRE(labels[i] == 0); // Now train on another dataset and make sure something kind of makes sense. mat trainingData; @@ -347,21 +344,21 @@ BOOST_AUTO_TEST_CASE(EmptyConstructorTest) Row predictedLabels(testingData.n_cols); ds.Classify(testingData, predictedLabels); - BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 1), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 2), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 3), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 5), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 6), 2); - BOOST_CHECK_EQUAL(predictedLabels(0, 7), 2); + REQUIRE(predictedLabels(0, 0) == 0); + REQUIRE(predictedLabels(0, 1) == 0); + REQUIRE(predictedLabels(0, 2) == 1); + REQUIRE(predictedLabels(0, 3) == 1); + REQUIRE(predictedLabels(0, 4) == 1); + REQUIRE(predictedLabels(0, 5) == 1); + REQUIRE(predictedLabels(0, 6) == 2); + REQUIRE(predictedLabels(0, 7) == 2); } /** * Ensure that a matrix holding ints can be trained. The bigger issue here is * just compilation. */ -BOOST_AUTO_TEST_CASE(IntTest) +TEST_CASE("IntTest", "[DecisionStumpTest]") { // Train on a dataset and make sure something kind of makes sense. imat trainingData; @@ -381,20 +378,20 @@ BOOST_AUTO_TEST_CASE(IntTest) arma::Row predictedLabels; ds.Classify(testingData, predictedLabels); - BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 1), 0); - BOOST_CHECK_EQUAL(predictedLabels(0, 2), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 3), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 5), 1); - BOOST_CHECK_EQUAL(predictedLabels(0, 6), 2); - BOOST_CHECK_EQUAL(predictedLabels(0, 7), 2); + REQUIRE(predictedLabels(0, 0) == 0); + REQUIRE(predictedLabels(0, 1) == 0); + REQUIRE(predictedLabels(0, 2) == 1); + REQUIRE(predictedLabels(0, 3) == 1); + REQUIRE(predictedLabels(0, 4) == 1); + REQUIRE(predictedLabels(0, 5) == 1); + REQUIRE(predictedLabels(0, 6) == 2); + REQUIRE(predictedLabels(0, 7) == 2); } /** * Test that DecisionStump::Train() returns finite gain. */ -BOOST_AUTO_TEST_CASE(DecisionStumpTrainReturnEntropy) +TEST_CASE("DecisionStumpTrainReturnEntropy", "[DecisionStumpTest]") { const size_t numClasses = 2; const size_t inpBucketSize = 2; @@ -413,14 +410,12 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTrainReturnEntropy) double gain = ds.Train(trainingData, labelsIn.row(0), numClasses, inpBucketSize); - BOOST_REQUIRE_EQUAL(std::isfinite(gain), true); + REQUIRE(std::isfinite(gain) == true); // Train decision stump with weights. DecisionStump<> wds; gain = wds.Train(trainingData, labelsIn.row(0), weights, numClasses, inpBucketSize); - BOOST_REQUIRE_EQUAL(std::isfinite(gain), true); + REQUIRE(std::isfinite(gain) == true); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/decision_tree_test.cpp b/src/mlpack/tests/decision_tree_test.cpp index f96203cf2d..70d324d197 100644 --- a/src/mlpack/tests/decision_tree_test.cpp +++ b/src/mlpack/tests/decision_tree_test.cpp @@ -16,8 +16,7 @@ #include #include -#include -#include "test_tools.hpp" +#include "catch.hpp" #include "serialization.hpp" #include "mock_categorical_data.hpp" @@ -25,12 +24,10 @@ using namespace mlpack; using namespace mlpack::tree; using namespace mlpack::distribution; -BOOST_AUTO_TEST_SUITE(DecisionTreeTest); - /** * Make sure the Gini gain is zero when the labels are perfect. */ -BOOST_AUTO_TEST_CASE(GiniGainPerfectTest) +TEST_CASE("GiniGainPerfectTest", "[DecisionTreeTest]") { arma::rowvec weights(10, arma::fill::ones); arma::Row labels; @@ -38,14 +35,15 @@ BOOST_AUTO_TEST_CASE(GiniGainPerfectTest) // Test that it's perfect regardless of number of classes. for (size_t c = 1; c < 10; ++c) - BOOST_REQUIRE_SMALL(GiniGain::Evaluate(labels, c, weights), 1e-5); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == + Approx(0.0).margin(1e-7)); } /** * Make sure the Gini gain is -0.5 when the class split between two classes * is even. */ -BOOST_AUTO_TEST_CASE(GiniGainEvenSplitTest) +TEST_CASE("GiniGainEvenSplitTest", "[DecisionTreeTest]") { arma::rowvec weights = arma::ones(10); arma::Row labels(10); @@ -57,35 +55,37 @@ BOOST_AUTO_TEST_CASE(GiniGainEvenSplitTest) // Test that it's -0.5 regardless of the number of classes. for (size_t c = 2; c < 10; ++c) { - BOOST_REQUIRE_CLOSE( - GiniGain::Evaluate(labels, c, weights), -0.5, 1e-5); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == + Approx(-0.5).epsilon(1e-7)); + double weightedGain = GiniGain::Evaluate(labels, c, weights); // The weighted gain should stay the same with unweight one - BOOST_REQUIRE_EQUAL( - GiniGain::Evaluate(labels, c, weights), weightedGain); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == weightedGain); } } /** * The Gini gain of an empty vector is 0. */ -BOOST_AUTO_TEST_CASE(GiniGainEmptyTest) +TEST_CASE("GiniGainEmptyTest", "[DecisionTreeTest]") { arma::rowvec weights = arma::ones(10); // Test across some numbers of classes. arma::Row labels; for (size_t c = 1; c < 10; ++c) - BOOST_REQUIRE_SMALL(GiniGain::Evaluate(labels, c, weights), 1e-5); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == + Approx(0.0).margin(1e-7)); for (size_t c = 1; c < 10; ++c) - BOOST_REQUIRE_SMALL(GiniGain::Evaluate(labels, c, weights), 1e-5); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == + Approx(0.0).margin(1e-7)); } /** * The Gini gain is -(1 - 1/k) for k classes evenly split. */ -BOOST_AUTO_TEST_CASE(GiniGainEvenSplitManyClassTest) +TEST_CASE("GiniGainEvenSplitManyClassTest", "[DecisionTreeTest]") { // Try with many different classes. for (size_t c = 2; c < 30; ++c) @@ -99,17 +99,17 @@ BOOST_AUTO_TEST_CASE(GiniGainEvenSplitManyClassTest) } // Calculate Gini gain and make sure it is correct. - BOOST_REQUIRE_CLOSE(GiniGain::Evaluate(labels, c, weights), - -(1.0 - 1.0 / c), 1e-5); - BOOST_REQUIRE_CLOSE(GiniGain::Evaluate(labels, c, weights), - -(1.0 - 1.0 / c), 1e-5); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == + Approx(-(1.0 - 1.0 / c)).epsilon(1e-7)); + REQUIRE(GiniGain::Evaluate(labels, c, weights) == + Approx(-(1.0 - 1.0 / c)).epsilon(1e-7)); } } /** * The Gini gain should not be sensitive to the number of points. */ -BOOST_AUTO_TEST_CASE(GiniGainManyPoints) +TEST_CASE("GiniGainManyPoints", "[DecisionTreeTest]") { for (size_t i = 1; i < 20; ++i) { @@ -121,11 +121,10 @@ BOOST_AUTO_TEST_CASE(GiniGainManyPoints) labels[j] = 0; for (size_t j = numPoints / 2; j < numPoints; ++j) labels[j] = 1; - - BOOST_REQUIRE_CLOSE(GiniGain::Evaluate(labels, 2, weights), -0.5, - 1e-5); - BOOST_REQUIRE_CLOSE(GiniGain::Evaluate(labels, 2, weights), -0.5, - 1e-5); + REQUIRE(GiniGain::Evaluate(labels, 2, weights) == + Approx(-0.5).epsilon(1e-7)); + REQUIRE(GiniGain::Evaluate(labels, 2, weights) == + Approx(-0.5).epsilon(1e-7)); } } @@ -133,7 +132,7 @@ BOOST_AUTO_TEST_CASE(GiniGainManyPoints) /** * To make sure the Gini gain can been cacluate proporately with weight. */ -BOOST_AUTO_TEST_CASE(GiniGainWithWeight) +TEST_CASE("GiniGainWithWeight", "[DecisionTreeTest]") { arma::Row labels(10); arma::rowvec weights(10); @@ -148,14 +147,14 @@ BOOST_AUTO_TEST_CASE(GiniGainWithWeight) weights[i] = 0.7; } - BOOST_REQUIRE_CLOSE( - GiniGain::Evaluate(labels, 2, weights), -0.42, 1e-5); + REQUIRE(GiniGain::Evaluate(labels, 2, weights) == + Approx(-0.42).epsilon(1e-7)); } /** * The information gain should be zero when the labels are perfect. */ -BOOST_AUTO_TEST_CASE(InformationGainPerfectTest) +TEST_CASE("InformationGainPerfectTest", "[DecisionTreeTest]") { arma::rowvec weights; arma::Row labels; @@ -164,15 +163,15 @@ BOOST_AUTO_TEST_CASE(InformationGainPerfectTest) // Test that it's perfect regardless of number of classes. for (size_t c = 1; c < 10; ++c) { - BOOST_REQUIRE_SMALL( - InformationGain::Evaluate(labels, c, weights), 1e-5); + REQUIRE(InformationGain::Evaluate(labels, c, weights) == + Approx(0.0).margin(1e-5)); } } /** * If we have an even split, the information gain should be -1. */ -BOOST_AUTO_TEST_CASE(InformationGainEvenSplitTest) +TEST_CASE("InformationGainEvenSplitTest", "[DecisionTreeTest]") { arma::Row labels(10); arma::rowvec weights(10); @@ -186,33 +185,33 @@ BOOST_AUTO_TEST_CASE(InformationGainEvenSplitTest) for (size_t c = 2; c < 10; ++c) { // Weighted and unweighted result should be the same. - BOOST_REQUIRE_CLOSE(InformationGain::Evaluate(labels, c, weights), - -1.0, 1e-5); - BOOST_REQUIRE_CLOSE(InformationGain::Evaluate(labels, c, weights), - -1.0, 1e-5); + REQUIRE(InformationGain::Evaluate(labels, c, weights) == + Approx(-1.0).epsilon(1e-7)); + REQUIRE(InformationGain::Evaluate(labels, c, weights) == + Approx(-1.0).epsilon(1e-7)); } } /** * The information gain of an empty vector is 0. */ -BOOST_AUTO_TEST_CASE(InformationGainEmptyTest) +TEST_CASE("InformationGainEmptyTest", "[DecisionTreeTest]") { arma::Row labels; arma::rowvec weights = arma::ones(10); for (size_t c = 1; c < 10; ++c) { - BOOST_REQUIRE_SMALL(InformationGain::Evaluate(labels, c, weights), - 1e-5); - BOOST_REQUIRE_SMALL(InformationGain::Evaluate(labels, c, weights), - 1e-5); + REQUIRE(InformationGain::Evaluate(labels, c, weights) == + Approx(0.0).margin(1e-7)); + REQUIRE(InformationGain::Evaluate(labels, c, weights) == + Approx(0.0).margin(1e-7)); } } /** * The information gain is log2(1/k) when splitting equal classes. */ -BOOST_AUTO_TEST_CASE(InformationGainEvenSplitManyClassTest) +TEST_CASE("InformationGainEvenSplitManyClassTest", "[DecisionTreeTest]") { arma::rowvec weights; // Try with many different numbers of classes. @@ -223,15 +222,15 @@ BOOST_AUTO_TEST_CASE(InformationGainEvenSplitManyClassTest) labels[i] = i; // Calculate information gain and make sure it is correct. - BOOST_REQUIRE_CLOSE(InformationGain::Evaluate(labels, c, weights), - std::log2(1.0 / c), 1e-5); + REQUIRE(InformationGain::Evaluate(labels, c, weights) == + Approx(std::log2(1.0 / c)).epsilon(1e-7)); } } /** * Test the information gain with weighted labels */ -BOOST_AUTO_TEST_CASE(InformationWithWeight) +TEST_CASE("InformationWithWeight", "[DecisionTreeTest]") { arma::Row labels(10); arma::rowvec weights("1 1 1 1 1 0 0 0 0 0"); @@ -242,15 +241,15 @@ BOOST_AUTO_TEST_CASE(InformationWithWeight) // Zero is not a good result as gain, but we just need to prove // cacluation works. - BOOST_REQUIRE_CLOSE( - InformationGain::Evaluate(labels, 2, weights), 0, 1e-5); + REQUIRE(InformationGain::Evaluate(labels, 2, weights) == + Approx(0).epsilon(1e-7)); } /** * The information gain should not be sensitive to the number of points. */ -BOOST_AUTO_TEST_CASE(InformationGainManyPoints) +TEST_CASE("InformationGainManyPoints", "[DecisionTreeTest]") { for (size_t i = 1; i < 20; ++i) { @@ -262,12 +261,13 @@ BOOST_AUTO_TEST_CASE(InformationGainManyPoints) for (size_t j = numPoints / 2; j < numPoints; ++j) labels[j] = 1; - BOOST_REQUIRE_CLOSE(InformationGain::Evaluate(labels, 2, weights), - -1.0, 1e-5); + REQUIRE(InformationGain::Evaluate(labels, 2, weights) == + Approx(-1.0).epsilon(1e-7)); + // It should make no difference between a weighted and unweighted // calculation. - BOOST_REQUIRE_CLOSE(InformationGain::Evaluate(labels, 2, weights), - -1.0, 1e-5); + REQUIRE(InformationGain::Evaluate(labels, 2, weights) == + Approx(-1.0).epsilon(1e-7)); } } @@ -275,7 +275,7 @@ BOOST_AUTO_TEST_CASE(InformationGainManyPoints) * Check that the BestBinaryNumericSplit will split on an obviously splittable * dimension. */ -BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitSimpleSplitTest) +TEST_CASE("BestBinaryNumericSplitSimpleSplitTest", "[DecisionTreeTest]") { arma::vec values("0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0"); arma::Row labels("0 0 0 0 0 1 1 1 1 1 1"); @@ -295,26 +295,26 @@ BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitSimpleSplitTest) labels, 2, weights, 3, 1e-7, classProbabilities, aux); // Make sure that a split was made. - BOOST_REQUIRE_GT(gain, bestGain); + REQUIRE(gain > bestGain); // Make sure weight works and is not different than the unweighted one. - BOOST_REQUIRE_EQUAL(gain, weightedGain); + REQUIRE(gain == weightedGain); // The split is perfect, so we should be able to accomplish a gain of 0. - BOOST_REQUIRE_SMALL(gain, 1e-5); + REQUIRE(gain == Approx(0.0).margin(1e-7)); // The class probabilities, for this split, hold the splitting point, which // should be between 4 and 5. - BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 1); - BOOST_REQUIRE_GT(classProbabilities[0], 0.4); - BOOST_REQUIRE_LT(classProbabilities[0], 0.5); + REQUIRE(classProbabilities.n_elem == 1); + REQUIRE(classProbabilities[0] > 0.4); + REQUIRE(classProbabilities[0] < 0.5); } /** * Check that the BestBinaryNumericSplit won't split if not enough points are * given. */ -BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitMinSamplesTest) +TEST_CASE("BestBinaryNumericSplitMinSamplesTest", "[DecisionTreeTest]") { arma::vec values("0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0"); arma::Row labels("0 0 0 0 0 1 1 1 1 1 1"); @@ -334,16 +334,16 @@ BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitMinSamplesTest) labels, 2, weights, 8, 1e-7, classProbabilities, aux); // Make sure that no split was made. - BOOST_REQUIRE_EQUAL(gain, DBL_MAX); - BOOST_REQUIRE_EQUAL(gain, weightedGain); - BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0); + REQUIRE(gain == DBL_MAX); + REQUIRE(gain == weightedGain); + REQUIRE(classProbabilities.n_elem == 0); } /** * Check that the BestBinaryNumericSplit doesn't split a dimension that gives no * gain. */ -BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitNoGainTest) +TEST_CASE("BestBinaryNumericSplitNoGainTest", "[DecisionTreeTest]") { arma::vec values(100); arma::Row labels(100); @@ -366,15 +366,15 @@ BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitNoGainTest) aux); // Make sure there was no split. - BOOST_REQUIRE_EQUAL(gain, DBL_MAX); - BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0); + REQUIRE(gain == DBL_MAX); + REQUIRE(classProbabilities.n_elem == 0); } /** * Check that the AllCategoricalSplit will split when the split is obviously * better. */ -BOOST_AUTO_TEST_CASE(AllCategoricalSplitSimpleSplitTest) +TEST_CASE("AllCategoricalSplitSimpleSplitTest", "[DecisionTreeTest]") { arma::vec values("0 0 0 1 1 1 2 2 2 3 3 3"); arma::Row labels("0 0 0 2 2 2 1 1 1 2 2 2"); @@ -394,23 +394,23 @@ BOOST_AUTO_TEST_CASE(AllCategoricalSplitSimpleSplitTest) labels, 3, weights, 3, 1e-7, classProbabilities, aux); // Make sure that a split was made. - BOOST_REQUIRE_GT(gain, bestGain); + REQUIRE(gain > bestGain); // Since the split is perfect, make sure the new gain is 0. - BOOST_REQUIRE_SMALL(gain, 1e-5); + REQUIRE(gain == Approx(0.0).margin(1e-7)); - BOOST_REQUIRE_EQUAL(gain, weightedGain); + REQUIRE(gain == weightedGain); // Make sure the class probabilities now hold the number of children. - BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 1); - BOOST_REQUIRE_EQUAL((size_t) classProbabilities[0], 4); + REQUIRE(classProbabilities.n_elem == 1); + REQUIRE((size_t) classProbabilities[0] == 4); } /** * Make sure that AllCategoricalSplit respects the minimum number of samples * required to split. */ -BOOST_AUTO_TEST_CASE(AllCategoricalSplitMinSamplesTest) +TEST_CASE("AllCategoricalSplitMinSamplesTest", "[DecisionTreeTest]") { arma::vec values("0 0 0 1 1 1 2 2 2 3 3 3"); arma::Row labels("0 0 0 2 2 2 1 1 1 2 2 2"); @@ -427,14 +427,14 @@ BOOST_AUTO_TEST_CASE(AllCategoricalSplitMinSamplesTest) aux); // Make sure it's not split. - BOOST_REQUIRE_EQUAL(gain, DBL_MAX); - BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0); + REQUIRE(gain == DBL_MAX); + REQUIRE(classProbabilities.n_elem == 0); } /** * Check that no split is made when it doesn't get us anything. */ -BOOST_AUTO_TEST_CASE(AllCategoricalSplitNoGainTest) +TEST_CASE("AllCategoricalSplitNoGainTest", "[DecisionTreeTest]") { arma::vec values(300); arma::Row labels(300); @@ -463,16 +463,16 @@ BOOST_AUTO_TEST_CASE(AllCategoricalSplitNoGainTest) labels, 3, weights, 10, 1e-7, classProbabilities, aux); // Make sure that there was no split. - BOOST_REQUIRE_EQUAL(gain, DBL_MAX); - BOOST_REQUIRE_EQUAL(gain, weightedGain); - BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0); + REQUIRE(gain == DBL_MAX); + REQUIRE(gain == weightedGain); + REQUIRE(classProbabilities.n_elem == 0); } /** * A basic construction of the decision tree---ensure that we can create the * tree and that it split at least once. */ -BOOST_AUTO_TEST_CASE(BasicConstructionTest) +TEST_CASE("BasicConstructionTest", "[DecisionTreeTest]") { arma::mat dataset(10, 100, arma::fill::randu); arma::Row labels(100); @@ -491,13 +491,13 @@ BOOST_AUTO_TEST_CASE(BasicConstructionTest) DecisionTree<> d(dataset, labels, 2, 10); // Now require that we have some children. - BOOST_REQUIRE_GT(d.NumChildren(), 0); + REQUIRE(d.NumChildren() > 0); } /** * Construct a tree with weighted labels. */ -BOOST_AUTO_TEST_CASE(BasicConstructionTestWithWeight) +TEST_CASE("BasicConstructionTestWithWeight", "[DecisionTreeTest]") { arma::mat dataset(10, 100, arma::fill::randu); arma::Row labels(100); @@ -519,15 +519,15 @@ BOOST_AUTO_TEST_CASE(BasicConstructionTestWithWeight) DecisionTree<> d(dataset, labels, 2, 10); // Now require that we have some children. - BOOST_REQUIRE_GT(wd.NumChildren(), 0); - BOOST_REQUIRE_EQUAL(wd.NumChildren(), d.NumChildren()); + REQUIRE(wd.NumChildren() > 0); + REQUIRE(wd.NumChildren() == d.NumChildren()); } /** * Construct the decision tree on numeric data only and see that we can fit it * exactly and achieve perfect performance on the training set. */ -BOOST_AUTO_TEST_CASE(PerfectTrainingSet) +TEST_CASE("PerfectTrainingSet", "[DecisionTreeTest]") { arma::mat dataset(10, 100, arma::fill::randu); arma::Row labels(100); @@ -551,14 +551,14 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSet) arma::vec probabilities; d.Classify(dataset.col(i), prediction, probabilities); - BOOST_REQUIRE_EQUAL(prediction, labels[i]); - BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2); + REQUIRE(prediction == labels[i]); + REQUIRE(probabilities.n_elem == 2); for (size_t j = 0; j < 2; ++j) { if (labels[i] == j) - BOOST_REQUIRE_CLOSE(probabilities[j], 1.0, 1e-5); + REQUIRE(probabilities[j] == Approx(1.0).epsilon(1e-7)); else - BOOST_REQUIRE_SMALL(probabilities[j], 1e-5); + REQUIRE(probabilities[j] == Approx(0.0).margin(1e-7)); } } } @@ -566,7 +566,7 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSet) /** * Construct the decision tree with weighted labels */ -BOOST_AUTO_TEST_CASE(PerfectTrainingSetWithWeight) +TEST_CASE("PerfectTrainingSetWithWeight", "[DecisionTreeTest]") { // Completely random dataset with no structure. arma::mat dataset(10, 100, arma::fill::randu); @@ -594,14 +594,14 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSetWithWeight) arma::vec probabilities; d.Classify(dataset.col(i), prediction, probabilities); - BOOST_REQUIRE_EQUAL(prediction, labels[i]); - BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2); + REQUIRE(prediction == labels[i]); + REQUIRE(probabilities.n_elem == 2); for (size_t j = 0; j < 2; ++j) { if (labels[i] == j) - BOOST_REQUIRE_CLOSE(probabilities[j], 1.0, 1e-5); + REQUIRE(probabilities[j] == Approx(1.0).epsilon(1e-7)); else - BOOST_REQUIRE_SMALL(probabilities[j], 1e-5); + REQUIRE(probabilities[j] == Approx(0.0).margin(1e-7)); } } } @@ -610,7 +610,7 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSetWithWeight) /** * Make sure class probabilities are computed correctly in the root node. */ -BOOST_AUTO_TEST_CASE(ClassProbabilityTest) +TEST_CASE("ClassProbabilityTest", "[DecisionTreeTest]") { arma::mat dataset(5, 100, arma::fill::randu); arma::Row labels(100); @@ -623,30 +623,30 @@ BOOST_AUTO_TEST_CASE(ClassProbabilityTest) // Create a decision tree that can't split. DecisionTree<> d(dataset, labels, 2, 1000); - BOOST_REQUIRE_EQUAL(d.NumChildren(), 0); + REQUIRE(d.NumChildren() == 0); // Estimate a point's probabilities. arma::vec probabilities; size_t prediction; d.Classify(dataset.col(0), prediction, probabilities); - BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2); - BOOST_REQUIRE_CLOSE(probabilities[0], 0.5, 1e-5); - BOOST_REQUIRE_CLOSE(probabilities[1], 0.5, 1e-5); + REQUIRE(probabilities.n_elem == 2); + REQUIRE(probabilities[0] == Approx(0.5).epsilon(1e-7)); + REQUIRE(probabilities[1] == Approx(0.5).epsilon(1e-7)); } /** * Test that the decision tree generalizes reasonably. */ -BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest) +TEST_CASE("SimpleGeneralizationTest", "[DecisionTreeTest]") { arma::mat inputData; if (!data::Load("vc2.csv", inputData)) - BOOST_FAIL("Cannot load test dataset vc2.csv!"); + FAIL("Cannot load test dataset vc2.csv!"); arma::Row labels; if (!data::Load("vc2_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for vc2_labels.txt"); + FAIL("Cannot load labels for vc2_labels.txt"); // Initialize an all-ones weight matrix. arma::rowvec weights(labels.n_cols, arma::fill::ones); @@ -658,17 +658,17 @@ BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest) // Load testing data. arma::mat testData; if (!data::Load("vc2_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset vc2_test.csv!"); + FAIL("Cannot load test dataset vc2_test.csv!"); arma::Mat trueTestLabels; if (!data::Load("vc2_test_labels.txt", trueTestLabels)) - BOOST_FAIL("Cannot load labels for vc2_test_labels.txt"); + FAIL("Cannot load labels for vc2_test_labels.txt"); // Get the predicted test labels. arma::Row predictions; d.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); // Figure out the accuracy. double correct = 0.0; @@ -677,13 +677,13 @@ BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest) ++correct; correct /= predictions.n_elem; - BOOST_REQUIRE_GT(correct, 0.75); + REQUIRE(correct > 0.75); // reset the prediction predictions.zeros(); wd.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); // Figure out the accuracy. double wdcorrect = 0.0; @@ -692,13 +692,13 @@ BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest) ++wdcorrect; wdcorrect /= predictions.n_elem; - BOOST_REQUIRE_GT(wdcorrect, 0.75); + REQUIRE(wdcorrect > 0.75); } /** * Test that we can build a decision tree on a simple categorical dataset. */ -BOOST_AUTO_TEST_CASE(CategoricalBuildTest) +TEST_CASE("CategoricalBuildTest", "[DecisionTreeTest]") { arma::mat d; arma::Row l; @@ -718,7 +718,7 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTest) arma::Row predictions; tree.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); size_t correct = 0; for (size_t i = 0; i < testData.n_cols; ++i) if (testLabels[i] == predictions[i]) @@ -726,14 +726,14 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTest) // Make sure we got at least 70% accuracy. const double correctPct = double(correct) / double(testData.n_cols); - BOOST_REQUIRE_GT(correctPct, 0.70); + REQUIRE(correctPct > 0.70); } /** * Test that we can build a decision tree with weights on a simple categorical * dataset. */ -BOOST_AUTO_TEST_CASE(CategoricalBuildTestWithWeight) +TEST_CASE("CategoricalBuildTestWithWeight", "[DecisionTreeTest]") { arma::mat d; arma::Row l; @@ -756,7 +756,7 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTestWithWeight) arma::Row predictions; tree.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); size_t correct = 0; for (size_t i = 0; i < testData.n_cols; ++i) if (testLabels[i] == predictions[i]) @@ -764,13 +764,13 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTestWithWeight) // Make sure we got at least 70% accuracy. const double correctPct = double(correct) / double(testData.n_cols); - BOOST_REQUIRE_GT(correctPct, 0.70); + REQUIRE(correctPct > 0.70); } /** * Make sure that when we ask for a decision stump, we get one. */ -BOOST_AUTO_TEST_CASE(DecisionStumpTest) +TEST_CASE("DecisionStumpTest", "[DecisionTreeTest]") { // Use a random dataset. arma::mat dataset(10, 1000, arma::fill::randu); @@ -783,10 +783,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTest) AllDimensionSelect, double, true> stump(dataset, labels, 3, 1); // Check that it has children. - BOOST_REQUIRE_EQUAL(stump.NumChildren(), 2); + REQUIRE(stump.NumChildren() == 2); // Check that its children doesn't have children. - BOOST_REQUIRE_EQUAL(stump.Child(0).NumChildren(), 0); - BOOST_REQUIRE_EQUAL(stump.Child(1).NumChildren(), 0); + REQUIRE(stump.Child(0).NumChildren() == 0); + REQUIRE(stump.Child(1).NumChildren() == 0); } /** @@ -794,7 +794,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTest) * low-weighted data is random noise), and that the tree still builds correctly * enough to get good results. */ -BOOST_AUTO_TEST_CASE(WeightedDecisionTreeTest) +TEST_CASE("WeightedDecisionTreeTest", "[DecisionTreeTest]") { arma::mat dataset; arma::Row labels; @@ -830,7 +830,7 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeTest) arma::Row predictions; d.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); // Figure out the accuracy. double correct = 0.0; @@ -839,13 +839,13 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeTest) ++correct; correct /= predictions.n_elem; - BOOST_REQUIRE_GT(correct, 0.75); + REQUIRE(correct > 0.75); } /** * Test that we can build a decision tree on a simple categorical dataset using * weights, with low-weight noise added. */ -BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest) +TEST_CASE("CategoricalWeightedBuildTest", "[DecisionTreeTest]") { arma::mat d; arma::Row l; @@ -887,7 +887,7 @@ BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest) arma::Row predictions; tree.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); size_t correct = 0; for (size_t i = 0; i < testData.n_cols; ++i) if (testLabels[i] == predictions[i]) @@ -895,7 +895,7 @@ BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest) // Make sure we got at least 70% accuracy. const double correctPct = double(correct) / double(testData.n_cols); - BOOST_REQUIRE_GT(correctPct, 0.70); + REQUIRE(correctPct > 0.70); } /** @@ -903,7 +903,7 @@ BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest) * low-weighted data is random noise) with information gain, and that the tree * still builds correctly enough to get good results. */ -BOOST_AUTO_TEST_CASE(WeightedDecisionTreeInformationGainTest) +TEST_CASE("WeightedDecisionTreeInformationGainTest", "[DecisionTreeTest]") { arma::mat dataset; arma::Row labels; @@ -939,7 +939,7 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeInformationGainTest) arma::Row predictions; d.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); // Figure out the accuracy. double correct = 0.0; @@ -948,13 +948,13 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeInformationGainTest) ++correct; correct /= predictions.n_elem; - BOOST_REQUIRE_GT(correct, 0.75); + REQUIRE(correct > 0.75); } /** * Test that we can build a decision tree using information gain on a simple * categorical dataset using weights, with low-weight noise added. */ -BOOST_AUTO_TEST_CASE(CategoricalInformationGainWeightedBuildTest) +TEST_CASE("CategoricalInformationGainWeightedBuildTest", "[DecisionTreeTest]") { arma::mat d; arma::Row l; @@ -996,7 +996,7 @@ BOOST_AUTO_TEST_CASE(CategoricalInformationGainWeightedBuildTest) arma::Row predictions; tree.Classify(testData, predictions); - BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols); + REQUIRE(predictions.n_elem == testData.n_cols); size_t correct = 0; for (size_t i = 0; i < testData.n_cols; ++i) if (testLabels[i] == predictions[i]) @@ -1004,27 +1004,27 @@ BOOST_AUTO_TEST_CASE(CategoricalInformationGainWeightedBuildTest) // Make sure we got at least 70% accuracy. const double correctPct = double(correct) / double(testData.n_cols); - BOOST_REQUIRE_GT(correctPct, 0.70); + REQUIRE(correctPct > 0.70); } /** * Make sure that the random dimension selector only has one element. */ -BOOST_AUTO_TEST_CASE(RandomDimensionSelectTest) +TEST_CASE("RandomDimensionSelectTest", "[DecisionTreeTest]") { RandomDimensionSelect r; r.Dimensions() = 10; - BOOST_REQUIRE_LT(r.Begin(), 10); - BOOST_REQUIRE_EQUAL(r.Next(), r.End()); - BOOST_REQUIRE_EQUAL(r.Next(), r.End()); - BOOST_REQUIRE_EQUAL(r.Next(), r.End()); + REQUIRE(r.Begin() < 10); + REQUIRE(r.Next() == r.End()); + REQUIRE(r.Next() == r.End()); + REQUIRE(r.Next() == r.End()); } /** * Make sure that the random dimension selector selects different values. */ -BOOST_AUTO_TEST_CASE(RandomDimensionSelectRandomTest) +TEST_CASE("RandomDimensionSelectRandomTest", "[DecisionTreeTest]") { // We'll check that 4 values are not all the same. RandomDimensionSelect r1, r2, r3, r4; @@ -1033,33 +1033,33 @@ BOOST_AUTO_TEST_CASE(RandomDimensionSelectRandomTest) r3.Dimensions() = 100000; r4.Dimensions() = 100000; - BOOST_REQUIRE((r1.Begin() != r2.Begin()) || - (r1.Begin() != r3.Begin()) || - (r1.Begin() != r4.Begin())); + REQUIRE(((r1.Begin() != r2.Begin()) || + (r1.Begin() != r3.Begin()) || + (r1.Begin() != r4.Begin()))); } /** * Make sure that the multiple random dimension select only has the right number * of elements. */ -BOOST_AUTO_TEST_CASE(MultipleRandomDimensionSelectTest) +TEST_CASE("MultipleRandomDimensionSelectTest", "[DecisionTreeTest]") { MultipleRandomDimensionSelect r(5); r.Dimensions() = 10; // Make sure we get five elements. - BOOST_REQUIRE_LT(r.Begin(), 10); - BOOST_REQUIRE_LT(r.Next(), 10); - BOOST_REQUIRE_LT(r.Next(), 10); - BOOST_REQUIRE_LT(r.Next(), 10); - BOOST_REQUIRE_LT(r.Next(), 10); - BOOST_REQUIRE_EQUAL(r.Next(), r.End()); + REQUIRE(r.Begin() < 10); + REQUIRE(r.Next() < 10); + REQUIRE(r.Next() < 10); + REQUIRE(r.Next() < 10); + REQUIRE(r.Next() < 10); + REQUIRE(r.Next() == r.End()); } /** * Make sure we get every element from the distribution. */ -BOOST_AUTO_TEST_CASE(MultipleRandomDimensionAllSelectTest) +TEST_CASE("MultipleRandomDimensionAllSelectTest", "[DecisionTreeTest]") { MultipleRandomDimensionSelect r(3); r.Dimensions() = 3; @@ -1071,24 +1071,24 @@ BOOST_AUTO_TEST_CASE(MultipleRandomDimensionAllSelectTest) found[r.Next()] = true; found[r.Next()] = true; - BOOST_REQUIRE_EQUAL(found[0], true); - BOOST_REQUIRE_EQUAL(found[1], true); - BOOST_REQUIRE_EQUAL(found[2], true); + REQUIRE(found[0] == true); + REQUIRE(found[1] == true); + REQUIRE(found[2] == true); } /** * Make sure the right number of classes is returned for an empty tree (1). */ -BOOST_AUTO_TEST_CASE(NumClassesEmptyTreeTest) +TEST_CASE("NumClassesEmptyTreeTest", "[DecisionTreeTest]") { DecisionTree<> dt; - BOOST_REQUIRE_EQUAL(dt.NumClasses(), 1); + REQUIRE(dt.NumClasses() == 1); } /** * Make sure the right number of classes is returned for a nonempty tree. */ -BOOST_AUTO_TEST_CASE(NumClassesTest) +TEST_CASE("NumClassesTest", "[DecisionTreeTest]") { // Load a dataset to train with. arma::mat dataset; @@ -1098,13 +1098,13 @@ BOOST_AUTO_TEST_CASE(NumClassesTest) DecisionTree<> dt(dataset, labels, 3); - BOOST_REQUIRE_EQUAL(dt.NumClasses(), 3); + REQUIRE(dt.NumClasses() == 3); } /* * Test that we can pass const data into DecisionTree constructors. */ -BOOST_AUTO_TEST_CASE(ConstDataTest) +TEST_CASE("ConstDataTest", "[DecisionTreeTest]") { arma::mat data; arma::Row labels; @@ -1127,7 +1127,7 @@ BOOST_AUTO_TEST_CASE(ConstDataTest) * Construct the decision tree with splitting only if gain is more than * threshold. */ -BOOST_AUTO_TEST_CASE(RegularisedDecisionTree) +TEST_CASE("RegularisedDecisionTree", "[DecisionTreeTest]") { // Completely random dataset with no structure. arma::mat dataset(10, 1000, arma::fill::randu); @@ -1157,17 +1157,17 @@ BOOST_AUTO_TEST_CASE(RegularisedDecisionTree) if (prediction != predictionsregularised) count++; - BOOST_REQUIRE_EQUAL(probabilities.n_elem, 3); - BOOST_REQUIRE_EQUAL(probabilitiesRegularised.n_elem, 3); + REQUIRE(probabilities.n_elem == 3); + REQUIRE(probabilitiesRegularised.n_elem == 3); } - BOOST_REQUIRE_GT(count, 0); + REQUIRE(count > 0); } /** * Test that DecisionTree::Train() returns finite entropy on numeric dataset. */ -BOOST_AUTO_TEST_CASE(DecisionTreeNumericTrainReturnEntropy) +TEST_CASE("DecisionTreeNumericTrainReturnEntropy", "[DecisionTreeTest]") { arma::mat dataset(10, 1000, arma::fill::randu); arma::Row labels(1000); @@ -1181,20 +1181,20 @@ BOOST_AUTO_TEST_CASE(DecisionTreeNumericTrainReturnEntropy) DecisionTree<> d(3); double entropy = d.Train(dataset, labels, 3, 50); - BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true); + REQUIRE(std::isfinite(entropy) == true); // Train a tree with weights on numeric dataset. DecisionTree<> wd(3); entropy = wd.Train(dataset, labels, 3, weights, 50); - BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true); + REQUIRE(std::isfinite(entropy) == true); } /** * Test that DecisionTree::Train() returns finite entropy on categorical * dataset. */ -BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalTrainReturnEntropy) +TEST_CASE("DecisionTreeCategoricalTrainReturnEntropy", "[DecisionTreeTest]") { arma::mat d; arma::Row l; @@ -1207,19 +1207,19 @@ BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalTrainReturnEntropy) DecisionTree<> dtree(5); double entropy = dtree.Train(d, di, l, 5, 10); - BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true); + REQUIRE(std::isfinite(entropy) == true); // Train a tree with weights on categorical dataset. DecisionTree<> wdtree(5); entropy = wdtree.Train(d, di, l, 5, weights, 10); - BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true); + REQUIRE(std::isfinite(entropy) == true); } /** * Make sure different maximum depth values give different numbers of children. */ -BOOST_AUTO_TEST_CASE(DifferentMaximumDepthTest) +TEST_CASE("DifferentMaximumDepthTest", "[DecisionTreeTest]") { arma::mat dataset; arma::Row labels; @@ -1233,17 +1233,15 @@ BOOST_AUTO_TEST_CASE(DifferentMaximumDepthTest) DecisionTree<> d2(dataset, labels, 3, 10, 1e-7); // Now require that we have zero children. - BOOST_REQUIRE_EQUAL(d.NumChildren(), 0); + REQUIRE(d.NumChildren() == 0); // Now require that we have two children. - BOOST_REQUIRE_EQUAL(d1.NumChildren(), 2); - BOOST_REQUIRE_EQUAL(d1.Child(0).NumChildren(), 0); - BOOST_REQUIRE_EQUAL(d1.Child(1).NumChildren(), 0); + REQUIRE(d1.NumChildren() == 2); + REQUIRE(d1.Child(0).NumChildren() == 0); + REQUIRE(d1.Child(1).NumChildren() == 0); // Now require that we have two children. - BOOST_REQUIRE_EQUAL(d2.NumChildren(), 2); - BOOST_REQUIRE_EQUAL(d2.Child(0).NumChildren(), 2); - BOOST_REQUIRE_EQUAL(d2.Child(1).NumChildren(), 2); + REQUIRE(d2.NumChildren() == 2); + REQUIRE(d2.Child(0).NumChildren() == 2); + REQUIRE(d2.Child(1).NumChildren() == 2); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/main_tests/decision_stump_test.cpp b/src/mlpack/tests/main_tests/decision_stump_test.cpp index 8f6c77f05b..8919a7b973 100644 --- a/src/mlpack/tests/main_tests/decision_stump_test.cpp +++ b/src/mlpack/tests/main_tests/decision_stump_test.cpp @@ -18,8 +18,8 @@ static const std::string testName = "DecisionStump"; #include #include "test_helper.hpp" -#include -#include "../test_tools.hpp" +#include "../test_catch_tools.hpp" +#include "../catch.hpp" using namespace mlpack; @@ -40,17 +40,16 @@ struct DecisionStumpTestFixture } }; -BOOST_FIXTURE_TEST_SUITE(DecisionStumpMainTest, DecisionStumpTestFixture); - /** * Ensure that we get desired dimensions when both training * data and labels are passed. */ -BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest) +TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpOutputDimensionTest", + "[DecisionStumpMainTest][BindingTests]") { arma::mat inputData; if (!data::Load("trainSet.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + FAIL("Cannot load train dataset trainSet.csv!"); // Get the labels out. arma::Row labels(inputData.n_cols); @@ -62,7 +61,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest) arma::mat testData; if (!data::Load("testSet.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + FAIL("Cannot load test dataset testSet.csv!"); // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); @@ -79,12 +78,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); // Check prediction have only single row. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_rows, - 1); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); } /** @@ -92,12 +89,14 @@ BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest) * when labels are not passed specifically and results * are same from both label and labeless models. */ -BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest) +TEST_CASE_METHOD(DecisionStumpTestFixture, + "DecisionStumpLabelsLessDimensionTest", + "[DecisionStumpMainTest][BindingTests]") { // Train DS without providing labels. arma::mat inputData; if (!data::Load("trainSet.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + FAIL("Cannot load train dataset trainSet.csv!"); // Get the labels out. arma::Row labels(inputData.n_cols); @@ -106,7 +105,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest) arma::mat testData; if (!data::Load("testSet.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + FAIL("Cannot load test dataset testSet.csv!"); // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); @@ -122,12 +121,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); // Check prediction have only single row. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_rows, - 1); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); // Reset data passed. IO::GetSingleton().Parameters()["training"].wasPassed = false; @@ -154,12 +151,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); // Check prediction have only single row. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_rows, - 1); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); // Check that initial output and final output matrix // from two models are same. @@ -169,15 +164,16 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest) /** * Ensure that saved model can be used again. */ -BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest) +TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpModelReuseTest", + "[DecisionStumpMainTest][BindingTests]") { arma::mat inputData; if (!data::Load("trainSet.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + FAIL("Cannot load train dataset trainSet.csv!"); arma::mat testData; if (!data::Load("testSet.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + FAIL("Cannot load test dataset testSet.csv!"); // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); @@ -207,12 +203,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); // Check predictions have only single row. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_rows, - 1); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); // Check that initial predictions and final predicitons matrix // using saved model are same. @@ -222,29 +216,31 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest) /** * Ensure that bucket_size is always positive. */ -BOOST_AUTO_TEST_CASE(DecisionStumpBucketSizeTest) +TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpBucketSizeTest", + "[DecisionStumpMainTest][BindingTests]") { arma::mat inputData; if (!data::Load("trainSet.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + FAIL("Cannot load train dataset trainSet.csv!"); // Input training data. SetInputParam("training", std::move(inputData)); SetInputParam("bucket_size", (int) 0); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Make sure only one of training data or pre-trained model is passed. */ -BOOST_AUTO_TEST_CASE(DecisionStumpTrainingVerTest) +TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpTrainingVerTest", + "[DecisionStumpMainTest][BindingTests]") { arma::mat inputData; if (!data::Load("trainSet.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + FAIL("Cannot load train dataset trainSet.csv!"); // Input training data. SetInputParam("training", std::move(inputData)); @@ -256,8 +252,6 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTrainingVerTest) std::move(IO::GetParam("output_model"))); 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/main_tests/decision_tree_test.cpp b/src/mlpack/tests/main_tests/decision_tree_test.cpp index e833d46217..a7c7ae9fa4 100644 --- a/src/mlpack/tests/main_tests/decision_tree_test.cpp +++ b/src/mlpack/tests/main_tests/decision_tree_test.cpp @@ -18,8 +18,8 @@ static const std::string testName = "DecisionTree"; #include #include "test_helper.hpp" -#include -#include "../test_tools.hpp" +#include "../test_catch_tools.hpp" +#include "../catch.hpp" using namespace mlpack; using namespace data; @@ -47,30 +47,28 @@ void ResetDTSettings() IO::RestoreSettings(testName); } -BOOST_FIXTURE_TEST_SUITE(DecisionTreeMainTest, - DecisionTreeTestFixture); - /** * Check that number of output points and * number of input points are equal. */ -BOOST_AUTO_TEST_CASE(DecisionTreeOutputDimensionTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeOutputDimensionTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("vc2.csv", inputData, info)) - BOOST_FAIL("Cannot load train dataset vc2.csv!"); + FAIL("Cannot load train dataset vc2.csv!"); arma::Row labels; if (!data::Load("vc2_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for vc2_labels.txt"); + FAIL("Cannot load labels for vc2_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); arma::mat testData; if (!data::Load("vc2_test.csv", testData, info)) - BOOST_FAIL("Cannot load test dataset vc2.csv!"); + FAIL("Cannot load test dataset vc2.csv!"); size_t testSize = testData.n_cols; @@ -85,39 +83,38 @@ BOOST_AUTO_TEST_CASE(DecisionTreeOutputDimensionTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); + REQUIRE(IO::GetParam("probabilities").n_cols == testSize); // Check number of output rows equals number of classes in case of // probabilities and 1 for predictions. - BOOST_REQUIRE_EQUAL( - IO::GetParam>("predictions").n_rows, 1); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_rows, 3); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); + REQUIRE(IO::GetParam("probabilities").n_rows == 3); } /** * Check that number of output points and number * of input points are equal for categorical dataset. */ -BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalOutputDimensionTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, + "DecisionTreeCategoricalOutputDimensionTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("braziltourism.arff", inputData, info)) - BOOST_FAIL("Cannot load train dataset braziltourism.arff!"); + FAIL("Cannot load train dataset braziltourism.arff!"); arma::Row labels; if (!data::Load("braziltourism_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for braziltourism_labels.txt"); + FAIL("Cannot load labels for braziltourism_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); arma::mat testData; if (!data::Load("braziltourism_test.arff", testData, info)) - BOOST_FAIL("Cannot load test dataset braziltourism_test.arff!"); + FAIL("Cannot load test dataset braziltourism_test.arff!"); size_t testSize = testData.n_cols; @@ -132,31 +129,29 @@ BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalOutputDimensionTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); + REQUIRE(IO::GetParam("probabilities").n_cols == testSize); // Check number of output rows equals number of classes in case of // probabilities and 1 for predictions. - BOOST_REQUIRE_EQUAL( - IO::GetParam>("predictions").n_rows, 1); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_rows, 6); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); + REQUIRE(IO::GetParam("probabilities").n_rows == 6); } /** * Make sure minimum leaf size is always a non-negative number. */ -BOOST_AUTO_TEST_CASE(DecisionTreeMinimumLeafSizeTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeMinimumLeafSizeTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("braziltourism.arff", inputData, info)) - BOOST_FAIL("Cannot load train dataset braziltourism.arff!"); + FAIL("Cannot load train dataset braziltourism.arff!"); arma::Row labels; if (!data::Load("braziltourism_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for braziltourism_labels.txt"); + FAIL("Cannot load labels for braziltourism_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); @@ -169,23 +164,25 @@ BOOST_AUTO_TEST_CASE(DecisionTreeMinimumLeafSizeTest) SetInputParam("minimum_leaf_size", (int) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Make sure maximum depth is always a non-negative number. */ -BOOST_AUTO_TEST_CASE(DecisionTreeNonNegativeMaximumDepthTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, + "DecisionTreeNonNegativeMaximumDepthTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("braziltourism.arff", inputData, info)) - BOOST_FAIL("Cannot load train dataset braziltourism.arff!"); + FAIL("Cannot load train dataset braziltourism.arff!"); arma::Row labels; if (!data::Load("braziltourism_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for braziltourism_labels.txt"); + FAIL("Cannot load labels for braziltourism_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); @@ -198,23 +195,24 @@ BOOST_AUTO_TEST_CASE(DecisionTreeNonNegativeMaximumDepthTest) SetInputParam("maximum_depth", (int) -1); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Make sure minimum gain split is always a fraction in range [0,1]. */ -BOOST_AUTO_TEST_CASE(DecisionMinimumGainSplitTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionMinimumGainSplitTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("braziltourism.arff", inputData, info)) - BOOST_FAIL("Cannot load train dataset braziltourism.arff!"); + FAIL("Cannot load train dataset braziltourism.arff!"); arma::Row labels; if (!data::Load("braziltourism_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for braziltourism_labels.txt"); + FAIL("Cannot load labels for braziltourism_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); @@ -227,23 +225,24 @@ BOOST_AUTO_TEST_CASE(DecisionMinimumGainSplitTest) SetInputParam("minimum_gain_split", 1.5); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Make sure minimum gain split produces regularised tree. */ -BOOST_AUTO_TEST_CASE(DecisionRegularisationTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionRegularisationTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("braziltourism.arff", inputData, info)) - BOOST_FAIL("Cannot load train dataset braziltourism.arff!"); + FAIL("Cannot load train dataset braziltourism.arff!"); arma::Row labels; if (!data::Load("braziltourism_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for braziltourism_labels.txt"); + FAIL("Cannot load labels for braziltourism_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); @@ -277,36 +276,37 @@ BOOST_AUTO_TEST_CASE(DecisionRegularisationTest) predRegularised = std::move(IO::GetParam>("predictions")); size_t count = 0; - BOOST_REQUIRE_EQUAL(pred.n_elem, predRegularised.n_elem); + REQUIRE(pred.n_elem == predRegularised.n_elem); for (size_t i = 0; i < pred.n_elem; ++i) { if (pred[i] != predRegularised[i]) count++; } - BOOST_REQUIRE_GT(count, 0); + REQUIRE(count > 0); } /** * Ensure that saved model can be used again. */ -BOOST_AUTO_TEST_CASE(DecisionModelReuseTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionModelReuseTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("vc2.csv", inputData, info)) - BOOST_FAIL("Cannot load train dataset vc2.csv!"); + FAIL("Cannot load train dataset vc2.csv!"); arma::Row labels; if (!data::Load("vc2_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for vc2_labels.txt"); + FAIL("Cannot load labels for vc2_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); arma::mat testData; if (!data::Load("vc2_test.csv", testData, info)) - BOOST_FAIL("Cannot load test dataset vc2.csv!"); + FAIL("Cannot load test dataset vc2.csv!"); size_t testSize = testData.n_cols; @@ -339,16 +339,13 @@ BOOST_AUTO_TEST_CASE(DecisionModelReuseTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); + REQUIRE(IO::GetParam("probabilities").n_cols == testSize); // Check number of output rows equals number of classes in case of // probabilities and 1 for predicitions. - BOOST_REQUIRE_EQUAL( - IO::GetParam>("predictions").n_rows, 1); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_rows, 3); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); + REQUIRE(IO::GetParam("probabilities").n_rows == 3); // Check that initial predictions and predictions using saved model are same. CheckMatrices(predictions, IO::GetParam>("predictions")); @@ -358,16 +355,17 @@ BOOST_AUTO_TEST_CASE(DecisionModelReuseTest) /** * Make sure only one of training data or pre-trained model is passed. */ -BOOST_AUTO_TEST_CASE(DecisionTreeTrainingVerTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeTrainingVerTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("vc2.csv", inputData, info)) - BOOST_FAIL("Cannot load train dataset vc2.csv!"); + FAIL("Cannot load train dataset vc2.csv!"); arma::Row labels; if (!data::Load("vc2_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for vc2_labels.txt"); + FAIL("Cannot load labels for vc2_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); @@ -388,30 +386,31 @@ BOOST_AUTO_TEST_CASE(DecisionTreeTrainingVerTest) SetInputParam("input_model", model); Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } /** * Ensure that saved model trained on categorical dataset can be used again. */ -BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionModelCategoricalReuseTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("braziltourism.arff", inputData, info)) - BOOST_FAIL("Cannot load train dataset braziltourism.arff!"); + FAIL("Cannot load train dataset braziltourism.arff!"); arma::Row labels; if (!data::Load("braziltourism_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for braziltourism_labels.txt"); + FAIL("Cannot load labels for braziltourism_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); arma::mat testData; if (!data::Load("braziltourism_test.arff", testData, info)) - BOOST_FAIL("Cannot load test dataset braziltourism_test.arff!"); + FAIL("Cannot load test dataset braziltourism_test.arff!"); size_t testSize = testData.n_cols; @@ -448,16 +447,13 @@ BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest) mlpackMain(); // Check that number of output points are equal to number of input points. - BOOST_REQUIRE_EQUAL(IO::GetParam>("predictions").n_cols, - testSize); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_cols, - testSize); + REQUIRE(IO::GetParam>("predictions").n_cols == testSize); + REQUIRE(IO::GetParam("probabilities").n_cols == testSize); // Check number of output rows equals number of classes in case of // probabilities and 1 for predicitions. - BOOST_REQUIRE_EQUAL( - IO::GetParam>("predictions").n_rows, 1); - BOOST_REQUIRE_EQUAL(IO::GetParam("probabilities").n_rows, 6); + REQUIRE(IO::GetParam>("predictions").n_rows == 1); + REQUIRE(IO::GetParam("probabilities").n_rows == 6); // Check that initial predictions and predictions using saved model are same. CheckMatrices(predictions, IO::GetParam>("predictions")); @@ -467,23 +463,24 @@ BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest) /** * Check that different maximum depths give different results. */ -BOOST_AUTO_TEST_CASE(DecisionTreeMaximumDepthTest) +TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeMaximumDepthTest", + "[DecisionTreeMainTest][BindingTests]") { arma::mat inputData; DatasetInfo info; if (!data::Load("vc2.csv", inputData, info)) - BOOST_FAIL("Cannot load train dataset vc2.csv!"); + FAIL("Cannot load train dataset vc2.csv!"); arma::Row labels; if (!data::Load("vc2_labels.txt", labels)) - BOOST_FAIL("Cannot load labels for vc2_labels.txt"); + FAIL("Cannot load labels for vc2_labels.txt"); // Initialize an all-ones weight matrix. arma::mat weights(1, labels.n_cols, arma::fill::ones); arma::mat testData; if (!data::Load("vc2_test.csv", testData, info)) - BOOST_FAIL("Cannot load test dataset vc2.csv!"); + FAIL("Cannot load test dataset vc2.csv!"); // Input training data. SetInputParam("training", std::make_tuple(info, inputData)); @@ -516,5 +513,3 @@ BOOST_AUTO_TEST_CASE(DecisionTreeMaximumDepthTest) CheckMatricesNotEqual(predictions, IO::GetParam>("predictions")); } - -BOOST_AUTO_TEST_SUITE_END(); From ac85e1a9f3e824f0efbc40902cce54e0429c48aa Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Wed, 29 Jul 2020 01:31:53 +0530 Subject: [PATCH 262/297] migrate svd_* and related test from boost to catch2 --- src/mlpack/tests/CMakeLists.txt | 20 +++---- src/mlpack/tests/armadillo_svd_test.cpp | 33 ++++++----- src/mlpack/tests/bias_svd_test.cpp | 53 ++++++++--------- src/mlpack/tests/block_krylov_svd_test.cpp | 18 +++--- src/mlpack/tests/quic_svd_test.cpp | 17 ++---- src/mlpack/tests/randomized_svd_test.cpp | 13 ++--- src/mlpack/tests/regularized_svd_test.cpp | 40 ++++++------- src/mlpack/tests/svd_batch_test.cpp | 26 ++++----- src/mlpack/tests/svd_incremental_test.cpp | 23 +++----- src/mlpack/tests/svdplusplus_test.cpp | 67 ++++++++++------------ 10 files changed, 135 insertions(+), 175 deletions(-) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 6ec5a68fd8..277342fb00 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -6,12 +6,9 @@ add_executable(mlpack_test ann_test_tools.hpp ann_visitor_test.cpp arma_extend_test.cpp - armadillo_svd_test.cpp async_learning_test.cpp augmented_rnns_tasks_test.cpp - bias_svd_test.cpp binarize_test.cpp - block_krylov_svd_test.cpp callback_test.cpp cf_test.cpp cli_binding_test.cpp @@ -72,16 +69,13 @@ add_executable(mlpack_test python_binding_test.cpp q_learning_test.cpp qdafn_test.cpp - quic_svd_test.cpp radical_test.cpp random_forest_test.cpp random_test.cpp - randomized_svd_test.cpp range_search_test.cpp rbm_network_test.cpp rectangle_tree_test.cpp recurrent_network_test.cpp - regularized_svd_test.cpp reward_clipping_test.cpp rl_components_test.cpp scaling_test.cpp @@ -96,9 +90,6 @@ add_executable(mlpack_test split_data_test.cpp string_encoding_test.cpp sumtree_test.cpp - svd_batch_test.cpp - svd_incremental_test.cpp - svdplusplus_test.cpp termination_policy_test.cpp test_function_tools.hpp test_tools.hpp @@ -156,6 +147,9 @@ add_executable(mlpack_catch_test adaboost_test.cpp akfn_test.cpp aknn_test.cpp + armadillo_svd_test.cpp + bias_svd_test.cpp + block_krylov_svd_test.cpp convolutional_network_test.cpp convolution_test.cpp image_load_test.cpp @@ -167,6 +161,12 @@ add_executable(mlpack_catch_test serialization_catch.cpp serialization_catch.hpp softmax_regression_test.cpp + quic_svd_test.cpp + randomized_svd_test.cpp + regularized_svd_test.cpp + svd_batch_test.cpp + svd_incremental_test.cpp + svdplusplus_test.cpp test_catch_tools.hpp main_tests/adaboost_test.cpp main_tests/approx_kfn_test.cpp @@ -225,8 +225,6 @@ add_custom_command(TARGET mlpack_test set(parallel_tests "ANNLayerTest;" "AsyncLearningTest;" - "SVDIncrementalTest;" - "SVDBatchTest;" "LocalCoordinateCodingTest;" "FeedForwardNetworkTest;" "RecurrentNetworkTest;" diff --git a/src/mlpack/tests/armadillo_svd_test.cpp b/src/mlpack/tests/armadillo_svd_test.cpp index 367c7e955e..96820f9148 100644 --- a/src/mlpack/tests/armadillo_svd_test.cpp +++ b/src/mlpack/tests/armadillo_svd_test.cpp @@ -1,10 +1,17 @@ +/** + * @file tests/armadillo_svd_test.cpp + * + * Test armadillo SVD. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ #include #include -#include -#include "test_tools.hpp" - -BOOST_AUTO_TEST_SUITE(ArmadilloSVDTest); +#include "catch.hpp" using namespace std; using namespace mlpack; @@ -13,13 +20,8 @@ using namespace arma; /** * Test armadillo SVD for normal factorization - * - * 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. */ -BOOST_AUTO_TEST_CASE(ArmadilloSVDNormalFactorizationTest) +TEST_CASE("ArmadilloSVDNormalFactorizationTest", "[ArmadilloSVDTest]") { mat test = randu(20, 20); @@ -27,18 +29,18 @@ BOOST_AUTO_TEST_CASE(ArmadilloSVDNormalFactorizationTest) arma::mat W, H, sigma; double result = svd.Apply(test, W, sigma, H); - BOOST_REQUIRE_LT(result, 0.01); + REQUIRE(result < 0.01); test = randu(50, 50); result = svd.Apply(test, W, sigma, H); - BOOST_REQUIRE_LT(result, 0.01); + REQUIRE(result < 0.01); } /** * Test armadillo SVD for low rank matrix factorization */ -BOOST_AUTO_TEST_CASE(ArmadilloSVDLowRankFactorizationTest) +TEST_CASE("ArmadilloSVDLowRankFactorizationTest", "[ArmadilloSVDTest]") { mat W_t = randu(30, 3); mat H_t = randu(3, 40); @@ -50,8 +52,5 @@ BOOST_AUTO_TEST_CASE(ArmadilloSVDLowRankFactorizationTest) arma::mat W, H; double result = svd.Apply(test, 3, W, H); - BOOST_REQUIRE_LT(result, 0.01); + REQUIRE(result < 0.01); } - - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/bias_svd_test.cpp b/src/mlpack/tests/bias_svd_test.cpp index 9164b64bdf..bb9f3936f3 100644 --- a/src/mlpack/tests/bias_svd_test.cpp +++ b/src/mlpack/tests/bias_svd_test.cpp @@ -15,15 +15,12 @@ #include -#include -#include "test_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::svd; -BOOST_AUTO_TEST_SUITE(BiasSVDTest); - -BOOST_AUTO_TEST_CASE(BiasSVDFunctionRandomEvaluate) +TEST_CASE("BiasSVDFunctionRandomEvaluate", "[BiasSVDTest]") { // Define useful constants. const size_t numUsers = 100; @@ -69,11 +66,11 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionRandomEvaluate) } // Compare calculated cost and value obtained using Evaluate(). - BOOST_REQUIRE_CLOSE(cost, biasSVDFunc.Evaluate(parameters), 1e-5); + REQUIRE(cost == Approx(biasSVDFunc.Evaluate(parameters)).epsilon(1e-7)); } } -BOOST_AUTO_TEST_CASE(BiasSVDFunctionRegularizationEvaluate) +TEST_CASE("BiasSVDFunctionRegularizationEvaluate", "[BiasSVDTest]") { // Define useful constants. const size_t numUsers = 100; @@ -123,14 +120,14 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionRegularizationEvaluate) // Cost with regularization should be close to the sum of cost without // regularization and the regularization terms. - BOOST_REQUIRE_CLOSE(biasSVDFuncNoReg.Evaluate(parameters) + smallRegTerm, - biasSVDFuncSmallReg.Evaluate(parameters), 1e-5); - BOOST_REQUIRE_CLOSE(biasSVDFuncNoReg.Evaluate(parameters) + bigRegTerm, - biasSVDFuncBigReg.Evaluate(parameters), 1e-5); + REQUIRE(biasSVDFuncNoReg.Evaluate(parameters) + smallRegTerm == + Approx(biasSVDFuncSmallReg.Evaluate(parameters)).epsilon(1e-7)); + REQUIRE(biasSVDFuncNoReg.Evaluate(parameters) + bigRegTerm == + Approx(biasSVDFuncBigReg.Evaluate(parameters)).epsilon(1e-7)); } } -BOOST_AUTO_TEST_CASE(BiasSVDFunctionGradient) +TEST_CASE("BiasSVDFunctionGradient", "[BiasSVDTest]") { // Define useful constants. const size_t numUsers = 50; @@ -189,19 +186,19 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionGradient) // Compare numerical and backpropagation gradient values. if (std::abs(gradient1(i, j)) <= 1e-6) - BOOST_REQUIRE_SMALL(numGradient1, 1e-5); + REQUIRE(numGradient1 == Approx(0.0).margin(1e-5)); else - BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 0.02); + REQUIRE(numGradient1 == Approx(gradient1(i, j)).epsilon(0.0002)); if (std::abs(gradient2(i, j)) <= 1e-6) - BOOST_REQUIRE_SMALL(numGradient2, 1e-5); + REQUIRE(numGradient2 == Approx(0.0).margin(1e-5)); else - BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 0.02); + REQUIRE(numGradient2 == Approx(gradient2(i, j)).epsilon(0.0002)); } } } -BOOST_AUTO_TEST_CASE(BiasSVDOutputSizeTest) +TEST_CASE("BiasSVDOutputSizeTest", "[BiasSVDTest]") { // Define useful constants. const size_t numUsers = 100; @@ -230,15 +227,15 @@ BOOST_AUTO_TEST_CASE(BiasSVDOutputSizeTest) biasSVD.Apply(data, rank, itemLatent, userLatent, itemBias, userBias); // Check the size of outputs. - BOOST_REQUIRE_EQUAL(itemLatent.n_rows, numItems); - BOOST_REQUIRE_EQUAL(itemLatent.n_cols, rank); - BOOST_REQUIRE_EQUAL(userLatent.n_rows, rank); - BOOST_REQUIRE_EQUAL(userLatent.n_cols, numUsers); - BOOST_REQUIRE_EQUAL(itemBias.n_elem, numItems); - BOOST_REQUIRE_EQUAL(userBias.n_elem, numUsers); + REQUIRE(itemLatent.n_rows == numItems); + REQUIRE(itemLatent.n_cols == rank); + REQUIRE(userLatent.n_rows == rank); + REQUIRE(userLatent.n_cols == numUsers); + REQUIRE(itemBias.n_elem == numItems); + REQUIRE(userBias.n_elem == numUsers); } -BOOST_AUTO_TEST_CASE(BiasSVDFunctionOptimize) +TEST_CASE("BiasSVDFunctionOptimize", "[BiasSVDTest]") { // Define useful constants. const size_t numUsers = 50; @@ -299,7 +296,7 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionOptimize) arma::norm(data, "frob"); // Relative error should be small. - BOOST_REQUIRE_SMALL(relativeError, 1e-2); + REQUIRE(relativeError == Approx(0.0).margin(1e-2)); } // The test is only compiled if the user has specified OpenMP to be @@ -307,7 +304,7 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionOptimize) #ifdef HAS_OPENMP // Test Bias SVD with parallel SGD. -BOOST_AUTO_TEST_CASE(BiasSVDFunctionParallelOptimize) +TEST_CASE("BiasSVDFunctionParallelOptimize", "[BiasSVDTest]") { // Define useful constants. const size_t numUsers = 50; @@ -374,9 +371,7 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionParallelOptimize) arma::norm(data, "frob"); // Relative error should be small. - BOOST_REQUIRE_SMALL(relativeError, 1e-2); + REQUIRE(relativeError == Approx(0.0).margin(1e-2)); } #endif - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/block_krylov_svd_test.cpp b/src/mlpack/tests/block_krylov_svd_test.cpp index 2ef1bf1116..3c24b9d1b5 100644 --- a/src/mlpack/tests/block_krylov_svd_test.cpp +++ b/src/mlpack/tests/block_krylov_svd_test.cpp @@ -13,10 +13,7 @@ #include #include -#include -#include "test_tools.hpp" - -BOOST_AUTO_TEST_SUITE(BlockKrylovSVDTest); +#include "catch.hpp" using namespace mlpack; @@ -48,7 +45,8 @@ void CreateNoisyLowRankMatrix(arma::mat& data, * The reconstruction and sigular value error of the obtained SVD should be * small. */ -BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDReconstructionError) +TEST_CASE("RandomizedBlockKrylovSVDReconstructionError", + "[BlockKrylovSVDTest]") { arma::mat U = arma::randn(3, 20); arma::mat V = arma::randn(10, 3); @@ -78,20 +76,20 @@ BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDReconstructionError) // The sigular value error should be small. double error = arma::norm(s2 - s3, "frob") / arma::norm(s2, "frob"); - BOOST_REQUIRE_SMALL(error, 1e-5); + REQUIRE(error == Approx(0.0).margin(1e-5)); arma::mat reconstruct = U2 * arma::diagmat(s2) * V2.t(); // The relative reconstruction error should be small. error = arma::norm(centeredData - reconstruct, "frob") / arma::norm(centeredData, "frob"); - BOOST_REQUIRE_SMALL(error, 1e-5); + REQUIRE(error == Approx(0.0).margin(1e-7)); } /* * Check if the method can handle noisy matrices. */ -BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDNoisyLowRankTest) +TEST_CASE("RandomizedBlockKrylovSVDNoisyLowRankTest", "[BlockKrylovSVDTest]") { arma::mat data; CreateNoisyLowRankMatrix(data, 200, 1000, 5, 0.5); @@ -106,7 +104,5 @@ BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDNoisyLowRankTest) svd::RandomizedBlockKrylovSVD rSVDB(data, U2, s2, V2, 10, rank, 20); double error = arma::max(arma::abs(s1.subvec(0, rank) - s2.subvec(0, rank))); - BOOST_REQUIRE_SMALL(error, 1e-2); + REQUIRE(error == Approx(0.0).margin(1e-4)); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/quic_svd_test.cpp b/src/mlpack/tests/quic_svd_test.cpp index 284a42c978..9ae2e33a79 100644 --- a/src/mlpack/tests/quic_svd_test.cpp +++ b/src/mlpack/tests/quic_svd_test.cpp @@ -13,17 +13,14 @@ #include #include -#include -#include "test_tools.hpp" - -BOOST_AUTO_TEST_SUITE(QUICSVDTest); +#include "catch.hpp" using namespace mlpack; /** * The reconstruction error of the obtained SVD should be small. */ -BOOST_AUTO_TEST_CASE(QUICSVDReconstructionError) +TEST_CASE("QUICSVDReconstructionError", "[QUICSVDTest]") { // Load the dataset. arma::mat dataset; @@ -49,13 +46,13 @@ BOOST_AUTO_TEST_CASE(QUICSVDReconstructionError) ++successes; } - BOOST_REQUIRE_GT(successes, 0); + REQUIRE(successes > 0); } /** * The singular value error of the obtained SVD should be small. */ -BOOST_AUTO_TEST_CASE(QUICSVDSingularValueError) +TEST_CASE("QUICSVDSingularValueError", "[QUICSVDTest]") { arma::mat U = arma::randn(3, 20); arma::mat V = arma::randn(10, 3); @@ -80,10 +77,10 @@ BOOST_AUTO_TEST_CASE(QUICSVDSingularValueError) // The sigular value error should be small. double error = arma::norm(s1 - s3); - BOOST_REQUIRE_SMALL(error, 0.1); + REQUIRE(error == Approx(0.0).margin(0.1)); } -BOOST_AUTO_TEST_CASE(QUICSVDSameDimensionTest) +TEST_CASE("QUICSVDSameDimensionTest", "[QUICSVDTest]") { arma::mat dataset = arma::randn(10, 10); @@ -91,5 +88,3 @@ BOOST_AUTO_TEST_CASE(QUICSVDSameDimensionTest) arma::mat u, v, sigma; svd::QUIC_SVD quicsvd(dataset, u, v, sigma); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/randomized_svd_test.cpp b/src/mlpack/tests/randomized_svd_test.cpp index 07371842bf..377a04918a 100644 --- a/src/mlpack/tests/randomized_svd_test.cpp +++ b/src/mlpack/tests/randomized_svd_test.cpp @@ -13,10 +13,7 @@ #include #include -#include -#include "test_tools.hpp" - -BOOST_AUTO_TEST_SUITE(RandomizedSVDTest); +#include "catch.hpp" using namespace mlpack; @@ -24,7 +21,7 @@ using namespace mlpack; * The reconstruction and sigular value error of the obtained SVD should be * small. */ -BOOST_AUTO_TEST_CASE(RandomizedSVDReconstructionError) +TEST_CASE("RandomizedSVDReconstructionError", "[RandomizedSVDTest]") { arma::mat U = arma::randn(3, 20); arma::mat V = arma::randn(10, 3); @@ -54,14 +51,12 @@ BOOST_AUTO_TEST_CASE(RandomizedSVDReconstructionError) // The sigular value error should be small. double error = arma::norm(s2 - s3, "frob") / arma::norm(s2, "frob"); - BOOST_REQUIRE_SMALL(error, 1e-5); + REQUIRE(error == Approx(0.0).margin(1e-5)); arma::mat reconstruct = U2 * arma::diagmat(s2) * V2.t(); // The relative reconstruction error should be small. error = arma::norm(centeredData - reconstruct, "frob") / arma::norm(centeredData, "frob"); - BOOST_REQUIRE_SMALL(error, 1e-5); + REQUIRE(error == Approx(0.0).margin(1e-5)); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/regularized_svd_test.cpp b/src/mlpack/tests/regularized_svd_test.cpp index 32b438b69b..eb412dcd26 100644 --- a/src/mlpack/tests/regularized_svd_test.cpp +++ b/src/mlpack/tests/regularized_svd_test.cpp @@ -14,16 +14,13 @@ #include -#include -#include "test_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::svd; using namespace ens; -BOOST_AUTO_TEST_SUITE(RegularizedSVDTest); - -BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRandomEvaluate) +TEST_CASE("RegularizedSVDFunctionRandomEvaluate", "[RegularizedSVDTest]") { // Define useful constants. const size_t numUsers = 100; @@ -66,11 +63,12 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRandomEvaluate) } // Compare calculated cost and value obtained using Evaluate(). - BOOST_REQUIRE_CLOSE(cost, rSVDFunc.Evaluate(parameters), 1e-5); + REQUIRE(cost == Approx(rSVDFunc.Evaluate(parameters)).epsilon(1e-7)); } } -BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRegularizationEvaluate) +TEST_CASE("RegularizedSVDFunctionRegularizationEvaluate", + "[RegularizedSVDTest]") { // Define useful constants. const size_t numUsers = 100; @@ -119,14 +117,14 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRegularizationEvaluate) // Cost with regularization should be close to the sum of cost without // regularization and the regularization terms. - BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + smallRegTerm, - rSVDFuncSmallReg.Evaluate(parameters), 1e-5); - BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + bigRegTerm, - rSVDFuncBigReg.Evaluate(parameters), 1e-5); + REQUIRE(rSVDFuncNoReg.Evaluate(parameters) + smallRegTerm == + Approx(rSVDFuncSmallReg.Evaluate(parameters)).epsilon(1e-7)); + REQUIRE(rSVDFuncNoReg.Evaluate(parameters) + bigRegTerm == + Approx(rSVDFuncBigReg.Evaluate(parameters)).epsilon(1e-7)); } } -BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionGradient) +TEST_CASE("RegularizedSVDFunctionGradient", "[RegularizedSVDTest]") { // Define useful constants. const size_t numUsers = 50; @@ -185,19 +183,19 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionGradient) // Compare numerical and backpropagation gradient values. if (std::abs(gradient1(i, j)) <= 1e-6) - BOOST_REQUIRE_SMALL(numGradient1, 1e-5); + REQUIRE(numGradient1 == Approx(0.0).margin(1e-5)); else - BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 0.02); + REQUIRE(numGradient1 == Approx(gradient1(i, j)).epsilon(0.0002)); if (std::abs(gradient2(i, j)) <= 1e-6) - BOOST_REQUIRE_SMALL(numGradient2, 1e-5); + REQUIRE(numGradient2 == Approx(0.0).margin(1e-5)); else - BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 0.02); + REQUIRE(numGradient2 == Approx(gradient2(i, j)).epsilon(0.0002)); } } } -BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize) +TEST_CASE("RegularizedSVDFunctionOptimize", "[RegularizedSVDTest]") { // Define useful constants. const size_t numUsers = 50; @@ -248,7 +246,7 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize) arma::norm(data, "frob"); // Relative error should be small. - BOOST_REQUIRE_SMALL(relativeError, 1e-2); + REQUIRE(relativeError == Approx(0.0).margin(1e-2)); } // The test is only compiled if the user has specified OpenMP to be @@ -256,7 +254,7 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize) #ifdef HAS_OPENMP // Test Regularized SVD with parallel SGD. -BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimizeHOGWILD) +TEST_CASE("RegularizedSVDFunctionOptimizeHOGWILD", "[RegularizedSVDTest]") { // Define useful constants. const size_t numUsers = 50; @@ -313,9 +311,7 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimizeHOGWILD) arma::norm(data, "frob"); // Relative error should be small. - BOOST_REQUIRE_SMALL(relativeError, 1e-2); + REQUIRE(relativeError == Approx(0.0).margin(1e-2)); } #endif - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/svd_batch_test.cpp b/src/mlpack/tests/svd_batch_test.cpp index bccea66a88..bac6df4917 100644 --- a/src/mlpack/tests/svd_batch_test.cpp +++ b/src/mlpack/tests/svd_batch_test.cpp @@ -17,10 +17,7 @@ #include #include -#include -#include "test_tools.hpp" - -BOOST_AUTO_TEST_SUITE(SVDBatchTest); +#include "catch.hpp" using namespace std; using namespace mlpack; @@ -30,7 +27,7 @@ using namespace arma; /** * Make sure the SVD Batch lerning is converging. */ -BOOST_AUTO_TEST_CASE(SVDBatchConvergenceElementTest) +TEST_CASE("SVDBatchConvergenceElementTest", "[SVDBatchTest]") { sp_mat data; data.sprandn(100, 100, 0.2); @@ -40,8 +37,8 @@ BOOST_AUTO_TEST_CASE(SVDBatchConvergenceElementTest) mat m1, m2; amf.Apply(data, 2, m1, m2); - BOOST_REQUIRE_NE(amf.TerminationPolicy().Iteration(), - amf.TerminationPolicy().MaxIterations()); + REQUIRE(amf.TerminationPolicy().Iteration() != + amf.TerminationPolicy().MaxIterations()); } //! This is used to ensure we start from the same initial point. @@ -70,7 +67,7 @@ class SpecificRandomInitialization /** * Make sure the momentum is working okay. */ -BOOST_AUTO_TEST_CASE(SVDBatchMomentumTest) +TEST_CASE("SVDBatchMomentumTest", "[SVDBatchTest]") { mat dataset; data::Load("GroupLensSmall.csv", dataset); @@ -111,13 +108,13 @@ BOOST_AUTO_TEST_CASE(SVDBatchMomentumTest) const double momentumRMSE = amf2.Apply(cleanedData, 2, m1, m2); - BOOST_REQUIRE_LE(momentumRMSE, regularRMSE + 0.1); + REQUIRE(momentumRMSE <= regularRMSE + 0.1); } /** * Make sure the regularization is working okay. */ -BOOST_AUTO_TEST_CASE(SVDBatchRegularizationTest) +TEST_CASE("SVDBatchRegularizationTest", "[SVDBatchTest]") { mat dataset; data::Load("GroupLensSmall.csv", dataset); @@ -158,13 +155,13 @@ BOOST_AUTO_TEST_CASE(SVDBatchRegularizationTest) double momentumRMSE = amf2.Apply(cleanedData, 2, m1, m2); - BOOST_REQUIRE_LE(momentumRMSE, regularRMSE + 0.05); + REQUIRE(momentumRMSE <= regularRMSE + 0.05); } /** * Make sure the SVD can factorize matrices with negative entries. */ -BOOST_AUTO_TEST_CASE(SVDBatchNegativeElementTest) +TEST_CASE("SVDBatchNegativeElementTest", "[SVDBatchTest]") { // Create two 5x3 matrices that we should be able to recover. mat testLeft; @@ -189,7 +186,6 @@ BOOST_AUTO_TEST_CASE(SVDBatchNegativeElementTest) arma::mat result = m1 * m2; // 6.5% tolerance on the norm. - BOOST_REQUIRE_CLOSE(arma::norm(test, "fro"), arma::norm(result, "fro"), 9.0); + REQUIRE(arma::norm(test, "fro") == + Approx(arma::norm(result, "fro")).epsilon(0.09)); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/svd_incremental_test.cpp b/src/mlpack/tests/svd_incremental_test.cpp index 50558c6d1e..433a86755f 100644 --- a/src/mlpack/tests/svd_incremental_test.cpp +++ b/src/mlpack/tests/svd_incremental_test.cpp @@ -20,10 +20,7 @@ #include #include -#include -#include "test_tools.hpp" - -BOOST_AUTO_TEST_SUITE(SVDIncrementalTest); +#include "catch.hpp" using namespace std; using namespace mlpack; @@ -33,7 +30,7 @@ using namespace arma; /** * Test for convergence of incomplete incremenal learning. */ -BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalConvergenceTest) +TEST_CASE("SVDIncompleteIncrementalConvergenceTest", "[SVDIncrementalTest]") { sp_mat data; data.sprandn(100, 100, 0.2); @@ -48,14 +45,14 @@ BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalConvergenceTest) mat m1, m2; amf.Apply(data, 2, m1, m2); - BOOST_REQUIRE_NE(amf.TerminationPolicy().Iteration(), - amf.TerminationPolicy().MaxIterations()); + REQUIRE(amf.TerminationPolicy().Iteration() != + amf.TerminationPolicy().MaxIterations()); } /** * Test for convergence of complete incremenal learning */ -BOOST_AUTO_TEST_CASE(SVDCompleteIncrementalConvergenceTest) +TEST_CASE("SVDCompleteIncrementalConvergenceTest", "[SVDIncrementalTest]") { sp_mat data; data.sprandn(100, 100, 0.2); @@ -71,8 +68,8 @@ BOOST_AUTO_TEST_CASE(SVDCompleteIncrementalConvergenceTest) mat m1, m2; amf.Apply(data, 2, m1, m2); - BOOST_REQUIRE_NE(amf.TerminationPolicy().Iteration(), - amf.TerminationPolicy().MaxIterations()); + REQUIRE(amf.TerminationPolicy().Iteration() != + amf.TerminationPolicy().MaxIterations()); } //! This is used to ensure we start from the same initial point. @@ -98,7 +95,7 @@ class SpecificRandomInitialization arma::mat H; }; -BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalRegularizationTest) +TEST_CASE("SVDIncompleteIncrementalRegularizationTest", "[SVDIncrementalTest]") { mat dataset; data::Load("GroupLensSmall.csv", dataset); @@ -143,7 +140,5 @@ BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalRegularizationTest) mat m3, m4; double regularizedRMSE = amf2.Apply(cleanedData2, 2, m3, m4); - BOOST_REQUIRE_LT(regularizedRMSE, regularRMSE + 0.105); + REQUIRE(regularizedRMSE < regularRMSE + 0.105); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/svdplusplus_test.cpp b/src/mlpack/tests/svdplusplus_test.cpp index a7918a259c..dbf1417397 100644 --- a/src/mlpack/tests/svdplusplus_test.cpp +++ b/src/mlpack/tests/svdplusplus_test.cpp @@ -15,15 +15,12 @@ #include -#include -#include "test_tools.hpp" +#include "catch.hpp" using namespace mlpack; using namespace mlpack::svd; -BOOST_AUTO_TEST_SUITE(SVDPlusPlusTest); - -BOOST_AUTO_TEST_CASE(SVDPlusPlusEvaluate) +TEST_CASE("SVDPlusPlusEvaluate", "[SVDPlusPlusTest]") { // Define useful constants. const size_t numUsers = 100; @@ -89,11 +86,11 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusEvaluate) } // Compare calculated cost and value obtained using Evaluate(). - BOOST_REQUIRE_CLOSE(cost, svdPPFunc.Evaluate(parameters), 1e-5); + REQUIRE(cost == Approx(svdPPFunc.Evaluate(parameters)).epsilon(1e-7)); } } -BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionRegularizationEvaluate) +TEST_CASE("SVDPlusPlusFunctionRegularizationEvaluate", "[SVDPlusPlusTest]") { // Define useful constants. const size_t numUsers = 100; @@ -173,14 +170,14 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionRegularizationEvaluate) // Cost with regularization should be close to the sum of cost without // regularization and the regularization terms. - BOOST_REQUIRE_CLOSE(svdPPFuncNoReg.Evaluate(parameters) + smallRegTerm, - svdPPFuncSmallReg.Evaluate(parameters), 1e-5); - BOOST_REQUIRE_CLOSE(svdPPFuncNoReg.Evaluate(parameters) + bigRegTerm, - svdPPFuncBigReg.Evaluate(parameters), 1e-5); + REQUIRE(svdPPFuncNoReg.Evaluate(parameters) + smallRegTerm == + Approx(svdPPFuncSmallReg.Evaluate(parameters)).epsilon(1e-7)); + REQUIRE(svdPPFuncNoReg.Evaluate(parameters) + bigRegTerm == + Approx(svdPPFuncBigReg.Evaluate(parameters)).epsilon(1e-7)); } } -BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionGradient) +TEST_CASE("SVDPlusPlusFunctionGradient", "[SVDPlusPlusTest]") { // Define useful constants. const size_t numUsers = 100; @@ -242,19 +239,19 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionGradient) // Compare numerical and backpropagation gradient values. if (std::abs(gradient1(i, j)) <= 1e-6) - BOOST_REQUIRE_SMALL(numGradient1, 1e-5); + REQUIRE(numGradient1 == Approx(0.0).margin(1e-5)); else - BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 0.02); + REQUIRE(numGradient1 == Approx(gradient1(i, j)).epsilon(0.0002)); if (std::abs(gradient2(i, j)) <= 1e-6) - BOOST_REQUIRE_SMALL(numGradient2, 1e-5); + REQUIRE(numGradient2 == Approx(0.0).margin(1e-5)); else - BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 0.02); + REQUIRE(numGradient2 == Approx(gradient2(i, j)).epsilon(0.0002)); } } } -BOOST_AUTO_TEST_CASE(SVDplusPlusOutputSizeTest) +TEST_CASE("SVDplusPlusOutputSizeTest", "[SVDPlusPlusTest]") { // Load small GroupLens dataset. arma::mat data; @@ -277,17 +274,17 @@ BOOST_AUTO_TEST_CASE(SVDplusPlusOutputSizeTest) itemImplicit); // Check the size of outputs. - BOOST_REQUIRE_EQUAL(itemLatent.n_rows, numItems); - BOOST_REQUIRE_EQUAL(itemLatent.n_cols, rank); - BOOST_REQUIRE_EQUAL(userLatent.n_rows, rank); - BOOST_REQUIRE_EQUAL(userLatent.n_cols, numUsers); - BOOST_REQUIRE_EQUAL(itemBias.n_elem, numItems); - BOOST_REQUIRE_EQUAL(userBias.n_elem, numUsers); - BOOST_REQUIRE_EQUAL(itemImplicit.n_rows, rank); - BOOST_REQUIRE_EQUAL(itemImplicit.n_cols, numItems); + REQUIRE(itemLatent.n_rows == numItems); + REQUIRE(itemLatent.n_cols == rank); + REQUIRE(userLatent.n_rows == rank); + REQUIRE(userLatent.n_cols == numUsers); + REQUIRE(itemBias.n_elem == numItems); + REQUIRE(userBias.n_elem == numUsers); + REQUIRE(itemImplicit.n_rows == rank); + REQUIRE(itemImplicit.n_cols == numItems); } -BOOST_AUTO_TEST_CASE(SVDPlusPlusCleanDataTest) +TEST_CASE("SVDPlusPlusCleanDataTest", "[SVDPlusPlusTest]") { // Load small GroupLens dataset. arma::mat data; @@ -320,21 +317,21 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusCleanDataTest) SVDPlusPlus<>::CleanData(implicitData, cleanedData, data); // Make sure cleanedData has correct size. - BOOST_REQUIRE_EQUAL(cleanedData.n_rows, numItems); - BOOST_REQUIRE_EQUAL(cleanedData.n_cols, numUsers); + REQUIRE(cleanedData.n_rows == numItems); + REQUIRE(cleanedData.n_cols == numUsers); // Make sure cleanedData has correct number of implicit data. - BOOST_REQUIRE_EQUAL(cleanedData.n_nonzero, implicitData.n_cols); + REQUIRE(cleanedData.n_nonzero == implicitData.n_cols); // Make sure all implicitData are in cleanedData. for (size_t i = 0; i < implicitData.n_cols; ++i) { double value = cleanedData(implicitData(1, i), implicitData(0, i)); - BOOST_REQUIRE_GT(std::fabs(value), 0); + REQUIRE(std::fabs(value) > 0); } } -BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionOptimize) +TEST_CASE("SVDPlusPlusFunctionOptimize", "[SVDPlusPlusTest]") { // Define useful constants. const size_t numUsers = 100; @@ -433,7 +430,7 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionOptimize) arma::norm(data, "frob"); // Relative error should be small. - BOOST_REQUIRE_SMALL(relativeError, 1e-2); + REQUIRE(relativeError == Approx(0.0).margin(1e-2)); } // The test is only compiled if the user has specified OpenMP to be @@ -441,7 +438,7 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionOptimize) #ifdef HAS_OPENMP // Test SVDPlusPlus with parallel SGD. -BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionParallelOptimize) +TEST_CASE("SVDPlusPlusFunctionParallelOptimize", "[SVDPlusPlusTest]") { // Define useful constants. const size_t numUsers = 100; @@ -547,9 +544,7 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionParallelOptimize) arma::norm(data, "frob"); // Relative error should be small. - BOOST_REQUIRE_SMALL(relativeError, 1e-2); + REQUIRE(relativeError == Approx(0.0).margin(1e-2)); } #endif - -BOOST_AUTO_TEST_SUITE_END(); From 114ffe1706c5fc49a46241db053eca10152a753b Mon Sep 17 00:00:00 2001 From: kartikdutt18 Date: Thu, 30 Jul 2020 13:02:08 +0530 Subject: [PATCH 263/297] Add tests for forward pass --- src/mlpack/tests/ann_layer_test.cpp | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 8cd06e56f5..c5d547db64 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4078,4 +4078,38 @@ BOOST_AUTO_TEST_CASE(GradientBatchNormWithMiniBatchesTest) BOOST_REQUIRE(pass); } +BOOST_AUTO_TEST_CASE(ConvolutionLayerTestCase) +{ + arma::mat input, output; + + // The input test matrix is of the form 3 x 2 x 4 x 1 where + // number of images are 3 and number of feature maps are 2. + input = arma::mat(8, 3); + input << 1 << 446 << 42 << arma::endr + << 2 << 16 << 63 << arma::endr + << 3 << 13 << 63 << arma::endr + << 4 << 21 << 21 << arma::endr + << 1 << 13 << 11 << arma::endr + << 32 << 45 << 42 << arma::endr + << 22 << 16 << 63 << arma::endr + << 32 << 13 << 42 << arma::endr; + + Convolution<> layer(2, 4, 1, 1, 1, 1, 0, 0, 4, 1); + + layer.Reset(); + // Set weights to 1.0 and bias to 0.0. + layer.Parameters().zeros(); + arma::mat weight(2 * 4, 1); + weight.fill(1.0); + layer.Parameters().submat(arma::span(0, 2 * 4 - 1), arma::span()) = weight; + + layer.Forward(input, output); + BOOST_REQUIRE_EQUAL(arma::accu(output), 4108); + + // Set bias to one. + layer.Parameters().fill(1.0); + layer.Forward(input, output); + BOOST_REQUIRE_EQUAL(arma::accu(output), 4156); +} + BOOST_AUTO_TEST_SUITE_END(); From da459d7d2781f7a60a59b502bc5a4293edf6386c Mon Sep 17 00:00:00 2001 From: kartikdutt18 <39593019+kartikdutt18@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:33:48 +0530 Subject: [PATCH 264/297] Update ann_layer_test.cpp --- src/mlpack/tests/ann_layer_test.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index c5d547db64..98b0afeffb 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4095,20 +4095,23 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerTestCase) << 32 << 13 << 42 << arma::endr; Convolution<> layer(2, 4, 1, 1, 1, 1, 0, 0, 4, 1); - layer.Reset(); + // Set weights to 1.0 and bias to 0.0. layer.Parameters().zeros(); arma::mat weight(2 * 4, 1); weight.fill(1.0); layer.Parameters().submat(arma::span(0, 2 * 4 - 1), arma::span()) = weight; - layer.Forward(input, output); + + // Value calculated using torch.nn.Conv2d(). BOOST_REQUIRE_EQUAL(arma::accu(output), 4108); // Set bias to one. layer.Parameters().fill(1.0); layer.Forward(input, output); + + // Value calculated using torch.nn.Conv2d(). BOOST_REQUIRE_EQUAL(arma::accu(output), 4156); } From 9ce881e4416f0d2ae9fe24120356e102933d3891 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:31:09 +0200 Subject: [PATCH 265/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index ef87f2e13c..2384762027 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -117,7 +117,7 @@ class BayesianLinearRegression * * @param data Column-major input data, dim(P, N). * @param responses A vector of targets, dim(N). - * @return score. Root Mean Square Error. + * @return Root mean squared error. */ double Train(const arma::mat& data, const arma::rowvec& responses); From 31688bff49b929af3ac11eeb7fe3dcb05cf6436d Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:31:20 +0200 Subject: [PATCH 266/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 2384762027..ca7df2d410 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -139,7 +139,7 @@ class BayesianLinearRegression * currently-trained Bayesian Ridge estimator. * * @param points The data point to apply the model. - * @param predictions y, which will contained calculated values on completion. + * @param predictions Vector which will contain calculated values on completion. * @param std Standard deviations of the predictions. */ void Predict(const arma::mat& points, From d119289cd46a138662e08c13df0090ec15aa334c Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:31:31 +0200 Subject: [PATCH 267/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index ca7df2d410..123ccff697 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -146,13 +146,13 @@ class BayesianLinearRegression arma::rowvec& predictions, arma::rowvec& std) const; - /** + /** * Compute the Root Mean Square Error between the predictions returned by the * model and the true repsonses. * * @param data Data points to predict * @param responses A vector of targets. - * @return RMSE + * @return Root mean squared error. **/ double RMSE(const arma::mat& data, const arma::rowvec& responses) const; From f47b616ca6f5d1d8b1eb9d88b7f5a2d1eb7af766 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:31:42 +0200 Subject: [PATCH 268/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp index bc10f901bb..86fc946fe2 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp @@ -1,5 +1,5 @@ /** - * @file bayesian_linear_regression_main.cpp + * @file methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp * @author Clement Mercier * * Executable for BayesianLinearRegression. From ed70c60cd1f98cac9833f1fcd69fc3b47114d82c Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:31:51 +0200 Subject: [PATCH 269/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index 0634408875..b290ad5e33 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -2,7 +2,7 @@ * @file bayesian_linear_regression_test.cpp * @author Clement Mercier * - * Test mlpackMain() of pca_main.cpp. + * Test mlpackMain() of bayesian_linear_regression_main.cpp. * * mlpack is free software; you may redistribute it and/or modify it under the * terms of the 3-clause BSD license. You should have received a copy of the From 3c7b775e37cbaaae6fb87e2a491ef08861441f41 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:32:05 +0200 Subject: [PATCH 270/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 123ccff697..9b2d68b608 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -148,7 +148,7 @@ class BayesianLinearRegression /** * Compute the Root Mean Square Error between the predictions returned by the - * model and the true repsonses. + * model and the true responses. * * @param data Data points to predict * @param responses A vector of targets. From af21900f71f7ce187bedb0cf66c7c5cb8a378113 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:32:14 +0200 Subject: [PATCH 271/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp index 3ef2cfce73..9c4cb20f09 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp @@ -1,5 +1,5 @@ /** - * @file bayesian_linear_regression_impl.hpp + * @file methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp * @author Clement Mercier * * Implementation of templated BayesianLinearRegression functions. From ad5d34a1a9f3d3c7a9e08973cc3ae28e04459ff1 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:32:24 +0200 Subject: [PATCH 272/297] Update src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp index b290ad5e33..e1b6773a5e 100644 --- a/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/bayesian_linear_regression_test.cpp @@ -1,5 +1,5 @@ /** - * @file bayesian_linear_regression_test.cpp + * @file tests/main_tests/bayesian_linear_regression_test.cpp * @author Clement Mercier * * Test mlpackMain() of bayesian_linear_regression_main.cpp. From 3067c9ff4053b3960cd31f534f265887817675bd Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:32:33 +0200 Subject: [PATCH 273/297] Update src/mlpack/tests/bayesian_linear_regression_test.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/bayesian_linear_regression_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/bayesian_linear_regression_test.cpp b/src/mlpack/tests/bayesian_linear_regression_test.cpp index 344a3130c1..d0c34509b9 100644 --- a/src/mlpack/tests/bayesian_linear_regression_test.cpp +++ b/src/mlpack/tests/bayesian_linear_regression_test.cpp @@ -1,5 +1,5 @@ /** - * @file bayesian_linear_regression_test.cpp + * @file tests/bayesian_linear_regression_test.cpp * @author Clement Mercier * * Test for BayesianLinearRegression. From bd2e74ca98b29bc0e08df8289294bdac07125cc3 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:32:48 +0200 Subject: [PATCH 274/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 9b2d68b608..be13bed1ef 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -258,8 +258,8 @@ class BayesianLinearRegression * * @param data Design matrix in column-major format, dim(P, N). * @param responses A vector of targets. - * @param dataProc data processed, dim(P, N). - * @param responsesProc responses processed, dim(N). + * @param dataProc Data processed, dim(P, N). + * @param responsesProc Responses processed, dim(N). * @return reponsesOffset Mean of responses. */ double CenterScaleData(const arma::mat& data, From e6ce56fd4f658ac01d2ae675d6eb3b59dc1e4657 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:33:05 +0200 Subject: [PATCH 275/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index be13bed1ef..19a6fcdaf9 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -271,7 +271,7 @@ class BayesianLinearRegression * Center and scale the points before prediction. * * @param data Design matrix in column-major format, dim(P, N). - * @param dataProc data processed, dim(P, N). + * @param dataProc Data processed, dim(P, N). */ void CenterScaleDataPred(const arma::mat& data, arma::mat& dataProc) const; From 202612971d0d1269155399543f01d0ff15ea46f1 Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:33:44 +0200 Subject: [PATCH 276/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index f9af417729..f2c45886d9 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -1,5 +1,5 @@ /** - * @file bayesian_linear_regression.cpp + * @file methods/bayesian_linear_regression/bayesian_linear_regression.cpp * @author Clement Mercier * * Implementation of Bayesian linear regression. From e0dfd967962c2f669cffb18fd29d1ea257fb2bcd Mon Sep 17 00:00:00 2001 From: mercierc <54903400+mercierc@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:33:58 +0200 Subject: [PATCH 277/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 19a6fcdaf9..07ca51e9cf 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -1,5 +1,5 @@ /** - * @file bayesian_linear_regression.hpp + * @file methods/bayesian_linear_regression/bayesian_linear_regression.hpp * @author Clement Mercier * * Definition of the BayesianRidge class, which performs the From d646a06a708feaa388eac39675ed59c42866004f Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Sat, 1 Aug 2020 02:48:31 +0530 Subject: [PATCH 278/297] some style fixes --- src/mlpack/tests/decision_tree_test.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/mlpack/tests/decision_tree_test.cpp b/src/mlpack/tests/decision_tree_test.cpp index 70d324d197..d1ae2225a1 100644 --- a/src/mlpack/tests/decision_tree_test.cpp +++ b/src/mlpack/tests/decision_tree_test.cpp @@ -35,8 +35,10 @@ TEST_CASE("GiniGainPerfectTest", "[DecisionTreeTest]") // Test that it's perfect regardless of number of classes. for (size_t c = 1; c < 10; ++c) + { REQUIRE(GiniGain::Evaluate(labels, c, weights) == - Approx(0.0).margin(1e-7)); + Approx(0.0).margin(1e-5)); + } } /** @@ -74,12 +76,16 @@ TEST_CASE("GiniGainEmptyTest", "[DecisionTreeTest]") // Test across some numbers of classes. arma::Row labels; for (size_t c = 1; c < 10; ++c) + { REQUIRE(GiniGain::Evaluate(labels, c, weights) == - Approx(0.0).margin(1e-7)); + Approx(0.0).margin(1e-5)); + } for (size_t c = 1; c < 10; ++c) + { REQUIRE(GiniGain::Evaluate(labels, c, weights) == - Approx(0.0).margin(1e-7)); + Approx(0.0).margin(1e-5)); + } } /** @@ -202,9 +208,9 @@ TEST_CASE("InformationGainEmptyTest", "[DecisionTreeTest]") for (size_t c = 1; c < 10; ++c) { REQUIRE(InformationGain::Evaluate(labels, c, weights) == - Approx(0.0).margin(1e-7)); + Approx(0.0).margin(1e-5)); REQUIRE(InformationGain::Evaluate(labels, c, weights) == - Approx(0.0).margin(1e-7)); + Approx(0.0).margin(1e-5)); } } @@ -558,7 +564,7 @@ TEST_CASE("PerfectTrainingSet", "[DecisionTreeTest]") if (labels[i] == j) REQUIRE(probabilities[j] == Approx(1.0).epsilon(1e-7)); else - REQUIRE(probabilities[j] == Approx(0.0).margin(1e-7)); + REQUIRE(probabilities[j] == Approx(0.0).margin(1e-5)); } } } @@ -601,7 +607,7 @@ TEST_CASE("PerfectTrainingSetWithWeight", "[DecisionTreeTest]") if (labels[i] == j) REQUIRE(probabilities[j] == Approx(1.0).epsilon(1e-7)); else - REQUIRE(probabilities[j] == Approx(0.0).margin(1e-7)); + REQUIRE(probabilities[j] == Approx(0.0).margin(1e-5)); } } } @@ -1034,8 +1040,8 @@ TEST_CASE("RandomDimensionSelectRandomTest", "[DecisionTreeTest]") r4.Dimensions() = 100000; REQUIRE(((r1.Begin() != r2.Begin()) || - (r1.Begin() != r3.Begin()) || - (r1.Begin() != r4.Begin()))); + (r1.Begin() != r3.Begin()) || + (r1.Begin() != r4.Begin()))); } /** From 43e97f385b9d1f2210f56c574b38ba113afbda1c Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 31 Jul 2020 18:53:58 -0400 Subject: [PATCH 279/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 07ca51e9cf..45919a2026 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -108,7 +108,7 @@ class BayesianLinearRegression */ BayesianLinearRegression(const bool centerData = true, const bool scaleData = false, - const int nIterMax = 50, + const size_t nIterMax = 50, const double tol = 1e-4); /** From 2d2118eeef0091ed9e3cb95501f02fccc4c894e0 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 31 Jul 2020 18:54:08 -0400 Subject: [PATCH 280/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp index 45919a2026..415f63e595 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp @@ -223,7 +223,7 @@ class BayesianLinearRegression bool scaleData; //! Maximum number of iterations for convergency. - int nIterMax; + size_t nIterMax; //! Level from which the solution is considered sufficientlly stable. double tol; From 2c0592ec6160fb7b5f46047dcf659806d8fbfc8e Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 31 Jul 2020 19:01:36 -0400 Subject: [PATCH 281/297] Update src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp Co-authored-by: Marcus Edel --- .../bayesian_linear_regression/bayesian_linear_regression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp index f2c45886d9..10a5f92bd5 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -18,7 +18,7 @@ using namespace mlpack::regression; BayesianLinearRegression::BayesianLinearRegression(const bool centerData, const bool scaleData, - const int nIterMax, + const size_t nIterMax, const double tol) : centerData(centerData), scaleData(scaleData), From 0a2f50e64e99c043cde822473b37f868a05657a6 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sat, 1 Aug 2020 16:28:13 +0530 Subject: [PATCH 282/297] change weight dimension to (vocabSize, embeddingSize) --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 12 ++++++------ src/mlpack/tests/ann_layer_test.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 20bcd076d0..aed3cfe7d5 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -26,7 +26,7 @@ Lookup::Lookup( vocabSize(vocabSize), embeddingSize(embeddingSize) { - weights.set_size(embeddingSize, vocabSize); + weights.set_size(vocabSize, embeddingSize); } template @@ -37,11 +37,11 @@ void Lookup::Forward( const size_t seqLength = input.n_rows; const size_t batchSize = input.n_cols; - output.set_size(embeddingSize * seqLength, batchSize); + output.set_size(seqLength * embeddingSize, batchSize); for (size_t i = 0; i < batchSize; ++i) { - output.col(i) = arma::vectorise(weights.cols( + output.col(i) = arma::vectorise(weights.rows( arma::conv_to::from(input.col(i)) - 1)); } } @@ -67,14 +67,14 @@ void Lookup::Gradient( const size_t batchSize = input.n_cols; arma::Cube errorTemp(const_cast&>(error).memptr(), - embeddingSize, seqLength, batchSize, false, false); + seqLength, embeddingSize, batchSize, false, false); gradient.set_size(arma::size(weights)); gradient.zeros(); for (size_t i = 0; i < batchSize; ++i) { - gradient.cols(arma::conv_to::from(input.col(i)) - 1) + gradient.rows(arma::conv_to::from(input.col(i)) - 1) += errorTemp.slice(i); } } @@ -90,7 +90,7 @@ void Lookup::serialize( // This is inefficient, but we have to allocate this memory so that // WeightSetVisitor gets the right size. if (Archive::is_loading::value) - weights.set_size(embeddingSize, vocabSize); + weights.set_size(vocabSize, embeddingSize); } } // namespace ann diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 6d7e719747..aa64f6fb52 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1674,7 +1674,7 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) for (size_t i = 0; i < batchSize; ++i) { // The Lookup module uses index - 1 for the cols. - const double outputSum = arma::accu(module.Parameters().cols( + const double outputSum = arma::accu(module.Parameters().rows( arma::conv_to::from(input.col(i)) - 1)); BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output.col(i)), 1e-3); @@ -1740,7 +1740,7 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) const size_t batchSize = 4; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-5); + BOOST_REQUIRE_LE(CheckGradient(function), 1e-7); } /** From 21dc590bfa5c176880900d79ceaf6685dbf9f1c0 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sat, 1 Aug 2020 16:33:31 +0530 Subject: [PATCH 283/297] keep tolerance to be 1e-05 in gradient check because different platforms give results with different precision on matrix operations. --- src/mlpack/tests/ann_layer_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index aa64f6fb52..f0b51d2ffc 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1740,7 +1740,7 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) const size_t batchSize = 4; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-7); + BOOST_REQUIRE_LE(CheckGradient(function), 1e-5); } /** From 0997b7e6fe113d9101e403bb3ff0a2c7e0914b1a Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Sat, 1 Aug 2020 20:16:20 +0530 Subject: [PATCH 284/297] migrate ann_* and related test from boost to catch2 --- src/mlpack/tests/CMakeLists.txt | 11 +- src/mlpack/tests/ann_dist_test.cpp | 57 +- src/mlpack/tests/ann_layer_test.cpp | 887 +++++++++++----------- src/mlpack/tests/ann_regularizer_test.cpp | 20 +- src/mlpack/tests/ann_visitor_test.cpp | 14 +- src/mlpack/tests/test_catch_tools.hpp | 4 +- 6 files changed, 483 insertions(+), 510 deletions(-) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 277342fb00..3936e00065 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -1,10 +1,5 @@ # mlpack test executable. add_executable(mlpack_test - ann_dist_test.cpp - ann_layer_test.cpp - ann_regularizer_test.cpp - ann_test_tools.hpp - ann_visitor_test.cpp arma_extend_test.cpp async_learning_test.cpp augmented_rnns_tasks_test.cpp @@ -147,6 +142,11 @@ add_executable(mlpack_catch_test adaboost_test.cpp akfn_test.cpp aknn_test.cpp + ann_dist_test.cpp + ann_layer_test.cpp + ann_regularizer_test.cpp + ann_test_tools.hpp + ann_visitor_test.cpp armadillo_svd_test.cpp bias_svd_test.cpp block_krylov_svd_test.cpp @@ -223,7 +223,6 @@ add_custom_command(TARGET mlpack_test # The list of long running parallel tests set(parallel_tests - "ANNLayerTest;" "AsyncLearningTest;" "LocalCoordinateCodingTest;" "FeedForwardNetworkTest;" diff --git a/src/mlpack/tests/ann_dist_test.cpp b/src/mlpack/tests/ann_dist_test.cpp index 702414759a..9648289a94 100644 --- a/src/mlpack/tests/ann_dist_test.cpp +++ b/src/mlpack/tests/ann_dist_test.cpp @@ -16,20 +16,18 @@ #include #include -#include -#include "test_tools.hpp" +#include "catch.hpp" +#include "test_catch_tools.hpp" #include using namespace mlpack; using namespace mlpack::ann; -BOOST_AUTO_TEST_SUITE(ANNDistTest); - /** * Simple bernoulli distribution module test. */ -BOOST_AUTO_TEST_CASE(SimpleBernoulliDistributionTest) +TEST_CASE("SimpleBernoulliDistributionTest", "[ANNDistTest]") { arma::mat param = arma::mat("1 1 0"); BernoulliDistribution<> module(param, false); @@ -43,7 +41,7 @@ BOOST_AUTO_TEST_CASE(SimpleBernoulliDistributionTest) /** * Jacobian bernoulli distribution module test when we don't apply logistic. */ -BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionTest) +TEST_CASE("JacobianBernoulliDistributionTest", "[ANNDistTest]") { for (size_t i = 0; i < 5; ++i) { @@ -78,15 +76,14 @@ BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionTest) } module.LogProbBackward(target, jacobianB); - BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))), - 1e-5); + REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 1e-5); } } /** * Jacobian bernoulli distribution module test when we apply logistic. */ -BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionLogisticTest) +TEST_CASE("JacobianBernoulliDistributionLogisticTest", "[ANNDistTest]") { for (size_t i = 0; i < 5; ++i) { @@ -124,15 +121,14 @@ BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionLogisticTest) } module.LogProbBackward(target, jacobianB); - BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))), - 3e-5); + REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 3e-5); } } /** * Normal Distribution module test. */ -BOOST_AUTO_TEST_CASE(NormalDistributionTest) +TEST_CASE("NormalDistributionTest", "[ANNDistTest]") { arma::vec mu = {1.1, 1.2, 1.5, 1.7}; arma::vec sigma = {0.1, 0.11, 0.5, 0.23}; @@ -145,29 +141,29 @@ BOOST_AUTO_TEST_CASE(NormalDistributionTest) normalDist.LogProbability(x, prob); // Testing output of log probability for some random mu, sigma and x. - BOOST_REQUIRE_CLOSE(prob[0], 1.2586464, 1e-3); - BOOST_REQUIRE_CLOSE(prob[1], 0.8751131, 1e-3); - BOOST_REQUIRE_CLOSE(prob[2], -0.30579138, 1e-3); - BOOST_REQUIRE_CLOSE(prob[3], -5.498411, 1e-3); + REQUIRE(prob[0] == Approx( 1.2586464).epsilon(1e-5)); + REQUIRE(prob[1] == Approx( 0.8751131).epsilon(1e-5)); + REQUIRE(prob[2] == Approx( -0.30579138).epsilon(1e-5)); + REQUIRE(prob[3] == Approx( -5.498411).epsilon(1e-5)); arma::vec dmu, dsigma; normalDist.ProbBackward(x, dmu, dsigma); // Testing output of dmu and dsigma for some random mu, sigma and x. - BOOST_REQUIRE_CLOSE(dmu[0], -17.603287, 1e-3); - BOOST_REQUIRE_CLOSE(dsigma[0], -26.40487, 1e-3); - BOOST_REQUIRE_CLOSE(dmu[1], -19.827663, 1e-3); - BOOST_REQUIRE_CLOSE(dsigma[1], -3.7852707, 1e-3); - BOOST_REQUIRE_CLOSE(dmu[2], 0.5892323, 1e-3); - BOOST_REQUIRE_CLOSE(dsigma[2], -1.2373875, 1e-3); - BOOST_REQUIRE_CLOSE(dmu[3], 0.061901994, 1e-3); - BOOST_REQUIRE_CLOSE(dsigma[3], 0.19751444, 1e-3); + REQUIRE(dmu[0] == Approx( -17.603287).epsilon(1e-5)); + REQUIRE(dsigma[0] == Approx( -26.40487).epsilon(1e-5)); + REQUIRE(dmu[1] == Approx( -19.827663).epsilon(1e-5)); + REQUIRE(dsigma[1] == Approx( -3.7852707).epsilon(1e-5)); + REQUIRE(dmu[2] == Approx( 0.5892323).epsilon(1e-5)); + REQUIRE(dsigma[2] == Approx( -1.2373875).epsilon(1e-5)); + REQUIRE(dmu[3] == Approx( 0.061901994).epsilon(1e-5)); + REQUIRE(dsigma[3] == Approx( 0.19751444).epsilon(1e-5)); } /** * Jacobian Normal Distribution module test for mean. */ -BOOST_AUTO_TEST_CASE(JacobianNormalDistributionMeanTest) +TEST_CASE("JacobianNormalDistributionMeanTest", "[ANNDistTest]") { for (size_t i = 0; i < 5; i++) { @@ -226,15 +222,14 @@ BOOST_AUTO_TEST_CASE(JacobianNormalDistributionMeanTest) jacobianB.col(k) = deltaMu % deriv; } - BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))), - 5e-3); + REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 5e-3); } } /** * Jacobian Normal Distribution module test for standard deviation. */ -BOOST_AUTO_TEST_CASE(JacobianNormalDistributionStandardDeviationTest) +TEST_CASE("JacobianNormalDistributionStandardDeviationTest", "[ANNDistTest]") { for (size_t i = 0; i < 5; i++) { @@ -293,10 +288,6 @@ BOOST_AUTO_TEST_CASE(JacobianNormalDistributionStandardDeviationTest) jacobianB.col(k) = deltaSigma % deriv; } - BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))), - 5e-3); + REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 5e-3); } } - - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 98b0afeffb..a930fb4879 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -21,20 +21,18 @@ #include #include -#include -#include "test_tools.hpp" +#include "test_catch_tools.hpp" +#include "catch.hpp" #include "ann_test_tools.hpp" -#include "serialization.hpp" +#include "serialization_catch.hpp" using namespace mlpack; using namespace mlpack::ann; -BOOST_AUTO_TEST_SUITE(ANNLayerTest); - /** * Simple add module test. */ -BOOST_AUTO_TEST_CASE(SimpleAddLayerTest) +TEST_CASE("SimpleAddLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; Add<> module(10); @@ -43,27 +41,27 @@ BOOST_AUTO_TEST_CASE(SimpleAddLayerTest) // Test the Forward function. input = arma::zeros(10, 1); module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(module.Parameters()), arma::accu(output)); + REQUIRE(arma::accu(module.Parameters()) == arma::accu(output)); // Test the Backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(delta)); + REQUIRE(arma::accu(output) == arma::accu(delta)); // Test the forward function. input = arma::ones(10, 1); module.Forward(input, output); - BOOST_REQUIRE_CLOSE(10 + arma::accu(module.Parameters()), - arma::accu(output), 1e-3); + REQUIRE(10 + arma::accu(module.Parameters()) == + Approx(arma::accu(output)).epsilon(1e-5)); // Test the backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_CLOSE(arma::accu(output), arma::accu(delta), 1e-3); + REQUIRE(arma::accu(output) == Approx(arma::accu(delta)).epsilon(1e-5)); } /** * Jacobian add module test. */ -BOOST_AUTO_TEST_CASE(JacobianAddLayerTest) +TEST_CASE("JacobianAddLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -75,14 +73,14 @@ BOOST_AUTO_TEST_CASE(JacobianAddLayerTest) module.Parameters().randu(); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Add layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientAddLayerTest) +TEST_CASE("GradientAddLayerTest", "[ANNLayerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -119,26 +117,26 @@ BOOST_AUTO_TEST_CASE(GradientAddLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Test that the function that can access the outSize parameter of * the Add layer works. */ -BOOST_AUTO_TEST_CASE(AddLayerParametersTest) +TEST_CASE("AddLayerParametersTest", "[ANNLayerTest]") { // Parameter : outSize. Add<> layer(7); // Make sure we can get the parameter successfully. - BOOST_REQUIRE_EQUAL(layer.OutputSize(), 7); + REQUIRE(layer.OutputSize() == 7); } /** * Simple constant module test. */ -BOOST_AUTO_TEST_CASE(SimpleConstantLayerTest) +TEST_CASE("SimpleConstantLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; Constant<> module(10, 3.0); @@ -146,26 +144,26 @@ BOOST_AUTO_TEST_CASE(SimpleConstantLayerTest) // Test the Forward function. input = arma::zeros(10, 1); module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); + REQUIRE(arma::accu(output) == 30.0); // Test the Backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); // Test the forward function. input = arma::ones(10, 1); module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); + REQUIRE(arma::accu(output) == 30.0); // Test the backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); } /** * Jacobian constant module test. */ -BOOST_AUTO_TEST_CASE(JacobianConstantLayerTest) +TEST_CASE("JacobianConstantLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -176,7 +174,7 @@ BOOST_AUTO_TEST_CASE(JacobianConstantLayerTest) Constant<> module(elements, 1.0); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } @@ -184,19 +182,19 @@ BOOST_AUTO_TEST_CASE(JacobianConstantLayerTest) * Test that the function that can access the outSize parameter of the * Constant layer works. */ -BOOST_AUTO_TEST_CASE(ConstantLayerParametersTest) +TEST_CASE("ConstantLayerParametersTest", "[ANNLayerTest]") { // Parameter : outSize. Constant<> layer(7); // Make sure we can get the parameter successfully. - BOOST_REQUIRE_EQUAL(layer.OutSize(), 7); + REQUIRE(layer.OutSize() == 7); } /** * Simple dropout module test. */ -BOOST_AUTO_TEST_CASE(SimpleDropoutLayerTest) +TEST_CASE("SimpleDropoutLayerTest", "[ANNLayerTest]") { // Initialize the probability of setting a value to zero. const double p = 0.2; @@ -211,19 +209,17 @@ BOOST_AUTO_TEST_CASE(SimpleDropoutLayerTest) // Test the Forward function. arma::mat output; module.Forward(input, output); - BOOST_REQUIRE_LE( - arma::as_scalar(arma::abs(arma::mean(output) - (1 - p))), 0.05); + REQUIRE(arma::as_scalar(arma::abs(arma::mean(output) - (1 - p))) <= 0.05); // Test the Backward function. arma::mat delta; module.Backward(input, input, delta); - BOOST_REQUIRE_LE( - arma::as_scalar(arma::abs(arma::mean(delta) - (1 - p))), 0.05); + REQUIRE(arma::as_scalar(arma::abs(arma::mean(delta) - (1 - p))) <= 0.05); // Test the Forward function. module.Deterministic() = true; module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(output)); + REQUIRE(arma::accu(input) == arma::accu(output)); } /** @@ -231,7 +227,7 @@ BOOST_AUTO_TEST_CASE(SimpleDropoutLayerTest) * validate that the layer is producing approximately the correct number of * ones. */ -BOOST_AUTO_TEST_CASE(DropoutProbabilityTest) +TEST_CASE("DropoutProbabilityTest", "[ANNLayerTest]") { arma::mat input = arma::ones(1500, 1); const size_t iterations = 10; @@ -257,14 +253,14 @@ BOOST_AUTO_TEST_CASE(DropoutProbabilityTest) iterations; const double error = fabs(nonzeroCount - expected) / expected; - BOOST_REQUIRE_LE(error, 0.15); + REQUIRE(error <= 0.15); } } /* * Perform dropout with probability 1 - p where p = 0, means no dropout. */ -BOOST_AUTO_TEST_CASE(NoDropoutTest) +TEST_CASE("NoDropoutTest", "[ANNLayerTest]") { arma::mat input = arma::ones(1500, 1); Dropout<> module(0); @@ -273,14 +269,14 @@ BOOST_AUTO_TEST_CASE(NoDropoutTest) arma::mat output; module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(input)); + REQUIRE(arma::accu(output) == arma::accu(input)); } /* * Perform test to check whether mean and variance remain nearly same * after AlphaDropout. */ -BOOST_AUTO_TEST_CASE(SimpleAlphaDropoutLayerTest) +TEST_CASE("SimpleAlphaDropoutLayerTest", "[ANNLayerTest]") { // Initialize the probability of setting a value to alphaDash. const double p = 0.2; @@ -296,23 +292,20 @@ BOOST_AUTO_TEST_CASE(SimpleAlphaDropoutLayerTest) arma::mat output; module.Forward(input, output); // Check whether mean remains nearly same. - BOOST_REQUIRE_LE( - arma::as_scalar(arma::abs(arma::mean(input) - arma::mean(output))), 0.1); + REQUIRE(arma::as_scalar(arma::abs(arma::mean(input) - arma::mean(output))) <= 0.1); // Check whether variance remains nearly same. - BOOST_REQUIRE_LE( - arma::as_scalar(arma::abs(arma::var(input) - arma::var(output))), 0.1); + REQUIRE(arma::as_scalar(arma::abs(arma::var(input) - arma::var(output))) <= 0.1); // Test the Backward function when training phase. arma::mat delta; module.Backward(input, input, delta); - BOOST_REQUIRE_LE( - arma::as_scalar(arma::abs(arma::mean(delta) - 0)), 0.05); + REQUIRE(arma::as_scalar(arma::abs(arma::mean(delta) - 0)) <= 0.05); // Test the Forward function when testing phase. module.Deterministic() = true; module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(output)); + REQUIRE(arma::accu(input) == arma::accu(output)); } /** @@ -320,7 +313,7 @@ BOOST_AUTO_TEST_CASE(SimpleAlphaDropoutLayerTest) * and validate that the layer is producing approximately the correct number * of ones. */ -BOOST_AUTO_TEST_CASE(AlphaDropoutProbabilityTest) +TEST_CASE("AlphaDropoutProbabilityTest", "[ANNLayerTest]") { arma::mat input = arma::ones(1500, 1); const size_t iterations = 10; @@ -348,7 +341,7 @@ BOOST_AUTO_TEST_CASE(AlphaDropoutProbabilityTest) const double error = fabs(nonzeroCount - expected) / expected; - BOOST_REQUIRE_LE(error, 0.15); + REQUIRE(error <= 0.15); } } @@ -356,7 +349,7 @@ BOOST_AUTO_TEST_CASE(AlphaDropoutProbabilityTest) * Perform AlphaDropout with probability 1 - p where p = 0, * means no AlphaDropout. */ -BOOST_AUTO_TEST_CASE(NoAlphaDropoutTest) +TEST_CASE("NoAlphaDropoutTest", "[ANNLayerTest]") { arma::mat input = arma::ones(1500, 1); AlphaDropout<> module(0); @@ -365,13 +358,13 @@ BOOST_AUTO_TEST_CASE(NoAlphaDropoutTest) arma::mat output; module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(input)); + REQUIRE(arma::accu(output) == arma::accu(input)); } /** * Simple linear module test. */ -BOOST_AUTO_TEST_CASE(SimpleLinearLayerTest) +TEST_CASE("SimpleLinearLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; Linear<> module(10, 10); @@ -381,19 +374,19 @@ BOOST_AUTO_TEST_CASE(SimpleLinearLayerTest) // Test the Forward function. input = arma::zeros(10, 1); module.Forward(input, output); - BOOST_REQUIRE_CLOSE(arma::accu( - module.Parameters().submat(100, 0, module.Parameters().n_elem - 1, 0)), - arma::accu(output), 1e-3); + REQUIRE(arma::accu(module.Parameters().submat(100, + 0, module.Parameters().n_elem - 1, 0)) == + Approx(arma::accu(output)).epsilon(1e-5)); // Test the Backward function. module.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); } /** * Jacobian linear module test. */ -BOOST_AUTO_TEST_CASE(JacobianLinearLayerTest) +TEST_CASE("JacobianLinearLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -407,14 +400,14 @@ BOOST_AUTO_TEST_CASE(JacobianLinearLayerTest) module.Parameters().randu(); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Linear layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientLinearLayerTest) +TEST_CASE("GradientLinearLayerTest", "[ANNLayerTest]") { // Linear function gradient instantiation. struct GradientFunction @@ -451,13 +444,13 @@ BOOST_AUTO_TEST_CASE(GradientLinearLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Simple noisy linear module test. */ -BOOST_AUTO_TEST_CASE(SimpleNoisyLinearLayerTest) +TEST_CASE("SimpleNoisyLinearLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; NoisyLinear<> module(10, 10); @@ -466,13 +459,13 @@ BOOST_AUTO_TEST_CASE(SimpleNoisyLinearLayerTest) // Test the Backward function. module.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); } /** * Jacobian noisy linear module test. */ -BOOST_AUTO_TEST_CASE(JacobianNoisyLinearLayerTest) +TEST_CASE("JacobianNoisyLinearLayerTest", "[ANNLayerTest]") { const size_t inputElements = math::RandInt(2, 1000); const size_t outputElements = math::RandInt(2, 1000); @@ -484,13 +477,13 @@ BOOST_AUTO_TEST_CASE(JacobianNoisyLinearLayerTest) module.Parameters().randu(); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } /** * Noisy Linear layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientNoisyLinearLayerTest) +TEST_CASE("GradientNoisyLinearLayerTest", "[ANNLayerTest]") { // Noisy linear function gradient instantiation. struct GradientFunction @@ -527,13 +520,13 @@ BOOST_AUTO_TEST_CASE(GradientNoisyLinearLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Simple linear no bias module test. */ -BOOST_AUTO_TEST_CASE(SimpleLinearNoBiasLayerTest) +TEST_CASE("SimpleLinearNoBiasLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; LinearNoBias<> module(10, 10); @@ -543,17 +536,17 @@ BOOST_AUTO_TEST_CASE(SimpleLinearNoBiasLayerTest) // Test the Forward function. input = arma::zeros(10, 1); module.Forward(input, output); - BOOST_REQUIRE_EQUAL(0, arma::accu(output)); + REQUIRE(0 == arma::accu(output)); // Test the Backward function. module.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); } /** * Simple padding layer test. */ -BOOST_AUTO_TEST_CASE(SimplePaddingLayerTest) +TEST_CASE("SimplePaddingLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; Padding<> module(1, 2, 3, 4); @@ -561,9 +554,9 @@ BOOST_AUTO_TEST_CASE(SimplePaddingLayerTest) // Test the Forward function. input = arma::randu(10, 1); module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(output)); - BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows + 3); - BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols + 7); + REQUIRE(arma::accu(input) == arma::accu(output)); + REQUIRE(output.n_rows == input.n_rows + 3); + REQUIRE(output.n_cols == input.n_cols + 7); // Test the Backward function. module.Backward(input, output, delta); @@ -573,7 +566,7 @@ BOOST_AUTO_TEST_CASE(SimplePaddingLayerTest) /** * Jacobian linear no bias module test. */ -BOOST_AUTO_TEST_CASE(JacobianLinearNoBiasLayerTest) +TEST_CASE("JacobianLinearNoBiasLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -587,14 +580,14 @@ BOOST_AUTO_TEST_CASE(JacobianLinearNoBiasLayerTest) module.Parameters().randu(); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * LinearNoBias layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientLinearNoBiasLayerTest) +TEST_CASE("GradientLinearNoBiasLayerTest", "[ANNLayerTest]") { // LinearNoBias function gradient instantiation. struct GradientFunction @@ -631,13 +624,13 @@ BOOST_AUTO_TEST_CASE(GradientLinearNoBiasLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Jacobian negative log likelihood module test. */ -BOOST_AUTO_TEST_CASE(JacobianNegativeLogLikelihoodLayerTest) +TEST_CASE("JacobianNegativeLogLikelihoodLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -651,14 +644,14 @@ BOOST_AUTO_TEST_CASE(JacobianNegativeLogLikelihoodLayerTest) target(0) = math::RandInt(1, inputElements - 1); double error = JacobianPerformanceTest(module, input, target); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Jacobian LeakyReLU module test. */ -BOOST_AUTO_TEST_CASE(JacobianLeakyReLULayerTest) +TEST_CASE("JacobianLeakyReLULayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -670,14 +663,14 @@ BOOST_AUTO_TEST_CASE(JacobianLeakyReLULayerTest) LeakyReLU<> module; double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Jacobian FlexibleReLU module test. */ -BOOST_AUTO_TEST_CASE(JacobianFlexibleReLULayerTest) +TEST_CASE("JacobianFlexibleReLULayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -689,14 +682,14 @@ BOOST_AUTO_TEST_CASE(JacobianFlexibleReLULayerTest) FlexibleReLU<> module; double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Flexible ReLU layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientFlexibleReLULayerTest) +TEST_CASE("GradientFlexibleReLULayerTest", "[ANNLayerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -735,13 +728,13 @@ BOOST_AUTO_TEST_CASE(GradientFlexibleReLULayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Jacobian MultiplyConstant module test. */ -BOOST_AUTO_TEST_CASE(JacobianMultiplyConstantLayerTest) +TEST_CASE("JacobianMultiplyConstantLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -753,14 +746,14 @@ BOOST_AUTO_TEST_CASE(JacobianMultiplyConstantLayerTest) MultiplyConstant<> module(3.0); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Jacobian HardTanH module test. */ -BOOST_AUTO_TEST_CASE(JacobianHardTanHLayerTest) +TEST_CASE("JacobianHardTanHLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -772,14 +765,14 @@ BOOST_AUTO_TEST_CASE(JacobianHardTanHLayerTest) HardTanH<> module; double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Simple select module test. */ -BOOST_AUTO_TEST_CASE(SimpleSelectLayerTest) +TEST_CASE("SimpleSelectLayerTest", "[ANNLayerTest]") { arma::mat outputA, outputB, input, delta; @@ -792,40 +785,40 @@ BOOST_AUTO_TEST_CASE(SimpleSelectLayerTest) // Test the Forward function. Select<> moduleA(3); moduleA.Forward(input, outputA); - BOOST_REQUIRE_EQUAL(30, arma::accu(outputA)); + REQUIRE(30 == arma::accu(outputA)); // Test the Forward function. Select<> moduleB(3, 5); moduleB.Forward(input, outputB); - BOOST_REQUIRE_EQUAL(15, arma::accu(outputB)); + REQUIRE(15 == arma::accu(outputB)); // Test the Backward function. moduleA.Backward(input, outputA, delta); - BOOST_REQUIRE_EQUAL(30, arma::accu(delta)); + REQUIRE(30 == arma::accu(delta)); // Test the Backward function. moduleB.Backward(input, outputA, delta); - BOOST_REQUIRE_EQUAL(15, arma::accu(delta)); + REQUIRE(15 == arma::accu(delta)); } /** * Test that the functions that can access the parameters of the * Select layer work. */ -BOOST_AUTO_TEST_CASE(SelectLayerParametersTest) +TEST_CASE("SelectLayerParametersTest", "[ANNLayerTest]") { // Parameter order : index, elements. Select<> layer(3, 5); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.Index(), 3); - BOOST_REQUIRE_EQUAL(layer.NumElements(), 5); + REQUIRE(layer.Index() == 3); + REQUIRE(layer.NumElements() == 5); } /** * Simple join module test. */ -BOOST_AUTO_TEST_CASE(SimpleJoinLayerTest) +TEST_CASE("SimpleJoinLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; input = arma::ones(10, 5); @@ -833,23 +826,23 @@ BOOST_AUTO_TEST_CASE(SimpleJoinLayerTest) // Test the Forward function. Join<> module; module.Forward(input, output); - BOOST_REQUIRE_EQUAL(50, arma::accu(output)); + REQUIRE(50 == arma::accu(output)); bool b = output.n_rows == 1 || output.n_cols == 1; - BOOST_REQUIRE_EQUAL(b, true); + REQUIRE(b == true); // Test the Backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(50, arma::accu(delta)); + REQUIRE(50 == arma::accu(delta)); b = delta.n_rows == input.n_rows && input.n_cols; - BOOST_REQUIRE_EQUAL(b, true); + REQUIRE(b == true); } /** * Simple add merge module test. */ -BOOST_AUTO_TEST_CASE(SimpleAddMergeLayerTest) +TEST_CASE("SimpleAddMergeLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; input = arma::ones(10, 1); @@ -868,18 +861,18 @@ BOOST_AUTO_TEST_CASE(SimpleAddMergeLayerTest) // Test the Forward function. module.Forward(input, output); - BOOST_REQUIRE_EQUAL(10 * numMergeModules, arma::accu(output)); + REQUIRE(10 * numMergeModules == arma::accu(output)); // Test the Backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(delta)); + REQUIRE(arma::accu(output) == arma::accu(delta)); } } /** * Test the LSTM layer with a user defined rho parameter and without. */ -BOOST_AUTO_TEST_CASE(LSTMRrhoTest) +TEST_CASE("LSTMRrhoTest", "[ANNLayerTest]") { const size_t rho = 5; arma::cube input = arma::randu(1, 1, 5); @@ -916,7 +909,7 @@ BOOST_AUTO_TEST_CASE(LSTMRrhoTest) /** * LSTM layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientLSTMLayerTest) +TEST_CASE("GradientLSTMLayerTest", "[ANNLayerTest]") { // LSTM function gradient instantiation. struct GradientFunction @@ -954,37 +947,37 @@ BOOST_AUTO_TEST_CASE(GradientLSTMLayerTest) arma::cube input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Test that the functions that can modify and access the parameters of the * LSTM layer work. */ -BOOST_AUTO_TEST_CASE(LSTMLayerParametersTest) +TEST_CASE("LSTMLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, outSize, rho. LSTM<> layer1(1, 2, 3); LSTM<> layer2(1, 2, 4); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InSize(), 1); - BOOST_REQUIRE_EQUAL(layer1.OutSize(), 2); - BOOST_REQUIRE_EQUAL(layer1.Rho(), 3); + REQUIRE(layer1.InSize() == 1); + REQUIRE(layer1.OutSize() == 2); + REQUIRE(layer1.Rho() == 3); // Now modify the parameters to match the second layer. layer1.Rho() = 4; // Now ensure all the results are the same. - BOOST_REQUIRE_EQUAL(layer1.InSize(), layer2.InSize()); - BOOST_REQUIRE_EQUAL(layer2.OutSize(), layer2.OutSize()); - BOOST_REQUIRE_EQUAL(layer1.Rho(), layer2.Rho()); + REQUIRE(layer1.InSize() == layer2.InSize()); + REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.Rho() == layer2.Rho()); } /** * Test the FastLSTM layer with a user defined rho parameter and without. */ -BOOST_AUTO_TEST_CASE(FastLSTMRrhoTest) +TEST_CASE("FastLSTMRrhoTest", "[ANNLayerTest]") { const size_t rho = 5; arma::cube input = arma::randu(1, 1, 5); @@ -1021,7 +1014,7 @@ BOOST_AUTO_TEST_CASE(FastLSTMRrhoTest) /** * FastLSTM layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientFastLSTMLayerTest) +TEST_CASE("GradientFastLSTMLayerTest", "[ANNLayerTest]") { // Fast LSTM function gradient instantiation. struct GradientFunction @@ -1062,31 +1055,31 @@ BOOST_AUTO_TEST_CASE(GradientFastLSTMLayerTest) // The threshold should be << 0.1 but since the Fast LSTM layer uses an // approximation of the sigmoid function the estimated gradient is not // correct. - BOOST_REQUIRE_LE(CheckGradient(function), 0.2); + REQUIRE(CheckGradient(function) <= 0.2); } /** * Test that the functions that can modify and access the parameters of the * Fast LSTM layer work. */ -BOOST_AUTO_TEST_CASE(FastLSTMLayerParametersTest) +TEST_CASE("FastLSTMLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, outSize, rho. FastLSTM<> layer1(1, 2, 3); FastLSTM<> layer2(1, 2, 4); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InSize(), 1); - BOOST_REQUIRE_EQUAL(layer1.OutSize(), 2); - BOOST_REQUIRE_EQUAL(layer1.Rho(), 3); + REQUIRE(layer1.InSize() == 1); + REQUIRE(layer1.OutSize() == 2); + REQUIRE(layer1.Rho() == 3); // Now modify the parameters to match the second layer. layer1.Rho() = 4; // Now ensure all the results are the same. - BOOST_REQUIRE_EQUAL(layer1.InSize(), layer2.InSize()); - BOOST_REQUIRE_EQUAL(layer2.OutSize(), layer2.OutSize()); - BOOST_REQUIRE_EQUAL(layer1.Rho(), layer2.Rho()); + REQUIRE(layer1.InSize() == layer2.InSize()); + REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.Rho() == layer2.Rho()); } /** @@ -1094,7 +1087,7 @@ BOOST_AUTO_TEST_CASE(FastLSTMLayerParametersTest) * state. Besides output, the overloaded function provides read access to cell * state of the LSTM layer. */ -BOOST_AUTO_TEST_CASE(ReadCellStateParamLSTMLayerTest) +TEST_CASE("ReadCellStateParamLSTMLayerTest", "[ANNLayerTest]") { const size_t rho = 5, inputSize = 3, outputSize = 2; @@ -1163,7 +1156,7 @@ BOOST_AUTO_TEST_CASE(ReadCellStateParamLSTMLayerTest) * state. Besides output, the overloaded function provides write access to cell * state of the LSTM layer. */ -BOOST_AUTO_TEST_CASE(WriteCellStateParamLSTMLayerTest) +TEST_CASE("WriteCellStateParamLSTMLayerTest", "[ANNLayerTest]") { const size_t rho = 5, inputSize = 3, outputSize = 2; @@ -1254,11 +1247,11 @@ BOOST_AUTO_TEST_CASE(WriteCellStateParamLSTMLayerTest) { arma::mat empty; // Should throw error. - BOOST_REQUIRE_THROW(lstm.Forward(stepData, // Input. - outLstm, // Output. - empty, // Cell state. - true), // Write into cell state. - std::runtime_error); + REQUIRE_THROWS_AS(lstm.Forward(stepData, // Input. + outLstm, // Output. + empty, // Cell state. + true), // Write into cell state. + std::runtime_error); } } @@ -1266,31 +1259,31 @@ BOOST_AUTO_TEST_CASE(WriteCellStateParamLSTMLayerTest) * Test that the functions that can modify and access the parameters of the * GRU layer work. */ -BOOST_AUTO_TEST_CASE(GRULayerParametersTest) +TEST_CASE("GRULayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, outSize, rho. GRU<> layer1(1, 2, 3); GRU<> layer2(1, 2, 4); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InSize(), 1); - BOOST_REQUIRE_EQUAL(layer1.OutSize(), 2); - BOOST_REQUIRE_EQUAL(layer1.Rho(), 3); + REQUIRE(layer1.InSize() == 1); + REQUIRE(layer1.OutSize() == 2); + REQUIRE(layer1.Rho() == 3); // Now modify the parameters to match the second layer. layer1.Rho() = 4; // Now ensure all the results are the same. - BOOST_REQUIRE_EQUAL(layer1.InSize(), layer2.InSize()); - BOOST_REQUIRE_EQUAL(layer2.OutSize(), layer2.OutSize()); - BOOST_REQUIRE_EQUAL(layer1.Rho(), layer2.Rho()); + REQUIRE(layer1.InSize() == layer2.InSize()); + REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.Rho() == layer2.Rho()); } /** * Check if the gradients computed by GRU cell are close enough to the * approximation of the gradients. */ -BOOST_AUTO_TEST_CASE(GradientGRULayerTest) +TEST_CASE("GradientGRULayerTest", "[ANNLayerTest]") { // GRU function gradient instantiation. struct GradientFunction @@ -1329,13 +1322,13 @@ BOOST_AUTO_TEST_CASE(GradientGRULayerTest) arma::cube input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * GRU layer manual forward test. */ -BOOST_AUTO_TEST_CASE(ForwardGRULayerTest) +TEST_CASE("ForwardGRULayerTest", "[ANNLayerTest]") { // This will make it easier to clean memory later. GRU<>* gruAlloc = new GRU<>(3, 3, 5); @@ -1361,7 +1354,7 @@ BOOST_AUTO_TEST_CASE(ForwardGRULayerTest) // For the first input the output should be equal to the output of // gate z_t as the previous output fed to the cell is all zeros. - BOOST_REQUIRE_LE(arma::as_scalar(arma::trans(output) * expectedOutput), 1e-2); + REQUIRE(arma::as_scalar(arma::trans(output) * expectedOutput) <= 1e-2); expectedOutput = output; @@ -1384,7 +1377,7 @@ BOOST_AUTO_TEST_CASE(ForwardGRULayerTest) // Expected output for the second input. expectedOutput = z_t % expectedOutput + (arma::ones(3, 1) - z_t) % o_t; - BOOST_REQUIRE_LE(arma::as_scalar(arma::trans(output) * expectedOutput), 1e-2); + REQUIRE(arma::as_scalar(arma::trans(output) * expectedOutput) <= 1e-2); LayerTypes<> layer(gruAlloc); boost::apply_visitor(DeleteVisitor(), layer); @@ -1393,7 +1386,7 @@ BOOST_AUTO_TEST_CASE(ForwardGRULayerTest) /** * Simple concat module test. */ -BOOST_AUTO_TEST_CASE(SimpleConcatLayerTest) +TEST_CASE("SimpleConcatLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta, error; @@ -1419,18 +1412,18 @@ BOOST_AUTO_TEST_CASE(SimpleConcatLayerTest) const double sumModuleB = arma::accu( moduleB->Parameters().submat( 100, 0, moduleB->Parameters().n_elem - 1, 0)); - BOOST_REQUIRE_CLOSE(sumModuleA + sumModuleB, arma::accu(output.col(0)), 1e-3); + REQUIRE(sumModuleA + sumModuleB == Approx(arma::accu(output.col(0))).epsilon(1e-5)); // Test the Backward function. error = arma::zeros(20, 1); module.Backward(input, error, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); } /** * Test to check Concat layer along different axes. */ -BOOST_AUTO_TEST_CASE(ConcatAlongAxisTest) +TEST_CASE("ConcatAlongAxisTest", "[ANNLayerTest]") { arma::mat output, input, error, outputA, outputB; size_t inputWidth = 4, inputHeight = 4, inputChannel = 2; @@ -1516,20 +1509,20 @@ BOOST_AUTO_TEST_CASE(ConcatAlongAxisTest) * Test that the function that can access the axis parameter of the * Concat layer works. */ -BOOST_AUTO_TEST_CASE(ConcatLayerParametersTest) +TEST_CASE("ConcatLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inputSize{width, height, channels}, axis, model, run. arma::Row inputSize{128, 128, 3}; Concat<> layer(inputSize, 2, false, true); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.ConcatAxis(), 2); + REQUIRE(layer.ConcatAxis() == 2); } /** * Concat layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientConcatLayerTest) +TEST_CASE("GradientConcatLayerTest", "[ANNLayerTest]") { // Concat function gradient instantiation. struct GradientFunction @@ -1571,13 +1564,13 @@ BOOST_AUTO_TEST_CASE(GradientConcatLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Simple concatenate module test. */ -BOOST_AUTO_TEST_CASE(SimpleConcatenateLayerTest) +TEST_CASE("SimpleConcatenateLayerTest", "[ANNLayerTest]") { arma::mat input = arma::ones(5, 1); arma::mat output, delta; @@ -1588,17 +1581,17 @@ BOOST_AUTO_TEST_CASE(SimpleConcatenateLayerTest) // Test the Forward function. module.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 7.5); + REQUIRE(arma::accu(output) == 7.5); // Test the Backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 5); + REQUIRE(arma::accu(delta) == 5); } /** * Concatenate layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientConcatenateLayerTest) +TEST_CASE("GradientConcatenateLayerTest", "[ANNLayerTest]") { // Concatenate function gradient instantiation. struct GradientFunction @@ -1642,13 +1635,13 @@ BOOST_AUTO_TEST_CASE(GradientConcatenateLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Simple lookup module test. */ -BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) +TEST_CASE("SimpleLookupLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta, gradient; Lookup<> module(10, 5); @@ -1665,11 +1658,11 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) const double outputSum = arma::accu(module.Parameters().col(0)) + arma::accu(module.Parameters().col(2)); - BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output), 1e-3); + REQUIRE(outputSum == Approx(arma::accu(output)).epsilon(1e-5)); // Test the Backward function. module.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(input)); + REQUIRE(arma::accu(input) == arma::accu(input)); // Test the Gradient function. arma::mat error = arma::ones(2, 5); @@ -1682,28 +1675,28 @@ BOOST_AUTO_TEST_CASE(SimpleLookupLayerTest) const double gradientSum = arma::accu(gradient.col(0)) + arma::accu(gradient.col(2)); - BOOST_REQUIRE_CLOSE(gradientSum, arma::accu(error), 1e-3); - BOOST_REQUIRE_CLOSE(arma::accu(gradient), arma::accu(error), 1e-3); + REQUIRE(gradientSum == Approx(arma::accu(error)).epsilon(1e-5)); + REQUIRE(arma::accu(gradient) == Approx(arma::accu(error)).epsilon(1e-5)); } /** * Test that the functions that can access the parameters of the * Lookup layer work. */ -BOOST_AUTO_TEST_CASE(LookupLayerParametersTest) +TEST_CASE("LookupLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, outSize. Lookup<> layer(5, 7); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.InSize(), 5); - BOOST_REQUIRE_EQUAL(layer.OutSize(), 7); + REQUIRE(layer.InSize() == 5); + REQUIRE(layer.OutSize() == 7); } /** * Simple LogSoftMax module test. */ -BOOST_AUTO_TEST_CASE(SimpleLogSoftmaxLayerTest) +TEST_CASE("SimpleLogSoftmaxLayerTest", "[ANNLayerTest]") { arma::mat output, input, error, delta; LogSoftMax<> module; @@ -1711,22 +1704,22 @@ BOOST_AUTO_TEST_CASE(SimpleLogSoftmaxLayerTest) // Test the Forward function. input = arma::mat("0.5; 0.5"); module.Forward(input, output); - BOOST_REQUIRE_SMALL(arma::accu(arma::abs( - arma::mat("-0.6931; -0.6931") - output)), 1e-3); + REQUIRE(arma::accu(arma::abs(arma::mat("-0.6931; -0.6931") - output)) == + Approx(0.0).margin(1e-3)); // Test the Backward function. error = arma::zeros(input.n_rows, input.n_cols); // Assume LogSoftmax layer is always associated with NLL output layer. error(1, 0) = -1; module.Backward(input, error, delta); - BOOST_REQUIRE_SMALL(arma::accu(arma::abs( - arma::mat("1.6487; 0.6487") - delta)), 1e-3); + REQUIRE(arma::accu(arma::abs(arma::mat("1.6487; 0.6487") - delta)) == + Approx(0.0).margin(1e-3)); } /** * Simple Softmax module test. */ -BOOST_AUTO_TEST_CASE(SimpleSoftmaxLayerTest) +TEST_CASE("SimpleSoftmaxLayerTest", "[ANNLayerTest]") { arma::mat input, output, gy, g; Softmax<> module; @@ -1734,21 +1727,21 @@ BOOST_AUTO_TEST_CASE(SimpleSoftmaxLayerTest) // Test the forward function. input = arma::mat("1.7; 3.6"); module.Forward(input, output); - BOOST_REQUIRE_SMALL(arma::accu(arma::abs( - arma::mat("0.130108; 0.869892") - output)), 1e-4); + REQUIRE(arma::accu(arma::abs(arma::mat("0.130108; 0.869892") - output)) == + Approx(0.0).margin(1e-4)); // Test the backward function. gy = arma::zeros(input.n_rows, input.n_cols); gy(0) = 1; module.Backward(output, gy, g); - BOOST_REQUIRE_SMALL(arma::accu(arma::abs( - arma::mat("0.11318; -0.11318") - g)), 1e-04); + REQUIRE(arma::accu(arma::abs(arma::mat("0.11318; -0.11318") - g)) == + Approx(0.0).margin(1e-04)); } /** * Softmax layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientSoftmaxTest) +TEST_CASE("GradientSoftmaxTest", "[ANNLayerTest]") { // Softmax function gradient instantiation. struct GradientFunction @@ -1785,13 +1778,13 @@ BOOST_AUTO_TEST_CASE(GradientSoftmaxTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /* * Simple test for the BilinearInterpolation layer */ -BOOST_AUTO_TEST_CASE(SimpleBilinearInterpolationLayerTest) +TEST_CASE("SimpleBilinearInterpolationLayerTest", "[ANNLayerTest]") { // Tested output against tensorflow.image.resize_bilinear() arma::mat input, output, unzoomedOutput, expectedOutput; @@ -1826,18 +1819,18 @@ BOOST_AUTO_TEST_CASE(SimpleBilinearInterpolationLayerTest) * Test that the functions that can modify and access the parameters of the * Bilinear Interpolation layer work. */ -BOOST_AUTO_TEST_CASE(BilinearInterpolationLayerParametersTest) +TEST_CASE("BilinearInterpolationLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inRowSize, inColSize, outRowSize, outColSize, depth. BilinearInterpolation<> layer1(1, 2, 3, 4, 5); BilinearInterpolation<> layer2(2, 3, 4, 5, 6); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InRowSize(), 1); - BOOST_REQUIRE_EQUAL(layer1.InColSize(), 2); - BOOST_REQUIRE_EQUAL(layer1.OutRowSize(), 3); - BOOST_REQUIRE_EQUAL(layer1.OutColSize(), 4); - BOOST_REQUIRE_EQUAL(layer1.InDepth(), 5); + REQUIRE(layer1.InRowSize() == 1); + REQUIRE(layer1.InColSize() == 2); + REQUIRE(layer1.OutRowSize() == 3); + REQUIRE(layer1.OutColSize() == 4); + REQUIRE(layer1.InDepth() == 5); // Now modify the parameters to match the second layer. layer1.InRowSize() = 2; @@ -1847,11 +1840,11 @@ BOOST_AUTO_TEST_CASE(BilinearInterpolationLayerParametersTest) layer1.InDepth() = 6; // Now ensure all results are the same. - BOOST_REQUIRE_EQUAL(layer1.InRowSize(), layer2.InRowSize()); - BOOST_REQUIRE_EQUAL(layer1.InColSize(), layer2.InColSize()); - BOOST_REQUIRE_EQUAL(layer1.OutRowSize(), layer2.OutRowSize()); - BOOST_REQUIRE_EQUAL(layer1.OutColSize(), layer2.OutColSize()); - BOOST_REQUIRE_EQUAL(layer1.InDepth(), layer2.InDepth()); + REQUIRE(layer1.InRowSize() == layer2.InRowSize()); + REQUIRE(layer1.InColSize() == layer2.InColSize()); + REQUIRE(layer1.OutRowSize() == layer2.OutRowSize()); + REQUIRE(layer1.OutColSize() == layer2.OutColSize()); + REQUIRE(layer1.InDepth() == layer2.InDepth()); } /** @@ -1859,7 +1852,7 @@ BOOST_AUTO_TEST_CASE(BilinearInterpolationLayerParametersTest) * the values from another implementation. * Link to the implementation - http://cthorey.github.io./backpropagation/ */ -BOOST_AUTO_TEST_CASE(BatchNormTest) +TEST_CASE("BatchNormTest", "[ANNLayerTest]") { arma::mat input, output; input << 5.1 << 3.5 << 1.4 << arma::endr @@ -1949,7 +1942,7 @@ BOOST_AUTO_TEST_CASE(BatchNormTest) /** * BatchNorm layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientBatchNormTest) +TEST_CASE("GradientBatchNormTest", "[ANNLayerTest]") { bool pass = false; for (size_t trial = 0; trial < 10; trial++) @@ -1999,21 +1992,21 @@ BOOST_AUTO_TEST_CASE(GradientBatchNormTest) } } - BOOST_REQUIRE(pass); + REQUIRE(pass); } /** * Test that the functions that can access the parameters of the * Batch Norm layer work. */ -BOOST_AUTO_TEST_CASE(BatchNormLayerParametersTest) +TEST_CASE("BatchNormLayerParametersTest", "[ANNLayerTest]") { // Parameter order : size, eps. BatchNorm<> layer(7, 1e-3); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.InputSize(), 7); - BOOST_REQUIRE_EQUAL(layer.Epsilon(), 1e-3); + REQUIRE(layer.InputSize() == 7); + REQUIRE(layer.Epsilon() == 1e-3); arma::mat runningMean(7, 1, arma::fill::randn); arma::mat runningVariance(7, 1, arma::fill::randn); @@ -2027,7 +2020,7 @@ BOOST_AUTO_TEST_CASE(BatchNormLayerParametersTest) /** * VirtualBatchNorm layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientVirtualBatchNormTest) +TEST_CASE("GradientVirtualBatchNormTest", "[ANNLayerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -2067,14 +2060,14 @@ BOOST_AUTO_TEST_CASE(GradientVirtualBatchNormTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Test that the functions that can modify and access the parameters of the * Virtual Batch Norm layer work. */ -BOOST_AUTO_TEST_CASE(VirtualBatchNormLayerParametersTest) +TEST_CASE("VirtualBatchNormLayerParametersTest", "[ANNLayerTest]") { arma::mat input = arma::randn(5, 256); arma::mat referenceBatch = arma::mat(input.memptr(), input.n_rows, 16); @@ -2083,14 +2076,14 @@ BOOST_AUTO_TEST_CASE(VirtualBatchNormLayerParametersTest) VirtualBatchNorm<> layer(referenceBatch, 5, 1e-3); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.InSize(), 5); - BOOST_REQUIRE_EQUAL(layer.Epsilon(), 1e-3); + REQUIRE(layer.InSize() == 5); + REQUIRE(layer.Epsilon() == 1e-3); } /** * MiniBatchDiscrimination layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(MiniBatchDiscriminationTest) +TEST_CASE("MiniBatchDiscriminationTest", "[ANNLayerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -2127,13 +2120,13 @@ BOOST_AUTO_TEST_CASE(MiniBatchDiscriminationTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Simple Transposed Convolution layer test. */ -BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) +TEST_CASE("SimpleTransposedConvolutionLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; @@ -2146,12 +2139,12 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module1.Reset(); module1.Forward(input, output); // Value calculated using tensorflow.nn.conv2d_transpose() - BOOST_REQUIRE_EQUAL(arma::accu(output), 360.0); + REQUIRE(arma::accu(output) == 360.0); // Test the backward function. module1.Backward(input, output, delta); // Value calculated using tensorflow.nn.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 720.0); + REQUIRE(arma::accu(delta) == 720.0); TransposedConvolution<> module2(1, 1, 4, 4, 1, 1, 1, 1, 5, 5, 6, 6); // Test the forward function. @@ -2166,12 +2159,12 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module2.Reset(); module2.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 1512.0); + REQUIRE(arma::accu(output) == 1512.0); // Test the backward function. module2.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 6504.0); + REQUIRE(arma::accu(delta) == 6504.0); TransposedConvolution<> module3(1, 1, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5); // Test the forward function. @@ -2184,12 +2177,12 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module3.Reset(); module3.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 2370.0); + REQUIRE(arma::accu(output) == 2370.0); // Test the backward function. module3.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 19154.0); + REQUIRE(arma::accu(delta) == 19154.0); TransposedConvolution<> module4(1, 1, 3, 3, 1, 1, 0, 0, 5, 5, 7, 7); // Test the forward function. @@ -2202,12 +2195,12 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module4.Reset(); module4.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 6000.0); + REQUIRE(arma::accu(output) == 6000.0); // Test the backward function. module4.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 86208.0); + REQUIRE(arma::accu(delta) == 86208.0); TransposedConvolution<> module5(1, 1, 3, 3, 2, 2, 0, 0, 2, 2, 5, 5); // Test the forward function. @@ -2220,12 +2213,12 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module5.Reset(); module5.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 120.0); + REQUIRE(arma::accu(output) == 120.0); // Test the backward function. module5.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 960.0); + REQUIRE(arma::accu(delta) == 960.0); TransposedConvolution<> module6(1, 1, 3, 3, 2, 2, 1, 1, 3, 3, 5, 5); // Test the forward function. @@ -2238,12 +2231,12 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module6.Reset(); module6.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 410.0); + REQUIRE(arma::accu(output) == 410.0); // Test the backward function. module6.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 4444.0); + REQUIRE(arma::accu(delta) == 4444.0); TransposedConvolution<> module7(1, 1, 3, 3, 2, 2, 1, 1, 3, 3, 6, 6); // Test the forward function. @@ -2256,17 +2249,17 @@ BOOST_AUTO_TEST_CASE(SimpleTransposedConvolutionLayerTest) module7.Reset(); module7.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 606.0); + REQUIRE(arma::accu(output) == 606.0); module7.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(delta), 7732.0); + REQUIRE(arma::accu(delta) == 7732.0); } /** * Transposed Convolution layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientTransposedConvolutionLayerTest) +TEST_CASE("GradientTransposedConvolutionLayerTest", "[ANNLayerTest]") { // Add function gradient instantiation. // To make this test robust, check it five times. @@ -2312,13 +2305,13 @@ BOOST_AUTO_TEST_CASE(GradientTransposedConvolutionLayerTest) break; } } - BOOST_REQUIRE_EQUAL(pass, true); + REQUIRE(pass == true); } /** * Simple MultiplyMerge module test. */ -BOOST_AUTO_TEST_CASE(SimpleMultiplyMergeLayerTest) +TEST_CASE("SimpleMultiplyMergeLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; input = arma::ones(10, 1); @@ -2337,18 +2330,18 @@ BOOST_AUTO_TEST_CASE(SimpleMultiplyMergeLayerTest) // Test the Forward function. module.Forward(input, output); - BOOST_REQUIRE_EQUAL(10, arma::accu(output)); + REQUIRE(10 == arma::accu(output)); // Test the Backward function. module.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(delta)); + REQUIRE(arma::accu(output) == arma::accu(delta)); } } /** * Simple Atrous Convolution layer test. */ -BOOST_AUTO_TEST_CASE(SimpleAtrousConvolutionLayerTest) +TEST_CASE("SimpleAtrousConvolutionLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta; @@ -2361,11 +2354,11 @@ BOOST_AUTO_TEST_CASE(SimpleAtrousConvolutionLayerTest) module1.Reset(); module1.Forward(input, output); // Value calculated using tensorflow.nn.atrous_conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 792.0); + REQUIRE(arma::accu(output) == 792.0); // Test the Backward function. module1.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 2376); + REQUIRE(arma::accu(delta) == 2376); AtrousConvolution<> module2(1, 1, 3, 3, 2, 2, 0, 0, 7, 7, 2, 2); // Test the forward function. @@ -2377,17 +2370,17 @@ BOOST_AUTO_TEST_CASE(SimpleAtrousConvolutionLayerTest) module2.Reset(); module2.Forward(input, output); // Value calculated using tensorflow.nn.conv2d() - BOOST_REQUIRE_EQUAL(arma::accu(output), 264.0); + REQUIRE(arma::accu(output) == 264.0); // Test the backward function. module2.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 792.0); + REQUIRE(arma::accu(delta) == 792.0); } /** * Atrous Convolution layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientAtrousConvolutionLayerTest) +TEST_CASE("GradientAtrousConvolutionLayerTest", "[ANNLayerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -2425,14 +2418,14 @@ BOOST_AUTO_TEST_CASE(GradientAtrousConvolutionLayerTest) // TODO: this tolerance seems far higher than necessary. The implementation // should be checked. - BOOST_REQUIRE_LE(CheckGradient(function), 0.2); + REQUIRE(CheckGradient(function) <= 0.2); } /** * Test the functions to access and modify the parameters of the * AtrousConvolution layer. */ -BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerParametersTest) +TEST_CASE("AtrousConvolutionLayerParametersTest", "[ANNLayerTest]") { // Parameter order for the constructor: inSize, outSize, kW, kH, dW, dH, padW, // padH, inputWidth, inputHeight, dilationW, dilationH, paddingType ("none"). @@ -2442,18 +2435,18 @@ BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerParametersTest) std::make_tuple(10, 11), 12, 13, 14, 15); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InputWidth(), 11); - BOOST_REQUIRE_EQUAL(layer1.InputHeight(), 12); - BOOST_REQUIRE_EQUAL(layer1.KernelWidth(), 3); - BOOST_REQUIRE_EQUAL(layer1.KernelHeight(), 4); - BOOST_REQUIRE_EQUAL(layer1.StrideWidth(), 5); - BOOST_REQUIRE_EQUAL(layer1.StrideHeight(), 6); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadHTop(), 9); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadHBottom(), 10); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadWLeft(), 7); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadWRight(), 8); - BOOST_REQUIRE_EQUAL(layer1.DilationWidth(), 13); - BOOST_REQUIRE_EQUAL(layer1.DilationHeight(), 14); + REQUIRE(layer1.InputWidth() == 11); + REQUIRE(layer1.InputHeight() == 12); + REQUIRE(layer1.KernelWidth() == 3); + REQUIRE(layer1.KernelHeight() == 4); + REQUIRE(layer1.StrideWidth() == 5); + REQUIRE(layer1.StrideHeight() == 6); + REQUIRE(layer1.Padding().PadHTop() == 9); + REQUIRE(layer1.Padding().PadHBottom() == 10); + REQUIRE(layer1.Padding().PadWLeft() == 7); + REQUIRE(layer1.Padding().PadWRight() == 8); + REQUIRE(layer1.DilationWidth() == 13); + REQUIRE(layer1.DilationHeight() == 14); // Now modify the parameters to match the second layer. layer1.InputWidth() = 12; @@ -2470,28 +2463,28 @@ BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerParametersTest) layer1.DilationHeight() = 15; // Now ensure all results are the same. - BOOST_REQUIRE_EQUAL(layer1.InputWidth(), layer2.InputWidth()); - BOOST_REQUIRE_EQUAL(layer1.InputHeight(), layer2.InputHeight()); - BOOST_REQUIRE_EQUAL(layer1.KernelWidth(), layer2.KernelWidth()); - BOOST_REQUIRE_EQUAL(layer1.KernelHeight(), layer2.KernelHeight()); - BOOST_REQUIRE_EQUAL(layer1.StrideWidth(), layer2.StrideWidth()); - BOOST_REQUIRE_EQUAL(layer1.StrideHeight(), layer2.StrideHeight()); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadHTop(), layer2.Padding().PadHTop()); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadHBottom(), + REQUIRE(layer1.InputWidth() == layer2.InputWidth()); + REQUIRE(layer1.InputHeight() == layer2.InputHeight()); + REQUIRE(layer1.KernelWidth() == layer2.KernelWidth()); + REQUIRE(layer1.KernelHeight() == layer2.KernelHeight()); + REQUIRE(layer1.StrideWidth() == layer2.StrideWidth()); + REQUIRE(layer1.StrideHeight() == layer2.StrideHeight()); + REQUIRE(layer1.Padding().PadHTop() == layer2.Padding().PadHTop()); + REQUIRE(layer1.Padding().PadHBottom() == layer2.Padding().PadHBottom()); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadWLeft(), + REQUIRE(layer1.Padding().PadWLeft() == layer2.Padding().PadWLeft()); - BOOST_REQUIRE_EQUAL(layer1.Padding().PadWRight(), + REQUIRE(layer1.Padding().PadWRight() == layer2.Padding().PadWRight()); - BOOST_REQUIRE_EQUAL(layer1.DilationWidth(), layer2.DilationWidth()); - BOOST_REQUIRE_EQUAL(layer1.DilationHeight(), layer2.DilationHeight()); + REQUIRE(layer1.DilationWidth() == layer2.DilationWidth()); + REQUIRE(layer1.DilationHeight() == layer2.DilationHeight()); } /** * Test that the padding options are working correctly in Atrous Convolution * layer. */ -BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerPaddingTest) +TEST_CASE("AtrousConvolutionLayerPaddingTest", "[ANNLayerTest]") { arma::mat output, input, delta; @@ -2506,9 +2499,9 @@ BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerPaddingTest) module1.Reset(); module1.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, 9); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == 9); + REQUIRE(output.n_cols == 1); // Test the Backward function. module1.Backward(input, output, delta); @@ -2524,9 +2517,9 @@ BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerPaddingTest) module2.Reset(); module2.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, 49); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == 49); + REQUIRE(output.n_cols == 1); // Test the backward function. module2.Backward(input, output, delta); @@ -2535,7 +2528,7 @@ BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerPaddingTest) /** * Tests the LayerNorm layer. */ -BOOST_AUTO_TEST_CASE(LayerNormTest) +TEST_CASE("LayerNormTest", "[ANNLayerTest]") { arma::mat input, output; input << 5.1 << 3.5 << arma::endr @@ -2569,7 +2562,7 @@ BOOST_AUTO_TEST_CASE(LayerNormTest) /** * LayerNorm layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientLayerNormTest) +TEST_CASE("GradientLayerNormTest", "[ANNLayerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -2608,28 +2601,28 @@ BOOST_AUTO_TEST_CASE(GradientLayerNormTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Test that the functions that can access the parameters of the * Layer Norm layer work. */ -BOOST_AUTO_TEST_CASE(LayerNormLayerParametersTest) +TEST_CASE("LayerNormLayerParametersTest", "[ANNLayerTest]") { // Parameter order : size, eps. LayerNorm<> layer(5, 1e-3); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.InSize(), 5); - BOOST_REQUIRE_EQUAL(layer.Epsilon(), 1e-3); + REQUIRE(layer.InSize() == 5); + REQUIRE(layer.Epsilon() == 1e-3); } /** * Test if the AddMerge layer is able to forward the * Forward/Backward/Gradient calls. */ -BOOST_AUTO_TEST_CASE(AddMergeRunTest) +TEST_CASE("AddMergeRunTest", "[ANNLayerTest]") { arma::mat output, input, delta, error; @@ -2653,15 +2646,15 @@ BOOST_AUTO_TEST_CASE(AddMergeRunTest) // Clean up before we break, delete linear; - BOOST_REQUIRE_CLOSE(parameterSum, arma::accu(output), 1e-3); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(parameterSum == Approx(arma::accu(output)).epsilon(1e-5)); + REQUIRE(arma::accu(delta) == 0); } /** * Test if the MultiplyMerge layer is able to forward the * Forward/Backward/Gradient calls. */ -BOOST_AUTO_TEST_CASE(MultiplyMergeRunTest) +TEST_CASE("MultiplyMergeRunTest", "[ANNLayerTest]") { arma::mat output, input, delta, error; @@ -2685,14 +2678,14 @@ BOOST_AUTO_TEST_CASE(MultiplyMergeRunTest) // Clean up before we break, delete linear; - BOOST_REQUIRE_CLOSE(parameterSum, arma::accu(output), 1e-3); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(parameterSum == Approx(arma::accu(output)).epsilon(1e-5)); + REQUIRE(arma::accu(delta) == 0); } /** * Simple subview module test. */ -BOOST_AUTO_TEST_CASE(SimpleSubviewLayerTest) +TEST_CASE("SimpleSubviewLayerTest", "[ANNLayerTest]") { arma::mat output, input, delta, outputMat; Subview<> moduleRow(1, 10, 19); @@ -2700,26 +2693,26 @@ BOOST_AUTO_TEST_CASE(SimpleSubviewLayerTest) // Test the Forward function for a vector. input = arma::ones(20, 1); moduleRow.Forward(input, output); - BOOST_REQUIRE_EQUAL(output.n_rows, 10); + REQUIRE(output.n_rows == 10); Subview<> moduleMat(4, 3, 6, 0, 2); // Test the Forward function for a matrix. input = arma::ones(20, 8); moduleMat.Forward(input, outputMat); - BOOST_REQUIRE_EQUAL(outputMat.n_rows, 12); - BOOST_REQUIRE_EQUAL(outputMat.n_cols, 2); + REQUIRE(outputMat.n_rows == 12); + REQUIRE(outputMat.n_cols == 2); // Test the Backward function. moduleMat.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(accu(delta), 160); - BOOST_REQUIRE_EQUAL(delta.n_rows, 20); + REQUIRE(accu(delta) == 160); + REQUIRE(delta.n_rows == 20); } /** * Subview index test. */ -BOOST_AUTO_TEST_CASE(SubviewIndexTest) +TEST_CASE("SubviewIndexTest", "[ANNLayerTest]") { arma::mat outputEnd, outputMid, outputStart, input, delta; input = arma::linspace(1, 20, 20); @@ -2749,7 +2742,7 @@ BOOST_AUTO_TEST_CASE(SubviewIndexTest) /** * Subview batch test. */ -BOOST_AUTO_TEST_CASE(SubviewBatchTest) +TEST_CASE("SubviewBatchTest", "[ANNLayerTest]") { arma::mat output, input, outputCol, outputMat, outputDef; @@ -2782,18 +2775,18 @@ BOOST_AUTO_TEST_CASE(SubviewBatchTest) * Test that the functions that can modify and access the parameters of the * Subview layer work. */ -BOOST_AUTO_TEST_CASE(SubviewLayerParametersTest) +TEST_CASE("SubviewLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, beginRow, endRow, beginCol, endCol. Subview<> layer1(1, 2, 3, 4, 5); Subview<> layer2(1, 3, 4, 5, 6); // Make sure we can get the parameters correctly. - BOOST_REQUIRE_EQUAL(layer1.InSize(), 1); - BOOST_REQUIRE_EQUAL(layer1.BeginRow(), 2); - BOOST_REQUIRE_EQUAL(layer1.EndRow(), 3); - BOOST_REQUIRE_EQUAL(layer1.BeginCol(), 4); - BOOST_REQUIRE_EQUAL(layer1.EndCol(), 5); + REQUIRE(layer1.InSize() == 1); + REQUIRE(layer1.BeginRow() == 2); + REQUIRE(layer1.EndRow() == 3); + REQUIRE(layer1.BeginCol() == 4); + REQUIRE(layer1.EndCol() == 5); // Now modify the parameters to match the second layer. layer1.BeginRow() = 3; @@ -2802,17 +2795,17 @@ BOOST_AUTO_TEST_CASE(SubviewLayerParametersTest) layer1.EndCol() = 6; // Now ensure all results are the same. - BOOST_REQUIRE_EQUAL(layer1.InSize(), layer2.InSize()); - BOOST_REQUIRE_EQUAL(layer1.BeginRow(), layer2.BeginRow()); - BOOST_REQUIRE_EQUAL(layer1.EndRow(), layer2.EndRow()); - BOOST_REQUIRE_EQUAL(layer1.BeginCol(), layer2.BeginCol()); - BOOST_REQUIRE_EQUAL(layer1.EndCol(), layer2.EndCol()); + REQUIRE(layer1.InSize() == layer2.InSize()); + REQUIRE(layer1.BeginRow() == layer2.BeginRow()); + REQUIRE(layer1.EndRow() == layer2.EndRow()); + REQUIRE(layer1.BeginCol() == layer2.BeginCol()); + REQUIRE(layer1.EndCol() == layer2.EndCol()); } /* * Simple Reparametrization module test. */ -BOOST_AUTO_TEST_CASE(SimpleReparametrizationLayerTest) +TEST_CASE("SimpleReparametrizationLayerTest", "[ANNLayerTest]") { arma::mat input, output, delta; Reparametrization<> module(5); @@ -2823,18 +2816,18 @@ BOOST_AUTO_TEST_CASE(SimpleReparametrizationLayerTest) input = join_cols(arma::ones(5, 1) * -15, arma::zeros(5, 1)); module.Forward(input, output); - BOOST_REQUIRE_LE(arma::accu(output), 1e-5); + REQUIRE(arma::accu(output) <= 1e-5); // Test the Backward function. arma::mat gy = arma::zeros(5, 1); module.Backward(input, gy, delta); - BOOST_REQUIRE(arma::accu(delta) != 0); // klBackward will be added. + REQUIRE(arma::accu(delta) != 0); // klBackward will be added. } /** * Reparametrization module stochastic boolean test. */ -BOOST_AUTO_TEST_CASE(ReparametrizationLayerStochasticTest) +TEST_CASE("ReparametrizationLayerStochasticTest", "[ANNLayerTest]") { arma::mat input, outputA, outputB; Reparametrization<> module(5, false); @@ -2852,7 +2845,7 @@ BOOST_AUTO_TEST_CASE(ReparametrizationLayerStochasticTest) /** * Reparametrization module includeKl boolean test. */ -BOOST_AUTO_TEST_CASE(ReparametrizationLayerIncludeKlTest) +TEST_CASE("ReparametrizationLayerIncludeKlTest", "[ANNLayerTest]") { arma::mat input, output, gy, delta; Reparametrization<> module(5, true, false); @@ -2866,13 +2859,13 @@ BOOST_AUTO_TEST_CASE(ReparametrizationLayerIncludeKlTest) gy = arma::zeros(output.n_rows, output.n_cols); module.Backward(output, gy, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(arma::accu(delta) == 0); } /** * Jacobian Reparametrization module test. */ -BOOST_AUTO_TEST_CASE(JacobianReparametrizationLayerTest) +TEST_CASE("JacobianReparametrizationLayerTest", "[ANNLayerTest]") { for (size_t i = 0; i < 5; ++i) { @@ -2884,14 +2877,14 @@ BOOST_AUTO_TEST_CASE(JacobianReparametrizationLayerTest) Reparametrization<> module(inputElementsHalf, false, false); double error = JacobianTest(module, input); - BOOST_REQUIRE_LE(error, 1e-5); + REQUIRE(error <= 1e-5); } } /** * Reparametrization layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientReparametrizationLayerTest) +TEST_CASE("GradientReparametrizationLayerTest", "[ANNLayerTest]") { // Linear function gradient instantiation. struct GradientFunction @@ -2929,13 +2922,13 @@ BOOST_AUTO_TEST_CASE(GradientReparametrizationLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Reparametrization layer beta numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientReparametrizationLayerBetaTest) +TEST_CASE("GradientReparametrizationLayerBetaTest", "[ANNLayerTest]") { // Linear function gradient instantiation. struct GradientFunction @@ -2974,29 +2967,29 @@ BOOST_AUTO_TEST_CASE(GradientReparametrizationLayerBetaTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Test that the functions that can access the parameters of the * Reparametrization layer work. */ -BOOST_AUTO_TEST_CASE(ReparametrizationLayerParametersTest) +TEST_CASE("ReparametrizationLayerParametersTest", "[ANNLayerTest]") { // Parameter order : latentSize, stochastic, includeKL, beta. Reparametrization<> layer(5, false, false, 2); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.OutputSize(), 5); - BOOST_REQUIRE_EQUAL(layer.Stochastic(), false); - BOOST_REQUIRE_EQUAL(layer.IncludeKL(), false); - BOOST_REQUIRE_EQUAL(layer.Beta(), 2); + REQUIRE(layer.OutputSize() == 5); + REQUIRE(layer.Stochastic() == false); + REQUIRE(layer.IncludeKL() == false); + REQUIRE(layer.Beta() == 2); } /** * Simple residual module test. */ -BOOST_AUTO_TEST_CASE(SimpleResidualLayerTest) +TEST_CASE("SimpleResidualLayerTest", "[ANNLayerTest]") { arma::mat outputA, outputB, input, deltaA, deltaB; @@ -3040,7 +3033,7 @@ BOOST_AUTO_TEST_CASE(SimpleResidualLayerTest) /** * Simple Highway module test. */ -BOOST_AUTO_TEST_CASE(SimpleHighwayLayerTest) +TEST_CASE("SimpleHighwayLayerTest", "[ANNLayerTest]") { arma::mat outputA, outputB, input, deltaA, deltaB; Sequential<>* sequential = new Sequential<>(true); @@ -3079,19 +3072,19 @@ BOOST_AUTO_TEST_CASE(SimpleHighwayLayerTest) * Test that the function that can access the inSize parameter of the * Highway layer works. */ -BOOST_AUTO_TEST_CASE(HighwayLayerParametersTest) +TEST_CASE("HighwayLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, model. Highway<> layer(1, true); // Make sure we can get the parameter successfully. - BOOST_REQUIRE_EQUAL(layer.InSize(), 1); + REQUIRE(layer.InSize() == 1); } /** * Sequential layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientHighwayLayerTest) +TEST_CASE("GradientHighwayLayerTest", "[ANNLayerTest]") { // Linear function gradient instantiation. struct GradientFunction @@ -3137,13 +3130,13 @@ BOOST_AUTO_TEST_CASE(GradientHighwayLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Sequential layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientSequentialLayerTest) +TEST_CASE("GradientSequentialLayerTest", "[ANNLayerTest]") { // Linear function gradient instantiation. struct GradientFunction @@ -3188,13 +3181,13 @@ BOOST_AUTO_TEST_CASE(GradientSequentialLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * WeightNorm layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientWeightNormLayerTest) +TEST_CASE("GradientWeightNormLayerTest", "[ANNLayerTest]") { // Linear function gradient instantiation. struct GradientFunction @@ -3235,14 +3228,14 @@ BOOST_AUTO_TEST_CASE(GradientWeightNormLayerTest) arma::mat input, target; } function; - BOOST_REQUIRE_LE(CheckGradient(function), 1e-4); + REQUIRE(CheckGradient(function) <= 1e-4); } /** * Test if the WeightNorm layer is able to forward the * Forward/Backward/Gradient calls. */ -BOOST_AUTO_TEST_CASE(WeightNormRunTest) +TEST_CASE("WeightNormRunTest", "[ANNLayerTest]") { arma::mat output, input, delta, error; @@ -3261,8 +3254,8 @@ BOOST_AUTO_TEST_CASE(WeightNormRunTest) // Test the Backward function. module.Backward(input, input, delta); - BOOST_REQUIRE_EQUAL(0, arma::accu(output)); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); + REQUIRE(0 == arma::accu(output)); + REQUIRE(arma::accu(delta) == 0); } // General ANN serialization test. @@ -3306,7 +3299,7 @@ void ANNLayerSerializationTest(LayerType& layer) /** * Simple serialization test for batch normalization layer. */ -BOOST_AUTO_TEST_CASE(BatchNormSerializationTest) +TEST_CASE("BatchNormSerializationTest", "[ANNLayerTest]") { BatchNorm<> layer(10); ANNLayerSerializationTest(layer); @@ -3315,7 +3308,7 @@ BOOST_AUTO_TEST_CASE(BatchNormSerializationTest) /** * Simple serialization test for layer normalization layer. */ -BOOST_AUTO_TEST_CASE(LayerNormSerializationTest) +TEST_CASE("LayerNormSerializationTest", "[ANNLayerTest]") { LayerNorm<> layer(10); ANNLayerSerializationTest(layer); @@ -3325,7 +3318,7 @@ BOOST_AUTO_TEST_CASE(LayerNormSerializationTest) * Test that the functions that can modify and access the parameters of the * Convolution layer work. */ -BOOST_AUTO_TEST_CASE(ConvolutionLayerParametersTest) +TEST_CASE("ConvolutionLayerParametersTest", "[ANNLayerTest]") { // Parameter order: inSize, outSize, kW, kH, dW, dH, padW, padH, inputWidth, // inputHeight, paddingType. @@ -3335,16 +3328,16 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerParametersTest) std::tuple(10, 11), 12, 13, "none"); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InputWidth(), 11); - BOOST_REQUIRE_EQUAL(layer1.InputHeight(), 12); - BOOST_REQUIRE_EQUAL(layer1.KernelWidth(), 3); - BOOST_REQUIRE_EQUAL(layer1.KernelHeight(), 4); - BOOST_REQUIRE_EQUAL(layer1.StrideWidth(), 5); - BOOST_REQUIRE_EQUAL(layer1.StrideHeight(), 6); - BOOST_REQUIRE_EQUAL(layer1.PadWLeft(), 7); - BOOST_REQUIRE_EQUAL(layer1.PadWRight(), 8); - BOOST_REQUIRE_EQUAL(layer1.PadHTop(), 9); - BOOST_REQUIRE_EQUAL(layer1.PadHBottom(), 10); + REQUIRE(layer1.InputWidth() == 11); + REQUIRE(layer1.InputHeight() == 12); + REQUIRE(layer1.KernelWidth() == 3); + REQUIRE(layer1.KernelHeight() == 4); + REQUIRE(layer1.StrideWidth() == 5); + REQUIRE(layer1.StrideHeight() == 6); + REQUIRE(layer1.PadWLeft() == 7); + REQUIRE(layer1.PadWRight() == 8); + REQUIRE(layer1.PadHTop() == 9); + REQUIRE(layer1.PadHBottom() == 10); // Now modify the parameters to match the second layer. layer1.InputWidth() = 12; @@ -3359,22 +3352,22 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerParametersTest) layer1.PadHBottom() = 11; // Now ensure all results are the same. - BOOST_REQUIRE_EQUAL(layer1.InputWidth(), layer2.InputWidth()); - BOOST_REQUIRE_EQUAL(layer1.InputHeight(), layer2.InputHeight()); - BOOST_REQUIRE_EQUAL(layer1.KernelWidth(), layer2.KernelWidth()); - BOOST_REQUIRE_EQUAL(layer1.KernelHeight(), layer2.KernelHeight()); - BOOST_REQUIRE_EQUAL(layer1.StrideWidth(), layer2.StrideWidth()); - BOOST_REQUIRE_EQUAL(layer1.StrideHeight(), layer2.StrideHeight()); - BOOST_REQUIRE_EQUAL(layer1.PadWLeft(), layer2.PadWLeft()); - BOOST_REQUIRE_EQUAL(layer1.PadWRight(), layer2.PadWRight()); - BOOST_REQUIRE_EQUAL(layer1.PadHTop(), layer2.PadHTop()); - BOOST_REQUIRE_EQUAL(layer1.PadHBottom(), layer2.PadHBottom()); + REQUIRE(layer1.InputWidth() == layer2.InputWidth()); + REQUIRE(layer1.InputHeight() == layer2.InputHeight()); + REQUIRE(layer1.KernelWidth() == layer2.KernelWidth()); + REQUIRE(layer1.KernelHeight() == layer2.KernelHeight()); + REQUIRE(layer1.StrideWidth() == layer2.StrideWidth()); + REQUIRE(layer1.StrideHeight() == layer2.StrideHeight()); + REQUIRE(layer1.PadWLeft() == layer2.PadWLeft()); + REQUIRE(layer1.PadWRight() == layer2.PadWRight()); + REQUIRE(layer1.PadHTop() == layer2.PadHTop()); + REQUIRE(layer1.PadHBottom() == layer2.PadHBottom()); } /** * Test that the padding options are working correctly in Convolution layer. */ -BOOST_AUTO_TEST_CASE(ConvolutionLayerPaddingTest) +TEST_CASE("ConvolutionLayerPaddingTest", "[ANNLayerTest]") { arma::mat output, input, delta; @@ -3388,9 +3381,9 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerPaddingTest) module1.Reset(); module1.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, 25); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == 25); + REQUIRE(output.n_cols == 1); // Test the Backward function. module1.Backward(input, output, delta); @@ -3405,9 +3398,9 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerPaddingTest) module2.Reset(); module2.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, 49); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == 49); + REQUIRE(output.n_cols == 1); // Test the backward function. module2.Backward(input, output, delta); @@ -3416,7 +3409,7 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerPaddingTest) /** * Test that the padding options in Transposed Convolution layer. */ -BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) +TEST_CASE("TransposedConvolutionLayerPaddingTest", "[ANNLayerTest]") { arma::mat output, input, delta; @@ -3428,11 +3421,11 @@ BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) module1.Reset(); module1.Forward(input, output); // Value calculated using tensorflow.nn.conv2d_transpose(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 0.0); + REQUIRE(arma::accu(output) == 0.0); // Test the Backward Function. module1.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + REQUIRE(arma::accu(delta) == 0.0); // Test Valid for non zero padding. TransposedConvolution<> module2(1, 1, 3, 3, 2, 2, @@ -3448,11 +3441,11 @@ BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) module2.Reset(); module2.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 120.0); + REQUIRE(arma::accu(output) == 120.0); // Test the Backward Function. module2.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 960.0); + REQUIRE(arma::accu(delta) == 960.0); // Test for same padding type. TransposedConvolution<> module3(1, 1, 3, 3, 2, 2, 0, 0, 3, 3, 3, 3, "SAME"); @@ -3461,13 +3454,13 @@ BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) module3.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); module3.Reset(); module3.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); - BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); // Test the Backward Function. module3.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + REQUIRE(arma::accu(delta) == 0.0); // Output shape should equal input. TransposedConvolution<> module4(1, 1, 3, 3, 1, 1, @@ -3478,13 +3471,13 @@ BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) module4.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); module4.Reset(); module4.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); - BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); // Test the Backward Function. module4.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + REQUIRE(arma::accu(delta) == 0.0); TransposedConvolution<> module5(1, 1, 3, 3, 2, 2, 0, 0, 2, 2, 2, 2, "SAME"); // Test the forward function. @@ -3492,13 +3485,13 @@ BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) module5.Parameters() = arma::mat(25 + 1, 1, arma::fill::zeros); module5.Reset(); module5.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); - BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); // Test the Backward Function. module5.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + REQUIRE(arma::accu(delta) == 0.0); TransposedConvolution<> module6(1, 1, 4, 4, 1, 1, 1, 1, 5, 5, 5, 5, "SAME"); // Test the forward function. @@ -3506,19 +3499,19 @@ BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) module6.Parameters() = arma::mat(16 + 1, 1, arma::fill::zeros); module6.Reset(); module6.Forward(input, output); - BOOST_REQUIRE_EQUAL(arma::accu(output), 0); - BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); - BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + REQUIRE(arma::accu(output) == 0); + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); // Test the Backward Function. module6.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + REQUIRE(arma::accu(delta) == 0.0); } /** * Simple test for Max Pooling layer. */ -BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) +TEST_CASE("MaxPoolingTestCase", "[ANNLayerTest]") { // For rectangular input to pooling layers. arma::mat input = arma::mat(12, 1); @@ -3540,9 +3533,9 @@ BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) module1.InputWidth() = 4; module1.Forward(input, output); // Calculated using torch.nn.MaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 28); - BOOST_REQUIRE_EQUAL(output.n_elem, 4); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 28); + REQUIRE(output.n_elem == 4); + REQUIRE(output.n_cols == 1); // For Square input. input = arma::mat(9, 1); @@ -3559,9 +3552,9 @@ BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) module2.InputWidth() = 3; module2.Forward(input, output); // Calculated using torch.nn.MaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 12.0); - BOOST_REQUIRE_EQUAL(output.n_elem, 2); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 12.0); + REQUIRE(output.n_elem == 2); + REQUIRE(output.n_cols == 1); // For Square input. input = arma::mat(16, 1); @@ -3578,9 +3571,9 @@ BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) module3.InputWidth() = 4; module3.Forward(input, output); // Calculated using torch.nn.MaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); - BOOST_REQUIRE_EQUAL(output.n_elem, 9); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 30.0); + REQUIRE(output.n_elem == 9); + REQUIRE(output.n_cols == 1); // For Rectangular input. input = arma::mat(6, 1); @@ -3595,73 +3588,73 @@ BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) module4.InputWidth() = 3; module4.Forward(input, output); // Calculated using torch.nn.MaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 3); - BOOST_REQUIRE_EQUAL(output.n_elem, 4); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 3); + REQUIRE(output.n_elem == 4); + REQUIRE(output.n_cols == 1); } /** * Test that the functions that can modify and access the parameters of the * Glimpse layer work. */ -BOOST_AUTO_TEST_CASE(GlimpseLayerParametersTest) +TEST_CASE("GlimpseLayerParametersTest", "[ANNLayerTest]") { // Parameter order : inSize, size, depth, scale, inputWidth, inputHeight. Glimpse<> layer1(1, 2, 3, 4, 5, 6); Glimpse<> layer2(1, 2, 3, 4, 6, 7); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer1.InputHeight(), 6); - BOOST_REQUIRE_EQUAL(layer1.InputWidth(), 5); - BOOST_REQUIRE_EQUAL(layer1.Scale(), 4); - BOOST_REQUIRE_EQUAL(layer1.Depth(), 3); - BOOST_REQUIRE_EQUAL(layer1.GlimpseSize(), 2); - BOOST_REQUIRE_EQUAL(layer1.InSize(), 1); + REQUIRE(layer1.InputHeight() == 6); + REQUIRE(layer1.InputWidth() == 5); + REQUIRE(layer1.Scale() == 4); + REQUIRE(layer1.Depth() == 3); + REQUIRE(layer1.GlimpseSize() == 2); + REQUIRE(layer1.InSize() == 1); // Now modify the parameters to match the second layer. layer1.InputHeight() = 7; layer1.InputWidth() = 6; // Now ensure that all the results are the same. - BOOST_REQUIRE_EQUAL(layer1.InputHeight(), layer2.InputHeight()); - BOOST_REQUIRE_EQUAL(layer1.InputWidth(), layer2.InputWidth()); - BOOST_REQUIRE_EQUAL(layer1.Scale(), layer2.Scale()); - BOOST_REQUIRE_EQUAL(layer1.Depth(), layer2.Depth()); - BOOST_REQUIRE_EQUAL(layer1.GlimpseSize(), layer2.GlimpseSize()); - BOOST_REQUIRE_EQUAL(layer1.InSize(), layer2.InSize()); + REQUIRE(layer1.InputHeight() == layer2.InputHeight()); + REQUIRE(layer1.InputWidth() == layer2.InputWidth()); + REQUIRE(layer1.Scale() == layer2.Scale()); + REQUIRE(layer1.Depth() == layer2.Depth()); + REQUIRE(layer1.GlimpseSize() == layer2.GlimpseSize()); + REQUIRE(layer1.InSize() == layer2.InSize()); } /** * Test that the function that can access the stdev parameter of the * Reinforce Normal layer works. */ -BOOST_AUTO_TEST_CASE(ReinforceNormalLayerParametersTest) +TEST_CASE("ReinforceNormalLayerParametersTest", "[ANNLayerTest]") { // Parameter : stdev. ReinforceNormal<> layer(4.0); // Make sure we can get the parameter successfully. - BOOST_REQUIRE_EQUAL(layer.StandardDeviation(), 4.0); + REQUIRE(layer.StandardDeviation() == 4.0); } /** * Test that the function that can access the parameters of the * VR Class Reward layer works. */ -BOOST_AUTO_TEST_CASE(VRClassRewardLayerParametersTest) +TEST_CASE("VRClassRewardLayerParametersTest", "[ANNLayerTest]") { // Parameter order : scale, sizeAverage. VRClassReward<> layer(2, false); // Make sure we can get the parameters successfully. - BOOST_REQUIRE_EQUAL(layer.Scale(), 2); - BOOST_REQUIRE_EQUAL(layer.SizeAverage(), false); + REQUIRE(layer.Scale() == 2); + REQUIRE(layer.SizeAverage() == false); } /** * Simple test for Adaptive pooling for Max Pooling layer. */ -BOOST_AUTO_TEST_CASE(AdaptiveMaxPoolingTestCase) +TEST_CASE("AdaptiveMaxPoolingTestCase", "[ANNLayerTest]") { // For rectangular input. arma::mat input = arma::mat(12, 1); @@ -3684,12 +3677,12 @@ BOOST_AUTO_TEST_CASE(AdaptiveMaxPoolingTestCase) module1.InputWidth() = 4; module1.Forward(input, output); // Calculated using torch.nn.AdaptiveMaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 28); - BOOST_REQUIRE_EQUAL(output.n_elem, 4); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 28); + REQUIRE(output.n_elem == 4); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module1.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 28.0); + REQUIRE(arma::accu(delta) == 28.0); // For Square input. input = arma::mat(9, 1); @@ -3706,12 +3699,12 @@ BOOST_AUTO_TEST_CASE(AdaptiveMaxPoolingTestCase) module2.InputWidth() = 3; module2.Forward(input, output); // Calculated using torch.nn.AdaptiveMaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 15.0); - BOOST_REQUIRE_EQUAL(output.n_elem, 2); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 15.0); + REQUIRE(output.n_elem == 2); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module2.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 15.0); + REQUIRE(arma::accu(delta) == 15.0); // For Square input. input = arma::mat(16, 1); @@ -3728,12 +3721,12 @@ BOOST_AUTO_TEST_CASE(AdaptiveMaxPoolingTestCase) module3.InputWidth() = 4; module3.Forward(input, output); // Calculated using torch.nn.AdaptiveMaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); - BOOST_REQUIRE_EQUAL(output.n_elem, 9); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 30.0); + REQUIRE(output.n_elem == 9); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module3.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 30.0); + REQUIRE(arma::accu(delta) == 30.0); // For Rectangular input. input = arma::mat(20, 1); @@ -3748,18 +3741,18 @@ BOOST_AUTO_TEST_CASE(AdaptiveMaxPoolingTestCase) module4.InputWidth() = 5; module4.Forward(input, output); // Calculated using torch.nn.AdaptiveMaxPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 2); - BOOST_REQUIRE_EQUAL(output.n_elem, 4); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 2); + REQUIRE(output.n_elem == 4); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module4.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 2.0); + REQUIRE(arma::accu(delta) == 2.0); } /** * Simple test for Adaptive pooling for Mean Pooling layer. */ -BOOST_AUTO_TEST_CASE(AdaptiveMeanPoolingTestCase) +TEST_CASE("AdaptiveMeanPoolingTestCase", "[ANNLayerTest]") { // For rectangular input. arma::mat input = arma::mat(12, 1); @@ -3782,12 +3775,12 @@ BOOST_AUTO_TEST_CASE(AdaptiveMeanPoolingTestCase) module1.InputWidth() = 4; module1.Forward(input, output); // Calculated using torch.nn.AdaptiveAvgPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 19.75); - BOOST_REQUIRE_EQUAL(output.n_elem, 4); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 19.75); + REQUIRE(output.n_elem == 4); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module1.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 7.0); + REQUIRE(arma::accu(delta) == 7.0); // For Square input. input = arma::mat(9, 1); @@ -3804,12 +3797,12 @@ BOOST_AUTO_TEST_CASE(AdaptiveMeanPoolingTestCase) module2.InputWidth() = 3; module2.Forward(input, output); // Calculated using torch.nn.AdaptiveAvgPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 4.5); - BOOST_REQUIRE_EQUAL(output.n_elem, 2); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 4.5); + REQUIRE(output.n_elem == 2); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module2.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + REQUIRE(arma::accu(delta) == 0.0); // For Square input. input = arma::mat(16, 1); @@ -3826,12 +3819,12 @@ BOOST_AUTO_TEST_CASE(AdaptiveMeanPoolingTestCase) module3.InputWidth() = 4; module3.Forward(input, output); // Calculated using torch.nn.AdaptiveAvgPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 10.5); - BOOST_REQUIRE_EQUAL(output.n_elem, 9); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 10.5); + REQUIRE(output.n_elem == 9); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module3.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 10.5); + REQUIRE(arma::accu(delta) == 10.5); // For Rectangular input. input = arma::mat(24, 1); @@ -3846,29 +3839,29 @@ BOOST_AUTO_TEST_CASE(AdaptiveMeanPoolingTestCase) module4.InputWidth() = 6; module4.Forward(input, output); // Calculated using torch.nn.AdaptiveAvgPool2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 2.25); - BOOST_REQUIRE_EQUAL(output.n_elem, 9); - BOOST_REQUIRE_EQUAL(output.n_cols, 1); + REQUIRE(arma::accu(output) == 2.25); + REQUIRE(output.n_elem == 9); + REQUIRE(output.n_cols == 1); // Test the Backward Function. module4.Backward(input, output, delta); - BOOST_REQUIRE_EQUAL(arma::accu(delta), 1.5); + REQUIRE(arma::accu(delta) == 1.5); } -BOOST_AUTO_TEST_CASE(TransposedConvolutionalLayerOptionalParameterTest) +TEST_CASE("TransposedConvolutionalLayerOptionalParameterTest", "[ANNLayerTest]") { Sequential<>* decoder = new Sequential<>(); // Check if we can create an object without specifying output. - BOOST_REQUIRE_NO_THROW(decoder->Add>(24, 16, + REQUIRE_NOTHROW(decoder->Add>(24, 16, 5, 5, 1, 1, 0, 0, 10, 10)); - BOOST_REQUIRE_NO_THROW(decoder->Add>(16, 1, + REQUIRE_NOTHROW(decoder->Add>(16, 1, 15, 15, 1, 1, 1, 1, 14, 14)); - delete decoder; + delete decoder; } -BOOST_AUTO_TEST_CASE(BatchNormWithMinBatchesTest) +TEST_CASE("BatchNormWithMinBatchesTest", "[ANNLayerTest]") { arma::mat input, output, result, runningMean, runningVar, delta; @@ -3903,7 +3896,7 @@ BOOST_AUTO_TEST_CASE(BatchNormWithMinBatchesTest) // Check backward function. module1.Backward(input, output, delta); - BOOST_REQUIRE_CLOSE(arma::accu(delta), 0.0102676, 1e-3); + REQUIRE(arma::accu(delta) == Approx(0.0102676).epsilon(1e-5)); // Check values for running mean and running variance. // Calculated using torch.nn.BatchNorm2d(). @@ -4024,7 +4017,7 @@ BOOST_AUTO_TEST_CASE(BatchNormWithMinBatchesTest) /** * Batch Normalization layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientBatchNormWithMiniBatchesTest) +TEST_CASE("GradientBatchNormWithMiniBatchesTest", "[ANNLayerTest]") { // Add function gradient instantiation. // To make this test robust, check it ten times. @@ -4075,10 +4068,10 @@ BOOST_AUTO_TEST_CASE(GradientBatchNormWithMiniBatchesTest) } } - BOOST_REQUIRE(pass); + REQUIRE(pass); } -BOOST_AUTO_TEST_CASE(ConvolutionLayerTestCase) +TEST_CASE("ConvolutionLayerTestCase", "[ANNLayerTest]") { arma::mat input, output; @@ -4105,14 +4098,12 @@ BOOST_AUTO_TEST_CASE(ConvolutionLayerTestCase) layer.Forward(input, output); // Value calculated using torch.nn.Conv2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 4108); + REQUIRE(arma::accu(output) == 4108); // Set bias to one. layer.Parameters().fill(1.0); layer.Forward(input, output); // Value calculated using torch.nn.Conv2d(). - BOOST_REQUIRE_EQUAL(arma::accu(output), 4156); + REQUIRE(arma::accu(output) == 4156); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/ann_regularizer_test.cpp b/src/mlpack/tests/ann_regularizer_test.cpp index a852e94d0c..2252852ee8 100644 --- a/src/mlpack/tests/ann_regularizer_test.cpp +++ b/src/mlpack/tests/ann_regularizer_test.cpp @@ -16,16 +16,14 @@ #include #include -#include +#include "catch.hpp" #include "ann_test_tools.hpp" -#include "serialization.hpp" +#include "serialization_catch.hpp" using namespace mlpack; using namespace mlpack::ann; -BOOST_AUTO_TEST_SUITE(ANNRegularizerTest); - -BOOST_AUTO_TEST_CASE(GradientL1RegularizerTest) +TEST_CASE("GradientL1RegularizerTest", "[ANNRegularizerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -51,10 +49,10 @@ BOOST_AUTO_TEST_CASE(GradientL1RegularizerTest) L1Regularizer reg; } function; - BOOST_REQUIRE_LE(CheckRegularizerGradient(function), 1e-4); + REQUIRE(CheckRegularizerGradient(function) <= 1e-4); } -BOOST_AUTO_TEST_CASE(GradientL2RegularizerTest) +TEST_CASE("GradientL2RegularizerTest", "[ANNRegularizerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -80,10 +78,10 @@ BOOST_AUTO_TEST_CASE(GradientL2RegularizerTest) L2Regularizer reg; } function; - BOOST_REQUIRE_LE(CheckRegularizerGradient(function), 1e-4); + REQUIRE(CheckRegularizerGradient(function) <= 1e-4); } -BOOST_AUTO_TEST_CASE(GradientOrthogonalRegularizerTest) +TEST_CASE("GradientOrthogonalRegularizerTest", "[ANNRegularizerTest]") { // Add function gradient instantiation. struct GradientFunction @@ -111,7 +109,5 @@ BOOST_AUTO_TEST_CASE(GradientOrthogonalRegularizerTest) OrthogonalRegularizer reg; } function; - BOOST_REQUIRE_LE(CheckRegularizerGradient(function), 1e-4); + REQUIRE(CheckRegularizerGradient(function) <= 1e-4); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/ann_visitor_test.cpp b/src/mlpack/tests/ann_visitor_test.cpp index 13b3e60657..1b01308ff3 100644 --- a/src/mlpack/tests/ann_visitor_test.cpp +++ b/src/mlpack/tests/ann_visitor_test.cpp @@ -15,18 +15,16 @@ #include #include -#include -#include "test_tools.hpp" +#include "catch.hpp" +#include "test_catch_tools.hpp" using namespace mlpack; using namespace mlpack::ann; -BOOST_AUTO_TEST_SUITE(ANNVisitorTest); - /** * Test that the BiasSetVisitor works properly. */ -BOOST_AUTO_TEST_CASE(BiasSetVisitorTest) +TEST_CASE("BiasSetVisitorTest", "[ANNVisitorTest]") { LayerTypes<> linear = new Linear<>(10, 10); @@ -43,16 +41,14 @@ BOOST_AUTO_TEST_CASE(BiasSetVisitorTest) size_t biasSize = boost::apply_visitor(BiasSetVisitor(weight, 0), linear); - BOOST_REQUIRE_EQUAL(biasSize, 10); + REQUIRE(biasSize == 10); arma::mat input(10, 1), output; input.randu(); boost::apply_visitor(ForwardVisitor(input, output), linear); - BOOST_REQUIRE_EQUAL(arma::accu(output), 55); + REQUIRE(arma::accu(output) == 55); boost::apply_visitor(DeleteVisitor(), linear); } - -BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/test_catch_tools.hpp b/src/mlpack/tests/test_catch_tools.hpp index 34396e3cf9..1bac310ddc 100644 --- a/src/mlpack/tests/test_catch_tools.hpp +++ b/src/mlpack/tests/test_catch_tools.hpp @@ -33,7 +33,7 @@ inline void CheckMatrices(const arma::mat& a, for (size_t i = 0; i < a.n_elem; ++i) { if (std::abs(a[i]) < tolerance / 2) - REQUIRE(b[i] == Approx(0.0).margin(tolerance / 200)); + REQUIRE(b[i] == Approx(0.0).margin(tolerance / 2)); else REQUIRE(a[i] == Approx(b[i]).epsilon(tolerance / 100)); } @@ -62,7 +62,7 @@ inline void CheckMatrices(const arma::cube& a, for (size_t i = 0; i < a.n_elem; ++i) { if (std::abs(a[i]) < tolerance / 2) - REQUIRE(b[i] == Approx(0.0).margin(tolerance / 200)); + REQUIRE(b[i] == Approx(0.0).margin(tolerance / 2)); else REQUIRE(a[i] == Approx(b[i]).epsilon(tolerance / 100)); } From ff4ef04782b8e0b96270eb203c15afa7c80e2c3c Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Sun, 2 Aug 2020 01:48:59 +0530 Subject: [PATCH 285/297] style fixes --- src/mlpack/tests/ann_dist_test.cpp | 24 ++++++++++++------------ src/mlpack/tests/ann_layer_test.cpp | 9 ++++++--- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/mlpack/tests/ann_dist_test.cpp b/src/mlpack/tests/ann_dist_test.cpp index 9648289a94..ea1d8605a1 100644 --- a/src/mlpack/tests/ann_dist_test.cpp +++ b/src/mlpack/tests/ann_dist_test.cpp @@ -141,23 +141,23 @@ TEST_CASE("NormalDistributionTest", "[ANNDistTest]") normalDist.LogProbability(x, prob); // Testing output of log probability for some random mu, sigma and x. - REQUIRE(prob[0] == Approx( 1.2586464).epsilon(1e-5)); - REQUIRE(prob[1] == Approx( 0.8751131).epsilon(1e-5)); - REQUIRE(prob[2] == Approx( -0.30579138).epsilon(1e-5)); - REQUIRE(prob[3] == Approx( -5.498411).epsilon(1e-5)); + REQUIRE(prob[0] == Approx(1.2586464).epsilon(1e-5)); + REQUIRE(prob[1] == Approx(0.8751131).epsilon(1e-5)); + REQUIRE(prob[2] == Approx(-0.30579138).epsilon(1e-5)); + REQUIRE(prob[3] == Approx(-5.498411).epsilon(1e-5)); arma::vec dmu, dsigma; normalDist.ProbBackward(x, dmu, dsigma); // Testing output of dmu and dsigma for some random mu, sigma and x. - REQUIRE(dmu[0] == Approx( -17.603287).epsilon(1e-5)); - REQUIRE(dsigma[0] == Approx( -26.40487).epsilon(1e-5)); - REQUIRE(dmu[1] == Approx( -19.827663).epsilon(1e-5)); - REQUIRE(dsigma[1] == Approx( -3.7852707).epsilon(1e-5)); - REQUIRE(dmu[2] == Approx( 0.5892323).epsilon(1e-5)); - REQUIRE(dsigma[2] == Approx( -1.2373875).epsilon(1e-5)); - REQUIRE(dmu[3] == Approx( 0.061901994).epsilon(1e-5)); - REQUIRE(dsigma[3] == Approx( 0.19751444).epsilon(1e-5)); + REQUIRE(dmu[0] == Approx(-17.603287).epsilon(1e-5)); + REQUIRE(dsigma[0] == Approx(-26.40487).epsilon(1e-5)); + REQUIRE(dmu[1] == Approx(-19.827663).epsilon(1e-5)); + REQUIRE(dsigma[1] == Approx(-3.7852707).epsilon(1e-5)); + REQUIRE(dmu[2] == Approx(0.5892323).epsilon(1e-5)); + REQUIRE(dsigma[2] == Approx(-1.2373875).epsilon(1e-5)); + REQUIRE(dmu[3] == Approx(0.061901994).epsilon(1e-5)); + REQUIRE(dsigma[3] == Approx(0.19751444).epsilon(1e-5)); } /** diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index a930fb4879..3dd92eafd4 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -292,10 +292,12 @@ TEST_CASE("SimpleAlphaDropoutLayerTest", "[ANNLayerTest]") arma::mat output; module.Forward(input, output); // Check whether mean remains nearly same. - REQUIRE(arma::as_scalar(arma::abs(arma::mean(input) - arma::mean(output))) <= 0.1); + REQUIRE(arma::as_scalar(arma::abs(arma::mean(input) - arma::mean(output))) <= + 0.1); // Check whether variance remains nearly same. - REQUIRE(arma::as_scalar(arma::abs(arma::var(input) - arma::var(output))) <= 0.1); + REQUIRE(arma::as_scalar(arma::abs(arma::var(input) - arma::var(output))) <= + 0.1); // Test the Backward function when training phase. arma::mat delta; @@ -1412,7 +1414,8 @@ TEST_CASE("SimpleConcatLayerTest", "[ANNLayerTest]") const double sumModuleB = arma::accu( moduleB->Parameters().submat( 100, 0, moduleB->Parameters().n_elem - 1, 0)); - REQUIRE(sumModuleA + sumModuleB == Approx(arma::accu(output.col(0))).epsilon(1e-5)); + REQUIRE(sumModuleA + sumModuleB == + Approx(arma::accu(output.col(0))).epsilon(1e-5)); // Test the Backward function. error = arma::zeros(20, 1); From 977f32625183e9f8a8ca9f4a4ec68a7417ccc779 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 1 Aug 2020 17:03:39 -0400 Subject: [PATCH 286/297] Update HISTORY. --- HISTORY.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index a941b58491..67d39452d2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -11,6 +11,11 @@ * Additional functionality for the ARFF loader (#2486); use case sensitive categories (#2516). + * Add `bayesian_linear_regression` binding for the command-line, Python, + Julia, and Go. Also called "Bayesian Ridge", this is equivalent to a + version of linear regression where the regularization parameter is + automatically tuned (#2030). + ### mlpack 3.3.2 ###### 2020-06-18 * Added Noisy DQN to q_networks (#2446). From 0e3458f24466999f34fbedf712b93c7ea5201d74 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Mon, 3 Aug 2020 10:59:55 +0530 Subject: [PATCH 287/297] apply suggestions from code review Co-authored-by: Mikhail Lozhnikov --- src/mlpack/methods/ann/layer/lookup.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/lookup.hpp b/src/mlpack/methods/ann/layer/lookup.hpp index e1492b64c8..e704a5a1f7 100644 --- a/src/mlpack/methods/ann/layer/lookup.hpp +++ b/src/mlpack/methods/ann/layer/lookup.hpp @@ -27,7 +27,7 @@ namespace ann /* Artificial Neural Network. */ { * the embeddings of those tokens. * * The input shape : (sequenceLength, batchSize). - * The output shape : (embeddingSize * sequenceLength, batchSize). + * The output shape : (sequenceLength * embeddingSize, batchSize). * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). From 345b312c00391ae93cfddd2cbcd910de69fba59d Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 3 Aug 2020 12:24:26 +0530 Subject: [PATCH 288/297] add comments about matrix dimensions --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index aed3cfe7d5..378662a15e 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -41,6 +41,11 @@ void Lookup::Forward( for (size_t i = 0; i < batchSize; ++i) { + //! ith column of output is a vectorized form of a matrix of shape + //! (seqLength, embeddingSize) selected as a combination of rows from the + //! weights. It is done to ensure that the feature dimension remains beside + //! the batch dimension when vectorized form is unpacked for some other + //! layer. output.col(i) = arma::vectorise(weights.rows( arma::conv_to::from(input.col(i)) - 1)); } From f3056ff6ed4df23116b7d6db4dc608a89f23bb61 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 3 Aug 2020 13:41:44 +0530 Subject: [PATCH 289/297] some correction in comments --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 378662a15e..8c00b69c94 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -43,9 +43,8 @@ void Lookup::Forward( { //! ith column of output is a vectorized form of a matrix of shape //! (seqLength, embeddingSize) selected as a combination of rows from the - //! weights. It is done to ensure that the feature dimension remains beside - //! the batch dimension when vectorized form is unpacked for some other - //! layer. + //! weights. This particular ordering of matrix dimensions is required by + //! the MultiheadAttention class. output.col(i) = arma::vectorise(weights.rows( arma::conv_to::from(input.col(i)) - 1)); } From 5081d77d6c7da1615ad6974aeb1cf5152aa0dcc6 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 3 Aug 2020 17:25:53 +0530 Subject: [PATCH 290/297] trigger the build --- src/mlpack/methods/ann/layer/lookup_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lookup_impl.hpp b/src/mlpack/methods/ann/layer/lookup_impl.hpp index 8c00b69c94..6afcb56218 100644 --- a/src/mlpack/methods/ann/layer/lookup_impl.hpp +++ b/src/mlpack/methods/ann/layer/lookup_impl.hpp @@ -43,8 +43,8 @@ void Lookup::Forward( { //! ith column of output is a vectorized form of a matrix of shape //! (seqLength, embeddingSize) selected as a combination of rows from the - //! weights. This particular ordering of matrix dimensions is required by - //! the MultiheadAttention class. + //! weights. The MultiheadAttention class requires this particular ordering + //! of matrix dimensions. output.col(i) = arma::vectorise(weights.rows( arma::conv_to::from(input.col(i)) - 1)); } From c32c47137b5492faaf8a798c49a9f15a4eddd93b Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 4 Aug 2020 00:11:57 +0530 Subject: [PATCH 291/297] correcting catch tests --- src/mlpack/tests/ann_layer_test.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 2110b546ee..32ca697575 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1673,20 +1673,20 @@ TEST_CASE("SimpleLookupLayerTest", "[ANNLayerTest]") const double outputSum = arma::accu(module.Parameters().rows( arma::conv_to::from(input.col(i)) - 1)); - REQUIRE(outputSum == Approx(arma::accu(output.col(i))).epsilon(1e-3); + REQUIRE(std::abs(outputSum - arma::accu(output.col(i))) <= 1e-5); } // Test the Gradient function. arma::mat error = 0.01 * arma::randu(embeddingSize * seqLength, batchSize); module.Gradient(input, error, gradient); - REQUIRE(arma::accu(error) == Approx(arma::accu(gradient)).epsilon(1e-05); + REQUIRE(std::abs(arma::accu(error) - arma::accu(gradient)) <= 1e-07); } /** * Lookup layer numerical gradient test. */ -BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) +TEST_CASE("GradientLookupLayerTest", "[ANNLayerTest]") { // Lookup function gradient instantiation. struct GradientFunction @@ -1736,7 +1736,7 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) const size_t batchSize = 4; } function; - REQUIRE(CheckGradient(function) <= 1e-5); + REQUIRE(CheckGradient(function) <= 1e-6); } /** @@ -1745,12 +1745,12 @@ BOOST_AUTO_TEST_CASE(GradientLookupLayerTest) */ TEST_CASE("LookupLayerParametersTest", "[ANNLayerTest]") { - // Parameter order : inSize, outSize. + // Parameter order : vocabSize, embedingSize. Lookup<> layer(100, 8); // Make sure we can get the parameters successfully. - REQUIRE(layer.InSize() == 5); - REQUIRE(layer.OutSize() == 7); + REQUIRE(layer.VocabSize() == 100); + REQUIRE(layer.EmbeddingSize() == 8); } /** From bdb5abd1818079da69fe16083f0acefe6f59605c Mon Sep 17 00:00:00 2001 From: kartikdutt18 Date: Tue, 4 Aug 2020 17:11:11 +0530 Subject: [PATCH 292/297] Changes in Deterministic parameter of FNN, default to train mode --- src/mlpack/methods/ann/ffn_impl.hpp | 10 ++-------- src/mlpack/tests/ann_layer_test.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/ann/ffn_impl.hpp b/src/mlpack/methods/ann/ffn_impl.hpp index 12194ec9c0..e11b624cc8 100644 --- a/src/mlpack/methods/ann/ffn_impl.hpp +++ b/src/mlpack/methods/ann/ffn_impl.hpp @@ -39,7 +39,7 @@ FFN::FFN( height(0), reset(false), numFunctions(0), - deterministic(true) + deterministic(false) { /* Nothing to do here. */ } @@ -60,7 +60,7 @@ void FFN::ResetData( numFunctions = responses.n_cols; this->predictors = std::move(predictors); this->responses = std::move(responses); - this->deterministic = true; + this->deterministic = false; ResetDeterministic(); if (!reset) @@ -158,12 +158,6 @@ void FFN::Forward( if (parameter.is_empty()) ResetParameters(); - if (!deterministic) - { - deterministic = true; - ResetDeterministic(); - } - Forward(inputs); results = boost::apply_visitor(outputParameterVisitor, network.back()); } diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 3dd92eafd4..f07bcb00ac 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4110,3 +4110,22 @@ TEST_CASE("ConvolutionLayerTestCase", "[ANNLayerTest]") // Value calculated using torch.nn.Conv2d(). REQUIRE(arma::accu(output) == 4156); } + +TEST_CASE("BatchNormDeterministicTest", "[ANNLayerTest]") +{ + FFN<> module; + module.Add>(2, 1e-5, false); + module.Add>(); + + arma::mat input(4, 3), output; + module.ResetParameters(); + + // The model should switch to Deterministic mode for predicting. + module.Predict(input, output); + REQUIRE(boost::get*>(module.Model()[0])->Deterministic() == true); + + output.ones(); + module.Train(input, output); + // The model should switch to training mode for predicting. + REQUIRE(boost::get*>(module.Model()[0])->Deterministic() == false); +} \ No newline at end of file From d570d7c69478b8e249c67dfbb92dfd5b7d85c242 Mon Sep 17 00:00:00 2001 From: kartikdutt18 Date: Tue, 4 Aug 2020 17:14:14 +0530 Subject: [PATCH 293/297] Add empty line after tests --- src/mlpack/tests/ann_layer_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index f07bcb00ac..393004e678 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4128,4 +4128,4 @@ TEST_CASE("BatchNormDeterministicTest", "[ANNLayerTest]") module.Train(input, output); // The model should switch to training mode for predicting. REQUIRE(boost::get*>(module.Model()[0])->Deterministic() == false); -} \ No newline at end of file +} From 8ddd2250fed23455d1ab5dbfa10216410e04d56a Mon Sep 17 00:00:00 2001 From: kartikdutt18 Date: Tue, 4 Aug 2020 17:24:35 +0530 Subject: [PATCH 294/297] Style fix --- src/mlpack/tests/ann_layer_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 393004e678..bf0d8eb61c 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4127,5 +4127,5 @@ TEST_CASE("BatchNormDeterministicTest", "[ANNLayerTest]") output.ones(); module.Train(input, output); // The model should switch to training mode for predicting. - REQUIRE(boost::get*>(module.Model()[0])->Deterministic() == false); + REQUIRE(boost::get*>(module.Model()[0])->Deterministic() == 0); } From 172bd68d35ae45aebae483b8a5a6e67a0e01544c Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Tue, 4 Aug 2020 18:46:13 +0530 Subject: [PATCH 295/297] apply suggestions from code review Co-authored-by: Mikhail Lozhnikov --- src/mlpack/tests/ann_layer_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 32ca697575..03af1fc118 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1673,14 +1673,14 @@ TEST_CASE("SimpleLookupLayerTest", "[ANNLayerTest]") const double outputSum = arma::accu(module.Parameters().rows( arma::conv_to::from(input.col(i)) - 1)); - REQUIRE(std::abs(outputSum - arma::accu(output.col(i))) <= 1e-5); + REQUIRE(std::fabs(outputSum - arma::accu(output.col(i))) <= 1e-5); } // Test the Gradient function. arma::mat error = 0.01 * arma::randu(embeddingSize * seqLength, batchSize); module.Gradient(input, error, gradient); - REQUIRE(std::abs(arma::accu(error) - arma::accu(gradient)) <= 1e-07); + REQUIRE(std::fabs(arma::accu(error) - arma::accu(gradient)) <= 1e-07); } /** From d85c689424bdf9c5a1a8d3953ff110d3c0608982 Mon Sep 17 00:00:00 2001 From: kartikdutt18 Date: Tue, 4 Aug 2020 20:33:35 +0530 Subject: [PATCH 296/297] static analysis check fixes --- src/mlpack/tests/ann_layer_test.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index bf0d8eb61c..35cb8e9394 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -972,7 +972,7 @@ TEST_CASE("LSTMLayerParametersTest", "[ANNLayerTest]") // Now ensure all the results are the same. REQUIRE(layer1.InSize() == layer2.InSize()); - REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.OutSize() == layer2.OutSize()); REQUIRE(layer1.Rho() == layer2.Rho()); } @@ -1080,7 +1080,7 @@ TEST_CASE("FastLSTMLayerParametersTest", "[ANNLayerTest]") // Now ensure all the results are the same. REQUIRE(layer1.InSize() == layer2.InSize()); - REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.OutSize() == layer2.OutSize()); REQUIRE(layer1.Rho() == layer2.Rho()); } @@ -1277,7 +1277,7 @@ TEST_CASE("GRULayerParametersTest", "[ANNLayerTest]") // Now ensure all the results are the same. REQUIRE(layer1.InSize() == layer2.InSize()); - REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.OutSize() == layer2.OutSize()); REQUIRE(layer1.Rho() == layer2.Rho()); } @@ -1663,10 +1663,6 @@ TEST_CASE("SimpleLookupLayerTest", "[ANNLayerTest]") REQUIRE(outputSum == Approx(arma::accu(output)).epsilon(1e-5)); - // Test the Backward function. - module.Backward(input, input, delta); - REQUIRE(arma::accu(input) == arma::accu(input)); - // Test the Gradient function. arma::mat error = arma::ones(2, 5); error = error.t(); From f146e3e2b349054ee2b93644332ce83368d409ef Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 4 Aug 2020 22:55:30 +0530 Subject: [PATCH 297/297] fix static code analysis error --- src/mlpack/tests/ann_layer_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 03af1fc118..bbb9aff8c6 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -974,7 +974,7 @@ TEST_CASE("LSTMLayerParametersTest", "[ANNLayerTest]") // Now ensure all the results are the same. REQUIRE(layer1.InSize() == layer2.InSize()); - REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.OutSize() == layer2.OutSize()); REQUIRE(layer1.Rho() == layer2.Rho()); } @@ -1082,7 +1082,7 @@ TEST_CASE("FastLSTMLayerParametersTest", "[ANNLayerTest]") // Now ensure all the results are the same. REQUIRE(layer1.InSize() == layer2.InSize()); - REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.OutSize() == layer2.OutSize()); REQUIRE(layer1.Rho() == layer2.Rho()); } @@ -1279,7 +1279,7 @@ TEST_CASE("GRULayerParametersTest", "[ANNLayerTest]") // Now ensure all the results are the same. REQUIRE(layer1.InSize() == layer2.InSize()); - REQUIRE(layer2.OutSize() == layer2.OutSize()); + REQUIRE(layer1.OutSize() == layer2.OutSize()); REQUIRE(layer1.Rho() == layer2.Rho()); }